--- a/vim/.vimrc Thu Feb 10 17:11:26 2011 -0500
+++ b/vim/.vimrc Thu Feb 17 15:23:03 2011 -0500
@@ -86,7 +86,7 @@
" }}}
" Useful Abbreviations -------------------------------------------------------- {{{
-iabbrev lkdis ಠ_à²
+iabbrev ldis ಠ_à²
" }}}
" Searching and Movement ------------------------------------------------------ {{{
@@ -113,13 +113,15 @@
nnoremap n nzz
nnoremap N Nzz
-vnoremap < <gv
-vnoremap > >gv
-
nnoremap L $
vnoremap L $
onoremap L $
+nnoremap Ëš :lnext<cr>
+nnoremap ¬ :lprevious<cr>
+inoremap Ëš <esc>:lnext<cr>
+inoremap ¬ <esc>:lprevious<cr>
+
" Directional Keys {{{
" Why stretch?
@@ -164,7 +166,7 @@
let line = substitute(line, '\t', onetab, 'g')
let line = strpart(line, 0, windowwidth - 2 -len(foldedlinecount))
- let fillcharcount = windowwidth - len(line) - len(foldedlinecount) - 4
+ let fillcharcount = windowwidth - len(line) - len(foldedlinecount)
return line . '…' . repeat(" ",fillcharcount) . foldedlinecount . '…' . ' '
endfunction " }}}
set foldtext=MyFoldText()
@@ -209,11 +211,17 @@
au BufNewFile,BufRead *.html imap <buffer> <d-e><space> <d-e>.<bs>
au BufNewFile,BufRead *.html nnoremap <s-cr> vit<esc>a<cr><esc>vito<esc>i<cr><esc>
" }}}
+" CSS {{{
+au BufNewFile,BufRead *.css setlocal foldmethod=marker
+au BufNewFile,BufRead *.css setlocal foldmarker={,}
+au BufNewFile,BufRead *.css nnoremap <buffer> cc ddko
+au BufNewFile,BufRead *.css nnoremap <buffer> <localleader>S ?{<CR>jV/^\s*\}?$<CR>k:sort<CR>:noh<CR>
+au BufNewFile,BufRead *.css inoremap <buffer> {<cr> {}<left><cr>.<cr><esc>kA<bs><space><space><space><space>
+" }}}
" LessCSS {{{
au BufNewFile,BufRead *.less setlocal filetype=less
au BufNewFile,BufRead *.less setlocal foldmethod=marker
au BufNewFile,BufRead *.less setlocal foldmarker={,}
-au BufNewFile,BufRead *.less setlocal nocursorline
au BufNewFile,BufRead *.less nnoremap <buffer> cc ddko
au BufNewFile,BufRead *.less nnoremap <buffer> <localleader>S ?{<CR>jV/^\s*\}?$<CR>k:sort<CR>:noh<CR>
au BufNewFile,BufRead *.less inoremap <buffer> {<cr> {}<left><cr>.<cr><esc>kA<bs><space><space><space><space>
@@ -238,6 +246,11 @@
" Vim {{{
au FileType vim setlocal foldmethod=marker
" }}}
+" Python {{{
+au Filetype python noremap <localleader>rr :RopeRename<CR>
+au Filetype python vnoremap <localleader>rm :RopeExtractMethod<CR>
+au Filetype python noremap <localleader>ri :RopeOrganizeImports<CR>
+" }}}
" Django {{{
au BufNewFile,BufRead urls.py setlocal nowrap
au BufNewFile,BufRead urls.py normal! zR
@@ -328,15 +341,12 @@
let g:microdata_attributes_complete = 0
let g:atia_attributes_complete = 0
" }}}
-" Rope and Bike {{{
-let g:bike_exceptions=1
-source $HOME/.vim/sadness/sadness.vim
-
+" Rope {{{
let ropevim_enable_shortcuts = 0
let ropevim_guess_project = 1
-noremap <leader>rr :RopeRename<CR>
-vnoremap <leader>rm :RopeExtractMethod<CR>
-noremap <leader>roi :RopeOrganizeImports<CR>
+let ropevim_global_prefix = '<C-c>p'
+
+source $HOME/.vim/sadness/sadness.vim
" }}}
" Gundo {{{
nnoremap <F5> :GundoToggle<CR>
@@ -449,56 +459,25 @@
endfunction " }}}
" }}}
-" Diff ------------------------------------------------------------------------ {{{
-
-let g:HgDiffing = 0
+" Open quoted ----------------------------------------------------------------- {{{
+nnoremap <silent> <c-o> :OpenQuoted<cr>
+command! OpenQuoted call OpenQuoted()
+function! OpenQuoted() " {{{
+ let @r = ''
-function! s:HgDiffCurrentFile() " {{{
- if g:HgDiffing == 1
- if bufwinnr(bufnr('__HGDIFF__')) != -1
- exe bufwinnr(bufnr('__HGDIFF__')) . "wincmd w"
- bdelete
- endif
+ exe 'normal! vi' . "'" . '"ry'
- diffoff!
-
- let g:HgDiffing = 0
-
- return
+ if len(@r) == 0
+ exe 'normal! i' . '"' . '"ry'
endif
- let fname = bufname('%')
- let ftype = &ft
- diffthis
-
- vnew __HGDIFF__
-
- setlocal buftype=nofile
- setlocal bufhidden=hide
- setlocal noswapfile
- setlocal nobuflisted
- exec 'setlocal filetype='.ftype
-
- setlocal modifiable
+ if len(@r) == 0
+ exe 'normal! "ry'
+ let @r = ''
+ endif
- silent normal! ggdG
- silent exec ':r!hg cat ' . fname
- silent normal! ggdd
-
- setlocal nomodifiable
-
- diffthis
-
- wincmd l
-
- let g:HgDiffing = 1
-
- return
+ exe "silent !open ." . @r
endfunction " }}}
-
-command! HgDiffCurrent call s:HgDiffCurrentFile()
-nmap <leader>d :HgDiffCurrent<cr>
-
" }}}
" MacVim ---------------------------------------------------------------------- {{{
--- a/vim/colors/molokai.vim Thu Feb 10 17:11:26 2011 -0500
+++ b/vim/colors/molokai.vim Thu Feb 17 15:23:03 2011 -0500
@@ -68,8 +68,9 @@
hi Question guifg=#66D9EF
hi Repeat guifg=#F92672 gui=bold
hi Search guifg=#FFFFFF guibg=#455354
+
" marks column
-hi SignColumn guifg=#A6E22E guibg=#1B1D1E
+hi SignColumn guifg=#A6E22E guibg=#151617
hi SpecialChar guifg=#F92672 gui=bold
hi SpecialComment guifg=#465457 gui=bold
hi Special guifg=#66D9EF guibg=bg gui=italic
@@ -93,7 +94,7 @@
hi Type guifg=#66D9EF gui=none
hi Underlined guifg=#808080 gui=underline
-hi VertSplit guifg=#808080 guibg=#080808 gui=bold
+hi VertSplit guifg=#AAAAAA guibg=#151617 gui=none
hi VisualNOS guibg=#403D3D
hi Visual guibg=#403D3D
hi WarningMsg guifg=#FFFFFF guibg=#333333 gui=bold
--- a/vim/ftplugin/python/folding.vim Thu Feb 10 17:11:26 2011 -0500
+++ b/vim/ftplugin/python/folding.vim Thu Feb 17 15:23:03 2011 -0500
@@ -64,7 +64,7 @@
let line = substitute(line, '\t', onetab, 'g')
let line = strpart(line, 0, windowwidth - 2 -len(foldedlinecount))
- let fillcharcount = windowwidth - len(line) - len(foldedlinecount) - 4
+ let fillcharcount = windowwidth - len(line) - len(foldedlinecount)
return line . '…' . repeat(" ",fillcharcount) . foldedlinecount . '…' . ' '
endfunction
--- a/vim/sadness/bike/AUTHORS Thu Feb 10 17:11:26 2011 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,24 +0,0 @@
-Authors
--------
-
-Phil Dawes <pdawes@users.sourceforge.net> - Current Maintainer
- and Main Author
-Shae Erisson <shae@lapland.fi> - Original Maintainer
-
-
-The following people have contributed code, bugfixes and patches:
-
-Jürgen Hermann <jh@web.de>
-Canis Lupus
-Syver Enstad <syver-en@online.no> Windows emacs patches
-Mathew Yeates <mathew@comma.jpl.nasa.gov> VIM support and bug fixes
-Marius Gedminas <mgedmin@delfi.lt> More VIM support
-François Pinard <pinard@iro.umontreal.ca> Pymacs + help with
- emacs integration
-Ender <ender@objectrealms.net>
-Jonathan <jonathan@infogen.net.nz>
-Steve <thepindropper@yahoo.com.au>
-Peter Astrand <peter@cendio.se>
-
-See ChangeLog for more details.
-
--- a/vim/sadness/bike/COPYING Thu Feb 10 17:11:26 2011 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,32 +0,0 @@
-COPYRIGHT AND PERMISSION NOTICE
-
-Copyright (c) 2000 by Shae Erisson <shae@lapland.fi>
-Copyright (c) 2001 by Phil Dawes <pdawes@users.sourceforge.net>
-
-All rights reserved.
-
-Permission is hereby granted, free of charge, to any person obtaining a
-copy of this software and associated documentation files (the
-"Software"), to deal in the Software without restriction, including
-without limitation the rights to use, copy, modify, merge, publish,
-distribute, and/or sell copies of the Software, and to permit persons
-to whom the Software is furnished to do so, provided that the above
-copyright notice(s) and this permission notice appear in all copies of
-the Software and that both the above copyright notice(s) and this
-permission notice appear in supporting documentation.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
-OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
-OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
-HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL
-INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING
-FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
-NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
-WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
-Except as contained in this notice, the name of a copyright holder
-shall not be used in advertising or otherwise to promote the sale, use
-or other dealings in this Software without prior written authorization
-of the copyright holder.
-
--- a/vim/sadness/bike/ChangeLog Thu Feb 10 17:11:26 2011 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,2034 +0,0 @@
-2004-02-18 Phil Dawes <pdawes@users.sourceforge.net>
-
- * bike/query/getTypeOf.py: Added feature to
- resolveImportedModuleOrPackage that searches the package hierarchy
- of the scope even if it isn't in the pythonpath.
-
-2004-02-11 Phil Dawes <pdawes@users.sf.net>
-
- * bike/query/getTypeOf.py: rewrote resolveImportedModuleOrPackage
- to use purely getModuleOrPackageUsingFQN searches. (doesnt use
- getTypeOf Root searching any more)
-
- * bike/query/common.py: rewrote getLogicalLine to handle
- multilines that parse seperately. (But was submitted by Peter
- Astrand)
-
-2004-02-10 Phil Dawes <pdawes@users.sourceforge.net>
-
- * bike/query/getTypeOf.py: Added functionality to search from the
- current directory if looking for an import and scope is a module
-
-2004-02-10 Phil Dawes <pdawes@users.sourceforge.net>
-
- * bike/refactor/moveToModule.py: Added handling of individual
- 'from a.foo import theFunction'.
-
- * bike/parsing/fastparserast.py: Added Peter Astrand's patch to
- fix following bug:
- 'Find-References (and probably others) fails if there is more
- whitespace than a single space between the "class"/"def" keyword
- and the class/def name.'
-
- * bike/query/common.py: fixed bug in just-written-code where no
- dest in Printnl causes npe.
-
- * bike/query/common.py: Fixed a bug in MatchFinder. Printnl ast
- nodes (print >>foo, bah) look at there children the opposito way
- to the way the text comes. (i.e. they do visit(bah), visit(foo) in
- the example above). Wrote code to get round this.
-
-2004-02-09 Phil Dawes <pdawes@users.sourceforge.net>
-
- * bike/refactor/moveToModule.py: added more functionality to
- moveFunction
-
- * bike/bikefacade.py: added expanduser to normalizeFilename so
- that ~/src/foo gets turned into a proper full path.
-
- * bike/bikefacade.py: exposed moveClassToNewModule.
-
- * bike/refactor/moveClass.py: started move-class-to-new-module
- refactoring.
-
-2004-02-05 Phil Dawes <pdawes@users.sourceforge.net>
-
- * bike/parsing/pathutils.py: new module containing all the
- functions that search all the files in the pythonpath.
-
- * bike/parsing/extended_ast.py: Removed this module. SourceFile is
- now in load.py, the rest is in fastparserast.py
-
- * ide-integration/BicycleRepairMan_Idle.py : Added patch from
- Steve <thepindropper@yahoo.com.au> to allow easier saving of files
- before refactoring in IDLE
-
-2004-02-04 Phil Dawes <pdawes@users.sourceforge.net>
-
- * bike/parsing/extended_ast.py: lots of cleanup. Renamed Source
- class to SourceFile. Slimmed down Package and Root. Am planning on
- removing this module completely, and moving the classes into other
- modules.
-
-
- * bike/refactor/extractVariable.py: refactored and removed
- extractLocalVariable_old
-
- * bike/refactor/extractMethod.py: refactored and removed
- extractMethod_old
-
- * bike/refactor/test_rename*.py: Removed the 'rename twice'
- tests. They are no longer applicable (since BRM saves to disk
- after each refactoring)
-
- * bike/transformer/: Moved save.py and undo.py into the
- transformer package
-
- * bike/parsing/newstuff.py: moved generatePackageDependencies into
- the parsing package, because it needs to be used by other modules
- in the parsing package.
-
-2004-02-03 Phil Dawes <pdawes@users.sourceforge.net>
-
- * bike/query/relationships.py: Added generatePackageDependencies
- which given a file in a package hierarchy, yields a list of
- external packages and modules used by the package.
-
- * bike/parsing/newstuff.py: Rewrote
- generateModuleFilenamesInPythonPath wrt new ref search scheme.
- Scheme: If the module you are searching from is in a package
- hierarchy, scan every module in the hierarchy, and the files in
- the directory above it (since they can reach the package without
- including it in PYTHONPATH).
- If the module is in a non-package directory, search in all files
- in the directory, and in any packages below that directory.
- N.B. this is in addition to directories in the PYTHONPATH.
-
-2004-02-02 Phil Dawes <pdawes@users.sourceforge.net>
-
- * bike/parsing/newstuff.py: Removed getRegexMatchesInPythonPath
-
- * bike/parsing/newstuff.py: Modified getSourceNodesContainingRegex
- to search the pythonpath + the set of python files in the
- directory above the root package of the current file. This should
- remove the requirement to add the root directory to the python
- path, and thus prevent BRM from finding references in other
- package structures.
-
- * bike/query/common.py: Removed scanASTSourceNodesForMatches and walkSourceNodes
-
- * bike/globals.py: Added True/False declaration for python 2.2
- back-compatibility.
-
-2004-01-26 Phil Dawes <pdawes@users.sourceforge.net>
-
- * bike/query/common.py: Added code to check for \ in a previous
- line when locating logical lines
-
-2004-01-25 Phil Dawes <pdawes@users.sourceforge.net>
-
- * bike/query/common.py: Added a test and fixed a bug that meant
- find-definitions from multiline statements wouldn't work if the
- braces were equalised on the following line.
- (thanks again to Detlev for reporting this bug)
-
-2004-01-14 Phil Dawes <pdawes@users.sourceforge.net>
-
- * bike/query/common.py: Added a test and fixed a bug that meant
- find-definitions from multiline statements wouldn't work.
- (thanks to Detlev for reporting this bug)
-
-2004-01-12 Phil Dawes <pdawes@users.sourceforge.net>
-
- * bike/parsing/load.py: Added Detlevs patch to not recurse into
- subversion directories.
-
-2004-01-11 Phil Dawes <pdawes@users.sourceforge.net>
-
- * bike/parsing/newstuff.py: Added code in
- generateModuleFilenamesInPythonPath to ensure each filename is
- generated once. (and added test to check for it)
- (Thanks to Detlev & Syver for this bug report)
-
- * bike/query/common.py (globalScanForMatches): Removed old
- ast-based code from globalScanForMatches
-
-2004-01-08 Phil Dawes <pdawes@users.sourceforge.net>
-
- * bike/query/getTypeOf.py: Fixed bug where 'from foo import aou'
- would cause an assert to fail if foo didn't exist. (Thanks Syver)
-
-2004-01-06 Phil Dawes <pdawes@users.sourceforge.net>
-
- * bike/bikefacade.py: Added code to normalize paths coming into
- BRM. (hopefully fixes Syver's problems on windows - Thanks Syver)
-
-
-2003-09-04 Phil Dawes <pdawes@users.sourceforge.net>
-
- * ide-integration/BicycleRepairMan_Idle.py: Fixed bug in
- Bicyclerepair_idle.
-
------------------------ 0.9 BETA4 -------------------------------
-
-2003-09-02 Phil Dawes <pdawes@users.sourceforge.net>
-
- * ide-integration/BicycleRepairMan_Idle.py: Fixed bug where brmctx
- was being tested for a __nonzero__ operator due to new wrapper
- stuff.
- Also made the matches window a singleton
-
- * bike/query/findReferences.py: Rewrote attribute reference
- finding algorithm to locate a possible match, and then check if
- the match class shares a common ancestor with the target. (rather
- than finding all classes in the target hierarchy and then testing
- each match class against the hierarchy).
- This results in a 10000%
-
-2003-09-02 Phil Dawes <pdawes@users.sourceforge.net>
-
- * bike/query/relationships.py: Added buildClassHierarchy
- functionality to guess a class hierarchy, but found that it's
- still much too slow to handle the wxpython class hierarchy of 1900
- odd classes under 1 root!
-
-
-2003-09-01 Phil Dawes <pdawes@users.sourceforge.net>
-
- * bike/parsing/fastparserast.py: Added maskedsrc to the cache
-
- * bike/query/getTypeOf.py: Added caching of type lookups
-
- * bike/bikefacade.py: Added a generic wrapper which purges the
- caches before and after each brm ctx call
-
-2003-08-31 Phil Dawes <pdawes@users.sourceforge.net>
-
- * bike/parsing/newstuff.py: Added simple caching mechanism for
- sourceNodes
-
-2003-08-30 Phil Dawes <pdawes@users.sourceforge.net>
-
- * bike/parsing/extended_ast.py: Removed some crufty methods and
- base classes for managing the ast tree hierarchy
-
- * bike/bikefacade.py: Removed a couple of ast related methods
-
- * bike/query/findReferences.py: Modified the findRefs
- functionality to exclude matches where the confidence is high that
- it's *not* the right type.
-
- * bike/parsing/load.py: removed the load function (and made
- necessary refactorings to remove it)
-
-2003-08-25 Phil Dawes <pdawes@users.sourceforge.net>
-
- * bike/bikefacade.py: Added setWarningLogger
-
-2003-08-25 Phil Dawes <pdawes@users.sourceforge.net>
-
- * bike/parsing/extended_ast.py: Fixed bug where "../.." was being
- added to sys.path. This was because extended_ast.py was adding
- importing setpath.py.
-
-2003-08-25 Phil Dawes <pdawes@users.sourceforge.net>
-
- * bike/bikefacade.py: Added warning code to print message if
- sys.path is changed by setpath.py
-
- * ide-integration/test/README: Added ide tests for inline and
- extract variable
-
- * bike/bikefacade.py: Removed the load() function, and fixed
- inline and extract local variable
-
------------------------ 0.9 BETA3 -------------------------------
-
-2003-08-22 Phil Dawes <pdawes@users.sourceforge.net>
-
- * bike/bikefacade.py: Fixed removeLibdirsFromPath to work with
- windows python lib directories
-
------------------------ 0.9 BETA2 -------------------------------
-
-2003-08-21 Phil Dawes <pdawes@users.sourceforge.net>
-
- * bike/*: Made it backward compatible with python 2.2
-
- * ide-integration/bike.vim: Adapted vim plugin to work with new
- api.
-
------------------------ 0.9 BETA1 -------------------------------
-
-2003-08-20 Phil Dawes <pdawes@users.sourceforge.net>
-
- * bike/test_*: Misc fixes for windows paths
-
- * ide-integration/BicycleRepairMan_Idle.py: Cleaned up error
- handling for undo stack
-
- * bike/query/*: Misc fixes for tests
-
- * bike/refactor/extractMethod.py: Updated to work with new
- non-tree system
-
-2003-08-19 Phil Dawes <pdawes@users.sourceforge.net>
-
- * bike/testutils.py: Converted createSourceNodeAt to create a
- directory structure rather than an ast. (and broke a load of tests)
-
-2003-08-18 Phil Dawes <pdawes@users.sourceforge.net>
-
- * bike/testutils.py: added test setup fixture to change directory
- before executing tests
-
-2003-08-17 Phil Dawes <pdawes@users.sourceforge.net>
-
- * bike/query/getTypeOf.py: Fixed bug which was stopping sub
- packages from being found properly
-
- * bike/query/relationships.py: Fixed getAllClassesInHierarchy and
- getAllDerivedClasses to work without AST. Uses a smart algorithm
- which scans the text of files with regexes for baseclassnames and
- import aliases to narrow down the likely candidates.
-
-
-2003-08-12 Phil Dawes <pdawes@users.sourceforge.net>
-
- * README.idle: Updated docs for python2.3/idlefork
-
-2003-08-11 Phil Dawes <pdawes@users.sourceforge.net>
-
- * ide-integration/BicycleRepairMan_Idle.py: Added code to just use
- 1 window for matches, and to reopen it if needed after it is closed
-
-2003-08-04 Phil Dawes <pdawes@users.sourceforge.net>
-
- * bike/parsing/load.py: Fixed bug which cause BRM to descend into
- non-package directorys
-
- * bike/parsing/extended_ast.py: Added a couple of new functions to
- handle pythonpaths for queries and refactorings
-
-2003-08-01 Phil Dawes <pdawes@users.sourceforge.net>
-
- * bike/query/common.py: modified globalScanForMatches to scan
- files in addition to walking the ast.
-
- * bike/query/findReferences.py: Added code to work with new
- stateless design.
-
-2003-07-31 Phil Dawes <pdawes@users.sourceforge.net>
-
- * bike/query/findDefinition.py: Removed module locating code from
- findDefinition, and made it use resolveImportedModuleOrPackage
- instead.
-
- * bike/query/getTypeOf.py: Modified resolveImportedModuleOrPackage
- to use the newstuff function getModuleOrPackageUsingFQN if it cant
- locate the module in the AST tree.
-
- * bike/parsing/newstuff.py: modified getModuleUsingFQN
- to handle packages. renamed to getModuleOrPackageUsingFQN
-
-2003-07-25 Phil Dawes <pdawes@users.sourceforge.net>
-
- * bike/query/findDefinition.py: Made necessary modifications
- enable finding of function definitions without importing code
- (uses the python path to determine where to look). Doesnt work for
- methods yet.
-
-2003-07-10 Phil Dawes <pdawes@users.sourceforge.net>
-
- * bike/refactor/inlineVariable.py: Applied Jonathan's patch which
- fixes bug when multiple instances of a variable are on one line.
-
-2003-06-12 Phil Dawes <pdawes@users.sourceforge.net>
-
- * bike/query/findReferences.py: changed findReferences interface
- to take a filename instead of a srcnode
-
- * bike/query/findReferences.py: Fixed bug where error wasnt being
- reported properly
-
-2003-06-11 Phil Dawes <pdawes@users.sourceforge.net>
-
- * bike/query/findReferences.py: renamed findReferences to
- findReferences_old, and created a new findReferences which takes a
- filename instead of the srcnode
-
- * bike/bikefacade.py: Removed getFullyQualifiedNameOfScope - it's
- not used anywhere, and relies on the fqn stuff working.
-
- * all tests: attempted to remove all usage of fqn from
- tests. Instead, replaced with name and filename tests. This is
- because fqn is one of the major things binding the scopes
- together.
-
- * bike/bikefacade.py: removed getTypeOfExpression. It's not used
- anywhere. Will reinstate when it is required again.
-
- * bike/query/getTypeOf.py: Fixed bug where a recursive function
- could cause BRM to stack overflow
-
-2003-06-10 Phil Dawes <pdawes@users.sourceforge.net>
-
- * bike/query/getTypeOf.py: Added resolveImportedModuleOrPackage fn
- to try and split the number of calls to getTypeOf()
-
- * bike/query/getTypeOf.py: Fixed bug where a[0].theMethod() would
- cause brm to barf.
-
- * bike/parsing/fastparserast.py: Beefed up the __str__ members for
- fastparser nodes
-
-2003-06-06 Phil Dawes <pdawes@users.sourceforge.net>
-
- * bike/parsing/output.py: Removed output.py. (functionality now in
- save.py)
-
-2003-06-05 Phil Dawes <pdawes@users.sourceforge.net>
-
- * bike/refactor/extractMethod.py: removed the ismodified stuff, in
- an attempt to make the xast hierarchy a read-only resource.
- Added a hook in save.py to update the xast whenever somebody
- queues an update to be saved.
-
- * bike/parsing/save.py: Added new save module which maintains its
- own queue of src to be written back to disk. Replaces output.py
-
-2003-05-30 Phil Dawes <pdawes@users.sourceforge.net>
-
- * bike/parsing/undo.py (UndoStack.undo): refactored to use dictionary
-
- * bike/query/findDefinition.py: Refactored main function to have a
- 'stateless' interface (i.e. no need to pass a context).
- findAllPossibleDefinitionsByCoords(filepath,lineno,col)
-
-2003-05-29 Phil Dawes <pdawes@users.sourceforge.net>
-
- * bike/parsing/extended_ast.py (getRoot): Made the Root object a
- singleton. Use the getRoot() method to get it. This is an
- intermediate step in making the parser stateless. (idea is to make
- it pretend to be stateless by being a singleton, then once the
- interfaces have changed, transition the parser code to actually
- make it stateless)
-
-2003-04-02 Phil Dawes <pdawes@users.sourceforge.net>
-
- * ide-integration/bikeemacs.py: Added exception catching and error
- reporting to bike-emacs integration
-
-2003-03-31 Phil Dawes <pdawes@users.sourceforge.net>
-
- * Applied Jonathan's patches
- - InlineVariable handles multiline statements
- - Fix to bike vim integration
-
-2003-03-31 Marius Gedminas <mgedmin@delfi.lt>
-
- * ide-integration/bike.vim: Removed unnecessary argument
- to BikeRename().
-
- * bike/query/common.py: Fixed handling of lambdas in MatchFinder.
-
-2003-03-17 Phil Dawes <pdawes@users.sourceforge.net>
-
- * bike/refactor/extractVariable.py: Made a start on the
- extract-local-variable refactoring
-
-2003-03-13 Phil Dawes <pdawes@users.sourceforge.net>
-
- * bike/refactor/inlineVariable.py: Made a start on the
- inline-local-variable refactoring
-
------------------------ 0.8 BETA2 -------------------------------
-
-2003-03-11 Phil Dawes <pdawes@users.sourceforge.net>
-
- * ide-integration/BicycleRepairMan_Idle.py: Fixed bug where
- paths with spaces meant that you couldn't select a reference when
- doing a findReferences. (Thanks to Andy Bulka for the report)
-
- * bike/query/getTypeOf.py: Added infinite recursion protection to
- getTypeOf
-
- * bike/query/relationships.py: Added some performance improving
- code when searching for a classhierarchy. Rather than doing a
- getTypeOf() on every base class, it finds the strings likely to be
- base classes (i.e. the name of the base class, and any 'import
- name as foo' lines) to narrow the search.
-
-2003-03-10 Phil Dawes <pdawes@users.sourceforge.net>
-
- * bike/refactor/extractMethod.py: Fixed bug in extract method,
- where blank lines were messing up the indentation in the resultant
- block
-
-
------------------------ 0.8 BETA1 -------------------------------
-
-2003-03-10 Phil Dawes <pdawes@users.sourceforge.net>
-
- * ide-integration/bikeemacs.py: Fixed bug in brm with emacs on
- windows, where the mark can be active and nil at the same time.
-
- * bike/bikefacade.py (BRMContext_impl.load): Fixed bug which
- affected windows users. Path needs to be saved after it's been
- normalized.
-
-2003-03-06 Phil Dawes <pdawes@users.sourceforge.net>
-
- * bike/query/findDefinition.py: fixed bug in attribute finding
- code - was only searching the first function
-
- * bike/query/getTypeOf.py: Fixed bug where x = x.bah() would cause
- recursion error. (just catches the stack overflow)
-
-2003-03-05 Phil Dawes <pdawes@users.sourceforge.net>
-
- * bike/*: implemented automatic importing of changed files. This
- means that ide integration stuff no longer has to import code into
- brm whenever it is saved.
-
-2003-02-25 Phil Dawes <pdawes@users.sourceforge.net>
-
- * ide-integration/bike.vim: Consolidated RenameMethod,
- RenameFunction and RenameClass into 1 menu option. This is because
- brm now supports renaming of variables and attributes and I didn't
- want to add another 2 menu items.
-
-
-2003-02-24 Phil Dawes <pdawes@users.sourceforge.net>
-
- * ide-integration/bikeemacs.py: Fixed rename 'prompt'
- bug. Consolidated all the rename stuff into 1 menu option.
-
-2003-02-19 Phil Dawes <pdawes@users.sourceforge.net>
-
- * bike/query/*: removed getReferencesToClass/Function/Method and
- replaced with findReferences
-
-2003-02-13 Phil Dawes <pdawes@users.sourceforge.net>
-
- * bike/query/findReferences.py: Added findReferencesIncludingDefn
- and made 'vanilla' findReferences not return the definition. This
- paves the way for a unified rename that can be used to rename
- anything.
-
-2003-02-11 Phil Dawes <pdawes@users.sourceforge.net>
-
- * bike/query/findDefinition.py: Fixed bug reported by Marius - if
- class is declared in __init__.py, it blows up.
-
- * bike/query/findReferences.py: Fixed bugs in
- 'getDefinitionAndScope' logic, so can handle nested classes etc..
-
-2003-02-10 Phil Dawes <pdawes@users.sourceforge.net>
-
- * bike/query/getReferencesToClass.py: Replaced module logic
- with call to findReferences()
-
- * tests: modified or removed tests that tested for the erroneous
- 'import a.b.bah.TheClass'. (A class or function can't be imported
- - only a module)
-
-2003-01-24 Marius Gedminas <mgedmin@delfi.lt>
-
- * ide-integration/bike.vim: Show the line itself after finding
- references/definition.
-
-2003-01-23 Marius Gedminas <mgedmin@delfi.lt>
-
- * bike/query/common.py: Fixed a trivial NameError in
- MatchFinder.visitGlobal().
-
-2003-01-23 Phil Dawes <pdawes@users.sourceforge.net>
-
- * bike/query/getTypeOf.py: Refactored and cleaned up the code in
- this module.
-
-2003-01-22 Marius Gedminas <mgedmin@delfi.lt>
-
- * bike/query/common.py: Fixed another ValueError, this time on
- "from foo import bar" lines.
-
-2003-01-20 Marius Gedminas <mgedmin@delfi.lt>
-
- * bike/query/common.py, bike/query/findDefinition.py,
- bike/query/findReferences.py: Fixed ValueError: list.index(x): x not
- in list" error caused by several visitFunction methods visiting
- their child nodes (argument names and default values) out-of-order.
-
-2003-01-16 Marius Gedminas <mgedmin@delfi.lt>
-
- * bike/refactor/extractMethod.py: Now puts spaces after commas in
- generated code.
-
-2003-01-15 Marius Gedminas <mgedmin@delfi.lt>
-
- * ide-integration/bike.vim: Better load failure diagnostics.
-
-2003-01-14 Marius Gedminas <mgedmin@delfi.lt>
-
- * bike/bikefacade.py, bike/parsing/fastparserast.py,
- ide-integration/BicycleRepairMan_Idle.py: CRLF -> LF translation
-
-2003-01-13 Marius Gedminas <mgedmin@delfi.lt>
-
- * bike/bikefacade.py: Added a function to check whether a given file
- was ever imported.
-
- * bike/test_bikefacade.py: Unit test for the above.
-
- * ide-integration/bike.vim: Added code to watch for modified files
- and reimport them into if they had been imported previously.
-
-2003-01-13 Phil Dawes <pdawes@users.sourceforge.net>
-
- * bike/query/getReferencesToModule.py: Added Ender's
- getReferencesToModule module (and test module)
-
-2003-01-10 Phil Dawes <pdawes@users.sourceforge.net>
-
- * bike/query/findDefinition.py: Added some find class attribute
- definition functionality
-
-2003-01-09 Phil Dawes <pdawes@users.sourceforge.net>
-
- * bike/query/findDefinition.py: fixed bug where 'import'
- statements in fn scopes weren't being searched
-
- * ide-integration/bike.vim: Modified Marius' bike.vim vi
- integration to support new rename and findReferences calls.
-
-2003-01-06 Phil Dawes <pdawes@users.sourceforge.net>
-
- * ide-integration/bikeemacs.py: Added fix to redisplay frame in
- emacs, and to test for mark correctly in emacs.
-
-2003-01-05 Phil Dawes <pdawes@users.sourceforge.net>
-
- * AUTHORS: Added Mathew and Marius
-
-2003-01-03 Phil Dawes <pdawes@users.sourceforge.net>
-
- * README.emacs: Added simple instructions for installing pymacs.
-
- * ide-integration/Pymacs-0.20: I'm going to ship pymacs-0.20 with
- bicyclerepairman. I've modified it a little to make installation
- easier.
-
- * ide-integration/bikeemacs.py: Moved bikeemacs back to its
- original place.
-
-
-2003-01-02 Phil Dawes <pdawes@users.sourceforge.net>
-
- * bike/parsing/extended_ast.py: Cleaned this up a bit
-
- * bike/parsing/fastparser.py: Fixed bug reported by Mathew Yeates
- where more than one space between 'class' and the name foxed the
- parser.
-
-2002-12-22 Phil Dawes <pdawes@users.sourceforge.net>
-
- * bike/query/findReferences.py: Started work on unified
- findReferences code. (uses findDefinition to compare matches)
-
- * ide-integration/emacs/bikeemacs.py: Rewrote emacs integration
- using the excellent pymacs package
-
-2002-12-09 Phil Dawes <pdawes@users.sourceforge.net>
-
- * ide-integration/BicycleRepairMan_Idle.py: Fixed findDefinition
- cosmetic bug
-
- * ide-integration/bike.el, bikeemacs: Added Syver Enstad's patch
- for allowing filenames with spaces
-
-2002-12-06 Phil Dawes <pdawes@users.sourceforge.net>
-
- * ide-integration/BicycleRepairMan_Idle.py: Completed support for
- findDefinition
-
- * ide-integration/bike.el: added code to handle the fact that if
- you select a region, the point is one greater than the end of the
- region and so misses it.
-
-2002-12-03 Phil Dawes <pdawes@users.sourceforge.net>
-
- * bike/query/findDefinition.py: Added code to scan for other
- method matches after locating the 100% one
-
-2002-12-02 Phil Dawes <pdawes@users.sourceforge.net>
-
- * ide-integration/BicycleRepairMan_Idle.py: Added basic
- finddefinition support to idle
-
- * ide-integration/bikeemacs.py: Added finddefinition support to xemacs
-
- * bike/bikefacade.py: Exposed findDefinition through bikefacade
-
- * bike/query/findDefinition.py: Added new query interface for
- finding the definition of a reference, given its line/col position
- in a module. Just supports function, method, and class references
- for now.
-
----------------------- 0.7 ---------------------------------------
-
-2002-11-27 Phil Dawes <pdawes@users.sourceforge.net>
-
- * ide-integration/bike.el: Fixed bug where saving buffers caused
- the new emacs protocol to get in a tangle. My solution was to add
- a disableMessages capability
-
----------------------- 0.7RC3 ------------------------------------
-
-2002-11-22 Phil Dawes <pdawes@users.sourceforge.net>
-
- * ide-integration/bikeemacs.py: Added acknowledgement protocol, to
- get round synchronisation problems in windows emacs
-
-2002-11-20 Phil Dawes <pdawes@users.sourceforge.net>
-
- * bike/parsing: decommissioned addtypeinfo, typeinfo, tokenutils,
- tokenhandler, matchTokensToAST, doublelinkedlist, testdata
-
- * bike/query/getReferencesToClass.py: Fixed bug where
- 'from foo import *' would cause an exception if searching for a
- class called 'foo'
-
- * bike/*/test_*.py: Removed dependency on brmtransformer.
-
-2002-11-15 Phil Dawes <pdawes@users.sourceforge.net>
-
- * bike/refactor/extractMethod.py: Rewrote extract method module to
- use all the new cool stuff (and operate or strings). Doesnt use
- linked lists, iterators, tokens, brmtransformer or any of that
- shite any more.
-
-2002-11-11 Phil Dawes <pdawes@users.sourceforge.net>
-
- * bike/query/getTypeOf.py: Fixed bug where classscope was being
- searched if the name wasnt found in methodscope. This is incorrect
- because class scope isn't visible except through 'self' or a fully
- qualified classname.
-
-2002-11-10 Phil Dawes <pdawes@users.sourceforge.net>
-
- * bike/query/common.py: Re-wrote MatchFinder to scan along the
- source code text when visiting ast nodes. This removes the need to
- match tokens in order to find the source code location of an ast
- node.
-
----------------------- 0.7RC1 ------------------------------------
-
-
-2002-11-01 Phil Dawes <pdawes@users.sourceforge.net>
-
- * bike/query/relationships.py: Added performance enhancement to
- getAllDerivedClasses. Now does string search on file before ast
- searching the classes.
-
-2002-10-30 Phil Dawes <pdawes@users.sourceforge.net>
-
- * ide-integration/BicycleRepairMan_Idle.py: Finished
- findReferencesByCoordinates support in idle.
-
-2002-10-29 Phil Dawes <pdawes@users.sourceforge.net>
-
- * ide-integration/BicycleRepairMan_Idle.py: Added trace
- console. Started integration of findReferencesByCoordinates into
- idle.
-
- * ide-integration/bike-emacs.py: Added xemacs support for
- getFullyQualifiedNameOfScope, getTypeOfExpression and
- findReferencesByCoordinates
-
-
-2002-10-28 Phil Dawes <pdawes@users.sourceforge.net>
-
- * bike/bikefacade.py: Added getFullyQualifiedNameOfScope,
- getTypeOfExpression and findReferencesByCoordinates
-
-2002-10-08 Phil Dawes <pdawes@users.sourceforge.net>
-
- * bike/bikefacade.py: changed promptForRename callback signature
- to be linenumbers and columnnumbers
-
- * bike/refactor/renameMethod.py: Added prompt
- functionality.
-
-2002-10-02 Phil Dawes <pdawes@users.sourceforge.net>
-
- * bike/query/getTypeOf.py: Added functionality to handle scanning
- for types of references (needed by getReferencesToMethod)
-
- * bike/query/getReferencesToMethod.py: Implemented to use
- common.py stuff
-
-2002-09-30 Phil Dawes <pdawes@users.sourceforge.net>
-
- * bike/query/common.py: Split out common query code into common.py
-
-2002-09-27 Phil Dawes <pdawes@users.sourceforge.net>
-
- * bike/refactor/renameFunction.py: Now uses the getReferences stuff
-
-2002-09-26 Phil Dawes <pdawes@users.sourceforge.net>
-
- * bike/transformer/WordRewriter.py: Split this class out of the
- renameClass module.
-
- * bike/transformer: Added new transformer package to contain code
- which rewrites the internal representation of the sourcecode
-
- * bike/bikefacade.py: Implemented locateNode to use the new
- fastparserast stuff.
-
- * bike/parsing/extended_ast.py: Added code to set fqn (fully
- qualified name) attributes on the fastparser ast
-
-2002-09-25 Phil Dawes <pdawes@users.sourceforge.net>
-
- * bike/refactor/renameClass.py: Finished modification to use
- getReferencesToClass.
-
-2002-09-06 Phil Dawes <pdawes@users.sourceforge.net>
-
- * bike/query/getTypeOf.py: Refactored getType() functionality out
- of ast classes and into a query module.
-
- * bike/parsing/fastparser.py: Added parsing of import and from
- lines to fastparser, and optimised a little.
-
-2002-09-04 Phil Dawes <pdawes@users.sourceforge.net>
-
- * bike/refactor/renameClass.py: Started modification to use
- getReferencesToClass.
-
-2002-08-30 Phil Dawes <pdawes@users.sourceforge.net>
-
- * bike/query/getReferencesToClass.py: New module which returns a
- sequence of references to a class
-
- * bike/parsing/fastparser.py: Wrote new parser which builds a tree
- of functions and classes, very quickly.
-
-2002-08-14 Phil Dawes <pdawes@users.sourceforge.net>
-
- * bike/parsing/tokenutils.py: Fixed bug where attempting to
- tokenize small strings would result in attributeerror
-
-2002-08-05 Phil Dawes <pdawes@users.sourceforge.net>
-
- * bike/logging.py: Logging module. Eventually will be replaced by
- import logging, but for now is a copy of the code by Vinay Sajip
- (to save people from having to download the module)
-
- * bike/parsing/brmtransformer.py: Added simple fix - tuple being
- concatinated to list was causing problems
-
-
----------------------- 0.6.7 ------------------------------------
-
-2002-07-31 Phil Dawes <pdawes@users.sourceforge.net>
-
-
- * ide-integration/BicycleRepairMan_Idle.py: Added Canis fix for
- the bug which stopped brm from displaying the menu when starting
- idle via right-click file.
-
- * bike/bikefacade.py: Added Canis windows compatability fix for
- dealing with .pyw files
-
-
-2002-07-25 Phil Dawes <pdawes@users.sourceforge.net>
-
- * bike/refactor/extractMethod.py: Fixed bug where extracting an
- expression from a line just below a block opener (e.g. if foo:)
- would cause a parse error.
-
-2002-07-21 Phil Dawes <pdawes@users.sourceforge.net>
-
- * README.idle: Doc about problems on windows
-
----------------------- 0.6.6 ------------------------------------
-
-2002-07-19 Phil Dawes <pdawes@users.sourceforge.net>
-
- * bike/parsing/doublelinkedlist.py: Optimised to use a list rather
- than a class instance for each link element.
-
-2002-07-17 Phil Dawes <pdawes@users.sourceforge.net>
-
- * bike/parsing/typeinfo.py: Fixed bug - package wasn't checking
- parent packages (and Root) for types. This meant that modules
- imported from higher up the tree weren't being found.
-
- * bike/parsing/extended_ast.py: Renamed 'Top' to 'Root'
-
----------------------- 0.6.5 ------------------------------------
-
-2002-07-15 Phil Dawes <pdawes@users.sourceforge.net>
-
- * ide-integration/bike.el: Minor bug fix
-
-2002-07-12 Phil Dawes <pdawes@users.sourceforge.net>
-
- * ide-integration/bikeemacs.py: Added code so that it waits for
- buffer to be reloaded in emacs before sending the request to
- update the next one.
-
- * ide-integration/bike.el: Added bug fix - if prompt for rename
- was on file not loaded, emacs would send a message back to brm
- when it ran find-file, which buggered up the 'rename-this-method?'
- interaction.
-
-2002-07-11 Phil Dawes <pdawes@users.sourceforge.net>
-
- * ide-integration/bike.el: Added support for GNU emacs
-
- * README.emacs: renamed from README.xemacs
-
- *
-
-2002-07-09 Phil Dawes <pdawes@users.sourceforge.net>
-
- * bike/bikefacade.py: Added code to handle more windows filename
- brokenness
-
-2002-07-05 Phil Dawes <pdawes@users.sourceforge.net>
-
- * bike/refactor/renameMethod.py: Added same optimisation to
- renameMethod.
-
- * bike/refactor/renameClass.py: Added optimisation: source string
- is scanned for classname before visiting ast. (with the lazy ast
- creation this means that files aren't parsed unless they contain
- the keyword (or are linked to the source via function call).
-
- * bike/parsing/extended_ast.py: Refactored .source member into
- .getSource() method and implemented so that tokens are
- synchronised with source if they're modified.
-
-2002-07-03 Phil Dawes <pdawes@users.sourceforge.net>
-
- * bike/parsing/extended_ast.py: Added lazy parsing of ast when
- source.getModule() is called.
-
- * bike/parsing/typeinfo.py: Added PackageTypeInfo which deduces
- child types by interrogating the package rather than relying on
- children to register themselves in the typeinfo. This was required
- to facilitate lazy parsing of ast. (since parse would have had to
- be done to add module node to package). A lookup of a module now
- causes getModule() to be called on the sourcefile, thus triggering
- parse of source into ast.
-
----------------------- 0.6.4 ------------------------------------
-
-2002-06-27 Phil Dawes <pdawes@users.sourceforge.net>
-
- * bike/parsing/tokenutils.py: Added bug fix for superflous
- brackets. Basically, if brackets are unecessary (e.g. '(a).foo()')
- then they aren't in the parse tree but are in the token
- stream. This buggers up the token matching.
- This fix just ignores unmatching ')'s. It was the simplist thing
- that could possibly work, but may cause problems later - needs
- lots of testing.
-
----------------------- 0.6.3 ------------------------------------
-
-2002-06-26 Phil Dawes <pdawes@users.sourceforge.net>
-
- * bike/parsing/tokenhandler.py: Fixed bug where getattr renamed
- all occurences of the methodattr in the rest of the tokens
-
-2002-06-21 Phil Dawes <pdawes@users.sourceforge.net>
-
- * bike/refactor/extractMethod.py: Fixed bug where commend before
- the extracted block would make brm think it should be extracting
- an expression rather than a block.
-
- * bike/parsing/addtypeinfo.py: Fixed the same bug in _getImportedType
-
- * bike/refactor/renameClass.py: Fixed bug where the module search
- routine in the 'From foo import *' code was using the parent scope
- as the search position. This doesnt work if 'from' is nested in a
- class since parent scope is a module, not a package. Added method
- _getParentPackage() to handle this correctly.
-
-2002-06-13 Phil Dawes <pdawes@users.sourceforge.net>
-
- * bike/refactor/extractMethod.py: Fixed the 'loop' bug. extract
- method will now recognise variables assigned to by the extracted
- function and used in a loop by the calling function.
-
-2002-06-12 Phil Dawes <pdawes@users.sourceforge.net>
-
- * bike/refactor/extractMethod.py: Lots of refactoring prior to
- fixing a bug.
-
-2002-06-10 Phil Dawes <pdawes@users.sourceforge.net>
-
- * bike/parsing/doublelinkedlist.py: Rewrote 'insert' so that it
- doesnt move the iterator. Renamed old method to
- insertAndPositionIteratorOnNewElement.
-
-2002-06-07 Phil Dawes <pdawes@users.sourceforge.net>
-
- * bike/refactor/extractMethod.py: Fixed the parse error when
- extracting code from an if...else... block. The problem was that
- the code below the extraction contained the 'else', but not the
- 'if'. This is hacked around by inserting an 'if 1: <indent>
- pass'. This seems to work, but I welcome a better way of handling
- this.
-
- * bike/parsing/output.py: Added code to ensure that indent never
- dips below 0. This fixes a bug in parsing during method extracts
- out of nested blocks.
-
- * bike/refactor/extractMethod.py: Fixed the 'don't know what type
- this isAssAttr(Name('item'), 'decl', 'OP_ASSIGN')' bug
-
----------------------- 0.6 --------------------------------------
-
-2002-05-28 Phil Dawes <pdawes@users.sourceforge.net>
-
- * ide-integration/test/*: Added manual test script for testing ide
- integration before a release
-
- * ide-integration/BicycleRepairMan_Idle.py: Now imports code into
- brm when loaded, or saved for the first time.
-
- * ide-integration/bike.el: Now imports all loaded python files
- into brm. Also checks to see if file was just updated to avoid
- superflous reloads.
-
-2002-05-27 Phil Dawes <pdawes@users.sourceforge.net>
-
- * ide-integration/bike.el: Added menu for brm
-
- * bike/parsing/undo.py: Added an internal undo buffer size
-
- * ide-integration/BicycleRepairMan_Idle.py: Added generic
- exception reporting to idle
-
- * ide-integration/bikeemacs.py: Added generic exception
- reporting. All exceptions are handled and reported back to the
- user.
-
-2002-05-24 Phil Dawes <pdawes@users.sourceforge.net>
-
- * ide-integration/BicycleRepairMan_Idle.py: Exposed undo to idle
-
- * ide-integration/bikeemacs.py: Exposed undo to emacs
-
- * bike/bikefacade.py: Exposed undo functionality to facade
-
- * bike/parsing/undo.py: Added undo functionality
-
-2002-05-15 Phil Dawes <pdawes@users.sourceforge.net>
-
- * bike/refactor/test_extractMethod.py: Fixed bug in expression
- extracting code (which caused a parse exception with correct code)
-
- * bike/bikefacade.py: Added public interface
-
----------------------- 0.5 --------------------------------------
-
- * ide-integration: Created new directory for integration modules
-
-2002-05-14 Phil Dawes <pdawes@users.sourceforge.net>
-
- * bike/ui/BicycleRepairMan_Idle.py: Exposed extract function to idle
-
- * bike/ui/bikeemacs.py: Exposed extract function to emacs
-
- * bike/refactor/extractMethod.py: Added support for extracting
- expressions into methods (e.g. a = 1+2 -> a = self.oneplustwo())
- Added support for extracting functions.
-
-2002-05-13 Phil Dawes <pdawes@users.sourceforge.net>
-
- * bike/refactor/extractMethod.py: Extract Method pretty much
- finished. Now on with the testing...
-
-2002-05-03 Phil Dawes <pdawes@users.sourceforge.net>
-
- * bike/ui/BicycleRepairMan_Idle.py: Added extract method support
- for idle
-
-2002-05-02 Phil Dawes <pdawes@users.sourceforge.net>
-
- * bike/ui/bike.el: implemented extract-method for emacs
-
- * bike/bikefacade.py: Exposed extract-method to the outside world
-
-
-2002-05-01 Phil Dawes <pdawes@users.sourceforge.net>
-
- * bike/refactor/extractMethod.py: Implemented simple extract
- method
-
-2002-04-28 Phil Dawes <pdawes@users.sourceforge.net>
-
- * bike/parsing/matchTokensToAST.py: The 'new' addtokens. Instead
- of each AST node getting its own slice of tokens, there is only
- one token list and each node has 2 linked list iterators pointing
- to the start and end of its tokens in within it.
- Thus the process of calculating the position of these iterators is
- now called 'token matching' rather than 'adding tokens to ast'.
-
- Having only 1 token stream vastly simplifies things. There are no
- consistency problems when renaming or moving tokens, and no need
- to 'divide' the comments amongst the AST nodes.
- This enables one matching algorithm to be able to cater for all
- ast nodes without specialized logic.
-
- * bike/parsing/vector.py, bike/parsing/doublelinkedlist.py:
- containers which support the same bi-directional iterator
- interface. Used in refactoring the parsing module to use a linked
- list of tokens
-
-2002-04-12 Phil Dawes <pdawes@users.sourceforge.net>
-
- * bike/bikefacade.py: Removed use of tokens
-
----------------------- 0.4.3 ------------------------------------
-
-2002-04-11 Phil Dawes <pdawes@users.sourceforge.net>
-
- * bike/ui/BicycleRepairMan_Idle.py: fixed import problem in
- windows
-
- * bike/parsing/load.py: Added code so that if you select a
- directory it will load all the modules and packages in it even if
- it isnt a package (i.e. doesnt have a __init__.py), but would
- recurse into non-package sub directories.
-
- * bike/ui/*: This is no longer a package, since the only 2 files
- are installed elsewhere.
-
- * setup.py: Made BicycleRepairMan_Idle.py a root level
- module. This means it can be used with idle by just adding
- [BicycleRepairMan_Idle] to your .idle file.
-
-
-2002-04-06 Phil Dawes <pdawes@users.sourceforge.net>
-
- * bike/parsing/addtokens.py: Addtokens class now takes tokens in
- constructor. The addTokens function is renamed to
- addTokensToASTFromSrc. This will pave the way for Source nodes to
- hold tokens rather than the source as a string
-
- * bike/parsing/tokenhandler.py: Fixed bug which caused name ast
- node to not be tokenized
-
- * bike/parsing/load.py: Added check for __init__.py before
- recursing into sub directories. This means that non-package sub
- directories will not be recursed into. (i.e. the user must load
- those seperately)
-
-
-2002-03-29 Phil Dawes <pdawes@users.sourceforge.net>
-
- * NEWS: consolidated all README-version files into one NEWS file
-
- * README*: updated documentation
-
- * bike/ui/BicycleRepairMan_Idle.py: Fixed another windows filename
- isnt normalized bug
-
- * bike/ui/bike.el: Added same functionality as for idle
-
- * bike/ui/BicycleRepairMan_Idle.py: Added load on save
- functionality - means each saved python file gets automatically
- imported into bicyclerepairman.
-
-2002-03-27 Phil Dawes <pdawes@users.sourceforge.net>
-
- * bike/parsing/load.py: Added functionality to deduce the package
- of the loaded module/package by inspecting parent directories for
- __init__.py modules. This allows adding of new modules to an
- existing AST.
-
-2002-03-24 Phil Dawes <pdawes@users.sourceforge.net>
-
- * README.idle: Added Evelyn's ammendment to doc
-
----------------------- 0.4.2 ------------------------------------
-
-2002-03-23 Phil Dawes <pdawes@users.sourceforge.net>
-
- * setup.py: Removed Icons stuff from setup
-
- * bike/ui/BicycleRepairMan_Idle.py: Fixed some bugs with idle
- integration in windows:
- - Ask if should rename dialogs dont take focus (which
- makes selection disappear in windows)
- - Filename normalizing means that filenames get compared correctly.
-
-2002-03-21 Phil Dawes <pdawes@users.sourceforge.net>
-
- * bike/testutils.py: Changed the test package structure generation
- code to add __init__.py modules to the packages. This will be used
- to work with the new loader code (when I write it).
-
-2002-03-20 Phil Dawes <pdawes@users.sourceforge.net>
-
- * bike/ui/BicycleRepairMan_Idle.py: Fixed bug which was stopping
- changed files from being reloaded on windows
-
----------------------- 0.4.1 ------------------------------------
-
-2002-03-19 Phil Dawes <pdawes@users.sourceforge.net>
-
- * bike/ui/BicycleRepairMan_Idle.py: Fixed bug where rename method
- prompts weren't visible to the user.
-
- * bike/parsing/addtypeinfo.py: Fixed a bug which meant that
- sourcenode wasnt getting added to default arguments, which caused
- brm to crash when attempting to tokenize these.
-
-
----------------------- 0.4 --------------------------------------
-
-2002-03-18 Phil Dawes <pdawes@users.sourceforge.net>
-
- * setup.py: Removed bikegui and pyxmi from the setup
- program. These are now deprecated.
-
- * bike/ui/BicycleRepairMan_Idle.py: Added the idle support module
- to cvs.
-
- * bike/parsing/tokenhandler.py: Simplified SimpleTokenHandler
-
- * bike/parsing/extended_ast.py: Removed ExtendedNode base class -
- it isnt needed (thanks Evelyn)
-
- * bike/parsing/tokenutils.py: fixed bug in
- _getOffsetOfTokensCorrespondingToParseTree which was including the
- NL token in the offset it returned.
-
- * bike/bikefacade.py: Changed signature of rename method
- callback. It now sends filename and coords as args rather than
- exposing the ast nodes to the client.
-
-2002-03-07 Phil Dawes <pdawes@users.sourceforge.net>
-
- * bike/__init__.py: Moved bikefacade.py (from the ui package) into
- the bike package. This is now referenced from __init__.py so a
- client can do:
- import bike; ctx = bike.load("mypath"); ctx.renameMethod()
-
-
- * bike/parsing/typeinfo.py: ModuleTypeinfo.getTypeOf()
- functionality now uses the imported module *name* to check other
- modules, rather than a reference to the module itself. This is to
- allow module reloading.
-
- * bike/parsing/extended_ast.py: Added 'addtypeinfo' call to Source
- node. This is now done when the sourcenode is added to the parent
- node rather than being run once over the whole tree. This
- facilitates adding additional trees to the ast without having to
- run the whole addtypeinfo step again.
-
- * bike/parsing/addtypeinfo.py: Removed the subclasses stuff from
- the classtypeinfo functionality. Doing this at initial-parse time
- is too brittle, since a reload of a child source node could remove
- (or add) a subclass from a base class.
- Instead, subclasses are calculated at refactoring time.
-
-
-
-2002-03-07 Phil Dawes <pdawes@users.sourceforge.net>
-
- * bike/parsing/addtypeinfo.py: Removed addfqn,
- addparentscopeToNode and addSourcenode to nodes functionality from
- the SourceModule, and integrated them with the first 'addtypeinfo'
- pass. This almost halves the initial parsing time.
-
-
-2002-03-04 Phil Dawes <pdawes@users.sourceforge.net>
-
- * bike/refactor/renameMethod.py: Changed renameMethod signature to
- take a method fqn rather than class and method parameters. This
- allows the tests to take advantage of the same signature for
- renameMethod,renameFunction and renameClass.
-
- * bike/ui/bikeemacs.py: refactored to use the new bikefacade module
-
- * bike/ui/bikefacade.py: New module which provides easy interface
- into brm, for integrating into IDEs.
-
- * bike/parsing/test_addtypeinfo.py: Added recursion handling for
- things like a=a() (just catches the runtime error)
-
-2002-02-28 Phil Dawes <pdawes@users.sourceforge.net>
-
- * bike/parsing/addtypeinfo.py: found a problem with lambdas - they
- take the reference from the outer scope. If the reference is a
- loop variable (e.g. for i in blah) then it is reassigned which
- knackers the closure.
- Solution - lambda i=i: doSomethingWith(i)
-
- * bike/ui/bikegui.py: removed reliance on tokens
-
- * bike/parsing/tokenhandler.py: added getStartCoords() and
- getEndCoords() functions.
-
-
-2002-02-27 Phil Dawes <pdawes@users.sourceforge.net>
-
- * */setpath.py: code which insures pythonpath includes path
- to the bike module (used for running test scripts). This is
- imported by most modules.
-
- * bike/parsing/extended_ast.py: moved addParentScopeToNodes()
- functionality from addtypeinfo into Source class.
-
- * bike/parsing/addtypeinfo.py: For deduced types (e.g. types got
- from function calls), the closure of the type deducing function is
- put in the typeinfo rather than the type itself. The closure is
- then run at lookup.
- This facilitates lazy loading, and means source modules can be
- reloaded without invalidating the typeinfo objects.
-
-2002-02-18 Phil Dawes <pdawes@users.sourceforge.net>
-
- * bike/ui/bikeemacs.py: Added reload source functionality
-
- * bike/ui/bike.el: Added support for renameMethod - prompts user
- for types that brm can't deduce
-
-2002-02-06 Phil Dawes <pdawes@users.sourceforge.net>
-
- * bike/ui/bikeemacs.py: New support for emacs
-
- * bike/parsing/addtypeinfo.py: Fixed bug which was causing
- inheritance specs not to be renamed
-
- * bike/parsing/output.py: Added some code to preserve level of
- indent in multiline (comma ended) statements (e.g. function
- arguments, class inheritence args etc...). This really needs
- reworking into a general solution, but works 70% of the time for
- now.
-
-2002-01-31 Phil Dawes <pdawes@bea.com>
-
- * bike/parsing/output.py: Added comment indenting code which
- should preserve the indent level of comments
-
-2002-01-28 Phil Dawes <pdawes@users.sourceforge.net>
-
- * bike/refactor/renameClass.py: Added functionality to rename the
- function and class ref in 'import a.b.theFunction and from a
- import theClass' type statements
-
- * bike/parsing/renameFunction.py: new refactoring
-
- * bike/parsing/tokenhandler.py: Added code to update the typeinfo
- objects of the parent scope and the Top node. This enables renames
- to be carried out more than once on the same ast
-
- * bike/parsing/addtypeinfo.py: Removed node.typeinfo.fqn. refactor
- code should now use node.fqn
-
-2002-01-25 Phil Dawes <pdawes@users.sourceforge.net>
-
- * bike/parsing/tokenhandler.py: Added token functionality to
- Name. Removed the getPreceedingTokens() stuff - the getTokens()
- now returns all tokens including preceeding comments, tokens
- etc... getNodeTokens() returns just the tokens associated with the
- node. This is consistent across all the tokenhandler base classes.
-
- * bike/parsing/tokenutils.py: Fixed bug in _appendTokens where
- the src 'raise foo' would result in 'raise' being picked up when
- searching for 'foo' because both tokens are of the same type (name).
-
-2002-01-24 Phil Dawes <pdawes@users.sourceforge.net>
-
- * bike/parsing/addtokens.py: Added code to class tokenizer to
- delegate tokens to the baseclass spec (i.e. bah in
- 'class foo(bah):').
-
- * bike/parsing/tokenhandler.py: Class handler stuff to output
- tokens (see above). This means that renameClass now renames class
- refs in baseclass specs.
-
-2002-01-23 Phil Dawes <pdawes@users.sourceforge.net>
-
- * bike/refactor/renameMethod.py: Fixed a bug which stopped classes
- that inherited from classes not in the ast from having method
- declarations renamed.
-
-2002-01-22 Phil Dawes <pdawes@users.sourceforge.net>
-
- * bike/parsing/output.py: Added support for handling line breaks.
- i.e. if foo and \
- bah:
-
- * bike/refactor/renameClass.py: Started new refactoring -
- renameClass
-
- * bike/parsing/addtypeinfo.py: removed 'typing indirect recursive
- functions causes stack overflow' bug
-
- * bike/refactor/renameMethod.py: Refactored the code so that the
- renameMethodReferences is done once, with a list of all the
- classes (in the hierarchy) to match.
-
-
-2002-01-21 Phil Dawes <pdawes@users.sourceforge.net>
-
- * bike/refactor/renameMethod.py: Now renames methods on all
- related classes (base classes and sub classes).
-
- * doc/*: added some html documentation
-
-2002-01-19 Phil Dawes <pdawes@users.sourceforge.net>
-
- * bike/refactor/renameMethod.py: Did some major refactoring and
- removed all the code which is functionally duplicated in the
- addtypeinfo module.
-
- * bike/parsing/addtypeinfo.py: Spruced up the type inference
- stuff.
- ModuleTypeInfo now handles from foo import * by storing a list of
- other modules to search.
-
-2002-01-17 Phil Dawes <pdawes@users.sourceforge.net>
-
- * bike/parsing/output.py: Save now returns a list of the files modified
-
-2002-01-16 Phil Dawes <pdawes@users.sourceforge.net>
-
- * bike/parsing/extended_ast.py: Added lazy tokenization. Source
- node now parses the source (rather than being handed the ast).
-
-2002-01-15 Phil Dawes <pdawes@users.sourceforge.net>
-
- * bike/parsing/output.py: Added lazy saving. Files are only saved
- if source modified.
-
- * bike/testutils.py: Added new utility to find an ast node in a
- tree based on attributes of the node.
- e.g. getMatchingASTNode(ast,"Function",name="foo")
-
-2002-01-14 Phil Dawes <pdawes@users.sourceforge.net>
-
- * bike/refactor/renameMethod.py: Added functionality to look for
- method and ref renames in sub classes
-
-2002-01-11 Phil Dawes <pdawes@users.sourceforge.net>
-
- * bike/parsing/addtypeinfo.py: Added support for imports, import
- from and import as statements
-
-2002-01-09 Phil Dawes <pdawes@users.sourceforge.net>
-
- * bike/parsing/tokenutils.py: Fixed bug where method call was
- split over 2 lines. The problem is that the tokenlist contains the
- NL, but the parsetree doesnt, so the matching wasnt working. See
- addtokens test_doesntBarfWhenMethodCallSplitOverTwoLines for details.
-
- * bike/parsing/brmtransformer.py: Added 2 classes which override
- Print and Println, and return the child nodes in the desired order
- (they are the wrong way round as they come out of
- ast.py). The print_stmt method returns these.
-
- * bike/parsing/output.py: Added code to handle spacing with commas
- and stream operators
-
-2002-01-08 Phil Dawes <pdawes@users.sourceforge.net>
-
- * bike/refactor/test_renameMethod.py: Refactored tests so that
- BikeGUI can use them (through template method). Tests are now
- split into RenameMethodTests,
- RenameMethodReferenceTests_ImportsClass and
- RenameMethodReferenceTests_doesntImportClass. This is because
- bikegui
-
-2002-01-07 Phil Dawes <pdawes@users.sourceforge.net>
-
- * bike/ui/bikegui.py: Added dialog to ask user if want to rename
- method reference (for cases where the type engine can't deduce the
- type of the instance)
-
-2002-01-04 Phil Dawes <pdawes@users.sourceforge.net>
-
- * bike/ui/bikegui.py: Added a simple gui for renameMethod
-
-2002-01-03 Phil Dawes <pdawes@users.sourceforge.net>
-
- * bike/parsing/load.py: Added functionality to strip of preceeding
- directories from package structures. (so if you load
- '/usr/local/python2.2/compiler', the root package is 'compiler')
-
- * bike/parsing/load.py: Added load_readonly(), which doesn't do the
- addtokens step.
- Also added code to enable load() to be called more than once, to
- add new files and packages to the tree.
- Moved ui messages into constants module
-
-2002-01-02 Phil Dawes <pdawes@users.sourceforge.net>
-
- * bike/parsing/brmtransformer.py: removed addTokens() step from
- parse(), so that it must be called seperately. This is because it
- isn't complete, and imposes quite a performance penalty. (and it's
- not needed by pyxmi). Updated all the tests to reflect this.
-
-2002-01-01 Phil Dawes <pdawes@users.sourceforge.net>
-
- * bike/parsing/addtypeinfo.py : Added getSubClasses()
- functionality to class typeinfo.
-
-2001-12-30 Phil Dawes <pdawes@users.sourceforge.net>
- * bike/*: Fixed path bugs for windows platform. All tests run on
- win32 python now.
-
-2001-12-29 Phil Dawes <pdawes@users.sourceforge.net>
-
- * bike/parsing/addtypeinfo.py: Added 'self' type to function
- typeinfo. This means renameMethod can handle self.theMethod()
- automatically.
-
-2001-12-28 Phil Dawes <pdawes@users.sourceforge.net>
-
- * pyxmi: Wrote little tool to create xmi representation of python
- code. Suitable for loading into argouml.
-
- * bike/ui/bikecli.py: Added progress meter support. (also in
- addtokens.py, renameMethod.py, load.py and output.py
-
-2001-12-26 Phil Dawes <pdawes@users.sourceforge.net>
-
- * bike/refactor/renameMethod.py: Fixed bug where function call
- returning instance resulted in crash. 'e.g. e().f()'
-
-2001-12-24 Phil Dawes <pdawes@users.sourceforge.net>
-
- * bike/parsing/addtokens.py: Reworked addtokens scheme to 'get all
- tokens for node, and then pass them to children to take their
- nodes'. This makes for a much easier time processing tokens.
-
-2001-12-16 Phil Dawes <pdawes@users.sourceforge.net>
-
- * bike/parsing/tokenhandler.py: Changed Getattr rename
- functionality to work when attribute token isn't second token of
- node tokenlist
-
- * bike/refactor/test_renameMethod.py: refactored renameMethod
- tests into generic abstract base class. These are now used by the
- ui package (rather than vice versa)
-
- * bike/ui/bikecli.py: Added code to tell you how many changes have
- been made, and advice on what might be wrong if this number is 0.
-
-2001-12-15 Phil Dawes <pdawes@users.sourceforge.net>
-
- * bike/parsing/tokenhandler.py: Added getNodeTokens()
- implementation to miss out any preceeding cruft not picked up by
- addtoken functionality on previous nodes.
-
-2001-12-14 Phil Dawes <pdawes@users.sourceforge.net>
-
- * bike/refactor/renameMethod.py: Changed renameMethodDefinition to
- work with nested methods (utilising the new typeinfo.fqn stuff).
- Removed findclass and findmethod.
-
-2001-12-12 Phil Dawes <pdawes@users.sourceforge.net>
-
- * bike/ui/bikecli.py: Modified prompt message a bit. Added actual
- standard io stuff so that it works with a user input as well as
- through the test harness.
-
- * bike/refactor/renameMethod.py: Modified RenameMethodReferences
- to create a stack of scopes. The code uses the typeinfo from each
- scope to determine the type of references, and if it can't find
- the type there, it checks its own references deduced from the
- classname passed in. I.e. it assumes that the classname is a
- class, even if it can't find the definition, and renames instances
- derived from it.
-
- Also ammended the 'prompt user callback' code to only ask the user
- if the type engine doesnt know the type of the instance
- expression. (before now it was prompting if the type was not the
- same as the input classname)
-
-2001-12-11 Phil Dawes <pdawes@users.sourceforge.net>
-
- * bike/ui/bikecli.py: Added code to handle prompting the user for
- whether the method reference should be renamed.
-
- * bike/refactor/renameMethod.py: Added code to prompt user when
- type of object instance isn't known
-
-2001-12-08 Phil Dawes <pdawes@users.sourceforge.net>
-
- * bike/refactor.py: now takes advantage of typeinfo stuff to
- deduce types of references
-
-2001-12-03 Phil Dawes <pdawes@users.sourceforge.net>
-
- * bike/parsing/addtypeinfo.py: New classes to deduce the types of
- references. Adds a typeinfo attribute to each scope ast node,
- which maps reference names to their types (currently as strings).
-
-2001-11-26 Phil Dawes <pdawes@users.sourceforge.net>
-
- * bike/refactor/renameMethod.py: Added stack to maintain
- references to object instances while visiting package structure
-
-2001-11-25 Phil Dawes <pdawes@users.sourceforge.net>
-
- * bike/refactor/renameMethod.py: Added support for 'from foo
- import *'
-
- * bike/ui/test_bikecli.py: Refactored tests so that all the single
- file tests are exercised in a package hierarchy context.
-
-2001-11-24 Phil Dawes <pdawes@users.sourceforge.net>
-
- * bike/refactor/renameMethod.py: Added support to rename methods
- based on imported classes
-
-2001-11-23 Phil Dawes <pdawes@users.sourceforge.net>
-
- * bike/refactor/renameMethod.py: Refactored code (took out
- RenameMethod class, since wasnt using instance state). Added
- support for compound references (a.b.c.foo)
-
-2001-11-21 Phil Dawes <pdawes@users.sourceforge.net>
-
- * bike/parsing/load_application.py: removed. (see load.py instead)
-
- * bike/refactor/renameMethod.py: Added support for fully qualified
- classnames in _findClass. e.g. a.b.bah.foo. This means that the ui
- now supports renaming package nested methods (but not their
- references).
-
-2001-11-20 Phil Dawes <pdawes@users.sourceforge.net>
-
- * bike/parsing: Added fixes to parser module to reflect changes in
- python 2.2 compiler module
-
-2001-11-16 Phil Dawes <pdawes@users.sourceforge.net>
-
- * bike/parsing/output.py: new function 'save' saves an entire ast
- tree
-
- * bike/refactor/renameMethod.py: Adapted to take an ast rather
- than source file
-
-2001-11-14 Phil Dawes <pdawes@bea.com>
-
- * bike/parsing/load.py: Replacement for load_application.py using
- Juergen's pythius loader code. load() hierarchically loads a bunch
- of packages and modules into a big AST.
-
- * bike/parsing/extended_ast.py: Fleshed out Package and Top nodes
- to support hierarchical module ast
-
-
-2001-11-08 Phil Dawes <pdawes@users.sourceforge.net>
-
- * bike/parsing/load_application.py: Fixed import visitor code to
- handle comma seperated imports. (i.e. import foo,bar). Added code
- to recognise imports via a from clause (i.e. from foo import bar)
-
- Removed Imports.py. Integrated code into load_application
-
-
-2001-11-06 Phil Dawes <pdawes@users.sourceforge.net>
-
- * bike/parsing/load_application.py: Added load_application and
- Imports modules back into build. Started writing tests for them.
-
-
-2001-11-05 Phil Dawes <pdawes@users.sourceforge.net>
-
- * bike/parsing/brmtransformer.py : Rewrote this to override the
- methods which create nodes at the root of the parse. This means
- that a few methods adding parser nodelists to ast nodes should
- cater for practically all the AST nodes.
-
- * bike/parsing/tokenhandler.py (GetattrTokenHander.renameAttr):
- added renameAttr method which renames the attribute in the object
- state, and in the corresponding tokens. This is a very brittle
- implementation, but will be fixed as new functionality is
- added. (it's the simplist thing right now)
-
- * bike/parsing/addtokens.py (AddTokens.visitGetattr): added
- token support for getattr
-
- * bike/parsing/tokenutils.py: Added getTokensPreceedingNodes,
- which takes a parsetree of nodes and returns all the tokens before
- the node represented by the parsetree. This is important because
- until there is an token-handling implementation of all the ast
- nodes, some tokens will be missed. By eating the tokens in between
- the implemented ast nodes, this ensures all the tokens will be
- outputted at the end.
-
-
-2001-10-30 Phil Dawes <pdawes@users.sourceforge.net>
-
- Created new CVS module, which makes use of distutils much more
- uniform.
-
- * setup.py: Created distutils setup stript:
-
-2001-10-25 Phil Dawes <pdawes@users.sourceforge.net>
-
- * parsing/output.py: Code to handle spacing in inline comments
-
- * refactor/renameMethod.py: Started code to handle references when
- object is created in same scope
-
-
-2001-10-24 Phil Dawes <pdawes@users.sourceforge.net>
-
- * parsing/output.py: spaces in conditionals (a == b etc..)
-
- * parsing/tokenutils.py: Refactored code in TokenList to handle
- rearranging indent/dedent tokens so that whole-line comments are
- indented with the things they comment. The transformations are now
- done after the initial scan (slower, but easier to follow)
-
-
-2001-10-23 Phil Dawes <pdawes@users.sourceforge.net>
-
- * parsing/output.py: ensured a.b not seperated by spaces.
-
-
-2001-10-22 Phil Dawes <pdawes@users.sourceforge.net>
-
- * parsing/output.py: Code to seperate a=b with spaces (a = b)
-
- * ui/test_cli.py: Merged cli tests with renameMethod tests to
- ensure all tests work through the cli
-
-2001-10-19 Phil Dawes <pdawes@users.sourceforge.net>
-
- * */testall.py: unified testing scripts so that all tests can be
- run from one place
-
-2001-10-15 Phil Dawes <pdawes@users.sourceforge.net>
-
- * ui/cli.py: Added simple command line interface.
-
-2001-10-14 Phil Dawes <pdawes@users.sourceforge.net>
-
- * parsing/output.py: Finished simple ast->string functionality
-
-2001-10-13 Phil Dawes <pdawes@users.sourceforge.net>
-
- * testall.py: added master test script
-
- * parsing/tokenhandler.py (FunctionTokenHandler.rename): added
- rename a function and keep tokens in sync functionality
-
-
-2001-10-12 Phil Dawes <pdawes@users.sourceforge.net>
-
- * parsing/output.py: started tokens -> string functionality
-
-2001-10-07 Phil Dawes <pdawes@users.sourceforge.net>
- * refactor/renameMethod.py: very basic findClass, findMethod
- functionality. Needs refactoring into analysis package, and
- merging with existing code
-
-2001-10-05 Phil Dawes <pdawes@users.sourceforge.net>
-
- * refactor/simplediff.py: wrote a simple diff utility to support
- writing top down tests. (i.e. do a renameMethod, then assert that
- the diff is correct)
-
-
-2001-10-04 Phil Dawes <pdawes@users.sourceforge.net>
-
- * refactor/renameMethod.py: Got fedup with trying to secondguess
- what the parser module should do. Decided to do some top-down
- proper XP style development. Started with implementing the
- renameMethod story.
-
-2001-10-01 Phil Dawes <pdawes@users.sourceforge.net>
-
- * parsing/test_addtokens.py: refactored tests so that they use
- brmtransformer to get a node, rather than mocking it.
-
-2001-09-29 Phil Dawes <pdawes@users.sourceforge.net>
-
- * parsing/brmtransformer.py: Added nodelist to pass_stmt
-
-2001-09-28 Phil Dawes <pdawes@users.sourceforge.net>
-
- * parsing/addtokens.py (AddTokens.visitModule): finished method
-
- * parsing/tokenutils.py
- (TokenConverter.getTokensUptoLastNewlineBeforeCode): method added
-
-2001-09-27 Phil Dawes <pdawes@users.sourceforge.net>
-
- * parsing/addtokens.py: started visitmodule() impl
-
- * parsing/extended_ast.py: Added tokens support to Module
-
-2001-09-26 Phil Dawes <pdawes@users.sourceforge.net>
-
- * parsing/test_addtokens.py Refactored tests. Made up better names.
-
-2001-09-25 Phil Dawes <pdawes@users.sourceforge.net>
-
- Laptop broke. Continuing with an older version of the code (hence
- the gap in changelog)
-
- * parsing/tokenutils.py (TokenConverter.getTokensToColon): Added
- function which just gobbles tokens to the next colon. Refactored
- getTokensStartBlock() to use this instead of walking the nodelist,
- since I think all
-
- * parsing/addtokens.py (AddTokens.visitFunction): Now that
- function and class no longer need to pass in partial nodelists,
- the code is common. Refactored common code into
- visitCompoundNode().
-
- (hence the gap in the changelog)
-
- * parsing/tokenhandler.py: removed the preceeding tokens code -
- you ain't gonna need it!
-
- * parsing/test_addtokens.py: changed visitclass tests to use
- mockobjects
-
-2001-09-10 Phil Dawes <pdawes@users.sourceforge.net>
-
- * parsing/tokenhandler.py:
-
- * parsing/*: Integrated code with bike parsing package
-
- Split tokenhandler base classes into seperate module
- Merged brmast stuff into extended_ast package
-
-
-2001-09-08 Phil Dawes <pdawes@users.sourceforge.net>
-
- * test_tokenutils.py: Added more unit tests
-
-2001-09-06 Phil Dawes <pdawes@users.sourceforge.net>
-
- * test_tokenutils.py: Added more unit tests
-
-
-2001-09-04 Phil Dawes <pdawes@users.sourceforge.net>
-
- * test_addtokens.py: Added some mock objects and tests
-
-2001-08-31 Phil Dawes <pdawes@users.sourceforge.net>
-
- * test_tokenutils.py: beefed up the unit tests a bit
-
-2001-08-29 Phil Dawes <pdawes@users.sourceforge.net>
-
- * brmtransformer.py: This module now just contains code to add the
- nodelist member to each ast node as the compiler generates
- it. This is so the code in addtokens has access to the original
- python parser nodes to generate tokens from.
-
- * addtokens.py: Moved the code to add the tokens to the ast nodes
- to this module. It now relies on there being a 'nodelist' member
- on each ast object, containing the original python parser
- nodelist.
-
- * brmast.py: Added hack to retrofit TokenHandler base class to
- existing compiler.ast classes. This means that we no longer have
- to include compiler classes with the distribution.
- Not sure if this is completely legal - doesn't work with jython.
-
- Removed stock Python compiler classes from src tree.
-
-
-2001-08-27 Phil Dawes <pdawes@users.sourceforge.net>
- Set about reimplementing the token stuff - will now add tokens to
- ast objects *after* the nodes have been processed by the compiler
- module.
-
-2001-08-22 Phil Dawes <pdawes@users.sourceforge.net>
-
- * tokenutils.py: Added support for tokenising strings as well as
- files.
-
- * test_tokenutils.py: removed testdata directory, and moved all
- the testdata into this module, now that the tokenutils stuff can
- take strings as well as files
-
- * brmtransformer.py: Renamed TransformerWithTokens to Transformer,
- now that it's in a seperate module.
-
- * brmast.py: Refactored the added token code out of ast module
- into this one. Created a seperate mixin called TokenHandler rather
- than sticking this code in the Node base class. Each class now
- re-inherits this baseclass.
- Unfortunately this means that I had to modify the transformer.py
- file to import brmast rather than ast. Need to think of a better
- way of doing this.
-
-2001-08-21 Phil Dawes <pdawes@users.sourceforge.net>
-
- * brmtransformer.py: Created new brmtransformer module and
- refactored token code from transformer.Transformer into seperate
- class TransformerWithTokens. Refactored common code from
- funcdef() and classdef() into do_compound_stmt()
-
- * transformer.py: Now that all new code is factored out, reverted
- to original transformer module from Python-2.1/Tools/compiler.
-
- * tokenutils.py: Added code to alter DEDENT token line numbers
- when they are rearranged
-
-2001-08-19 Phil Dawes <pdawes@users.sourceforge.net>
-
- * tokenutils.py: Added code to do token reordering to ensure that
- comments immediately before a block of code are placed after the
- previous block DEDENT token.
-
-2001-08-15 Phil Dawes <pdawes@users.sourceforge.net>
-
- * transformer.py: tidied up code, and released prototype
-
-2001-08-14 Phil Dawes <pdawes@users.sourceforge.net>
-
- * ast.py: Refactored management of tokens into base Node
- class. Removed code from Class, and moved node->token conversion
- to transformer.py
-
- * transformer.py: See above
-
-2001-08-13 Phil Dawes <pdawes@users.sourceforge.net>
-
- * ast.py: Added support for tokens in 'Class' nodes. 'Class' uses
- nodes passed to convert to tokens using TokenConverter.
-
-
-2001-08-10 Phil Dawes <pdawes@users.sourceforge.net>
-
- * tokenutils.py: Started TokenConverter class to convert python
- parser nodes to tokens.
-
- * test_tokenutils.py: unit tests for above
-
------------------- One year later... -------------------------
-
-
-2000-10-21 19:02 gwilder
-
- * context.py, refactor/.cvsignore, refactor/NewClass.py,
- refactor/Refactor.py, refactor/__init__.py:
-
- first refactoring: NewClass
-
-2000-10-21 18:56 gwilder
-
- * kickstand/: test_HasFromStar.py, test_IsClass.py,
- test_IsGlobal.py, test_all.py, test_context.py,
- test_load_application.py, testdata/HasFromStar_tf1.py,
- testdata/HasFromStar_tf2.py, testdata/IsGlobal_tf1.py,
- testdata/load_application_tf1.expected,
- testdata/load_application_tf1.py,
- testdata/rf_addclass_tf1.expected, testdata/rf_addclass_tf1.py:
-
- more tests
-
-2000-10-21 18:55 gwilder
-
- * analysis/: HasFromStar.py, IsClass.py, IsGlobal.py,
- Superclasses.py, TODO:
-
- more analysis functions
-
-2000-10-21 18:38 gwilder
-
- * parsing/: .cvsignore, Imports.py, README, TODO, __init__.py,
- extended_ast.py, load_application.py:
-
- parse and load a whole app.
-
-2000-10-13 19:32 gwilder
-
- * INSTALL, analysis/.cvsignore, analysis/IsClass.py,
- analysis/IsGlobal.py, analysis/README, analysis/TODO,
- analysis/__init__.py, assembly/genpy.py, kickstand/test_IsClass.py,
- kickstand/test_IsGlobal.py, kickstand/test_all.py,
- kickstand/testdata/.cvsignore, kickstand/testdata/IsClass_tf1.py,
- kickstand/testdata/IsGlobal_tf1.py:
-
- new analysis functions; install instructions; testsuite additions.
-
-2000-09-28 00:59 eris
-
- * .cvsignore, CHANGES, README, assembly/.cvsignore,
- disassembly/.cvsignore, kickstand/.cvsignore,
- kickstand/test_common.py, kickstand/treefailtest.py,
- kickstand/treematchtest.py, kickstand/unequalvars.py,
- sprocket/.cvsignore, sprocket/common.py, sprocket/common.txt:
-
-
- added .cvsignore files in each dir got the unit test for
- sprocket/common.py working, added files for that test.
-
-2000-09-06 01:21 jhermann
-
- * CHANGES, INSTALL, README, TODO:
-
- Added administrative files
-
-2000-09-05 22:13 jhermann
-
- * assembly/__init__.py, disassembly/__init__.py,
- kickstand/__init__.py, sprocket/__init__.py:
-
- Made the inits non-empty
-
-2000-09-05 22:11 jhermann
-
- * __init__.py:
-
- Minor correction
-
-2000-09-01 18:33 jhermann
-
- * kickstand/__init__.py, kickstand/test_fsm.py,
- kickstand/test_regast.py, sprocket/__init__.py, sprocket/common.py,
- sprocket/fsm.py, sprocket/regast.py:
-
- Initial source checkin (2000-09-01)
-
-2000-09-01 18:26 jhermann
-
- * .cvsignore, __init__.py, assembly/__init__.py, assembly/genpy.py,
- disassembly/__init__.py, disassembly/ast.py, disassembly/consts.py,
- disassembly/transformer.py:
-
- Initial source checkin (2000-09-01)
-
-2000-09-01 18:22 jhermann
-
- * README:
-
- Additions by shae
-
-2000-08-19 01:35 eris
-
- * README:
-
-
- new dir structure by snibril aka Jürgen Herrman first stab at a
- tree matcher in common.py
-
-2000-08-01 01:44 jhermann
-
- * README:
-
- Added a readme dummy
--- a/vim/sadness/bike/INSTALL Thu Feb 10 17:11:26 2011 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,17 +0,0 @@
-Bicycle Repair Man - a Python Refactoring Browser
-=================================================
-
-$Id: INSTALL,v 1.4 2002/03/29 13:10:49 pdawes Exp $
-
------------------------------------------------------------------------------
-
-Bicycle Repair Man requires Python 2.2 and above.
-
-Run
-% python setup.py install
-
-
-Then look for at the relevant README file to integrate Bicycle Repair
-Man with your IDE.
-
------------------------------------------------------------------------------
--- a/vim/sadness/bike/NEWS Thu Feb 10 17:11:26 2011 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,98 +0,0 @@
-Main highlights of each new version. See ChangeLog for a more detailed
-description of changes.
-
-Version 0.9
------------
-
-This version removes the requirement to load files into
-bicyclerepairman before refactoring. Instead, it searches the
-PYTHONPATH (and the path in which the file being queried is in). This
-allows 'findDefinition' queries to be made on references
-(e.g. classes, methods) where the definition is in the python library.
-
-
-Version 0.8
------------
-
-This release improves on the internal type-deduction engine to handle
-variables and attributes. To reflect this, 'rename' now works on
-variables and attributes, in addition to methods, functions and
-classes. This release also adds vim support (thanks to Marius Gedminas
-and Matt Yeates for this)
-
-Version 0.7
------------
-
-This release includes a totally re-written type querying engine, which
-is much faster and paves the way for new refactorings. It also adds
-the 'FindReferences' and 'FindDefinition' query to emacs and idle.
-
-
-Version 0.6
------------
-
-This release adds undo functionality to the mix, and beefs up the idle
-and emacs integration so that code is automatically imported into brm
-when you load a file into a buffer.
-
-
-Version 0.5
------------
-
-This release adds the ExtractMethod refactoring
-
-
-Version 0.4
------------
-
-This release adds support for IDLE (see README.idle), and fixes a few
-bugs. The CLI and GUI interfaces are now deprecated and have been
-removed from this release.
-
-
-
-Version 0.3
------------
-
-This release adds the RenameClass and RenameFunction refactorings.
-It also contains the initial xemacs integration functionality (see
-README.xemacs).
-
-
-
-Version 0.2
------------
-
-This release adds a simple GUI for renaming methods - run bikegui.py
-after installation.
-
-There's also some upgrades to pyxmi. It should now be able to generate
-xmi to model all generalizations (including cross-package ones).
-N.B. pyxmi.py is now called py2xmi.py. See changelog for reasons!
-
-
-
-Version 0.1
------------
-
-This is the first release of Bicycle Repair Man. It requires python
-version 2.2 and above.
-
-This version supports a partial implementation of the RenameMethod
-refactoring through a command line interface.
-
-It automatically renames the method and references to the method that
-it can deduce. It asks you about method references it can't deduce the
-instance type of.
-
-This software should be considered alpha, and may damage your source
-files - backup your sources before use!
-
-See INSTALL for installation and usage instructions.
-
-
-N.B. This package also contains pyxmi - a little python -> xmi tool I
-cobbled together out of the bicycle repair man parsing package. It
-generates an xmi file out of a source-file or package-structure,
-suitable for loading into the argouml tool. See
-http://argouml.tigris.org.
--- a/vim/sadness/bike/PKG-INFO Thu Feb 10 17:11:26 2011 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,10 +0,0 @@
-Metadata-Version: 1.0
-Name: bicyclerepair
-Version: 0.9
-Summary: Bicycle Repair Man, the Python refactoring tool
-Home-page: http://bicyclerepair.sourceforge.net
-Author: Phil Dawes
-Author-email: pdawes@users.sourceforge.net
-License: UNKNOWN
-Description: UNKNOWN
-Platform: UNKNOWN
--- a/vim/sadness/bike/README Thu Feb 10 17:11:26 2011 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,70 +0,0 @@
-Bicycle Repair Man - a Python Refactoring Browser
-=================================================
-
-Copyright (c) 2000 by Shae Erisson <shae@lapland.fi>
-Copyright (c) 2001-3 by Phil Dawes <pdawes@users.sourceforge.net>
-
-All rights reserved, see COPYING for details.
-
-$Id: README,v 1.7 2003/08/24 19:48:43 pdawes Exp $
-
------------------------------------------------------------------------------
-
-Bicycle Repair Man is the Python Refactoring Browser, helping
-Pythonistas everywhere glide over the gory details of refactoring their
-code. Watch him extract jumbled code into well ordered classes. Gasp, as
-he renames all occurrences of a method. Thank You, Bicycle Repair Man!
-
-execute ./testall.py to run all the tests
-
-see INSTALL for installation instructions (uses distutils).
-
-see README.idle, README.emacs etc.. for instructions on how to
-integrate bicyclerepairman into supported IDEs.
-
------------------------------------------------------------------------------
-
-
-What's Python?
-
-Python is a programming language. To find out more
-about it, go to the Python Homepage at http://www.python.org/
-
-
-What's a Refactoring Browser?
-
-A Refactoring Browser is an editor that automates Refactorings. The
-first Refactoring Browser was written by Dr. Don Roberts and Dr. John
-Brant at the University of Illinois in Urbana-Champagne. Dr. Don
-Roberts wrote his Ph.D. thesis on the design and implementation of the
-Refactoring Browser. For more detail, read the aforementioned thesis
-at http://st-www.cs.uiuc.edu/~droberts/thesis.pdf
-
-
-What's a Refactoring?
-
-A Refactoring is a behaviour preserving change to source code. Some
-Refactorings are RenameVariable, RenameClass, RenameMethod,
-PullUpMethod, and PushDownVariable. Lots of people say it's very easy
-to just type a different name in where your class, method, or variable
-is defined. That's not always a refactoring though. The Refactoring
-Browser is smart enough to rename every reference to your class,
-method or variable. If you've ever renamed a variable and broken
-classes in widely scattered parts of your system, you might be happier
-using a Refactoring Browser. A Refactoring Browser operates on any of
-method, function, class, or variable. It can add, delete, rename, move
-up down or sideways, inline and abstract. There are some operations
-that are specific to one of the three types, such as abstracting a
-variable into accessors, or turing several lines of code into a
-separate method.
-
-For more information on Refactoring, check out the websites of Martin
-Fowler at http://www.martinfowler.com/ and his Refactoring Site at
-http://www.refactoring.com/ .
-
-
-Why Bicycle Repair Man?
-
-The Bicycle Repair Man was a superhero in a Monty Python skit, his
-special power was repairing bicycles.
-
--- a/vim/sadness/bike/README.emacs Thu Feb 10 17:11:26 2011 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,115 +0,0 @@
-Instructions for running Bicycle Repair Man through emacs/xemacs
-----------------------------------------------------------------
-
-N.B. You need xemacs / emacs 21 or above.
-
-The emacs integration utilises the excellent 'Pymacs' package, written
-by François Pinard, which integrates python with emacs. A copy of this
-software is included with this package.
-
-
-There are 3 steps to installing bicyclerepairman for emacs:
-
-1) Install the base bicyclerepairman package
-
-2) Install the Pymacs package (if you haven't already got it)
-
-3) Modify your .emacs to active the bicyclerepairman functionality
-
-See the sections below for instructions on doing each of these.
-
-WINDOWS USERS:
-You need to have both the python executable and the scripts directory
-(e.g. c:\Python22/Scripts) in your path for Bicyclerepairman to work.
-
-There are a couple of niggles with brm/emacs on
-windows. See the comments at the end of this file.
-
-
-
-
-
-
-
-1) Installation of Base Bicyclerepairman:
------------------------------------------
-
-- install bicyclerepair man as per INSTALL
-
-
-2) Installation of Pymacs:
---------------------------
-
-(You can skip this if you already have pymacs installed.
-
-- Go to the ide-integration/Pymacs-0.20 directory
-- Run
- python setup.py install
-- Run
- python setup-emacs.py -l <LISP DIR>
- OR
- python setup-emacs.py -E xemacs -l <LISP DIR>
- Depending on your version of emacs.
-
-- Add the following into your .emacs or .xemacs/init.el:
-
-;; pymacs
-(autoload 'pymacs-load "pymacs" nil t)
-(autoload 'pymacs-eval "pymacs" nil t)
-(autoload 'pymacs-apply "pymacs")
-(autoload 'pymacs-call "pymacs")
-
-- Check that it has installed correctly:
- (Taken from the pymacs README)
-
-
- To check that `pymacs.el' is properly installed, start Emacs and give
- it the command `M-x load-library RET pymacs': you should not receive
- any error.
-
- To check that `pymacs.py' is properly installed, start
- an interactive Python session (e.g. from a command shell) and type
- `from Pymacs import lisp': you should not receive any error.
-
- To check that `pymacs-services' is properly installed, type
- `pymacs-services' in a shell; you should then get a line ending
- with "(pymacs-version VERSION)". Press ctrl-c to exit.
-
-
-If you have any problems, consult the README file included with the
-pymacs distribution. N.B. I renamed the setup script to setup-emacs.py
-to make it more intuitive and easier for windows users. I've also
-added a pymacs-services.bat file to allow it to run on windows.
-
-
-3) Activating the Bike/Emacs integration
-----------------------------------------
-
-Add the following to your .emacs or .xemacs/init.el, after the pymacs
-stuff:
-
-(pymacs-load "bikeemacs" "brm-")
-(brm-init)
-
-
-You need to be using python-mode for the bicyclerepairman menu to
-appear. If you haven't already, enable this with:
-
-(autoload 'python-mode "python-mode" "Python editing mode." t)
-(setq auto-mode-alist
- (cons '("\\.py$" . python-mode) auto-mode-alist))
-
-
-
-Usage:
-------
-
-Load a python file into emacs. A BicycleRepairMan menu should appear.
-
-
-Windows GNU-Emacs users
------------------------
-
-The load dialog in windows GNU-Emacs doesn't seem to allow selection
-of directories. If this is the case for you, use 'M-x brm-load' to
-import a package hierarchy.
--- a/vim/sadness/bike/README.idle Thu Feb 10 17:11:26 2011 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,47 +0,0 @@
-BicycleRepairMan_Idle.py is the name of the idle integration module.
-
-
-Installation on Python 2.3 or idlefork
---------------------------------------
-1) Install Bicycle Repair Man (see INSTALL)
-
-2) Add the following to your ~/.idlerc/config-extensions.cfg:
-(NOTE - I had to put this in my
-<PYTHONLIBDIR>/idlelib/config-extensions.def for it to work correctly)
-
-[BicycleRepairMan_Idle]
-enable=1
-trace=0
-[BicycleRepairMan_Idle_cfgBindings]
-brm-find-references=
-brm-find-definition=
-brm-rename=
-brm-extract-method=
-brm-undo=
-
-Python sourcefile editor windows will now have a 'BicycleRepairMan'
-menu.
-
-
-
-Installation on python 2.2 version of idle
-------------------------------------------
-
-1) Install Bicycle Repair Man (see INSTALL)
-
-2) Add the following line to your <idle-installation>/config.txt or
-~/.idle:
-
-[BicycleRepairMan_Idle]
-
-
-Python sourcefile editor windows will now have a 'BicycleRepairMan'
-menu.
-
-
-
-Caveats
--------
-
-Sometimes dialogs get lost behind windows. If things seem to have
-paused in a rename-method, try looking for a dialog.
--- a/vim/sadness/bike/README.vim Thu Feb 10 17:11:26 2011 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,2 +0,0 @@
-Instructions for installing bike.vim are in the file itself.
-See ide-integration/bike.vim
\ No newline at end of file
--- a/vim/sadness/bike/bike/__init__.py Thu Feb 10 17:11:26 2011 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,10 +0,0 @@
-# The root bicyclerepairman package
-# do:
-# ---------------------
-# import bike
-# ctx = bike.load()
-# ---------------------
-# to instantiate a bicyclerepairman context object
-
-
-from bikefacade import init, NotAPythonModuleOrPackageException, CouldntLocateASTNodeFromCoordinatesException, UndoStackEmptyException
--- a/vim/sadness/bike/bike/bikefacade.py Thu Feb 10 17:11:26 2011 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,274 +0,0 @@
-import os
-import sys
-import compiler
-from parser import ParserError
-from bike.parsing.pathutils import getRootDirectory
-from bike.refactor import extractMethod
-from bike.refactor.rename import rename
-from bike.refactor.extractMethod import coords
-from bike.transformer.save import save as saveUpdates
-from bike.parsing.utils import fqn_rcar, fqn_rcdr
-from bike.parsing import visitor
-from bike.transformer.undo import getUndoStack, UndoStackEmptyException
-from bike.parsing.fastparserast import getRoot, Class, Function
-from bike.query.common import getScopeForLine
-from bike.query.getTypeOf import getTypeOfExpr, UnfoundType
-from bike.query.findReferences import findReferences
-from bike.query.findDefinition import findAllPossibleDefinitionsByCoords
-from bike.refactor import inlineVariable, extractVariable, moveToModule
-from bike.parsing.load import Cache
-from bike import log
-
-def init():
- #context = BRMContext_impl()
- context = BRMContext_wrapper()
- return context
-
-# the context object public interface
-class BRMContext(object):
-
-
- def save(self):
- """ save the changed files out to disk """
-
- def setRenameMethodPromptCallback(self, callback):
- """
- sets a callback to ask the user about method refs which brm
- can't deduce the type of. The callback must be callable, and
- take the following parameters:
- - filename
- - linenumber
- - begin column
- - end column
- (begin and end columns enclose the problematic method call)
- """
-
- def renameByCoordinates(self, filename_path, line, col, newname):
- """ an ide friendly method which renames a class/fn/method
- pointed to by the coords and filename"""
-
- def extract(self, filename_path,
- begin_line, begin_col,
- end_line, end_col,
- name):
- """ extracts the region into the named method/function based
- on context"""
-
- def inlineLocalVariable(self,filename_path, line, col):
- """ Inlines the variable pointed to by
- line:col. (N.B. line:col can also point to a reference to the
- variable as well as the definition) """
-
-
- def extractLocalVariable(self,filename_path, begin_line, begin_col,
- end_line, end_col, variablename):
- """ Extracts the region into a variable """
-
- def setProgressLogger(self,logger):
- """ Sets the progress logger to an object with a write method
- """
-
- def setWarningLogger(self,logger):
- """ Sets the warning logger to an object with a write method
- """
-
- def undo(self):
- """ undoes the last refactoring. WARNING: this is dangerous if
- the user has modified files since the last refactoring.
- Raises UndoStackEmptyException"""
-
- def findReferencesByCoordinates(self, filename_path, line, column):
- """ given the coords of a function, class, method or variable
- returns a generator which finds references to it.
- """
-
- def findDefinitionByCoordinates(self,filename_path,line,col):
- """ given the coordates to a reference, tries to find the
- definition of that reference """
-
- def moveClassToNewModule(self,filename_path, line,
- newfilename):
- """ moves the class pointed to by (filename_path, line)
- to a new module """
-
-
-class NotAPythonModuleOrPackageException: pass
-class CouldntLocateASTNodeFromCoordinatesException: pass
-
-
-# Wrapper to ensure that caches are purged on each request
-class BRMContext_wrapper:
- def __init__(self):
- self.brmctx = BRMContext_impl()
-
- def __getattr__(self,name):
- return BRMContext_callWrapper(self.brmctx,name)
-
-
-class BRMContext_callWrapper:
- def __init__(self,brmctx,methodname):
- self.name = methodname
- self.brmctx = brmctx
-
- def __call__(self,*args):
- Cache.instance.reset()
- try:
- return getattr(self.brmctx,self.name)(*args)
- finally:
- Cache.instance.reset()
-
-
-class BRMContext_impl(BRMContext):
-
- def __init__(self):
- self.ast = getRoot()
-
- # Used because some refactorings delegate back to the user.
- # this flag ensures that code isnt imported during those times
- self.readyToLoadNewCode = 1
- self.paths = []
- getUndoStack(1) # force new undo stack
- if not getRoot().unittestmode:
- log.warning = sys.stderr
- self.promptUserClientCallback = None
-
- def _getAST(self):
- return self.ast
-
- # returns a list of saved filenames
- def save(self):
- savedfiles = saveUpdates()
- return savedfiles
-
- def setRenameMethodPromptCallback(self, callback):
- self.promptUserClientCallback = callback
-
-
- def normalizeFilename(self,filename):
- filename = os.path.expanduser(filename)
- filename = os.path.normpath(os.path.abspath(filename))
- return filename
-
- def extractMethod(self, filename_path,
- begin_line, begin_column,
- end_line, end_column,
- methodname):
- self.extract(filename_path, begin_line, begin_column,
- end_line, end_column,methodname)
-
- def extractFunction(self, filename_path,
- begin_line, begin_column,
- end_line, end_column,
- methodname):
- self.extract(filename_path, begin_line, begin_column,
- end_line, end_column,methodname)
-
- # does it based on context
- def extract(self, filename_path,
- begin_line, begin_col,
- end_line, end_col,
- name):
- filename_path = self.normalizeFilename(filename_path)
- extractMethod.extractMethod(filename_path,
- coords(begin_line, begin_col),
- coords(end_line, end_col), name)
-
- def inlineLocalVariable(self,filename_path, line, col):
- filename_path = self.normalizeFilename(filename_path)
- inlineVariable.inlineLocalVariable(filename_path,line,col)
-
- def extractLocalVariable(self,filename_path, begin_line, begin_col,
- end_line, end_col, variablename):
- filename_path = self.normalizeFilename(filename_path)
- extractVariable.extractLocalVariable(filename_path,
- coords(begin_line, begin_col),
- coords(end_line, end_col),
- variablename)
-
- def moveClassToNewModule(self,filename_path, line,
- newfilename):
- filename_path = self.normalizeFilename(filename_path)
- newfilename = self.normalizeFilename(newfilename)
- moveToModule.moveClassToNewModule(filename_path, line,
- newfilename)
-
- def undo(self):
- getUndoStack().undo()
-
- def _promptUser(self, filename, lineno, colbegin, colend):
- return self.promptUserClientCallback(filename, lineno, colbegin, colend)
-
-
- # must be an object with a write method
- def setProgressLogger(self,logger):
- log.progress = logger
-
- # must be an object with a write method
- def setWarningLogger(self,logger):
- log.warning = logger
-
-
- # filename_path must be absolute
- def renameByCoordinates(self, filename_path, line, col, newname):
- filename_path = self.normalizeFilename(filename_path)
- Cache.instance.reset()
- try:
- self._setNonLibPythonPath(filename_path)
- rename(filename_path,line,col,newname,
- self.promptUserClientCallback)
- finally:
- Cache.instance.reset()
-
- def _reverseCoordsIfWrongWayRound(self, colbegin, colend):
- if(colbegin > colend):
- colbegin,colend = colend,colbegin
- return colbegin,colend
-
-
- def findDefinitionByCoordinates(self,filename_path,line,col):
- filename_path = self.normalizeFilename(filename_path)
- self._setCompletePythonPath(filename_path)
- return findAllPossibleDefinitionsByCoords(filename_path,line,col)
-
-
- # filename_path must be absolute
- def findReferencesByCoordinates(self, filename_path, line, column):
- filename_path = self.normalizeFilename(filename_path)
- self._setNonLibPythonPath(filename_path)
- return findReferences(filename_path,line,column)
-
- def refreshASTFromFileSystem(self):
- for path in self.paths:
- self.ast = loadast(path, self.ast)
-
- def _setCompletePythonPath(self,filename):
- pythonpath = [] + sys.path # make a copy
- self.ast.pythonpath = pythonpath
-
- def _setNonLibPythonPath(self,filename):
- if getRoot().unittestmode:
- return
- pythonpath = self._removeLibdirsFromPath(sys.path)
- pythonpath = [os.path.abspath(p) for p in pythonpath]
- self.ast.pythonpath = pythonpath
-
- def _getCurrentSearchPath(self):
- return self.ast.pythonpath
-
- def _removeLibdirsFromPath(self, pythonpath):
- libdir = os.path.join(sys.prefix,"lib").lower()
- pythonpath = [p for p in pythonpath
- if not p.lower().startswith(libdir)]
- return pythonpath
-
-
-def _deducePackageOfFile(filename):
- package = ""
- dot = ""
- dir = os.path.dirname(filename)
- while dir != ""and \
- os.path.exists(os.path.join(dir, "__init__.py")):
- dir, dirname = os.path.split(dir)
- package = dirname+dot+package
- dot = "."
- return package
--- a/vim/sadness/bike/bike/globals.py Thu Feb 10 17:11:26 2011 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,6 +0,0 @@
-try:
- True = 1
- False = 0
-except:
- pass
-
--- a/vim/sadness/bike/bike/log.py Thu Feb 10 17:11:26 2011 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,8 +0,0 @@
-import sys
-class SilentLogger:
- def write(*args):
- pass
-
-progress = SilentLogger()
-warning = SilentLogger()
-#warning = sys.stderr
--- a/vim/sadness/bike/bike/logging.py Thu Feb 10 17:11:26 2011 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,1995 +0,0 @@
-#! /usr/bin/env python
-#
-# Copyright 2001-2002 by Vinay Sajip. All Rights Reserved.
-#
-# Permission to use, copy, modify, and distribute this software and its
-# documentation for any purpose and without fee is hereby granted,
-# provided that the above copyright notice appear in all copies and that
-# both that copyright notice and this permission notice appear in
-# supporting documentation, and that the name of Vinay Sajip
-# not be used in advertising or publicity pertaining to distribution
-# of the software without specific, written prior permission.
-# VINAY SAJIP DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
-# ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
-# VINAY SAJIP BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
-# ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
-# IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
-# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-#
-# For the change history, see README.txt in the distribution.
-#
-# This file is part of the Python logging distribution. See
-# http://www.red-dove.com/python_logging.html
-#
-
-"""
-Logging module for Python. Based on PEP 282 and comments thereto in
-comp.lang.python, and influenced by Apache's log4j system.
-
-Should work under Python versions >= 1.5.2, except that source line
-information is not available unless 'inspect' is.
-
-Copyright (C) 2001-2002 Vinay Sajip. All Rights Reserved.
-
-To use, simply 'import logging' and log away!
-"""
-
-import sys, os, types, time, string, socket, cPickle, cStringIO
-
-from SocketServer import ThreadingTCPServer, StreamRequestHandler
-
-
-try:
- import thread
-except ImportError:
- thread = None
-try:
- import inspect
-except ImportError:
- inspect = None
-
-__author__ = "Vinay Sajip <vinay_sajip@red-dove.com>"
-__status__ = "alpha"
-__version__ = "0.4.5"
-__date__ = "4 June 2002"
-
-#---------------------------------------------------------------------------
-# Miscellaneous module data
-#---------------------------------------------------------------------------
-
-#
-#_srcfile is used when walking the stack to check when we've got the first
-# caller stack frame.
-#If run as a script, __file__ is not bound.
-#
-if __name__ == "__main__":
- _srcfile = None
-else:
- if string.lower(__file__[-4:]) in ['.pyc', '.pyo']:
- _srcfile = __file__[:-4] + '.py'
- else:
- _srcfile = __file__
- _srcfile = os.path.normcase(_srcfile)
-
-#
-#_startTime is used as the base when calculating the relative time of events
-#
-_startTime = time.time()
-
-#
-# Some constants...
-#
-
-DEFAULT_TCP_LOGGING_PORT = 9020
-DEFAULT_UDP_LOGGING_PORT = 9021
-DEFAULT_HTTP_LOGGING_PORT = 9022
-DEFAULT_SOAP_LOGGING_PORT = 9023
-DEFAULT_LOGGING_CONFIG_PORT = 9030
-SYSLOG_UDP_PORT = 514
-
-#---------------------------------------------------------------------------
-# Level related stuff
-#---------------------------------------------------------------------------
-#
-# Default levels and level names, these can be replaced with any positive set
-# of values having corresponding names. There is a pseudo-level, ALL, which
-# is only really there as a lower limit for user-defined levels. Handlers and
-# loggers are initialized with ALL so that they will log all messages, even
-# at user-defined levels.
-#
-CRITICAL = 50
-FATAL = CRITICAL
-ERROR = 40
-WARN = 30
-INFO = 20
-DEBUG = 10
-ALL = 0
-
-_levelNames = {
- CRITICAL : 'CRITICAL',
- ERROR : 'ERROR',
- WARN : 'WARN',
- INFO : 'INFO',
- DEBUG : 'DEBUG',
- ALL : 'ALL',
- 'CRITICAL' : CRITICAL,
- 'ERROR' : ERROR,
- 'WARN' : WARN,
- 'INFO' : INFO,
- 'DEBUG' : DEBUG,
- 'ALL' : ALL,
-}
-
-def getLevelName(lvl):
- """
- Return the textual representation of logging level 'lvl'. If the level is
- one of the predefined levels (CRITICAL, ERROR, WARN, INFO, DEBUG) then you
- get the corresponding string. If you have associated levels with names
- using addLevelName then the name you have associated with 'lvl' is
- returned. Otherwise, the string "Level %s" % lvl is returned.
- """
- return _levelNames.get(lvl, ("Level %s" % lvl))
-
-def addLevelName(lvl, levelName):
- """
- Associate 'levelName' with 'lvl'. This is used when converting levels
- to text during message formatting.
- """
- _acquireLock()
- try: #unlikely to cause an exception, but you never know...
- _levelNames[lvl] = levelName
- _levelNames[levelName] = lvl
- finally:
- _releaseLock()
-
-#---------------------------------------------------------------------------
-# Thread-related stuff
-#---------------------------------------------------------------------------
-
-#
-#_lock is used to serialize access to shared data structures in this module.
-#This needs to be an RLock because fileConfig() creates Handlers and so
-#might arbitrary user threads. Since Handler.__init__() updates the shared
-#dictionary _handlers, it needs to acquire the lock. But if configuring,
-#the lock would already have been acquired - so we need an RLock.
-#The same argument applies to Loggers and Manager.loggerDict.
-#
-_lock = None
-
-def _acquireLock():
- """
- Acquire the module-level lock for serializing access to shared data.
- This should be released with _releaseLock().
- """
- global _lock
- if (not _lock) and thread:
- import threading #this had better work
- _lock = threading.RLock()
- if _lock:
- _lock.acquire()
-
-def _releaseLock():
- """
- Release the module-level lock acquired by calling _acquireLock().
- """
- if _lock:
- _lock.release()
-
-#---------------------------------------------------------------------------
-# The logging record
-#---------------------------------------------------------------------------
-
-class LogRecord:
- """
- LogRecord instances are created every time something is logged. They
- contain all the information pertinent to the event being logged. The
- main information passed in is in msg and args, which are combined
- using msg % args to create the message field of the record. The record
- also includes information such as when the record was created, the
- source line where the logging call was made, and any exception
- information to be logged.
- """
- def __init__(self, name, lvl, pathname, lineno, msg, args, exc_info):
- """
- Initialize a logging record with interesting information.
- """
- ct = time.time()
- self.name = name
- self.msg = msg
- self.args = args
- self.levelname = getLevelName(lvl)
- self.levelno = lvl
- self.pathname = pathname
- try:
- self.filename = os.path.basename(pathname)
- self.module = os.path.splitext(self.filename)[0]
- except:
- self.filename = pathname
- self.module = "Unknown module"
- self.exc_info = exc_info
- self.lineno = lineno
- self.created = ct
- self.msecs = (ct - long(ct)) * 1000
- self.relativeCreated = (self.created - _startTime) * 1000
- if thread:
- self.thread = thread.get_ident()
- else:
- self.thread = None
-
- def __str__(self):
- return '<LogRecord: %s, %s, %s, %s, "%s">'%(self.name, self.levelno,
- self.pathname, self.lineno, self.msg)
-
- def getMessage(self):
- """
- Return the message for this LogRecord, merging any user-supplied
- arguments with the message.
- """
- msg = str(self.msg)
- if self.args:
- msg = msg % self.args
- return msg
-
-#---------------------------------------------------------------------------
-# Formatter classes and functions
-#---------------------------------------------------------------------------
-
-class Formatter:
- """
- Formatters need to know how a LogRecord is constructed. They are
- responsible for converting a LogRecord to (usually) a string which can
- be interpreted by either a human or an external system. The base Formatter
- allows a formatting string to be specified. If none is supplied, the
- default value of "%s(message)\\n" is used.
-
- The Formatter can be initialized with a format string which makes use of
- knowledge of the LogRecord attributes - e.g. the default value mentioned
- above makes use of the fact that the user's message and arguments are pre-
- formatted into a LogRecord's message attribute. Currently, the useful
- attributes in a LogRecord are described by:
-
- %(name)s Name of the logger (logging channel)
- %(levelno)s Numeric logging level for the message (DEBUG, INFO,
- WARN, ERROR, CRITICAL)
- %(levelname)s Text logging level for the message ("DEBUG", "INFO",
- "WARN", "ERROR", "CRITICAL")
- %(pathname)s Full pathname of the source file where the logging
- call was issued (if available)
- %(filename)s Filename portion of pathname
- %(module)s Module (name portion of filename)
- %(lineno)d Source line number where the logging call was issued
- (if available)
- %(created)f Time when the LogRecord was created (time.time()
- return value)
- %(asctime)s Textual time when the LogRecord was created
- %(msecs)d Millisecond portion of the creation time
- %(relativeCreated)d Time in milliseconds when the LogRecord was created,
- relative to the time the logging module was loaded
- (typically at application startup time)
- %(thread)d Thread ID (if available)
- %(message)s The result of msg % args, computed just as the
- record is emitted
- """
- def __init__(self, fmt=None, datefmt=None):
- """
- Initialize the formatter either with the specified format string, or a
- default as described above. Allow for specialized date formatting with
- the optional datefmt argument (if omitted, you get the ISO8601 format).
- """
- if fmt:
- self._fmt = fmt
- else:
- self._fmt = "%(message)s"
- self.datefmt = datefmt
-
- def formatTime(self, record, datefmt=None):
- """
- This method should be called from format() by a formatter which
- wants to make use of a formatted time. This method can be overridden
- in formatters to provide for any specific requirement, but the
- basic behaviour is as follows: if datefmt (a string) is specified,
- it is used with time.strftime() to format the creation time of the
- record. Otherwise, the ISO8601 format is used. The resulting
- string is returned.
- """
- ct = record.created
- if datefmt:
- s = time.strftime(datefmt, time.localtime(ct))
- else:
- t = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(ct))
- s = "%s,%03d" % (t, record.msecs)
- return s
-
- def formatException(self, ei):
- """
- Format the specified exception information as a string. This
- default implementation just uses traceback.print_exception()
- """
- import traceback
- sio = cStringIO.StringIO()
- traceback.print_exception(ei[0], ei[1], ei[2], None, sio)
- s = sio.getvalue()
- sio.close()
- if s[-1] == "\n":
- s = s[:-1]
- return s
-
- def format(self, record):
- """
- The record's attribute dictionary is used as the operand to a
- string formatting operation which yields the returned string.
- Before formatting the dictionary, a couple of preparatory steps
- are carried out. The message attribute of the record is computed
- using msg % args. If the formatting string contains "%(asctime)",
- formatTime() is called to format the event time. If there is
- exception information, it is formatted using formatException()
- and appended to the message.
- """
- record.message = record.getMessage()
- if string.find(self._fmt,"%(asctime)") >= 0:
- record.asctime = self.formatTime(record, self.datefmt)
- s = self._fmt % record.__dict__
- if record.exc_info:
- if s[-1] != "\n":
- s = s + "\n"
- s = s + self.formatException(record.exc_info)
- return s
-
-#
-# The default formatter to use when no other is specified
-#
-_defaultFormatter = Formatter()
-
-class BufferingFormatter:
- """
- A formatter suitable for formatting a number of records.
- """
- def __init__(self, linefmt=None):
- """
- Optionally specify a formatter which will be used to format each
- individual record.
- """
- if linefmt:
- self.linefmt = linefmt
- else:
- self.linefmt = _defaultFormatter
-
- def formatHeader(self, records):
- """
- Return the header string for the specified records.
- """
- return ""
-
- def formatFooter(self, records):
- """
- Return the footer string for the specified records.
- """
- return ""
-
- def format(self, records):
- """
- Format the specified records and return the result as a string.
- """
- rv = ""
- if len(records) > 0:
- rv = rv + self.formatHeader(records)
- for record in records:
- rv = rv + self.linefmt.format(record)
- rv = rv + self.formatFooter(records)
- return rv
-
-#---------------------------------------------------------------------------
-# Filter classes and functions
-#---------------------------------------------------------------------------
-
-class Filter:
- """
- The base filter class. Loggers and Handlers can optionally use Filter
- instances to filter records as desired. The base filter class only allows
- events which are below a certain point in the logger hierarchy. For
- example, a filter initialized with "A.B" will allow events logged by
- loggers "A.B", "A.B.C", "A.B.C.D", "A.B.D" etc. but not "A.BB", "B.A.B"
- etc. If initialized with the empty string, all events are passed.
- """
- def __init__(self, name=''):
- """
- Initialize with the name of the logger which, together with its
- children, will have its events allowed through the filter. If no
- name is specified, allow every event.
- """
- self.name = name
- self.nlen = len(name)
-
- def filter(self, record):
- """
- Is the specified record to be logged? Returns 0 for no, nonzero for
- yes. If deemed appropriate, the record may be modified in-place.
- """
- if self.nlen == 0:
- return 1
- elif self.name == record.name:
- return 1
- elif string.find(record.name, self.name, 0, self.nlen) != 0:
- return 0
- return (record.name[self.nlen] == ".")
-
-class Filterer:
- """
- A base class for loggers and handlers which allows them to share
- common code.
- """
- def __init__(self):
- """
- Initialize the list of filters to be an empty list.
- """
- self.filters = []
-
- def addFilter(self, filter):
- """
- Add the specified filter to this handler.
- """
- if not (filter in self.filters):
- self.filters.append(filter)
-
- def removeFilter(self, filter):
- """
- Remove the specified filter from this handler.
- """
- if filter in self.filters:
- self.filters.remove(filter)
-
- def filter(self, record):
- """
- Determine if a record is loggable by consulting all the filters. The
- default is to allow the record to be logged; any filter can veto this
- and the record is then dropped. Returns a boolean value.
- """
- rv = 1
- for f in self.filters:
- if not f.filter(record):
- rv = 0
- break
- return rv
-
-#---------------------------------------------------------------------------
-# Handler classes and functions
-#---------------------------------------------------------------------------
-
-_handlers = {} #repository of handlers (for flushing when shutdown called)
-
-class Handler(Filterer):
- """
- The base handler class. Acts as a placeholder which defines the Handler
- interface. Handlers can optionally use Formatter instances to format
- records as desired. By default, no formatter is specified; in this case,
- the 'raw' message as determined by record.message is logged.
- """
- def __init__(self, level=ALL):
- """
- Initializes the instance - basically setting the formatter to None
- and the filter list to empty.
- """
- Filterer.__init__(self)
- self.level = level
- self.formatter = None
- #get the module data lock, as we're updating a shared structure.
- _acquireLock()
- try: #unlikely to raise an exception, but you never know...
- _handlers[self] = 1
- finally:
- _releaseLock()
- self.createLock()
-
- def createLock(self):
- """
- Acquire a thread lock for serializing access to the underlying I/O.
- """
- if thread:
- self.lock = thread.allocate_lock()
- else:
- self.lock = None
-
- def acquire(self):
- """
- Acquire the I/O thread lock.
- """
- if self.lock:
- self.lock.acquire()
-
- def release(self):
- """
- Release the I/O thread lock.
- """
- if self.lock:
- self.lock.release()
-
- def setLevel(self, lvl):
- """
- Set the logging level of this handler.
- """
- self.level = lvl
-
- def format(self, record):
- """
- Do formatting for a record - if a formatter is set, use it.
- Otherwise, use the default formatter for the module.
- """
- if self.formatter:
- fmt = self.formatter
- else:
- fmt = _defaultFormatter
- return fmt.format(record)
-
- def emit(self, record):
- """
- Do whatever it takes to actually log the specified logging record.
- This version is intended to be implemented by subclasses and so
- raises a NotImplementedError.
- """
- raise NotImplementedError, 'emit must be implemented '\
- 'by Handler subclasses'
-
- def handle(self, record):
- """
- Conditionally emit the specified logging record, depending on
- filters which may have been added to the handler. Wrap the actual
- emission of the record with acquisition/release of the I/O thread
- lock.
- """
- if self.filter(record):
- self.acquire()
- try:
- self.emit(record)
- finally:
- self.release()
-
- def setFormatter(self, fmt):
- """
- Set the formatter for this handler.
- """
- self.formatter = fmt
-
- def flush(self):
- """
- Ensure all logging output has been flushed. This version does
- nothing and is intended to be implemented by subclasses.
- """
- pass
-
- def close(self):
- """
- Tidy up any resources used by the handler. This version does
- nothing and is intended to be implemented by subclasses.
- """
- pass
-
- def handleError(self):
- """
- This method should be called from handlers when an exception is
- encountered during an emit() call. By default it does nothing,
- which means that exceptions get silently ignored. This is what is
- mostly wanted for a logging system - most users will not care
- about errors in the logging system, they are more interested in
- application errors. You could, however, replace this with a custom
- handler if you wish.
- """
- #import traceback
- #ei = sys.exc_info()
- #traceback.print_exception(ei[0], ei[1], ei[2], None, sys.stderr)
- #del ei
- pass
-
-class StreamHandler(Handler):
- """
- A handler class which writes logging records, appropriately formatted,
- to a stream. Note that this class does not close the stream, as
- sys.stdout or sys.stderr may be used.
- """
- def __init__(self, strm=None):
- """
- If strm is not specified, sys.stderr is used.
- """
- Handler.__init__(self)
- if not strm:
- strm = sys.stderr
- self.stream = strm
- self.formatter = None
-
- def flush(self):
- """
- Flushes the stream.
- """
- self.stream.flush()
-
- def emit(self, record):
- """
- If a formatter is specified, it is used to format the record.
- The record is then written to the stream with a trailing newline
- [N.B. this may be removed depending on feedback]. If exception
- information is present, it is formatted using
- traceback.print_exception and appended to the stream.
- """
- try:
- msg = self.format(record)
- self.stream.write("%s\n" % msg)
- self.flush()
- except:
- self.handleError()
-
-class FileHandler(StreamHandler):
- """
- A handler class which writes formatted logging records to disk files.
- """
- def __init__(self, filename, mode="a+"):
- """
- Open the specified file and use it as the stream for logging.
- By default, the file grows indefinitely. You can call setRollover()
- to allow the file to rollover at a predetermined size.
- """
- StreamHandler.__init__(self, open(filename, mode))
- self.maxBytes = 0
- self.backupCount = 0
- self.baseFilename = filename
- #self.backupIndex = 0
- self.mode = mode
-
- def setRollover(self, maxBytes, backupCount):
- """
- Set the rollover parameters so that rollover occurs whenever the
- current log file is nearly maxBytes in length. If backupCount
- is >= 1, the system will successively create new files with the
- same pathname as the base file, but with extensions ".1", ".2"
- etc. appended to it. For example, with a backupCount of 5 and a
- base file name of "app.log", you would get "app.log", "app.log.1",
- "app.log.2", ... through to "app.log.5". When the last file reaches
- its size limit, the logging reverts to "app.log" which is truncated
- to zero length. If maxBytes is zero, rollover never occurs.
- """
- self.maxBytes = maxBytes
- self.backupCount = backupCount
- if maxBytes > 0:
- self.mode = "a+"
-
- def doRollover(self):
- """
- Do a rollover, as described in setRollover().
- """
-# Old algorithm
-# if self.backupIndex >= self.backupCount:
-# self.backupIndex = 0
-# fn = self.baseFilename
-# else:
-# self.backupIndex = self.backupIndex + 1
-# fn = "%s.%d" % (self.baseFilename, self.backupIndex)
-# self.stream.close()
-# self.stream = open(fn, "w+")
- self.stream.close()
- if self.backupCount > 0:
- for i in range(self.backupCount - 1, 0, -1):
- sfn = "%s.%d" % (self.baseFilename, i)
- dfn = "%s.%d" % (self.baseFilename, i + 1)
- if os.path.exists(sfn):
- #print "%s -> %s" % (sfn, dfn)
- if os.path.exists(dfn):
- os.remove(dfn)
- os.rename(sfn, dfn)
- dfn = self.baseFilename + ".1"
- if os.path.exists(dfn):
- os.remove(dfn)
- os.rename(self.baseFilename, dfn)
- self.stream = open(self.baseFilename, "w+")
-
- def emit(self, record):
- """
- Output the record to the file, catering for rollover as described
- in setRollover().
- """
- if self.maxBytes > 0: # are we rolling over?
- msg = "%s\n" % self.format(record)
- if self.stream.tell() + len(msg) >= self.maxBytes:
- self.doRollover()
- StreamHandler.emit(self, record)
-
- def close(self):
- """
- Closes the stream.
- """
- self.stream.close()
-
-class SocketHandler(Handler):
- """
- A handler class which writes logging records, in pickle format, to
- a streaming socket. The socket is kept open across logging calls.
- If the peer resets it, an attempt is made to reconnect on the next call.
- Note that the very simple wire protocol used means that packet sizes
- are expected to be encodable within 16 bits (i.e. < 32767 bytes).
- """
-
- def __init__(self, host, port):
- """
- Initializes the handler with a specific host address and port.
- """
- Handler.__init__(self)
- self.host = host
- self.port = port
- self.sock = None
- self.closeOnError = 1
-
- def makeSocket(self):
- """
- A factory method which allows subclasses to define the precise
- type of socket they want.
- """
- s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
- s.connect((self.host, self.port))
- return s
-
- def send(self, s):
- """
- Send a pickled string to the socket. This function allows for
- partial sends which can happen when the network is busy.
- """
- sentsofar = 0
- left = len(s)
- while left > 0:
- sent = self.sock.send(s[sentsofar:])
- sentsofar = sentsofar + sent
- left = left - sent
-
- def makePickle(self, record):
- """
- Pickles the record in binary format with a length prefix, and
- returns it ready for transmission across the socket.
- """
- s = cPickle.dumps(record.__dict__, 1)
- n = len(s)
- slen = "%c%c" % ((n >> 8) & 0xFF, n & 0xFF)
- return slen + s
-
- def handleError(self):
- """
- An error has occurred during logging. Most likely cause -
- connection lost. Close the socket so that we can retry on the
- next event.
- """
- if self.closeOnError and self.sock:
- self.sock.close()
- self.sock = None #try to reconnect next time
-
- def emit(self, record):
- """
- Pickles the record and writes it to the socket in binary format.
- If there is an error with the socket, silently drop the packet.
- If there was a problem with the socket, re-establishes the
- socket.
- """
- try:
- s = self.makePickle(record)
- if not self.sock:
- self.sock = self.makeSocket()
- self.send(s)
- except:
- self.handleError()
-
- def close(self):
- """
- Closes the socket.
- """
- if self.sock:
- self.sock.close()
- self.sock = None
-
-class DatagramHandler(SocketHandler):
- """
- A handler class which writes logging records, in pickle format, to
- a datagram socket. Note that the very simple wire protocol used means
- that packet sizes are expected to be encodable within 16 bits
- (i.e. < 32767 bytes).
-
- """
- def __init__(self, host, port):
- """
- Initializes the handler with a specific host address and port.
- """
- SocketHandler.__init__(self, host, port)
- self.closeOnError = 0
-
- def makeSocket(self):
- """
- The factory method of SocketHandler is here overridden to create
- a UDP socket (SOCK_DGRAM).
- """
- s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
- return s
-
- def send(self, s):
- """
- Send a pickled string to a socket. This function allows for
- partial sends which can happen when the network is busy.
- """
- sentsofar = 0
- left = len(s)
- addr = (self.host, self.port)
- while left > 0:
- sent = self.sock.sendto(s[sentsofar:], addr)
- sentsofar = sentsofar + sent
- left = left - sent
-
-class SysLogHandler(Handler):
- """
- A handler class which sends formatted logging records to a syslog
- server. Based on Sam Rushing's syslog module:
- http://www.nightmare.com/squirl/python-ext/misc/syslog.py
- Contributed by Nicolas Untz (after which minor refactoring changes
- have been made).
- """
-
- # from <linux/sys/syslog.h>:
- # ======================================================================
- # priorities/facilities are encoded into a single 32-bit quantity, where
- # the bottom 3 bits are the priority (0-7) and the top 28 bits are the
- # facility (0-big number). Both the priorities and the facilities map
- # roughly one-to-one to strings in the syslogd(8) source code. This
- # mapping is included in this file.
- #
- # priorities (these are ordered)
-
- LOG_EMERG = 0 # system is unusable
- LOG_ALERT = 1 # action must be taken immediately
- LOG_CRIT = 2 # critical conditions
- LOG_ERR = 3 # error conditions
- LOG_WARNING = 4 # warning conditions
- LOG_NOTICE = 5 # normal but significant condition
- LOG_INFO = 6 # informational
- LOG_DEBUG = 7 # debug-level messages
-
- # facility codes
- LOG_KERN = 0 # kernel messages
- LOG_USER = 1 # random user-level messages
- LOG_MAIL = 2 # mail system
- LOG_DAEMON = 3 # system daemons
- LOG_AUTH = 4 # security/authorization messages
- LOG_SYSLOG = 5 # messages generated internally by syslogd
- LOG_LPR = 6 # line printer subsystem
- LOG_NEWS = 7 # network news subsystem
- LOG_UUCP = 8 # UUCP subsystem
- LOG_CRON = 9 # clock daemon
- LOG_AUTHPRIV = 10 # security/authorization messages (private)
-
- # other codes through 15 reserved for system use
- LOG_LOCAL0 = 16 # reserved for local use
- LOG_LOCAL1 = 17 # reserved for local use
- LOG_LOCAL2 = 18 # reserved for local use
- LOG_LOCAL3 = 19 # reserved for local use
- LOG_LOCAL4 = 20 # reserved for local use
- LOG_LOCAL5 = 21 # reserved for local use
- LOG_LOCAL6 = 22 # reserved for local use
- LOG_LOCAL7 = 23 # reserved for local use
-
- priority_names = {
- "alert": LOG_ALERT,
- "crit": LOG_CRIT,
- "critical": LOG_CRIT,
- "debug": LOG_DEBUG,
- "emerg": LOG_EMERG,
- "err": LOG_ERR,
- "error": LOG_ERR, # DEPRECATED
- "info": LOG_INFO,
- "notice": LOG_NOTICE,
- "panic": LOG_EMERG, # DEPRECATED
- "warn": LOG_WARNING, # DEPRECATED
- "warning": LOG_WARNING,
- }
-
- facility_names = {
- "auth": LOG_AUTH,
- "authpriv": LOG_AUTHPRIV,
- "cron": LOG_CRON,
- "daemon": LOG_DAEMON,
- "kern": LOG_KERN,
- "lpr": LOG_LPR,
- "mail": LOG_MAIL,
- "news": LOG_NEWS,
- "security": LOG_AUTH, # DEPRECATED
- "syslog": LOG_SYSLOG,
- "user": LOG_USER,
- "uucp": LOG_UUCP,
- "local0": LOG_LOCAL0,
- "local1": LOG_LOCAL1,
- "local2": LOG_LOCAL2,
- "local3": LOG_LOCAL3,
- "local4": LOG_LOCAL4,
- "local5": LOG_LOCAL5,
- "local6": LOG_LOCAL6,
- "local7": LOG_LOCAL7,
- }
-
- def __init__(self, address=('localhost', SYSLOG_UDP_PORT), facility=LOG_USER):
- """
- If address is specified as a string, UNIX socket is used.
- If facility is not specified, LOG_USER is used.
- """
- Handler.__init__(self)
-
- self.address = address
- self.facility = facility
- if type(address) == types.StringType:
- self.socket = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
- self.socket.connect(address)
- self.unixsocket = 1
- else:
- self.socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
- self.unixsocket = 0
-
- self.formatter = None
-
- # curious: when talking to the unix-domain '/dev/log' socket, a
- # zero-terminator seems to be required. this string is placed
- # into a class variable so that it can be overridden if
- # necessary.
- log_format_string = '<%d>%s\000'
-
- def encodePriority (self, facility, priority):
- """
- Encode the facility and priority. You can pass in strings or
- integers - if strings are passed, the facility_names and
- priority_names mapping dictionaries are used to convert them to
- integers.
- """
- if type(facility) == types.StringType:
- facility = self.facility_names[facility]
- if type(priority) == types.StringType:
- priority = self.priority_names[priority]
- return (facility << 3) | priority
-
- def close (self):
- """
- Closes the socket.
- """
- if self.unixsocket:
- self.socket.close()
-
- def emit(self, record):
- """
- The record is formatted, and then sent to the syslog server. If
- exception information is present, it is NOT sent to the server.
- """
- msg = self.format(record)
- """
- We need to convert record level to lowercase, maybe this will
- change in the future.
- """
- msg = self.log_format_string % (
- self.encodePriority(self.facility,
- string.lower(record.levelname)),
- msg)
- try:
- if self.unixsocket:
- self.socket.send(msg)
- else:
- self.socket.sendto(msg, self.address)
- except:
- self.handleError()
-
-class SMTPHandler(Handler):
- """
- A handler class which sends an SMTP email for each logging event.
- """
- def __init__(self, mailhost, fromaddr, toaddrs, subject):
- """
- Initialize the instance with the from and to addresses and subject
- line of the email. To specify a non-standard SMTP port, use the
- (host, port) tuple format for the mailhost argument.
- """
- Handler.__init__(self)
- if type(mailhost) == types.TupleType:
- host, port = mailhost
- self.mailhost = host
- self.mailport = port
- else:
- self.mailhost = mailhost
- self.mailport = None
- self.fromaddr = fromaddr
- self.toaddrs = toaddrs
- self.subject = subject
-
- def getSubject(self, record):
- """
- If you want to specify a subject line which is record-dependent,
- override this method.
- """
- return self.subject
-
- def emit(self, record):
- """
- Format the record and send it to the specified addressees.
- """
- try:
- import smtplib
- port = self.mailport
- if not port:
- port = smtplib.SMTP_PORT
- smtp = smtplib.SMTP(self.mailhost, port)
- msg = self.format(record)
- msg = "From: %s\r\nTo: %s\r\nSubject: %s\r\n\r\n%s" % (
- self.fromaddr,
- string.join(self.toaddrs, ","),
- self.getSubject(record), msg
- )
- smtp.sendmail(self.fromaddr, self.toaddrs, msg)
- smtp.quit()
- except:
- self.handleError()
-
-class BufferingHandler(Handler):
- """
- A handler class which buffers logging records in memory. Whenever each
- record is added to the buffer, a check is made to see if the buffer should
- be flushed. If it should, then flush() is expected to do the needful.
- """
- def __init__(self, capacity):
- """
- Initialize the handler with the buffer size.
- """
- Handler.__init__(self)
- self.capacity = capacity
- self.buffer = []
-
- def shouldFlush(self, record):
- """
- Returns true if the buffer is up to capacity. This method can be
- overridden to implement custom flushing strategies.
- """
- return (len(self.buffer) >= self.capacity)
-
- def emit(self, record):
- """
- Append the record. If shouldFlush() tells us to, call flush() to process
- the buffer.
- """
- self.buffer.append(record)
- if self.shouldFlush(record):
- self.flush()
-
- def flush(self):
- """
- Override to implement custom flushing behaviour. This version just zaps
- the buffer to empty.
- """
- self.buffer = []
-
-class MemoryHandler(BufferingHandler):
- """
- A handler class which buffers logging records in memory, periodically
- flushing them to a target handler. Flushing occurs whenever the buffer
- is full, or when an event of a certain severity or greater is seen.
- """
- def __init__(self, capacity, flushLevel=ERROR, target=None):
- """
- Initialize the handler with the buffer size, the level at which
- flushing should occur and an optional target. Note that without a
- target being set either here or via setTarget(), a MemoryHandler
- is no use to anyone!
- """
- BufferingHandler.__init__(self, capacity)
- self.flushLevel = flushLevel
- self.target = target
-
- def shouldFlush(self, record):
- """
- Check for buffer full or a record at the flushLevel or higher.
- """
- return (len(self.buffer) >= self.capacity) or \
- (record.levelno >= self.flushLevel)
-
- def setTarget(self, target):
- """
- Set the target handler for this handler.
- """
- self.target = target
-
- def flush(self):
- """
- For a MemoryHandler, flushing means just sending the buffered
- records to the target, if there is one. Override if you want
- different behaviour.
- """
- if self.target:
- for record in self.buffer:
- self.target.handle(record)
- self.buffer = []
-
- def close(self):
- """
- Flush, set the target to None and lose the buffer.
- """
- self.flush()
- self.target = None
- self.buffer = []
-
-class NTEventLogHandler(Handler):
- """
- A handler class which sends events to the NT Event Log. Adds a
- registry entry for the specified application name. If no dllname is
- provided, win32service.pyd (which contains some basic message
- placeholders) is used. Note that use of these placeholders will make
- your event logs big, as the entire message source is held in the log.
- If you want slimmer logs, you have to pass in the name of your own DLL
- which contains the message definitions you want to use in the event log.
- """
- def __init__(self, appname, dllname=None, logtype="Application"):
- Handler.__init__(self)
- try:
- import win32evtlogutil, win32evtlog
- self.appname = appname
- self._welu = win32evtlogutil
- if not dllname:
- dllname = os.path.split(self._welu.__file__)
- dllname = os.path.split(dllname[0])
- dllname = os.path.join(dllname[0], r'win32service.pyd')
- self.dllname = dllname
- self.logtype = logtype
- self._welu.AddSourceToRegistry(appname, dllname, logtype)
- self.deftype = win32evtlog.EVENTLOG_ERROR_TYPE
- self.typemap = {
- DEBUG : win32evtlog.EVENTLOG_INFORMATION_TYPE,
- INFO : win32evtlog.EVENTLOG_INFORMATION_TYPE,
- WARN : win32evtlog.EVENTLOG_WARNING_TYPE,
- ERROR : win32evtlog.EVENTLOG_ERROR_TYPE,
- CRITICAL: win32evtlog.EVENTLOG_ERROR_TYPE,
- }
- except ImportError:
- print "The Python Win32 extensions for NT (service, event "\
- "logging) appear not to be available."
- self._welu = None
-
- def getMessageID(self, record):
- """
- Return the message ID for the event record. If you are using your
- own messages, you could do this by having the msg passed to the
- logger being an ID rather than a formatting string. Then, in here,
- you could use a dictionary lookup to get the message ID. This
- version returns 1, which is the base message ID in win32service.pyd.
- """
- return 1
-
- def getEventCategory(self, record):
- """
- Return the event category for the record. Override this if you
- want to specify your own categories. This version returns 0.
- """
- return 0
-
- def getEventType(self, record):
- """
- Return the event type for the record. Override this if you want
- to specify your own types. This version does a mapping using the
- handler's typemap attribute, which is set up in __init__() to a
- dictionary which contains mappings for DEBUG, INFO, WARN, ERROR
- and CRITICAL. If you are using your own levels you will either need
- to override this method or place a suitable dictionary in the
- handler's typemap attribute.
- """
- return self.typemap.get(record.levelno, self.deftype)
-
- def emit(self, record):
- """
- Determine the message ID, event category and event type. Then
- log the message in the NT event log.
- """
- if self._welu:
- try:
- id = self.getMessageID(record)
- cat = self.getEventCategory(record)
- type = self.getEventType(record)
- msg = self.format(record)
- self._welu.ReportEvent(self.appname, id, cat, type, [msg])
- except:
- self.handleError()
-
- def close(self):
- """
- You can remove the application name from the registry as a
- source of event log entries. However, if you do this, you will
- not be able to see the events as you intended in the Event Log
- Viewer - it needs to be able to access the registry to get the
- DLL name.
- """
- #self._welu.RemoveSourceFromRegistry(self.appname, self.logtype)
- pass
-
-class HTTPHandler(Handler):
- """
- A class which sends records to a Web server, using either GET or
- POST semantics.
- """
- def __init__(self, host, url, method="GET"):
- """
- Initialize the instance with the host, the request URL, and the method
- ("GET" or "POST")
- """
- Handler.__init__(self)
- method = string.upper(method)
- if method not in ["GET", "POST"]:
- raise ValueError, "method must be GET or POST"
- self.host = host
- self.url = url
- self.method = method
-
- def emit(self, record):
- """
- Send the record to the Web server as an URL-encoded dictionary
- """
- try:
- import httplib, urllib
- h = httplib.HTTP(self.host)
- url = self.url
- data = urllib.urlencode(record.__dict__)
- if self.method == "GET":
- if (string.find(url, '?') >= 0):
- sep = '&'
- else:
- sep = '?'
- url = url + "%c%s" % (sep, data)
- h.putrequest(self.method, url)
- if self.method == "POST":
- h.putheader("Content-length", str(len(data)))
- h.endheaders()
- if self.method == "POST":
- h.send(data)
- h.getreply() #can't do anything with the result
- except:
- self.handleError()
-
-#---------------------------------------------------------------------------
-# Manager classes and functions
-#---------------------------------------------------------------------------
-
-class PlaceHolder:
- """
- PlaceHolder instances are used in the Manager logger hierarchy to take
- the place of nodes for which no loggers have been defined [FIXME add
- example].
- """
- def __init__(self, alogger):
- """
- Initialize with the specified logger being a child of this placeholder.
- """
- self.loggers = [alogger]
-
- def append(self, alogger):
- """
- Add the specified logger as a child of this placeholder.
- """
- if alogger not in self.loggers:
- self.loggers.append(alogger)
-
-#
-# Determine which class to use when instantiating loggers.
-#
-_loggerClass = None
-
-def setLoggerClass(klass):
- """
- Set the class to be used when instantiating a logger. The class should
- define __init__() such that only a name argument is required, and the
- __init__() should call Logger.__init__()
- """
- if klass != Logger:
- if type(klass) != types.ClassType:
- raise TypeError, "setLoggerClass is expecting a class"
- if not issubclass(klass, Logger):
- raise TypeError, "logger not derived from logging.Logger: " + \
- klass.__name__
- global _loggerClass
- _loggerClass = klass
-
-class Manager:
- """
- There is [under normal circumstances] just one Manager instance, which
- holds the hierarchy of loggers.
- """
- def __init__(self, root):
- """
- Initialize the manager with the root node of the logger hierarchy.
- """
- self.root = root
- self.disable = 0
- self.emittedNoHandlerWarning = 0
- self.loggerDict = {}
-
- def getLogger(self, name):
- """
- Get a logger with the specified name, creating it if it doesn't
- yet exist. If a PlaceHolder existed for the specified name [i.e.
- the logger didn't exist but a child of it did], replace it with
- the created logger and fix up the parent/child references which
- pointed to the placeholder to now point to the logger.
- """
- rv = None
- _acquireLock()
- try:
- if self.loggerDict.has_key(name):
- rv = self.loggerDict[name]
- if isinstance(rv, PlaceHolder):
- ph = rv
- rv = _loggerClass(name)
- rv.manager = self
- self.loggerDict[name] = rv
- self._fixupChildren(ph, rv)
- self._fixupParents(rv)
- else:
- rv = _loggerClass(name)
- rv.manager = self
- self.loggerDict[name] = rv
- self._fixupParents(rv)
- finally:
- _releaseLock()
- return rv
-
- def _fixupParents(self, alogger):
- """
- Ensure that there are either loggers or placeholders all the way
- from the specified logger to the root of the logger hierarchy.
- """
- name = alogger.name
- i = string.rfind(name, ".")
- rv = None
- while (i > 0) and not rv:
- substr = name[:i]
- if not self.loggerDict.has_key(substr):
- self.loggerDict[substr] = PlaceHolder(alogger)
- else:
- obj = self.loggerDict[substr]
- if isinstance(obj, Logger):
- rv = obj
- else:
- assert isinstance(obj, PlaceHolder)
- obj.append(alogger)
- i = string.rfind(name, ".", 0, i - 1)
- if not rv:
- rv = self.root
- alogger.parent = rv
-
- def _fixupChildren(self, ph, alogger):
- """
- Ensure that children of the placeholder ph are connected to the
- specified logger.
- """
- for c in ph.loggers:
- if string.find(c.parent.name, alogger.name) <> 0:
- alogger.parent = c.parent
- c.parent = alogger
-
-#---------------------------------------------------------------------------
-# Logger classes and functions
-#---------------------------------------------------------------------------
-
-class Logger(Filterer):
- """
- Instances of the Logger class represent a single logging channel. A
- "logging channel" indicates an area of an application. Exactly how an
- "area" is defined is up to the application developer. Since an
- application can have any number of areas, logging channels are identified
- by a unique string. Application areas can be nested (e.g. an area
- of "input processing" might include sub-areas "read CSV files", "read
- XLS files" and "read Gnumeric files"). To cater for this natural nesting,
- channel names are organized into a namespace hierarchy where levels are
- separated by periods, much like the Java or Python package namespace. So
- in the instance given above, channel names might be "input" for the upper
- level, and "input.csv", "input.xls" and "input.gnu" for the sub-levels.
- There is no arbitrary limit to the depth of nesting.
- """
- def __init__(self, name, level=ALL):
- """
- Initialize the logger with a name and an optional level.
- """
- Filterer.__init__(self)
- self.name = name
- self.level = level
- self.parent = None
- self.propagate = 1
- self.handlers = []
- self.disabled = 0
-
- def setLevel(self, lvl):
- """
- Set the logging level of this logger.
- """
- self.level = lvl
-
-# def getRoot(self):
-# """
-# Get the root of the logger hierarchy.
-# """
-# return Logger.root
-
- def debug(self, msg, *args, **kwargs):
- """
- Log 'msg % args' with severity 'DEBUG'. To pass exception information,
- use the keyword argument exc_info with a true value, e.g.
-
- logger.debug("Houston, we have a %s", "thorny problem", exc_info=1)
- """
- if self.manager.disable >= DEBUG:
- return
- if DEBUG >= self.getEffectiveLevel():
- apply(self._log, (DEBUG, msg, args), kwargs)
-
- def info(self, msg, *args, **kwargs):
- """
- Log 'msg % args' with severity 'INFO'. To pass exception information,
- use the keyword argument exc_info with a true value, e.g.
-
- logger.info("Houston, we have a %s", "interesting problem", exc_info=1)
- """
- if self.manager.disable >= INFO:
- return
- if INFO >= self.getEffectiveLevel():
- apply(self._log, (INFO, msg, args), kwargs)
-
- def warn(self, msg, *args, **kwargs):
- """
- Log 'msg % args' with severity 'WARN'. To pass exception information,
- use the keyword argument exc_info with a true value, e.g.
-
- logger.warn("Houston, we have a %s", "bit of a problem", exc_info=1)
- """
- if self.manager.disable >= WARN:
- return
- if self.isEnabledFor(WARN):
- apply(self._log, (WARN, msg, args), kwargs)
-
- def error(self, msg, *args, **kwargs):
- """
- Log 'msg % args' with severity 'ERROR'. To pass exception information,
- use the keyword argument exc_info with a true value, e.g.
-
- logger.error("Houston, we have a %s", "major problem", exc_info=1)
- """
- if self.manager.disable >= ERROR:
- return
- if self.isEnabledFor(ERROR):
- apply(self._log, (ERROR, msg, args), kwargs)
-
- def exception(self, msg, *args):
- """
- Convenience method for logging an ERROR with exception information
- """
- apply(self.error, (msg,) + args, {'exc_info': 1})
-
- def critical(self, msg, *args, **kwargs):
- """
- Log 'msg % args' with severity 'CRITICAL'. To pass exception
- information, use the keyword argument exc_info with a true value, e.g.
-
- logger.critical("Houston, we have a %s", "major disaster", exc_info=1)
- """
- if self.manager.disable >= CRITICAL:
- return
- if CRITICAL >= self.getEffectiveLevel():
- apply(self._log, (CRITICAL, msg, args), kwargs)
-
- fatal = critical
-
- def log(self, lvl, msg, *args, **kwargs):
- """
- Log 'msg % args' with the severity 'lvl'. To pass exception
- information, use the keyword argument exc_info with a true value, e.g.
- logger.log(lvl, "We have a %s", "mysterious problem", exc_info=1)
- """
- if self.manager.disable >= lvl:
- return
- if self.isEnabledFor(lvl):
- apply(self._log, (lvl, msg, args), kwargs)
-
- def findCaller(self):
- """
- Find the stack frame of the caller so that we can note the source
- file name and line number.
- """
- rv = (None, None)
- frame = inspect.currentframe().f_back
- while frame:
- sfn = inspect.getsourcefile(frame)
- if sfn:
- sfn = os.path.normcase(sfn)
- if sfn != _srcfile:
- #print frame.f_code.co_code
- lineno = inspect.getlineno(frame)
- rv = (sfn, lineno)
- break
- frame = frame.f_back
- return rv
-
- def makeRecord(self, name, lvl, fn, lno, msg, args, exc_info):
- """
- A factory method which can be overridden in subclasses to create
- specialized LogRecords.
- """
- return LogRecord(name, lvl, fn, lno, msg, args, exc_info)
-
- def _log(self, lvl, msg, args, exc_info=None):
- """
- Low-level logging routine which creates a LogRecord and then calls
- all the handlers of this logger to handle the record.
- """
- if inspect and _srcfile:
- _acquireLock()
- try:
- fn, lno = self.findCaller()
- finally:
- _releaseLock()
- else:
- fn, lno = "<unknown file>", 0
- if exc_info:
- exc_info = sys.exc_info()
- record = self.makeRecord(self.name, lvl, fn, lno, msg, args, exc_info)
- self.handle(record)
-
- def handle(self, record):
- """
- Call the handlers for the specified record. This method is used for
- unpickled records received from a socket, as well as those created
- locally. Logger-level filtering is applied.
- """
- if (not self.disabled) and self.filter(record):
- self.callHandlers(record)
-
- def addHandler(self, hdlr):
- """
- Add the specified handler to this logger.
- """
- if not (hdlr in self.handlers):
- self.handlers.append(hdlr)
-
- def removeHandler(self, hdlr):
- """
- Remove the specified handler from this logger.
- """
- if hdlr in self.handlers:
- hdlr.close()
- self.handlers.remove(hdlr)
-
- def callHandlers(self, record):
- """
- Loop through all handlers for this logger and its parents in the
- logger hierarchy. If no handler was found, output a one-off error
- message to sys.stderr. Stop searching up the hierarchy whenever a
- logger with the "propagate" attribute set to zero is found - that
- will be the last logger whose handlers are called.
- """
- c = self
- found = 0
- while c:
- for hdlr in c.handlers:
- found = found + 1
- if record.levelno >= hdlr.level:
- hdlr.handle(record)
- if not c.propagate:
- c = None #break out
- else:
- c = c.parent
- if (found == 0) and not self.manager.emittedNoHandlerWarning:
- sys.stderr.write("No handlers could be found for logger"
- " \"%s\"\n" % self.name)
- self.manager.emittedNoHandlerWarning = 1
-
- def getEffectiveLevel(self):
- """
- Loop through this logger and its parents in the logger hierarchy,
- looking for a non-zero logging level. Return the first one found.
- """
- logger = self
- while logger:
- if logger.level:
- return logger.level
- logger = logger.parent
- return ALL
-
- def isEnabledFor(self, lvl):
- """
- Is this logger enabled for level lvl?
- """
- if self.manager.disable >= lvl:
- return 0
- return lvl >= self.getEffectiveLevel()
-
-class RootLogger(Logger):
- """
- A root logger is not that different to any other logger, except that
- it must have a logging level and there is only one instance of it in
- the hierarchy.
- """
- def __init__(self, lvl):
- """
- Initialize the logger with the name "root".
- """
- Logger.__init__(self, "root", lvl)
-
-_loggerClass = Logger
-
-root = RootLogger(DEBUG)
-Logger.root = root
-Logger.manager = Manager(Logger.root)
-
-#---------------------------------------------------------------------------
-# Configuration classes and functions
-#---------------------------------------------------------------------------
-
-BASIC_FORMAT = "%(levelname)s:%(name)s:%(message)s"
-
-def basicConfig():
- """
- Do basic configuration for the logging system by creating a
- StreamHandler with a default Formatter and adding it to the
- root logger.
- """
- if len(root.handlers) == 0:
- hdlr = StreamHandler()
- fmt = Formatter(BASIC_FORMAT)
- hdlr.setFormatter(fmt)
- root.addHandler(hdlr)
-
-def fileConfig(fname):
- """
- Read the logging configuration from a ConfigParser-format file. This can
- be called several times from an application, allowing an end user the
- ability to select from various pre-canned configurations (if the
- developer provides a mechanism to present the choices and load the chosen
- configuration).
- """
- import ConfigParser
-
- cp = ConfigParser.ConfigParser()
- cp.read(fname)
- #first, do the formatters...
- flist = cp.get("formatters", "keys")
- if len(flist):
- flist = string.split(flist, ",")
- formatters = {}
- for form in flist:
- sectname = "formatter_%s" % form
- opts = cp.options(sectname)
- if "format" in opts:
- fs = cp.get(sectname, "format", 1)
- else:
- fs = None
- if "datefmt" in opts:
- dfs = cp.get(sectname, "datefmt", 1)
- else:
- dfs = None
- f = Formatter(fs, dfs)
- formatters[form] = f
- #next, do the handlers...
- #critical section...
- _acquireLock()
- try:
- try:
- #first, lose the existing handlers...
- _handlers.clear()
- #now set up the new ones...
- hlist = cp.get("handlers", "keys")
- if len(hlist):
- hlist = string.split(hlist, ",")
- handlers = {}
- fixups = [] #for inter-handler references
- for hand in hlist:
- sectname = "handler_%s" % hand
- klass = cp.get(sectname, "class")
- opts = cp.options(sectname)
- if "formatter" in opts:
- fmt = cp.get(sectname, "formatter")
- else:
- fmt = ""
- klass = eval(klass)
- args = cp.get(sectname, "args")
- args = eval(args)
- h = apply(klass, args)
- if "level" in opts:
- lvl = cp.get(sectname, "level")
- h.setLevel(_levelNames[lvl])
- if len(fmt):
- h.setFormatter(formatters[fmt])
- #temporary hack for FileHandler and MemoryHandler.
- if klass == FileHandler:
- maxsize = 0
- if "maxsize" in opts:
- ms = cp.getint(sectname, "maxsize")
- if ms > 0:
- maxsize = ms
- if maxsize:
- backcount = 0
- if "backcount" in opts:
- bc = cp.getint(sectname, "backcount")
- if bc > 0:
- backcount = bc
- h.setRollover(maxsize, backcount)
- elif klass == MemoryHandler:
- if "target" in opts:
- target = cp.get(sectname,"target")
- else:
- target = ""
- if len(target): #the target handler may not be loaded yet, so keep for later...
- fixups.append((h, target))
- handlers[hand] = h
- #now all handlers are loaded, fixup inter-handler references...
- for fixup in fixups:
- h = fixup[0]
- t = fixup[1]
- h.setTarget(handlers[t])
- #at last, the loggers...first the root...
- llist = cp.get("loggers", "keys")
- llist = string.split(llist, ",")
- llist.remove("root")
- sectname = "logger_root"
- log = root
- opts = cp.options(sectname)
- if "level" in opts:
- lvl = cp.get(sectname, "level")
- log.setLevel(_levelNames[lvl])
- for h in root.handlers:
- root.removeHandler(h)
- hlist = cp.get(sectname, "handlers")
- if len(hlist):
- hlist = string.split(hlist, ",")
- for hand in hlist:
- log.addHandler(handlers[hand])
- #and now the others...
- #we don't want to lose the existing loggers,
- #since other threads may have pointers to them.
- #existing is set to contain all existing loggers,
- #and as we go through the new configuration we
- #remove any which are configured. At the end,
- #what's left in existing is the set of loggers
- #which were in the previous configuration but
- #which are not in the new configuration.
- existing = root.manager.loggerDict.keys()
- #now set up the new ones...
- for log in llist:
- sectname = "logger_%s" % log
- qn = cp.get(sectname, "qualname")
- opts = cp.options(sectname)
- if "propagate" in opts:
- propagate = cp.getint(sectname, "propagate")
- else:
- propagate = 1
- logger = getLogger(qn)
- if qn in existing:
- existing.remove(qn)
- if "level" in opts:
- lvl = cp.get(sectname, "level")
- logger.setLevel(_levelNames[lvl])
- for h in logger.handlers:
- logger.removeHandler(h)
- logger.propagate = propagate
- logger.disabled = 0
- hlist = cp.get(sectname, "handlers")
- if len(hlist):
- hlist = string.split(hlist, ",")
- for hand in hlist:
- logger.addHandler(handlers[hand])
- #Disable any old loggers. There's no point deleting
- #them as other threads may continue to hold references
- #and by disabling them, you stop them doing any logging.
- for log in existing:
- root.manager.loggerDict[log].disabled = 1
- except:
- import traceback
- ei = sys.exc_info()
- traceback.print_exception(ei[0], ei[1], ei[2], None, sys.stderr)
- del ei
- finally:
- _releaseLock()
-
-#---------------------------------------------------------------------------
-# Utility functions at module level.
-# Basically delegate everything to the root logger.
-#---------------------------------------------------------------------------
-
-def getLogger(name=None):
- """
- Return a logger with the specified name, creating it if necessary.
- If no name is specified, return the root logger.
- """
- if name:
- return Logger.manager.getLogger(name)
- else:
- return root
-
-def getRootLogger():
- """
- Return the root logger. Note that getLogger('') now does the same thing,
- so this function is deprecated and may disappear in the future.
- """
- return root
-
-def critical(msg, *args, **kwargs):
- """
- Log a message with severity 'CRITICAL' on the root logger.
- """
- if len(root.handlers) == 0:
- basicConfig()
- apply(root.critical, (msg,)+args, kwargs)
-
-fatal = critical
-
-def error(msg, *args, **kwargs):
- """
- Log a message with severity 'ERROR' on the root logger.
- """
- if len(root.handlers) == 0:
- basicConfig()
- apply(root.error, (msg,)+args, kwargs)
-
-def exception(msg, *args):
- """
- Log a message with severity 'ERROR' on the root logger,
- with exception information.
- """
- apply(error, (msg,)+args, {'exc_info': 1})
-
-def warn(msg, *args, **kwargs):
- """
- Log a message with severity 'WARN' on the root logger.
- """
- if len(root.handlers) == 0:
- basicConfig()
- apply(root.warn, (msg,)+args, kwargs)
-
-def info(msg, *args, **kwargs):
- """
- Log a message with severity 'INFO' on the root logger.
- """
- if len(root.handlers) == 0:
- basicConfig()
- apply(root.info, (msg,)+args, kwargs)
-
-def debug(msg, *args, **kwargs):
- """
- Log a message with severity 'DEBUG' on the root logger.
- """
- if len(root.handlers) == 0:
- basicConfig()
- apply(root.debug, (msg,)+args, kwargs)
-
-def disable(level):
- """
- Disable all logging calls less severe than 'level'.
- """
- root.manager.disable = level
-
-def shutdown():
- """
- Perform any cleanup actions in the logging system (e.g. flushing
- buffers). Should be called at application exit.
- """
- for h in _handlers.keys():
- h.flush()
- h.close()
-
-#
-# The following code implements a socket listener for on-the-fly
-# reconfiguration of logging.
-#
-# _listener holds the server object doing the listening
-_listener = None
-
-def listen(port=DEFAULT_LOGGING_CONFIG_PORT):
- """
- Start up a socket server on the specified port, and listen for new
- configurations. These will be sent as a file suitable for processing
- by fileConfig(). Returns a Thread object on which you can call start()
- to start the server, and which you can join() when appropriate.
- To stop the server, call stopListening().
- """
- if not thread:
- raise NotImplementedError, "listen() needs threading to work"
-
- import threading
-
- class ConfigStreamHandler(StreamRequestHandler):
- """
- Handler for a logging configuration request. It expects a
- completely new logging configuration and uses fileConfig to
- install it.
- """
- def handle(self):
- """
- Each request is expected to be a 2-byte length,
- followed by the config file. Uses fileConfig() to do the
- needful.
- """
- import tempfile
- try:
- conn = self.connection
- chunk = conn.recv(2)
- if len(chunk) == 2:
- slen = (ord(chunk[0]) << 8) | ord(chunk[1])
- chunk = self.connection.recv(slen)
- while len(chunk) < slen:
- chunk = chunk + conn.recv(slen - len(chunk))
- #Apply new configuration. We'd like to be able to
- #create a StringIO and pass that in, but unfortunately
- #1.5.2 ConfigParser does not support reading file
- #objects, only actual files. So we create a temporary
- #file and remove it later.
- file = tempfile.mktemp(".ini")
- f = open(file, "w")
- f.write(chunk)
- f.close()
- fileConfig(file)
- os.remove(file)
- except socket.error, e:
- if type(e.args) != types.TupleType:
- raise
- else:
- errcode = e.args[0]
- if errcode != RESET_ERROR:
- raise
-
- class ConfigSocketReceiver(ThreadingTCPServer):
- """
- A simple TCP socket-based logging config receiver.
- """
-
- allow_reuse_address = 1
-
- def __init__(self, host='localhost', port=DEFAULT_LOGGING_CONFIG_PORT,
- handler=None):
- ThreadingTCPServer.__init__(self, (host, port), handler)
- _acquireLock()
- self.abort = 0
- _releaseLock()
- self.timeout = 1
-
- def serve_until_stopped(self):
- import select
- abort = 0
- while not abort:
- rd, wr, ex = select.select([self.socket.fileno()],
- [], [],
- self.timeout)
- if rd:
- self.handle_request()
- _acquireLock()
- abort = self.abort
- _releaseLock()
-
- def serve(rcvr, hdlr):
- server = rcvr(handler=hdlr)
- global _listener
- _acquireLock()
- _listener = server
- _releaseLock()
- server.serve_until_stopped()
-
- return threading.Thread(target=serve, args=(ConfigSocketReceiver, ConfigStreamHandler))
-
-def stopListening():
- """
- Stop the listening server which was created with a call to listen().
- """
- if _listener:
- _acquireLock()
- _listener.abort = 1
- _listener = None
- _releaseLock()
-
-
-# bicycle repair man stuff
-
-bike_logger_initialised = 0
-
-def init():
- global bike_logger_initialised
- if not bike_logger_initialised:
- log = getLogger("bike")
- h = StreamHandler()
- h.setFormatter(Formatter(
- fmt="%(pathname)s:%(lineno)s:%(levelname)s %(message)s"))
- log.addHandler(h)
- bike_logger_initialised = 1
-
-if __name__ == "__main__":
- print __doc__
--- a/vim/sadness/bike/bike/mock.py Thu Feb 10 17:11:26 2011 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,143 +0,0 @@
-#
-# (c) Dave Kirby 2001
-# dkirby@bigfoot.com
-#
-# Call interceptor code by Phil Dawes (pdawes@users.sourceforge.net)
-
-'''
-The Mock class emulates any other class for testing purposes.
-All method calls are stored for later examination.
-The class constructor takes a dictionary of method names and the values
-they return. Methods that are not in the dictionary will return None.
-'''
-import inspect
-
-
-class Mock:
- def __init__(self, returnValues=None ):
- self.mockCalledMethods = {}
- self.mockAllCalledMethods = []
- self.mockReturnValues = returnValues or {}
- self.setupMethodInterceptors()
-
- def setupMethodInterceptors(self):
- if self.__class__ != Mock: # check we've been subclassed
- methods = inspect.getmembers(self.__class__,inspect.ismethod)
- for m in methods:
- name = m[0]
- self.__dict__[name] = MethodCallInterceptor(name,self)
-
- def __getattr__( self, name ):
- return MockCaller( name, self )
-
- def getAllCalls(self):
- '''return a list of MockCall objects,
- representing all the methods in the order they were called'''
- return self.mockAllCalledMethods
-
- def getNamedCalls(self, methodName ):
- '''return a list of MockCall objects,
- representing all the calls to the named method in the order they were called'''
- return self.mockCalledMethods.get(methodName, [] )
-
- def assertNamedCall(self,methodName,*args):
- # assert call was made once
- assert(len(self.getNamedCalls(methodName)) == 1)
- # assert args are correct
- argsdict = inspect.getargvalues(inspect.currentframe())[3]
- i=0
- for arg in argsdict['args']:
- assert(self.getNamedCalls(methodName)[0].getParam(i) == arg)
- i += 1
-
- def assertCallInOrder(self,methodName,*args):
- ''' Convenience method to allow client to check that calls were
- made in the right order. Call once for each methodcall'''
-
- # initialise callIndex. (n.b. __getattr__ method complicates
- # this since attrs are MockCaller instances by default)
- if type(self.callIndex) != type(1):
- self.callIndex=0
-
- call = self.getAllCalls()[self.callIndex]
- # assert method name is correct
- assert(call.getName() == methodName)
- # assert args are correct
- argsdict = inspect.getargvalues(inspect.currentframe())[3]
- i=0
- for arg in argsdict['args']:
- assert(call.getParam(i) == arg)
- i += 1
- # assert num args are correct
- assert(call.getNumParams() == i)
- self.callIndex += 1
-
- def assertNoMoreCalls(self):
- assert(len(self.getAllCalls()) == self.callIndex)
-
-class MockCall:
- def __init__(self, name, params, kwparams ):
- self.name = name
- self.params = params
- self.kwparams = kwparams
- def getParam( self, n ):
- if type(n) == type(1):
- return self.params[n]
- elif type(n) == type(''):
- return self.kwparams[n]
- else:
- raise IndexError, 'illegal index type for getParam'
-
- def getNumParams(self):
- return len(self.params)
-
-
- def getName(self):
- return self.name
-
- #pretty-print the method call
- def __str__(self):
- s = self.name + "("
- sep = ''
- for p in self.params:
- s = s + sep + repr(p)
- sep = ', '
- for k,v in self.kwparams.items():
- s = s + sep + k+ '='+repr(v)
- sep = ', '
- s = s + ')'
- return s
- def __repr__(self):
- return self.__str__()
-
-class MockCaller:
- def __init__( self, name, mock):
- self.name = name
- self.mock = mock
- def __call__(self, *params, **kwparams ):
- self.recordCall(params,kwparams)
- return self.mock.mockReturnValues.get(self.name)
-
- def recordCall(self,params,kwparams):
- thisCall = MockCall( self.name, params, kwparams )
- calls = self.mock.mockCalledMethods.get(self.name, [] )
- if calls == []:
- self.mock.mockCalledMethods[self.name] = calls
- calls.append(thisCall)
- self.mock.mockAllCalledMethods.append(thisCall)
-
-
-# intercepts the call and records it, then delegates to the real call
-class MethodCallInterceptor(MockCaller):
-
- def __call__(self, *params, **kwparams ):
- self.recordCall(params,kwparams)
- return self.makeCall(params)
-
- def makeCall(self,params):
- argsstr="(self.mock"
- for i in range(len(params)):
- argsstr += ",params["+`i`+"]"
- argsstr+=")"
- return eval("self.mock.__class__."+self.name+argsstr)
-
--- a/vim/sadness/bike/bike/parsing/__init__.py Thu Feb 10 17:11:26 2011 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,3 +0,0 @@
-#from addtypeinfo import addtypeinfo
-#from load import load
-#from brmtransformer import parse
--- a/vim/sadness/bike/bike/parsing/constants.py Thu Feb 10 17:11:26 2011 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,3 +0,0 @@
-messages={"PARSING":"Parsing","ADDTYPEINFO":"Deducing Type Information"}
-
-MAXCALLDEPTH = 10
--- a/vim/sadness/bike/bike/parsing/fastparser.py Thu Feb 10 17:11:26 2011 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,70 +0,0 @@
-#!/usr/bin/env python
-from bike.parsing.fastparserast import *
-from bike.parsing.parserutils import *
-from parser import ParserError
-#import exceptions
-
-indentRE = re.compile("^\s*(\w+)")
-
-# returns a tree of objects representing nested classes and functions
-# in the source
-def fastparser(src,modulename="",filename=""):
- try:
- return fastparser_impl(src,modulename,filename)
- except RuntimeError, ex: # if recursive call exceeds maximum depth
- if str(ex) == "maximum recursion limit exceeded":
- raise ParserError,"maximum recursion depth exceeded when fast-parsing src "+filename
- else:
- raise
-
-def fastparser_impl(src,modulename,filename):
- lines = src.splitlines(1)
- maskedSrc = maskPythonKeywordsInStringsAndComments(src)
- maskedLines = maskedSrc.splitlines(1)
- root = Module(filename,modulename,lines,maskedSrc)
- parentnode = root
- lineno = 0
- for line in maskedLines:
- lineno+=1
- #print "line",lineno,":",line
- m = indentRE.match(line)
- if m:
- indent = m.start(1)
- tokenstr = m.group(1)
- if tokenstr == "import" or tokenstr == "from":
- while indent <= parentnode.indent: # root indent is -TABWIDTH
- parentnode = parentnode.getParent()
- try:
- parentnode.importlines.append(lineno)
- except AttributeError:
- parentnode.importlines = [lineno]
- elif tokenstr == "class":
- m2 = classNameRE.match(line)
- if m2:
- n = Class(m2.group(1), filename, root, lineno, indent, lines, maskedSrc)
- root.flattenedNodes.append(n)
-
- while indent <= parentnode.indent:
- parentnode = parentnode.getParent()
- parentnode.addChild(n)
- parentnode = n
-
- elif tokenstr == "def":
- m2 = fnNameRE.match(line)
- if m2:
- n = Function(m2.group(1), filename, root, lineno, indent, lines, maskedSrc)
- root.flattenedNodes.append(n)
-
- while indent <= parentnode.indent:
- parentnode = parentnode.getParent()
- parentnode.addChild(n)
- parentnode = n
-
- elif indent <= parentnode.indent and \
- tokenstr in ['if','for','while','try']:
- parentnode = parentnode.getParent()
- while indent <= parentnode.indent:
- parentnode = parentnode.getParent()
-
- return root
-
--- a/vim/sadness/bike/bike/parsing/fastparserast.py Thu Feb 10 17:11:26 2011 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,327 +0,0 @@
-from __future__ import generators
-from parserutils import generateLogicalLines, maskStringsAndComments, maskStringsAndRemoveComments
-import re
-import os
-import compiler
-from bike.transformer.save import resetOutputQueue
-
-TABWIDTH = 4
-
-classNameRE = re.compile("^\s*class\s+(\w+)")
-fnNameRE = re.compile("^\s*def\s+(\w+)")
-
-_root = None
-
-def getRoot():
- global _root
- if _root is None:
- resetRoot()
- return _root
-
-def resetRoot(root = None):
- global _root
- _root = root or Root()
- _root.unittestmode = False
- resetOutputQueue()
-
-
-def getModule(filename_path):
- from bike.parsing.load import CantLocateSourceNodeException, getSourceNode
- try:
- sourcenode = getSourceNode(filename_path)
- return sourcenode.fastparseroot
- except CantLocateSourceNodeException:
- return None
-
-def getPackage(directory_path):
- from bike.parsing.pathutils import getRootDirectory
- rootdir = getRootDirectory(directory_path)
- if rootdir == directory_path:
- return getRoot()
- else:
- return Package(directory_path,
- os.path.basename(directory_path))
-
-
-
-
-
-class Root:
- def __init__(self, pythonpath = None):
- # singleton hack to allow functions in query package to appear
- # 'stateless'
- resetRoot(self)
-
- # this is to get round a python optimisation which reuses an
- # empty list as a default arg. unfortunately the client of
- # this method may fill that list, so it's not empty
- if not pythonpath:
- pythonpath = []
- self.pythonpath = pythonpath
-
- def __repr__(self):
- return "Root()"
- #return "Root(%s)"%(self.getChildNodes())
-
-
- # dummy method
- def getChild(self,name):
- return None
-
-class Package:
- def __init__(self, path, name):
- self.path = path
- self.name = name
-
- def getChild(self,name):
- from bike.parsing.newstuff import getModule
- return getModule(os.path.join(self.path,name+".py"))
-
- def __repr__(self):
- return "Package(%s,%s)"%(self.path, self.name)
-
-# used so that linenum can be an attribute
-class Line(str):
- pass
-
-class StructuralNode:
- def __init__(self, filename, srclines, modulesrc):
- self.childNodes = []
- self.filename = filename
- self._parent = None
- self._modulesrc = modulesrc
- self._srclines = srclines
- self._maskedLines = None
-
- def addChild(self, node):
- self.childNodes.append(node)
- node.setParent(self)
-
- def setParent(self, parent):
- self._parent = parent
-
- def getParent(self):
- return self._parent
-
- def getChildNodes(self):
- return self.childNodes
-
- def getChild(self,name):
- matches = [c for c in self.getChildNodes() if c.name == name]
- if matches != []:
- return matches[0]
-
- def getLogicalLine(self,physicalLineno):
- return generateLogicalLines(self._srclines[physicalLineno-1:]).next()
-
- # badly named: actually returns line numbers of import statements
- def getImportLineNumbers(self):
- try:
- return self.importlines
- except AttributeError:
- return[]
-
- def getLinesNotIncludingThoseBelongingToChildScopes(self):
- srclines = self.getMaskedModuleLines()
- lines = []
- lineno = self.getStartLine()
- for child in self.getChildNodes():
- lines+=srclines[lineno-1: child.getStartLine()-1]
- lineno = child.getEndLine()
- lines+=srclines[lineno-1: self.getEndLine()-1]
- return lines
-
-
- def generateLinesNotIncludingThoseBelongingToChildScopes(self):
- srclines = self.getMaskedModuleLines()
- lines = []
- lineno = self.getStartLine()
- for child in self.getChildNodes():
- for line in srclines[lineno-1: child.getStartLine()-1]:
- yield self.attachLinenum(line,lineno)
- lineno +=1
- lineno = child.getEndLine()
- for line in srclines[lineno-1: self.getEndLine()-1]:
- yield self.attachLinenum(line,lineno)
- lineno +=1
-
- def generateLinesWithLineNumbers(self,startline=1):
- srclines = self.getMaskedModuleLines()
- for lineno in range(startline,len(srclines)+1):
- yield self.attachLinenum(srclines[lineno-1],lineno)
-
- def attachLinenum(self,line,lineno):
- line = Line(line)
- line.linenum = lineno
- return line
-
- def getMaskedModuleLines(self):
- from bike.parsing.load import Cache
- try:
- maskedlines = Cache.instance.maskedlinescache[self.filename]
- except:
- # make sure src is actually masked
- # (could just have keywords masked)
- maskedsrc = maskStringsAndComments(self._modulesrc)
- maskedlines = maskedsrc.splitlines(1)
- Cache.instance.maskedlinescache[self.filename] = maskedlines
- return maskedlines
-
-
-class Module(StructuralNode):
- def __init__(self, filename, name, srclines, maskedsrc):
- StructuralNode.__init__(self, filename, srclines, maskedsrc)
- self.name = name
- self.indent = -TABWIDTH
- self.flattenedNodes = []
- self.module = self
-
- def getMaskedLines(self):
- return self.getMaskedModuleLines()
-
- def getFlattenedListOfChildNodes(self):
- return self.flattenedNodes
-
- def getStartLine(self):
- return 1
-
- def getEndLine(self):
- return len(self.getMaskedModuleLines())+1
-
- def getSourceNode(self):
- return self.sourcenode
-
- def setSourceNode(self, sourcenode):
- self.sourcenode = sourcenode
-
- def matchesCompilerNode(self,node):
- return isinstance(node,compiler.ast.Module) and \
- node.name == self.name
-
- def getParent(self):
- if self._parent is not None:
- return self._parent
- else:
- from newstuff import getPackage
- return getPackage(os.path.dirname(self.filename))
-
-
- def __str__(self):
- return "bike:Module:"+self.filename
-
-indentRE = re.compile("^(\s*)\S")
-class Node:
- # module = the module node
- # linenum = starting line number
- def __init__(self, name, module, linenum, indent):
- self.name = name
- self.module = module
- self.linenum = linenum
- self.endline = None
- self.indent = indent
-
- def getMaskedLines(self):
- return self.getMaskedModuleLines()[self.getStartLine()-1:self.getEndLine()-1]
-
- def getStartLine(self):
- return self.linenum
-
- def getEndLine(self):
- if self.endline is None:
- physicallines = self.getMaskedModuleLines()
- lineno = self.linenum
- logicallines = generateLogicalLines(physicallines[lineno-1:])
-
- # skip the first line, because it's the declaration
- line = logicallines.next()
- lineno+=line.count("\n")
-
- # scan to the end of the fn
- for line in logicallines:
- #print lineno,":",line,
- match = indentRE.match(line)
- if match and match.end()-1 <= self.indent:
- break
- lineno+=line.count("\n")
- self.endline = lineno
- return self.endline
-
- # linenum starts at 0
- def getLine(self, linenum):
- return self._srclines[(self.getStartLine()-1) + linenum]
-
-
-baseClassesRE = re.compile("class\s+[^(]+\(([^)]+)\):")
-
-class Class(StructuralNode, Node):
- def __init__(self, name, filename, module, linenum, indent, srclines, maskedmodulesrc):
- StructuralNode.__init__(self, filename, srclines, maskedmodulesrc)
- Node.__init__(self, name, module, linenum, indent)
- self.type = "Class"
-
-
- def getBaseClassNames(self):
- #line = self.getLine(0)
- line = self.getLogicalLine(self.getStartLine())
- match = baseClassesRE.search(line)
- if match:
- return [s.strip()for s in match.group(1).split(",")]
- else:
- return []
-
- def getColumnOfName(self):
- match = classNameRE.match(self.getLine(0))
- return match.start(1)
-
- def __repr__(self):
- return "<bike:Class:%s>" % self.name
-
- def __str__(self):
- return "bike:Class:"+self.filename+":"+\
- str(self.getStartLine())+":"+self.name
-
- def matchesCompilerNode(self,node):
- return isinstance(node,compiler.ast.Class) and \
- node.name == self.name
-
- def __eq__(self,other):
- return isinstance(other,Class) and \
- self.filename == other.filename and \
- self.getStartLine() == other.getStartLine()
-
-# describes an instance of a class
-class Instance:
- def __init__(self, type):
- assert type is not None
- self._type = type
-
- def getType(self):
- return self._type
-
- def __str__(self):
- return "Instance(%s)"%(self.getType())
-
-
-class Function(StructuralNode, Node):
- def __init__(self, name, filename, module, linenum, indent,
- srclines, maskedsrc):
- StructuralNode.__init__(self, filename, srclines, maskedsrc)
- Node.__init__(self, name, module, linenum, indent)
- self.type = "Function"
-
- def getColumnOfName(self):
- match = fnNameRE.match(self.getLine(0))
- return match.start(1)
-
- def __repr__(self):
- return "<bike:Function:%s>" % self.name
-
- def __str__(self):
- return "bike:Function:"+self.filename+":"+\
- str(self.getStartLine())+":"+self.name
-
- def matchesCompilerNode(self,node):
- return isinstance(node,compiler.ast.Function) and \
- node.name == self.name
-
-
--- a/vim/sadness/bike/bike/parsing/load.py Thu Feb 10 17:11:26 2011 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,94 +0,0 @@
-from bike.globals import *
-import os
-from bike.parsing.fastparser import fastparser
-
-class Cache:
- def __init__(self):
- self.reset()
- def reset(self):
- self.srcnodecache = {}
- self.typecache = {}
- self.maskedlinescache = {}
-
- instance = None
-
-Cache.instance = Cache()
-
-class CantLocateSourceNodeException(Exception): pass
-
-def getSourceNode(filename_path):
- #print "getSourceNode:",filename_path
- sourcenode = None
-
- try:
- sourcenode = Cache.instance.srcnodecache[filename_path]
- except KeyError:
- pass
-
- if sourcenode is None:
- from bike.parsing.newstuff import translateFnameToModuleName
- sourcenode = SourceFile.createFromFile(filename_path,
- translateFnameToModuleName(filename_path))
- if sourcenode is None:
- raise CantLocateSourceNodeException(filename_path)
-
- Cache.instance.srcnodecache[filename_path]=sourcenode
- return sourcenode
-
-class SourceFile:
-
- def createFromString(filename, modulename, src):
- return SourceFile(filename,modulename,src)
- createFromString = staticmethod(createFromString)
-
- def createFromFile(filename,modulename):
- try:
- f = file(filename)
- src = f.read()
- f.close()
- except IOError:
- return None
- else:
- return SourceFile(filename,modulename,src)
-
- createFromFile = staticmethod(createFromFile)
-
- def __init__(self, filename, modulename, src):
-
- if os.path.isabs(filename):
- self.filename = filename
- else:
- self.filename = os.path.abspath(filename)
- self.modulename = modulename
-
- self.resetWithSource(src)
-
- def resetWithSource(self, source):
- # fastparser ast
- self.fastparseroot = fastparser(source,self.modulename,self.filename)
- self.fastparseroot.setSourceNode(self)
- self._lines = source.splitlines(1)
- self.sourcenode = self
-
- def __repr__(self):
- return "Source(%s,%s)"%('source', self.filename)
-
- def getChildNodes(self):
- return self.fastparseroot.getChildNodes()
-
- def getSource(self):
- return "".join(self.getLines())
-
- def getLine(self,linenum):
- return self.getLines()[linenum-1]
-
- # TODO: rename me!
- def getFlattenedListOfFastParserASTNodes(self):
- return self.fastparseroot.getFlattenedListOfChildNodes()
-
- def getLines(self):
- return self._lines
-
-
-
-
--- a/vim/sadness/bike/bike/parsing/newstuff.py Thu Feb 10 17:11:26 2011 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,114 +0,0 @@
-from __future__ import generators
-# Holding module for scaffolding needed to transition parsing package
-# into stateless design
-import os
-import re
-from bike.parsing.pathutils import getRootDirectory, getPackageBaseDirectory, \
- filenameToModulePath, getPathOfModuleOrPackage, getFilesForName
-from bike.parsing.fastparserast import Module, Package, getRoot, getPackage, getModule
-import sys
-from bike.parsing.load import getSourceNode, CantLocateSourceNodeException
-
-
-def translateFnameToModuleName(filename_path):
- return filenameToModulePath(filename_path)
-
-
-
-# scope is the scope to search from
-def getModuleOrPackageUsingFQN(fqn, dirpath=None):
- pythonpath = getPythonPath()
- #print "getModuleOrPackageUsingFQN",pythonpath,fqn
- if dirpath is not None:
- assert os.path.isdir(dirpath)
- pythonpath = [dirpath] + pythonpath
- filename = getPathOfModuleOrPackage(fqn,pythonpath)
- #print "getModuleOrPackageUsingFQN - filename",filename
- if filename is not None:
- if os.path.isdir(filename):
- return getPackage(filename)
- else:
- return getModule(filename)
- else:
- return None
-
-def getPythonPath():
- return getRoot().pythonpath
-
-
-def generateModuleFilenamesInPythonPath(contextFilename):
- files = []
- rootdir = getRootDirectory(contextFilename)
- if rootdir in getPythonPath():
- # just search the pythonpath
- for path in getPythonPath():
- for file in getFilesForName(path):
- if file not in files: # check for duplicates
- files.append(file)
- yield file
- else:
- # search the package hierarchy containing contextFilename
- # in addition to pythonpath
- basedir = getPackageBaseDirectory(contextFilename)
- for path in [basedir] + getPythonPath():
- for file in getFilesForName(path):
- if file not in files: # check for duplicates
- files.append(file)
- yield file
-
- # and search the files immediately above the package hierarchy
- for file in getFilesForName(os.path.join(rootdir,"*.py")):
- if file not in files: # check for duplicates
- files.append(file)
- yield file
-
-def generateModuleFilenamesInPackage(filenameInPackage):
- basedir = getPackageBaseDirectory(filenameInPackage)
- for file in getFilesForName(basedir):
- yield file
-
-
-
-# search all sourcenodes globally from the perspective of file 'contextFilename'
-def getSourceNodesContainingRegex(regexstr,contextFilename):
- regex = re.compile(regexstr)
- for fname in generateModuleFilenamesInPythonPath(contextFilename):
- try:
- f = file(fname)
- src = f.read()
- finally:
- f.close()
- if regex.search(src) is not None:
- yield getSourceNode(fname)
-
-
-
-
-fromRegex = re.compile("^\s*from\s+(\w+)\s+import")
-importregex = re.compile("^\s*import\s+(\w+)")
-
-# fileInPackage is the filename of a file in the package hierarchy
-# generates file and directory paths
-def generatePackageDependencies(fileInPackage):
- rejectPackagePaths = [getPackageBaseDirectory(fileInPackage)]
- for fname in generateModuleFilenamesInPackage(fileInPackage):
-
- try:
- f = file(fname)
- src = f.read()
- finally:
- f.close()
-
- packagepath = None
-
- for line in src.splitlines():
- match = fromRegex.search(line) or importregex.search(line)
- if match is not None:
- modulepath = match.group(1)
- packagename = modulepath.split('.')[0]
- packagepath = getPathOfModuleOrPackage(packagename,
- getPythonPath())
- if packagepath is not None and \
- packagepath not in rejectPackagePaths:
- rejectPackagePaths.append(packagepath) # avoid duplicates
- yield packagepath
--- a/vim/sadness/bike/bike/parsing/parserutils.py Thu Feb 10 17:11:26 2011 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,194 +0,0 @@
-from __future__ import generators
-import re
-
-escapedQuotesRE = re.compile(r"(\\\\|\\\"|\\\')")
-
-# changess \" \' and \\ into ** so that text searches
-# for " and ' won't hit escaped ones
-def maskEscapedQuotes(src):
- return escapedQuotesRE.sub("**", src)
-
-stringsAndCommentsRE = \
- re.compile("(\"\"\".*?\"\"\"|'''.*?'''|\"[^\"]*\"|\'[^\']*\'|#.*?\n)", re.DOTALL)
-
-import string
-#transtable = string.maketrans('classdefifforwhiletry', "*********************")
-
-# performs a transformation on all of the comments and strings so that
-# text searches for python keywords won't accidently find a keyword in
-# a string or comment
-def maskPythonKeywordsInStringsAndComments(src):
- src = escapedQuotesRE.sub("**", src)
- allstrings = stringsAndCommentsRE.split(src)
- # every odd element is a string or comment
- for i in xrange(1, len(allstrings), 2):
- allstrings[i] = allstrings[i].upper()
- #allstrings[i] = allstrings[i].translate(transtable)
- return "".join(allstrings)
-
-
-allchars = string.maketrans("", "")
-allcharsExceptNewline = allchars[: allchars.index('\n')]+allchars[allchars.index('\n')+1:]
-allcharsExceptNewlineTranstable = string.maketrans(allcharsExceptNewline, '*'*len(allcharsExceptNewline))
-
-
-# replaces all chars in a string or a comment with * (except newlines).
-# this ensures that text searches don't mistake comments for keywords, and that all
-# matches are in the same line/comment as the original
-def maskStringsAndComments(src):
- src = escapedQuotesRE.sub("**", src)
- allstrings = stringsAndCommentsRE.split(src)
- # every odd element is a string or comment
- for i in xrange(1, len(allstrings), 2):
- if allstrings[i].startswith("'''")or allstrings[i].startswith('"""'):
- allstrings[i] = allstrings[i][:3]+ \
- allstrings[i][3:-3].translate(allcharsExceptNewlineTranstable)+ \
- allstrings[i][-3:]
- else:
- allstrings[i] = allstrings[i][0]+ \
- allstrings[i][1:-1].translate(allcharsExceptNewlineTranstable)+ \
- allstrings[i][-1]
-
- return "".join(allstrings)
-
-
-# replaces all chars in a string or a comment with * (except newlines).
-# this ensures that text searches don't mistake comments for keywords, and that all
-# matches are in the same line/comment as the original
-def maskStringsAndRemoveComments(src):
- src = escapedQuotesRE.sub("**", src)
- allstrings = stringsAndCommentsRE.split(src)
- # every odd element is a string or comment
- for i in xrange(1, len(allstrings), 2):
- if allstrings[i].startswith("'''")or allstrings[i].startswith('"""'):
- allstrings[i] = allstrings[i][:3]+ \
- allstrings[i][3:-3].translate(allcharsExceptNewlineTranstable)+ \
- allstrings[i][-3:]
- elif allstrings[i].startswith("#"):
- allstrings[i] = '\n'
- else:
- allstrings[i] = allstrings[i][0]+ \
- allstrings[i][1:-1].translate(allcharsExceptNewlineTranstable)+ \
- allstrings[i][-1]
- return "".join(allstrings)
-
-
-implicitContinuationChars = (('(', ')'), ('[', ']'), ('{', '}'))
-emptyHangingBraces = [0,0,0,0,0]
-linecontinueRE = re.compile(r"\\\s*(#.*)?$")
-multiLineStringsRE = \
- re.compile("(^.*?\"\"\".*?\"\"\".*?$|^.*?'''.*?'''.*?$)", re.DOTALL)
-
-#def splitLogicalLines(src):
-# src = multiLineStringsRE.split(src)
-
-# splits the string into logical lines. This requires the comments to
-# be removed, and strings masked (see other fns in this module)
-def splitLogicalLines(src):
- physicallines = src.splitlines(1)
- return [x for x in generateLogicalLines(physicallines)]
-
-
-class UnbalancedBracesException: pass
-
-# splits the string into logical lines. This requires the strings
-# masked (see other fns in this module)
-# Physical Lines *Must* start on a non-continued non-in-a-comment line
-# (although detects unbalanced braces)
-def generateLogicalLines(physicallines):
- tmp = []
- hangingBraces = list(emptyHangingBraces)
- hangingComments = 0
- for line in physicallines:
- # update hanging braces
- for i in range(len(implicitContinuationChars)):
- contchar = implicitContinuationChars[i]
- numHanging = hangingBraces[i]
- hangingBraces[i] = numHanging+line.count(contchar[0]) - \
- line.count(contchar[1])
-
- hangingComments ^= line.count('"""') % 2
- hangingComments ^= line.count("'''") % 2
-
- if hangingBraces[0] < 0 or \
- hangingBraces[1] < 0 or \
- hangingBraces[2] < 0:
- raise UnbalancedBracesException()
-
- if linecontinueRE.search(line):
- tmp.append(line)
- elif hangingBraces != emptyHangingBraces:
- tmp.append(line)
- elif hangingComments:
- tmp.append(line)
- else:
- tmp.append(line)
- yield "".join(tmp)
- tmp = []
-
-
-# see above but yields (line,linenum)
-# needs physicallines to have linenum attribute
-# TODO: refactor with previous function
-def generateLogicalLinesAndLineNumbers(physicallines):
- tmp = []
- hangingBraces = list(emptyHangingBraces)
- hangingComments = 0
- linenum = None
- for line in physicallines:
- if tmp == []:
- linenum = line.linenum
-
- # update hanging braces
- for i in range(len(implicitContinuationChars)):
- contchar = implicitContinuationChars[i]
- numHanging = hangingBraces[i]
- hangingBraces[i] = numHanging+line.count(contchar[0]) - \
- line.count(contchar[1])
-
- hangingComments ^= line.count('"""') % 2
- hangingComments ^= line.count("'''") % 2
-
- if linecontinueRE.search(line):
- tmp.append(line)
- elif hangingBraces != emptyHangingBraces:
- tmp.append(line)
- elif hangingComments:
- tmp.append(line)
- else:
- tmp.append(line)
- yield "".join(tmp),linenum
- tmp = []
-
-
-
-
-# takes a line of code, and decorates it with noops so that it can be
-# parsed by the python compiler.
-# e.g. "if foo:" -> "if foo: pass"
-# returns the line, and the adjustment made to the column pos of the first char
-# line must have strings and comments masked
-#
-# N.B. it only inserts keywords whitespace and 0's
-notSpaceRE = re.compile("\s*(\S)")
-commentRE = re.compile("#.*$")
-
-def makeLineParseable(line):
- return makeLineParseableWhenCommentsRemoved(commentRE.sub("",line))
-
-def makeLineParseableWhenCommentsRemoved(line):
- line = line.strip()
- if ":" in line:
- if line.endswith(":"):
- line += " pass"
- if line.startswith("try"):
- line += "\nexcept: pass"
- elif line.startswith("except") or line.startswith("finally"):
- line = "try: pass\n" + line
- return line
- elif line.startswith("else") or line.startswith("elif"):
- line = "if 0: pass\n" + line
- return line
- elif line.startswith("yield"):
- return ("return"+line[5:])
- return line
--- a/vim/sadness/bike/bike/parsing/pathutils.py Thu Feb 10 17:11:26 2011 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,165 +0,0 @@
-
-# A some of this code is take from Pythius -
-# Copyright (GPL) 2001 Jurgen Hermann <jh@web.de>
-
-from bike.globals import *
-import os
-
-def containsAny(str, set):
- """ Check whether 'str' contains ANY of the chars in 'set'
- """
- return 1 in [c in str for c in set]
-
-
-
-def getPathOfModuleOrPackage(dotted_name, pathlist = None):
- """ Get the filesystem path for a module or a package.
-
- Return the file system path to a file for a module,
- and to a directory for a package. Return None if
- the name is not found, or is a builtin or extension module.
- """
- from bike.parsing.newstuff import getPythonPath
- if pathlist is None:
- pathlist = getPythonPath()
-
- import imp
-
- # split off top-most name
- parts = dotted_name.split('.', 1)
-
- if len(parts) > 1:
- # we have a dotted path, import top-level package
- try:
- file, pathname, description = imp.find_module(parts[0], pathlist)
- if file: file.close()
- except ImportError:
- return None
-
- # check if it's indeed a package
- if description[2] == imp.PKG_DIRECTORY:
- # recursively handle the remaining name parts
- pathname = getPathOfModuleOrPackage(parts[1], [pathname])
- else:
- pathname = None
- else:
- # plain name
- try:
- file, pathname, description = imp.find_module(dotted_name, pathlist)
- if file: file.close()
- if description[2]not in[imp.PY_SOURCE, imp.PKG_DIRECTORY]:
- pathname = None
- except ImportError:
- pathname = None
-
- return pathname
-
-
-def getFilesForName(name):
- """ Get a list of module files for a filename, a module or package name,
- or a directory.
- """
- import imp
-
- if not os.path.exists(name):
- # check for glob chars
- if containsAny(name, "*?[]"):
- import glob
- files = glob.glob(name)
- list = []
- for file in files:
- list.extend(getFilesForName(file))
- return list
-
- # try to find module or package
- name = getPathOfModuleOrPackage(name)
- if not name:
- return[]
-
- if os.path.isdir(name):
- # find all python files in directory
- list = []
- os.path.walk(name, _visit_pyfiles, list)
- return list
- elif os.path.exists(name) and not name.startswith("."):
- # a single file
- return [name]
-
- return []
-
-def _visit_pyfiles(list, dirname, names):
- """ Helper for getFilesForName().
- """
- # get extension for python source files
- if not globals().has_key('_py_ext'):
- import imp
- global _py_ext
- _py_ext = [triple[0]for triple in imp.get_suffixes()if triple[2] == imp.PY_SOURCE][0]
-
- # don't recurse into CVS or Subversion directories
- if 'CVS'in names:
- names.remove('CVS')
- if '.svn'in names:
- names.remove('.svn')
-
- names_copy = [] + names
- for n in names_copy:
- if os.path.isdir(os.path.join(dirname, n))and \
- not os.path.exists(os.path.join(dirname, n, "__init__.py")):
- names.remove(n)
-
- # add all *.py files to list
- list.extend(
- [os.path.join(dirname, file)
- for file in names
- if os.path.splitext(file)[1] == _py_ext and not file.startswith(".")])
-
-
-# returns the directory which holds the first package of the package
-# hierarchy under which 'filename' belongs
-def getRootDirectory(filename):
- if os.path.isdir(filename):
- dir = filename
- else:
- dir = os.path.dirname(filename)
- while dir != "" and \
- os.path.exists(os.path.join(dir, "__init__.py")):
- dir = os.path.dirname(dir)
- return dir
-
-
-
-# Returns the root package directoryname of the package hierarchy
-# under which 'filename' belongs
-def getPackageBaseDirectory(filename):
- if os.path.isdir(filename):
- dir = filename
- else:
- dir = os.path.dirname(filename)
-
- if not os.path.exists(os.path.join(dir, "__init__.py")):
- # parent dir is not a package
- return dir
-
- while dir != "" and \
- os.path.exists(os.path.join(os.path.dirname(dir), "__init__.py")):
- dir = os.path.dirname(dir)
- return dir
-
-
-
-def filenameToModulePath(fname):
- directoriesPreceedingRoot = getRootDirectory(fname)
- import os
- # strip off directories preceeding root package directory
- if directoriesPreceedingRoot != "":
- mpath = fname.replace(directoriesPreceedingRoot, "")
- else:
- mpath = fname
-
- if(mpath[0] == os.path.normpath("/")):
- mpath = mpath[1:]
- mpath, ext = os.path.splitext(mpath)
- mpath = mpath.replace(os.path.normpath("/"), ".")
- return mpath
-
--- a/vim/sadness/bike/bike/parsing/setpath.py Thu Feb 10 17:11:26 2011 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,5 +0,0 @@
-import sys,os
-if not os.path.abspath("../..") in sys.path:
- from bike import log
- print >> log.warning, "Appending to the system path. This should only happen in unit tests"
- sys.path.append(os.path.abspath("../.."))
--- a/vim/sadness/bike/bike/parsing/test_fastparser.py Thu Feb 10 17:11:26 2011 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,160 +0,0 @@
-#!/usr/bin/env python
-import unittest
-from fastparser import*
-from bike.parsing.load import*
-from bike.parsing.fastparserast import*
-from bike.testutils import *
-
-class TestFastParser(BRMTestCase):
- def test_doesntGetClassDeclsInMLStrings(self):
- src = trimLines('''
- """
- class foo bah
- """
- ''')
- root = fastparser(src)
- assert root.getChildNodes() == []
-
- def test_evaluatesMLStringWithQuoteInIt(self):
- src = trimLines('''
- """some ml comment inclosing a " """
- def foo:
- pass
- " hello "
- ''')
- root = fastparser(src)
- assert root.getChildNodes() != []
-
- def test_handlesClassDefsWithTwoSpacesInDecl(self):
- src = trimLines('''
- class foo: pass
- ''')
- root = fastparser(src)
- assert root.getChildNodes() != []
-
- def test_handlesFnDefsWithTwoSpacesInDecl(self):
- src = trimLines('''
- def foo: pass
- ''')
- root = fastparser(src)
- assert root.getChildNodes() != []
-
-
-MLStringWithQuoteInIt = """
-\"\"\"some ml comment inclosing a \" \"\"\"
-def foo:
- pass
-\" hello \"
-"""
-
-def load(path):
- files = getFilesForName(path)
- for fname in files:
- src = file(fname).read()
- fastparser(src)
- #print fname
- #myroot = parseFile(fname)
-
-
-
-def fastparsetreeToString(root):
- class stringholder: pass
- s = stringholder()
- s.mystr = ""
- s.tabstr = ""
- def t2s(node):
- if isinstance(node, Class):
- s.mystr+=s.tabstr+"class "+node.name+"\n"
- s.tabstr+="\t"
- for n in node.getChildNodes():
- t2s(n)
- s.tabstr = s.tabstr[:-1]
-
- elif isinstance(node, Function):
- s.mystr+=s.tabstr+"function "+node.name+"\n"
- s.tabstr+="\t"
- for n in node.getChildNodes():
- t2s(n)
- s.tabstr = s.tabstr[:-1]
-
-
- for n in root.getChildNodes():
- t2s(n)
- return s.mystr
-
-
-def compilerParseTreeToString(root):
- try:
- class TreeVisitor:
- def __init__(self):
- self.mystr = ""
- self.tabstr = ""
-
- def visitClass(self, node):
- self.mystr+=self.tabstr+"class "+node.name+"\n"
- self.tabstr+="\t"
- for child in node.getChildNodes():
- self.visit(child)
- self.tabstr = self.tabstr[:-1]
-
- def visitFunction(self, node):
- self.mystr+=self.tabstr+"function "+node.name+"\n"
- self.tabstr+="\t"
- for child in node.getChildNodes():
- self.visit(child)
- self.tabstr = self.tabstr[:-1]
-
- return compiler.walk(root, TreeVisitor()).mystr
-
- except:
- log.exception("ex")
- import sys
- sys.exit(0)
-
-
-def compareCompilerWithFastparserOverPath(path):
- from bike.parsing.load import getFilesForName
- files = getFilesForName(path)
- for fname in files:
- if fname.endswith("bdist_wininst.py"): continue
- log.info(fname)
- src = file(fname).read()
- try:
- compiler_root = compiler.parse(src)
- except SyntaxError:
- continue
- fastparse_root = fastparser(src)
- str1 = fastparsetreeToString(fastparse_root)
- str2 = compilerParseTreeToString(compiler_root)
- assert str1 == str2, "\n"+"-"*70+"\n"+str1+"-"*70+"\n"+str2
-
-
-def timeParseOfPythonLibrary(path):
- import time
- t1 = time.time()
- files = getFilesForName(path)
- import sys
- for fname in files:
- if fname.endswith("bdist_wininst.py"): continue
- src = file(fname).read()
- fastparser(src)
- print "\n", time.time()-t1
-
-
-if __name__ == "__main__":
- from bike import logging
- logging.init()
- log = logging.getLogger("bike")
- log.setLevel(logging.INFO)
- # add soak tests to end of test
- class Z_SoakTestFastparser(BRMTestCase):
-
- def test_A_timeParseOfPythonLibrary(self):
- timeParseOfPythonLibrary("/usr/local/lib/python2.2")
-
- def test_parsesPythonLibraryCorrectly(self):
- print ""
- compareCompilerWithFastparserOverPath("/usr/local/lib/python2.2")
-
- unittest.main()
-
--- a/vim/sadness/bike/bike/parsing/test_fastparserast.py Thu Feb 10 17:11:26 2011 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,151 +0,0 @@
-#!/usr/bin/env python
-import unittest
-from fastparserast import *
-from fastparser import fastparser
-from bike.query.getTypeOf import getTypeOf
-from bike.testutils import *
-
-class TestGetModule(BRMTestCase):
-
- def test_getRootWorksAfterDefinedByCreateSourceNodeAt(self):
- src=trimLines("""
- class TheClass:
- pass
- a = TheClass()
- """)
- root = createSourceNodeAt(src,"mymodule")
- assert root == getRoot()
-
- def test_returnsNoneIfModuleDoesntExist(self):
- assert getModule(tmpfile) == None
-
-
-class TestGetEndLine(BRMTestCase):
- def test_returnsEndLineWithSimpleFunction(self):
- src = trimLines("""
- class TheClass:
- def theMethod():
- pass
- def foo():
- b = TheClass()
- return b
- a = foo()
- a.theMethod()
- """)
- root = fastparser(src)
- fn = getTypeOf(root,"foo")
- self.assertEqual(fn.getEndLine(),7)
-
- def test_worksWithFunctionsThatHaveEmptyLinesInThem(self):
- src = fnWithEmptyLineInIt
- root = fastparser(src)
- fn = getTypeOf(root,"TheClass.theFunction")
- self.assertEqual(fn.getEndLine(),8)
-
-class TestGetBaseClassNames(BRMTestCase):
- def test_worksForClassHierarchy(self):
- src = trimLines("""
- class root:
- def theMethod():
- pass
-
- class a(root):
- def theMethod():
- pass
-
- class b(root):
- pass
-
- class TheClass(a,b):
- def theMethod():
- pass
-
- rootinstance = root()
- rootinstance.theMethod()
- """)
- #classes = getASTNodeFromSrc(src,"Source").fastparseroot.getChildNodes()
- classes = createAST(src).fastparseroot.getChildNodes()
- self.assertEqual(classes[3].getBaseClassNames(),['a','b'])
-
- def test_returnsEmptyListForClassWithNoBases(self):
- src = trimLines("""
- class root:
- pass
- """)
- #classes = getASTNodeFromSrc(src,"Source").fastparseroot.getChildNodes()
- classes = createAST(src).fastparseroot.getChildNodes()
- self.assertEqual(classes[0].getBaseClassNames(),[])
-
-
-class TestGetMaskedLines(BRMTestCase):
- def test_doit(self):
- src =trimLines("""
- class foo: #bah
- pass
- """)
- mod = createAST(src).fastparseroot
- lines = mod.getMaskedModuleLines()
- assert lines[0] == "class foo: #***\n"
-
-
-class TestGetLinesNotIncludingThoseBelongingToChildScopes(BRMTestCase):
- def test_worksForModule(self):
- src =trimLines("""
- class TheClass:
- def theMethod():
- pass
- def foo():
- b = TheClass()
- return b
- a = foo()
- a.theMethod()
- """)
- mod = createAST(src).fastparseroot
- self.assertEqual(''.join(mod.getLinesNotIncludingThoseBelongingToChildScopes()),
- trimLines("""
- a = foo()
- a.theMethod()
- """))
-
- def test_worksForModuleWithSingleLineFunctions(self):
- src=trimLines("""
- a = blah()
- def foo(): pass
- b = 1
- """)
- mod = createAST(src).fastparseroot
- lines = mod.getLinesNotIncludingThoseBelongingToChildScopes()
- self.assertEqual(''.join(lines),
- trimLines("""
- a = blah()
- b = 1
- """))
-
-
- def test_worksForSingleLineFunction(self):
- src=trimLines("""
- a = blah()
- def foo(): pass
- b = 1
- """)
- fn = createAST(src).fastparseroot.getChildNodes()[0]
- lines = fn.getLinesNotIncludingThoseBelongingToChildScopes()
- self.assertEqual(''.join(lines),
- trimLines("""
- def foo(): pass
- """))
-
-
-fnWithEmptyLineInIt = """
-class TheClass:
- def theFunction():
- a = foo()
-
- print 'a'
-
- # end of function
-"""
-
-if __name__ == "__main__":
- unittest.main()
-
--- a/vim/sadness/bike/bike/parsing/test_load.py Thu Feb 10 17:11:26 2011 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,18 +0,0 @@
-#!/usr/bin/env python
-import setpath
-import unittest
-import compiler
-import os
-
-from bike import testdata
-from bike.testutils import *
-from bike.mock import Mock
-
-from pathutils import getPathOfModuleOrPackage
-from load import *
-import load as loadmodule
-
-
-
-if __name__ == "__main__":
- unittest.main()
--- a/vim/sadness/bike/bike/parsing/test_newstuff.py Thu Feb 10 17:11:26 2011 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,284 +0,0 @@
-#!/usr/bin/env python
-import setpath
-import os
-import unittest
-from bike.testutils import *
-from bike.parsing.fastparserast import getRoot
-from bike.parsing.newstuff import getModuleOrPackageUsingFQN,\
- generateModuleFilenamesInPythonPath, getSourceNodesContainingRegex,\
- generatePackageDependencies
-
-
-class TestGetModuleOrPackageUsingFQN(BRMTestCase):
- def test_worksForFullPath(self):
- try:
- createPackageStructure("pass","pass")
- self.assertEqual(getModuleOrPackageUsingFQN("a.b.bah").filename,
- pkgstructureFile2)
- finally:
- removePackageStructure()
-
- def test_worksForPackage(self):
- try:
- createPackageStructure("pass","pass")
- self.assertEqual(getModuleOrPackageUsingFQN("a.b").path,
- pkgstructureChilddir)
- finally:
- removePackageStructure()
-
-
-class TestGenerateModuleFilenamesInPythonPath(BRMTestCase):
- def test_works(self):
- try:
- createPackageStructure("pass","pass")
- fnames = [f for f in \
- generateModuleFilenamesInPythonPath(pkgstructureFile2)]
-
-
- assert os.path.join(pkgstructureBasedir,"__init__.py") in fnames
- assert pkgstructureFile1 in fnames
- assert os.path.join(pkgstructureChilddir,"__init__.py") in fnames
- assert pkgstructureFile2 in fnames
- assert len(fnames) == 5
- finally:
- removePackageStructure()
-
-
-
- def test_doesntTraverseIntoNonPackages(self):
- try:
- createPackageStructure("pass","pass")
- nonPkgDir = os.path.join(pkgstructureChilddir,"c")
- newfile = os.path.join(nonPkgDir,"baz.py")
- # N.B. don't put an __init__.py in it, so isnt a package
- os.makedirs(nonPkgDir)
- writeFile(newfile,"pass")
- fnames = [f for f in \
- generateModuleFilenamesInPythonPath(pkgstructureFile2)]
- assert newfile not in fnames
- finally:
- #os.remove(initfile)
- os.remove(newfile)
- os.removedirs(nonPkgDir)
- removePackageStructure()
-
-
- def test_doesScanFilesInTheRootDirectory(self):
- try:
- createPackageStructure("pass","pass","pass")
- fnames = [f for f in \
- generateModuleFilenamesInPythonPath(pkgstructureFile2)]
- assert pkgstructureFile0 in fnames
- finally:
- #os.remove(initfile)
- removePackageStructure()
-
- def test_returnsOtherFilesInSameNonPackageDirectory(self):
- try:
- oldpath = getRoot().pythonpath
- getRoot().pythonpath = [] # clear the python path
- writeTmpTestFile("")
- newtmpfile = os.path.join(tmproot,"baz.py")
- writeFile(newtmpfile, "")
- fnames = [f for f in \
- generateModuleFilenamesInPythonPath(tmpfile)]
- assert newtmpfile in fnames
- finally:
- os.remove(newtmpfile)
- deleteTmpTestFile()
- getRoot().pythonpath = oldpath
-
-
-
- def test_doesntTraverseIntoNonPackagesUnderRoot(self):
- try:
- os.makedirs(pkgstructureBasedir)
- writeFile(pkgstructureFile1,"pass")
- fnames = [f for f in \
- generateModuleFilenamesInPythonPath(pkgstructureFile2)]
- assert pkgstructureFile1 not in fnames
- finally:
- os.remove(pkgstructureFile1)
- os.removedirs(pkgstructureBasedir)
-
-
- def test_doesntGenerateFilenamesMoreThanOnce(self):
- try:
- createPackageStructure("pass","pass")
- newfile = os.path.join(pkgstructureChilddir,"baz.py")
- writeFile(newfile,"pass")
- fnames = [f for f in \
- generateModuleFilenamesInPythonPath(pkgstructureFile2)]
- matched = [f for f in fnames if f == newfile]
- self.assertEqual(1, len(matched))
- finally:
- os.remove(newfile)
- removePackageStructure()
-
-class TestGetSourceNodesContainingRegex(BRMTestCase):
- def test_works(self):
- try:
- createPackageStructure("# testregexfoobah","pass")
- srcfiles = [s for s in
- getSourceNodesContainingRegex("testregexfoobah",
- pkgstructureFile2)]
- self.assertEqual(pkgstructureFile1,srcfiles[0].filename)
- finally:
- removePackageStructure()
-
-class TestGenerateModuleFilenamesInPythonPath2(BRMTestCase):
- def test_getsAllFilenamesInSameHierarchyAsContextFile(self):
- try:
- oldpath = getRoot().pythonpath
- getRoot().pythonpath = [] # clear the python path
- createPackageStructure("","")
- fnames = [f for f in
- generateModuleFilenamesInPythonPath(pkgstructureFile1)]
- self.assert_(pkgstructureFile0 in fnames)
- self.assert_(pkgstructureFile1 in fnames)
- self.assert_(pkgstructureFile2 in fnames)
- finally:
- getRoot().pythonpath = oldpath
- removePackageStructure()
-
- def test_getsFilenamesInSubPackagesIfCtxFilenameIsInTheRoot(self):
- try:
- oldpath = getRoot().pythonpath
- getRoot().pythonpath = [] # clear the python path
- createPackageStructure("","")
- fnames = [f for f in
- generateModuleFilenamesInPythonPath(pkgstructureFile0)]
- self.assert_(pkgstructureFile1 in fnames)
- self.assert_(pkgstructureFile2 in fnames)
- finally:
- getRoot().pythonpath = oldpath
- removePackageStructure()
-
- def test_doesntTraverseOtherPackagesOffOfTheRoot(self):
- try:
- oldpath = getRoot().pythonpath
- getRoot().pythonpath = [] # clear the python path
- createPackageStructure("","")
- os.makedirs(os.path.join(pkgstructureRootDir, "c"))
- writeFile(os.path.join(pkgstructureRootDir, "c", "__init__.py"), "# ")
- bazfile = os.path.join(pkgstructureRootDir, "c", "baz.py")
- writeFile(bazfile, "pass")
- fnames = [f for f in
- generateModuleFilenamesInPythonPath(pkgstructureFile1)]
- self.assert_(pkgstructureFile0 in fnames)
- self.assert_(pkgstructureFile1 in fnames)
- self.assert_(pkgstructureFile2 in fnames)
- self.assert_(bazfile not in fnames)
- finally:
- getRoot().pythonpath = oldpath
- os.remove(os.path.join(pkgstructureRootDir, "c", "baz.py"))
- os.remove(os.path.join(pkgstructureRootDir, "c", "__init__.py"))
- os.removedirs(os.path.join(pkgstructureRootDir, "c"))
- removePackageStructure()
-
-
-class TestGetPackageDependencies(BRMTestCase):
-
- def test_followsImportModule(self):
- try:
- createPackageStructure("","import c.bing")
- createSecondPackageStructure("")
- dependencies = [d for d in
- generatePackageDependencies(pkgstructureFile2)]
- self.assertEqual([pkgstructureBasedir2],dependencies)
- finally:
- removeSecondPackageStructure()
- removePackageStructure()
-
-
- def test_followsFromImportPackage(self):
- try:
- createPackageStructure("","import c")
- createSecondPackageStructure("")
- dependencies = [d for d in
- generatePackageDependencies(pkgstructureFile2)]
- self.assertEqual([pkgstructureBasedir2],dependencies)
- finally:
- removeSecondPackageStructure()
- removePackageStructure()
-
-
-
- def test_followsFromImportStar(self):
- try:
- createPackageStructure("","from c import *")
- createSecondPackageStructure("")
- dependencies = [d for d in
- generatePackageDependencies(pkgstructureFile2)]
- self.assertEqual([pkgstructureBasedir2],dependencies)
- finally:
- removeSecondPackageStructure()
- removePackageStructure()
-
- def test_followsFromImportModule(self):
- try:
- createPackageStructure("","from c import bing")
- createSecondPackageStructure("")
- dependencies = [d for d in
- generatePackageDependencies(pkgstructureFile2)]
- self.assertEqual([pkgstructureBasedir2],dependencies)
- finally:
- removeSecondPackageStructure()
- removePackageStructure()
-
-
- def test_doesntBreakIfImportIsInAMultilineString(self):
- try:
- createPackageStructure("",trimLines("""
- '''
- from aoeuaoeu import aocxaoieicxoe
- '''
- """))
- createSecondPackageStructure("")
- dependencies = [d for d in
- generatePackageDependencies(pkgstructureFile2)]
- self.assertEqual([],dependencies)
- finally:
- removeSecondPackageStructure()
- removePackageStructure()
-
- def test_doesntBreakIfImportIsCommented(self):
- try:
- createPackageStructure("","#from aoeuaoeu import aocxaoieicxoe")
- createSecondPackageStructure("")
- dependencies = [d for d in
- generatePackageDependencies(pkgstructureFile2)]
- self.assertEqual([],dependencies)
- finally:
- removeSecondPackageStructure()
- removePackageStructure()
-
-
- def test_doesntBreakIfCantFindImport(self):
- try:
- createPackageStructure("","from aoeuaoeu import aocxaoieicxoe")
- createSecondPackageStructure("")
- dependencies = [d for d in
- generatePackageDependencies(pkgstructureFile2)]
- self.assertEqual([],dependencies)
- finally:
- removeSecondPackageStructure()
- removePackageStructure()
-
-
- def test_doesntIncludeCurrentPackage(self):
- try:
- createPackageStructure("","import a.foo")
- createSecondPackageStructure("")
- dependencies = [d for d in
- generatePackageDependencies(pkgstructureFile2)]
- self.assertEqual([],dependencies)
- finally:
- removeSecondPackageStructure()
- removePackageStructure()
-
-
-
-
-if __name__ == "__main__":
- unittest.main()
--- a/vim/sadness/bike/bike/parsing/test_parserutils.py Thu Feb 10 17:11:26 2011 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,135 +0,0 @@
-#!/usr/bin/env python
-import unittest
-from parserutils import *
-from bike.testutils import *
-
-class TestRemoveEscapedQuotes(BRMTestCase):
-
- def testMaskEscapedQuotes_MasksEscapedQuotes(self):
- src = '\" \\\\\\\" \' \\\\\\\\\" \' \''
- self.assertEqual(maskEscapedQuotes(src),'" **** \' ****" \' \'')
-
-class TestMungePythonKeywordsInStrings(BRMTestCase):
- def test_mungesKeywords(self):
- src = '\"\"\"class try while\"\"\" class2 try2 while2 \'\'\' def if for \'\'\' def2 if2 for2'
- self.assertEqual(maskPythonKeywordsInStringsAndComments(src),
- '"""CLASS TRY WHILE""" class2 try2 while2 \'\'\' DEF IF FOR \'\'\' def2 if2 for2')
-
-
-class TestSplitLines(BRMTestCase):
- def test_handlesExplicitlyContinuedLineWithComment(self):
- self.assertEqual(splitLogicalLines(explicitlyContinuedLineWithComment),
- ['\n', 'z = a + b + \\ # comment\n c + d\n', 'pass\n'])
-
- def test_handlesImplicitlyContinuedLine(self):
- self.assertEqual(splitLogicalLines(implicitlyContinuedLine),
- ['\n', 'z = a + b + (\n c + d)\n', 'pass\n'])
-
- def test_handlesNestedImplicitlyContinuedLine(self):
- self.assertEqual(splitLogicalLines(implicitlyContinuedLine2),
- ['\n', 'z = a + b + ( c + [d\n + e]\n + f) # comment\n', 'pass\n'])
-
-
- def test_handlesMultiLineStrings(self):
- self.assertEqual(splitLogicalLines(multilineComment),
- ['\n', "''' this is an mlc\nso is this\n'''\n", 'pass\n'])
-
-
-class TestMakeLineParseable(BRMTestCase):
- def test_worksWithIfStatement(self):
- src = "if foo:"
- self.assertEqual(makeLineParseable(src),("if foo: pass"))
-
- def test_worksWithTryStatement(self):
- src = "try :"
- self.assertEqual(makeLineParseable(src),("try : pass\nexcept: pass"))
-
- def test_worksOnTryStatementWithCodeInlined(self):
- src = "try : a = 1"
- self.assertEqual(makeLineParseable(src),("try : a = 1\nexcept: pass"))
-
- def test_worksWithExceptStatement(self):
- src = "except :"
- self.assertEqual(makeLineParseable(src),("try: pass\nexcept : pass"))
-
- def test_worksWithFinallyStatement(self):
- src = "finally:"
- self.assertEqual(makeLineParseable(src),("try: pass\nfinally: pass"))
-
- def test_worksWithIfStatement(self):
- src = "if foo:"
- self.assertEqual(makeLineParseable(src),("if foo: pass"))
-
- def test_worksWithElseStatement(self):
- src = "else :"
- self.assertEqual(makeLineParseable(src),("if 0: pass\nelse : pass"))
-
- def test_worksWithElifStatement(self):
- src = "elif foo:"
- self.assertEqual(makeLineParseable(src),("if 0: pass\nelif foo: pass"))
-
-
-def runOverPath(path):
- import compiler
- from parser import ParserError
- from bike.parsing.load import getFilesForName
- files = getFilesForName(path)
- for fname in files:
- print fname
- src = file(fname).read()
- #print src
- src = maskStringsAndRemoveComments(src)
-
- for logicalline in splitLogicalLines(src):
- #print "logicalline=",logicalline
- logicalline = logicalline.strip()
- logicalline = makeLineParseable(logicalline)
- try:
- compiler.parse(logicalline)
- except ParserError:
- print "ParserError on logicalline:",logicalline
- except:
- log.exception("caught exception")
-
-
-explicitlyContinuedLineWithComment = """
-z = a + b + \ # comment
- c + d
-pass
-"""
-
-implicitlyContinuedLine = """
-z = a + b + (
- c + d)
-pass
-"""
-
-
-implicitlyContinuedLine2 = """
-z = a + b + ( c + [d
- + e]
- + f) # comment
-pass
-"""
-
-multilineComment = """
-''' this is an mlc
-so is this
-'''
-pass
-"""
-
-if __name__ == "__main__":
- from bike import logging
- logging.init()
- log = logging.getLogger("bike")
- log.setLevel(logging.INFO)
-
- # add soak tests to end of test
- class Z_SoakTest(BRMTestCase):
- def test_linesRunThroughPythonParser(self):
- print ""
- #print splitLogicalLines(file('/usr/local/lib/python2.2/aifc.py').read())
- #runOverPath('/usr/local/lib/python2.2/test/badsyntax_nocaret.py')
- runOverPath('/usr/local/lib/python2.2/')
- unittest.main()
--- a/vim/sadness/bike/bike/parsing/test_pathutils.py Thu Feb 10 17:11:26 2011 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,128 +0,0 @@
-#!/usr/bin/env python
-import setpath
-import unittest
-import compiler
-import os
-
-from bike import testdata
-from bike.testutils import *
-from bike.mock import Mock
-
-from pathutils import getPathOfModuleOrPackage
-from pathutils import *
-import pathutils as loadmodule
-
-class TestGetFilesForName(BRMTestCase):
- def testGetFilesForName_recursivelyReturnsFilesInBreadthFirstOrder(self):
- createPackageStructure("pass", "pass")
-
- files = getFilesForName(pkgstructureBasedir)
- for f in files:
- assert f in \
- [os.path.join(pkgstructureBasedir, '__init__.py'),
- os.path.join(pkgstructureBasedir, 'foo.py'),
- os.path.join(pkgstructureChilddir, '__init__.py'),
- os.path.join(pkgstructureChilddir, 'bah.py')]
-
- def testGetFilesForName_globsStars(self):
- createPackageStructure("pass", "pass")
- assert getFilesForName(os.path.join(pkgstructureBasedir, "fo*")) == [os.path.join(pkgstructureBasedir, 'foo.py')]
- removePackageStructure()
-
- def testGetFilesForName_doesntListFilesWithDotAtFront(self):
- writeFile(os.path.join(".foobah.py"),"")
- files = getFilesForName("a")
- self.assertEqual([],files)
-
-
-
-
-class TestGetRootDirectory(BRMTestCase):
- def test_returnsParentDirectoryIfFileNotInPackage(self):
- try:
- # this doesnt have __init__.py file, so
- # isnt package
- os.makedirs("a")
- writeFile(os.path.join("a", "foo.py"), "pass")
- dir = loadmodule.getRootDirectory(os.path.join("a", "foo.py"))
- assert dir == "a"
- finally:
- os.remove(os.path.join("a", "foo.py"))
- os.removedirs(os.path.join("a"))
-
- def test_returnsFirstNonPackageParentDirectoryIfFileInPackage(self):
- try:
- os.makedirs(os.path.join("root", "a", "b"))
- writeFile(os.path.join("root", "a", "__init__.py"), "# ")
- writeFile(os.path.join("root", "a", "b", "__init__.py"), "# ")
- writeFile(os.path.join("root", "a", "b", "foo.py"), "pass")
- dir = loadmodule.getRootDirectory(os.path.join("root", "a", "b", "foo.py"))
- assert dir == "root"
- finally:
- os.remove(os.path.join("root", "a", "__init__.py"))
- os.remove(os.path.join("root", "a", "b", "__init__.py"))
- os.remove(os.path.join("root", "a", "b", "foo.py"))
- os.removedirs(os.path.join("root", "a", "b"))
-
- def test_returnsFirstNonPackageParentDirectoryIfPathIsAPackage(self):
- try:
- os.makedirs(os.path.join("root", "a", "b"))
- writeFile(os.path.join("root", "a", "__init__.py"), "# ")
- writeFile(os.path.join("root", "a", "b", "__init__.py"), "# ")
- writeFile(os.path.join("root", "a", "b", "foo.py"), "pass")
- dir = loadmodule.getRootDirectory(os.path.join("root", "a", "b"))
- assert dir == "root"
- finally:
- os.remove(os.path.join("root", "a", "__init__.py"))
- os.remove(os.path.join("root", "a", "b", "__init__.py"))
- os.remove(os.path.join("root", "a", "b", "foo.py"))
- os.removedirs(os.path.join("root", "a", "b"))
-
- def test_returnsDirIfDirIsTheRootDirectory(self):
- try:
- os.makedirs(os.path.join("root", "a", "b"))
- writeFile(os.path.join("root", "a", "__init__.py"), "# ")
- writeFile(os.path.join("root", "a", "b", "__init__.py"), "# ")
- writeFile(os.path.join("root", "a", "b", "foo.py"), "pass")
- dir = loadmodule.getRootDirectory("root")
- assert dir == "root"
- finally:
- os.remove(os.path.join("root", "a", "__init__.py"))
- os.remove(os.path.join("root", "a", "b", "__init__.py"))
- os.remove(os.path.join("root", "a", "b", "foo.py"))
- os.removedirs(os.path.join("root", "a", "b"))
-
-
-class getPackageBaseDirectory(BRMTestCase):
- def test_returnsBasePackageIfFileInPackageHierarchy(self):
- try:
- createPackageStructure("","")
- dir = loadmodule.getPackageBaseDirectory(pkgstructureFile2)
- self.assertEqual(pkgstructureBasedir, dir)
- finally:
- removePackageStructure()
-
- def test_returnsFileDirectoryIfFileNotInPackage(self):
- try:
- createPackageStructure("","")
- dir = loadmodule.getPackageBaseDirectory(pkgstructureFile0)
- self.assertEqual(pkgstructureRootDir, dir)
- finally:
- removePackageStructure()
-
-
-class TestGetPathOfModuleOrPackage(BRMTestCase):
- def test_worksForFullPath(self):
- try:
- createPackageStructure("pass","pass")
- import sys
- self.assertEqual(getPathOfModuleOrPackage("a.b.bah",
- [pkgstructureRootDir]),
- pkgstructureFile2)
- finally:
- removePackageStructure()
-
-
-
-if __name__ == "__main__":
- unittest.main()
--- a/vim/sadness/bike/bike/parsing/test_utils.py Thu Feb 10 17:11:26 2011 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,41 +0,0 @@
-#!/usr/bin/env python
-import setpath
-import unittest
-from utils import *
-
-class Test_CarCdrEtc(unittest.TestCase):
- def test_carReturnsTheFirstElementOfTheFqn(self):
- fqn = "apple.pear.foo"
- assert fqn_car(fqn) == "apple"
-
- def test_carReturnsElementInOneElementFqn(self):
- fqn = "apple"
- assert fqn_car(fqn) == "apple"
-
- def test_cdrReturnsTheAllElementsOfTheFqnExceptFirst(self):
- fqn = "apple.pear.foo"
- assert fqn_cdr(fqn) == "pear.foo"
-
- def test_cdrReturnsEmptyStringForOneElementFqn(self):
- fqn = "apple"
- assert fqn_cdr(fqn) == ""
-
- def test_rcarReturnsTheLastElementOfTheFqn(self):
- fqn = "apple.pear.foo"
- assert fqn_rcar(fqn) == "foo"
-
- def test_rcarReturnsElementInOneElementFqn(self):
- fqn = "apple"
- assert fqn_rcar(fqn) == "apple"
-
- def test_rdrReturnsTheAllElementsOfTheFqnExceptLast(self):
- fqn = "apple.pear.foo"
- assert fqn_rcdr(fqn) == "apple.pear"
-
- def test_rdrReturnsEmptyStringForOneElementFqn(self):
- fqn = "apple"
- assert fqn_rcdr(fqn) == ""
-
-
-if __name__ == "__main__":
- unittest.main()
--- a/vim/sadness/bike/bike/parsing/test_visitor.py Thu Feb 10 17:11:26 2011 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,114 +0,0 @@
-#!/usr/bin/env python
-from __future__ import generators
-import setpath
-import unittest
-import visitor
-from bike.testutils import *
-
-class TestVisitor(BRMTestCase):
- def test_callsVistorFunctions(self):
- tree = createTree()
-
- class TreeVisitor:
- def __init__(self):
- self.txt = []
-
- def visitAClass(self,node):
- self.txt.append("visitAClass")
- self.txt.append(node.txt)
- return self.visitChildren(node)
-
- def visitCClass(self,node):
- self.txt.append("visitCClass")
- self.txt.append(node.txt)
-
- def getTxt(self):
- return ",".join(self.txt)
-
- self.assertEqual(visitor.walk(tree,TreeVisitor()).getTxt(),
- "visitAClass,aclass,visitCClass,cclass0,visitCClass,cclass1,visitCClass,cclass2")
-
-
- def test_callsVisitorFunctionsWithYield(self):
- tree = createTree()
-
- class TreeVisitor:
- def __init__(self):
- self.txt = []
-
- def visitAClass(self,node):
- self.txt.append("visitAClass")
- self.txt.append(node.txt)
- yield node
- for i in self.visitChildren(node):
- yield i
-
- def visitCClass(self,node):
- self.txt.append("visitCClass")
- self.txt.append(node.txt)
- if 0: yield 1
-
- def getTxt(self):
- return ",".join(self.txt)
-
- for node in visitor.walkAndGenerate(tree,TreeVisitor()):
- assert node.txt == "aclass"
-
-
-def createTree():
- n = AClass("aclass")
- for i in xrange(3):
- b = n.addChildNode(BClass("bclass%d" % i))
- for j in xrange(20):
- b = b.addChildNode(BClass("bclass%d" % i))
- b.addChildNode(CClass("cclass%d" % i))
- return n
-
-class node(object):
- def __init__(self,txt):
- self._childNodes=[]
- self.txt = txt
-
- def addChildNode(self,node):
- self._childNodes.append(node)
- return node
-
- def getChildNodes(self):
- return [x for x in self._childNodes]
-
-
-class AClass(node):
- pass
-
-class BClass(node):
- pass
-
-class CClass(node):
- pass
-
-if __name__ == "__main__":
-
- # add perf test at end of tests
- class Z_SoakTestFastparser(BRMTestCase):
- def test_parsesPythonLibraryCorrectly(self):
-
- class TreeVisitor:
- pass
-
- import time
-
- tree = createTree()
-
- t1 = time.time()
- for i in xrange(1000):
- visitor.walk(tree,TreeVisitor())
- print "tree without yield",time.time()-t1
-
- t1 = time.time()
- for i in xrange(1000):
- for node in visitor.walkAndGenerate(tree,TreeVisitor()):
- pass
- print "tree with yield",time.time()-t1
-
-
- unittest.main()
--- a/vim/sadness/bike/bike/parsing/testall.py Thu Feb 10 17:11:26 2011 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,18 +0,0 @@
-#!/usr/bin/env python
-import setpath
-
-import unittest
-
-#import all the tests
-from test_load import *
-from test_newstuff import *
-from test_parserutils import *
-from test_fastparser import *
-from test_fastparserast import *
-
-if __name__ == "__main__":
- from bike import logging
- logging.init()
- log = logging.getLogger("bike")
- log.setLevel(logging.WARN)
- unittest.main()
--- a/vim/sadness/bike/bike/parsing/utils.py Thu Feb 10 17:11:26 2011 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,30 +0,0 @@
-# get the first element of a fully qualified python path
-#(e.g. _car('a.b.c.d') = 'a')
-def fqn_car(fqn):
- try:
- return fqn[:fqn.index(".")]
- except ValueError: # i.e. no dots in fqn
- return fqn
-
-# get the other elements of a fully qualified python path
-#(e.g. _cdr('a.b.c.d') = 'b.c.d')
-def fqn_cdr(fqn):
- try:
- return fqn[fqn.index(".")+1:]
- except ValueError: # i.e. no dots in fqn
- return ""
-
-# reverse of above _rcar("a.b.c.d") = "d"
-def fqn_rcar(fqn):
- try:
- return fqn[fqn.rindex(".")+1:]
- except ValueError: # i.e. no dots in fqn
- return fqn
-
-
-# reverse of above _rcdr("a.b.c.d") = "a.b.c"
-def fqn_rcdr(fqn):
- try:
- return fqn[:fqn.rindex(".")]
- except ValueError: # i.e. no dots in fqn
- return ""
--- a/vim/sadness/bike/bike/parsing/visitor.py Thu Feb 10 17:11:26 2011 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,49 +0,0 @@
-from __future__ import generators
-
-class TreeWalker(object):
- VERBOSE = 0
-
- def __init__(self):
- self.node = None
- self._cache = {}
-
- def default(self, node, *args):
- for child in node.getChildNodes():
- self.dispatch(child, *args)
-
- def dispatch(self, node, *args):
- self.node = node
- klass = node.__class__
- meth = self._cache.get(klass, None)
- if meth is None:
- className = klass.__name__
- meth = getattr(self.visitor, 'visit' + className, self.default)
- self._cache[klass] = meth
- return meth(node, *args)
-
- def preorder(self, tree, visitor, *args):
- """Do preorder walk of tree using visitor"""
- self.visitor = visitor
- visitor.visit = self.dispatch
- visitor.visitChildren = self.default
- return self.dispatch(tree, *args)
-
-class GeneratingTreeWalker(TreeWalker):
-
- def default(self, node, *args):
- for child in node.getChildNodes():
- for i in self.dispatch(child, *args):
- yield i
-
-
-def walk(tree, visitor):
- walker = TreeWalker()
- walker.preorder(tree, visitor)
- return walker.visitor
-
-
-def walkAndGenerate(tree,visitor):
- walker = GeneratingTreeWalker()
- return walker.preorder(tree, visitor)
-
-
--- a/vim/sadness/bike/bike/query/__init__.py Thu Feb 10 17:11:26 2011 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,1 +0,0 @@
-#
\ No newline at end of file
--- a/vim/sadness/bike/bike/query/common.py Thu Feb 10 17:11:26 2011 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,333 +0,0 @@
-from __future__ import generators
-from bike.globals import *
-from bike.parsing.fastparserast import getRoot, Function, Class, Module, getModule
-from bike.parsing.parserutils import generateLogicalLines, makeLineParseable, UnbalancedBracesException, generateLogicalLinesAndLineNumbers
-from bike.parsing.newstuff import getSourceNodesContainingRegex
-from bike.parsing import visitor
-from bike import log
-import compiler
-from compiler.ast import Getattr, Name
-import re
-
-class Match:
- def __repr__(self):
- return ",".join([self.filename, str(self.lineno), str(self.colno),
- str(self.confidence)])
- def __eq__(self,other):
- if self is None or other is None:
- return False
- return self.filename == other.filename and \
- self.lineno == other.lineno and \
- self.colno == other.colno
-
-def getScopeForLine(sourceNode, lineno):
- scope = None
- childnodes = sourceNode.getFlattenedListOfFastParserASTNodes()
- if childnodes == []:
- return sourceNode.fastparseroot #module node
-
- scope = sourceNode.fastparseroot
-
- for node in childnodes:
- if node.linenum > lineno: break
- scope = node
-
- if scope.getStartLine() != scope.getEndLine(): # is inline
- while scope.getEndLine() <= lineno:
- scope = scope.getParent()
- return scope
-
-
-
-# global from the perspective of 'contextFilename'
-def globalScanForMatches(contextFilename, matchFinder, targetname):
- for sourcenode in getSourceNodesContainingRegex(targetname, contextFilename):
- print >> log.progress, "Scanning", sourcenode.filename
- searchscope = sourcenode.fastparseroot
- for match in scanScopeForMatches(sourcenode,searchscope,
- matchFinder,targetname):
- yield match
-
-
-def scanScopeForMatches(sourcenode,scope,matchFinder,targetname):
- lineno = scope.getStartLine()
- for line in generateLogicalLines(scope.getMaskedLines()):
- if line.find(targetname) != -1:
- doctoredline = makeLineParseable(line)
- ast = compiler.parse(doctoredline)
- scope = getScopeForLine(sourcenode, lineno)
- matchFinder.reset(line)
- matchFinder.setScope(scope)
- matches = visitor.walk(ast, matchFinder).getMatches()
- for index, confidence in matches:
- match = Match()
- match.filename = sourcenode.filename
- match.sourcenode = sourcenode
- x, y = indexToCoordinates(line, index)
- match.lineno = lineno+y
- match.colno = x
- match.colend = match.colno+len(targetname)
- match.confidence = confidence
- yield match
- lineno+=line.count("\n")
-
-
-def walkLinesContainingStrings(scope,astWalker,targetnames):
- lineno = scope.getStartLine()
- for line in generateLogicalLines(scope.getMaskedLines()):
- if lineContainsOneOf(line,targetnames):
- doctoredline = makeLineParseable(line)
- ast = compiler.parse(doctoredline)
- astWalker.lineno = lineno
- matches = visitor.walk(ast, astWalker)
- lineno+=line.count("\n")
-
-
-def lineContainsOneOf(line,targetnames):
- for name in targetnames:
- if line.find(name) != -1:
- return True
- return False
-
-
-# translates an idx in a logical line into physical line coordinates
-# returns x and y coords
-def indexToCoordinates(src, index):
- y = src[: index].count("\n")
- startOfLineIdx = src.rfind("\n", 0, index)+1
- x = index-startOfLineIdx
- return x, y
-
-
-
-# interface for MatchFinder classes
-# implement the visit methods
-class MatchFinder:
- def setScope(self, scope):
- self.scope = scope
-
- def reset(self, line):
- self.matches = []
- self.words = re.split("(\w+)", line) # every other one is a non word
- self.positions = []
- i = 0
- for word in self.words:
- self.positions.append(i)
- #if '\n' in word: # handle newlines
- # i = len(word[word.index('\n')+1:])
- #else:
- i+=len(word)
- self.index = 0
-
- def getMatches(self):
- return self.matches
-
- # need to visit childnodes in same order as they appear
- def visitPrintnl(self,node):
- if node.dest:
- self.visit(node.dest)
- for n in node.nodes:
- self.visit(n)
-
- def visitName(self, node):
- self.popWordsUpTo(node.name)
-
- def visitClass(self, node):
- self.popWordsUpTo(node.name)
- for base in node.bases:
- self.visit(base)
-
- def zipArgs(self, argnames, defaults):
- """Takes a list of argument names and (possibly a shorter) list of
- default values and zips them into a list of pairs (argname, default).
- Defaults are aligned so that the last len(defaults) arguments have
- them, and the first len(argnames) - len(defaults) pairs have None as a
- default.
- """
- fixed_args = len(argnames) - len(defaults)
- defaults = [None] * fixed_args + list(defaults)
- return zip(argnames, defaults)
-
- def visitFunction(self, node):
- self.popWordsUpTo(node.name)
- for arg, default in self.zipArgs(node.argnames, node.defaults):
- self.popWordsUpTo(arg)
- if default is not None:
- self.visit(default)
- self.visit(node.code)
-
- def visitGetattr(self,node):
- self.visit(node.expr)
- self.popWordsUpTo(node.attrname)
-
- def visitAssName(self, node):
- self.popWordsUpTo(node.name)
-
- def visitAssAttr(self, node):
- self.visit(node.expr)
- self.popWordsUpTo(node.attrname)
-
- def visitImport(self, node):
- for name, alias in node.names:
- for nameelem in name.split("."):
- self.popWordsUpTo(nameelem)
- if alias is not None:
- self.popWordsUpTo(alias)
-
- def visitFrom(self, node):
- for elem in node.modname.split("."):
- self.popWordsUpTo(elem)
- for name, alias in node.names:
- self.popWordsUpTo(name)
- if alias is not None:
- self.popWordsUpTo(alias)
-
- def visitLambda(self, node):
- for arg, default in self.zipArgs(node.argnames, node.defaults):
- self.popWordsUpTo(arg)
- if default is not None:
- self.visit(default)
- self.visit(node.code)
-
- def visitGlobal(self, node):
- for name in node.names:
- self.popWordsUpTo(name)
-
- def popWordsUpTo(self, word):
- if word == "*":
- return # won't be able to find this
- posInWords = self.words.index(word)
- idx = self.positions[posInWords]
- self.words = self.words[posInWords+1:]
- self.positions = self.positions[posInWords+1:]
-
- def appendMatch(self,name,confidence=100):
- idx = self.getNextIndexOfWord(name)
- self.matches.append((idx, confidence))
-
- def getNextIndexOfWord(self,name):
- return self.positions[self.words.index(name)]
-
-class CouldNotLocateNodeException(Exception): pass
-
-def translateSourceCoordsIntoASTNode(filename,lineno,col):
- module = getModule(filename)
- maskedlines = module.getMaskedModuleLines()
- lline,backtrackchars = getLogicalLine(module, lineno)
- doctoredline = makeLineParseable(lline)
- ast = compiler.parse(doctoredline)
- idx = backtrackchars+col
- nodefinder = ASTNodeFinder(lline,idx)
- node = compiler.walk(ast, nodefinder).node
- if node is None:
- raise CouldNotLocateNodeException("Could not translate editor coordinates into source node")
- return node
-
-def getLogicalLine(module, lineno):
- # we know that the scope is the start of a logical line, so
- # we search from there
- scope = getScopeForLine(module.getSourceNode(), lineno)
- linegenerator = \
- module.generateLinesWithLineNumbers(scope.getStartLine())
- for lline,llinenum in \
- generateLogicalLinesAndLineNumbers(linegenerator):
- if llinenum > lineno:
- break
- prevline = lline
- prevlinenum = llinenum
-
- backtrackchars = 0
- for i in range(prevlinenum,lineno):
- backtrackchars += len(module.getSourceNode().getLines()[i-1])
- return prevline, backtrackchars
-
-
-
-class ASTNodeFinder(MatchFinder):
- # line is a masked line of text
- # lineno and col are coords
- def __init__(self,line,col):
- self.line = line
- self.col = col
- self.reset(line)
- self.node = None
-
- def visitName(self,node):
- if self.checkIfNameMatchesColumn(node.name):
- self.node = node
- self.popWordsUpTo(node.name)
-
- def visitGetattr(self,node):
- self.visit(node.expr)
- if self.checkIfNameMatchesColumn(node.attrname):
- self.node = node
- self.popWordsUpTo(node.attrname)
-
- def visitFunction(self, node):
- if self.checkIfNameMatchesColumn(node.name):
- self.node = node
- self.popWordsUpTo(node.name)
-
- for arg, default in self.zipArgs(node.argnames, node.defaults):
- if self.checkIfNameMatchesColumn(arg):
- self.node = Name(arg)
- self.popWordsUpTo(arg)
- if default is not None:
- self.visit(default)
- self.visit(node.code)
-
-
- visitAssName = visitName
- visitAssAttr = visitGetattr
-
- def visitClass(self, node):
- if self.checkIfNameMatchesColumn(node.name):
- self.node = node
- self.popWordsUpTo(node.name)
- for base in node.bases:
- self.visit(base)
-
-
- def checkIfNameMatchesColumn(self,name):
- idx = self.getNextIndexOfWord(name)
- #print "name",name,"idx",idx,"self.col",self.col
- if idx <= self.col and idx+len(name) > self.col:
- return 1
- return 0
-
- def visitFrom(self, node):
- for elem in node.modname.split("."):
- self.popWordsUpTo(elem)
- for name, alias in node.names:
- if self.checkIfNameMatchesColumn(name):
- self.node = self._manufactureASTNodeFromFQN(name)
- return
- self.popWordsUpTo(name)
- if alias is not None:
- self.popWordsUpTo(alias)
-
- # gets round the fact that imports etc dont contain nested getattr
- # nodes for fqns (e.g. import a.b.bah) by converting the fqn
- # string into a getattr instance
- def _manufactureASTNodeFromFQN(self,fqn):
- if "." in fqn:
- assert 0, "getattr not supported yet"
- else:
- return Name(fqn)
-
-def isAMethod(scope,node):
- return isinstance(node,compiler.ast.Function) and \
- isinstance(scope,Class)
-
-def convertNodeToMatchObject(node,confidence=100):
- m = Match()
- m.sourcenode = node.module.getSourceNode()
- m.filename = node.filename
- if isinstance(node,Module):
- m.lineno = 1
- m.colno = 0
- elif isinstance(node,Class) or isinstance(node,Function):
- m.lineno = node.getStartLine()
- m.colno = node.getColumnOfName()
- m.confidence = confidence
- return m
--- a/vim/sadness/bike/bike/query/findDefinition.py Thu Feb 10 17:11:26 2011 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,277 +0,0 @@
-from __future__ import generators
-from bike.query.common import Match, MatchFinder, \
- getScopeForLine, indexToCoordinates, \
- translateSourceCoordsIntoASTNode, scanScopeForMatches, \
- isAMethod, convertNodeToMatchObject, walkLinesContainingStrings
-from bike.parsing.parserutils import generateLogicalLines,\
- generateLogicalLinesAndLineNumbers, \
- splitLogicalLines, makeLineParseable
-import compiler
-from compiler.ast import Getattr, Name, AssName, AssAttr
-from bike.parsing.fastparserast import getRoot, Package, Class, \
- Module, Function, Instance
-import re
-from bike.query.getTypeOf import getTypeOfExpr, UnfoundType, \
- isWordInLine, resolveImportedModuleOrPackage
-from bike.parsing import visitor
-from bike.parsing.visitor import walkAndGenerate
-
-from bike.parsing.parserutils import makeLineParseable,splitLogicalLines
-from bike.parsing.newstuff import getSourceNodesContainingRegex
-from bike.parsing.load import getSourceNode
-from bike import log
-
-
-class CantFindDefinitionException:
- pass
-
-
-def findAllPossibleDefinitionsByCoords(filepath,lineno,col):
-
- #try:
- node = translateSourceCoordsIntoASTNode(filepath,lineno,col)
- #except:
- # import traceback
- # traceback.print_exc()
-
- if node is None:
- raise "selected node type not supported"
- scope = getScopeForLine(getSourceNode(filepath),lineno)
- match = findDefinitionFromASTNode(scope,node)
- if match is not None:
- yield match
- if isinstance(node,Getattr) and (match is None or match.confidence != 100):
- root = getRoot()
- name = node.attrname
- for match in scanPythonPathForMatchingMethodNames(name,filepath):
- yield match
- print >>log.progress,"done"
-
-
-def findDefinitionFromASTNode(scope,node):
- assert node is not None
- if isinstance(node,Name) or isinstance(node,AssName):
- while 1:
- # try scope children
- childscope = scope.getChild(node.name)
- if childscope is not None:
- return convertNodeToMatchObject(childscope,100)
-
- if isinstance(scope,Package):
- scope = scope.getChild("__init__")
-
- # try arguments and assignments
- match = scanScopeAST(scope,node.name,
- AssignmentAndFnArgsSearcher(node.name))
- if match is not None:
- return match
-
- # try imports
- match = searchImportedModulesForDefinition(scope,node)
- if match is not None:
- return match
-
-
- if not isinstance(scope,Module):
- # try parent scope
- scope = scope.getParent()
- else:
- break
- assert isinstance(scope,Module)
-
- elif isinstance(node,Getattr) or isinstance(node,AssAttr):
- exprtype = getTypeOfExpr(scope,node.expr)
- if not (exprtype is None or isinstance(exprtype,UnfoundType)):
- if isinstance(exprtype,Instance):
- exprtype = exprtype.getType()
- match = findDefinitionOfAttributeFromASTNode(exprtype,
- node.attrname)
- else:
- match = findDefinitionFromASTNode(exprtype,
- Name(node.attrname))
- if match is not None:
- return match
-
- elif isinstance(node,compiler.ast.Function) or \
- isinstance(node,compiler.ast.Class):
- if isAMethod(scope,node):
- match = findDefinitionOfAttributeFromASTNode(scope,
- node.name)
- else:
- match = findDefinitionFromASTNode(scope,Name(node.name))
- if match is not None:
- return match
-
-
- type = getTypeOfExpr(scope,node)
- if type is not None and (not isinstance(type,UnfoundType)) and \
- (not isinstance(type,Instance)):
- return convertNodeToMatchObject(type,100)
- else:
- return None
-
-
-def findDefinitionOfAttributeFromASTNode(type,name):
- assert isinstance(type,Class)
- attrfinder = AttrbuteDefnFinder([type],name)
-
- # first scan the method names:
- for child in type.getChildNodes():
- if child.name == name:
- return convertNodeToMatchObject(child,100)
- # then scan the method source for attribues
- for child in type.getChildNodes():
- if isinstance(child,Function):
- try:
- return scanScopeForMatches(child.module.getSourceNode(),
- child, attrfinder,
- name).next()
- except StopIteration:
- continue
-
-
-class AttrbuteDefnFinder(MatchFinder):
- def __init__(self,targetClasses,targetAttribute):
- self.targetClasses = targetClasses
- self.targetAttributeName = targetAttribute
-
- def visitAssAttr(self, node):
- for c in node.getChildNodes():
- self.visit(c)
-
- if node.attrname == self.targetAttributeName:
- exprtype = getTypeOfExpr(self.scope,node.expr)
- if isinstance(exprtype,Instance) and \
- exprtype.getType() in self.targetClasses:
- self.appendMatch(self.targetAttributeName)
- #else:
- # self.appendMatch(self.targetAttributeName,50)
- self.popWordsUpTo(node.attrname)
-
-
-
-
-def searchImportedModulesForDefinition(scope,node):
- lines = scope.module.getSourceNode().getLines()
- for lineno in scope.getImportLineNumbers():
- logicalline = getLogicalLine(lines,lineno)
- logicalline = makeLineParseable(logicalline)
- ast = compiler.parse(logicalline)
- class ImportVisitor:
- def __init__(self,node):
- self.target = node
- self.match = None
- assert isinstance(self.target,Name), \
- "Getattr not supported"
-
- def visitFrom(self, node):
- module = resolveImportedModuleOrPackage(scope,node.modname)
- if module is None: # couldn't find module
- return
-
- if node.names[0][0] == '*': # e.g. from foo import *
- match = findDefinitionFromASTNode(module,self.target)
- if match is not None:
- self.match = match
- return
-
- for name, alias in node.names:
- if alias is None and name == self.target.name:
- match = findDefinitionFromASTNode(module,self.target)
- if match is not None:
- self.match = match
- return
-
-
- match = visitor.walk(ast, ImportVisitor(node)).match
- if match:
- return match
- # loop
-
-
-def getLogicalLine(lines,lineno):
- return generateLogicalLines(lines[lineno-1:]).next()
-
-class AssignmentAndFnArgsSearcher(MatchFinder):
- def __init__(self,name):
- self.targetname = name
- self.match = None
-
- def visitAssName(self, node):
- if node.name == self.targetname:
- idx = self.getNextIndexOfWord(self.targetname)
- self.match = idx
- return
-
- def visitFunction(self, node):
- self.popWordsUpTo(node.name)
- for arg, default in self.zipArgs(node.argnames, node.defaults):
- if arg == self.targetname:
- idx = self.getNextIndexOfWord(self.targetname)
- self.match = idx
- return
- self.popWordsUpTo(arg)
- if default is not None:
- self.visit(default)
- self.visit(node.code)
-
- def getMatch(self):
- return self.match
-
-
-
-# scans for lines containing keyword, and then runs the visitor over
-# the parsed AST for that line
-def scanScopeAST(scope,keyword,matchfinder):
- lines = scope.generateLinesNotIncludingThoseBelongingToChildScopes()
- match = None
- for line,linenum in generateLogicalLinesAndLineNumbers(lines):
- if isWordInLine(keyword, line):
- doctoredline = makeLineParseable(line)
- ast = compiler.parse(doctoredline)
- matchfinder.reset(line)
- match = visitor.walk(ast,matchfinder).getMatch()
- if match is not None:
- column,yoffset = indexToCoordinates(line,match)
- m = createMatch(scope,linenum + yoffset,column)
- return m
- return None
-
-def createMatch(scope,lineno,x):
- m = Match()
- m.sourcenode = scope.module.getSourceNode()
- m.filename = m.sourcenode.filename
- m.lineno = lineno
- m.colno = x
- m.confidence = 100
- return m
-
-# scan for methods globally (from perspective of 'perspectiveFilename')
-def scanPythonPathForMatchingMethodNames(name, contextFilename):
- class MethodFinder:
- def __init__(self,srcnode):
- self.matches = []
- self.srcnode = srcnode
- def visitFunction(self,node):
- node = getScopeForLine(self.srcnode, self.lineno)
- if isinstance(node.getParent(),Class):
- if node.name == name:
- self.matches.append(convertNodeToMatchObject(node,50))
-
- for srcnode in getSourceNodesContainingRegex(name,contextFilename):
- m = MethodFinder(srcnode)
- walkLinesContainingStrings(srcnode.fastparseroot,m,[name])
- for match in m.matches:
- yield match
-
-
-def getIndexOfWord(line,targetword):
- words = re.split("(\w+)", line)
- idx = 0
- for word in words:
- if word == targetword:
- break
- idx += len(word)
- return idx
-
-
--- a/vim/sadness/bike/bike/query/findReferences.py Thu Feb 10 17:11:26 2011 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,224 +0,0 @@
-from __future__ import generators
-from bike.globals import *
-from bike.parsing.fastparserast import Module, Class, Function, getRoot, Instance
-from bike.query.common import Match, MatchFinder,\
- getScopeForLine, indexToCoordinates, \
- translateSourceCoordsIntoASTNode, scanScopeForMatches,\
- globalScanForMatches, isAMethod, convertNodeToMatchObject
-from compiler.ast import AssName,Name,Getattr,AssAttr
-import compiler
-from findDefinition import findDefinitionFromASTNode
-from bike.query.getTypeOf import getTypeOfExpr, UnfoundType
-from bike.query.relationships import getRootClassesOfHierarchy
-from bike import log
-from bike.parsing.load import getSourceNode
-
-
-class CouldntFindDefinitionException(Exception):
- pass
-
-def findReferencesIncludingDefn(filename,lineno,col):
- return findReferences(filename,lineno,col,1)
-
-
-def findReferences(filename,lineno,col,includeDefn=0):
- sourcenode = getSourceNode(filename)
- node = translateSourceCoordsIntoASTNode(filename,lineno,col)
- assert node is not None
- scope,defnmatch = getDefinitionAndScope(sourcenode,lineno,node)
-
- try:
- for match in findReferencesIncludingDefn_impl(sourcenode,node,
- scope,defnmatch):
- if not includeDefn and match == defnmatch:
- continue # don't return definition
- else:
- yield match
- except CouldntFindDefinitionException:
- raise CouldntFindDefinitionException("Could not find definition. Please locate manually (maybe using find definition) and find references from that")
-
-def findReferencesIncludingDefn_impl(sourcenode,node,scope,defnmatch):
- if isinstance(node,Name) or isinstance(node,AssName):
- return generateRefsToName(node.name,scope,sourcenode,defnmatch)
- elif isinstance(node,Getattr) or isinstance(node,AssAttr):
- exprtype = getTypeOfExpr(scope,node.expr)
- if exprtype is None or isinstance(exprtype,UnfoundType):
- raise CouldntFindDefinitionException()
-
- if isinstance(exprtype,Instance):
- exprtype = exprtype.getType()
- return generateRefsToAttribute(exprtype,node.attrname)
-
- else:
- targetname = node.attrname
- return globalScanForMatches(sourcenode.filename,
- NameRefFinder(targetname, defnmatch),
- targetname, )
- if match is not None:
- return match
- elif isinstance(node,compiler.ast.Function) or \
- isinstance(node,compiler.ast.Class):
- return handleClassOrFunctionRefs(scope, node, defnmatch)
- else:
- assert 0,"Seed to references must be Name,Getattr,Function or Class"
-
-def handleClassOrFunctionRefs(scope, node, defnmatch):
- if isAMethod(scope,node):
- for ref in generateRefsToAttribute(scope,node.name):
- yield ref
- else:
- #yield convertNodeToMatchObject(node,100)
- yield defnmatch
- for ref in generateRefsToName(node.name,scope,
- scope.module.getSourceNode(),
- defnmatch):
- yield ref
-
-def getDefinitionAndScope(sourcenode,lineno,node):
- scope = getScopeForLine(sourcenode,lineno)
- if scope.getStartLine() == lineno and \
- scope.matchesCompilerNode(node): # scope is the node
- return scope.getParent(), convertNodeToMatchObject(scope,100)
- defnmatch = findDefinitionFromASTNode(scope,node)
- if defnmatch is None:
- raise CouldntFindDefinitionException()
- scope = getScopeForLine(sourcenode,defnmatch.lineno)
- return scope,defnmatch
-
-def generateRefsToName(name,scope,sourcenode,defnmatch):
- assert scope is not None
- if isinstance(scope,Function):
- # search can be limited to scope
- return scanScopeForMatches(sourcenode,scope,
- NameRefFinder(name,defnmatch),
- name)
- else:
- return globalScanForMatches(sourcenode.filename,
- NameRefFinder(name,defnmatch),
- name)
-
-
-class NameRefFinder(MatchFinder):
- def __init__(self, targetstr,targetMatch):
- self.targetstr = targetstr
- self.targetMatch = targetMatch
-
- def visitName(self, node):
- if node.name == self.targetstr:
- potentualMatch = findDefinitionFromASTNode(self.scope, node)
- if potentualMatch is not None and \
- potentualMatch == self.targetMatch:
- self.appendMatch(node.name)
- self.popWordsUpTo(node.name)
-
- visitAssName = visitName
-
- def visitFunction(self, node):
- self.popWordsUpTo(node.name)
- for arg, default in self.zipArgs(node.argnames, node.defaults):
- if arg == self.targetstr:
- self.appendMatch(arg)
- self.popWordsUpTo(arg)
- if default is not None:
- self.visit(default)
- self.visit(node.code)
-
-
- def visitFrom(self, node):
- for elem in node.modname.split("."):
- self.popWordsUpTo(elem)
-
- for name, alias in node.names:
- if name == self.targetstr:
- if alias is not None:
- pretendNode = Name(alias)
- else:
- pretendNode = Name(name)
- if findDefinitionFromASTNode(self.scope, pretendNode) \
- == self.targetMatch:
- self.appendMatch(name)
- self.popWordsUpTo(name)
- if alias is not None:
- self.popWordsUpTo(alias)
-
-
- def visitGetattr(self, node):
- for c in node.getChildNodes():
- self.visit(c)
- if node.attrname == self.targetstr:
- defn = findDefinitionFromASTNode(self.scope, node)
- if defn is not None and defn == self.targetMatch:
- self.appendMatch(node.attrname)
- self.popWordsUpTo(node.attrname)
-
-
- def visitImport(self, node):
- for name, alias in node.names:
- if name.split(".")[-1] == self.targetstr:
- getattr = self.createGetattr(name)
- if findDefinitionFromASTNode(self.scope, getattr) == self.targetMatch:
- self.appendMatch(self.targetstr)
- for nameelem in name.split("."):
- self.popWordsUpTo(nameelem)
- if alias is not None:
- self.popWordsUpTo(alias)
-
-
- def createGetattr(self,fqn):
- node = Name(fqn[0])
- for name in fqn.split(".")[1:]:
- node = Getattr(node,name)
- return node
-
-def generateRefsToAttribute(classobj,attrname):
- rootClasses = getRootClassesOfHierarchy(classobj)
- attrRefFinder = AttrbuteRefFinder(rootClasses,attrname)
- for ref in globalScanForMatches(classobj.filename, attrRefFinder, attrname):
- yield ref
- print >>log.progress,"Done"
-
-
-class AttrbuteRefFinder(MatchFinder):
- def __init__(self,rootClasses,targetAttribute):
- self.rootClasses = rootClasses
- self.targetAttributeName = targetAttribute
-
-
- def visitGetattr(self, node):
- for c in node.getChildNodes():
- self.visit(c)
-
- if node.attrname == self.targetAttributeName:
- exprtype = getTypeOfExpr(self.scope,node.expr)
-
- if isinstance(exprtype,Instance) and \
- self._isAClassInTheSameHierarchy(exprtype.getType()):
- self.appendMatch(self.targetAttributeName)
- elif isinstance(exprtype,UnfoundType) or \
- exprtype is None: # couldn't find type, so not sure
- self.appendMatch(self.targetAttributeName,50)
- else:
- pass # definately not a match
- self.popWordsUpTo(node.attrname)
-
- visitAssAttr = visitGetattr
-
- def visitFunction(self,node): # visit methods
- if node.name == self.targetAttributeName:
- parentScope = self.scope.getParent()
- #print parentScope
- #print self.targetClasses
- if isinstance(parentScope,Class) and \
- self._isAClassInTheSameHierarchy(parentScope):
- self.appendMatch(node.name)
-
- for c in node.getChildNodes():
- self.visit(c)
-
- def _isAClassInTheSameHierarchy(self,classobj):
- #return classobj in self.targetClasses
- targetRootClasses = getRootClassesOfHierarchy(classobj)
- for rootclass in self.rootClasses:
- if rootclass in targetRootClasses:
- return True
- return False
--- a/vim/sadness/bike/bike/query/getAllRelatedClasses.py Thu Feb 10 17:11:26 2011 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,47 +0,0 @@
-
-
-"""
-
-def getAllRelatedClasses(root,classfqn):
- classobj = getTypeOf(root,classfqn)
- rootClasses = _getRootClasses(classobj)
- #print rootClasses
- relatedClasses = [] + rootClasses
- for rootClass in rootClasses:
- relatedClasses += _getAllSubClasses(rootClass,root)
- return relatedClasses
-
-def _getRootClasses(klass):
- if klass is None: # i.e. dont have base class in our ast
- return None
- if klass.getBaseClassNames() == []: # i.e. is a root class
- return[klass]
- else:
- rootclasses = []
- for base in klass.getBaseClassNames():
- baseclass = getTypeOf(klass,base)
- rootclass = _getRootClasses(baseclass)
- if rootclass is None: # base class not in our ast
- rootclass = [klass]
- rootclasses+=rootclass
- return rootclasses
-
-
-def _getAllSubClasses(baseclass, root, subclasses = []):
- class ClassVisitor:
- def visitSource(self,node):
- self.visit(node.fastparseroot)
-
- def visitClass(self, node):
- for basename in node.getBaseClassNames():
- if basename.find(baseclass.name) != -1 and \
- getTypeOf(node,basename) == baseclass:
- subclasses.append(node)
- _getAllSubClasses(node,root,subclasses)
- for child in node.getChildNodes():
- self.visit(child)
-
- walk(root, ClassVisitor())
- return subclasses
-
-"""
--- a/vim/sadness/bike/bike/query/getPackageDependencies.py Thu Feb 10 17:11:26 2011 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,6 +0,0 @@
-#!/usr/bin/env python
-
-# fileInPackage is the filename of a file in the package hierarchy
-def getPackageDependencies(fileInPackage):
-
-
--- a/vim/sadness/bike/bike/query/getReferencesToModule.py Thu Feb 10 17:11:26 2011 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,62 +0,0 @@
-from __future__ import generators
-from bike.query.common import Match, globalScanForMatches, getScopeForLine, MatchFinder
-from getTypeOf import getTypeOf, getTypeOfExpr
-import compiler
-import re
-
-def getReferencesToModule(root, fqn):
-
- modulename = fqn.split(".")[-1]
- moduleobj = getTypeOf(root, fqn)
- moduleRefFinder = ModuleRefFinder(moduleobj)
-
- for ref in globalScanForMatches(moduleRefFinder, modulename):
- yield ref
-
-
-class ModuleRefFinder(MatchFinder):
- def __init__(self, targetmodule):
- self.targetmodule = targetmodule
-
- def visitName(self, node):
- if node.name == self.targetmodule.name:
- if getTypeOfExpr(self.scope, node) == self.targetmodule:
- self.appendMatch(node.name)
- self.popWordsUpTo(node.name)
-
- def visitImport(self, node):
- for name, alias in node.names:
- if name.split(".")[-1] == self.targetmodule.name:
- if getTypeOf(self.scope, name) == self.targetmodule:
- self.appendMatch(self.targetmodule.name)
- for nameelem in name.split("."):
- self.popWordsUpTo(nameelem)
- if alias is not None:
- self.popWordsUpTo(alias)
-
- def visitGetattr(self, node):
- for c in node.getChildNodes():
- self.visit(c)
- if node.attrname == self.targetmodule.name:
- if getTypeOfExpr(self.scope, node) == self.targetmodule:
- self.appendMatch(self.targetmodule.name)
- self.popWordsUpTo(node.attrname)
-
- def visitFrom(self, node):
- for elem in node.modname.split("."):
- if elem == self.targetmodule.name:
- getTypeOf(self.scope, elem) == self.targetmodule
- self.appendMatch(self.targetmodule.name)
- self.popWordsUpTo(elem)
-
- for name, alias in node.names:
- if name == self.targetmodule.name:
- if alias and \
- getTypeOf(self.scope, alias) == self.targetmodule:
- self.appendMatch(self.targetmodule.name)
- elif getTypeOf(self.scope, name) == self.targetmodule:
- self.appendMatch(self.targetmodule.name)
- if name != "*":
- self.popWordsUpTo(name)
- if alias is not None:
- self.popWordsUpTo(alias)
--- a/vim/sadness/bike/bike/query/getTypeOf.py Thu Feb 10 17:11:26 2011 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,377 +0,0 @@
-# getTypeOf(scope,fqn) and getTypeOfExpr(scope,ast)
-
-from bike.parsing.fastparserast import Class, Function, Module, Root, getRoot, Package, Instance, getModule
-from bike.parsing.parserutils import generateLogicalLines, makeLineParseable,splitLogicalLines, makeLineParseable
-from bike.parsing import visitor
-from bike import log
-from bike.parsing.newstuff import getModuleOrPackageUsingFQN
-from bike.parsing.pathutils import getPackageBaseDirectory
-from bike.parsing.load import Cache
-import os
-import re
-import compiler
-
-# used if an assignment exists, but cant find type
-# e.g. a = SomeFunctionNotLoaded()
-# (as opposed to 'None' if cant find an assignment)
-class UnfoundType: pass
-
-
-getTypeOfStack = []
-
-# name is the fqn of the reference, scope is the scope ast object from
-# which the question is being asked.
-# returns an fastparser-ast object representing the type
-# or None if type not found
-def getTypeOf(scope, fqn):
- if isinstance(scope, Root):
- assert False, "Can't use getTypeOf to resolve from Root. Use getModuleOrPackageUsingFQN instead"
-
-
- #print "getTypeOf:"+fqn+" -- "+str(scope)
- #print
- #print str(getTypeOfStack)
- #print
- if (fqn,scope) in getTypeOfStack: # loop protection
- return None
-
- # this is crap!
- hashcode = str(scope)+fqn
-
- try:
- getTypeOfStack.append((fqn,scope))
-
- try:
- type = Cache.instance.typecache[hashcode]
- except KeyError:
- type = getTypeOf_impl(scope, fqn)
- Cache.instance.typecache[hashcode] = type
- return type
- finally:
- del getTypeOfStack[-1]
-
-
-
-def getTypeOf_impl(scope, fqn):
- #print "getTypeOf_impl",scope,fqn
- if fqn == "None":
- return None
-
- if "."in fqn:
- rcdr = ".".join(fqn.split(".")[:-1])
- rcar = fqn.split(".")[-1]
- newscope = getTypeOf(scope,rcdr)
- if newscope is not None:
- return getTypeOf(newscope, rcar)
- else:
- #print "couldnt find "+rcdr+" in "+str(scope)
- pass
-
- assert scope is not None
- #assert not ("." in fqn)
-
- if isinstance(scope,UnfoundType):
- return UnfoundType()
-
- if isinstance(scope, Package):
- #assert 0,scope
- return handlePackageScope(scope, fqn)
- elif isinstance(scope,Instance):
- return handleClassInstanceAttribute(scope, fqn)
- else:
- return handleModuleClassOrFunctionScope(scope,fqn)
-
-
-
-def handleModuleClassOrFunctionScope(scope,name):
- if name == "self" and isinstance(scope,Function) and \
- isinstance(scope.getParent(),Class):
- return Instance(scope.getParent())
-
- matches = [c for c in scope.getChildNodes()if c.name == name]
- if matches != []:
- return matches[0]
-
- type = scanScopeSourceForType(scope, name)
- if type != None:
- return type
-
- #print "name = ",name,"scope = ",scope
- type = getImportedType(scope, name) # try imported types
- #print "type=",type
- if type != None:
- return type
- parentScope = scope.getParent()
- while isinstance(parentScope,Class):
- # don't search class scope, since this is not accessible except
- # through self (is this true?)
- parentScope = parentScope.getParent()
-
- if not (isinstance(parentScope,Package) or isinstance(parentScope,Root)):
- return getTypeOf(parentScope, name)
-
-
-def handleClassInstanceAttribute(instance, attrname):
- theClass = instance.getType()
-
- # search methods and inner classes
- match = theClass.getChild(attrname)
- if match:
- return match
-
- #search methods for assignments with self.foo getattrs
- for child in theClass.getChildNodes():
- if not isinstance(child,Function):
- continue
- res = scanScopeAST(child,attrname,
- SelfAttributeAssignmentVisitor(child,attrname))
- if res is not None:
- return res
-
-def handlePackageScope(package, fqn):
- #print "handlePackageScope",package,fqn
- child = package.getChild(fqn)
- if child:
- return child
-
- if isinstance(package,Root):
- return getModuleOrPackageUsingFQN(fqn)
-
- # try searching the fs
- node = getModuleOrPackageUsingFQN(fqn,package.path)
- if node:
- return node
-
-
-
-
- # try the package init module
- initmod = package.getChild("__init__")
- if initmod is not None:
- type = getImportedType(initmod, fqn)
- if type:
- return type
- # maybe fqn is absolute
- return getTypeOf(getRoot(), fqn)
-
-
-wordRE = re.compile("\w+")
-def isWordInLine(word, line):
- if line.find(word) != -1:
- words = wordRE.findall(line)
- if word in words:
- return 1
- return 0
-
-def getImportedType(scope, fqn):
- lines = scope.module.getSourceNode().getLines()
- for lineno in scope.getImportLineNumbers():
- logicalline = generateLogicalLines(lines[lineno-1:]).next()
- logicalline = makeLineParseable(logicalline)
- ast = compiler.parse(logicalline)
- match = visitor.walk(ast, ImportVisitor(scope,fqn)).match
- if match:
- return match
- #else loop
-
-class ImportVisitor:
- def __init__(self,scope,fqn):
- self.match = None
- self.targetfqn = fqn
- self.scope = scope
-
- def visitImport(self, node):
- # if target fqn is an import, then it must be a module or package
- for name, alias in node.names:
- if name == self.targetfqn:
- self.match = resolveImportedModuleOrPackage(self.scope,name)
- elif alias is not None and alias == self.targetfqn:
- self.match = resolveImportedModuleOrPackage(self.scope,name)
-
- def visitFrom(self, node):
- if node.names[0][0] == '*': # e.g. from foo import *
- if not "."in self.targetfqn:
- module = resolveImportedModuleOrPackage(self.scope,
- node.modname)
- if module:
- self.match = getTypeOf(module, self.targetfqn)
- else:
- for name, alias in node.names:
- if alias == self.targetfqn or \
- (alias is None and name == self.targetfqn):
- scope = resolveImportedModuleOrPackage(self.scope,
- node.modname)
- if scope is not None:
- if isinstance(scope,Package):
- self.match = getModuleOrPackageUsingFQN(name,scope.path)
- else:
- assert isinstance(scope,Module)
- self.match = getTypeOf(scope, name)
-
-
-
-
-class TypeNotSupportedException:
- def __init__(self,msg):
- self.msg = msg
-
- def __str__(self):
- return self.msg
-
-# attempts to evaluate the type of the expression
-def getTypeOfExpr(scope, ast):
- if isinstance(ast, compiler.ast.Name):
- return getTypeOf(scope, ast.name)
-
- elif isinstance(ast, compiler.ast.Getattr) or \
- isinstance(ast, compiler.ast.AssAttr):
-
- # need to do this in order to match foo.bah.baz as
- # a string in import statements
- fqn = attemptToConvertGetattrToFqn(ast)
- if fqn is not None:
- return getTypeOf(scope,fqn)
-
- expr = getTypeOfExpr(scope, ast.expr)
- if expr is not None:
- attrnametype = getTypeOf(expr, ast.attrname)
- return attrnametype
- return None
-
- elif isinstance(ast, compiler.ast.CallFunc):
- node = getTypeOfExpr(scope,ast.node)
- if isinstance(node,Class):
- return Instance(node)
- elif isinstance(node,Function):
- return getReturnTypeOfFunction(node)
- else:
- #raise TypeNotSupportedException, \
- # "Evaluation of "+str(ast)+" not supported. scope="+str(scope)
- print >> log.warning, "Evaluation of "+str(ast)+" not supported. scope="+str(scope)
- return None
-
-
-def attemptToConvertGetattrToFqn(ast):
- fqn = ast.attrname
- ast = ast.expr
- while isinstance(ast,compiler.ast.Getattr):
- fqn = ast.attrname + "." + fqn
- ast = ast.expr
- if isinstance(ast,compiler.ast.Name):
- return ast.name + "." + fqn
- else:
- return None
-
-
-getReturnTypeOfFunction_stack = []
-def getReturnTypeOfFunction(function):
- if function in getReturnTypeOfFunction_stack: # loop protection
- return None
- try:
- getReturnTypeOfFunction_stack.append(function)
- return getReturnTypeOfFunction_impl(function)
- finally:
- del getReturnTypeOfFunction_stack[-1]
-
-def getReturnTypeOfFunction_impl(function):
- return scanScopeAST(function,"return",ReturnTypeVisitor(function))
-
-
-# does parse of scope sourcecode to deduce type
-def scanScopeSourceForType(scope, name):
- return scanScopeAST(scope,name,AssignmentVisitor(scope,name))
-
-
-# scans for lines containing keyword, and then runs the visitor over
-# the parsed AST for that line
-def scanScopeAST(scope,keyword,astvisitor):
- lines = scope.getLinesNotIncludingThoseBelongingToChildScopes()
- src = ''.join(lines)
- match = None
- #print "scanScopeAST:"+str(scope)
- for line in splitLogicalLines(src):
- if isWordInLine(keyword, line):
- #print "scanning for "+keyword+" in line:"+line[:-1]
- doctoredline = makeLineParseable(line)
- ast = compiler.parse(doctoredline)
- match = visitor.walk(ast,astvisitor).getMatch()
- if match:
- return match
- return match
-
-
-class AssignmentVisitor:
- def __init__(self,scope,targetName):
- self.match=None
- self.scope = scope
- self.targetName = targetName
-
- def getMatch(self):
- return self.match
-
- def visitAssign(self,node):
- if isinstance(node.expr,compiler.ast.CallFunc):
- for assnode in node.nodes:
- if isinstance(assnode,compiler.ast.AssName) and \
- assnode.name == self.targetName:
- self.match = getTypeOfExpr(self.scope,node.expr)
- if self.match is None:
- self.match = UnfoundType()
-
-
-
-class SelfAttributeAssignmentVisitor:
- def __init__(self,scope,targetName):
- self.match=None
- self.scope = scope
- self.targetName = targetName
-
- def getMatch(self):
- return self.match
-
- def visitAssign(self,node):
- if isinstance(node.expr,compiler.ast.CallFunc):
- for assnode in node.nodes:
- if isinstance(assnode,compiler.ast.AssAttr) and \
- isinstance(assnode.expr,compiler.ast.Name) and \
- assnode.expr.name == "self" and \
- assnode.attrname == self.targetName:
- self.match = getTypeOfExpr(self.scope,node.expr)
- #print "here!",self.match.getType().fqn
-
-
-class ReturnTypeVisitor:
- def __init__(self,fn):
- self.match=None
- self.fn = fn
-
- def getMatch(self):
- return self.match
-
- def visitReturn(self,node):
- try:
- self.match = getTypeOfExpr(self.fn,node.value)
- except TypeNotSupportedException, ex:
- pass
-
-
-def resolveImportedModuleOrPackage(scope,fqn):
- # try searching from directory containing scope module
- path = os.path.dirname(scope.module.filename)
- node = getModuleOrPackageUsingFQN(fqn,path)
- if node is not None:
- return node
-
- # try searching in same package hierarchy
- basedir = getPackageBaseDirectory(scope.module.filename)
- if fqn.split('.')[0] == os.path.split(basedir)[-1]:
- # base package in fqn matches base directory
- restOfFqn = ".".join(fqn.split('.')[1:])
- node = getModuleOrPackageUsingFQN(restOfFqn,basedir)
- if node is not None:
- return node
-
- # try searching the python path
- node = getModuleOrPackageUsingFQN(fqn)
- if node is not None:
- return node
--- a/vim/sadness/bike/bike/query/relationships.py Thu Feb 10 17:11:26 2011 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,26 +0,0 @@
-# queries to do with module/class/function relationships
-from __future__ import generators
-from bike.globals import *
-from getTypeOf import getTypeOf, getTypeOfExpr
-from bike.parsing.newstuff import generateModuleFilenamesInPythonPath, generateModuleFilenamesInPackage, getPythonPath
-from bike.parsing.pathutils import getPackageBaseDirectory
-from bike.query.common import MatchFinder, walkLinesContainingStrings, getScopeForLine
-from bike import log
-from bike.parsing.fastparserast import Module
-import re
-
-def getRootClassesOfHierarchy(klass):
- if klass is None: # i.e. dont have base class in our ast
- return None
- if klass.getBaseClassNames() == []: # i.e. is a root class
- return [klass]
- else:
- rootclasses = []
- for base in klass.getBaseClassNames():
- baseclass = getTypeOf(klass,base)
- rootclass = getRootClassesOfHierarchy(baseclass)
- if rootclass is None: # base class not in our ast
- rootclass = [klass]
- rootclasses+=rootclass
- return rootclasses
-
--- a/vim/sadness/bike/bike/query/setpath.py Thu Feb 10 17:11:26 2011 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,5 +0,0 @@
-import sys,os
-if not os.path.abspath("..") in sys.path:
- from bike import log
- print >> log.warning, "Appending to the system path. This should only happen in unit tests"
- sys.path.append(os.path.abspath(".."))
--- a/vim/sadness/bike/bike/query/test_common.py Thu Feb 10 17:11:26 2011 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,122 +0,0 @@
-#!/usr/bin/env python
-import setpath
-import unittest
-import os
-import compiler
-from bike.testutils import *
-from bike.parsing.load import getSourceNode
-from bike.parsing.fastparser import fastparser
-from bike.parsing.fastparserast import Module, Class
-from common import indexToCoordinates, getScopeForLine, walkLinesContainingStrings, translateSourceCoordsIntoASTNode
-
-
-class TestGetScopeForLine(BRMTestCase):
-
- def test_worksWithFunctionScope(self):
- src = trimLines("""
- class a:
- def foo():
- pass
- """)
- node = createAST(src)
- self.assertEqual(getScopeForLine(node,3).name,"foo")
-
- def test_worksWithModuleScope(self):
- src = trimLines("""
- class TheClass:
- pass
- a = TheClass()
- """)
- node = createAST(src)
- assert isinstance(getScopeForLine(node,3),Module)
-
- def test_worksWithInlineClass(self):
- src = trimLines("""
- class TheClass: pass""")
- node = createAST(src)
- assert isinstance(getScopeForLine(node,1),Class)
-
-
-class TestIndexToCoordinates(BRMTestCase):
-
- def test_worksOnSingleLineString(self):
- src = trimLines('''
- foo bah
- ''')
- x,y = indexToCoordinates(src,src.index("bah"))
- self.assertEqual(x,4)
- self.assertEqual(y,0)
- x,y = indexToCoordinates(src,src.index("foo"))
- self.assertEqual(x,0)
- self.assertEqual(y,0)
-
- def test_worksOnMultilLineString(self):
- src = trimLines('''
- foo bah
- baz boh
- ''')
- x,y = indexToCoordinates(src,src.index("boh"))
- self.assertEqual(x,4)
- self.assertEqual(y,1)
-
-
-class TestTranslateSourceCoordsIntoASTNode(BRMTestCase):
-
- def test_worksOnImport(self):
- src = trimLines('''
- from foo import bar, baz
- ''')
- createSourceNodeAt(src,"mymodule")
- filename = os.path.abspath("mymodule.py")
- node = translateSourceCoordsIntoASTNode(filename, 1, 17)
- assert node.name == 'bar'
-
- def test_worksOnMultiline(self):
- src = trimLines("""
- def foo(x,
- y,
- z):
- return x*y*z
- """)
- createSourceNodeAt(src,"mymodule")
- filename = os.path.abspath("mymodule.py")
- node = translateSourceCoordsIntoASTNode(filename, 3, 8)
- assert node.name == 'z'
-
-
-
-
-class TestMatchFinder(BRMTestCase):
-
- def test_visitLambda(self):
- from common import MatchFinder
- finder = MatchFinder()
- src = '''x = lambda a, b, c=None, d=None: (a + b) and c or d'''
- ast = compiler.parse(src)
- finder.reset(src)
- compiler.walk(ast, finder)
-
-
-class TestWalkLinesContainingStrings(BRMTestCase):
- def test_walksClasses(self):
- src=trimLines("""
- class TestClass(a,
- baseclass):
- pass
- """)
- class MyWalker:
- def visitClass(self, node):
- self.basenames = []
- for name in node.bases:
- self.basenames.append(name.name)
-
- writeTmpTestFile(src)
- srcnode = getSourceNode(tmpfile)
- walker = MyWalker()
- walkLinesContainingStrings(srcnode.fastparseroot,walker,
- "baseclass")
- self.assertEqual(["a","baseclass"],walker.basenames)
-
-
-if __name__ == "__main__":
- unittest.main()
--- a/vim/sadness/bike/bike/query/test_findDefinition.py Thu Feb 10 17:11:26 2011 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,632 +0,0 @@
-#!/usr/bin/env python
-import setpath
-import unittest
-import os
-
-from bike import testdata
-from bike.query.findDefinition import findAllPossibleDefinitionsByCoords
-from bike.query.getTypeOf import getTypeOf,resolveImportedModuleOrPackage
-from bike.parsing.newstuff import getModuleOrPackageUsingFQN
-from bike.parsing.fastparserast import getRoot
-from bike.testutils import *
-
-class TestFindDefinitionByCoords(BRMTestCase):
-
- def test_findsClassRef(self):
- src=trimLines("""
- class TheClass:
- pass
- a = TheClass()
- """)
- createSourceNodeAt(src,"mymodule")
- defn = [x for x in findAllPossibleDefinitionsByCoords(os.path.abspath("mymodule.py"),3,6)]
- assert defn[0].filename == os.path.abspath("mymodule.py")
- assert defn[0].lineno == 1
- assert defn[0].colno == 6
- assert defn[0].confidence == 100
-
- def tests_findsMethodRef(self):
- src=trimLines("""
- class TheClass:
- def theMethod(self):
- pass
- a = TheClass()
- a.theMethod()
- """)
-
- createSourceNodeAt(src,"mymodule")
- defn = [x for x in findAllPossibleDefinitionsByCoords(os.path.abspath("mymodule.py"),5,3)]
-
- assert defn[0].filename == os.path.abspath("mymodule.py")
- assert defn[0].lineno == 2
- assert defn[0].colno == 8
- assert defn[0].confidence == 100
-
-
- def test_returnsOtherMethodsWithSameName(self):
- src=trimLines("""
- class TheClass:
- def theMethod(self):
- pass
- a = SomeOtherClass()
- a.theMethod()
- """)
-
- createSourceNodeAt(src,"mymodule")
- defn = [x for x in findAllPossibleDefinitionsByCoords(os.path.abspath("mymodule.py"),5,3)]
-
- assert defn[0].filename == os.path.abspath("mymodule.py")
- assert defn[0].lineno == 2
- assert defn[0].colno == 8
- assert defn[0].confidence == 50
-
-
-
-
- def test_findsTemporaryDefinition(self):
- src=trimLines("""
- a = 3
- b = a + 1
- """)
- createSourceNodeAt(src,"mymodule")
- defn = [x for x in findAllPossibleDefinitionsByCoords(os.path.abspath("mymodule.py"),2,4)]
- assert defn[0].filename == os.path.abspath("mymodule.py")
- assert defn[0].lineno == 1
- assert defn[0].colno == 0
- assert defn[0].confidence == 100
-
- def test_findsArgumentDefinition(self):
- src=trimLines("""
- def someFunction(a):
- b = a + 1
- """)
- createSourceNodeAt(src,"mymodule")
- defn = [x for x in findAllPossibleDefinitionsByCoords(os.path.abspath("mymodule.py"),2,8)]
- assert defn[0].filename == os.path.abspath("mymodule.py")
- assert defn[0].lineno == 1
- assert defn[0].colno == 17
- assert defn[0].confidence == 100
-
- def test_findsClassInstanceDefinition(self):
- src=trimLines("""
- class TheClass():
- pass
- a = TheClass()
- print a
- """)
- createSourceNodeAt(src,"mymodule")
- defn = [x for x in findAllPossibleDefinitionsByCoords(os.path.abspath("mymodule.py"),4,6)]
- assert defn[0].filename == os.path.abspath("mymodule.py")
- assert defn[0].lineno == 3
- assert defn[0].colno == 0
- assert defn[0].confidence == 100
-
- def test_findsDefinitionInParentScope(self):
- src=trimLines("""
- a = 3
- def foo(self):
- b = a + 1
- """)
- createSourceNodeAt(src,"mymodule")
- defn = [x for x in findAllPossibleDefinitionsByCoords(os.path.abspath("mymodule.py"),3,8)]
- assert defn[0].filename == os.path.abspath("mymodule.py")
- assert defn[0].lineno == 1
- assert defn[0].colno == 0
- assert defn[0].confidence == 100
-
- def test_findsDefinitionWithinFunction(self):
- src=trimLines("""
- def foo(yadda):
- a = someFunction()
- print a
- """)
- createSourceNodeAt(src,"mymodule")
- defn = [x for x in findAllPossibleDefinitionsByCoords(os.path.abspath("mymodule.py"),3,10)]
- assert defn[0].filename == os.path.abspath("mymodule.py")
- assert defn[0].lineno == 2
- assert defn[0].colno == 4
- assert defn[0].confidence == 100
-
-
- def test_findsDefinitionFromSubsequentAssignment(self):
- src=trimLines("""
- def foo(yadda):
- a = 3
- print a
- a = 5
- """)
- createSourceNodeAt(src,"mymodule")
- defn = [x for x in findAllPossibleDefinitionsByCoords(os.path.abspath("mymodule.py"),4,4)]
- assert defn[0].filename == os.path.abspath("mymodule.py")
- assert defn[0].lineno == 2
- assert defn[0].colno == 4
- assert defn[0].confidence == 100
-
- def test_findsDefinitionFromDefinition(self):
- src=trimLines("""
- def foo(yadda):
- a = 3
- print a
- a = 5
- """)
- createSourceNodeAt(src,"mymodule")
- defn = [x for x in findAllPossibleDefinitionsByCoords(os.path.abspath("mymodule.py"),4,4)]
- assert defn[0].filename == os.path.abspath("mymodule.py")
- assert defn[0].lineno == 2
- assert defn[0].colno == 4
- assert defn[0].confidence == 100
-
-
- def test_findsClassRefUsingFromImportStatement(self):
- src=trimLines("""
- from a.b.bah import TheClass
- """)
- classsrc=trimLines("""
- class TheClass:
- pass
- """)
- root = createSourceNodeAt(src,"a.foo")
- root = createSourceNodeAt(classsrc, "a.b.bah")
- module = getModuleOrPackageUsingFQN("a.foo")
- filename = os.path.abspath(os.path.join("a","foo.py"))
- defn = [x for x in findAllPossibleDefinitionsByCoords(filename,1,21)]
- assert defn[0].filename == os.path.abspath(os.path.join("a","b","bah.py"))
- assert defn[0].lineno == 1
- assert defn[0].colno == 6
- assert defn[0].confidence == 100
-
-
- def test_findsVariableRefUsingFromImportStatement(self):
- importsrc=trimLines("""
- from a.b.bah import mytext
- print mytext
- """)
- src=trimLines("""
- mytext = 'hello'
- """)
- root = createSourceNodeAt(importsrc,"a.foo")
- root = createSourceNodeAt(src, "a.b.bah")
- filename = os.path.abspath(os.path.join("a","foo.py"))
- defn = [x for x in findAllPossibleDefinitionsByCoords(filename,2,6)]
- assert defn[0].filename == os.path.abspath(os.path.join("a","b","bah.py"))
- assert defn[0].lineno == 1
- assert defn[0].colno == 0
- assert defn[0].confidence == 100
-
-
- def test_findsVariableRefUsingImportStatement(self):
- importsrc=trimLines("""
- import a.b.bah
- print a.b.bah.mytext
- """)
- src=trimLines("""
- mytext = 'hello'
- """)
- root = createSourceNodeAt(importsrc,"a.foo")
- root = createSourceNodeAt(src, "a.b.bah")
- filename = os.path.abspath(os.path.join("a","foo.py"))
- defn = [x for x in findAllPossibleDefinitionsByCoords(filename,2,14)]
- assert defn[0].filename == os.path.abspath(os.path.join("a","b","bah.py"))
- assert defn[0].lineno == 1
- assert defn[0].colno == 0
- assert defn[0].confidence == 100
-
-
- def test_findsVariableRefUsingFromImportStarStatement(self):
- importsrc=trimLines("""
- from a.b.bah import *
- print mytext
- """)
- src=trimLines("""
- mytext = 'hello'
- """)
- createSourceNodeAt(importsrc,"a.foo")
- createSourceNodeAt(src, "a.b.bah")
- filename = os.path.abspath(os.path.join("a","foo.py"))
- defn = [x for x in findAllPossibleDefinitionsByCoords(filename,2,6)]
- assert defn[0].filename == os.path.abspath(os.path.join("a","b","bah.py"))
- assert defn[0].lineno == 1
- assert defn[0].colno == 0
- assert defn[0].confidence == 100
-
- def test_findsVariableRefUsingFromPackageImportModuleStatement(self):
- importsrc=trimLines("""
- from a.b import bah
- print bah.mytext
- """)
- src=trimLines("""
- mytext = 'hello'
- """)
- root = createSourceNodeAt(importsrc,"a.b.foo")
- root = createSourceNodeAt(src, "a.b.bah")
- filename = os.path.abspath(os.path.join("a","b","foo.py"))
- defn = [x for x in findAllPossibleDefinitionsByCoords(filename,2,10)]
- assert defn[0].filename == os.path.abspath(os.path.join("a","b","bah.py"))
- assert defn[0].lineno == 1
- assert defn[0].colno == 0
- assert defn[0].confidence == 100
-
- def test_findsImportedVariableRefInAFunctionArg(self):
- importsrc=trimLines("""
- from a.b import bah
- someFunction(bah.mytext)
- """)
- src=trimLines("""
- mytext = 'hello'
- """)
- root = createSourceNodeAt(importsrc,"a.b.foo")
- root = createSourceNodeAt(src, "a.b.bah")
- filename = os.path.abspath(os.path.join("a","b","foo.py"))
- defn = [x for x in findAllPossibleDefinitionsByCoords(filename,2,17)]
- assert defn[0].filename == os.path.abspath(os.path.join("a","b","bah.py"))
- assert defn[0].lineno == 1
- assert defn[0].colno == 0
- assert defn[0].confidence == 100
-
-
- def test_findsVariableRefUsingFromImportStatementInFunction(self):
- importsrc=trimLines("""
- def foo:
- from a.b.bah import mytext
- print mytext
- """)
- src=trimLines("""
- mytext = 'hello'
- """)
- root = createSourceNodeAt(importsrc,"a.foo")
- root = createSourceNodeAt(src, "a.b.bah")
- filename = os.path.abspath(os.path.join("a","foo.py"))
- defn = [x for x in findAllPossibleDefinitionsByCoords(filename,3,10)]
- assert defn[0].filename == os.path.abspath(os.path.join("a","b","bah.py"))
- assert defn[0].lineno == 1
- assert defn[0].colno == 0
- assert defn[0].confidence == 100
-
- def test_findsVariableRefByImportingModule(self):
- importsrc=trimLines("""
- import a.b.bah
- print a.b.bah.mytext
- """)
- src=trimLines("""
- mytext = 'hello'
- """)
- defn = self.helper(importsrc, src, 2, 14)
- assert defn[0].filename == pkgstructureFile2
- assert defn[0].lineno == 1
- assert defn[0].colno == 0
- assert defn[0].confidence == 100
-
-
- def test_findsVariableRefByImportingModuleWithFrom(self):
- importsrc=trimLines("""
- from a.b import bah
- someFunction(bah.mytext)
- """)
- src=trimLines("""
- mytext = 'hello'
- """)
-
- defn = self.helper(importsrc, src, 2, 17)
- assert defn[0].filename == pkgstructureFile2
- assert defn[0].lineno == 1
- assert defn[0].colno == 0
- assert defn[0].confidence == 100
-
-
- def helper(self, src, classsrc, line, col):
- try:
- createPackageStructure(src,classsrc)
- filename = pkgstructureFile1
- #Root(None,None,[pkgstructureRootDir])
- defn = [x for x in findAllPossibleDefinitionsByCoords(filename,line,col)]
- finally:
- removePackageStructure()
- return defn
-
- def test_doesntfindVariableRefOfUnimportedModule(self):
- importsrc=trimLines("""
- # a.b.bah not imported
- print a.b.bah.mytext
- """)
- src=trimLines("""
- mytext = 'hello'
- """)
- root = createSourceNodeAt(importsrc,"a.b.foo")
- root = createSourceNodeAt(src, "a.b.bah")
- filename = os.path.abspath(os.path.join("a","b","foo.py"))
- defn = [x for x in findAllPossibleDefinitionsByCoords(filename,2,14)]
- self.assertEqual(defn,[])
-
-
-
- def test_findsSelfAttributeDefinition(self):
- src=trimLines("""
- class MyClass:
- def __init__(self):
- self.a = 'hello'
- def myMethod(self):
- print self.a
- """)
- root = createSourceNodeAt(src,"mymodule")
- filename = os.path.abspath("mymodule.py")
- defn = [x for x in findAllPossibleDefinitionsByCoords(filename,5,18)]
- assert defn[0].filename == os.path.abspath("mymodule.py")
- assert defn[0].lineno == 3
- assert defn[0].colno == 12
- assert defn[0].confidence == 100
-
- def test_findsSelfAttributeDefinitionFromSamePlace(self):
- src=trimLines("""
- class MyClass:
- def __init__(self):
- self.a = 'hello'
- def myMethod(self):
- print self.a
- """)
- root = createSourceNodeAt(src,"mymodule")
- filename = os.path.abspath("mymodule.py")
- defn = [x for x in findAllPossibleDefinitionsByCoords(filename,3,12)]
- assert defn[0].filename == os.path.abspath("mymodule.py")
- assert defn[0].lineno == 3
- assert defn[0].colno == 12
- assert defn[0].confidence == 100
-
-
- def test_findsSelfAttributeDefinition(self):
- src=trimLines("""
- class MyClass:
- def someOtherFn(self):
- pass
- def load(self, source):
- # fastparser ast
- self.fastparseroot = fastparser(source,self.modulename)
- """)
- root = createSourceNodeAt(src,"mymodule")
- filename = os.path.abspath("mymodule.py")
- defn = [x for x in findAllPossibleDefinitionsByCoords(filename,6,14)]
- assert defn[0].filename == os.path.abspath("mymodule.py")
- assert defn[0].lineno == 6
- assert defn[0].colno == 13
- assert defn[0].confidence == 100
-
-
- def test_findsDefnOfInnerClass(self):
- src = trimLines("""
- class TheClass:
- class TheClass:
- pass
- a = TheClass.TheClass()
- """)
- root = createSourceNodeAt(src,"mymodule")
- filename = os.path.abspath("mymodule.py")
- defn = [x for x in findAllPossibleDefinitionsByCoords(filename,4,14)]
- assert defn[0].filename == os.path.abspath("mymodule.py")
- assert defn[0].lineno == 2
- assert defn[0].colno == 10
- assert defn[0].confidence == 100
-
- def test_findsDefnOfOuterClass(self):
- src = trimLines("""
- class TheClass:
- class TheClass:
- pass
- a = TheClass.TheClass()
- """)
- root = createSourceNodeAt(src,"mymodule")
- filename = os.path.abspath("mymodule.py")
- defn = [x for x in findAllPossibleDefinitionsByCoords(filename,4,4)]
- assert defn[0].filename == os.path.abspath("mymodule.py")
- assert defn[0].lineno == 1
- assert defn[0].colno == 6
- assert defn[0].confidence == 100
-
-
- def test_findsClassDeclaredIn__init__Module(self):
- importsrc=trimLines("""
- class TheClass:
- pass
- """)
- src=trimLines("""
- from a import TheClass
- c = TheClass()
- """)
-
-
-
- root = createSourceNodeAt(importsrc,"a.__init__")
- root = createSourceNodeAt(src, "mymodule")
- filename = os.path.abspath("mymodule.py")
- defn = [x for x in findAllPossibleDefinitionsByCoords(filename,2,6)]
- assert defn[0].filename == os.path.abspath(os.path.join("a",
- "__init__.py"))
- assert defn[0].lineno == 1
- assert defn[0].colno == 6
- assert defn[0].confidence == 100
-
-
-class TestFindDefinitionUsingFiles(BRMTestCase):
- def test_findsASimpleDefinitionUsingFiles(self):
- src=trimLines("""
- class TheClass:
- pass
- a = TheClass()
- """)
- writeTmpTestFile(src)
- defn = [x for x in findAllPossibleDefinitionsByCoords(tmpfile,3,6)]
- assert defn[0].filename == tmpfile
- assert defn[0].lineno == 1
- assert defn[0].colno == 6
- assert defn[0].confidence == 100
-
-
- def test_findsDefinitionInAnotherModuleUsingFiles(self):
- src=trimLines("""
- from a.b.bah import TheClass
- """)
- classsrc=trimLines("""
- class TheClass:
- pass
- """)
- defn = self.helper(src, classsrc, 1, 21)
- assert defn[0].filename == pkgstructureFile2
- assert defn[0].lineno == 1
- assert defn[0].colno == 6
- assert defn[0].confidence == 100
-
-
-
- def test_findsDefinitionInAnotherRelativeModuleUsingFiles(self):
- src=trimLines("""
- from b.bah import TheClass
- """)
- classsrc=trimLines("""
- class TheClass:
- pass
- """)
- defn = self.helper(src, classsrc,1,21)
- assert defn[0].filename == pkgstructureFile2
- assert defn[0].lineno == 1
- assert defn[0].colno == 6
- assert defn[0].confidence == 100
-
- def test_findsMethodDefinitionInAnotherModuleUsingFiles(self):
- src=trimLines("""
- from b.bah import TheClass
- a = TheClass()
- a.theMethod()
- """)
- classsrc=trimLines("""
- class TheClass:
- def theMethod(self):
- pass
- """)
- defn = self.helper(src, classsrc, 3, 2)
- assert defn[0].filename == pkgstructureFile2
- assert defn[0].lineno == 2
- assert defn[0].colno == 8
- assert defn[0].confidence == 100
-
- def test_findsDefinitonOfMethodWhenUseIsOnAMultiLine(self):
- classsrc=trimLines("""
- class TheClass:
- def theMethod(self):
- pass
- """)
- src=trimLines("""
- from b.bah import TheClass
- a = TheClass()
- i,j = (32,
- a.theMethod()) # <--- find me!
- something=somethingelse
- """)
- defn = self.helper(src, classsrc, 4, 9)
- assert defn[0].filename == pkgstructureFile2
- assert defn[0].lineno == 2
- assert defn[0].colno == 8
- assert defn[0].confidence == 100
-
-
- def test_findsDefinitionWhenUseIsOnAMultilineAndNextLineBalancesBrace(self):
- classsrc=trimLines("""
- class TheClass:
- def theMethod(self):
- pass
- """)
- src=trimLines("""
- from b.bah import TheClass
- c = TheClass()
- f1, f2 = (c.func1,
- c.theMethod)
- f1, f2 = (c.func1,
- c.theMethod)
- """)
- defn = self.helper(src, classsrc, 4, 10)
- self.assertEqual(pkgstructureFile2,defn[0].filename)
- self.assertEqual(2,defn[0].lineno)
- self.assertEqual(8,defn[0].colno)
- self.assertEqual(100,defn[0].confidence)
-
- def test_worksIfFindingDefnOfRefInSlashMultiline(self):
- classsrc=trimLines("""
- class TheClass:
- def theMethod(self):
- pass
- """)
- src=trimLines("""
- from b.bah import TheClass
- c = TheClass()
- f1, f2 = c.func1 \\
- ,c.theMethod
- """)
- defn = self.helper(src, classsrc, 4, 10)
- self.assertEqual(pkgstructureFile2,defn[0].filename)
- self.assertEqual(2,defn[0].lineno)
- self.assertEqual(8,defn[0].colno)
- self.assertEqual(100,defn[0].confidence)
-
- def test_findsDefnInSameNonPackageDirectory(self):
- try:
- getRoot().pythonpath = [] # clear the python path
- classsrc = trimLines("""
- def testFunction():
- print 'hello'
- """)
- src = trimLines("""
- from baz import testFunction
- """)
- writeTmpTestFile(src)
- newtmpfile = os.path.join(tmproot,"baz.py")
- writeFile(newtmpfile, classsrc)
- refs = [x for x in findAllPossibleDefinitionsByCoords(tmpfile,1,16)]
- assert refs[0].filename == newtmpfile
- assert refs[0].lineno == 1
- finally:
- os.remove(newtmpfile)
- deleteTmpTestFile()
-
-
- def test_findsDefnInPackageSubDirectoryAndRootNotInPath(self):
- src=trimLines("""
- from b.bah import TheClass
- """)
- classsrc=trimLines("""
- class TheClass:
- def theMethod(self):
- pass
- """)
- getRoot().pythonpath = [] # clear the python path
- defn = self.helper(src, classsrc, 1, 18)
- assert defn[0].filename == pkgstructureFile2
- assert defn[0].lineno == 1
- assert defn[0].colno == 6
- assert defn[0].confidence == 100
-
- def test_findsDefnInSamePackageHierarchyAndRootNotInPath(self):
- src=trimLines("""
- from a.b.bah import TheClass
- """)
- classsrc=trimLines("""
- class TheClass:
- def theMethod(self):
- pass
- """)
- getRoot().pythonpath = [] # clear the python path
- defn = self.helper(src, classsrc, 1, 20)
- assert defn[0].filename == pkgstructureFile2
- assert defn[0].lineno == 1
- assert defn[0].colno == 6
- assert defn[0].confidence == 100
-
- def helper(self, src, classsrc, line, col):
- try:
- createPackageStructure(src,classsrc)
- filename = pkgstructureFile1
- #Root(None,None,[pkgstructureRootDir])
- defn = [x for x in findAllPossibleDefinitionsByCoords(filename,line,col)]
- finally:
- removePackageStructure()
- return defn
-
-
-if __name__ == "__main__":
- unittest.main()
--- a/vim/sadness/bike/bike/query/test_findReferences.py Thu Feb 10 17:11:26 2011 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,516 +0,0 @@
-#!/usr/bin/env python
-import setpath
-import unittest
-import os
-from bike import testdata
-from bike.testutils import *
-#from bike.testutils import trimLines, createSourceNodeAt, \
-# createSourceNodeAt_old, BRMTestCase
-from bike import testdata
-from findReferences import findReferences, findReferencesIncludingDefn
-from bike.query.getTypeOf import getTypeOf
-
-class helpers:
- def helper(self,src,lineno,colno):
- writeTmpTestFile(src)
- refs = [x for x in findReferences(tmpfile,lineno,colno)]
- return refs
-
- def helper2(self,src,lineno,colno):
- writeTmpTestFile(src)
- refs = [x for x in findReferencesIncludingDefn(tmpfile,lineno,
- colno)]
- return refs
-
- def helper3(self, src, importedsrc, line, col):
- createPackageStructure(src,importedsrc)
- filename = pkgstructureFile2
- refs = [x for x in findReferences(filename,line,col)
- if x.confidence == 100]
- return refs
-
- def helper4(self, src, importedsrc, line, col):
- createPackageStructure(src,importedsrc)
- filename = pkgstructureFile1
- refs = [x for x in findReferences(filename,line,col)
- if x.confidence == 100]
- return refs
-
-
-
-class TestFindReferences(BRMTestCase,helpers):
- def test_findsSimpleReferencesGivenAssignment(self):
- src=trimLines("""
- def foo():
- a = 3
- print a
- """)
- refs = self.helper(src,3,10)
- assert refs[0].filename == tmpfile
- assert refs[0].lineno == 3
- assert refs[0].colno == 10
- assert refs[0].confidence == 100
-
-
-
- def test_findsSimpleReferencesGivenReference(self):
- src=trimLines("""
- def foo():
- a = 3
- print a
- """)
-
- refs = self.helper2(src,3,10)
- assert refs[0].filename == tmpfile
- assert refs[0].lineno == 2
- assert refs[0].colno == 4
- assert refs[0].confidence == 100
-
-
- def test_findsReferencesToOtherAssignments(self):
- src=trimLines("""
- def foo():
- a = 3
- a = 4
- """)
- refs = self.helper(src,2,4)
- assert refs[0].filename == tmpfile
- assert refs[0].lineno == 3
- assert refs[0].colno == 4
- assert refs[0].confidence == 100
-
- def test_findsFunctionArg(self):
- src=trimLines("""
- def foo(a):
- print a
- """)
- refs = self.helper2(src,2,10)
- assert refs[0].filename == tmpfile
- assert refs[0].lineno == 1
- assert refs[0].colno == 8
- assert refs[0].confidence == 100
-
- def test_findsFunctionArgWithDefault(self):
- src=trimLines("""
- def foo(a=None, b=None):
- print a, b
- """)
- refs = self.helper(src,1,4)
- self.assertEquals(refs, [])
-
- def test_findsFunctionArgWithDefault2(self):
- src=trimLines("""
- def foo(a=None, b=None):
- print a, b
- """)
- refs = self.helper2(src,2,13)
- assert refs[0].filename == tmpfile
- assert refs[0].lineno == 1
- assert refs[0].colno == 16
- assert refs[0].confidence == 100
-
-
- def test_findsReferencesGivenFunctionArg(self):
- src=trimLines("""
- def foo(a):
- print a
- """)
- refs = self.helper(src,1,8)
- assert refs[0].filename == tmpfile
- assert refs[0].lineno == 2
- assert refs[0].colno == 10
- assert refs[0].confidence == 100
-
-
- def test_findsVariableRefInImportStatementUsingFromImportStatement(self):
- importsrc=trimLines("""
- from a.b.bah import mytext
- """)
- src=trimLines("""
- mytext = 'hello'
- """)
- refs = self.helper3(importsrc,src,1,1)
- assert refs[0].filename == pkgstructureFile1
- assert refs[0].lineno == 1
- assert refs[0].colno == 20
- assert refs[0].confidence == 100
-
-
-
- def test_findsVariableRefUsingFromImportStatement(self):
- importsrc=trimLines("""
- from a.b.bah import mytext
- print mytext
- """)
- src=trimLines("""
- mytext = 'hello'
- """)
- refs = self.helper3(importsrc,src,1,1)
- assert refs[0].filename == pkgstructureFile1
- assert refs[1].lineno == 2
- assert refs[1].colno == 6
- assert refs[1].confidence == 100
-
- def test_findsImportedVariableRefInAFunctionArg(self):
- importsrc=trimLines("""
- from a.b import bah
- someFunction(bah.mytext)
- """)
- src=trimLines("""
- mytext = 'hello'
- """)
- refs = self.helper3(importsrc,src,1,1)
- assert refs[0].filename == pkgstructureFile1
- assert refs[0].lineno == 2
- assert refs[0].colno == 17
- assert refs[0].confidence == 100
-
- def test_getsReferenceOfSimpleMethodCall(self):
- src = trimLines("""
- from b.bah import TheClass
- a = TheClass()
- a.theMethod()
- """)
-
- refs = self.helper4(src,testdata.TheClass,3,2)
- assert refs[0].filename == pkgstructureFile1
- self.assertEqual(refs[0].lineno,3)
- self.assertEqual(refs[0].colno,2)
-
-
- def test_findsRefToSelfAttribute(self):
- src=trimLines("""
- class MyClass:
- def __init__(self):
- self.a = 'hello'
- def myMethod(self):
- print self.a
- """)
- refs = self.helper(src,3,12)
- assert refs[0].filename == tmpfile
- assert refs[0].lineno == 5
- assert refs[0].colno == 18
- assert refs[0].confidence == 100
-
-
-class FindReferencesToMethod(BRMTestCase,helpers):
- def test_findsReferenceOfSimpleMethodCall(self):
- src = trimLines("""
- from b.bah import TheClass
- a = TheClass()
- a.theMethod()
- """)
- refs = self.helper3(src,testClass,2,8)
- assert refs[0].filename == pkgstructureFile1
- self.assertEqual(refs[0].lineno,3)
- self.assertEqual(refs[0].colno,2)
- self.assertEqual(refs[0].colno,2)
-
- def test_getsReferenceOfMethodCallFromClassImportedWithAlias(self):
- src = trimLines("""
- from b.bah import TheClass as MyTheClass
-
- def foo():
- a = MyTheClass()
- a.theMethod()
- """)
- refs = self.helper3(src,testClass,2,8)
- assert refs[0].filename == pkgstructureFile1
- self.assertEqual(refs[0].lineno,5)
- self.assertEqual(refs[0].colno,6)
-
-
- def test_getsReferenceOfMethodCallWhenInstanceReturnedByFunction(self):
- src = trimLines("""
- from b.bah import TheClass
-
- def foo():
- return TheClass()
- a = foo()
- a.theMethod()
- """)
- refs = self.helper3(src,testClass,2,8)
- assert refs[0].filename == pkgstructureFile1
- self.assertEqual(refs[0].lineno,6)
- self.assertEqual(refs[0].colno,2)
-
- def test_getsReferenceOfMethodCallInSameClass(self):
- src = trimLines("""
- class TheClass:
- def theMethod(self):
- pass
- def anotherMethod(self):
- self.theMethod()
- """)
- refs = self.helper4(src,testClass,2,8)
- assert refs[0].filename == pkgstructureFile1
- self.assertEqual(refs[0].lineno,5)
- self.assertEqual(refs[0].colno,13)
-
- def test_getsReferenceOfMethodOnBaseClassInstance(self):
- src = trimLines("""
- class root:
- def theMethod(self):
- pass
-
- class a(root):
- def theMethod(self):
- pass
-
- class b(root):
- pass
-
- class TheClass(b):
- def theMethod(self):
- pass
-
- rootinstance = root()
- rootinstance.theMethod()
- """)
- refs = self.helper4(src,"pass",2,8)
- self.assertEqual(refs[2].filename,pkgstructureFile1)
- self.assertEqual(refs[2].lineno,17)
- self.assertEqual(refs[2].colno,13)
-
- def test_doesntGetReferenceToMethodWhenObjectCreatedInChildScopeToMethodReference(self):
- src = trimLines("""
- from b.bah import TheClass
- a = AnotherClass()
- def foo():
- a = TheClass()
- a.theMethod()
- """)
- refs = self.helper3(src,testClass,2,8)
- assert refs == []
-
- def test_renamesMethodReferenceOfInstanceCreatedInSubsequentFunction(self):
- src = trimLines("""
- class TheClass:
- def theMethod():
- pass
- class NotTheClass:
- def theMethod():
- pass
-
- def foo():
- a = bah()
- a.theMethod()
-
- def bah():
- return TheClass()
- """)
- refs = self.helper4(src,"pass",2,8)
- self.assertEqual(refs[0].filename,pkgstructureFile1)
- self.assertEqual(refs[0].lineno,10)
- self.assertEqual(refs[0].colno,6)
-
-
- def test_getsReferenceInMiddleOfBiggerCompoundCall(self):
- src = trimLines("""
- class TheClass:
- def theMethod(self): return AnotherClass()
- TheClass().theMethod().anotherMethod()
- """)
-
- refs = self.helper4(src,"pass",2,8)
- self.assertEqual(refs[0].filename,pkgstructureFile1)
- self.assertEqual(refs[0].lineno,3)
- self.assertEqual(refs[0].colno,11)
- self.assertEqual(refs[0].colend,20)
-
- def test_doesntBarfWhenObjectIsArrayMember(self):
- src = trimLines("""
- class TheClass:
- def theMethod(self):
- pass
- a[0] = TheClass()
- a[0].theMethod()
- """)
- refs = self.helper4(src,"pass",2,8)
- # should get to here without exception
-
-class FindReferencesToClass(BRMTestCase, helpers):
- def test_returnsEmptyListIfNoReferences(self):
- src = trimLines("""
- class MyClass:
- pass
- a = TheClass()
- """)
- refs = self.helper4(src,"pass",1,6)
- assert refs == []
-
-
- def test_findsSimpleReferenceInSameModule(self):
- src = trimLines("""
- class TheClass:
- pass
- a = TheClass()
- """)
- refs = self.helper4(src,"pass",1,6)
- self.assertEqual(refs[0].filename,pkgstructureFile1)
- self.assertEqual(refs[0].lineno,3)
- self.assertEqual(refs[0].colno,4)
- self.assertEqual(refs[0].confidence,100)
-
- def test_doesntBarfOnSingleLineSourceWithInlineClass(self):
- src=trimLines("""
- from b.bah import TheClass
- a = TheClass()
- """)
- refs = self.helper3(src,"class TheClass: pass",1,6)
- assert refs != []
-
- def test_findsReferenceToClassImportedInSameClassScope(self):
- src=trimLines("""
- class AnotherClass:
- from b.bah import TheClass
- TheClass.baz = 0
- """)
- refs = self.helper3(src,"class TheClass: pass",1,6)
- self.assertEqual(refs[0].filename,pkgstructureFile1)
- self.assertEqual(refs[0].lineno,2)
- self.assertEqual(refs[0].colno,22)
-
- self.assertEqual(refs[0].filename,pkgstructureFile1)
- self.assertEqual(refs[1].lineno,3)
- self.assertEqual(refs[1].colno,4)
-
- def testFindsClassReferenceWhenScopeIsSameNameAsClass(self):
- src = trimLines("""
- class TheClass:
- class TheClass:
- pass
- a = TheClass.TheClass()
- """)
- refs = self.helper4(src,"pass",2,10)
- self.assertEqual(refs[0].filename,pkgstructureFile1)
- self.assertEqual(refs[0].lineno,4)
- self.assertEqual(refs[0].colno,13)
- self.assertEqual(refs[0].confidence,100)
-
- def testFindsClassReferenceWhenChildIsSameNameAsClass(self):
- src = trimLines("""
- class TheClass:
- class TheClass:
- pass
- a = TheClass.TheClass()
- """)
- refs = self.helper4(src,"pass",1,6)
- self.assertEqual(refs[0].filename,pkgstructureFile1)
- self.assertEqual(refs[0].lineno,4)
- self.assertEqual(refs[0].colno,4)
- self.assertEqual(refs[0].confidence,100)
-
-
-class TestFindReferencesIncludingDefn(BRMTestCase,helpers):
- def test_findsMethodDecl(self):
- src=trimLines("""
- class TheClass:
- def theMethod(self):
- pass
- """)
- refs = self.helper2(src,2,8)
- self.assertEqual(refs[0].filename,tmpfile)
- self.assertEqual(refs[0].lineno,2)
- self.assertEqual(refs[0].colno,8)
- self.assertEqual(refs[0].confidence,100)
-
-
-
-class TestFindReferencesUsingFiles(BRMTestCase):
- def test_findsSimpleReferencesUsingFiles(self):
- src=trimLines("""
- def foo():
- a = 3
- print a
- """)
- refs = self.helper("pass",src,2,4)
- assert refs[0].filename == pkgstructureFile2
- assert refs[0].lineno == 3
- assert refs[0].colno == 10
- assert refs[0].confidence == 100
-
- def test_findsReferenceInModuleWhichImportsClassWithFromAndAlias(self):
- src = trimLines("""
- from b.bah import TheClass as MyTheClass
- def foo():
- a = MyTheClass()
- """)
- refs = self.helper(src,testClass,1,6)
- self.assertEqual(refs[0].filename,pkgstructureFile1)
- self.assertEqual(refs[0].lineno,1)
- self.assertEqual(refs[0].colno,18)
- self.assertEqual(refs[0].confidence,100)
-
-
- def test_doesntBarfWhenCantLocatePackageWhenTryingToFindBaseClass(self):
- src = trimLines("""
- from doesntexist import baseclass
- class foo(baseclass):
- def myMethod(self):
- pass
- """)
- refs = self.helper("",src,3,8)
-
- def test_doesntBarfWhenComesAcrossAPrintNl(self):
- src = trimLines("""
- class TheClass:
- pass
-
- print >>foo, TheClass
- """)
- refs = self.helper("",src,1,6)
-
-
- def test_returnsOtherFilesInSameNonPackageDirectory(self):
- try:
- getRoot().pythonpath = [] # clear the python path
- classsrc = trimLines("""
- def testFunction():
- print 'hello'
- """)
- src = trimLines("""
- from baz import testFunction
- """)
- writeTmpTestFile(src)
- newtmpfile = os.path.join(tmproot,"baz.py")
- writeFile(newtmpfile, classsrc)
- refs = [x for x in findReferences(newtmpfile,1,4)]
-
- assert refs[0].filename == tmpfile
- assert refs[0].lineno == 1
- finally:
- os.remove(newtmpfile)
- deleteTmpTestFile()
-
-
-
-
- def helper(self, src, classsrc, line, col):
- try:
- createPackageStructure(src,classsrc)
- filename = pkgstructureFile2
- refs = [x for x in findReferences(filename,line,col)]
- finally:
- removePackageStructure()
- return refs
-
-
-
-
-testClass = trimLines("""
-class TheClass:
- def theMethod(self):
- pass
- def differentMethod(self):
- pass
-
-class DifferentClass:
- def theMethod(self):
- pass
-""")
-
-
-
-if __name__ == "__main__":
- unittest.main()
--- a/vim/sadness/bike/bike/query/test_getPackageDependencies.py Thu Feb 10 17:11:26 2011 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,10 +0,0 @@
-#!/usr/bin/env python
-import setpath
-import unittest
-import os
-from bike import testdata
-from bike.testutils import *
-
-class TestGetPackageDependencies(BRMTestCase):
- def test_foo(self):
- assert 0
--- a/vim/sadness/bike/bike/query/test_getReferencesToClass.py Thu Feb 10 17:11:26 2011 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,280 +0,0 @@
-#!/usr/bin/env python
-import setpath
-import unittest
-import os
-from bike import testdata
-from bike.testutils import *
-from bike.query.findReferences import findReferences
-from bike.parsing.fastparserast import Module
-
-class TestGetReferencesToClass(BRMTestCase):
- def test_returnsEmptyListIfNoReferences(self):
- src = trimLines("""
- class MyClass:
- pass
- a = TheClass()
- """)
- root = createSourceNodeAt(src,"mymodule")
- refs = [x for x in findReferences(os.path.abspath("mymodule.py"),1,6)]
- self.assertEqual(refs,[])
-
- def test_findsSimpleReferenceInSameModule(self):
- src = trimLines("""
- class TheClass:
- pass
- a = TheClass()
- """)
- root = createSourceNodeAt(src,"mymodule")
- refs = [x for x in findReferences(os.path.abspath("mymodule.py"),1,6)]
- self.assertEqual(refs[0].filename,os.path.abspath("mymodule.py"))
- self.assertEqual(refs[0].lineno,3)
- self.assertEqual(refs[0].colno,4)
- self.assertEqual(refs[0].confidence,100)
-
- def test_findsReferencesInModuleWhichImportsClass(self):
- src = trimLines("""
- import b.bah
- def foo():
- a = b.bah.TheClass()
- a.theMethod()
- """)
- root = createSourceNodeAt(src, "a.foo")
- root = createSourceNodeAt(ClassTestdata, "a.b.bah")
- refs = [x for x in findReferences(os.path.abspath("a/b/bah.py"),1,6)]
-
- self.assertEqual(refs[0].filename,os.path.abspath(os.path.join("a","foo.py")))
- self.assertEqual(refs[0].lineno,3)
- self.assertEqual(refs[0].colno,14)
- self.assertEqual(refs[0].confidence,100)
-
-
- def test_findsReferenceInModuleWhichImportsClassWithFrom(self):
- src = trimLines("""
- from b.bah import TheClass
- def foo():
- a = TheClass()
- a.theMethod()
- """)
-
- root = createSourceNodeAt(src, "a.foo")
- root = createSourceNodeAt(ClassTestdata, "a.b.bah")
-
- filename = os.path.abspath("a/b/bah.py")
- refs = [x for x in findReferences(filename,1,6)]
-
- self.assertEqual(refs[0].filename,os.path.abspath(os.path.join("a","foo.py")))
- self.assertEqual(refs[0].lineno,1)
- self.assertEqual(refs[0].colno,18)
- self.assertEqual(refs[0].confidence,100)
-
- self.assertEqual(refs[1].filename,os.path.abspath(os.path.join("a/foo.py")))
- self.assertEqual(refs[1].lineno,3)
- self.assertEqual(refs[1].colno,8)
- self.assertEqual(refs[1].confidence,100)
-
- def test_findsReferenceToClassImportedInSameClassScope(self):
- src=trimLines("""
- class AnotherClass:
- from b.bah import TheClass
- TheClass.baz = 0
- """)
-
- root = createSourceNodeAt(src, "a.foo")
- root = createSourceNodeAt(ClassTestdata, "a.b.bah")
-
- filename = os.path.abspath("a/b/bah.py")
- refs = [x for x in findReferences(filename,1,6)]
- assert refs != []
-
- def test_findsReferenceInModuleWhichImportsClassWithFromAndAlias(self):
- src = trimLines("""
- from b.bah import TheClass as MyTheClass
- def foo():
- a = MyTheClass()
- a.theMethod()
- """)
-
- root = createSourceNodeAt(src, "a.foo")
- root = createSourceNodeAt(ClassTestdata, "a.b.bah")
- filename = os.path.abspath("a/b/bah.py")
- refs = [x for x in findReferences(filename,1,6)]
-
- self.assertEqual(refs[0].filename,os.path.abspath(os.path.join("a","foo.py")))
- self.assertEqual(refs[0].lineno,1)
- self.assertEqual(refs[0].colno,18)
- self.assertEqual(refs[0].confidence,100)
-
-
- def test_findsReferenceInModuleWhichImportsClassWithImportAs(self):
- src = trimLines("""
- from b.bah import TheClass as MyTheClass
- def foo():
- a = MyTheClass()
- a.theMethod()
- """)
-
- root = createSourceNodeAt(src, "a.foo")
- root = createSourceNodeAt(ClassTestdata, "a.b.bah")
- filename = os.path.abspath("a/b/bah.py")
- refs = [x for x in findReferences(filename,1,6)]
- self.assertEqual(refs[0].filename,os.path.abspath(os.path.join("a","foo.py")))
- self.assertEqual(refs[0].lineno,1)
- self.assertEqual(refs[0].colno,18)
- self.assertEqual(refs[0].confidence,100)
-
- def test_findsReferenceInModuleWhichImportsClassWithFromImportStar(self):
- src = trimLines("""
- from b.bah import *
- a = TheClass()
- a.theMethod()
- """)
-
- root = createSourceNodeAt(src, "a.foo")
- root = createSourceNodeAt(ClassTestdata, "a.b.bah")
- filename = os.path.abspath("a/b/bah.py")
- refs = [x for x in findReferences(filename,1,6)]
- self.assertEqual(refs[0].filename,os.path.abspath(os.path.join("a","foo.py")))
- self.assertEqual(refs[0].lineno,2)
- self.assertEqual(refs[0].colno,4)
- self.assertEqual(refs[0].confidence,100)
-
- def test_findsReferenceInModuleWhichImportsClassWithFromImportStar2(self):
- src = trimLines("""
- from a.b.bah import *
- a = TheClass()
- """)
-
- root = createSourceNodeAt(src, "a.foo")
- root = createSourceNodeAt(ClassTestdata, "a.b.bah")
- filename = os.path.abspath("a/b/bah.py")
- refs = [x for x in findReferences(filename,1,6)]
- self.assertEqual(refs[0].filename,os.path.abspath(os.path.join("a","foo.py")))
- self.assertEqual(refs[0].lineno,2)
- self.assertEqual(refs[0].colno,4)
- self.assertEqual(refs[0].confidence,100)
-
-
- def test_findsClassReferenceInInstanceCreation(self):
- src = trimLines("""
- class TheClass:
- def theMethod(self): pass
- TheClass().theMethod()
- """)
- root = createSourceNodeAt(src, "a.foo")
- filename = os.path.abspath("a/foo.py")
- refs = [x for x in findReferences(filename,1,6)]
- self.assertEqual(refs[0].filename,os.path.abspath(os.path.join("a","foo.py")))
- self.assertEqual(refs[0].lineno,3)
- self.assertEqual(refs[0].colno,0)
- self.assertEqual(refs[0].confidence,100)
-
-
- def test_findsClassReferenceInInstanceCreationWithFQN(self):
- src = trimLines("""
- import b.bah
- def foo():
- a = b.bah.TheClass()
- a.theMethod()
- """)
-
- root = createSourceNodeAt(src, "a.foo")
- root = createSourceNodeAt(ClassTestdata, "a.b.bah")
- filename = os.path.abspath("a/b/bah.py")
- refs = [x for x in findReferences(filename,1,6)]
-
- self.assertEqual(refs[0].filename,os.path.abspath(os.path.join("a","foo.py")))
- self.assertEqual(refs[0].lineno,3)
- self.assertEqual(refs[0].colno,14)
- self.assertEqual(refs[0].confidence,100)
-
- def test_doesntfindReferenceInModuleWhichDoesntImportClass(self):
- src = trimLines("""
- a = TheClass()
- """)
-
- root = createSourceNodeAt(src, "a.foo")
- root = createSourceNodeAt(ClassTestdata, "a.b.bah")
- filename = os.path.abspath("a/b/bah.py")
- refs = [x for x in findReferences(filename,1,6)]
- assert refs == []
-
- def test_findsReferenceInClassBases(self):
- src =trimLines("""
- from b.bah import TheClass
- class DerivedClass(TheClass):
- pass
- """)
-
- root = createSourceNodeAt(src, "a.foo")
- root = createSourceNodeAt(ClassTestdata, "a.b.bah")
- filename = os.path.abspath("a/b/bah.py")
- refs = [x for x in findReferences(filename,1,6)]
- self.assertEqual(refs[1].filename,os.path.abspath(os.path.join("a","foo.py")))
- self.assertEqual(refs[1].lineno,2)
- self.assertEqual(refs[1].colno,19)
- self.assertEqual(refs[1].confidence,100)
-
-
-
- def test_findsReferenceInMultiLineImportStatement(self):
- src =trimLines("""
- from b.bah import foo, \\
- TheFooBah, TheClass, Foobah, SomethingElse
- """)
-
- root = createSourceNodeAt(src, "a.foo")
- root = createSourceNodeAt(ClassTestdata, "a.b.bah")
- filename = os.path.abspath("a/b/bah.py")
- refs = [x for x in findReferences(filename,1,6)]
- self.assertEqual(refs[0].filename,os.path.abspath(os.path.join("a","foo.py")))
- self.assertEqual(refs[0].lineno,2)
- self.assertEqual(refs[0].colno,21)
- self.assertEqual(refs[0].confidence,100)
-
- def test_findsReferenceWhenModulenameSameAsClassMethodName(self):
- # asserts that brm doesnt search class scope after not finding name
- # in method scope (since class scope is invisible unless called on 'self'
- src =trimLines("""
- from a.b import bah
- class baz:
- def bah(self):
- print bah.TheClass
- """)
-
- root = createSourceNodeAt(src, "a.foo")
- root = createSourceNodeAt(ClassTestdata, "a.b.bah")
- filename = os.path.abspath("a/b/bah.py")
- refs = [x for x in findReferences(filename,1,6)]
- self.assertEqual(refs[0].filename,os.path.abspath(os.path.join("a","foo.py")))
- self.assertEqual(refs[0].lineno,4)
- self.assertEqual(refs[0].colno,18)
- self.assertEqual(refs[0].confidence,100)
-
-
- def test_doesntBarfOnFromImportStarWhenNameIsInFromClause(self):
- src = trimLines("""
- from a.b.bah import TheClass
- a = TheClass()
- """)
-
- root = createSourceNodeAt(src, "a.foo")
- root = createSourceNodeAt(ClassTestdata, "a.b.bah")
- filename = os.path.abspath("a/b/bah.py")
- refs = [x for x in findReferences(filename,1,6)]
-
-
-ClassTestdata = trimLines("""
-class TheClass:
- def theMethod(self):
- pass
- def differentMethod(self):
- pass
-
-class DifferentClass:
- def theMethod(self):
- pass
-""")
-
-
-if __name__ == "__main__":
- unittest.main()
--- a/vim/sadness/bike/bike/query/test_getReferencesToMethod.py Thu Feb 10 17:11:26 2011 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,194 +0,0 @@
-#!/usr/bin/env python
-import setpath
-import unittest
-import os
-from bike import testdata
-from bike.testutils import *
-from bike.query.findReferences import findReferences
-from bike.parsing.fastparserast import Module
-
-class TestGetReferencesToMethod(BRMTestCase):
-
- def test_getsReferenceOfSimpleMethodCall(self):
- src = trimLines("""
- from b.bah import TheClass
- a = TheClass()
- a.theMethod()
- """)
- root = createSourceNodeAt(src,"a.foo")
- root = createSourceNodeAt(MethodTestdata, "a.b.bah")
- filename = os.path.abspath("a/b/bah.py")
- refs = [x for x in findReferences(filename,2,8)
- if x.confidence == 100]
- self.assertEqual(refs[0].filename,
- os.path.abspath(os.path.join("a","foo.py")))
- self.assertEqual(refs[0].lineno,3)
- self.assertEqual(refs[0].colno,2)
- self.assertEqual(refs[0].colno,2)
-
- def test_getsReferenceOfMethodCallFromClassImportedWithAlias(self):
- src = trimLines("""
- from b.bah import TheClass as MyTheClass
-
- def foo():
- a = MyTheClass()
- a.theMethod()
- """)
- root = createSourceNodeAt(src,"a.foo")
- root = createSourceNodeAt(MethodTestdata, "a.b.bah")
- filename = os.path.abspath("a/b/bah.py")
- refs = [x for x in findReferences(filename,2,8)
- if x.confidence == 100]
- self.assertEqual(refs[0].filename,
- os.path.abspath(os.path.join("a","foo.py")))
- self.assertEqual(refs[0].lineno,5)
- self.assertEqual(refs[0].colno,6)
-
-
- def test_getsReferenceOfMethodCallWhenInstanceReturnedByFunction(self):
- src = trimLines("""
- from b.bah import TheClass
-
- def foo():
- return TheClass()
- a = foo()
- a.theMethod()
- """)
- root = createSourceNodeAt(src,"a.foo")
- root = createSourceNodeAt(MethodTestdata, "a.b.bah")
- filename = os.path.abspath("a/b/bah.py")
- refs = [x for x in findReferences(filename,2,8)
- if x.confidence == 100]
- self.assertEqual(refs[0].filename,
- os.path.abspath(os.path.join("a","foo.py")))
- self.assertEqual(refs[0].lineno,6)
- self.assertEqual(refs[0].colno,2)
-
- def test_getsReferenceOfMethodCallInSameClass(self):
- src = trimLines("""
- class TheClass:
- def theMethod(self):
- pass
- def anotherMethod(self):
- self.theMethod()
- """)
-
- root = createSourceNodeAt(src,"a.foo")
- filename = os.path.abspath("a/foo.py")
- refs = [x for x in findReferences(filename,2,8)
- if x.confidence == 100]
- self.assertEqual(refs[0].filename,
- os.path.abspath(os.path.join("a","foo.py")))
- self.assertEqual(refs[0].lineno,5)
- self.assertEqual(refs[0].colno,13)
-
- def test_getsReferenceOfMethodOnBaseClassInstance(self):
- src = trimLines("""
- class root:
- def theMethod():
- pass
-
- class a(root):
- def theMethod():
- pass
-
- class b(root):
- pass
-
- class TheClass(b):
- def theMethod(self):
- pass
-
- rootinstance = root()
- rootinstance.theMethod()
- """)
-
- refs =self.helper4(src,"pass",2,8)
- self.assertEqual(refs[2].filename,pkgstructureFile1)
- self.assertEqual(refs[2].lineno,17)
- self.assertEqual(refs[2].colno,13)
-
- def helper4(self, src, importedsrc, line, col):
- try:
- createPackageStructure(src,importedsrc)
- filename = pkgstructureFile1
- refs = [x for x in findReferences(filename,line,col)
- if x.confidence == 100]
- finally:
- removePackageStructure()
- return refs
-
- def test_doesntGetReferenceToMethodWhenObjectCreatedInChildScopeToMethodReference(self):
- src = trimLines("""
- from b.bah import TheClass
- a = AnotherClass()
- def foo():
- a = TheClass()
- a.theMethod()
- """)
- root = createSourceNodeAt(src,"a.foo")
- root = createSourceNodeAt(MethodTestdata, "a.b.bah")
- filename = os.path.abspath("a/b/bah.py")
- refs = [x for x in findReferences(filename,2,8)
- if x.confidence == 100]
- assert len(refs) == 0
-
- def test_renamesMethodReferenceOfInstanceCreatedInSubsequentFunction(self):
- src = trimLines("""
- class TheClass:
- def theMethod():
- pass
- class NotTheClass:
- def theMethod():
- pass
-
- def foo():
- a = bah()
- a.theMethod()
-
- def bah():
- return TheClass()
- """)
- root = createSourceNodeAt(src,"a.foo")
- filename = os.path.abspath("a/foo.py")
- refs = [x for x in findReferences(filename,2,8)
- if x.confidence == 100]
- self.assertEqual(refs[0].filename,
- os.path.abspath(os.path.join("a","foo.py")))
- self.assertEqual(refs[0].lineno,10)
- self.assertEqual(refs[0].colno,6)
-
-
- def test_getsReferenceInMiddleOfBiggerCompoundCall(self):
- src = trimLines("""
- class TheClass:
- def theMethod(self): return AnotherClass()
- TheClass().theMethod().anotherMethod()
- """)
-
- root = createSourceNodeAt(src,"a.foo")
- filename = os.path.abspath("a/foo.py")
- refs = [x for x in findReferences(filename,2,8)
- if x.confidence == 100]
- self.assertEqual(refs[0].filename,
- os.path.abspath(os.path.join("a","foo.py")))
- self.assertEqual(refs[0].lineno,3)
- self.assertEqual(refs[0].colno,11)
- self.assertEqual(refs[0].colend,20)
-
-
-MethodTestdata = trimLines("""
-class TheClass:
- def theMethod(self):
- pass
- def differentMethod(self):
- pass
-
-class DifferentClass:
- def theMethod(self):
- pass
-""")
-
-
-if __name__ == "__main__":
- unittest.main()
--- a/vim/sadness/bike/bike/query/test_getReferencesToModule.py Thu Feb 10 17:11:26 2011 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,179 +0,0 @@
-#!/usr/bin/env python
-import setpath
-import unittest
-import os
-from bike import testdata
-from bike.testutils import *
-from bike.query.getReferencesToModule import *
-from bike.parsing.fastparserast import Module
-
-class TestGetReferencesToModule(BRMTestCase):
-
- def test_returnsEmptyListIfNoReferences(self):
- src = trimLines("""
- class MyClass:
- pass
- a = TheClass()
- """)
- root = createSourceNodeAt(src,"mymodule")
- self.assertEqual([x for x in getReferencesToModule(root,"myothermodule")],[])
-
- def test_findsReferencesInModuleWhichImportsModule(self):
- src = trimLines("""
- import b.bah
- def foo():
- a = b.bah.TheClass()
- a.theMethod()
- """)
-
- root = createSourceNodeAt( src, "a.foo")
- root = createSourceNodeAt( testdata.TheClass, "a.b.bah")
- refs = [x for x in getReferencesToModule(root,"a.b.bah")]
-
-
- self.assertEqual(refs[0].filename,os.path.abspath(os.path.join("a","foo.py")))
- self.assertEqual(refs[0].lineno,1)
- self.assertEqual(refs[0].colno,9)
- self.assertEqual(refs[0].confidence,100)
-
- self.assertEqual(refs[1].filename,os.path.abspath(os.path.join("a","foo.py")))
- self.assertEqual(refs[1].lineno,3)
- self.assertEqual(refs[1].colno,10)
- self.assertEqual(refs[0].confidence,100)
-
- def test_findsReferenceInModuleWhichImportsModuleWithFrom(self):
- src = trimLines("""
- from b import bah
- def foo():
- a = bah.TheClass()
- a.theMethod()
- """)
-
- root = createSourceNodeAt( src, "a.foo")
- root = createSourceNodeAt( testdata.TheClass, "a.b.bah")
- refs = [x for x in getReferencesToModule(root,"a.b.bah")]
-
- self.assertEqual(refs[0].filename,os.path.abspath(os.path.join("a","foo.py")))
- self.assertEqual(refs[0].lineno,1)
- self.assertEqual(refs[0].colno,14)
- self.assertEqual(refs[0].confidence,100)
-
- self.assertEqual(refs[1].filename,os.path.abspath(os.path.join("a/foo.py")))
- self.assertEqual(refs[1].lineno,3)
- self.assertEqual(refs[1].colno,8)
- self.assertEqual(refs[0].confidence,100)
-
- def test_findsReferenceInModuleWhichImportsModuleWithFromAndAlias(self):
- src = trimLines("""
- from b import bah as mymodule
- def foo():
- a = mymodule.MyTheClass()
- a.theMethod()
- """)
-
-
- root = createSourceNodeAt( src, "a.foo")
- root = createSourceNodeAt( testdata.TheClass, "a.b.bah")
- refs = [x for x in getReferencesToModule(root,"a.b.bah")]
-
- self.assertEqual(refs[0].filename,os.path.abspath(os.path.join("a","foo.py")))
- self.assertEqual(refs[0].lineno,1)
- self.assertEqual(refs[0].colno,14)
- self.assertEqual(refs[0].confidence,100)
-
- """ # mymodule.MyTheClass
- self.assertEqual(refs[1].filename,os.path.abspath(os.path.join("a","foo.py")))
- self.assertEqual(refs[1].lineno,3)
- self.assertEqual(refs[1].colno,10)
- self.assertEqual(refs[1].confidence,100)
- """
-
- def test_findsReferenceInModuleWhichImportsModuleWithFromImportStar(self):
- src = trimLines("""
- from b.bah import *
- a = TheClass()
- a.theMethod()
- """)
-
- root = createSourceNodeAt( src, "a.foo")
- root = createSourceNodeAt( testdata.TheClass, "a.b.bah")
- refs = [x for x in getReferencesToModule(root,"a.b.bah")]
-
- self.assertEqual(refs[0].filename,os.path.abspath(os.path.join("a","foo.py")))
- self.assertEqual(refs[0].lineno,1)
- self.assertEqual(refs[0].colno,7)
- self.assertEqual(refs[0].confidence,100)
-
- ''' Dont think this is a valid test, since cant import a module with
- from package import *
- def test_findsReferenceInModuleWhichImportsClassWithFromImportStar2(self):
- src = trimLines("""
- from a.b import *
- a = bah.TheClass()
- """)
-
- root = createSourceNodeAt( src, "a.foo")
- root = createSourceNodeAt( testdata.TheClass, "a.b.bah")
- refs = [x for x in getReferencesToModule(root,"a.b.bah")]
-
- self.assertEqual(refs[0].filename,os.path.abspath(os.path.join("a","foo.py")))
- self.assertEqual(refs[0].lineno,2)
- self.assertEqual(refs[0].colno,4)
- self.assertEqual(refs[0].confidence,100)
- '''
-
- def test_findsReferenceInClassBases(self):
- src =trimLines("""
- from b import bah
- class DerivedClass(bah.TheClass):
- pass
- """)
-
- root = createSourceNodeAt(src, "a.foo")
- root = createSourceNodeAt(testdata.TheClass, "a.b.bah")
- refs = [x for x in getReferencesToModule(root,"a.b.bah")]
-
- self.assertEqual(refs[1].filename,os.path.abspath(os.path.join("a","foo.py")))
- self.assertEqual(refs[1].lineno,2)
- self.assertEqual(refs[1].colno,19)
- self.assertEqual(refs[1].confidence,100)
-
- def test_findsReferenceInMultiLineImportStatement(self):
- src =trimLines("""
- from b import foo, \\
- TheFooBah, TheClass, TheBastard, SomethingElse, bah
- """)
-
- root = createSourceNodeAt( src, "a.foo")
- root = createSourceNodeAt( testdata.TheClass, "a.b.bah")
- refs = [x for x in getReferencesToModule(root,"a.b.bah")]
- self.assertEqual(refs[0].filename,os.path.abspath(os.path.join("a","foo.py")))
- self.assertEqual(refs[0].lineno,2)
- self.assertEqual(refs[0].colno,58)
- self.assertEqual(refs[0].confidence,100)
-
- def test_findsReferenceWhenModulenameSameAsClassMethodName(self):
- # asserts that brm doesnt search class scope after not finding name
- # in method scope (since class scope is invisible unless called on 'self'
- src =trimLines("""
- from a.b import bah
- class baz:
- def bah(self):
- print bah.TheClass
- """)
-
- root = createSourceNodeAt( src, "a.foo")
- root = createSourceNodeAt( testdata.TheClass, "a.b.bah")
- refs = [x for x in getReferencesToModule(root,"a.b.bah")]
-
- self.assertEqual(refs[0].filename,os.path.abspath(os.path.join("a","foo.py")))
- self.assertEqual(refs[0].lineno,1)
- self.assertEqual(refs[0].colno,16)
- self.assertEqual(refs[0].confidence,100)
-
- assert (len(refs))==2
-
-
-
-if __name__ == "__main__":
- unittest.main()
--- a/vim/sadness/bike/bike/query/test_getTypeOf.py Thu Feb 10 17:11:26 2011 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,191 +0,0 @@
-#!/usr/bin/env python
-import setpath
-import unittest
-import os
-from bike import testdata
-from bike.testutils import *
-from bike.query.getTypeOf import getTypeOf, UnfoundType,\
- attemptToConvertGetattrToFqn
-from bike.parsing.fastparserast import Class, Function, Instance
-from bike.parsing.newstuff import getModuleOrPackageUsingFQN
-from compiler.ast import Getattr,CallFunc,Name
-
-class TestGetTypeOf(BRMTestCase):
- def test_getsTypeOfSimpleClassInstanceReference(self):
- src = trimLines("""
- from b.bah import TheClass
- a = TheClass()
- a.theMethod()
- """)
- root = createSourceNodeAt(src,"a.foo")
- root = createSourceNodeAt(testdata.TheClass, "a.b.bah")
- module = getModuleOrPackageUsingFQN("a.foo")
- res = getTypeOf(module,"a")
- assert isinstance(res,Instance)
- assert isinstance(res.getType(),Class)
- assert res.getType().name == "TheClass"
-
- def test_getsTypeOfImportedClassReference(self):
- src = trimLines("""
- import b.bah
- a = b.bah.TheClass()
- """)
- root = createSourceNodeAt(src,"a.foo")
- root = createSourceNodeAt(testdata.TheClass, "a.b.bah")
- module = getModuleOrPackageUsingFQN("a.foo")
- res = getTypeOf(module,"a")
- assert isinstance(res,Instance)
- assert isinstance(res.getType(),Class)
- assert res.getType().name == "TheClass"
-
- def test_getsTypeOfClassReferenceFromImportedPackage(self):
- src = trimLines("""
- import b
- a = b.bah.TheClass()
- """)
- root = createSourceNodeAt(src,"a.foo")
- root = createSourceNodeAt(testdata.TheClass, "a.b.bah")
- module = getModuleOrPackageUsingFQN("a.foo")
- res = getTypeOf(module,"a")
- assert isinstance(res,Instance)
- assert isinstance(res.getType(),Class)
- assert res.getType().name == "TheClass"
-
- def test_getsTypeOfInstanceThatIsAnAttributeOfSelf(self):
- src = trimLines("""
- class TheClass:
- def theMethod(self):
- pass
-
- class AnotherClass:
- def __init__(self):
- self.a = TheClass()
- def anotherFn(self):
- self.a.theMethod()
- """)
- root = createSourceNodeAt(src,"a.foo")
- module = getModuleOrPackageUsingFQN('a.foo')
- theclass = getTypeOf(module,"TheClass")
- fn = getTypeOf(module,"AnotherClass.anotherFn")
- self.assertEqual(getTypeOf(fn,"self.a").getType().name, "TheClass")
- #self.assertEqual(getTypeOf(fn,"self.a").getType(), theclass)
-
-
-
- def test_doesntGetTypeDefinedInChildFunction(self):
- src = trimLines("""
- from b.bah import TheClass
- a = AnotherClass()
- def foo():
- a = TheClass()
- a.theMethod()
- """)
- root = createSourceNodeAt(src,"a.foo")
- root = createSourceNodeAt(testdata.TheClass, "a.b.bah")
-
- themodule = getModuleOrPackageUsingFQN("a.foo")
- assert isinstance(getTypeOf(themodule,"a"),UnfoundType)
-
-
- def test_getsTypeOfClassReferencedViaAlias(self):
- src = trimLines("""
- from b.bah import TheClass as FooBah
- FooBah()
- """)
- root = createSourceNodeAt(src,"a.foo")
- root = createSourceNodeAt(testdata.TheClass, "a.b.bah")
- themodule = getModuleOrPackageUsingFQN("a.foo")
- self.assertEqual(getTypeOf(themodule,"FooBah").name,"TheClass")
- self.assertEqual(getTypeOf(themodule,"FooBah").filename,
- os.path.abspath(os.path.join("a","b","bah.py")))
-
-
- def test_getsTypeOfClassImportedFromPackageScope(self):
- initfile = trimLines("""
- from bah import TheClass
- """)
- src = trimLines("""
- from a import b
- b.TheClass()
- """)
- createSourceNodeAt(src,"a.foo")
- createSourceNodeAt(testdata.TheClass, "a.b.bah")
- createSourceNodeAt(initfile,"a.b.__init__")
- themodule = getModuleOrPackageUsingFQN("a.foo")
- self.assertEqual(getTypeOf(themodule,"b.TheClass").name,"TheClass")
- self.assertEqual(getTypeOf(themodule,"b.TheClass").filename,
- os.path.abspath(os.path.join("a","b","bah.py")))
-
-
- def test_attemptToConvertGetattrToFqn_returnsNoneIfFails(self):
- ast = Getattr(CallFunc(Name("foo"),[],[],[]),"hello")
- assert attemptToConvertGetattrToFqn(ast) is None
-
- def test_attemptToConvertGetattrToFqn_works(self):
- ast = Getattr(Getattr(Name("foo"),"bah"),"hello")
- assert attemptToConvertGetattrToFqn(ast) == "foo.bah.hello"
-
-
- def test_handlesRecursionProblem(self):
- src = trimLines("""
- def fn(root):
- node = root
- node = node.getPackage('something')
- """)
- root = createSourceNodeAt(src,"a.foo")
- m = getModuleOrPackageUsingFQN("a.foo")
- fn = getTypeOf(m,"fn")
- getTypeOf(fn,"node") # stack overflow!
-
-
- def test_doesntGotIntoRecursiveLoopWhenEvaluatingARecursiveFunction(self):
- src = trimLines("""
- def fn(v):
- if v < 45:
- return fn(root+1)
- val = fn(3)
- """)
- root = createSourceNodeAt(src,"a.foo")
- mod = getModuleOrPackageUsingFQN("a.foo")
- getTypeOf(mod,"val") # stack overflow!
-
- def test_getsModuleImportedWithFrom(self):
- importsrc=trimLines("""
- from a.b import bah
- """)
- src=trimLines("""
- mytext = 'hello'
- """)
- type = self.helper(importsrc,src,'bah')
- self.assertEqual(pkgstructureFile2,type.filename)
-
- def helper(self,importsrc,src,name):
- try:
- createPackageStructure(importsrc,src)
- from bike.parsing.newstuff import getModule
- scope = getModule(pkgstructureFile1)
- return getTypeOf(scope,name)
- finally:
- removePackageStructure()
-
-
- def test_getsTypeOfClassImportedAsAlias(self):
- importsrc = trimLines("""
- from b.bah import TheClass as MyTheClass
-
- def foo():
- a = MyTheClass()
- a.theMethod()
- """)
- src=trimLines("""
- class TheClass:
- def theMethod(self):
- pass
- """)
- type = self.helper(importsrc,src,'MyTheClass')
- self.assertEqual("TheClass",type.name)
-
-
-
-if __name__ == "__main__":
- unittest.main()
--- a/vim/sadness/bike/bike/query/test_relationships.py Thu Feb 10 17:11:26 2011 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,94 +0,0 @@
-#!/usr/bin/env python
-import setpath
-import unittest
-import os
-from bike import testdata
-from bike.testutils import *
-from bike.query.getTypeOf import getTypeOf
-from bike.parsing.fastparserast import Module
-from bike.query.relationships import getRootClassesOfHierarchy
-from bike.parsing.newstuff import getModule
-
-
-class TestGetRootClassesOfHierarchy(BRMTestCase):
- def test_getsRootClassFromDerivedClass(self):
- src = trimLines("""
- from b.bah import TheClass as BaseClass
-
- class DerivedClass(BaseClass):
- pass
-
- """)
- rootclasses = self.helper(src,"DerivedClass")
- self.assertEqual("TheClass",rootclasses[0].name)
- self.assertEqual(len(rootclasses),1)
-
- def test_getsRootClassFromDerivedDerivedClass(self):
- src = trimLines("""
- from b.bah import TheClass as BaseClass
-
- class DerivedClass(BaseClass):
- pass
- class DerivedDerivedClass(DerivedClass):
- pass
- """)
- rootclasses = self.helper(src,"DerivedDerivedClass")
- self.assertEqual("TheClass",rootclasses[0].name)
- self.assertEqual(len(rootclasses),1)
-
-
- def test_getsRootClassFromDiamondOfClasses(self):
- src = trimLines("""
- from b.bah import TheClass as BaseClass
-
- class DerivedClass(BaseClass):
- pass
- class DerivedDerivedClass(DerivedClass,BaseClass):
- pass
- """)
- rootclasses = self.helper(src,"DerivedDerivedClass")
- self.assertEqual("TheClass",rootclasses[0].name)
- self.assertEqual("TheClass",rootclasses[1].name)
- self.assertEqual(len(rootclasses),2)
-
-
- def test_getsRootClassesFromMultipleInheritance(self):
- src = trimLines("""
- from b.bah import TheClass as BaseClass
-
- class DerivedClass:
- pass
- class DerivedDerivedClass(DerivedClass,BaseClass):
- pass
- """)
- rootclasses = self.helper(src,"DerivedDerivedClass")
- self.assertEqual("DerivedClass",rootclasses[0].name)
- self.assertEqual("TheClass",rootclasses[1].name)
- self.assertEqual(len(rootclasses),2)
-
- def test_getsRootClassesFromMultipleInheritanceWithNewStyleClass(self):
- src = trimLines("""
- from b.bah import TheClass as BaseClass
-
- class DerivedClass(Object):
- pass
- class DerivedDerivedClass(DerivedClass,BaseClass):
- pass
- """)
- rootclasses = self.helper(src,"DerivedDerivedClass")
- self.assertEqual("DerivedClass",rootclasses[0].name)
- self.assertEqual("TheClass",rootclasses[1].name)
- self.assertEqual(len(rootclasses),2)
-
-
- def helper(self,src,classname):
- try:
- createPackageStructure(src,testdata.TheClass)
- classobj = getTypeOf(getModule(pkgstructureFile1),classname)
- return getRootClassesOfHierarchy(classobj)
- finally:
- removePackageStructure()
-
-
-if __name__ == "__main__":
- unittest.main()
--- a/vim/sadness/bike/bike/query/testall.py Thu Feb 10 17:11:26 2011 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,15 +0,0 @@
-#!/usr/bin/env python
-
-import setpath
-
-from test_common import *
-from test_getReferencesToClass import *
-from test_getReferencesToMethod import *
-#from test_getReferencesToModule import *
-from test_findDefinition import *
-from test_findReferences import *
-from test_relationships import *
-from test_getTypeOf import *
-
-if __name__ == "__main__":
- unittest.main()
--- a/vim/sadness/bike/bike/refactor/__init__.py Thu Feb 10 17:11:26 2011 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,1 +0,0 @@
-
--- a/vim/sadness/bike/bike/refactor/extractMethod.py Thu Feb 10 17:11:26 2011 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,363 +0,0 @@
-import re
-import compiler
-from bike.parsing import visitor
-from bike.query.common import getScopeForLine
-from bike.parsing.parserutils import generateLogicalLines, \
- makeLineParseable, maskStringsAndRemoveComments
-from parser import ParserError
-from bike.parsing.fastparserast import Class
-from bike.transformer.undo import getUndoStack
-from bike.refactor.utils import getTabWidthOfLine, getLineSeperator, \
- reverseCoordsIfWrongWayRound
-from bike.transformer.save import queueFileToSave
-from bike.parsing.load import getSourceNode
-TABSIZE = 4
-
-class coords:
- def __init__(self, line, column):
- self.column = column
- self.line = line
- def __str__(self):
- return "("+str(self.column)+","+str(self.line)+")"
-
-commentRE = re.compile(r"#.*?$")
-
-class ParserException(Exception): pass
-
-def extractMethod(filename, startcoords, endcoords, newname):
- ExtractMethod(getSourceNode(filename),
- startcoords, endcoords, newname).execute()
-
-class ExtractMethod(object):
- def __init__(self,sourcenode, startcoords, endcoords, newname):
- self.sourcenode = sourcenode
-
- startcoords, endcoords = \
- reverseCoordsIfWrongWayRound(startcoords,endcoords)
-
- self.startline = startcoords.line
- self.endline = endcoords.line
- self.startcol = startcoords.column
- self.endcol= endcoords.column
-
- self.newfn = NewFunction(newname)
-
- self.getLineSeperator()
- self.adjustStartColumnIfLessThanTabwidth()
- self.adjustEndColumnIfStartsANewLine()
- self.fn = self.getFunctionObject()
- self.getRegionToBuffer()
- #print "-"*80
- #print self.extractedLines
- #print "-"*80
- self.deduceIfIsMethodOrFunction()
-
- def execute(self):
- self.deduceArguments()
- getUndoStack().addSource(self.sourcenode.filename,
- self.sourcenode.getSource())
- srclines = self.sourcenode.getLines()
- newFnInsertPosition = self.fn.getEndLine()-1
- self.insertNewFunctionIntoSrcLines(srclines, self.newfn,
- newFnInsertPosition)
- self.writeCallToNewFunction(srclines)
-
- src = "".join(srclines)
- queueFileToSave(self.sourcenode.filename,src)
-
- def getLineSeperator(self):
- line = self.sourcenode.getLines()[self.startline-1]
- linesep = getLineSeperator(line)
- self.linesep = linesep
-
- def adjustStartColumnIfLessThanTabwidth(self):
- tabwidth = getTabWidthOfLine(self.sourcenode.getLines()[self.startline-1])
- if self.startcol < tabwidth: self.startcol = tabwidth
-
- def adjustEndColumnIfStartsANewLine(self):
- if self.endcol == 0:
- self.endline -=1
- nlSize = len(self.linesep)
- self.endcol = len(self.sourcenode.getLines()[self.endline-1])-nlSize
-
-
- def getFunctionObject(self):
- return getScopeForLine(self.sourcenode,self.startline)
-
-
- def getTabwidthOfParentFunction(self):
- line = self.sourcenode.getLines()[self.fn.getStartLine()-1]
- match = re.match("\s+",line)
- if match is None:
- return 0
- else:
- return match.end(0)
-
- # should be in the transformer module
- def insertNewFunctionIntoSrcLines(self,srclines,newfn,insertpos):
- tabwidth = self.getTabwidthOfParentFunction()
-
- while re.match("\s*"+self.linesep,srclines[insertpos-1]):
- insertpos -= 1
-
- srclines.insert(insertpos, self.linesep)
- insertpos +=1
-
- fndefn = "def "+newfn.name+"("
-
- if self.isAMethod:
- fndefn += "self"
- if newfn.args != []:
- fndefn += ", "+", ".join(newfn.args)
- else:
- fndefn += ", ".join(newfn.args)
-
- fndefn += "):"+self.linesep
-
-
- srclines.insert(insertpos,tabwidth*" "+fndefn)
- insertpos +=1
-
- tabwidth += TABSIZE
-
-
- if self.extractedCodeIsAnExpression(srclines):
- assert len(self.extractedLines) == 1
-
- fnbody = [tabwidth*" "+ "return "+self.extractedLines[0]]
-
-
- else:
- fnbody = [tabwidth*" "+line for line in self.extractedLines]
- if newfn.retvals != []:
- fnbody.append(tabwidth*" "+"return "+
- ", ".join(newfn.retvals) + self.linesep)
-
- for line in fnbody:
- srclines.insert(insertpos,line)
- insertpos +=1
-
-
- def writeCallToNewFunction(self, srclines):
- startline = self.startline
- endline = self.endline
- startcol = self.startcol
- endcol= self.endcol
-
- fncall = self.constructFunctionCallString(self.newfn.name, self.newfn.args,
- self.newfn.retvals)
-
- self.replaceCodeWithFunctionCall(srclines, fncall,
- startline, endline, startcol, endcol)
-
-
- def replaceCodeWithFunctionCall(self, srclines, fncall,
- startline, endline, startcol, endcol):
- if startline == endline: # i.e. extracted code part of existing line
- line = srclines[startline-1]
- srclines[startline-1] = self.replaceSectionOfLineWithFunctionCall(line,
- startcol, endcol, fncall)
- else:
- self.replaceLinesWithFunctionCall(srclines, startline, endline, fncall)
-
-
- def replaceLinesWithFunctionCall(self, srclines, startline, endline, fncall):
- tabwidth = getTabWidthOfLine(srclines[startline-1])
- line = tabwidth*" " + fncall + self.linesep
- srclines[startline-1:endline] = [line]
-
-
-
- def replaceSectionOfLineWithFunctionCall(self, line, startcol, endcol, fncall):
- line = line[:startcol] + fncall + line[endcol:]
- if not line.endswith(self.linesep):
- line+=self.linesep
- return line
-
-
-
- def constructFunctionCallString(self, fnname, fnargs, retvals):
- fncall = fnname + "("+", ".join(fnargs)+")"
- if self.isAMethod:
- fncall = "self." + fncall
-
- if retvals != []:
- fncall = ", ".join(retvals) + " = "+fncall
- return fncall
-
-
- def deduceArguments(self):
- lines = self.fn.getLinesNotIncludingThoseBelongingToChildScopes()
-
- # strip off comments
- lines = [commentRE.sub(self.linesep,line) for line in lines]
- extractedLines = maskStringsAndRemoveComments("".join(self.extractedLines)).splitlines(1)
-
- linesbefore = lines[:(self.startline - self.fn.getStartLine())]
- linesafter = lines[(self.endline - self.fn.getStartLine()) + 1:]
-
- # split into logical lines
- linesbefore = [line for line in generateLogicalLines(linesbefore)]
- extractedLines = [line for line in generateLogicalLines(extractedLines)]
- linesafter = [line for line in generateLogicalLines(linesafter)]
-
- if self.startline == self.endline:
- # need to include the line code is extracted from
- line = generateLogicalLines(lines[self.startline - self.fn.getStartLine():]).next()
- linesbefore.append(line[:self.startcol] + "dummyFn()" + line[self.endcol:])
- assigns = getAssignments(linesbefore)
- fnargs = getFunctionArgs(linesbefore)
- candidateArgs = assigns + fnargs
- refs = getVariableReferencesInLines(extractedLines)
- self.newfn.args = [ref for ref in refs if ref in candidateArgs]
-
- assignsInExtractedBlock = getAssignments(extractedLines)
- usesAfterNewFunctionCall = getVariableReferencesInLines(linesafter)
- usesInPreceedingLoop = getVariableReferencesInLines(
- self.getPreceedingLinesInLoop(linesbefore,line))
- self.newfn.retvals = [ref for ref in usesInPreceedingLoop+usesAfterNewFunctionCall
- if ref in assignsInExtractedBlock]
-
- def getPreceedingLinesInLoop(self,linesbefore,firstLineToExtract):
- if linesbefore == []: return []
- tabwidth = getTabWidthOfLine(firstLineToExtract)
- rootTabwidth = getTabWidthOfLine(linesbefore[0])
- llines = [line for line in generateLogicalLines(linesbefore)]
- startpos = len(llines)-1
- loopTabwidth = tabwidth
- for idx in range(startpos,0,-1):
- line = llines[idx]
- if re.match("(\s+)for",line) is not None or \
- re.match("(\s+)while",line) is not None:
- candidateLoopTabwidth = getTabWidthOfLine(line)
- if candidateLoopTabwidth < loopTabwidth:
- startpos = idx
- return llines[startpos:]
-
-
-
-
-
-
- def getRegionToBuffer(self):
- startline = self.startline
- endline = self.endline
- startcol = self.startcol
- endcol= self.endcol
-
-
- self.extractedLines = self.sourcenode.getLines()[startline-1:endline]
-
- match = re.match("\s*",self.extractedLines[0])
- tabwidth = match.end(0)
-
- self.extractedLines = [line[startcol:] for line in self.extractedLines]
-
- # above cropping can take a blank line's newline off.
- # this puts it back
- for idx in range(len(self.extractedLines)):
- if self.extractedLines[idx] == '':
- self.extractedLines[idx] = self.linesep
-
- if startline == endline:
- # need to crop the end
- # (n.b. if region is multiple lines, then whole lines are taken)
- self.extractedLines[-1] = self.extractedLines[-1][:endcol-startcol]
-
- if self.extractedLines[-1][-1] != '\n':
- self.extractedLines[-1] += self.linesep
-
- def extractedCodeIsAnExpression(self,lines):
- if len(self.extractedLines) == 1:
- charsBeforeSelection = lines[self.startline-1][:self.startcol]
- if re.match("^\s*$",charsBeforeSelection) is not None:
- return 0
- if re.search(":\s*$",charsBeforeSelection) is not None:
- return 0
- return 1
- return 0
-
- def deduceIfIsMethodOrFunction(self):
- if isinstance(self.fn.getParent(),Class):
- self.isAMethod = 1
- else:
- self.isAMethod = 0
-
-
-# holds information about the new function
-class NewFunction:
- def __init__(self,name):
- self.name = name
-
-
-# lines = list of lines.
-# Have to have strings masked and comments removed
-def getAssignments(lines):
- class AssignVisitor:
- def __init__(self):
- self.assigns = []
-
- def visitAssTuple(self, node):
- for a in node.nodes:
- if a.name not in self.assigns:
- self.assigns.append(a.name)
-
- def visitAssName(self, node):
- if node.name not in self.assigns:
- self.assigns.append(node.name)
-
- def visitAugAssign(self, node):
- if isinstance(node.node, compiler.ast.Name):
- if node.node.name not in self.assigns:
- self.assigns.append(node.node.name)
-
- assignfinder = AssignVisitor()
- for line in lines:
- doctoredline = makeLineParseable(line)
- try:
- ast = compiler.parse(doctoredline)
- except ParserError:
- raise ParserException("couldnt parse:"+doctoredline)
- visitor.walk(ast, assignfinder)
- return assignfinder.assigns
-
-
-# lines = list of lines.
-# Have to have strings masked and comments removed
-def getFunctionArgs(lines):
- if lines == []: return []
-
- class FunctionVisitor:
- def __init__(self):
- self.result = []
- def visitFunction(self, node):
- for n in node.argnames:
- if n != "self":
- self.result.append(n)
- fndef = generateLogicalLines(lines).next()
- doctoredline = makeLineParseable(fndef)
- try:
- ast = compiler.parse(doctoredline)
- except ParserError:
- raise ParserException("couldnt parse:"+doctoredline)
- return visitor.walk(ast, FunctionVisitor()).result
-
-
-
-# lines = list of lines. Have to have strings masked and comments removed
-def getVariableReferencesInLines(lines):
- class NameVisitor:
- def __init__(self):
- self.result = []
- def visitName(self, node):
- if node.name not in self.result:
- self.result.append(node.name)
- reffinder = NameVisitor()
- for line in lines:
- doctoredline = makeLineParseable(line)
- try:
- ast = compiler.parse(doctoredline)
- except ParserError:
- raise ParserException("couldnt parse:"+doctoredline)
- visitor.walk(ast, reffinder)
- return reffinder.result
--- a/vim/sadness/bike/bike/refactor/extractVariable.py Thu Feb 10 17:11:26 2011 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,32 +0,0 @@
-from bike.parsing.parserutils import maskStringsAndRemoveComments
-from bike.transformer.undo import getUndoStack
-from parser import ParserError
-import compiler
-from bike.refactor.extractMethod import coords
-from bike.refactor.utils import getTabWidthOfLine, getLineSeperator,\
- reverseCoordsIfWrongWayRound
-from bike.transformer.save import queueFileToSave
-from bike.parsing.load import getSourceNode
-
-
-def extractLocalVariable(filename, startcoords, endcoords, varname):
- sourceobj = getSourceNode(filename)
- if startcoords.line != endcoords.line:
- raise "Can't do multi-line extracts yet"
- startcoords, endcoords = \
- reverseCoordsIfWrongWayRound(startcoords,endcoords)
- line = sourceobj.getLine(startcoords.line)
- tabwidth = getTabWidthOfLine(line)
- linesep = getLineSeperator(line)
- region = line[startcoords.column:endcoords.column]
-
- getUndoStack().addSource(sourceobj.filename,sourceobj.getSource())
- sourceobj.getLines()[startcoords.line-1] = \
- line[:startcoords.column] + varname + line[endcoords.column:]
-
- defnline = tabwidth*" " + varname + " = " + region + linesep
-
- sourceobj.getLines().insert(startcoords.line-1,defnline)
-
- queueFileToSave(sourceobj.filename,"".join(sourceobj.getLines()))
-
--- a/vim/sadness/bike/bike/refactor/inlineVariable.py Thu Feb 10 17:11:26 2011 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,94 +0,0 @@
-from bike.query.findDefinition import findAllPossibleDefinitionsByCoords
-from bike.query.findReferences import findReferences
-from bike.parsing.parserutils import maskStringsAndRemoveComments, linecontinueRE
-from bike.transformer.undo import getUndoStack
-from bike.transformer.save import queueFileToSave
-from parser import ParserError
-from bike.parsing.load import getSourceNode
-import compiler
-import re
-
-
-def inlineLocalVariable(filename, lineno,col):
- sourceobj = getSourceNode(filename)
- return inlineLocalVariable_old(sourceobj, lineno,col)
-
-def inlineLocalVariable_old(sourcenode,lineno,col):
- definition, region, regionlinecount = getLocalVariableInfo(sourcenode, lineno, col)
- addUndo(sourcenode)
- replaceReferences(sourcenode, findReferences(sourcenode.filename, definition.lineno, definition.colno), region)
- delLines(sourcenode, definition.lineno-1, regionlinecount)
- updateSource(sourcenode)
-
-def getLocalVariableInfo(sourcenode, lineno, col):
- definition = findDefinition(sourcenode, lineno, col)
- region, linecount = getRegionToInline(sourcenode, definition)
- return definition, region, linecount
-
-def findDefinition(sourcenode, lineno, col):
- definition = findAllPossibleDefinitionsByCoords(sourcenode.filename,
- lineno,col).next()
- assert definition.confidence == 100
- return definition
-
-def getRegionToInline(sourcenode, defn):
- line, linecount = getLineAndContinues(sourcenode, defn.lineno)
- start, end = findRegionToInline(maskStringsAndRemoveComments(line))
- return line[start:end], linecount
-
-def findRegionToInline(maskedline):
- match = re.compile("[^=]+=\s*(.+)$\n", re.DOTALL).match(maskedline)
- assert match
- return match.start(1), match.end(1)
-
-# Possible refactoring: move to class of sourcenode
-def getLineAndContinues(sourcenode, lineno):
- line = sourcenode.getLine(lineno)
-
- linecount = 1
- while linecontinueRE.search(line):
- line += sourcenode.getLine(lineno + linecount)
- linecount += 1
-
- return line, linecount
-
-def addUndo(sourcenode):
- getUndoStack().addSource(sourcenode.filename,sourcenode.getSource())
-
-def replaceReferences(sourcenode, references, replacement):
- for reference in safeReplaceOrder( references ):
- replaceReference(sourcenode, reference, replacement)
-
-def safeReplaceOrder( references ):
- """
- When inlining a variable, if multiple instances occur on the line, then the
- last reference must be replaced first. Otherwise the remaining intra-line
- references will be incorrect.
- """
- def safeReplaceOrderCmp(self, other):
- return -cmp(self.colno, other.colno)
-
- result = list(references)
- result.sort(safeReplaceOrderCmp)
- return result
-
-
-def replaceReference(sourcenode, ref, replacement):
- """ sourcenode.getLines()[ref.lineno-1][ref.colno:ref.colend] = replacement
- But strings don't support slice assignment as they are immutable. :(
- """
- sourcenode.getLines()[ref.lineno-1] = \
- replaceSubStr(sourcenode.getLines()[ref.lineno-1],
- ref.colno, ref.colend, replacement)
-
-def replaceSubStr(str, start, end, replacement):
- return str[:start] + replacement + str[end:]
-
-# Possible refactoring: move to class of sourcenode
-def delLines(sourcenode, lineno, linecount=1):
- del sourcenode.getLines()[lineno:lineno+linecount]
-
-def updateSource(sourcenode):
- queueFileToSave(sourcenode.filename,"".join(sourcenode.getLines()))
-
-
--- a/vim/sadness/bike/bike/refactor/moveToModule.py Thu Feb 10 17:11:26 2011 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,148 +0,0 @@
-import bike.globals
-from bike.parsing.load import getSourceNode
-from bike.parsing.fastparserast import Module
-from bike.query.common import getScopeForLine, convertNodeToMatchObject
-from bike.transformer.save import queueFileToSave, save
-from bike.transformer.undo import getUndoStack
-from bike.refactor.extractMethod import getVariableReferencesInLines
-from bike.refactor.utils import getLineSeperator
-from bike.query.findDefinition import findDefinitionFromASTNode
-from bike.query.findReferences import findReferences
-from bike.parsing.pathutils import filenameToModulePath
-from compiler.ast import Name
-import re
-
-def moveClassToNewModule(origfile,line,newfile):
- srcnode = getSourceNode(origfile)
- targetsrcnode = getSourceNode(newfile)
- classnode = getScopeForLine(srcnode,line)
- classlines = srcnode.getLines()[classnode.getStartLine()-1:
- classnode.getEndLine()-1]
- getUndoStack().addSource(srcnode.filename,
- srcnode.getSource())
- getUndoStack().addSource(targetsrcnode.filename,
- targetsrcnode.getSource())
-
- srcnode.getLines()[classnode.getStartLine()-1:
- classnode.getEndLine()-1] = []
-
- targetsrcnode.getLines().extend(classlines)
-
- queueFileToSave(srcnode.filename,srcnode.getSource())
- queueFileToSave(targetsrcnode.filename,targetsrcnode.getSource())
-
-
-exactFromRE = "(from\s+\S+\s+import\s+%s)(.*)"
-fromRE = "from\s+\S+\s+import\s+(.*)"
-
-def moveFunctionToNewModule(origfile,line,newfile):
-
- srcnode = getSourceNode(origfile)
- targetsrcnode = getSourceNode(newfile)
- scope = getScopeForLine(srcnode,line)
-
- linesep = getLineSeperator(srcnode.getLines()[0])
-
- matches =[m for m in findReferences(origfile, line, scope.getColumnOfName())]
-
- origFileImport = []
- fromline = 'from %s import %s'%(filenameToModulePath(newfile),scope.name)
-
- for match in matches:
- if match.filename == origfile:
- origFileImport = fromline + linesep
- else:
- s = getSourceNode(match.filename)
- m = s.fastparseroot
- if match.lineno in m.getImportLineNumbers():
- getUndoStack().addSource(s.filename,
- s.getSource())
-
- maskedline = m.getLogicalLine(match.lineno)
- origline = s.getLines()[match.lineno-1]
- reMatch = re.match(exactFromRE%(scope.name),maskedline)
- if reMatch and not (',' in reMatch.group(2) or \
- '\\' in reMatch.group(2)):
- # i.e. line is 'from module import foo'
-
- if match.filename == newfile:
- #remove the import
- s.getLines()[match.lineno-1:match.lineno] = []
- pass
- else:
- restOfOrigLine = origline[len(reMatch.group(1)):]
- s.getLines()[match.lineno-1] = fromline + restOfOrigLine
-
- elif re.match(fromRE,maskedline):
- # i.e. line is 'from module import foo,bah,baz'
- #remove the element from the import stmt
- line = removeNameFromMultipleImportLine(scope.name, origline)
- s.getLines()[match.lineno-1] = line
- #and add a new line
- nextline = match.lineno + maskedline.count('\\') + 1
- s.getLines()[nextline-1:nextline-1] = [fromline+linesep]
-
- queueFileToSave(s.filename,s.getSource())
-
-
- refs = getVariableReferencesInLines(scope.getMaskedLines())
-
- scopeLines = srcnode.getLines()[scope.getStartLine()-1:
- scope.getEndLine()-1]
- importModules = deduceImportsForNewFile(refs, scope)
- importlines = composeNewFileImportLines(importModules, linesep)
-
-
-
- getUndoStack().addSource(srcnode.filename,
- srcnode.getSource())
- getUndoStack().addSource(targetsrcnode.filename,
- targetsrcnode.getSource())
-
- srcnode.getLines()[scope.getStartLine()-1:
- scope.getEndLine()-1] = origFileImport
-
- targetsrcnode.getLines().extend(importlines+scopeLines)
-
- queueFileToSave(srcnode.filename,srcnode.getSource())
- queueFileToSave(targetsrcnode.filename,targetsrcnode.getSource())
-
-def removeNameFromMultipleImportLine(name, origline):
- def replacefn(match):
- return match.group(1)
- line = re.sub('(\W)%s\s*?,'%(name),replacefn,origline)
- return line
-
-
-
-
-def composeNewFileImportLines(importModules, linesep):
- importlines = []
- for mpath in importModules:
- importlines += "from %s import %s"%(mpath,
- ', '.join(importModules[mpath]))
- importlines += linesep
- return importlines
-
-def deduceImportsForNewFile(refs, scope):
- importModules = {}
- for ref in refs:
- match = findDefinitionFromASTNode(scope,Name(ref))
-
- if match.filename == scope.module.filename:
- tgtscope = getScopeForLine(getSourceNode(match.filename),
- match.lineno)
- while tgtscope != scope and not isinstance(tgtscope,Module):
- tgtscope = tgtscope.getParent()
-
- if not isinstance(tgtscope,Module):
- continue # was defined in this function
-
- mpath = filenameToModulePath(match.filename)
- if mpath in importModules:
- importModules[mpath].append(ref)
- else:
- importModules[mpath] = [ref]
- return importModules
-
-
--- a/vim/sadness/bike/bike/refactor/rename.py Thu Feb 10 17:11:26 2011 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,19 +0,0 @@
-from bike.transformer.WordRewriter import WordRewriter
-from bike.query.findReferences import findReferencesIncludingDefn
-from bike.transformer.save import save
-
-def rename(filename,lineno,col,newname,promptcallback=None):
- strrewrite = WordRewriter()
- for match in findReferencesIncludingDefn(filename,lineno,col):
- #print "rename match ",match
- if match.confidence == 100 or promptUser(promptcallback,match):
- strrewrite.rewriteString(match.sourcenode,
- match.lineno,match.colno,newname)
- strrewrite.commit()
-
-def promptUser(promptCallback,match):
- if promptCallback is not None and \
- promptCallback(match.filename, match.lineno, match.colno, match.colend):
- return 1
- return 0
-
--- a/vim/sadness/bike/bike/refactor/setpath.py Thu Feb 10 17:11:26 2011 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,5 +0,0 @@
-import sys,os
-if not os.path.abspath("../..") in sys.path:
- from bike import log
- print >> log.warning, "Appending to the system path. This should only happen in unit tests"
- sys.path.append(os.path.abspath("../.."))
--- a/vim/sadness/bike/bike/refactor/test_extractMethod.py Thu Feb 10 17:11:26 2011 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,791 +0,0 @@
-#!/usr/bin/env python
-import setpath
-import unittest
-
-from bike.refactor.extractMethod import ExtractMethod, \
- extractMethod, coords
-from bike import testdata
-from bike.testutils import *
-from bike.parsing.load import Cache
-
-def assertTokensAreSame(t1begin, t1end, tokens):
- it = t1begin.clone()
- pos = 0
- while it != t1end:
- assert it.deref() == tokens[pos]
- it.incr()
- pos+=1
- assert pos == len(tokens)
-
-
-def helper(src,startcoords, endcoords, newname):
- sourcenode = createAST(src)
- extractMethod(tmpfile, startcoords, endcoords, newname)
- return sourcenode.getSource()
-
-class TestExtractMethod(BRMTestCase):
-
- def test_extractsPass(self):
- srcBefore=trimLines("""
- class MyClass:
- def myMethod(self):
- pass
- """)
- srcAfter=trimLines("""
- class MyClass:
- def myMethod(self):
- self.newMethod()
-
- def newMethod(self):
- pass
- """)
- src = helper(srcBefore, coords(3, 8), coords(3, 12), "newMethod")
- self.assertEqual(src,srcAfter)
-
- def test_extractsPassWhenFunctionAllOnOneLine(self):
- srcBefore=trimLines("""
- class MyClass:
- def myMethod(self): pass # comment
- """)
-
- srcAfter=trimLines("""
- class MyClass:
- def myMethod(self): self.newMethod() # comment
-
- def newMethod(self):
- pass
- """)
- src = helper(srcBefore, coords(2, 24), coords(2, 28),"newMethod")
- self.assertEqual(src,srcAfter)
-
- def test_extractsPassFromForLoop(self):
- srcBefore=trimLines("""
- class MyClass:
- def myMethod(self): # comment
- for i in foo:
- pass
- """)
- srcAfter=trimLines("""
- class MyClass:
- def myMethod(self): # comment
- for i in foo:
- self.newMethod()
-
- def newMethod(self):
- pass
- """)
- src = helper(srcBefore, coords(4, 12), coords(4, 16), "newMethod")
- self.assertEqual(srcAfter, src)
-
- def test_newMethodHasArgumentsForUsedTemporarys(self):
-
- srcBefore=trimLines("""
- class MyClass:
- def myMethod(self, c):
- a = something()
- b = somethingelse()
- print a + b + c + d
- print \"hello\"
- dosomethingelse(a, b)
- """)
- srcAfter=trimLines("""
- class MyClass:
- def myMethod(self, c):
- a = something()
- b = somethingelse()
- self.newMethod(a, b, c)
- dosomethingelse(a, b)
-
- def newMethod(self, a, b, c):
- print a + b + c + d
- print \"hello\"
- """)
-
- src = helper(srcBefore, coords(5, 8), coords(6, 21), "newMethod")
- self.assertEqual(srcAfter, src)
-
- def test_newMethodHasSingleArgument(self):
- srcBefore=trimLines("""
- class MyClass:
- def myMethod(self):
- a = something()
- print a
- print \"hello\"
- dosomethingelse(a, b)
- """)
- srcAfter=trimLines("""
- class MyClass:
- def myMethod(self):
- a = something()
- self.newMethod(a)
- dosomethingelse(a, b)
-
- def newMethod(self, a):
- print a
- print \"hello\"
- """)
- src = helper(srcBefore, coords(4, 8), coords(5, 21), "newMethod")
- self.assertEqual(srcAfter, src)
-
-
- def test_doesntHaveDuplicateArguments(self):
- srcBefore=trimLines("""
- class MyClass:
- def myMethod(self):
- a = 3
- print a
- print a
- """)
-
- srcAfter=trimLines("""
- class MyClass:
- def myMethod(self):
- a = 3
- self.newMethod(a)
-
- def newMethod(self, a):
- print a
- print a
- """)
- src = helper(srcBefore, coords(4, 0), coords(6, 0), "newMethod")
- self.assertEqual(srcAfter, src)
-
- def test_extractsQueryWhenFunctionAllOnOneLine(self):
- srcBefore=trimLines("""
- class MyClass:
- def myMethod(self, a): print a # comment
- """)
-
- srcAfter=trimLines("""
- class MyClass:
- def myMethod(self, a): self.newMethod(a) # comment
-
- def newMethod(self, a):
- print a
- """)
- src = helper(srcBefore, coords(2, 27), coords(2, 34), "newMethod")
- self.assertEqual(srcAfter, src)
-
-
- def test_worksWhenAssignmentsToTuples(self):
- srcBefore=trimLines("""
- class MyClass:
- def myMethod(self):
- a, b, c = 35, 36, 37
- print a + b
- """)
- srcAfter=trimLines("""
- class MyClass:
- def myMethod(self):
- a, b, c = 35, 36, 37
- self.newMethod(a, b)
-
- def newMethod(self, a, b):
- print a + b
- """)
-
- src = helper(srcBefore, coords(4, 8), coords(4, 19), "newMethod")
- self.assertEqual(srcAfter, src)
-
- def test_worksWhenUserSelectsABlockButDoesntSelectTheHangingDedent(self):
- srcBefore=trimLines("""
- class MyClass:
- def myMethod(self): # comment
- for i in foo:
- pass
- """)
- srcAfter=trimLines("""
- class MyClass:
- def myMethod(self): # comment
- for i in foo:
- self.newMethod()
-
- def newMethod(self):
- pass
- """)
-
- src = helper(srcBefore, coords(4, 8), coords(4, 16), "newMethod")
- self.assertEqual(srcAfter, src)
-
- def test_newMethodHasSingleReturnValue(self):
- srcBefore=trimLines("""
- class MyClass:
- def myMethod(self):
- a = 35 # <-- extract me
- print a
- """)
- srcAfter=trimLines("""
- class MyClass:
- def myMethod(self):
- a = self.newMethod()
- print a
-
- def newMethod(self):
- a = 35 # <-- extract me
- return a
- """)
-
- src = helper(srcBefore, coords(3, 4),
- coords(3, 34), "newMethod")
- self.assertEqual(srcAfter, src)
-
-
-
- def test_newMethodHasMultipleReturnValues(self):
- srcBefore=trimLines("""
- class MyClass:
- def myMethod(self):
- a = 35
- b = 352
- print a + b
- """)
- srcAfter=trimLines("""
- class MyClass:
- def myMethod(self):
- a, b = self.newMethod()
- print a + b
-
- def newMethod(self):
- a = 35
- b = 352
- return a, b
- """)
- src = helper(srcBefore, coords(3, 8),
- coords(4, 15), "newMethod")
- self.assertEqual(srcAfter, src)
-
-
-
- def test_worksWhenMovingCodeJustAfterDedent(self):
- srcBefore=trimLines("""
- class MyClass:
- def myMethod(self): # comment
- for i in foo:
- pass
- print \"hello\"
- """)
- srcAfter=trimLines("""
- class MyClass:
- def myMethod(self): # comment
- for i in foo:
- pass
- self.newMethod()
-
- def newMethod(self):
- print \"hello\"
- """)
-
- src = helper(srcBefore, coords(5, 8),
- coords(5, 21), "newMethod")
- self.assertEqual(srcAfter, src)
-
-
- def test_extractsPassWhenSelectionCoordsAreReversed(self):
- srcBefore=trimLines("""
- class MyClass:
- def myMethod(self):
- pass
- """)
- srcAfter=trimLines("""
- class MyClass:
- def myMethod(self):
- self.newMethod()
-
- def newMethod(self):
- pass
- """)
- src = helper(srcBefore, coords(3, 12), coords(3, 8), "newMethod")
- self.assertEqual(srcAfter, src)
-
-
- def test_extractsExpression(self):
- srcBefore=trimLines("""
- class MyClass:
- def myMethod(self): # comment
- a = 32
- b = 2 + a * 1 + 2
- """)
- srcAfter=trimLines("""
- class MyClass:
- def myMethod(self): # comment
- a = 32
- b = 2 + self.newMethod(a) + 2
-
- def newMethod(self, a):
- return a * 1
- """)
- src = helper(srcBefore, coords(4, 16), coords(4, 21), "newMethod")
- self.assertEqual(srcAfter, src)
-
-
- def test_extractsExpression2(self):
- srcBefore=trimLines("""
- class MyClass:
- def myMethod(self): # comment
- g = 32
- assert output.thingy(g) == \"bah\"
- """)
- srcAfter=trimLines("""
- class MyClass:
- def myMethod(self): # comment
- g = 32
- assert self.newMethod(g) == \"bah\"
-
- def newMethod(self, g):
- return output.thingy(g)
- """)
- src = helper(srcBefore, coords(4, 15), coords(4, 31), "newMethod")
- self.assertEqual(srcAfter, src)
-
-
-
-class TestExtractFunction(BRMTestCase):
- def runTarget(self, src, begincoords, endcoords, newname):
- ast = createAST(src)
- extractFunction(ast, begincoords, endcoords, newname)
- return ast
-
- def test_extractsFunction(self):
- srcBefore=trimLines("""
- def myFunction(): # comment
- a = 3
- c = a + 99
- b = c * 1
- print b
- """)
- srcAfter=trimLines("""
- def myFunction(): # comment
- a = 3
- b = newFunction(a)
- print b
-
- def newFunction(a):
- c = a + 99
- b = c * 1
- return b
- """)
-
- src = helper(srcBefore, coords(3, 4),
- coords(4, 13), "newFunction")
- self.assertEqual(srcAfter, src)
-
- def test_extractsAssignToAttribute(self):
- srcBefore=trimLines("""
- def simulateLoad(path):
- item = foo()
- item.decl = line
- """)
- srcAfter=trimLines("""
- def simulateLoad(path):
- item = foo()
- newFunction(item)
-
- def newFunction(item):
- item.decl = line
- """)
-
- src = helper(srcBefore, coords(3, 0),
- coords(4, 0), "newFunction")
- self.assertEqual(srcAfter, src)
-
-
- def test_extractsFromFirstBlockOfIfElseStatement(self):
- srcBefore=trimLines("""
- def foo():
- if bah:
- print \"hello1\"
- print \"hello2\"
-
- elif foo:
- pass
- """)
- srcAfter=trimLines("""
- def foo():
- if bah:
- newFunction()
- print \"hello2\"
-
- elif foo:
- pass
-
- def newFunction():
- print \"hello1\"
- """)
- src = helper(srcBefore, coords(3, 0),
- coords(4, 0), "newFunction")
- self.assertEqual(srcAfter, src)
-
-
- def test_extractsAugAssign(self):
- srcBefore=trimLines("""
- def foo():
- a = 3
- a += 1
- print a
- """)
- srcAfter=trimLines("""
- def foo():
- a = 3
- a = newFunction(a)
- print a
-
- def newFunction(a):
- a += 1
- return a
- """)
- src = helper(srcBefore, coords(3, 0),
- coords(4, 0), "newFunction")
- self.assertEqual(srcAfter, src)
-
- def test_extractsForLoopUsingLoopVariable(self):
- srcBefore=trimLines("""
- def foo():
- for i in range(1, 3):
- print i
- """)
- srcAfter=trimLines("""
- def foo():
- for i in range(1, 3):
- newFunction(i)
-
- def newFunction(i):
- print i
- """)
-
- src = helper(srcBefore, coords(3, 0),
- coords(4, 0), "newFunction")
- self.assertEqual(srcAfter, src)
-
- def test_extractWhileLoopVariableIncrement(self):
- srcBefore=trimLines("""
- def foo():
- a = 0
- while a != 3:
- a = a+1
- """)
- srcAfter=trimLines("""
- def foo():
- a = 0
- while a != 3:
- a = newFunction(a)
-
- def newFunction(a):
- a = a+1
- return a
- """)
- src = helper(srcBefore, coords(4, 0),
- coords(5, 0), "newFunction")
- self.assertEqual(srcAfter, src)
-
- def test_extractAssignedVariableUsedInOuterForLoop(self):
- srcBefore=trimLines("""
- def foo():
- b = 0
- for a in range(1, 3):
- b = b+1
- while b != 2:
- print a
- b += 1
- """)
- srcAfter=trimLines("""
- def foo():
- b = 0
- for a in range(1, 3):
- b = b+1
- while b != 2:
- b = newFunction(a, b)
-
- def newFunction(a, b):
- print a
- b += 1
- return b
- """)
-
- src = helper(srcBefore, coords(6, 0),
- coords(8, 0), "newFunction")
- self.assertEqual(srcAfter, src)
-
-
- def test_extractsConditionalFromExpression(self):
- srcBefore=trimLines("""
- def foo():
- if 123+3:
- print aoue
- """)
- srcAfter=trimLines("""
- def foo():
- if newFunction():
- print aoue
-
- def newFunction():
- return 123+3
- """)
- src = helper(srcBefore, coords(2, 7),
- coords(2, 12), "newFunction")
- self.assertEqual(srcAfter, src)
-
- def test_extractCodeAfterCommentInMiddleOfFnDoesntRaiseParseException(self):
- srcBefore=trimLines("""
- def theFunction():
- print 1
- # comment
- print 2
- """)
- srcAfter=trimLines("""
- def theFunction():
- print 1
- # comment
- newFunction()
-
- def newFunction():
- print 2
- """)
- src = helper(srcBefore, coords(4, 0),
- coords(5, 0), "newFunction")
- self.assertEqual(srcAfter, src)
-
-
- def test_canExtractQueryFromNestedIfStatement(self):
- srcBefore=trimLines("""
- def theFunction():
- if foo: # comment
- if bah:
- pass
- """)
- srcAfter=trimLines("""
- def theFunction():
- if foo: # comment
- if newFunction():
- pass
-
- def newFunction():
- return bah
- """)
- src = helper(srcBefore, coords(3, 11),
- coords(3, 14), "newFunction")
- self.assertEqual(srcAfter, src)
-
-
-
- def test_doesntMessUpTheNextFunctionOrClass(self):
- srcBefore=trimLines("""
- def myFunction():
- a = 3
- print \"hello\"+a # extract me
-
- class MyClass:
- def myMethod(self):
- b = 12 # extract me
- c = 3 # and me
- d = 2 # and me
- print b, c
- """)
- srcAfter=trimLines("""
- def myFunction():
- a = 3
- newFunction(a)
-
- def newFunction(a):
- print \"hello\"+a # extract me
-
- class MyClass:
- def myMethod(self):
- b = 12 # extract me
- c = 3 # and me
- d = 2 # and me
- print b, c
- """)
-
- # extract code on one line
- src = helper(srcBefore, coords(3, 4),
- coords(3, 34), "newFunction")
- self.assertEqual(srcAfter, src)
-
- # extract code on 2 lines (most common user method)
- resetRoot()
- Cache.instance.reset()
- Root()
- src = helper(srcBefore, coords(3, 0),
- coords(4, 0), "newFunction")
- self.assertEqual(srcAfter, src)
-
-
- def test_doesntBallsUpIndentWhenTheresALineWithNoSpacesInIt(self):
- srcBefore=trimLines("""
- def theFunction():
- if 1:
- pass
-
- pass
- """)
- srcAfter=trimLines("""
- def theFunction():
- newFunction()
-
- def newFunction():
- if 1:
- pass
-
- pass
- """)
- src = helper(srcBefore, coords(2, 4),
- coords(5, 8), "newFunction")
- self.assertEqual(srcAfter, src)
-
-
- def test_doesntHaveToBeInsideAFunction(self):
- srcBefore=trimLines(r"""
- a = 1
- print a + 2
- f(b)
- """)
- srcAfter=trimLines(r"""
- a = 1
- newFunction(a)
-
- def newFunction(a):
- print a + 2
- f(b)
- """)
- src = helper(srcBefore, coords(2, 0),
- coords(3, 4), "newFunction")
- self.assertEqual(srcAfter, src)
-
-
- def test_doesntBarfWhenEncountersMethodCalledOnCreatedObj(self):
- srcBefore=trimLines(r"""
- results = QueryEngine(q).foo()
- """)
- srcAfter=trimLines(r"""
- newFunction()
-
- def newFunction():
- results = QueryEngine(q).foo()
- """)
- src = helper(srcBefore, coords(1, 0),
- coords(2, 0), "newFunction")
- self.assertEqual(srcAfter, src)
-
-
- def test_worksIfNoLinesBeforeExtractedCode(self):
- srcBefore=trimLines(r"""
- print a + 2
- f(b)
- """)
- srcAfter=trimLines(r"""
- newFunction()
-
- def newFunction():
- print a + 2
- f(b)
- """)
- src = helper(srcBefore, coords(1, 0),
- coords(2, 4), "newFunction")
- self.assertEqual(srcAfter, src)
-
-
-class TestGetRegionAsString(BRMTestCase):
- def test_getsHighlightedSingleLinePassStatement(self):
- src=trimLines("""
- class MyClass:
- def myMethod(self):
- pass
- """)
- sourcenode = createAST(src)
- em = ExtractMethod(sourcenode, coords(3, 8),
- coords(3, 12), "foobah")
- em.getRegionToBuffer()
- self.assertEqual(len(em.extractedLines), 1)
- self.assertEqual(em.extractedLines[0], "pass\n")
-
- def test_getsSingleLinePassStatementWhenWholeLineIsHighlighted(self):
- src=trimLines("""
- class MyClass:
- def myMethod(self):
- pass
- """)
- sourcenode = createAST(src)
- em = ExtractMethod(sourcenode, coords(3, 0),
- coords(3, 12), "foobah")
- em.getRegionToBuffer()
- self.assertEqual(len(em.extractedLines), 1)
- self.assertEqual(em.extractedLines[0], "pass\n")
-
-
- def test_getsMultiLineRegionWhenJustRegionIsHighlighted(self):
- src=trimLines("""
- class MyClass:
- def myMethod(self):
- print 'hello'
- pass
- """)
- region=trimLines("""
- print 'hello'
- pass
- """)
- sourcenode = createAST(src)
- em = ExtractMethod(sourcenode, coords(3, 8),
- coords(4, 12), "foobah")
- em.getRegionToBuffer()
- self.assertEqual(em.extractedLines, region.splitlines(1))
-
- def test_getsMultiLineRegionWhenRegionLinesAreHighlighted(self):
- src=trimLines("""
- class MyClass:
- def myMethod(self):
- print 'hello'
- pass
-
- """)
- region=trimLines("""
- print 'hello'
- pass
- """)
- sourcenode = createAST(src)
- em = ExtractMethod(sourcenode, coords(3, 0),
- coords(5, 0), "foobah")
- em.getRegionToBuffer()
- self.assertEqual(em.extractedLines, region.splitlines(1))
-
- def test_getsHighlightedSubstringOfLine(self):
- src=trimLines("""
- class MyClass:
- def myMethod(self):
- if a == 3:
- pass
- """)
- region=trimLines("""
- a == 3
- """)
- sourcenode = createAST(src)
- em = ExtractMethod(sourcenode, coords(3, 11),
- coords(3, 17), "foobah")
- em.getRegionToBuffer()
- self.assertEqual(em.extractedLines, region.splitlines(1))
-
-
-class TestGetTabwidthOfParentFunction(BRMTestCase):
- def test_getsTabwidthForSimpleMethod(self):
- src=trimLines("""
- class MyClass:
- def myMethod(self):
- pass
- """)
- sourcenode = createAST(src)
- em = ExtractMethod(sourcenode, coords(3, 11),
- coords(3, 17), "foobah")
- self.assertEqual(em.getTabwidthOfParentFunction(), 4)
-
- def test_getsTabwidthForFunctionAtRootScope(self):
- src=trimLines("""
- def myFn(self):
- pass
- """)
- sourcenode = createAST(src)
- em = ExtractMethod(sourcenode, coords(2, 0),
- coords(2, 9), "foobah")
- self.assertEqual(em.getTabwidthOfParentFunction(), 0)
-
-
-if __name__ == "__main__":
- unittest.main()
--- a/vim/sadness/bike/bike/refactor/test_extractVariable.py Thu Feb 10 17:11:26 2011 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,40 +0,0 @@
-#!/usr/bin/env python
-import setpath
-import unittest
-from bike.testutils import *
-from bike.refactor.extractVariable import coords, extractLocalVariable
-
-class TestExtractLocalVariable(BRMTestCase):
- def test_worksOnSimpleCase(self):
- srcBefore=trimLines("""
- def foo():
- print 3 + 2
- """)
- srcAfter=trimLines("""
- def foo():
- a = 3 + 2
- print a
- """)
- sourcenode = createAST(srcBefore)
- extractLocalVariable(tmpfile,coords(2,10),coords(2,15),'a')
- self.assertEqual(sourcenode.getSource(),srcAfter)
-
- def test_worksIfCoordsTheWrongWayRound(self):
- srcBefore=trimLines("""
- def foo():
- print 3 + 2
- """)
- srcAfter=trimLines("""
- def foo():
- a = 3 + 2
- print a
- """)
- sourcenode = createAST(srcBefore)
- extractLocalVariable(tmpfile,coords(2,15),coords(2,10),'a')
- self.assertEqual(sourcenode.getSource(),srcAfter)
-
-
-if __name__ == "__main__":
- unittest.main()
-
-
--- a/vim/sadness/bike/bike/refactor/test_inlineVariable.py Thu Feb 10 17:11:26 2011 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,114 +0,0 @@
-#!/usr/bin/env python
-import setpath
-import unittest
-from bike.testutils import trimLines,createAST, BRMTestCase
-from inlineVariable import inlineLocalVariable_old
-
-class TestInlineLocalVariable(BRMTestCase):
-
- def test_worksWhenUserDoesItAgainstReference(self):
- srcBefore=r"""
- def foo():
- b = 'hello'
- print b
- """
- srcAfter=r"""
- def foo():
- print 'hello'
- """
-
- self.helper( srcBefore, 3, 10, srcAfter )
-
- def test_worksWhenInlinedCodeIsOverTwoLines(self):
- srcBefore=r"""
- def foo():
- b = 3 + \
- 2
- print b
- """
-
- srcAfter=r"""
- def foo():
- print 3 + \
- 2
- """
-
- self.helper(srcBefore, 2, 4, srcAfter)
-
- ''' Needs Adding Again
- def test_addsBracketsWhenInlinedCodeHasPresidenceOverSurroundingCode(self):
- srcBefore=trimLines(r"""
- def foo():
- b = 3 + 2
- print 3 * b
- """)
- srcAfter=trimLines(r"""
- def foo():
- print 3 * (3 + 2)
- """)
- assert 0
- '''
-
- def test_worksWithMultipleInstancesOfVariableOnLine(self):
- srcBefore=r"""
- def foo():
- x = 11
- print x, x
- """
-
- srcAfter=r"""
- def foo():
- print 11, 11
- """
-
- self.helper(srcBefore, 2, 4, srcAfter)
-
- def test_worksWithMultipleMultilineCode(self):
- srcBefore=r"""
- def foo():
- b = 3 + \
- 2
- print b
- print b
- """
-
- srcAfter=r"""
- def foo():
- print 3 + \
- 2
- print 3 + \
- 2
- """
-
- self.helper(srcBefore, 2, 4, srcAfter)
-
- ''' Can't do this without some hairy logic to deduce how to inline
- the variables. E.g. how do you inline a,b = foo() ?
-
- def test_handlesTupleAssignment(self):
- srcBefore=r"""
- def foo():
- x, y = 1, 2
- print x
- print y
- """
-
- srcAfter=r"""
- def foo():
- y = 2
- print 1
- print y
- """
-
- self.helper(srcBefore, 2, 4, srcAfter)
- '''
-
-
- def helper(self, srcBefore, y, x, srcAfter):
- sourcenode = createAST(trimLines(srcBefore))
- inlineLocalVariable_old(sourcenode,y,x)
- self.assertEqual(sourcenode.getSource(),trimLines(srcAfter))
-
-if __name__ == "__main__":
- unittest.main()
-
--- a/vim/sadness/bike/bike/refactor/test_moveToModule.py Thu Feb 10 17:11:26 2011 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,241 +0,0 @@
-#!/usr/bin/env python
-import setpath
-from bike.testutils import *
-from bike.transformer.save import save
-
-from moveToModule import *
-
-class TestMoveClass(BRMTestCase):
- def test_movesTheText(self):
- src1=trimLines("""
- def before(): pass
- class TheClass:
- pass
- def after(): pass
- """)
- src1after=trimLines("""
- def before(): pass
- def after(): pass
- """)
- src2after=trimLines("""
- class TheClass:
- pass
- """)
-
- try:
- createPackageStructure(src1, "")
- moveClassToNewModule(pkgstructureFile1,2,
- pkgstructureFile2)
- save()
- self.assertEqual(src1after,file(pkgstructureFile1).read())
- self.assertEqual(src2after,file(pkgstructureFile2).read())
- finally:
- removePackageStructure()
-
-class TestMoveFunction(BRMTestCase):
- def test_importsNameReference(self):
- src1=trimLines("""
- a = 'hello'
- def theFunction(self):
- print a
- """)
- src2after=trimLines("""
- from a.foo import a
- def theFunction(self):
- print a
- """)
- self.helper(src1, src2after)
-
-
-
- def test_importsExternalReference(self):
- src0=("""
- a = 'hello'
- """)
- src1=trimLines("""
- from top import a
- def theFunction(self):
- print a
- """)
- src2after=trimLines("""
- from top import a
- def theFunction(self):
- print a
- """)
- try:
- createPackageStructure(src1, "", src0)
- moveFunctionToNewModule(pkgstructureFile1,2,
- pkgstructureFile2)
- save()
- self.assertEqual(src2after,file(pkgstructureFile2).read())
- finally:
- removePackageStructure()
-
- def test_doesntImportRefCreatedInFunction(self):
- src1=trimLines("""
- def theFunction(self):
- a = 'hello'
- print a
- """)
- src2after=trimLines("""
- def theFunction(self):
- a = 'hello'
- print a
- """)
-
- self.helper(src1, src2after)
-
-
- def test_doesntImportRefCreatedInFunction(self):
- src1=trimLines("""
- def theFunction(self):
- a = 'hello'
- print a
- """)
- src2after=trimLines("""
- def theFunction(self):
- a = 'hello'
- print a
- """)
-
- self.helper(src1, src2after)
-
-
- def test_addsImportStatementToOriginalFileIfRequired(self):
- src1=trimLines("""
- def theFunction(self):
- pass
- b = theFunction()
- """)
-
- src1after=trimLines("""
- from a.b.bah import theFunction
- b = theFunction()
- """)
- try:
- createPackageStructure(src1,"")
- moveFunctionToNewModule(pkgstructureFile1,1,
- pkgstructureFile2)
- save()
- self.assertEqual(src1after,file(pkgstructureFile1).read())
- finally:
- removePackageStructure()
-
- def test_updatesFromImportStatementsInOtherModules(self):
- src0=trimLines("""
- from a.foo import theFunction
- print theFunction()
- """)
- src1=trimLines("""
- def theFunction(self):
- pass
- """)
-
- src0after=trimLines("""
- from a.b.bah import theFunction
- print theFunction()
- """)
- try:
- createPackageStructure(src1,"",src0)
- moveFunctionToNewModule(pkgstructureFile1,1,
- pkgstructureFile2)
- save()
- self.assertEqual(src0after,file(pkgstructureFile0).read())
- finally:
- removePackageStructure()
-
- def test_updatesFromImportMultiplesInOtherModules(self):
- src0=trimLines("""
- from a.foo import something,theFunction,somethingelse #comment
- print theFunction()
- """)
- src1=trimLines("""
- def theFunction(self):
- pass
- something = ''
- somethingelse = 0
- """)
-
- src0after=trimLines("""
- from a.foo import something,somethingelse #comment
- from a.b.bah import theFunction
- print theFunction()
- """)
- try:
- createPackageStructure(src1,"",src0)
- moveFunctionToNewModule(pkgstructureFile1,1,
- pkgstructureFile2)
- save()
- self.assertEqual(src0after,file(pkgstructureFile0).read())
- finally:
- removePackageStructure()
-
- def test_updatesFromImportMultiplesInTargetModule(self):
- src0=trimLines("""
- from a.foo import something,theFunction,somethingelse #comment
- print theFunction()
- """)
- src1=trimLines("""
- def theFunction(self):
- pass
- something = ''
- somethingelse = 0
- """)
-
- src0after=trimLines("""
- from a.foo import something,somethingelse #comment
- print theFunction()
- def theFunction(self):
- pass
- """)
- try:
- createPackageStructure(src1,"",src0)
- moveFunctionToNewModule(pkgstructureFile1,1,
- pkgstructureFile0)
- save()
- #print file(pkgstructureFile0).read()
- self.assertEqual(src0after,file(pkgstructureFile0).read())
- finally:
- removePackageStructure()
-
-
- def test_updatesFromImportInTargetModule(self):
- src0=trimLines("""
- from a.foo import theFunction
- print theFunction()
- """)
- src1=trimLines("""
- def theFunction(self):
- pass
- """)
-
- src0after=trimLines("""
- print theFunction()
- def theFunction(self):
- pass
- """)
- try:
- createPackageStructure(src1,"",src0)
- moveFunctionToNewModule(pkgstructureFile1,1,
- pkgstructureFile0)
- save()
- self.assertEqual(src0after,file(pkgstructureFile0).read())
- finally:
- removePackageStructure()
-
-
-
- def helper(self, src1, src2after):
- try:
- createPackageStructure(src1, "")
- moveFunctionToNewModule(pkgstructureFile1,2,
- pkgstructureFile2)
- save()
- self.assertEqual(src2after,file(pkgstructureFile2).read())
- finally:
- removePackageStructure()
-
-
-
-if __name__ == "__main__":
- unittest.main()
--- a/vim/sadness/bike/bike/refactor/test_rename.py Thu Feb 10 17:11:26 2011 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,35 +0,0 @@
-#!/usr/bin/env python
-import setpath
-import unittest
-from bike import testdata
-from rename import rename
-from bike.testutils import *
-
-class TestRenameTemporary(BRMTestCase):
- def test_renamesSimpleReferencesGivenAssignment(self):
- src=trimLines("""
- def foo():
- a = 3
- print a
- """)
- srcAfter=trimLines("""
- def foo():
- b = 3
- print b
- """)
- src = self.helper(src,"",2,4,"b")
- self.assertEqual(srcAfter,src)
-
- def helper(self, src, classsrc, line, col, newname):
- try:
- createPackageStructure(src,classsrc)
- filename = pkgstructureFile1
- rename(filename,line,col,newname)
- # modify me once save is moved
- #return readFile(filename)
- from bike.transformer.save import outputqueue
- return outputqueue[filename]
- finally:
- removePackageStructure()
-if __name__ == "__main__":
- unittest.main()
--- a/vim/sadness/bike/bike/refactor/test_renameClass.py Thu Feb 10 17:11:26 2011 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,257 +0,0 @@
-#!/usr/bin/env python
-import setpath
-import unittest
-from rename import rename
-from bike.transformer.save import save
-from bike.testutils import *
-import compiler
-
-class RenameClassTests:
-
- def testRenamesClassDcl(self):
- srcBefore=trimLines("""
- class TheClass:
- def theMethod():
- pass
- """)
- srcAfter=trimLines("""
- class NewName:
- def theMethod():
- pass
- """)
-
- src = self.rename(srcBefore, 1,6,"NewName")
- self.assertEqual(srcAfter,src)
-
- # i.e. a = TheClass()
- def testRenamesClassReference(self):
- srcBefore=trimLines("""
- class TheClass:
- pass
- a = TheClass()
- """)
- srcAfter=trimLines("""
- class NewName:
- pass
- a = NewName()
- """)
- src = self.rename(srcBefore, 1,6,"NewName")
- self.assertEqual(srcAfter,src)
-
- # i.e. a = TheClass.TheClass()
- def testRenamesClassReferenceWhenScopeIsSameNameAsClass(self):
- srcBefore = trimLines("""
- class TheClass:
- class TheClass:
- pass
- a = TheClass.TheClass()
- """)
- srcAfter=trimLines("""
- class TheClass:
- class NewName:
- pass
- a = TheClass.NewName()
- """)
- src = self.rename(srcBefore, 2,10, "NewName")
- self.assertEqual(srcAfter,src)
-
- # i.e. a = TheClass.TheClass()
- def testRenamesClassReferenceWhenChildIsSameNameAsClass(self):
- srcBefore = trimLines("""
- class TheClass:
- class TheClass:
- pass
- a = TheClass.TheClass()
- """)
- srcAfter=trimLines("""
- class NewName:
- class TheClass:
- pass
- a = NewName.TheClass()
- """)
- src = self.rename(srcBefore, 1,6,"NewName")
- self.assertEqual(srcAfter,src)
-
-
- # a = TheClass() + TheClass()
- def testRenamesClassReferenceWhenTwoRefsInTheSameLine(self):
- srcBefore=trimLines("""
- class TheClass:
- pass
- a = TheClass() + TheClass()
- """)
- srcAfter=trimLines("""
- class NewName:
- pass
- a = NewName() + NewName()
- """)
- src = self.rename(srcBefore,1,6, "NewName")
- self.assertEqual(srcAfter,src)
-
- def testRenamesClassReferenceInInstanceCreation(self):
- srcBefore=trimLines("""
- class TheClass:
- def theMethod(self): pass
- TheClass().theMethod()
- """)
- srcAfter=trimLines("""
- class NewName:
- def theMethod(self): pass
- NewName().theMethod()
- """)
- src = self.rename(srcBefore,1,6,"NewName")
- self.assertEqual(srcAfter,src)
-
- # i.e. if renaming TheClass, shouldnt rename a.b.c.TheClass
- def testDoesntRenameBugusClassReferenceOnEndOfGetattrNest(self):
- srcBefore=trimLines("""
- class TheClass:
- pass
- a.b.c.TheClass # Shouldn't be renamed
- """)
- srcAfter=trimLines("""
- class NewName:
- pass
- a.b.c.TheClass # Shouldn't be renamed
- """)
- src = self.rename(srcBefore,1,6,"NewName")
- self.assertEqual(srcAfter,src)
-
- def testRenamesClassRefUsedInExceptionRaise(self):
- srcBefore=trimLines("""
- class TheClass:
- pass
- raise TheClass, \"hello mum\"
- """)
- srcAfter=trimLines("""
- class NewName:
- pass
- raise NewName, \"hello mum\"
- """)
- src = self.rename(srcBefore, 1,6, "NewName")
- self.assertEqual(srcAfter,src)
-
- def testRenamesClassReferenceNameInInheritenceSpec(self):
- srcBefore=trimLines("""
- class TheClass:
- pass
- class DerivedClass(TheClass):
- pass
- """)
- srcAfter=trimLines("""
- class NewName:
- pass
- class DerivedClass(NewName):
- pass
- """)
- src = self.rename(srcBefore, 1,6, "NewName")
- self.assertEqual(srcAfter,src)
-
-
-
-class RenameClassTests_importsClass:
-
- def testRenamesClassReferenceInInstanceCreationWithFQN(self):
- srcBefore=trimLines("""
- import b.bah
- def foo():
- a = b.bah.TheClass()
- """)
- srcAfter=trimLines("""
- import b.bah
- def foo():
- a = b.bah.NewName()
- """)
- src = self.renameClass(srcBefore,"NewName")
- self.assertEqual(srcAfter,src)
-
- def testRenamesClassReferencesInInheritenceSpecs(self):
-
- srcBefore=trimLines("""
- import b
- class DerivedClass(b.bah.TheClass):
- pass
- """)
- srcAfter=trimLines("""
- import b
- class DerivedClass(b.bah.NewName):
- pass
- """)
- src = self.renameClass(srcBefore,"NewName")
- self.assertEqual(srcAfter,src)
-
- def testRenamesFromImportReferenceWhenInBodyOfClass(self):
- srcBefore=trimLines("""
- class AnotherClass:
- from b.bah import TheClass
- TheClass.baz = 0
- """)
- srcAfter=trimLines("""
- class AnotherClass:
- from b.bah import NewName
- NewName.baz = 0
- """)
- src = self.renameClass(srcBefore,"NewName")
- self.assertEqual(srcAfter,src)
-
-
- def testRenamesReferenceToClassImportedInSameClassScope(self):
- srcBefore=trimLines("""
- class AnotherClass:
- from b.bah import TheClass
- TheClass.baz = 0
- """)
- srcAfter=trimLines("""
- class AnotherClass:
- from b.bah import NewName
- NewName.baz = 0
- """)
- src = self.renameClass(srcBefore,"NewName")
- self.assertEqual(srcAfter,src)
-
- def testRenamesReferenceToClassImportedWithFromImportStar(self):
- srcBefore=trimLines("""
- from a.b.bah import *
- a = TheClass()
- """)
- srcAfter=trimLines("""
- from a.b.bah import *
- a = NewName()
- """)
- src = self.renameClass(srcBefore,"NewName")
- self.assertEqual(srcAfter,src)
-
-class TestRenameClass(BRMTestCase, RenameClassTests):
-
- def rename(self, src, line, col, newname):
- createPackageStructure(src,"pass")
- rename(pkgstructureFile1,line,col, newname)
- save()
- return file(pkgstructureFile1).read()
-
-
-class TestRenameClassReferenceWithDirectoryStructure(BRMTestCase,
- RenameClassTests_importsClass):
-
- def renameClass(self, src, newname):
- createPackageStructure(src,TheClassTestdata)
- rename(pkgstructureFile2,1,6, newname)
- save()
- return file(pkgstructureFile1).read()
-
-
-TheClassTestdata = trimLines("""
-class TheClass:
- def theMethod(self):
- pass
- def differentMethod(self):
- pass
-
-class DifferentClass:
- def theMethod(self):
- pass
-""")
-
-
-if __name__ == "__main__":
- unittest.main()
--- a/vim/sadness/bike/bike/refactor/test_renameFunction.py Thu Feb 10 17:11:26 2011 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,118 +0,0 @@
-#!/usr/bin/env python
-import setpath
-import unittest
-from rename import rename
-from bike import testdata
-from bike.testutils import *
-from bike.transformer.save import save
-import compiler
-
-class RenameFunctionTests:
- def runTarget(self, src, klassfqn, newname):
- # see concrete subclasses for implementation
- pass
-
- def testRenamesFunctionDcl(self):
- srcBefore=trimLines("""
- def theFunction():
- pass
- """)
- srcAfter=trimLines("""
- def newName():
- pass
- """)
- src = self.rename(srcBefore,1,4,"newName")
- self.assertEqual(srcAfter,src)
-
- def testDoesntBarfWhenFunctionIncludesBrackettedExpression(self):
- srcBefore=trimLines("""
- def theFunction():
- return ('\\n').strip()
- """)
- srcAfter=trimLines("""
- def newName():
- return ('\\n').strip()
- """)
- src = self.rename(srcBefore,1,4, "newName")
- self.assertEqual(srcAfter,src)
-
-
-
-
-class RenameFunctionTests_importsFunction:
-
- def testRenamesImportedFunctionReference(self):
- srcBefore=trimLines("""
- import b.bah
- b.bah.theFunction()
- """)
- srcAfter=trimLines("""
- import b.bah
- b.bah.newName()
- """)
- src = self.renameFunction(srcBefore,"newName")
- self.assertEqual(srcAfter,src)
-
- def testRenamesFunctionReferenceImportedWithFromClause(self):
- srcBefore=trimLines("""
- from b.bah import theFunction
- theFunction()
- """)
- srcAfter=trimLines("""
- from b.bah import newName
- newName()
- """)
- src = self.renameFunction(srcBefore,"newName")
- self.assertEqual(srcAfter,src)
-
- def testRenamesFunctionRefInImportClause(self):
- srcBefore=trimLines("""
- import b.bah
- b.bah.theFunction()
- """)
- srcAfter=trimLines("""
- import b.bah
- b.bah.newName()
- """)
- src = self.renameFunction(srcBefore,"newName")
- self.assertEqual(srcAfter,src)
-
-
- def testRenamesFunctionRefInImportFromClause(self):
- srcBefore=trimLines("""
- from b.bah import theFunction
- theFunction()
- """)
- srcAfter=trimLines("""
- from b.bah import newName
- newName()
- """)
- src = self.renameFunction(srcBefore,"newName")
- self.assertEqual(srcAfter,src)
-
-
-
-class TestRenameFunction(BRMTestCase, RenameFunctionTests):
- def rename(self, src, line, col, newname):
- writeTmpTestFile(src)
- rename(tmpfile,line,col, newname)
- save()
- return file(tmpfile).read()
-
-
-class TestRenameFunctionReferenceWithDirectoryStructure(BRMTestCase, RenameFunctionTests_importsFunction):
-
- def renameFunction(self, src, newname):
- createPackageStructure(src,FunctionTestdata)
- rename(pkgstructureFile2,1,4, newname)
- save()
- return file(pkgstructureFile1).read()
-
-FunctionTestdata = trimLines("""
-def theFunction():
- pass
-""")
-
-
-if __name__ == "__main__":
- unittest.main()
--- a/vim/sadness/bike/bike/refactor/test_renameMethod.py Thu Feb 10 17:11:26 2011 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,710 +0,0 @@
-#!/usr/bin/env python
-import setpath
-import unittest
-from rename import rename
-import compiler
-from bike import testdata
-
-from bike.testutils import*
-
-from bike.transformer.save import save
-
-class RenameMethodTests:
-
- def test_renamesTheMethod(self):
- srcBefore=trimLines("""
- class TheClass:
- def theMethod(self):
- pass
- """)
- srcAfter=trimLines("""
- class TheClass:
- def newName(self):
- pass
- """)
- src = self.rename(srcBefore,2,8,"newName")
- self.assertEqual(srcAfter,src)
-
- def test_doesntRenameMethodOfSameNameOnOtherClasses(self):
- srcBefore=trimLines("""
- class TheClass:
- def theMethod(self):
- pass
- class b:
- def theMethod(self):
- pass
- """)
- srcAfter=trimLines("""
- class TheClass:
- def newName(self):
- pass
- class b:
- def theMethod(self):
- pass
- """)
- src = self.rename(srcBefore,2,8,"newName")
- self.assertEqual(srcAfter,src)
-
- def test_doesntRenameOtherMethodsOfSameClass(self):
- srcBefore=trimLines("""
- class TheClass:
- def theMethod(self):
- a=b
- def aMethod(self):
- pass
- """)
- srcAfter=trimLines("""
- class TheClass:
- def newName(self):
- a=b
- def aMethod(self):
- pass
- """)
- src = self.rename(srcBefore,2,8,"newName")
- self.assertEqual(srcAfter,src)
-
- def test_renamesMethodWhenClassNestedInFunction(self):
- srcBefore=trimLines("""
- def theFunction():
- class TheClass:
- def theMethod(self):
- pass
- """)
- srcAfter=trimLines("""
- def theFunction():
- class TheClass:
- def newName(self):
- pass
- """)
- src = self.rename(srcBefore,3,12,"newName")
- self.assertEqual(srcAfter,src)
-
- def test_doesntBarfOnInheritanceHierarchies(self):
- srcBefore=trimLines("""
- from b.bah import DifferentClass
- class TheClass(foo.bah):
- def theMethod(self):
- pass
- """)
- src = self.rename(srcBefore,2,8,"newName")
-
- def test_renamesMethodWhenMethodCallFromOtherMethodInSameClass(self):
- srcBefore=trimLines("""
- class TheClass:
- def theMethod(self):
- pass
- def anotherMethod(self):
- self.theMethod()
- """)
- srcAfter=trimLines("""
- class TheClass:
- def newName(self):
- pass
- def anotherMethod(self):
- self.newName()
- """)
- src = self.rename(srcBefore,2,8,"newName")
- self.assertEqual(srcAfter,src)
-
- def test_doesntBarfOnNestedClasses(self):
- srcBefore=trimLines("""
- class TheClass:
- class AnotherClass:
- pass
- def theMethod(self):
- pass
- """)
- src = self.rename(srcBefore,4,8,"newName")
-
- def test_renamesMethodWhenBaseClassesArentInAST(self):
- srcBefore=trimLines("""
- class TheClass(notInAst):
- def theMethod(self):
- pass
- """)
- srcAfter=trimLines("""
- class TheClass(notInAst):
- def newName(self):
- pass
- """)
- src = self.rename(srcBefore,2,8,"newName")
- self.assertEqual(srcAfter,src)
-
- def test_renamesMethodInRelatedClasses(self):
- srcBefore=trimLines("""
- class root:
- def theMethod(self):
- pass
-
- class a(root):
- def theMethod(self):
- pass
-
- class b(root):
- pass
-
- class TheClass(b):
- def theMethod(self):
- pass
- """)
- srcAfter=trimLines("""
- class root:
- def newName(self):
- pass
-
- class a(root):
- def newName(self):
- pass
-
- class b(root):
- pass
-
- class TheClass(b):
- def newName(self):
- pass
- """)
- src = self.rename(srcBefore,13,8,"newName")
- self.assertEqual(srcAfter,src)
-
-
- def test_renameMethodDoesntBarfOnNoneAsDefaultArgToMethod(self):
- srcBefore=trimLines("""
- class TheClass:
- def theMethod(self, root, flist, stack=None):
- pass
- """)
- src = self.rename(srcBefore,2,8,"newName")
-
-
-
-class RenameMethodTests_ImportsClass:
- def test_renamesMethodOnDerivedClassInstance(self):
- srcBefore = trimLines("""
- from b.bah import TheClass as BaseClass
-
- class DerivedClass(BaseClass):
- pass
-
- class DerivedDerivedClass(DerivedClass):
- def theMethod(self):
- print 'hello'
- """)
- srcAfter = trimLines("""
- from b.bah import TheClass as BaseClass
-
- class DerivedClass(BaseClass):
- pass
-
- class DerivedDerivedClass(DerivedClass):
- def newName(self):
- print 'hello'
- """)
- src = self.renameMethod(srcBefore, 2,8, "newName")
- self.assertEqual(srcAfter,src)
-
-class RenameMethodReferenceTests:
- # Generic tests. These tests are designed to be run in the context of a ui
- # and in a package hierarchy structure
-
- def test_doesntBarfWhenConfrontedWithComplexReturnTypes(self):
- src = trimLines("""
- import a
- class TheClass:
- def theMethod(self):
- pass
-
- def bah():
- return a[35]
-
- b = bah()
- b.theMethod()
- """)
- self.rename(src,3,8,"newName")
-
- def test_doesntbarfWhenCallMadeOnInstanceReturnedFromFnCall(self):
- srcBefore=trimLines("""
- from foo import e
- class TheClass:
- def theMethod(self):
- pass
- ast = e().f(src)
- """)
- self.rename(srcBefore,3,8,"newName")
-
- def test_doesntStackOverflowOnRecursiveFunctions(self):
- srcBefore=trimLines("""
- class TheClass:
- def theMethod(self):
- pass
-
- def foo(a):
- return foo(a)
- """)
- self.rename(srcBefore,2,8,"newName")
-
- def test_renamesMethodReferenceOfInstanceCreatedInParentScopeAfterFunction(self):
- srcBefore=trimLines("""
- class TheClass:
- def theMethod(self):
- pass
- a = TheClass()
- def foo():
- a.theMethod()
- """)
- srcAfter=trimLines("""
- class TheClass:
- def newName(self):
- pass
- a = TheClass()
- def foo():
- a.newName()
- """)
- src = self.rename(srcBefore,2,8,"newName")
- self.assertEqual(srcAfter,src)
-
- def test_renamesMethodReferenceOfInstanceObtainedByCallingFunction(self):
- srcBefore=trimLines("""
- class TheClass:
- def theMethod():
- pass
- def foo():
- b = TheClass()
- return b
- a = foo()
- a.theMethod()
- """)
- srcAfter=trimLines("""
- class TheClass:
- def newName():
- pass
- def foo():
- b = TheClass()
- return b
- a = foo()
- a.newName()
- """)
- src = self.rename(srcBefore,2,8,"newName")
- self.assertEqual(srcAfter,src)
-
- def test_renamesMethodReferenceOfInstanceCreatedInAnotherFunction(self):
-
- srcBefore=trimLines("""
- class TheClass:
- def theMethod():
- pass
- def bah():
- return TheClass()
- def foo():
- a = bah()
- a.theMethod()
- """)
- srcAfter=trimLines("""
- class TheClass:
- def newName():
- pass
- def bah():
- return TheClass()
- def foo():
- a = bah()
- a.newName()
- """)
- src = self.rename(srcBefore,2,8,"newName")
- self.assertEqual(srcAfter,src)
-
- def test_renamesMethodReferenceOfInstanceCreatedInSubsequentFunction(self):
- srcBefore = trimLines("""
- class TheClass:
- def theMethod():
- pass
- class NotTheClass:
- def theMethod():
- pass
-
- def foo():
- a = bah()
- a.theMethod()
-
- def bah():
- return TheClass()
- """)
- srcAfter=trimLines("""
- class TheClass:
- def newName():
- pass
- class NotTheClass:
- def theMethod():
- pass
-
- def foo():
- a = bah()
- a.newName()
-
- def bah():
- return TheClass()
- """)
- src = self.rename(srcBefore,2,8,"newName")
- self.assertEqual(srcAfter,src)
-
- def test_renamesMethodReferenceOnInstanceThatIsAnAttributeOfSelf(self):
- srcBefore = trimLines("""
- class TheClass:
- def theMethod(self):
- pass
-
- class AnotherClass:
- def __init__(self):
- self.a = TheClass()
- def anotherFn(self):
- self.a.theMethod()
- """)
- srcAfter=trimLines("""
- class TheClass:
- def newName(self):
- pass
-
- class AnotherClass:
- def __init__(self):
- self.a = TheClass()
- def anotherFn(self):
- self.a.newName()
- """)
- src = self.rename(srcBefore,2,8,"newName")
- self.assertEqual(srcAfter,src)
-
- def test_doesntBarfOnGetattrThatItCantDeduceTypeOf(self):
- srcBefore=trimLines("""
- class TheClass:
- def theMethod(self):
- pass
- a = TheClass
-
- a.b.bah = 3
- """)
- self.rename(srcBefore,2,8,"newName")
-
-
-class RenameMethodReferenceTests_ImportsClass:
-
- def test_renamesReferenceOfClassImportedAsAnotherName(self):
- srcBefore=trimLines("""
- from b.bah import TheClass as MyTheClass
- def foo():
- a = MyTheClass()
- a.theMethod()
- """)
- srcAfter=trimLines("""
- from b.bah import TheClass as MyTheClass
- def foo():
- a = MyTheClass()
- a.newName()
- """)
- src = self.renameMethod(srcBefore,2,8, "newName")
- self.assertEqual(srcAfter,src)
-
- def test_renamesReferenceWhenObjectCreationAndReferenceInModuleScope(self):
- srcBefore=trimLines("""
- from b.bah import TheClass
- a = TheClass()
- a.theMethod()
- """)
- srcAfter=trimLines("""
- from b.bah import TheClass
- a = TheClass()
- a.newName()
- """)
- src = self.renameMethod(srcBefore, 2,8, "newName")
- self.assertEqual(srcAfter,src)
-
-
- def test_renamesReferenceWhenObjectCreatedInSameFunctionAsReference(self):
- srcBefore=trimLines("""
- import b.bah
- def foo():
- a = b.bah.TheClass()
- a.theMethod()
- """)
- srcAfter=trimLines("""
- import b.bah
- def foo():
- a = b.bah.TheClass()
- a.newName()
- """)
- src = self.renameMethod(srcBefore, 2,8, "newName")
- self.assertEqual(srcAfter,src)
-
- def test_doesntrenameDifferentMethodReferenceWhenObjectCreatedInSameScope(self):
- srcBefore=trimLines("""
- import b.bah.TheClass
- def foo():
- a = b.bah.TheClass()
- a.theMethod()
- """)
- src = self.renameMethod(srcBefore, 4,8, "newName")
- self.assertEqual(srcBefore,src)
-
- def test_doesntrenameMethodReferenceWhenDifferentObjectCreatedInSameScope(self):
- srcBefore=trimLines("""
- import b.bah.TheClass
- def foo():
- a = b.bah.TheClass()
- a.theMethod()
- """)
- src = self.renameMethod(srcBefore, 8,8,"newName")
- self.assertEqual(srcBefore,src)
-
- def test_renamesReferenceOfImportedClass(self):
- srcBefore=trimLines("""
- import b.bah
-
- def foo():
- a = b.bah.TheClass()
- a.theMethod()
- """)
- srcAfter=trimLines("""
- import b.bah
-
- def foo():
- a = b.bah.TheClass()
- a.newName()
- """)
- src = self.renameMethod(srcBefore, 2,8, "newName")
- self.assertEqual(srcAfter,src)
-
- def test_doesntRenameReferenceOfDifferentImportedClass(self):
- srcBefore=trimLines("""
- from b.bah import DifferentClass
-
- def foo():
- a = b.bah.TheClass()
- a.theMethod()
- """)
- src = self.renameMethod(srcBefore, 8,8,
- "newName")
- self.assertEqual(srcBefore,src)
-
- def test_renamesReferenceOfClassImportedWithFromClause(self):
- srcBefore=trimLines("""
- from b.bah import TheClass
-
- def foo():
- a = TheClass()
- a.theMethod()
- """)
- srcAfter=trimLines("""
- from b.bah import TheClass
-
- def foo():
- a = TheClass()
- a.newName()
- """)
- src = self.renameMethod(srcBefore, 2,8, "newName")
- self.assertEqual(srcAfter,src)
-
- def test_doesntrenameReferenceOfClassImportedWithDifferentAsClause(self):
- srcBefore = trimLines("""
- from b.bah import TheClass as MyClass
-
- def foo():
- a = TheClass()
- a.theMethod()
- """)
-
- src = self.renameMethod(srcBefore, 2,8, "newName")
- self.assertEqual(srcBefore,src)
-
- def test_renamesReferenceOfClassImportedWithFromFooImportStar(self):
- srcBefore=trimLines("""
- from b.bah import *
- a = TheClass()
- a.theMethod()
- """)
- srcAfter=trimLines("""
- from b.bah import *
- a = TheClass()
- a.newName()
- """)
- src = self.renameMethod(srcBefore, 2,8, "newName")
- self.assertEqual(srcAfter,src)
-
- def test_renamesMethodReferenceOfInstanceCreatedInParentScope(self):
- srcBefore=trimLines("""
- from b.bah import TheClass
- a = TheClass()
- def foo():
- a.theMethod()
- """)
- srcAfter=trimLines("""
- from b.bah import TheClass
- a = TheClass()
- def foo():
- a.newName()
- """)
- src = self.renameMethod(srcBefore, 2,8, "newName")
- self.assertEqual(srcAfter,src)
-
- def test_doesntRenameMethodWhenObjectCreatedInChildScopeToMethodReference(self):
- srcBefore = trimLines("""
- from b.bah import TheClass
- a = AnotherClass()
- def foo():
- a = TheClass()
- a.theMethod()
- """)
- src = self.renameMethod(srcBefore, 2,8, "newName")
- self.assertEqual(srcBefore,src)
-
- def test_renamesReferenceOnDerivedClassInstance(self):
- srcBefore=trimLines("""
- import b
- class DerivedClass(b.bah.TheClass):
- pass
- class DerivedDerivedClass(DerivedClass):
- pass
- theInstance = DerivedDerivedClass()
- theInstance.theMethod()
- """)
- srcAfter=trimLines("""
- import b
- class DerivedClass(b.bah.TheClass):
- pass
- class DerivedDerivedClass(DerivedClass):
- pass
- theInstance = DerivedDerivedClass()
- theInstance.newName()
- """)
- src = self.renameMethod(srcBefore, 2,8, "newName")
- self.assertEqual(srcAfter,src)
-
-
-
-# tests that cover stuff not renamed automatically
-# (I.e. are renamed after user manually expresses desire to do so)
-class RenameMethodAfterPromptTests:
- def test_renamesReferenceWhenMethodCallDoneOnInstanceCreation(self):
-
- srcBefore=trimLines("""
- class TheClass:
- def theMethod(self): pass
- TheClass().theMethod()
- """)
- srcAfter=trimLines("""
- class TheClass:
- def newName(self): pass
- TheClass().newName()
- """)
- src = self.renameMethod(srcBefore,2,8, "newName")
- self.assertEqual(srcAfter,src)
-
-
- def test_renamesReferenceInMiddleOfBiggerCompoundCall(self):
- srcBefore = trimLines("""
- class TheClass:
- def theMethod(self): return AnotherClass()
- TheClass().theMethod().anotherMethod()
- """)
- srcAfter=trimLines("""
- class TheClass:
- def newName(self): return AnotherClass()
- TheClass().newName().anotherMethod()
- """)
- src = self.renameMethod(srcBefore, 2,8, "newName")
- self.assertEqual(srcAfter,src)
-
-
-class TestRenameMethodWithSingleModule(BRMTestCase, RenameMethodTests, RenameMethodReferenceTests):
- # template method
- def rename(self, src, line, col, newname):
- try:
- createPackageStructure(src, "pass")
- rename(pkgstructureFile1,line,col,newname)
- save()
- return file(pkgstructureFile1).read()
- finally:
- removePackageStructure()
-
-
-class TestRenameMethodWithDirectoryStructure(RenameMethodTests, RenameMethodReferenceTests, BRMTestCase):
-
- def rename(self, src, line, col, newname):
- try:
- createPackageStructure("pass",src)
- rename(pkgstructureFile2,line,col,newname)
- save()
- return file(pkgstructureFile2).read()
- finally:
- removePackageStructure()
-
-
-class TestRenameMethodReferenceWithDirectoryStructure(BRMTestCase, RenameMethodTests_ImportsClass, RenameMethodReferenceTests_ImportsClass):
-
- def renameMethod(self, src, line, col, newname):
- try:
- createPackageStructure(src,MethodTestdata)
- rename(pkgstructureFile2,line,col,newname)
- save()
- return file(pkgstructureFile1).read()
- finally:
- removePackageStructure()
-
-class TestRenameMethodStuffCorrectlyAfterPromptReturnsTrue(BRMTestCase,
- RenameMethodAfterPromptTests):
-
- def callback(self, filename, line, colbegin, colend):
- return 1
-
-
- def renameMethod(self, src, line, col, newname):
- createPackageStructure(src, MethodTestdata)
- rename(pkgstructureFile1,line,col,newname,self.callback)
- save()
- return file(pkgstructureFile1).read()
-
-
-
-class TestDoesntRenameMethodIfPromptReturnsFalse(BRMTestCase):
- def callback(self, filename, line, colbegin, colend):
- return 0
-
- def renameMethod(self, src, line, col, newname):
- createPackageStructure(src, MethodTestdata)
- rename(pkgstructureFile1,line,col,newname,self.callback)
- save()
- return file(pkgstructureFile1).read()
-
- def test_doesntRenameMethodIfPromptReturnsFalse(self):
- srcBefore = trimLines("""
- class TheClass:
- def theMethod(self):
- pass
- b = TheClass()
- b.theMethod()
- a = someFunction()
- a.theMethod()
- """)
- srcAfter=trimLines("""
- class TheClass:
- def newName(self):
- pass
- b = TheClass()
- b.newName()
- a = someFunction()
- a.theMethod()
- """)
- src = self.renameMethod(srcBefore, 2,8, "newName")
- self.assertEqual(srcAfter,src)
-
-
-MethodTestdata = trimLines("""
-class TheClass:
- def theMethod(self):
- pass
- def differentMethod(self):
- pass
-
-class DifferentClass:
- def theMethod(self):
- pass
-""")
-
-if __name__ == "__main__":
- unittest.main()
--- a/vim/sadness/bike/bike/refactor/testall.py Thu Feb 10 17:11:26 2011 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,13 +0,0 @@
-#!/usr/bin/env python
-import setpath
-from test_renameMethod import *
-from test_renameClass import *
-from test_renameFunction import *
-from test_rename import *
-from test_extractMethod import *
-from test_inlineVariable import *
-from test_extractVariable import *
-from test_moveToModule import *
-
-if __name__ == "__main__":
- unittest.main()
--- a/vim/sadness/bike/bike/refactor/utils.py Thu Feb 10 17:11:26 2011 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,24 +0,0 @@
-import re
-
-def getLineSeperator(line):
- if line.endswith("\r\n"):
- linesep = "\r\n" # windoze
- else:
- linesep = line[-1] # mac or unix
- return linesep
-
-
-def getTabWidthOfLine(line):
- match = re.match("\s+",line)
- if match is None:
- return 0
- else:
- return match.end(0)
-
-def reverseCoordsIfWrongWayRound(startcoords,endcoords):
- if(startcoords.line > endcoords.line) or \
- (startcoords.line == endcoords.line and \
- startcoords.column > endcoords.column):
- return endcoords,startcoords
- else:
- return startcoords,endcoords
--- a/vim/sadness/bike/bike/setpath.py Thu Feb 10 17:11:26 2011 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,5 +0,0 @@
-import sys,os
-if not os.path.abspath("..") in sys.path:
- from bike import log
- print >> log.warning, "Appending to the system path. This should only happen in unit tests"
- sys.path.append(os.path.abspath(".."))
--- a/vim/sadness/bike/bike/test_bikefacade.py Thu Feb 10 17:11:26 2011 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,377 +0,0 @@
-#!/usr/bin/env python
-import unittest
-import setpath
-import sys
-
-from bike import testdata
-from bike.testutils import *
-import bike
-from bike.refactor.test_renameFunction import RenameFunctionTests, RenameFunctionTests_importsFunction, FunctionTestdata
-from bike.refactor.test_renameClass import RenameClassTests, RenameClassTests_importsClass, TheClassTestdata
-from bike.refactor.test_renameMethod import RenameMethodTests, RenameMethodTests_ImportsClass, RenameMethodReferenceTests, RenameMethodReferenceTests_ImportsClass, RenameMethodAfterPromptTests, TestDoesntRenameMethodIfPromptReturnsFalse,MethodTestdata
-from bike.refactor import test_extractMethod
-import bikefacade
-from bike import UndoStackEmptyException
-from bike.query.getTypeOf import getTypeOf
-
-class TestPathFunctions(BRMTestCase):
- def test_setCompletePythonPath_removesDuplicates(self):
- origpath = sys.path
- try:
- sys.path = ["foobah"]
- ctx = bike.init()
- ctx._setCompletePythonPath(sys.path[-1])
- self.assertEqual(1,ctx._getCurrentSearchPath().count(sys.path[-1]))
- finally:
- sys.path = origpath
-
-
- def test_setNonLibPathonPath_removesLibDirectories(self):
- origpath = sys.path
- try:
- writeTmpTestFile("pass")
- libdir = os.path.join(sys.prefix,"lib","python"+sys.version[:3])
- sys.path = [libdir,os.path.join(libdir,"site-packages")]
- ctx = bike.init()
- ctx._setNonLibPythonPath(tmproot)
- self.assertEqual([tmproot],ctx._getCurrentSearchPath())
- finally:
- sys.path = origpath
-
-class TestRenameMethodAfterPrompt(BRMTestCase,RenameMethodAfterPromptTests):
- def callback(self, filename, line, colstart, colend):
- return 1
-
- def renameMethod(self, src, line, col, newname):
- writeTmpTestFile(src)
- ctx = bike.init()
- ctx.setRenameMethodPromptCallback(self.callback)
- ctx.renameByCoordinates(tmpfile,line,col,newname)
- ctx.save()
- newsrc = readFile(tmpfile)
- return newsrc
-
-class TestDoesntRenameMethodIfPromptReturnsFalse(TestDoesntRenameMethodIfPromptReturnsFalse):
-
- def callback(self, filename, line, colstart, colend):
- return 0
-
- def renameMethod(self, src, line, col, newname):
- writeTmpTestFile(src)
- ctx = bike.init()
- ctx.setRenameMethodPromptCallback(self.callback)
- ctx.renameByCoordinates(tmpfile,line,col,newname)
- ctx.save()
- newsrc = readFile(tmpfile)
- return newsrc
-
-
-class TestRenameByCoordinates2(RenameMethodTests,RenameMethodReferenceTests, RenameClassTests,RenameFunctionTests,BRMTestCase):
- def rename(self, src, line, col, newname):
- writeTmpTestFile(src)
- ctx = bike.init()
- ctx.renameByCoordinates(os.path.abspath(tmpfile),line,col,newname)
- ctx.save()
- newsrc = readFile(tmpfile)
- return newsrc
-
-
-class TestRenameByCoordinatesWithDirectoryStructure(
- RenameClassTests_importsClass,
- RenameFunctionTests_importsFunction,
- RenameMethodTests_ImportsClass,
- RenameMethodReferenceTests_ImportsClass,
- BRMTestCase):
- def renameClass(self, src, newname):
- try:
- createPackageStructure(src, TheClassTestdata)
- ctx = bike.init()
- ctx.renameByCoordinates(pkgstructureFile2,1,6,newname)
- ctx.save()
- newsrc = readFile(pkgstructureFile1)
- return newsrc
- finally:
- removePackageStructure()
-
-
- def renameMethod(self, src, line, col, newname):
- try:
- createPackageStructure(src, MethodTestdata)
- ctx = bike.init()
- ctx.renameByCoordinates(pkgstructureFile2,line,col,newname)
- ctx.save()
- newsrc = readFile(pkgstructureFile1)
- return newsrc
- finally:
- removePackageStructure()
-
- def renameFunction(self, src, newname):
- try:
- createPackageStructure(src, FunctionTestdata)
- ctx = bike.init()
- ctx.renameByCoordinates(pkgstructureFile2,1,4,newname)
- ctx.save()
- newsrc = readFile(pkgstructureFile1)
- return newsrc
- finally:
- removePackageStructure()
-
-
-
-class Test_deducePackageOfFile(BRMTestCase):
- def test_returnsEmptyStringIfFileNotInPackage(self):
- try:
- # this doesnt have __init__.py file, so
- # isnt package
- os.makedirs("a")
- writeFile(os.path.join("a","foo.py"),"pass")
- pkg = bikefacade._deducePackageOfFile(os.path.join("a","foo.py"))
- assert pkg == ""
- finally:
- os.remove(os.path.join("a","foo.py"))
- os.removedirs(os.path.join("a"))
-
- def test_returnsNestedPackage(self):
- try:
- os.makedirs(os.path.join("a","b"))
- writeFile(os.path.join("a","__init__.py"),"# ")
- writeFile(os.path.join("a","b","__init__.py"),"# ")
- writeFile(os.path.join("a","b","foo.py"),"pass")
- pkg = bikefacade._deducePackageOfFile(os.path.join("a","b","foo.py"))
- assert pkg == "a.b"
- finally:
- os.remove(os.path.join("a","__init__.py"))
- os.remove(os.path.join("a","b","__init__.py"))
- os.remove(os.path.join("a","b","foo.py"))
- os.removedirs(os.path.join("a","b"))
-
-
-class TestExtractMethod(test_extractMethod.TestExtractMethod):
-
- def test_extractsPass(self):
- srcBefore=trimLines("""
- class MyClass:
- def myMethod(self):
- pass
- """)
-
- srcAfter=trimLines("""
- class MyClass:
- def myMethod(self):
- self.newMethod()
-
- def newMethod(self):
- pass
- """)
-
- writeTmpTestFile(srcBefore)
- ctx = bike.init()
- ctx.extractMethod(os.path.abspath(tmpfile),3,8,3,12,"newMethod")
- ctx.save()
- self.assertEqual(readTmpTestFile(),srcAfter)
- ctx.undo()
- ctx.save()
- self.assertEqual(readTmpTestFile(),srcBefore)
-
-
-class TestExtractFunction(test_extractMethod.TestExtractFunction):
- def test_extractsFunction(self):
- srcBefore=trimLines("""
- def myFunction(): # comment
- a = 3
- c = a + 99
- b = c * 1
- print b
- """)
- srcAfter=trimLines("""
- def myFunction(): # comment
- a = 3
- b = newFunction(a)
- print b
-
- def newFunction(a):
- c = a + 99
- b = c * 1
- return b
- """)
- writeTmpTestFile(srcBefore)
- ctx = bike.init()
- ctx.extractMethod(os.path.abspath(tmpfile),3,4,4,13,"newFunction")
- ctx.save()
- self.assertEqual(readTmpTestFile(),srcAfter)
- ctx.undo()
- ctx.save()
- self.assertEqual(readTmpTestFile(),srcBefore)
-
-
-class TestUndo(BRMTestCase):
-
- def test_undoesTheTextOfASingleFile(self):
- src = trimLines("""
- class a:
- def foo(self):
- pass
- """)
- writeTmpTestFile(src)
- #ctx = bike.init()
- ctx = bike.init()
-
- ctx.renameByCoordinates(tmpfile,2,8,"c")
- ctx.save()
- ctx.undo()
- ctx.save()
- newsrc = readFile(tmpfile)
- self.assertEqual(newsrc,src)
-
-
- def test_undoesTwoConsecutiveRefactorings(self):
- try:
- src = trimLines("""
- class a:
- def foo(self):
- pass
- """)
- writeTmpTestFile(src)
- ctx = bike.init()
- ctx.renameByCoordinates(tmpfile,2,8,"c")
- ctx.save()
-
- newsrc1 = readFile(tmpfile)
-
- ctx.renameByCoordinates(tmpfile,2,8,"d")
- ctx.save()
-
-
- # 1st undo
- ctx.undo()
- ctx.save()
- newsrc = readFile(tmpfile)
- self.assertEqual(newsrc,
- newsrc1)
-
- # 2nd undo
- ctx.undo()
- ctx.save()
- newsrc = readFile(tmpfile)
- self.assertEqual(newsrc,src)
- finally:
- pass
- #deleteTmpTestFile()
-
-
- def test_undoesTheTextOfAFileTwice(self):
- for i in range(3):
- src = trimLines("""
- class foo:
- def bah(self):
- pass
- """)
- writeTmpTestFile(src)
- ctx = bike.init()
- ctx.renameByCoordinates(tmpfile,2,8,"c")
- ctx.save()
- ctx.undo()
- ctx.save()
- newsrc = readFile(tmpfile)
- self.assertEqual(newsrc,src)
- raisedexception=0
- try:
- ctx.undo()
- except UndoStackEmptyException:
- pass
- else:
- assert 0,"should have raised an exception"
-
- '''
- def test_undoesManualModificationsToFiles(self):
- writeTmpTestFile("class foo: pass")
- origsrc = readFile(tmpfile)
- ctx = bike.init()
-
- writeTmpTestFile("pass")
- import os
- ctx.init()
- newsrc = readFile(tmpfile)
- assert newsrc != origsrc
- ctx.undo()
- ctx.save()
- newsrc = readFile(tmpfile)
- assert newsrc == origsrc
- '''
-
-class TestGetReferencesToClass_Facade(BRMTestCase):
- def test_returnsReferences(self):
- src = trimLines("""
- class TheClass:
- pass
- a = TheClass()
- """)
- writeTmpTestFile(src)
- ctx = bike.init()
- refs = [refs for refs in ctx.findReferencesByCoordinates(tmpfile,1,6)]
- self.assertEqual(refs[0].filename,os.path.abspath(tmpfile))
- self.assertEqual(refs[0].lineno,3)
- assert hasattr(refs[0],"confidence")
-
-
-class TestFindDefinitionByCoordinates(BRMTestCase):
- def test_findsClassRef(self):
- src=trimLines("""
- class TheClass:
- pass
- a = TheClass()
- """)
- writeTmpTestFile(src)
- ctx = bike.init()
- defn = [x for x in ctx.findDefinitionByCoordinates(tmpfile,3,6)]
- assert defn[0].filename == os.path.abspath(tmpfile)
- assert defn[0].lineno == 1
- assert defn[0].confidence == 100
-
-class TestBRM_InlineLocalVariable(BRMTestCase):
- def test_works(self):
- srcBefore=trimLines("""
- def foo():
- b = 'hello'
- print b
- """)
- srcAfter=trimLines("""
- def foo():
- print 'hello'
- """)
-
- writeTmpTestFile(srcBefore)
- ctx = bike.init()
- ctx.inlineLocalVariable(tmpfile,3,10)
- ctx.save()
- self.assertEqual(file(tmpfile).read(),srcAfter)
-
-
-class TestBRM_ExtractLocalVariable(BRMTestCase):
- def test_works(self):
- srcBefore=trimLines("""
- def foo():
- print 3 + 2
- """)
- srcAfter=trimLines("""
- def foo():
- a = 3 + 2
- print a
- """)
- try:
- writeTmpTestFile(srcBefore)
- ctx = bike.init()
- ctx.extractLocalVariable(tmpfile,2,10,2,15,'a')
- ctx.save()
- self.assertEqual(file(tmpfile).read(),srcAfter)
- finally:
- pass
- #deleteTmpTestFile()
-
-
-
-
-
-
-if __name__ == "__main__":
- unittest.main()
--- a/vim/sadness/bike/bike/test_testutils.py Thu Feb 10 17:11:26 2011 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,9 +0,0 @@
-#!/usr/bin/env python
-import setpath
-import unittest
-from testutils import*
-import testdata
-import sys
-
-if __name__ == "__main__":
- unittest.main()
--- a/vim/sadness/bike/bike/testall.py Thu Feb 10 17:11:26 2011 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,7 +0,0 @@
-#!/usr/bin/env python
-
-import setpath
-from test_bikefacade import *
-
-if __name__ == "__main__":
- unittest.main()
--- a/vim/sadness/bike/bike/testdata.py Thu Feb 10 17:11:26 2011 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,17 +0,0 @@
-TheClass = """
-class TheClass:
- def theMethod(self):
- pass
- def differentMethod(self):
- pass
-
-class DifferentClass:
- def theMethod(self):
- pass
-"""
-
-
-Function = """
-def theFunction():
- pass
-"""
--- a/vim/sadness/bike/bike/testutils.py Thu Feb 10 17:11:26 2011 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,170 +0,0 @@
-from bike.globals import *
-import unittest
-import os
-import os.path
-from mock import Mock
-from bike.parsing.fastparserast import getRoot, Root, resetRoot
-from parsing.utils import fqn_rcar, fqn_rcdr
-import re
-from bike import log
-filesToDelete = None
-dirsToDelete = None
-
-class BRMTestCase(unittest.TestCase):
- def setUp(self):
- log.warning = log.SilentLogger()
- try: os.makedirs(tmproot)
- except: pass
- os.chdir(tmproot)
-
- resetRoot(Root([tmproot]))
- getRoot().unittestmode = True
- global filesToDelete
- global dirsToDelete
- filesToDelete = []
- dirsToDelete = []
- from bike.parsing.load import Cache
- Cache.instance.reset()
-
-
-
- def tearDown(self):
- global filesToDelete
- global dirsToDelete
-
- for path in filesToDelete:
- try: os.remove(path)
- except: pass
- filesToDelete = []
-
- for path in dirsToDelete:
- try: os.removedirs(path)
- except: pass
- dirsToDelete = []
-
- os.chdir("..")
- try: os.removedirs(tmproot)
- except: pass
-
-
-
-tmproot = os.path.abspath("tmproot")
-tmpfile = os.path.join(tmproot, "bicyclerepairman_tmp_testfile.py")
-tmpmodule = "bicyclerepairman_tmp_testfile"
-
-
-def writeFile(filename, src):
- f = open(filename, "w+")
- f.write(src)
- f.close()
- filesToDelete.append(filename)
-
-def readFile(filename):
- f = open(filename)
- src = f.read()
- f.close()
- return src
-
-def writeTmpTestFile(src):
- try:
- os.makedirs(tmproot)
- except OSError:
- pass
- writeFile(tmpfile, src)
-
-def readTmpTestFile():
- return readFile(tmpfile)
-
-def deleteTmpTestFile():
- os.remove(tmpfile)
- os.removedirs(tmproot)
-
-
-pkgstructureRootDir = tmproot
-pkgstructureBasedir = os.path.join(pkgstructureRootDir, "a")
-pkgstructureChilddir = os.path.join(pkgstructureBasedir, "b")
-pkgstructureFile0 = os.path.join(pkgstructureRootDir, "top.py")
-pkgstructureFile1 = os.path.join(pkgstructureBasedir, "foo.py")
-pkgstructureFile2 = os.path.join(pkgstructureChilddir, "bah.py")
-
-
-def createPackageStructure(src1, src2, src0="pass"):
- try: os.makedirs(pkgstructureChilddir)
- except: pass
- writeFile(os.path.join(pkgstructureBasedir, "__init__.py"), "#")
- writeFile(os.path.join(pkgstructureChilddir, "__init__.py"), "#")
- writeFile(pkgstructureFile0, src0)
- writeFile(pkgstructureFile1, src1)
- writeFile(pkgstructureFile2, src2)
-
-def removePackageStructure():
- os.remove(os.path.join(pkgstructureBasedir, "__init__.py"))
- os.remove(os.path.join(pkgstructureChilddir, "__init__.py"))
- os.remove(pkgstructureFile0)
- os.remove(pkgstructureFile1)
- os.remove(pkgstructureFile2)
- os.removedirs(pkgstructureChilddir)
-
-
-pkgstructureBasedir2 = os.path.join(pkgstructureRootDir, "c")
-pkgstructureFile3 = os.path.join(pkgstructureBasedir2, "bing.py")
-
-def createSecondPackageStructure(src3):
- try: os.makedirs(pkgstructureBasedir2)
- except: pass
- writeFile(os.path.join(pkgstructureBasedir2, "__init__.py"), "#")
- writeFile(pkgstructureFile3, src3)
-
-def removeSecondPackageStructure():
- os.remove(os.path.join(pkgstructureBasedir2, "__init__.py"))
- os.remove(pkgstructureFile3)
- os.removedirs(pkgstructureBasedir2)
-
-
-
-def createAST(src):
- from bike.parsing.load import getSourceNode
- writeFile(tmpfile,src)
- return getSourceNode(tmpfile)
-
-
-def createSourceNodeAt(src, fqn):
- modname = fqn_rcar(fqn)
- packagefqn = fqn_rcdr(fqn)
- dirpath = os.path.join(*packagefqn.split("."))
- filepath = os.path.join(dirpath,modname+".py")
- try: os.makedirs(dirpath)
- except: pass
- dirsToDelete.append(dirpath)
-
- # add the __init__.py files
- path = "."
- for pathelem in packagefqn.split("."):
- path = os.path.join(path,pathelem)
- initfile = os.path.join(path,"__init__.py")
- writeFile(initfile,"#")
- filesToDelete.append(initfile)
- writeFile(filepath,src)
- filesToDelete.append(filepath)
- return getRoot()
-
-
-# takes the leading whitespace out of a multi line comment.
-# means you can imbed """
-# text like
-# this
-# """
-# in your code, and it will come out
-#"""text like
-#this"""
-def trimLines(src):
- lines = src.splitlines(1)[1:]
- tabwidth = re.match("\s*",lines[0]).end(0)
- newlines = []
- for line in lines:
- if line == "\n" or line == "\r\n":
- newlines.append(line)
- else:
- newlines.append(line[tabwidth:])
- return "".join(newlines)
-
--- a/vim/sadness/bike/bike/transformer/WordRewriter.py Thu Feb 10 17:11:26 2011 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,48 +0,0 @@
-from bike.parsing.load import getSourceNode
-from bike.transformer.undo import getUndoStack
-from bike.transformer.save import queueFileToSave
-import re
-
-# This class maintains a set of changed lines to the original source
-# nodes. This is important because the act of changing a line messes
-# up the coordinates on which renames are done.
-# Commit writes the changes back to the source nodes
-class WordRewriter:
- def __init__(self):
- self.modifiedsrc = {}
-
- def rewriteString(self, srcnode, lineno, colno, newname):
- filename = srcnode.filename
- if not self.modifiedsrc.has_key(filename):
- getUndoStack().addSource(filename,srcnode.getSource())
- self.modifiedsrc[filename] = {}
- if not self.modifiedsrc[filename].has_key(lineno):
- line = srcnode.getLines()[lineno-1]
- self.modifiedsrc[filename][lineno] = self._lineToDict(line)
- self.modifiedsrc[filename][lineno][colno] = newname
-
-
- # writes all the changes back to the src nodes
- def commit(self):
- for filename in self.modifiedsrc.keys():
- srcnode = getSourceNode(filename)
- for lineno in self.modifiedsrc[filename]:
- lines = srcnode.getLines()
- lines[lineno-1] = self._dictToLine(self.modifiedsrc[filename][lineno])
- queueFileToSave(filename,"".join(srcnode.getLines()))
-
-
- # this function creates a dictionary with each word referenced by
- # its column position in the original line
- def _lineToDict(self, line):
- words = re.split("(\w+)", line)
- h = {};i = 0
- for word in words:
- h[i] = word
- i+=len(word)
- return h
-
- def _dictToLine(self, d):
- cols = d.keys()
- cols.sort()
- return "".join([d[colno]for colno in cols])
--- a/vim/sadness/bike/bike/transformer/__init__.py Thu Feb 10 17:11:26 2011 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,4 +0,0 @@
-"""
-Package containing modules which transform the internal
-representation of the sourcecode.
-"""
--- a/vim/sadness/bike/bike/transformer/save.py Thu Feb 10 17:11:26 2011 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,36 +0,0 @@
-from bike import log
-
-outputqueue = {}
-
-def getQueuedFile(filename):
- try:
- return outputqueue[filename]
- except:
- pass
- #print "HERE!"
-
-
-def resetOutputQueue():
- global outputqueue
- outputqueue = {}
-
-def queueFileToSave(filename,src):
- outputqueue[filename] = src
- from bike.parsing.load import getSourceNode
- getSourceNode(filename).resetWithSource(src)
-
-def save():
- from bike.transformer.undo import getUndoStack
-
- global outputqueue
- savedFiles = []
- for filename,src in outputqueue.iteritems():
- print >> log.progress, "Writing:",filename
- f = file(filename, "w+")
- f.write(outputqueue[filename])
- f.close()
- savedFiles.append(filename)
- outputqueue = {}
- #print "stack is "+ str(getUndoStack().stack)
- getUndoStack().commitUndoFrame()
- return savedFiles
--- a/vim/sadness/bike/bike/transformer/setpath.py Thu Feb 10 17:11:26 2011 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,5 +0,0 @@
-import sys,os
-if not os.path.abspath("..") in sys.path:
- from bike import log
- print >> log.warning, "Appending to the system path. This should only happen in unit tests"
- sys.path.append(os.path.abspath(".."))
--- a/vim/sadness/bike/bike/transformer/testall.py Thu Feb 10 17:11:26 2011 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,6 +0,0 @@
-#!/usr/bin/env python
-
-#from test_undo import *
-
-if __name__ == "__main__":
- unittest.main()
--- a/vim/sadness/bike/bike/transformer/undo.py Thu Feb 10 17:11:26 2011 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,50 +0,0 @@
-from bike import log
-from bike.transformer.save import queueFileToSave
-
-_undoStack = None
-
-def getUndoStack(forceNewStack = 0):
- global _undoStack
- if _undoStack is None or forceNewStack:
- _undoStack = UndoStack()
- return _undoStack
-
-class UndoStackEmptyException: pass
-
-class UndoStack(object):
- def __init__(self):
- self.stack = []
- self.stack.append({})
- self.frame = self.stack[-1]
- self.setUndoBufferSize(10)
-
- def setUndoBufferSize(self, undoBufferSize):
- self.undoBufferSize = undoBufferSize
-
- def addSource(self, filename, src):
- if filename not in self.frame:
- self.frame[filename] = src
-
- def commitUndoFrame(self):
- #restrict size of buffer
- while len(self.stack) > self.undoBufferSize:
- #print "clipping undo stack"
- del self.stack[0]
-
- if len(self.frame) != 0:
- #print "commitUndoFrame"
- self.stack.append({})
- self.frame = self.stack[-1]
-
- def undo(self, **opts):
- #print "undo called",self.stack
- if len(self.stack) < 2:
- raise UndoStackEmptyException()
- undoframe = self.stack[-2]
- #print "undoframe is",undoframe
- for filename,src in undoframe.iteritems():
- print >>log.progress, "Undoing:",filename
- queueFileToSave(filename,src)
- self.stack = self.stack[:-2]
- self.stack.append({})
- self.frame = self.stack[-1]
--- a/vim/sadness/bike/ide-integration/BicycleRepairMan_Idle.py Thu Feb 10 17:11:26 2011 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,422 +0,0 @@
-# bicycle repair man idle extension
-import bike
-from bike.transformer.undo import UndoStackEmptyException
-import bike.parsing.load
-import os
-from Tkinter import *
-import tkFileDialog
-import tkMessageBox
-import tkSimpleDialog
-import sys
-import string
-try:
- from idlelib.PathBrowser import *
- from idlelib.WindowList import ListedToplevel
- from idlelib.TreeWidget import TreeNode, TreeItem, ScrolledCanvas
- from idlelib import EditorWindow
- from idlelib.PyShell import PyShell
- from idlelib.OutputWindow import OutputWindow
- try:
- from idlelib.configHandler import idleConf
- except ImportError:
- pass
-
-
-
-except ImportError:
- from PathBrowser import*
- from WindowList import ListedToplevel
- from TreeWidget import TreeNode, TreeItem, ScrolledCanvas
- import EditorWindow
- from PyShell import PyShell
- from OutputWindow import OutputWindow
- try:
- from configHandler import idleConf
- except ImportError:
- pass
-
-brmctx = None
-shellwin = None
-loadingFiles = 0
-matchwin = None
-
-class NotHighlightedException(Exception):
- pass
-
-class BicycleRepairMan_Idle:
- menudefs = [
- ('bicycleRepairMan', [
- ('----- Queries -----',''),
- ('_Find References','<<brm-find-references>>'),
- ('_Find Definition','<<brm-find-definition>>'),
- None,
- ('--- Refactoring ---',''),
- ('_Rename', '<<brm-rename>>'),
- ('_Extract Method', '<<brm-extract-method>>'),
- None,
- ('_Undo', '<<brm-undo>>'),
- ])
- ]
-
- keydefs = {
- '<<brm-find-references>>':[],
- '<<brm-find-definition>>':[],
- '<<brm-rename>>':[],
- '<<brm-extract-method>>':[],
- '<<brm-undo>>':[],
- }
-
-
- try:
- TRACE = idleConf.GetOption('extensions','BicycleRepairMan_Idle',
- 'trace',default=1)
- except NameError: # hasnt imported idleconf - probably python 22
- TRACE = 1
-
-
- def __init__(self, editwin):
- self.editwin = editwin
-
- if self.TRACE == 1:
- self.progressLogger = ProgressLogger(self.editwin.flist)
-
- if not isinstance(editwin, PyShell):
- # sly'ly add the refactor menu to the window
- name, label = ("bicycleRepairMan", "_BicycleRepairMan")
- underline, label = EditorWindow.prepstr(label)
- mbar = editwin.menubar
- editwin.menudict[name] = menu = Menu(mbar, name = name)
- mbar.add_cascade(label = label, menu = menu, underline = underline)
-
- # Initialize Bicyclerepairman and import the code
- path = self.editwin.io.filename
- if path is not None:
- global brmctx
- if brmctx is None:
- self.initbrm()
- else:
- global shellwin
- shellwin = editwin
-
-
- def initbrm(self):
- global brmctx
- brmctx = bike.init()
- if self.TRACE == 1:
- brmctx.setProgressLogger(self.progressLogger)
-
-
- def brm_find_references_event(self,event):
- try:
- if not self.confirm_all_buffers_saved():
- return
-
- if self.editwin.text.index("sel.first") == "":
- self.errorbox("Not highlighted", "Highlight the name of a Function, Class or Method and try again")
- return
-
- filename = os.path.normpath(self.editwin.io.filename)
- line, column = string.split(self.editwin.text.index("sel.first"),'.')
-
- numMatches = 0
- global matchwin
- if matchwin is None:
- matchwin = BRMMatchesWindow(self.editwin.flist, self)
-
- matchwin.clear()
-
- for ref in brmctx.findReferencesByCoordinates(filename,int(line),int(column)):
- print >>matchwin, "File \""+ref.filename+"\", line "+str(ref.lineno)+", "+str(ref.confidence)+"% confidence"
- numMatches +=1
-
- print >>matchwin, numMatches," matches"
- print >>matchwin, "(Hint: right-click to open locations.)"
- except:
- self._handleUnexpectedException()
-
-
- def brm_find_definition_event(self,event):
- try:
- if not self.confirm_all_buffers_saved():
- return
- filename = os.path.normpath(self.editwin.io.filename)
-
- if self.editwin.text.index("sel.first") != "":
- line, column = string.split(self.editwin.text.index("sel.first"),'.')
- else:
- line, column = string.split(self.editwin.text.index("insert"), '.')
-
-
- defns = brmctx.findDefinitionByCoordinates(filename,int(line),
- int(column))
-
- try:
-
- firstref = defns.next()
-
- editwin = self.editwin.flist.open(firstref.filename)
- editwin.gotoline(firstref.lineno)
- except StopIteration:
- self.errorbox("Couldn't Find definition","Couldn't Find definition")
- pass
- else:
- numRefs = 1
- global matchwin
- if matchwin is None:
- matchwin = BRMMatchesWindow(self.editwin.flist, self)
-
- for ref in defns:
- if numRefs == 1:
- print >>matchwin, firstref.filename+":"+str(firstref.lineno)+": "+str(firstref.confidence)+"% confidence"
-
- numRefs += 1
- print >>matchwin,ref.filename+":"+str(ref.lineno)+": "+str(ref.confidence)+"% confidence"
- if matchwin is not None:
- print >>matchwin, "(Hint: right-click to open locations.)"
-
- except:
- self._handleUnexpectedException()
-
-
- def brm_rename_event(self, event):
- try:
- self.renameItemByCoordinates()
- except:
- self._handleUnexpectedException()
-
- def brm_extract_method_event(self, event):
- try:
- if not self.confirm_all_buffers_saved():
- return
- try:
- filename, newname, beginline, begincolumn, endline, endcolumn = self._getExtractionInformation("Method")
- except NotHighlightedException:
- return
- brmctx.extractMethod(filename, int(beginline), int(begincolumn),
- int(endline), int(endcolumn), newname)
- savedfiles = brmctx.save()
- self.refreshWindows(savedfiles, beginline)
- except:
- self._handleUnexpectedException()
-
-
- def brm_undo_event(self, event):
- try:
- line, column = string.split(self.editwin.text.index("insert"), '.')
- brmctx.undo()
- savedfiles = brmctx.save()
- self.refreshWindows(savedfiles, line)
- except UndoStackEmptyException:
- self.errorbox("Undo Stack Empty", "Undo Stack is empty")
- except:
- self._handleUnexpectedException()
-
- def _handleUnexpectedException(self):
- import traceback
- traceback.print_exc()
- self.errorbox("Caught Exception", "Caught Exception "+str(sys.exc_info()[0]))
-
- def _getExtractionInformation(self, extracttype):
- if self.editwin.text.index("sel.first") == "":
- self.errorbox("Code not highlighted", "Highlight the region of code you want to extract and try again")
- raise NotHighlightedException()
- filename = os.path.normpath(self.editwin.io.filename)
- newname = tkSimpleDialog.askstring("Extract Method ",
- "New "+extracttype+" Name:",
- parent = self.editwin.text)
- beginline, begincolumn = string.split(self.editwin.text.index("sel.first"), '.')
- endline, endcolumn = string.split(self.editwin.text.index("sel.last"), '.')
- return filename, newname, beginline, begincolumn, endline, endcolumn
-
-
- def renameMethodPromptCallback(self, filename, line, colbegin, colend):
-
- editwin = self.editwin.flist.open(filename)
- originaltop = self.editwin.getwindowlines()[0]
-
- # select the method call and position the window
- editwin.text.tag_remove("sel", "1.0", "end")
- editwin.text.tag_add("sel", str(line)+"."+str(colbegin),
- str(line)+"."+str(colend))
-
- line, column = string.split(editwin.text.index("sel.first"), '.')
- editwin.text.yview(str(int(line)-2)+".0")
-
-
- d = NoFocusDialog("Rename?",
- "Cannot deduce the type of highlighted object reference.\nRename this declaration?",
- parent = editwin.text)
-
- # put the window back where it was
- self.editwin.text.yview(float(originaltop))
- return d.answer
-
- def renameItemByCoordinates(self):
- if not self.confirm_all_buffers_saved():
- return
- if self.editwin.text.index("sel.first") == "":
- self.errorbox("Name not highlighted", "Double click the name of the declaration you want to rename (to highlight it) and try again")
- return
-
- brmctx.setRenameMethodPromptCallback(self.renameMethodPromptCallback)
- line, column = string.split(self.editwin.text.index("sel.first"), '.')
- filename = os.path.normpath(self.editwin.io.filename)
- newname = tkSimpleDialog.askstring("Rename",
- "Rename to:",
- parent = self.editwin.text)
- if newname is None: # cancel clicked
- return
- brmctx.renameByCoordinates(filename, int(line), int(column), newname)
- savedfiles = brmctx.save()
- self.refreshWindows(savedfiles, line)
-
-
-
- def refreshWindows(self, savedfiles, line):
- # refresh editor windows
- oldtop = self.editwin.getwindowlines()[0]
-
- global loadingFiles
- loadingFiles = 1
- for sf in savedfiles:
- normsf = os.path.normcase(sf)
- if normsf in self.editwin.flist.dict:
- editwin = self.editwin.flist.dict[normsf]
- editwin.io.loadfile(sf)
- loadingFiles = 0
-
- self.editwin.text.mark_set("insert", float(line))
- self.editwin.text.yview(float(oldtop))
-
-
-
- def confirm_all_buffers_saved(self):
- filelist = self.editwin.flist.dict.keys()
- for f in filelist:
- #editwin = self.editwin.flist.open(f)
- editwin = self.editwin.flist.dict[f]
- if self.confirm_buffer_is_saved(editwin) == 0:
- return 0
- return 1
-
-
- def confirm_buffer_is_saved(self, editwin):
- if not editwin.get_saved():
- name = (editwin.short_title()or
- editwin.long_title()or
- "Untitled")
- reply = tkMessageBox.askokcancel("Bicycle Repair Man",
- "The buffer for %s is not saved.\n\n"%name+
- "Save it and continue?",
- master = self.editwin.text)
- &nbs p; self.editwin.text.focus_set()
- if reply:
- editwin.io.save(None)
- else:
- return 0
- return 1
-
- def errorbox(self, title, message):
- tkMessageBox.showerror(title, message, master = self.editwin.text)
- self.editwin.text.focus_set()
-
-
-class BRMTraceWindow(OutputWindow):
- def short_title(self):
- return "BicycleRepairMan Trace"
-
-class ProgressLogger:
- def __init__(self,flist):
- self.flist = flist
-
- def write(self,txt):
- if not hasattr(self,"io"):
- self.io = BRMTraceWindow(self.flist)
- try:
- self.io.write(txt)
- self.io.flush()
- except IOError:
- pass
-
-
-class NoFocusDialog(tkSimpleDialog._QueryDialog):
- def __init__(self, title, prompt,
- initialvalue = None,
- minvalue = None, maxvalue = None,
- parent = None):
- self.answer = 0
-
- if not parent:
- import Tkinter
- parent = Tkinter._default_root
-
- self.prompt = prompt
- self.minvalue = minvalue
- self.maxvalue = maxvalue
-
- self.initialvalue = initialvalue
-
- Toplevel.__init__(self, parent)
-
- if title:
- self.title(title)
-
- self.parent = parent
-
- self.result = None
-
- body = Frame(self)
- self.initial_focus = self.body(body)
- body.pack(padx = 5, pady = 5)
-
- self.buttonbox()
-
- self.grab_set()
-
- self.protocol("WM_DELETE_WINDOW", self.cancel)
-
- if self.parent is not None:
- self.geometry("+%d+%d"%(parent.winfo_rootx()+50,
- parent.winfo_rooty()+50))
- self.wait_window(self)
-
-
- def getresult(self):
- self.answer = 1
-
- def body(self, master):
- w = Label(master, text = self.prompt, justify = LEFT)
- w.grid(row = 0, padx = 5, sticky = W)
-
- def buttonbox(self):
- box = Frame(self)
-
- w = Button(box, text = "Yes", width = 10, command = self.ok, default = ACTIVE)
- w.pack(side = LEFT, padx = 5, pady = 5)
- w = Button(box, text = "No", width = 10, command = self.cancel)
- w.pack(side = LEFT, padx = 5, pady = 5)
-
- self.bind("<Return>", self.ok)
- self.bind("<Escape>", self.cancel)
- box.pack()
-
-
-
-
-
-class BRMMatchesWindow(OutputWindow):
- def __init__(self,flist,masterwin):
- OutputWindow.__init__(self,flist)
- self.masterwin = masterwin
-
- def close(self):
- global matchwin
- matchwin = None
- OutputWindow.close(self)
-
- def short_title(self):
- return "BicycleRepairMan Matches"
-
- def clear(self):
- self.text.delete("1.0","end-1c")
-
--- a/vim/sadness/bike/ide-integration/Pymacs-0.20/ChangeLog Thu Feb 10 17:11:26 2011 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,417 +0,0 @@
-2002-11-23 François Pinard <pinard@iro.umontreal.ca>
-
- * : Release 0.20.
-
- * Pymacs/__init__.py: Integrate version.py.
- * Pymacs/version.py: Deleted.
- * setup.py, Pymacs/pymacs.py: Adjusted.
-
-2002-11-15 François Pinard <pinard@iro.umontreal.ca>
-
- * pymacs.el (pymacs-python-reference): Handle when function is
- defined as a mere variable, or when a function is being advised.
-
-2002-11-14 François Pinard <pinard@iro.umontreal.ca>
-
- * : Release 0.19.
-
- * Pymacs/pymacs.py (List.__getitem__): Raise IndexError when
- out of bounds. This should allow for iterating over a list.
-
- * README.html: New, merely a template for Webert.
-
-2002-11-13 François Pinard <pinard@iro.umontreal.ca>
-
- * pymacs.el (pymacs-call): New. Use it whenever adequate.
-
-2002-09-26 François Pinard <pinard@iro.umontreal.ca>
-
- * Makefile (publish): Revised.
-
-2002-08-18 François Pinard <pinard@iro.umontreal.ca>
-
- * : Release 0.18.
-
-2002-08-09 François Pinard <pinard@iro.umontreal.ca>
-
- * Pymacs/rebox.py (Emacs_Rebox.find_comment): Correctly spell
- backward_char, not backward-char.
-
-2002-08-08 François Pinard <pinard@iro.umontreal.ca>
-
- * Pymacs/rebox.py (pymacs_load_hook): Compute the interactions
- map from the bound methods, instead of from the generic ones.
-
-2002-07-14 François Pinard <pinard@iro.umontreal.ca>
-
- * Pymacs/pymacs.py (Lisp_Interface.__call__): Wrap argument in
- progn, so lisp() could accept a sequence of expressions.
-
-2002-07-01 François Pinard <pinard@iro.umontreal.ca>
-
- * pymacs.el (pymacs-start-services): Disable undo for *Pymacs*.
-
-2002-06-25 François Pinard <pinard@iro.umontreal.ca>
-
- * : Release 0.17.
-
- * pymacs.py: Deleted, this was the compatibility module.
- * setup: Simplified to handle the Emacs Lisp part only.
- Deleted -P, -p and -x, as well as compile_python.
-
- * Makefile: Adjusted. Removed pythondir and pymacsdir.
- * pymacs.el (pymacs-load-path): Merely preset to nil.
-
- * setup: Changes for easing installation on Win32.
- Reported by Syver Enstad.
-
- * Pymacs/pymacs.py (print_lisp): Produce Emacs strings more
- explicitly, avoiding hexadecimal sequences generated by Python
- 2.2. Those hexadecimal sequences confused Emacs when immediately
- followed by more hexadecimal looking characters.
-
-2002-01-30 François Pinard <pinard@iro.umontreal.ca>
-
- * pymacs.el (pymacs-load-path): Initialise with pymacsdir.
- * pymacs-services: Do not handle a patched pymacsdir anymore.
- * setup (complete_install): Set pymacsdir for Lisp, not Python.
- Do not accept a -b option anymore, do not install pymacs-services,
- as this is now to be done through setup.py.
- * Makefile (install): Do not use -b while calling setup.
-
-2002-01-29 François Pinard <pinard@iro.umontreal.ca>
-
- * : Release 0.16.
-
- * Pymacs/pymacs.py: New file, previously top-level.
- * pymacs.py: Now a mere bootstrap for Pymacs/pymacs.py.
- * Pymacs/__init__.py: Define lisp and Let.
- * Makefile (pythondir): Documentation amended.
- * setup: Distinguish between empty arguments, which ask for
- autoconfiguration, and None arguments, which inhibit it.
- * pymacs-services: Import pymacs from Pymacs.
-
- * Pymacs/version.py: New file. Rename pymacs to Pymacs.
- * setup, setup.py, Pymacs/pymacs.py (main): Use it.
-
- * setup: Substitute None for pymacsdir instead of the empty string.
- * pymacs-services: Adjusted.
-
- * Pymacs/pymacs.py (Let): Have all push_* methods to return self.
-
-2002-01-20 François Pinard <pinard@iro.umontreal.ca>
-
- * pymacs.el, pymacs.el: Replace LISP by Lisp in comments.
- Reported by Paul Foley.
-
-2002-01-10 François Pinard <pinard@iro.umontreal.ca>
-
- * : Release 0.15.
-
- * pymacs.el (pymacs-start-services): Properly diagnose a timeout,
- using the timeout parameter value instead of a fixed string.
-
-2002-01-07 François Pinard <pinard@iro.umontreal.ca>
-
- * : Release 0.14.
-
- * pymacs.py: Set various __repr__() to yield Python code,
- containing the corresponding expanded LISP expression.
- Set various __str__() to yield mutable LISP code.
-
- * pymacs.py (Let): Point markers to nowhere once done with them.
-
-2002-01-06 François Pinard <pinard@iro.umontreal.ca>
-
- * : Release 0.13.
-
- * pymacs.el (pymacs-load): Imply prefix correctly when the module
- is part of a package, that is, when its name has at least one dot.
- * pymacs.py (pymacs_load_helper): Idem.
-
- * pymacs.py (Protocol): New name for Server.
-
- * pymacs.py (pymacs_load_helper): Implement pymacs_load_hook.
-
- * MANIFEST.in, setup.py, Pymacs/__init__.py: New files.
- * Makefile: Adjusted and simplified.
-
-2002-01-03 François Pinard <pinard@iro.umontreal.ca>
-
- * pymacs.py (pymacs_load_helper): Handle module within package.
- Reported by Syver Enstad.
-
-2001-12-18 François Pinard <pinard@iro.umontreal.ca>
-
- * pymacs.bat: New file.
-
-2001-11-29 François Pinard <pinard@iro.umontreal.ca>
-
- * : Release 0.12.
-
- * pymacs.el (pymacs-timeout-at-start, pymacs-timeout-at-reply,
- pymacs-timeout-at-line): New variables. Use them.
-
-2001-10-17 François Pinard <pinard@iro.umontreal.ca>
-
- * pymacs.py (pymacs_load_helper): Check the function attribute
- before the interactions dictionary, for people having Python 2.x.
- Reported by Carel Fellinger.
-
- * pymacs.el, pymacs.py, pymacs-services: Add the usual GPL notices.
- Reported by Richard Stallman.
-
-2001-10-16 François Pinard <pinard@iro.umontreal.ca>
-
- * : Release 0.11.
-
- * pymacs.el (pymacs-defuns): Accept interaction specifications.
- (pymacs-defun): Process an interaction specification.
- (pymacs-python-reference): Adjust for interactive functions.
- * pymacs.py (pymacs_load_helper): Transmit interaction specifications.
- Reported by Christian Tanzer and Stefan Reichör.
-
-2001-10-15 François Pinard <pinard@iro.umontreal.ca>
-
- * pymacs.py (pymacs_load_helper): Accept dashed module names.
- Reported by Stefan Reichör.
-
- * pymacs.el (pymacs-python-reference): Rewrite, as it was broken.
- (documentation): Say it is a Python function, even if no docstring.
- Reported by Stefan Reichör.
-
-2001-10-12 François Pinard <pinard@iro.umontreal.ca>
-
- * : Release 0.10.
-
- * pymacs.el (pymacs-print-for-eval): Handle multi-line strings.
- Reported by Dave Sellars.
-
- * pymacs.el (pymacs-print-for-eval): Remove string text properties.
- Reported by Eli Zaretskii.
-
-2001-10-06 François Pinard <pinard@iro.umontreal.ca>
-
- * pymacs.py (Let.__nonzero__): New.
-
-2001-09-28 François Pinard <pinard@iro.umontreal.ca>
-
- * : Release 0.9.
-
-2001-09-26 François Pinard <pinard@iro.umontreal.ca>
-
- * pymacs.py (Let.push): Save the value of the symbol, not the
- symbol itself.
-
-2001-09-25 François Pinard <pinard@iro.umontreal.ca>
-
- * : Release 0.8.
-
- * pymacs.py (Let): New class.
-
- * pymacs.el: New variable pymacs-use-hash-tables, set to t when
- hash tables are available, or nil otherwise. Use it. This is so
- older Emacs would work.
- Reported by Dirk Vleugels.
-
-2001-09-21 François Pinard <pinard@iro.umontreal.ca>
-
- * pymacs.el (pymacs-defun): Ensure the function is registered
- at definition, not at call time. Otherwise, it would never be
- garbage-collected if it is never called.
-
-2001-09-20 François Pinard <pinard@iro.umontreal.ca>
-
- * : Release 0.7.
-
- * pymacs.el (pymacs-print-for-apply): Also accept Python objects
- for a function, instead of requiring strings.
- (pymacs-defun): Use a Python object, not an explicit string reference.
- (pymacs-python): Merge pymacs-save-index.
- (pymacs-save-index): Deleted.
-
-2001-09-18 François Pinard <pinard@iro.umontreal.ca>
-
- * pymacs.el (pymacs-load): Accept a noerror argument.
-
-2001-09-17 François Pinard <pinard@iro.umontreal.ca>
-
- * setup: New script.
- * Makefile: Use it.
-
- * pymacs.py (Symbol.set): Make things simpler when value is None.
-
- * pymacs.el (pymacs-print-for-eval): Use Python lists to represent
- LISP proper lists and Python tuples to represent LISP vectors,
- instead of the other way around.
- * pymacs.py (pymacs_load_helper, print_lisp): Similar changes.
- Reported by John Wiegley.
-
-2001-09-16 François Pinard <pinard@iro.umontreal.ca>
-
- * : Release 0.6.
-
- * pymacs.el (pymacs-start-services, pymacs-print-for-eval,
- pymacs-round-trip): Protect match data.
-
-2001-09-15 François Pinard <pinard@iro.umontreal.ca>
-
- * pymacs.el (documentation): Completed. Now into service.
- (pymacs-documentation): Deleted.
- (pymacs-python-reference): New.
-
- * pymacs.el (pymacs-print-for-eval): Use car-safe.
-
-2001-09-14 François Pinard <pinard@iro.umontreal.ca>
-
- * pymacs.el (pymacs-print-for-eval): replace-regexp-in-string does
- not exist in older Emacs versions, so use paraphrases.
- Reported by Carey Evans.
-
- * pymacs.el (pymacs-start-services): Set pymacs-transit-buffer
- permanently only at end of the function, in case anything fails.
- Reported by Carey Evans.
-
-2001-09-13 François Pinard <pinard@iro.umontreal.ca>
-
- * : Release 0.5.
-
- * pymacs.el (documentation, pymacs-documentation): New, experimental.
- * pymacs.py (doc_string): New.
- (pymacs_load_helper): The result should evaluate to the module.
-
-2001-09-12 François Pinard <pinard@iro.umontreal.ca>
-
- * pymacs.py (pymacs_load_helper): Use reload instead of __import__
- whenever the module was already loaded.
-
- * pymacs.py (pymacs_load_helper): Return t when there is nothing
- to define, instead of returning a noisy pymacs-defuns noop.
-
- * Makefile (dist): Update a version-less symbolic link.
-
- * pymacs.el (pymacs-python, pymacs-defun): New functions.
- (pymacs-defuns): Use pymacs-defun.
- * pymacs.py (print_lisp): Use the above.
-
- * pymacs.py (Server): Free all accumulated LISP indices, while
- replying for another reason. This should decrease overhead.
- (Lisp.__del__): Delay freeing LISP, do not free one index at a time.
- * pymacs.el (pymacs-free-lisp): Free many indices at once.
-
- * pymacs.el (pymacs-start-services, pymacs-round-trip): Recognise
- reply even when not at beginning of line. The Python module may
- print incomplete lines, unrelated to the communication protocol.
-
-2001-09-11 François Pinard <pinard@iro.umontreal.ca>
-
- * : Release 0.4.
-
- * pymacs.py (zombie): New, so to get a clear diagnostic.
- (zombie_python): Link objects to the above function.
- * pymacs.el (pymacs-terminate-services): Ask for confirmation if
- any object in LISP space is still in use on the Python side.
- * pymacs-test.el (try-lisp): Do not terminate the helper.
-
- * pymacs.py (Buffer): New class, yet empty for now.
- * pymacs.el (pymacs-print-for-eval): Use it.
- Reported by Brian McErlean.
-
- * pymacs.py (Table): New class.
- * pymacs.el (pymacs-print-for-eval): Use it.
- Reported by Brian McErlean.
-
- * pymacs.py (List, Vector): New classes, split out of Lisp class.
- * pymacs.el (pymacs-print-for-eval): Use them.
- (pymacs-lisp-length, pymacs-lisp-ref, pymacs-list-set): Deleted.
- Reported by Brian McErlean.
-
- * pymacs.py (Server.loop): Allow keyboard interrupts through.
-
- * pymacs.el: Use Lisp instead of Handle. Rename
- pymacs-handle-length to pymacs-lisp-length, pymacs-handle-ref to
- pymacs-lisp-ref, pymacs-handle-set o pymacs-lisp-set,
- pymacs-allocate-handle to pymacs-allocate-lisp and
- pymacs-free-handle to pymacs-free-lisp.
-
- * pymacs.py: Rename Lisp to Lisp_Interface, and Handle to Lisp.
- Adjust for other renamings above.
-
- * pymacs.el: Rename pymacs-id to pymacs-python. Ajust for below.
- * pymacs.py: Rename handles to python, free_handles to
- free_python, zombie_handles to zombie_python and allocate_handle
- to allocate_python.
-
- * pymacs.el (pymacs-proper-list-p): New function. Use it
- everywhere instead of listp, which is not what I thought it was!
-
- * pymacs.el (pymacs-serve-until-reply): In case of LISP error,
- transmit a list of one argument, instead of the argument itself,
- to print-for-apply. This was preventing proper diagnostic.
- Correct a similar error for when expansion is requested.
-
- * pymacs.el (pymacs-print-for-eval): Do not transmit a symbol
- by its name, when it comes from another oblist than the main one.
-
- * pymacs.py (print_lisp): Transmit pymacs-id as a dotted pair.
- * pymacs.el (pymacs-print-for-eval): Adjusted.
-
- * pymacs.el (pymacs-print-for-eval): Use lisp[], not sym[].
- Avoid double escaping of the transmitted string in this case.
- Reported by Brian McErlean.
-
-2001-09-10 François Pinard <pinard@iro.umontreal.ca>
-
- * : Release 0.3.
-
- * pymacs.py (Server.send): Ensure an end of line after reply.
- * pymacs.el (pymacs-round-trip): Do not add one after Python replies.
-
- * pymacs.el (pymacs-round-trip): Check for vanishing helper process.
- (pymacs-serve-until-reply): Get text without catching errors, than
- eval. Else, protocol errors get reported back to Python.
- * pymacs.py (Server.ProtocolError): New. Better than AssertError.
- If it occurs, get out of program, do not keep returning errors.
- Reported by Carey Evans.
-
- * pymacs.el (pymacs-round-trip): If point coincides with marker,
- just keep it that way as the buffer grows.
-
- * pymacs.el (pymacs-start-services): If the hash table already
- exists, inform the Python side of IDs that it should not reuse.
- Otherwise, old lambdas may randomly refer to new Python objects.
- (pymacs-terminate-services): Remember Python IDs, do not reset them.
-
- * pymacs.py (zombie_handles): New.
-
- * Makefile: Transmit $(pymacsdir) to pymacs-services.
- * pymacs-services: Handle it.
-
- * pymacs.py (print_lisp): Process an empty tuple properly.
- Reported by Carey Evans.
-
- * pymacs.el (pymacs-start-services): With run-at-time, use `20 20'
- instead of `t 20', so XEmacs is happy.
- Reported by Carey Evans.
-
- * pymacs.el (pymacs-start-services, pymacs-terminate-services):
- Use `post-gc-hook' if available, instead of using a timer.
- Reported by Gerd Möllman.
-
- * pymacs.py (Symbol.value, Symbol.copy): Add argument self.
- (print_lisp): Quote symbols if quoted=1.
-
-2001-09-09 François Pinard <pinard@iro.umontreal.ca>
-
- * pymacs.el (pymacs-defuns): New function.
- * pymacs.py: Use it. This should allow faster imports.
-
- * Makefile, pymacs.el, pymacs.py: Use `(pymacs-version VERSION)',
- not `(started)'. Check for version discrepancies.
-
- * Makefile: A bit more parameterization.
-
- * : Release 0.2, including ideas and suggestions from others.
- Reported by Brian McErlean, Carel Fellinger, Cedric Adjih,
- Marcin Qrczak Kowalczyk, Paul Winkler and Steffen Ries.
-
--- a/vim/sadness/bike/ide-integration/Pymacs-0.20/ChangeLog-rebox Thu Feb 10 17:11:26 2011 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,146 +0,0 @@
-2002-01-29 François Pinard <pinard@iro.umontreal.ca>
-
- * Pymacs/rebox.py: Use an interactions map instead of the
- interaction attribute, so it works with earlier Python versions.
-
- * Pymacs/rebox.py: Import lisp and Let from Pymacs.
-
-2002-01-13 François Pinard <pinard@iro.umontreal.ca>
-
- * Pymacs/rebox.py (Emacs_Rebox.emacs_engine): Expand flag value,
- when it is neither the - symbol nor a number.
-
-2002-01-08 François Pinard <pinard@iro.umontreal.ca>
-
- * Pymacs/rebox.py (Template.build): Subtract margin from width
- just before actually rebuilding the box.
- Reported by Paul Provost.
-
-2002-01-07 François Pinard <pinard@iro.umontreal.ca>
-
- * Pymacs/rebox.py (main): Implement -v option.
-
- * Pymacs/rebox.py (pymacs_load_hook): Declare set_default_style.
-
- * Pymacs/rebox.py (Emacs_Rebox.clean_undo_after): Debugged.
-
- * Pymacs/rebox.py (Template): New class. Reorgnise all code.
- * Pymacs/rebox.py (engine): Moved out of Rebox class.
- * Pymacs/rebox.py (Rebox, Batch_Rebox): Deleted, as they got empty.
-
- * Pymacs/rebox.py (Emacs_Rebox.clean_undo_after): Rewrite in LISP.
-
-2002-01-06 François Pinard <pinard@iro.umontreal.ca>
-
- * rebox: New file.
-
-2002-01-03 François Pinard <pinard@iro.umontreal.ca>
-
- * Pymacs/rebox.py: New file, translated from Libit/rebox.el.
-
-2000-09-28 François Pinard <pinard@iro.umontreal.ca>
-
- * rebox.el: Replace statistical heuristics for box style recognition
- by more precise checks and explicit priorities between styles. To do
- so, add weights to rebox-templates, replace rebox-building-data by
- rebox-style-data holding regexps, delete rebox-recognition-data.
-
- * rebox.el (rebox-regexp-ruler): New function.
- (rebox-regexp-quote): Add matching for following white space.
- Don't force two characters on each middle line, nor in blank rulers.
- Reported by Paul Provost.
-
-2000-04-28 François Pinard <pinard@iro.umontreal.ca>
-
- * rebox.el (rebox-guess-style): When two styles have equal weight,
- retain the highest numbered, as it probably is the richest.
- Otherwise, simple C++ comments end up with a single slash.
- Reported by Akim Demaille.
-
-2000-04-19 François Pinard <pinard@iro.umontreal.ca>
-
- * rebox.el: Reorganize from bottom-up into top-down.
- (taarna-mode): Deleted.
-
-2000-04-18 François Pinard <pinard@iro.umontreal.ca>
-
- * rebox.el (rebox-show-style, rebox-help-string-for-language,
- rebox-help-string-for-quality, rebox-help-string-for-type): Deleted.
- (rebox-rstrip, rebox-regexp-quote, rebox-unbuild): New functions.
- (rebox-build): New name for rebox-reconstruct.
-
-2000-04-15 François Pinard <pinard@iro.umontreal.ca>
-
- * rebox.el (rebox-guess-style): New function.
- (rebox-engine): Use it. Simplified by using template information.
-
-2000-04-14 François Pinard <pinard@iro.umontreal.ca>
-
- * rebox.el (rebox-templates): New variable.
- (rebox-register-template): New function.
- (rebox-reconstruct): Much simplified by using the above.
-
-2000-04-12 François Pinard <pinard@iro.umontreal.ca>
-
- * rebox.el: Rework the initial documentation block.
- (rebox-reconstruct): Guarantee newline at end for style 241.
- Reported by Marc Feeley and Paul Provost.
-
-2000-02-22 François Pinard <pinard@iro.umontreal.ca>
-
- * rebox.el: Little speed cleanup. Avoid looking-at when easy.
-
-2000-02-10 François Pinard <pinard@iro.umontreal.ca>
-
- * rebox.el: Adjust comment to suggest add-hook instead of setq.
- Reported by Akim Demaille.
-
-2000-01-30 François Pinard <pinard@iro.umontreal.ca>
-
- * rebox.el: Prefer when, unless and cond over if and progn.
- Combine successive setq.
-
- * rebox.el (rebox-engine): Recognise quality for shell boxes.
- Reported by Akim Demaille.
-
-1999-06-30 François Pinard <pinard@iro.umontreal.ca>
-
- * rebox.el: Add GPL comment.
- Reported by Paul Eggert.
-
-1998-03-28 François Pinard <pinard@iro.umontreal.ca>
-
- * rebox.el (rebox-reconstruct): Refill a closing */ with the rest.
- Do not add spaces to a line which is otherwise empty.
-
-1997-12-01 François Pinard <pinard@iro.umontreal.ca>
-
- * rebox.el (rebox-engine): Simplify two regexps, for XEmacs.
- Reported by Ulrich Drepper.
-
-1997-02-17 François Pinard <pinard@iro.umontreal.ca>
-
- * rebox.el (rebox-reconstruct): Ensure indent-tabs-mode is nil.
-
-1997-02-14 François Pinard <pinard@iro.umontreal.ca>
-
- * rebox.el: Corrected a bug demonstrated as the beginning line
- of a paragraph spuriously jumping right spuriously. The full
- match of the beginning of comment was replaced by spaces on the
- initial line, while only \1 needed replacement. This shortened
- this line, causing later nasty effects.
-
-1996-07-10 François Pinard <pinard@iro.umontreal.ca>
-
- * rebox.el: Recognise style 241, so margin does not get doubled.
- Reported by Marc Feeley.
-
-1996-07-09 François Pinard <pinard@iro.umontreal.ca>
-
- * rebox.el: Use symbolic constants for language, quality and type.
-
-1996-06-09 François Pinard <pinard@iro.umontreal.ca>
-
- * rebox.el (rebox-find-and-narrow): Take care of a missing end of
- line after a comment being at end of buffer.
- Reported by Ulrich Drepper.
--- a/vim/sadness/bike/ide-integration/Pymacs-0.20/Makefile Thu Feb 10 17:11:26 2011 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,40 +0,0 @@
-# Interface between Emacs LISP and Python - Makefile.
-# Copyright © 2001, 2002 Progiciels Bourbeau-Pinard inc.
-# François Pinard <pinard@iro.umontreal.ca>, 2001.
-
-# The `README' file provides a few good hints about installation.
-
-### Start of customisation.
-#
-# Somewhere on your Emacs LISP load-path.
-lispdir =
-#
-### End of customisation.
-
-PYSETUP = python setup.py
-DISTRIBUTION := $(shell ./setup -V)
-
-all:
- $(PYSETUP) build
-
-install: all
- @./setup -l '$(lispdir)'
- $(PYSETUP) install
-
-tags:
- (find bin -type f; find -name '*.py') | grep -v '~$$' | etags -
-
-dist:
- $(PYSETUP) sdist
- mv dist/$(DISTRIBUTION).tar.gz .
- rmdir dist
- ls -l *.gz
-
-publish: dist
- traiter README.html > index.html
- chmod 644 index.html $(DISTRIBUTION).tar.gz
- scp -p index.html $(DISTRIBUTION).tar.gz bor:w/pymacs/
- rm index.html $(DISTRIBUTION).tar.gz
- ssh bor rm -vf w/pymacs/Pymacs.tar.gz
- ssh bor ln -vs $(DISTRIBUTION).tar.gz w/pymacs/Pymacs.tar.gz
- ssh bor ls -Llt w/pymacs
--- a/vim/sadness/bike/ide-integration/Pymacs-0.20/PKG-INFO Thu Feb 10 17:11:26 2011 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,10 +0,0 @@
-Metadata-Version: 1.0
-Name: Pymacs
-Version: 0.20
-Summary: Interface between Emacs LISP and Python.
-Home-page: http://www.iro.umontreal.ca/~pinard
-Author: François Pinard
-Author-email: pinard@iro.umontreal.ca
-License: UNKNOWN
-Description: UNKNOWN
-Platform: UNKNOWN
--- a/vim/sadness/bike/ide-integration/Pymacs-0.20/Pymacs/.cvsignore Thu Feb 10 17:11:26 2011 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,1 +0,0 @@
-*.pyc
--- a/vim/sadness/bike/ide-integration/Pymacs-0.20/Pymacs/__init__.py Thu Feb 10 17:11:26 2011 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,30 +0,0 @@
-#!/usr/bin/env python
-# Copyright © 2002 Progiciels Bourbeau-Pinard inc.
-# François Pinard <pinard@iro.umontreal.ca>, 2002.
-
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2, or (at your option)
-# any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software Foundation,
-# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
-
-"""\
-Interface between Emacs Lisp and Python - Module initialisation.
-
-A few symbols are moved in here so they appear to be defined at this level.
-"""
-
-from pymacs import Let, lisp
-
-# Identification of version.
-
-package = 'Pymacs'
-version = '0.20'
--- a/vim/sadness/bike/ide-integration/Pymacs-0.20/Pymacs/pymacs.py Thu Feb 10 17:11:26 2011 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,587 +0,0 @@
-#!/usr/bin/env python
-# Copyright © 2001, 2002 Progiciels Bourbeau-Pinard inc.
-# François Pinard <pinard@iro.umontreal.ca>, 2001.
-
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2, or (at your option)
-# any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software Foundation,
-# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
-
-"""\
-Interface between Emacs Lisp and Python - Python part.
-
-Emacs may launch this module as a stand-alone program, in which case it
-acts as a server of Python facilities for that Emacs session, reading
-requests from standard input and writing replies on standard output.
-
-This module may also be usefully imported by those other Python modules.
-See the Pymacs documentation (in `README') for more information.
-"""
-
-## Note: This code is currently compatible down to Python version 1.5.2.
-## It is probably worth keeping it that way for a good while, still.
-
-import os, string, sys, types
-
-# Python services for Emacs applications.
-
-def main(*arguments):
- """\
-Execute Python services for Emacs, and Emacs services for Python.
-This program is meant to be called from Emacs, using `pymacs.el'.
-
-The program arguments are additional search paths for Python modules.
-"""
- from Pymacs import version
- arguments = list(arguments)
- arguments.reverse()
- for argument in arguments:
- if os.path.isdir(argument):
- sys.path.insert(0, argument)
- lisp._protocol.send('(pymacs-version "%s")' % version)
- lisp._protocol.loop()
-
-class Protocol:
-
- # FIXME: The following should work, but does not:
- #
- # * pymacs.py (Protocol): Declare exceptions as classes, not strings.
- #
- #class ProtocolError(Exception): pass
- #class ReplyException(Exception): pass
- #class ErrorException(Exception): pass
- #
- # I get:
- # (pymacs-eval "lisp('\"abc\"').__class__.__name__")
- # "ReplyException"
-
- ProtocolError = 'ProtocolError'
- ReplyException = 'ReplyException'
- ErrorException = 'ErrorException'
-
- def __init__(self):
- self.freed = []
-
- def loop(self):
- # The server loop repeatedly receives a request from Emacs and
- # returns a response, which is either the value of the received
- # Python expression, or the Python traceback if an error occurs
- # while evaluating the expression.
-
- # The server loop may also be executed, as a recursive invocation,
- # in the context of Emacs serving a Python request. In which
- # case, we might also receive a notification from Emacs telling
- # that the reply has been transmitted, or that an error occurred.
- # A reply notification from Emacs interrupts the loop: the result
- # of this function is the value returned from Emacs.
- while 1:
- try:
- text = self.receive()
- if text[:5] == 'exec ':
- exec eval(text[5:], {}, {})
- status = 'reply'
- argument = None
- else:
- status = 'reply'
- argument = eval(text)
- except Protocol.ReplyException, value:
- return value
- except Protocol.ErrorException, message:
- status = 'error'
- argument = message
- except Protocol.ProtocolError, message:
- sys.stderr.write("Protocol error: %s\n" % message)
- sys.exit(1)
- except KeyboardInterrupt:
- raise
- except:
- import StringIO, traceback
- message = StringIO.StringIO()
- traceback.print_exc(file=message)
- status = 'error'
- argument = message.getvalue()
- # Send an expression to EMACS applying FUNCTION over ARGUMENT,
- # where FUNCTION is `pymacs-STATUS'.
- fragments = []
- write = fragments.append
- if self.freed:
- write('(progn (pymacs-free-lisp')
- for index in self.freed:
- write(' %d' % index)
- write(') ')
- write('(pymacs-%s ' % status)
- print_lisp(argument, write, quoted=1)
- write(')')
- if self.freed:
- write(')')
- self.freed = []
- self.send(string.join(fragments, ''))
-
- def receive(self):
- # Receive a Python expression from Emacs, return its text unevaluated.
- text = sys.stdin.read(3)
- if not text or text[0] != '>':
- raise Protocol.ProtocolError, "`>' expected."
- while text[-1] != '\t':
- text = text + sys.stdin.read(1)
- return sys.stdin.read(int(text[1:-1]))
-
- def send(self, text):
- # Send TEXT to Emacs, which is an expression to evaluate.
- if text[-1] == '\n':
- sys.stdout.write('<%d\t%s' % (len(text), text))
- else:
- sys.stdout.write('<%d\t%s\n' % (len(text) + 1, text))
- sys.stdout.flush()
-
-def reply(value):
- # This function implements the `reply' pseudo-function.
- raise Protocol.ReplyException, value
-
-def error(message):
- # This function implements the `error' pseudo-function.
- raise Protocol.ErrorException, "Emacs: %s" % message
-
-def pymacs_load_helper(file_without_extension, prefix):
- # This function imports a Python module, then returns a Lisp expression
- # which, when later evaluated, will install trampoline definitions in
- # Emacs for accessing the Python module facilities. MODULE may be a
- # full path, yet without the `.py' or `.pyc' extension, in which case
- # the directory is temporarily added to the Python search path for
- # the sole duration of that import. All defined symbols on the Lisp
- # side have have PREFIX prepended, and have Python underlines in Python
- # turned into dashes. If PREFIX is None, it then defaults to the base
- # name of MODULE with underlines turned to dashes, followed by a dash.
- directory, module_name = os.path.split(file_without_extension)
- module_components = string.split(module_name, '.')
- if prefix is None:
- prefix = string.replace(module_components[-1], '_', '-') + '-'
- try:
- object = sys.modules.get(module_name)
- if object:
- reload(object)
- else:
- try:
- if directory:
- sys.path.insert(0, directory)
- object = __import__(module_name)
- finally:
- if directory:
- del sys.path[0]
- # Whenever MODULE_NAME is of the form [PACKAGE.]...MODULE,
- # __import__ returns the outer PACKAGE, not the module.
- for component in module_components[1:]:
- object = getattr(object, component)
- except ImportError:
- return None
- load_hook = object.__dict__.get('pymacs_load_hook')
- if load_hook:
- load_hook()
- interactions = object.__dict__.get('interactions', {})
- if type(interactions) != types.DictType:
- interactions = {}
- arguments = []
- for name, value in object.__dict__.items():
- if callable(value) and value is not lisp:
- arguments.append(allocate_python(value))
- arguments.append(lisp[prefix + string.replace(name, '_', '-')])
- try:
- interaction = value.interaction
- except AttributeError:
- interaction = interactions.get(value)
- if callable(interaction):
- arguments.append(allocate_python(interaction))
- else:
- arguments.append(interaction)
- if arguments:
- return [lisp.progn,
- [lisp.pymacs_defuns, [lisp.quote, arguments]],
- object]
- return [lisp.quote, object]
-
-def doc_string(object):
- if hasattr(object, '__doc__'):
- return object.__doc__
-
-# Garbage collection matters.
-
-# Many Python types do not have direct Lisp equivalents, and may not be
-# directly returned to Lisp for this reason. They are rather allocated in
-# a list of handles, below, and a handle index is used for communication
-# instead of the Python value. Whenever such a handle is freed from the
-# Lisp side, its index is added of a freed list for later reuse.
-
-python = []
-freed_list = []
-
-def allocate_python(value):
- assert type(value) != type(''), (type(value), `value`)
- # Allocate some handle to hold VALUE, return its index.
- if freed_list:
- index = freed_list[-1]
- del freed_list[-1]
- python[index] = value
- else:
- index = len(python)
- python.append(value)
- return index
-
-def free_python(*indices):
- # Return many handles to the pool.
- for index in indices:
- python[index] = None
- freed_list.append(index)
-
-def zombie_python(*indices):
- # Ensure that some handles are _not_ in the pool.
- for index in indices:
- while index >= len(python):
- freed_list.append(len(python))
- python.append(None)
- python[index] = zombie
- freed_list.remove(index)
- # Merely to make `*Pymacs*' a bit more readable.
- freed_list.sort()
-
-def zombie(*arguments):
- error("Object vanished when helper was killed.")
-
-# Emacs services for Python applications.
-
-class Let:
-
- def __init__(self, **keywords):
- self.stack = []
- apply(self.push, (), keywords)
-
- def __del__(self):
- while self.stack:
- method = self.stack[-1][0]
- if method == 'variables':
- self.pop()
- elif method == 'excursion':
- self.pop_excursion()
- elif method == 'match_data':
- self.pop_match_data()
- elif method == 'restriction':
- self.pop_restriction()
- elif method == 'selected_window':
- self.pop_selected_window()
- elif method == 'window_excursion':
- self.pop_window_excursion()
-
- def __nonzero__(self):
- # So stylistic `if let:' executes faster.
- return 1
-
- def push(self, **keywords):
- pairs = []
- for name, value in keywords.items():
- pairs.append((name, getattr(lisp, name).value()))
- setattr(lisp, name, value)
- self.stack.append(('variables', pairs))
- return self
-
- def pop(self):
- method, pairs = self.stack[-1]
- assert method == 'variables', self.stack[-1]
- del self.stack[-1]
- for name, value in pairs:
- setattr(lisp, name, value)
-
- def push_excursion(self):
- self.stack.append(('excursion',
- (lisp.current_buffer(),
- lisp.point_marker(), lisp.mark_marker())))
- return self
-
- def pop_excursion(self):
- method, (buffer, point_marker, mark_marker) = self.stack[-1]
- assert method == 'excursion', self.stack[-1]
- del self.stack[-1]
- lisp.set_buffer(buffer)
- lisp.goto_char(point_marker)
- lisp.set_mark(mark_marker)
- lisp.set_marker(point_marker, None)
- lisp.set_marker(mark_marker, None)
-
- def push_match_data(self):
- self.stack.append(('match_data', lisp.match_data()))
- return self
-
- def pop_match_data(self):
- method, match_data = self.stack[-1]
- assert method == 'match_data', self.stack[-1]
- del self.stack[-1]
- lisp.set_match_data(match_data)
-
- def push_restriction(self):
- self.stack.append(('restriction',
- (lisp.point_min_marker(), lisp.point_max_marker())))
- return self
-
- def pop_restriction(self):
- method, (point_min_marker, point_max_marker) = self.stack[-1]
- assert method == 'restriction', self.stack[-1]
- del self.stack[-1]
- lisp.narrow_to_region(point_min_marker, point_max_marker)
- lisp.set_marker(point_min_marker, None)
- lisp.set_marker(point_max_marker, None)
-
- def push_selected_window(self):
- self.stack.append(('selected_window', lisp.selected_window()))
- return self
-
- def pop_selected_window(self):
- method, selected_window = self.stack[-1]
- assert method == 'selected_window', self.stack[-1]
- del self.stack[-1]
- lisp.select_window(selected_window)
-
- def push_window_excursion(self):
- self.stack.append(('window_excursion',
- lisp.current_window_configuration()))
- return self
-
- def pop_window_excursion(self):
- method, current_window_configuration = self.stack[-1]
- assert method == 'window_excursion', self.stack[-1]
- del self.stack[-1]
- lisp.set_window_configuration(current_window_configuration)
-
-class Symbol:
-
- def __init__(self, text):
- self.text = text
-
- def __repr__(self):
- return 'lisp[%s]' % repr(self.text)
-
- def __str__(self):
- return '\'' + self.text
-
- def value(self):
- return lisp(self.text)
-
- def copy(self):
- return lisp('(pymacs-expand %s)' % self.text)
-
- def set(self, value):
- if value is None:
- lisp('(setq %s nil)' % self.text)
- else:
- fragments = []
- write = fragments.append
- write('(progn (setq %s ' % self.text)
- print_lisp(value, write, quoted=1)
- write(') nil)')
- lisp(string.join(fragments, ''))
-
- def __call__(self, *arguments):
- fragments = []
- write = fragments.append
- write('(%s' % self.text)
- for argument in arguments:
- write(' ')
- print_lisp(argument, write, quoted=1)
- write(')')
- return lisp(string.join(fragments, ''))
-
-class Lisp:
-
- def __init__(self, index):
- self.index = index
-
- def __del__(self):
- lisp._protocol.freed.append(self.index)
-
- def __repr__(self):
- return ('lisp(%s)' % repr(lisp('(prin1-to-string %s)' % self)))
-
- def __str__(self):
- return '(aref pymacs-lisp %d)' % self.index
-
- def value(self):
- return self
-
- def copy(self):
- return lisp('(pymacs-expand %s)' % self)
-
-class Buffer(Lisp):
- pass
-
- #def write(text):
- # # So you could do things like
- # # print >>lisp.current_buffer(), "Hello World"
- # lisp.insert(text, self)
-
- #def point(self):
- # return lisp.point(self)
-
-class List(Lisp):
-
- def __call__(self, *arguments):
- fragments = []
- write = fragments.append
- write('(%s' % self)
- for argument in arguments:
- write(' ')
- print_lisp(argument, write, quoted=1)
- write(')')
- return lisp(string.join(fragments, ''))
-
- def __len__(self):
- return lisp('(length %s)' % self)
-
- def __getitem__(self, key):
- value = lisp('(nth %d %s)' % (key, self))
- if value is None and key >= len(self):
- raise IndexError, key
- return value
-
- def __setitem__(self, key, value):
- fragments = []
- write = fragments.append
- write('(setcar (nthcdr %d %s) ' % (key, self))
- print_lisp(value, write, quoted=1)
- write(')')
- lisp(string.join(fragments, ''))
-
-class Table(Lisp):
-
- def __getitem__(self, key):
- fragments = []
- write = fragments.append
- write('(gethash ')
- print_lisp(key, write, quoted=1)
- write(' %s)' % self)
- return lisp(string.join(fragments, ''))
-
- def __setitem__(self, key, value):
- fragments = []
- write = fragments.append
- write('(puthash ')
- print_lisp(key, write, quoted=1)
- write(' ')
- print_lisp(value, write, quoted=1)
- write(' %s)' % self)
- lisp(string.join(fragments, ''))
-
-class Vector(Lisp):
-
- def __len__(self):
- return lisp('(length %s)' % self)
-
- def __getitem__(self, key):
- return lisp('(aref %s %d)' % (self, key))
-
- def __setitem__(self, key, value):
- fragments = []
- write = fragments.append
- write('(aset %s %d ' % (self, key))
- print_lisp(value, write, quoted=1)
- write(')')
- lisp(string.join(fragments, ''))
-
-class Lisp_Interface:
-
- def __init__(self):
- self.__dict__['_cache'] = {'nil': None}
- self.__dict__['_protocol'] = Protocol()
-
- def __call__(self, text):
- self._protocol.send('(progn %s)' % text)
- return self._protocol.loop()
-
- def __getattr__(self, name):
- if name[0] == '_':
- raise AttributeError, name
- return self[string.replace(name, '_', '-')]
-
- def __setattr__(self, name, value):
- if name[0] == '_':
- raise AttributeError, name
- self[string.replace(name, '_', '-')] = value
-
- def __getitem__(self, name):
- try:
- return self._cache[name]
- except KeyError:
- symbol = self._cache[name] = Symbol(name)
- return symbol
-
- def __setitem__(self, name, value):
- try:
- symbol = self._cache[name]
- except KeyError:
- symbol = self._cache[name] = Symbol(name)
- symbol.set(value)
-
-lisp = Lisp_Interface()
-
-print_lisp_quoted_specials = {'"': '\\"', '\\': '\\\\', '\b': '\\b',
- '\f': '\\f', '\n': '\\n', '\t': '\\t'}
-
-def print_lisp(value, write, quoted=0):
- if value is None:
- write('nil')
- elif type(value) == types.IntType:
- write(repr(value))
- elif type(value) == types.FloatType:
- write(repr(value))
- elif type(value) == types.StringType:
- write('"')
- for character in value:
- special = print_lisp_quoted_specials.get(character)
- if special is not None:
- write(special)
- elif 32 <= ord(character) < 127:
- write(character)
- else:
- write('\\%.3o' % ord(character))
- write('"')
- elif type(value) == types.ListType:
- if quoted:
- write("'")
- if len(value) == 0:
- write('nil')
- elif len(value) == 2 and value[0] == lisp.quote:
- write("'")
- print_lisp(value[1], write)
- else:
- write('(')
- print_lisp(value[0], write)
- for sub_value in value[1:]:
- write(' ')
- print_lisp(sub_value, write)
- write(')')
- elif type(value) == types.TupleType:
- write('[')
- if len(value) > 0:
- print_lisp(value[0], write)
- for sub_value in value[1:]:
- write(' ')
- print_lisp(sub_value, write)
- write(']')
- elif isinstance(value, Lisp):
- write(str(value))
- elif isinstance(value, Symbol):
- if quoted:
- write("'")
- write(value.text)
- elif callable(value):
- write('(pymacs-defun %d)' % allocate_python(value))
- else:
- write('(pymacs-python %d)' % allocate_python(value))
-
-if __name__ == '__main__':
- apply(main, sys.argv[1:])
--- a/vim/sadness/bike/ide-integration/Pymacs-0.20/Pymacs/rebox.py Thu Feb 10 17:11:26 2011 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,1235 +0,0 @@
-#!/usr/bin/env python
-# Copyright © 1991-1998, 2000, 2002 Progiciels Bourbeau-Pinard inc.
-# François Pinard <pinard@iro.umontreal.ca>, April 1991.
-
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2, or (at your option)
-# any later version.
-
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software Foundation,
-# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-
-"""\
-Handling of boxed comments in various box styles.
-
-Introduction
-------------
-
-For comments held within boxes, it is painful to fill paragraphs, while
-stretching or shrinking the surrounding box "by hand", as needed. This piece
-of Python code eases my life on this. It may be used interactively from
-within Emacs through the Pymacs interface, or in batch as a script which
-filters a single region to be reformatted. I find only fair, while giving
-all sources for a package using such boxed comments, to also give the
-means I use for nicely modifying comments. So here they are!
-
-Box styles
-----------
-
-Each supported box style has a number associated with it. This number is
-arbitrary, yet by _convention_, it holds three non-zero digits such the the
-hundreds digit roughly represents the programming language, the tens digit
-roughly represents a box quality (or weight) and the units digit roughly
-a box type (or figure). An unboxed comment is merely one of box styles.
-Language, quality and types are collectively referred to as style attributes.
-
-When rebuilding a boxed comment, attributes are selected independently
-of each other. They may be specified by the digits of the value given
-as Emacs commands argument prefix, or as the `-s' argument to the `rebox'
-script when called from the shell. If there is no such prefix, or if the
-corresponding digit is zero, the attribute is taken from the value of the
-default style instead. If the corresponding digit of the default style
-is also zero, than the attribute is recognised and taken from the actual
-boxed comment, as it existed before prior to the command. The value 1,
-which is the simplest attribute, is ultimately taken if the parsing fails.
-
-A programming language is associated with comment delimiters. Values are
-100 for none or unknown, 200 for `/*' and `*/' as in plain C, 300 for `//'
-as in C++, 400 for `#' as in most scripting languages, 500 for `;' as in
-LISP or assembler and 600 for `%' as in TeX or PostScript.
-
-Box quality differs according to language. For unknown languages (100) or
-for the C language (200), values are 10 for simple, 20 for rounded, and
-30 or 40 for starred. Simple quality boxes (10) use comment delimiters
-to left and right of each comment line, and also for the top or bottom
-line when applicable. Rounded quality boxes (20) try to suggest rounded
-corners in boxes. Starred quality boxes (40) mostly use a left margin of
-asterisks or X'es, and use them also in box surroundings. For all others
-languages, box quality indicates the thickness in characters of the left
-and right sides of the box: values are 10, 20, 30 or 40 for 1, 2, 3 or 4
-characters wide. With C++, quality 10 is not useful, it is not allowed.
-
-Box type values are 1 for fully opened boxes for which boxing is done
-only for the left and right but not for top or bottom, 2 for half
-single lined boxes for which boxing is done on all sides except top,
-3 for fully single lined boxes for which boxing is done on all sides,
-4 for half double lined boxes which is like type 2 but more bold,
-or 5 for fully double lined boxes which is like type 3 but more bold.
-
-The special style 221 is for C comments between a single opening `/*'
-and a single closing `*/'. The special style 111 deletes a box.
-
-Batch usage
------------
-
-Usage is `rebox [OPTION]... [FILE]'. By default, FILE is reformatted to
-standard output by refilling the comment up to column 79, while preserving
-existing boxed comment style. If FILE is not given, standard input is read.
-Options may be:
-
- -n Do not refill the comment inside its box, and ignore -w.
- -s STYLE Replace box style according to STYLE, as explained above.
- -t Replace initial sequence of spaces by TABs on each line.
- -v Echo both the old and the new box styles on standard error.
- -w WIDTH Try to avoid going over WIDTH columns per line.
-
-So, a single boxed comment is reformatted by invocation. `vi' users, for
-example, would need to delimit the boxed comment first, before executing
-the `!}rebox' command (is this correct? my `vi' recollection is far away).
-
-Batch usage is also slow, as internal structures have to be reinitialised
-at every call. Producing a box in a single style is fast, but recognising
-the previous style requires setting up for all possible styles.
-
-Emacs usage
------------
-
-For most Emacs language editing modes, refilling does not make sense
-outside comments, one may redefine the `M-q' command and link it to this
-Pymacs module. For example, I use this in my `.emacs' file:
-
- (add-hook 'c-mode-hook 'fp-c-mode-routine)
- (defun fp-c-mode-routine ()
- (local-set-key "\M-q" 'rebox-comment))
- (autoload 'rebox-comment "rebox" nil t)
- (autoload 'rebox-region "rebox" nil t)
-
-with a "rebox.el" file having this single line:
-
- (pymacs-load "Pymacs.rebox")
-
-Install Pymacs from `http://www.iro.umontreal.ca/~pinard/pymacs.tar.gz'.
-
-The Emacs function `rebox-comment' automatically discovers the extent of
-the boxed comment near the cursor, possibly refills the text, then adjusts
-the box style. When this command is executed, the cursor should be within
-a comment, or else it should be between two comments, in which case the
-command applies to the next comment. The function `rebox-region' does
-the same, except that it takes the current region as a boxed comment.
-Both commands obey numeric prefixes to add or remove a box, force a
-particular box style, or to prevent refilling of text. Without such
-prefixes, the commands may deduce the current box style from the comment
-itself so the style is preserved.
-
-The default style initial value is nil or 0. It may be preset to another
-value through calling `rebox-set-default-style' from Emacs LISP, or changed
-to anything else though using a negative value for a prefix, in which case
-the default style is set to the absolute value of the prefix.
-
-A `C-u' prefix avoids refilling the text, but forces using the default box
-style. `C-u -' lets the user interact to select one attribute at a time.
-
-Adding new styles
------------------
-
-Let's suppose you want to add your own boxed comment style, say:
-
- //--------------------------------------------+
- // This is the style mandated in our company.
- //--------------------------------------------+
-
-You might modify `rebox.py' but then, you will have to edit it whenever you
-get a new release of `pybox.py'. Emacs users might modify their `.emacs'
-file or their `rebox.el' bootstrap, if they use one. In either cases,
-after the `(pymacs-load "Pymacs.rebox")' line, merely add:
-
- (rebox-Template NNN MMM ["//-----+"
- "// box "
- "//-----+"])
-
-If you use the `rebox' script rather than Emacs, the simplest is to make
-your own. This is easy, as it is very small. For example, the above
-style could be implemented by using this script instead of `rebox':
-
- #!/usr/bin/env python
- import sys
- from Pymacs import rebox
- rebox.Template(226, 325, ('//-----+',
- '// box ',
- '//-----+'))
- apply(rebox.main, tuple(sys.argv[1:]))
-
-In all cases, NNN is the style three-digit number, with no zero digit.
-Pick any free style number, you are safe with 911 and up. MMM is the
-recognition priority, only used to disambiguate the style of a given boxed
-comments, when it matches many styles at once. Try something like 400.
-Raise or lower that number as needed if you observe false matches.
-
-On average, the template uses three lines of equal length. Do not worry if
-this implies a few trailing spaces, they will be cleaned up automatically
-at box generation time. The first line or the third line may be omitted
-to create vertically opened boxes. But the middle line may not be omitted,
-it ought to include the word `box', which will get replaced by your actual
-comment. If the first line is shorter than the middle one, it gets merged
-at the start of the comment. If the last line is shorter than the middle
-one, it gets merged at the end of the comment and is refilled with it.
-
-History
--------
-
-I first observed rounded corners, as in style 223 boxes, in code from
-Warren Tucker, a previous maintainer of the `shar' package, circa 1980.
-
-Except for very special files, I carefully avoided boxed comments for
-real work, as I found them much too hard to maintain. My friend Paul
-Provost was working at Taarna, a computer graphics place, which had boxes
-as part of their coding standards. He asked that we try something to get
-him out of his misery, and this how `rebox.el' was originally written.
-I did not plan to use it for myself, but Paul was so enthusiastic that I
-timidly started to use boxes in my things, very little at first, but more
-and more as time passed, still in doubt that it was a good move. Later,
-many friends spontaneously started to use this tool for real, some being very
-serious workers. This convinced me that boxes are acceptable, after all.
-
-I do not use boxes much with Python code. It is so legible that boxing
-is not that useful. Vertical white space is less necessary, too. I even
-avoid white lines within functions. Comments appear prominent enough when
-using highlighting editors like Emacs or nice printer tools like `enscript'.
-
-After Emacs could be extended with Python, in 2001, I translated `rebox.el'
-into `rebox.py', and added the facility to use it as a batch script.
-"""
-
-## Note: This code is currently compatible down to Python version 1.5.2.
-## It is probably worth keeping it that way for a good while, still.
-
-## Note: a double hash comment introduces a group of functions or methods.
-
-import re, string, sys
-
-def main(*arguments):
- refill = 1
- style = None
- tabify = 0
- verbose = 0
- width = 79
- import getopt
- options, arguments = getopt.getopt(arguments, 'ns:tvw:', ['help'])
- for option, value in options:
- if option == '--help':
- sys.stdout.write(__doc__)
- sys.exit(0)
- elif option == '-n':
- refill = 0
- elif option == '-s':
- style = int(value)
- elif option == '-t':
- tabify = 1
- elif option == '-v':
- verbose = 1
- elif option == '-w':
- width = int(value)
- if len(arguments) == 0:
- text = sys.stdin.read()
- elif len(arguments) == 1:
- text = open(arguments[0]).read()
- else:
- sys.stderr.write("Invalid usage, try `rebox --help' for help.\n")
- sys.exit(1)
- old_style, new_style, text, position = engine(
- text, style=style, width=width, refill=refill, tabify=tabify)
- if text is None:
- sys.stderr.write("* Cannot rebox to style %d.\n" % new_style)
- sys.exit(1)
- sys.stdout.write(text)
- if verbose:
- if old_style == new_style:
- sys.stderr.write("Reboxed with style %d.\n" % old_style)
- else:
- sys.stderr.write("Reboxed from style %d to %d.\n"
- % (old_style, new_style))
-
-def pymacs_load_hook():
- global interactions, lisp, Let, region, comment, set_default_style
- from Pymacs import lisp, Let
- emacs_rebox = Emacs_Rebox()
- # Declare functions for Emacs to import.
- interactions = {}
- region = emacs_rebox.region
- interactions[region] = 'P'
- comment = emacs_rebox.comment
- interactions[comment] = 'P'
- set_default_style = emacs_rebox.set_default_style
-
-class Emacs_Rebox:
-
- def __init__(self):
- self.default_style = None
-
- def set_default_style(self, style):
- """\
-Set the default style to STYLE.
-"""
- self.default_style = style
-
- def region(self, flag):
- """\
-Rebox the boxed comment in the current region, obeying FLAG.
-"""
- self.emacs_engine(flag, self.find_region)
-
- def comment(self, flag):
- """\
-Rebox the surrounding boxed comment, obeying FLAG.
-"""
- self.emacs_engine(flag, self.find_comment)
-
- def emacs_engine(self, flag, find_limits):
- """\
-Rebox text while obeying FLAG. Call FIND_LIMITS to discover the extent
-of the boxed comment.
-"""
- # `C-u -' means that box style is to be decided interactively.
- if flag == lisp['-']:
- flag = self.ask_for_style()
- # If FLAG is zero or negative, only change default box style.
- if type(flag) is type(0) and flag <= 0:
- self.default_style = -flag
- lisp.message("Default style set to %d" % -flag)
- return
- # Decide box style and refilling.
- if flag is None:
- style = self.default_style
- refill = 1
- elif type(flag) == type(0):
- if self.default_style is None:
- style = flag
- else:
- style = merge_styles(self.default_style, flag)
- refill = 1
- else:
- flag = flag.copy()
- if type(flag) == type([]):
- style = self.default_style
- refill = 0
- else:
- lisp.error("Unexpected flag value %s" % flag)
- # Prepare for reboxing.
- lisp.message("Reboxing...")
- checkpoint = lisp.buffer_undo_list.value()
- start, end = find_limits()
- text = lisp.buffer_substring(start, end)
- width = lisp.fill_column.value()
- tabify = lisp.indent_tabs_mode.value() is not None
- point = lisp.point()
- if start <= point < end:
- position = point - start
- else:
- position = None
- # Rebox the text and replace it in Emacs buffer.
- old_style, new_style, text, position = engine(
- text, style=style, width=width,
- refill=refill, tabify=tabify, position=position)
- if text is None:
- lisp.error("Cannot rebox to style %d" % new_style)
- lisp.delete_region(start, end)
- lisp.insert(text)
- if position is not None:
- lisp.goto_char(start + position)
- # Collapse all operations into a single one, for Undo.
- self.clean_undo_after(checkpoint)
- # We are finished, tell the user.
- if old_style == new_style:
- lisp.message("Reboxed with style %d" % old_style)
- else:
- lisp.message("Reboxed from style %d to %d"
- % (old_style, new_style))
-
- def ask_for_style(self):
- """\
-Request the style interactively, using the minibuffer.
-"""
- language = quality = type = None
- while language is None:
- lisp.message("\
-Box language is 100-none, 200-/*, 300-//, 400-#, 500-;, 600-%%")
- key = lisp.read_char()
- if key >= ord('0') and key <= ord('6'):
- language = key - ord('0')
- while quality is None:
- lisp.message("\
-Box quality/width is 10-simple/1, 20-rounded/2, 30-starred/3 or 40-starred/4")
- key = lisp.read_char()
- if key >= ord('0') and key <= ord('4'):
- quality = key - ord('0')
- while type is None:
- lisp.message("\
-Box type is 1-opened, 2-half-single, 3-single, 4-half-double or 5-double")
- key = lisp.read_char()
- if key >= ord('0') and key <= ord('5'):
- type = key - ord('0')
- return 100*language + 10*quality + type
-
- def find_region(self):
- """\
-Return the limits of the region.
-"""
- return lisp.point(), lisp.mark(lisp.t)
-
- def find_comment(self):
- """\
-Find and return the limits of the block of comments following or enclosing
-the cursor, or return an error if the cursor is not within such a block
-of comments. Extend it as far as possible in both directions.
-"""
- let = Let()
- let.push_excursion()
- # Find the start of the current or immediately following comment.
- lisp.beginning_of_line()
- lisp.skip_chars_forward(' \t\n')
- lisp.beginning_of_line()
- if not language_matcher[0](self.remainder_of_line()):
- temp = lisp.point()
- if not lisp.re_search_forward('\\*/', None, lisp.t):
- lisp.error("outside any comment block")
- lisp.re_search_backward('/\\*')
- if lisp.point() > temp:
- lisp.error("outside any comment block")
- temp = lisp.point()
- lisp.beginning_of_line()
- lisp.skip_chars_forward(' \t')
- if lisp.point() != temp:
- lisp.error("text before start of comment")
- lisp.beginning_of_line()
- start = lisp.point()
- language = guess_language(self.remainder_of_line())
- # Find the end of this comment.
- if language == 2:
- lisp.search_forward('*/')
- if not lisp.looking_at('[ \t]*$'):
- lisp.error("text after end of comment")
- lisp.end_of_line()
- if lisp.eobp():
- lisp.insert('\n')
- else:
- lisp.forward_char(1)
- end = lisp.point()
- # Try to extend the comment block backwards.
- lisp.goto_char(start)
- while not lisp.bobp():
- if language == 2:
- lisp.skip_chars_backward(' \t\n')
- if not lisp.looking_at('[ \t]*\n[ \t]*/\\*'):
- break
- if lisp.point() < 2:
- break
- lisp.backward_char(2)
- if not lisp.looking_at('\\*/'):
- break
- lisp.re_search_backward('/\\*')
- temp = lisp.point()
- lisp.beginning_of_line()
- lisp.skip_chars_forward(' \t')
- if lisp.point() != temp:
- break
- lisp.beginning_of_line()
- else:
- lisp.previous_line(1)
- if not language_matcher[language](self.remainder_of_line()):
- break
- start = lisp.point()
- # Try to extend the comment block forward.
- lisp.goto_char(end)
- while language_matcher[language](self.remainder_of_line()):
- if language == 2:
- lisp.re_search_forward('[ \t]*/\\*')
- lisp.re_search_forward('\\*/')
- if lisp.looking_at('[ \t]*$'):
- lisp.beginning_of_line()
- lisp.forward_line(1)
- end = lisp.point()
- else:
- lisp.forward_line(1)
- end = lisp.point()
- return start, end
-
- def remainder_of_line(self):
- """\
-Return all characters between point and end of line in Emacs buffer.
-"""
- return lisp('''\
-(buffer-substring (point) (save-excursion (skip-chars-forward "^\n") (point)))
-''')
-
- def clean_undo_after_old(self, checkpoint):
- """\
-Remove all intermediate boundaries from the Undo list since CHECKPOINT.
-"""
- # Declare some LISP functions.
- car = lisp.car
- cdr = lisp.cdr
- eq = lisp.eq
- setcdr = lisp.setcdr
- # Remove any `nil' delimiter recently added to the Undo list.
- cursor = lisp.buffer_undo_list.value()
- if not eq(cursor, checkpoint):
- tail = cdr(cursor)
- while not eq(tail, checkpoint):
- if car(tail):
- cursor = tail
- tail = cdr(cursor)
- else:
- tail = cdr(tail)
- setcdr(cursor, tail)
-
- def clean_undo_after(self, checkpoint):
- """\
-Remove all intermediate boundaries from the Undo list since CHECKPOINT.
-"""
- lisp("""
-(let ((undo-list %s))
- (if (not (eq buffer-undo-list undo-list))
- (let ((cursor buffer-undo-list))
- (while (not (eq (cdr cursor) undo-list))
- (if (car (cdr cursor))
- (setq cursor (cdr cursor))
- (setcdr cursor (cdr (cdr cursor)))))))
- nil)
-"""
- % (checkpoint or 'nil'))
-
-def engine(text, style=None, width=79, refill=1, tabify=0, position=None):
- """\
-Add, delete or adjust a boxed comment held in TEXT, according to STYLE.
-STYLE values are explained at beginning of this file. Any zero attribute
-in STYLE indicates that the corresponding attribute should be recovered
-from the currently existing box. Produced lines will not go over WIDTH
-columns if possible, if refilling gets done. But if REFILL is false, WIDTH
-is ignored. If TABIFY is true, the beginning of produced lines will have
-spaces replace by TABs. POSITION is either None, or a character position
-within TEXT. Returns four values: the old box style, the new box style,
-the reformatted text, and either None or the adjusted value of POSITION in
-the new text. The reformatted text is returned as None if the requested
-style does not exist.
-"""
- last_line_complete = text and text[-1] == '\n'
- if last_line_complete:
- text = text[:-1]
- lines = string.split(string.expandtabs(text), '\n')
- # Decide about refilling and the box style to use.
- new_style = 111
- old_template = guess_template(lines)
- new_style = merge_styles(new_style, old_template.style)
- if style is not None:
- new_style = merge_styles(new_style, style)
- new_template = template_registry.get(new_style)
- # Interrupt processing if STYLE does not exist.
- if not new_template:
- return old_template.style, new_style, None, None
- # Remove all previous comment marks, and left margin.
- if position is not None:
- marker = Marker()
- marker.save_position(text, position, old_template.characters())
- lines, margin = old_template.unbuild(lines)
- # Ensure only one white line between paragraphs.
- counter = 1
- while counter < len(lines) - 1:
- if lines[counter] == '' and lines[counter-1] == '':
- del lines[counter]
- else:
- counter = counter + 1
- # Rebuild the boxed comment.
- lines = new_template.build(lines, width, refill, margin)
- # Retabify to the left only.
- if tabify:
- for counter in range(len(lines)):
- tabs = len(re.match(' *', lines[counter]).group()) / 8
- lines[counter] = '\t' * tabs + lines[counter][8*tabs:]
- # Restore the point position.
- text = string.join(lines, '\n')
- if last_line_complete:
- text = text + '\n'
- if position is not None:
- position = marker.get_position(text, new_template.characters())
- return old_template.style, new_style, text, position
-
-def guess_language(line):
- """\
-Guess the language in use for LINE.
-"""
- for language in range(len(language_matcher) - 1, 1, -1):
- if language_matcher[language](line):
- return language
- return 1
-
-def guess_template(lines):
- """\
-Find the heaviest box template matching LINES.
-"""
- best_template = None
- for template in template_registry.values():
- if best_template is None or template > best_template:
- if template.match(lines):
- best_template = template
- return best_template
-
-def left_margin_size(lines):
- """\
-Return the width of the left margin for all LINES. Ignore white lines.
-"""
- margin = None
- for line in lines:
- counter = len(re.match(' *', line).group())
- if counter != len(line):
- if margin is None or counter < margin:
- margin = counter
- if margin is None:
- margin = 0
- return margin
-
-def merge_styles(original, update):
- """\
-Return style attributes as per ORIGINAL, in which attributes have been
-overridden by non-zero corresponding style attributes from UPDATE.
-"""
- style = [original / 100, original / 10 % 10, original % 10]
- merge = update / 100, update / 10 % 10, update % 10
- for counter in range(3):
- if merge[counter]:
- style[counter] = merge[counter]
- return 100*style[0] + 10*style[1] + style[2]
-
-def refill_lines(lines, width):
- """\
-Refill LINES, trying to not produce lines having more than WIDTH columns.
-"""
- # Try using GNU `fmt'.
- import tempfile, os
- name = tempfile.mktemp()
- open(name, 'w').write(string.join(lines, '\n') + '\n')
- process = os.popen('fmt -cuw %d %s' % (width, name))
- text = process.read()
- os.remove(name)
- if process.close() is None:
- return map(string.expandtabs, string.split(text, '\n')[:-1])
- # If `fmt' failed, do refilling more naively, wihtout using the
- # Knuth algorithm, nor protecting full stops at end of sentences.
- lines.append(None)
- new_lines = []
- new_line = ''
- start = 0
- for end in range(len(lines)):
- if not lines[end]:
- margin = left_margin_size(lines[start:end])
- for line in lines[start:end]:
- counter = len(re.match(' *', line).group())
- if counter > margin:
- if new_line:
- new_lines.append(' ' * margin + new_line)
- new_line = ''
- indent = counter - margin
- else:
- indent = 0
- for word in string.split(line):
- if new_line:
- if len(new_line) + 1 + len(word) > width:
- new_lines.append(' ' * margin + new_line)
- new_line = word
- else:
- new_line = new_line + ' ' + word
- else:
- new_line = ' ' * indent + word
- indent = 0
- if new_line:
- new_lines.append(' ' * margin + new_line)
- new_line = ''
- if lines[end] is not None:
- new_lines.append('')
- start = end + 1
- return new_lines
-
-class Marker:
-
- ## Heuristic to simulate a marker while reformatting boxes.
-
- def save_position(self, text, position, ignorable):
- """\
-Given a TEXT and a POSITION in that text, save the adjusted position
-by faking that all IGNORABLE characters before POSITION were removed.
-"""
- ignore = {}
- for character in ' \t\r\n' + ignorable:
- ignore[character] = None
- counter = 0
- for character in text[:position]:
- if ignore.has_key(character):
- counter = counter + 1
- self.position = position - counter
-
- def get_position(self, text, ignorable, latest=0):
- """\
-Given a TEXT, return the value that would yield the currently saved position,
-if it was saved by `save_position' with IGNORABLE. Unless the position lies
-within a series of ignorable characters, LATEST has no effect in practice.
-If LATEST is true, return the biggest possible value instead of the smallest.
-"""
- ignore = {}
- for character in ' \t\r\n' + ignorable:
- ignore[character] = None
- counter = 0
- position = 0
- if latest:
- for character in text:
- if ignore.has_key(character):
- counter = counter + 1
- else:
- if position == self.position:
- break
- position = position + 1
- elif self.position > 0:
- for character in text:
- if ignore.has_key(character):
- counter = counter + 1
- else:
- position = position + 1
- if position == self.position:
- break
- return position + counter
-
-## Template processing.
-
-class Template:
-
- def __init__(self, style, weight, lines):
- """\
-Digest and register a single template. The template is numbered STYLE,
-has a parsing WEIGHT, and is described by one to three LINES.
-STYLE should be used only once through all `declare_template' calls.
-
-One of the lines should contain the substring `box' to represent the comment
-to be boxed, and if three lines are given, `box' should appear in the middle
-one. Lines containing only spaces are implied as necessary before and after
-the the `box' line, so we have three lines.
-
-Normally, all three template lines should be of the same length. If the first
-line is shorter, it represents a start comment string to be bundled within the
-first line of the comment text. If the third line is shorter, it represents
-an end comment string to be bundled at the end of the comment text, and
-refilled with it.
-"""
- assert not template_registry.has_key(style), \
- "Style %d defined more than once" % style
- self.style = style
- self.weight = weight
- # Make it exactly three lines, with `box' in the middle.
- start = string.find(lines[0], 'box')
- if start >= 0:
- line1 = None
- line2 = lines[0]
- if len(lines) > 1:
- line3 = lines[1]
- else:
- line3 = None
- else:
- start = string.find(lines[1], 'box')
- if start >= 0:
- line1 = lines[0]
- line2 = lines[1]
- if len(lines) > 2:
- line3 = lines[2]
- else:
- line3 = None
- else:
- assert 0, "Erroneous template for %d style" % style
- end = start + len('box')
- # Define a few booleans.
- self.merge_nw = line1 is not None and len(line1) < len(line2)
- self.merge_se = line3 is not None and len(line3) < len(line2)
- # Define strings at various cardinal directions.
- if line1 is None:
- self.nw = self.nn = self.ne = None
- elif self.merge_nw:
- self.nw = line1
- self.nn = self.ne = None
- else:
- if start > 0:
- self.nw = line1[:start]
- else:
- self.nw = None
- if line1[start] != ' ':
- self.nn = line1[start]
- else:
- self.nn = None
- if end < len(line1):
- self.ne = string.rstrip(line1[end:])
- else:
- self.ne = None
- if start > 0:
- self.ww = line2[:start]
- else:
- self.ww = None
- if end < len(line2):
- self.ee = line2[end:]
- else:
- self.ee = None
- if line3 is None:
- self.sw = self.ss = self.se = None
- elif self.merge_se:
- self.sw = self.ss = None
- self.se = string.rstrip(line3)
- else:
- if start > 0:
- self.sw = line3[:start]
- else:
- self.sw = None
- if line3[start] != ' ':
- self.ss = line3[start]
- else:
- self.ss = None
- if end < len(line3):
- self.se = string.rstrip(line3[end:])
- else:
- self.se = None
- # Define parsing regexps.
- if self.merge_nw:
- self.regexp1 = re.compile(' *' + regexp_quote(self.nw) + '.*$')
- elif self.nw and not self.nn and not self.ne:
- self.regexp1 = re.compile(' *' + regexp_quote(self.nw) + '$')
- elif self.nw or self.nn or self.ne:
- self.regexp1 = re.compile(
- ' *' + regexp_quote(self.nw) + regexp_ruler(self.nn)
- + regexp_quote(self.ne) + '$')
- else:
- self.regexp1 = None
- if self.ww or self.ee:
- self.regexp2 = re.compile(
- ' *' + regexp_quote(self.ww) + '.*'
- + regexp_quote(self.ee) + '$')
- else:
- self.regexp2 = None
- if self.merge_se:
- self.regexp3 = re.compile('.*' + regexp_quote(self.se) + '$')
- elif self.sw and not self.ss and not self.se:
- self.regexp3 = re.compile(' *' + regexp_quote(self.sw) + '$')
- elif self.sw or self.ss or self.se:
- self.regexp3 = re.compile(
- ' *' + regexp_quote(self.sw) + regexp_ruler(self.ss)
- + regexp_quote(self.se) + '$')
- else:
- self.regexp3 = None
- # Save results.
- template_registry[style] = self
-
- def __cmp__(self, other):
- return cmp(self.weight, other.weight)
-
- def characters(self):
- """\
-Return a string of characters which may be used to draw the box.
-"""
- characters = ''
- for text in (self.nw, self.nn, self.ne,
- self.ww, self.ee,
- self.sw, self.ss, self.se):
- if text:
- for character in text:
- if character not in characters:
- characters = characters + character
- return characters
-
- def match(self, lines):
- """\
-Returns true if LINES exactly match this template.
-"""
- start = 0
- end = len(lines)
- if self.regexp1 is not None:
- if start == end or not self.regexp1.match(lines[start]):
- return 0
- start = start + 1
- if self.regexp3 is not None:
- if end == 0 or not self.regexp3.match(lines[end-1]):
- return 0
- end = end - 1
- if self.regexp2 is not None:
- for line in lines[start:end]:
- if not self.regexp2.match(line):
- return 0
- return 1
-
- def unbuild(self, lines):
- """\
-Remove all comment marks from LINES, as hinted by this template. Returns the
-cleaned up set of lines, and the size of the left margin.
-"""
- margin = left_margin_size(lines)
- # Remove box style marks.
- start = 0
- end = len(lines)
- if self.regexp1 is not None:
- lines[start] = unbuild_clean(lines[start], self.regexp1)
- start = start + 1
- if self.regexp3 is not None:
- lines[end-1] = unbuild_clean(lines[end-1], self.regexp3)
- end = end - 1
- if self.regexp2 is not None:
- for counter in range(start, end):
- lines[counter] = unbuild_clean(lines[counter], self.regexp2)
- # Remove the left side of the box after it turned into spaces.
- delta = left_margin_size(lines) - margin
- for counter in range(len(lines)):
- lines[counter] = lines[counter][delta:]
- # Remove leading and trailing white lines.
- start = 0
- end = len(lines)
- while start < end and lines[start] == '':
- start = start + 1
- while end > start and lines[end-1] == '':
- end = end - 1
- return lines[start:end], margin
-
- def build(self, lines, width, refill, margin):
- """\
-Put LINES back into a boxed comment according to this template, after
-having refilled them if REFILL. The box should start at column MARGIN,
-and the total size of each line should ideally not go over WIDTH.
-"""
- # Merge a short end delimiter now, so it gets refilled with text.
- if self.merge_se:
- if lines:
- lines[-1] = lines[-1] + ' ' + self.se
- else:
- lines = [self.se]
- # Reduce WIDTH according to left and right inserts, then refill.
- if self.ww:
- width = width - len(self.ww)
- if self.ee:
- width = width - len(self.ee)
- if refill:
- lines = refill_lines(lines, width)
- # Reduce WIDTH further according to the current right margin,
- # and excluding the left margin.
- maximum = 0
- for line in lines:
- if line:
- if line[-1] in '.!?':
- length = len(line) + 1
- else:
- length = len(line)
- if length > maximum:
- maximum = length
- width = maximum - margin
- # Construct the top line.
- if self.merge_nw:
- lines[0] = ' ' * margin + self.nw + lines[0][margin:]
- start = 1
- elif self.nw or self.nn or self.ne:
- if self.nn:
- line = self.nn * width
- else:
- line = ' ' * width
- if self.nw:
- line = self.nw + line
- if self.ne:
- line = line + self.ne
- lines.insert(0, string.rstrip(' ' * margin + line))
- start = 1
- else:
- start = 0
- # Construct all middle lines.
- for counter in range(start, len(lines)):
- line = lines[counter][margin:]
- line = line + ' ' * (width - len(line))
- if self.ww:
- line = self.ww + line
- if self.ee:
- line = line + self.ee
- lines[counter] = string.rstrip(' ' * margin + line)
- # Construct the bottom line.
- if self.sw or self.ss or self.se and not self.merge_se:
- if self.ss:
- line = self.ss * width
- else:
- line = ' ' * width
- if self.sw:
- line = self.sw + line
- if self.se and not self.merge_se:
- line = line + self.se
- lines.append(string.rstrip(' ' * margin + line))
- return lines
-
-def regexp_quote(text):
- """\
-Return a regexp matching TEXT without its surrounding space, maybe
-followed by spaces. If STRING is nil, return the empty regexp.
-Unless spaces, the text is nested within a regexp parenthetical group.
-"""
- if text is None:
- return ''
- if text == ' ' * len(text):
- return ' *'
- return '(' + re.escape(string.strip(text)) + ') *'
-
-def regexp_ruler(character):
- """\
-Return a regexp matching two or more repetitions of CHARACTER, maybe
-followed by spaces. Is CHARACTER is nil, return the empty regexp.
-Unless spaces, the ruler is nested within a regexp parenthetical group.
-"""
- if character is None:
- return ''
- if character == ' ':
- return ' +'
- return '(' + re.escape(character + character) + '+) *'
-
-def unbuild_clean(line, regexp):
- """\
-Return LINE with all parenthetical groups in REGEXP erased and replaced by an
-equivalent number of spaces, except for trailing spaces, which get removed.
-"""
- match = re.match(regexp, line)
- groups = match.groups()
- for counter in range(len(groups)):
- if groups[counter] is not None:
- start, end = match.span(1 + counter)
- line = line[:start] + ' ' * (end - start) + line[end:]
- return string.rstrip(line)
-
-## Template data.
-
-# Matcher functions for a comment start, indexed by numeric LANGUAGE.
-language_matcher = []
-for pattern in (r' *(/\*|//+|#+|;+|%+)',
- r'', # 1
- r' */\*', # 2
- r' *//+', # 3
- r' *#+', # 4
- r' *;+', # 5
- r' *%+'): # 6
- language_matcher.append(re.compile(pattern).match)
-
-# Template objects, indexed by numeric style.
-template_registry = {}
-
-def make_generic(style, weight, lines):
- """\
-Add various language digit to STYLE and generate one template per language,
-all using the same WEIGHT. Replace `?' in LINES accordingly.
-"""
- for language, character in ((300, '/'), # C++ style comments
- (400, '#'), # scripting languages
- (500, ';'), # LISP and assembler
- (600, '%')): # TeX and PostScript
- new_style = language + style
- if 310 < new_style <= 319:
- # Disallow quality 10 with C++.
- continue
- new_lines = []
- for line in lines:
- new_lines.append(string.replace(line, '?', character))
- Template(new_style, weight, new_lines)
-
-# Generic programming language templates.
-
-make_generic(11, 115, ('? box',))
-
-make_generic(12, 215, ('? box ?',
- '? --- ?'))
-
-make_generic(13, 315, ('? --- ?',
- '? box ?',
- '? --- ?'))
-
-make_generic(14, 415, ('? box ?',
- '???????'))
-
-make_generic(15, 515, ('???????',
- '? box ?',
- '???????'))
-
-make_generic(21, 125, ('?? box',))
-
-make_generic(22, 225, ('?? box ??',
- '?? --- ??'))
-
-make_generic(23, 325, ('?? --- ??',
- '?? box ??',
- '?? --- ??'))
-
-make_generic(24, 425, ('?? box ??',
- '?????????'))
-
-make_generic(25, 525, ('?????????',
- '?? box ??',
- '?????????'))
-
-make_generic(31, 135, ('??? box',))
-
-make_generic(32, 235, ('??? box ???',
- '??? --- ???'))
-
-make_generic(33, 335, ('??? --- ???',
- '??? box ???',
- '??? --- ???'))
-
-make_generic(34, 435, ('??? box ???',
- '???????????'))
-
-make_generic(35, 535, ('???????????',
- '??? box ???',
- '???????????'))
-
-make_generic(41, 145, ('???? box',))
-
-make_generic(42, 245, ('???? box ????',
- '???? --- ????'))
-
-make_generic(43, 345, ('???? --- ????',
- '???? box ????',
- '???? --- ????'))
-
-make_generic(44, 445, ('???? box ????',
- '?????????????'))
-
-make_generic(45, 545, ('?????????????',
- '???? box ????',
- '?????????????'))
-
-# Textual (non programming) templates.
-
-Template(111, 113, ('box',))
-
-Template(112, 213, ('| box |',
- '+-----+'))
-
-Template(113, 313, ('+-----+',
- '| box |',
- '+-----+'))
-
-Template(114, 413, ('| box |',
- '*=====*'))
-
-Template(115, 513, ('*=====*',
- '| box |',
- '*=====*'))
-
-Template(121, 123, ('| box |',))
-
-Template(122, 223, ('| box |',
- '`-----\''))
-
-Template(123, 323, ('.-----.',
- '| box |',
- '`-----\''))
-
-Template(124, 423, ('| box |',
- '\\=====/'))
-
-Template(125, 523, ('/=====\\',
- '| box |',
- '\\=====/'))
-
-Template(141, 143, ('| box ',))
-
-Template(142, 243, ('* box *',
- '*******'))
-
-Template(143, 343, ('*******',
- '* box *',
- '*******'))
-
-Template(144, 443, ('X box X',
- 'XXXXXXX'))
-
-Template(145, 543, ('XXXXXXX',
- 'X box X',
- 'XXXXXXX'))
-# C language templates.
-
-Template(211, 118, ('/* box */',))
-
-Template(212, 218, ('/* box */',
- '/* --- */'))
-
-Template(213, 318, ('/* --- */',
- '/* box */',
- '/* --- */'))
-
-Template(214, 418, ('/* box */',
- '/* === */'))
-
-Template(215, 518, ('/* === */',
- '/* box */',
- '/* === */'))
-
-Template(221, 128, ('/* ',
- ' box',
- '*/'))
-
-Template(222, 228, ('/* .',
- '| box |',
- '`----*/'))
-
-Template(223, 328, ('/*----.',
- '| box |',
- '`----*/'))
-
-Template(224, 428, ('/* \\',
- '| box |',
- '\\====*/'))
-
-Template(225, 528, ('/*====\\',
- '| box |',
- '\\====*/'))
-
-Template(231, 138, ('/* ',
- ' | box',
- ' */ '))
-
-Template(232, 238, ('/* ',
- ' | box | ',
- ' *-----*/'))
-
-Template(233, 338, ('/*-----* ',
- ' | box | ',
- ' *-----*/'))
-
-Template(234, 438, ('/* box */',
- '/*-----*/'))
-
-Template(235, 538, ('/*-----*/',
- '/* box */',
- '/*-----*/'))
-
-Template(241, 148, ('/* ',
- ' * box',
- ' */ '))
-
-Template(242, 248, ('/* * ',
- ' * box * ',
- ' *******/'))
-
-Template(243, 348, ('/******* ',
- ' * box * ',
- ' *******/'))
-
-Template(244, 448, ('/* box */',
- '/*******/'))
-
-Template(245, 548, ('/*******/',
- '/* box */',
- '/*******/'))
-
-Template(251, 158, ('/* ',
- ' * box',
- ' */ '))
-
-if __name__ == '__main__':
- apply(main, sys.argv[1:])
--- a/vim/sadness/bike/ide-integration/Pymacs-0.20/README Thu Feb 10 17:11:26 2011 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,1030 +0,0 @@
-* README for `Pymacs' allout -*- outline -*-
-
- `http://www.iro.umontreal.ca/~pinard/pymacs/' contains a copy of this
- `README' file in HTML form. The canonical Pymacs distribution is
- available as `http://www.iro.umontreal.ca/~pinard/pymacs/Pymacs.tar.gz'.
- Report problems and suggestions to `mailto:pinard@iro.umontreal.ca'.
-
-.. Presentation.
-
-. : What is Pymacs?
-
- Pymacs is a powerful tool which, once started from Emacs, allows both-way
- communication between Emacs Lisp and Python. Yet, Pymacs aims Python as
- an extension language for Emacs rather than the other way around; this
- assymetry is reflected in some design choices. Within Emacs Lisp code,
- one may load and use Python modules. Python functions may themselves use
- Emacs services, and handle Emacs Lisp objects kept in Emacs Lisp space.
-
- The goals are to write "naturally" in both languages, debug with ease,
- fall back gracefully on errors, and allow full cross-recursivity.
-
- It is very easy to install Pymacs, as neither Emacs nor Python need to
- be compiled nor relinked. Emacs merely starts Python as a subprocess,
- and Pymacs implements a communication protocol between both processes.
-
-. : Warning to Pymacs users.
-
- I expect average Pymacs users to have a deeper knowledge of Python
- than Emacs Lisp. Some examples at the end of this file are meant
- for Python users having a limited experience with the Emacs API.
- Currently, there are only contains two examples, one is too small,
- the other is too big :-). As there is no dedicated mailing list nor
- discussion group for Pymacs, let's use `python-list@python.org' for
- asking questions or discussing Pymacs related matters.
-
- This is beta status software: specifications are slightly frozen, yet
- changes may still happen that would require small adaptations in your
- code. Report problems to François Pinard at `pinard@iro.umontreal.ca'.
- For discussing specifications or making suggestions, please also copy
- the `python-list@python.org' mailing list, to help brain-storming! :-)
-
-. : History and references.
-
- I once starved for a Python-extensible editor, and pondered the idea of
- dropping Emacs for other avenues, but found nothing much convincing.
- Moreover, looking at all LISP extensions I wrote for myself, and
- considering all those superb tools written by others and that became
- part of my computer life, it would have been a huge undertaking for
- me to reprogram these all in Python. So, when I began to see that
- something like Pymacs was possible, I felt strongly motivated! :-)
-
- Pymacs revisits previous Cedric Adjih's works about running Python as a
- process separate from Emacs. See `http://www.crepuscule.com/pyemacs/',
- or write Cedric at `adjih-pam@crepuscule.com'. Cedric presented
- `pyemacs' to me as a proof of concept. As I simplified that concept
- a bit, I dropped the `e' in `pyemacs' :-). Cedric also told me that
- there exist some older patches for linking Python right into XEmacs.
-
- Brian McErlean independently and simultaneously wrote a tool similar
- to this one, we decided to join our projects. Amusing coincidence, he
- even chose `pymacs' as a name. Brian paid good attention to complex
- details that escaped my courage, so his help and collaboration have
- been beneficial. You may reach Brian at `brianmce@crosswinds.net'.
-
- One other reference of interest is Doug Bagley shoot out project,
- which compares the relative speed of many popular languages.
- See `http://www.bagley.org/~doug/shootout/' for more information.
-
-.. Installation.
-
-. : Install the Pymacs proper.
-
- Currently, there are two installation scripts, and both should be run.
- If you prefer, you may use `make install lispdir=LISPDIR', where
- LISPDIR is some directory along the list kept in your Emacs `load-path'.
-
- The first installation script installs the Python package, including the
- Pymacs examples, using the Python standard Distutils tool. Merely `cd'
- into the Pymacs distribution, then execute `python setup.py install'.
- To get an option reminder, do `python setup.py install --help'. Check
- the Distutils documentation if you need more information about this.
-
- The second installation script installs the Emacs Lisp part only.
- (It used to do everything, but is now doomed to disappear completely.)
- Merely `cd' into the Pymacs distribution, then run `python setup -ie'.
- This will invite you to interactively confirm the Lisp installation
- directory. Without `-ie', the Lisp part of Pymacs will be installed
- in some automatically guessed place. Use `-n' to known about the guess
- without proceeding to the actual installation. `./setup -E xemacs ...'
- may be useful to XEmacs lovers. See `./setup -H' for all options.
-
- About Win32 systems, Syver Enstad says: "For Pymacs to operate correctly,
- one should create a batch file with `pymacs-services.bat' as a name,
- which runs the `pymacs-services' script. The `.bat' file could be
- placed along with `pymacs-services', wherever that maybe.".
-
- To check that `pymacs.el' is properly installed, start Emacs and give
- it the command `M-x load-library RET pymacs': you should not receive
- any error. To check that `pymacs.py' is properly installed, start
- an interactive Python session and type `from Pymacs import lisp':
- you should not receive any error. To check that `pymacs-services'
- is properly installed, type `pymacs-services </dev/null' in a shell;
- you should then get a line ending with "(pymacs-version VERSION)",
- and another saying: "Protocol error: `>' expected.".
-
- Currently, there is only one installed Pymacs example, which comes
- in two parts: a batch script `rebox' and a `Pymacs.rebox' module.
- To check that both are properly installed, type `rebox </dev/null'
- in a shell; you should not receive any output nor see any error.
-
-. : Prepare your `.emacs' file.
-
- The ".emacs" file is not given in the distribution, you likely have
- one already in your home directory. You need to add these lines:
-
- (autoload 'pymacs-load "pymacs" nil t)
- (autoload 'pymacs-eval "pymacs" nil t)
- (autoload 'pymacs-apply "pymacs")
- (autoload 'pymacs-call "pymacs")
- ;;(eval-after-load "pymacs"
- ;; '(add-to-list 'pymacs-load-path "YOUR-PYMACS-DIRECTORY"))
-
- If you plan to use a special directory to hold your own Pymacs code in
- Python, which should be searched prior to the usual Python import search
- path, then uncomment the last two lines (by removing the semi-colons)
- and replace YOUR-PYMACS-DIRECTORY by the name of your special directory.
- If the file "$HOME/.emacs" does not exist, merely create it with the
- above lines. You are now all set to use Pymacs.
-
- To check this, start a fresh Emacs session, and type `M-x pymacs-eval'.
- Emacs should prompt you for a Python expression. Try "`2L**111`" (type
- the backquotes, but not the external double-quotes). The minibuffer
- should display `2596148429267413814265248164610048L'. `M-x pymacs-load'
- should prompt you for a Python module name. Reply `os'. After Emacs
- prompts you for a prefix, merely hit Enter to accept the default prefix.
- This should have the effect of importing the Python "os" module within
- Emacs. Typing `M-: (os-getcwd)' should echo the current directory in
- the message buffer, as returned by the `os.getcwd' Python function.
-
-. : Porting Pymacs.
-
- Pymacs has been developped on Linux and Emacs (20 and 21), it is expected
- to work out of the box on most other Unices, and also with XEmacs.
-
- Syver Enstad reports that Pymacs could be made to work on Windows-2000
- (win2k), he suspects it should equally work with NT and XP. However,
- little shell stunts may be required, I hope to later document them here.
-
-. : Caveats.
-
- Some later versions of Emacs 20 silently ignore the request for
- creating weak hash tables, they create an ordinary table instead.
- Older Emacses just do not have hash tables. Pymacs should run on
- all, yet for these, memory will leak on the Python side whenever
- complex objects get transmitted to Emacs, as these objects will not
- be reclaimed on the Python side once Emacs is finished with them.
- It should not be a practical problem in most simple cases.
-
-.. Emacs Lisp structures and Python objects.
-
-. : Conversions.
-
- Whenever Emacs Lisp calls Python functions giving them arguments,
- these arguments are Emacs Lisp structures that should be converted
- into Python objects in some way. Conversely, whenever Python calls
- Emacs Lisp functions, the arguments are Python objects that should
- be received as Emacs Lisp structures. We need some conventions for
- doing such conversions.
-
- Conversions generally transmit mutable Emacs Lisp structures as mutable
- objects on the Python side, in such a way that transforming the object in
- Python will effectively transform the structure on the Emacs Lisp side
- (strings are handled a bit specially however, see below). The other
- way around, Python objects transmitted to Emacs Lisp often loose their
- mutability, so transforming the Emacs Lisp structure is not reflected
- on the Python side.
-
-. : Simple objects.
-
- Emacs Lisp `nil' and the equivalent Emacs Lisp `()' yield Python `None'.
- Python `None' and the Python empty list `[]' are returned as `nil'
- in Emacs Lisp.
-
- Emacs Lisp numbers, either integer or floating, are converted in
- equivalent Python numbers. Emacs Lisp characters are really numbers
- and yield Python numbers. In the other direction, Python numbers are
- converted into Emacs Lisp numbers, with the exception of long Python
- integers and complex numbers.
-
- Emacs Lisp strings are usually converted into equivalent Python narrow
- strings. As Python strings do not have text properties, these are not
- reflected. This may be changed by setting the `pymacs-mutable-strings'
- option: if this variable is not `nil', Emacs Lisp strings are then
- transmitted opaquely. Python strings, except Unicode, are always
- converted into Emacs Lisp strings.
-
- Emacs Lisp symbols yield the special `lisp.SYMBOL' or `lisp[STRING]'
- notations on the Python side. The first notation is used when the
- Emacs Lisp symbol starts with a letter, and contains only letters,
- digits and hyphens, in which case Emacs Lisp hyphens get replaced
- by Python underscores. This convention is welcome, as Emacs Lisp
- programmers commonly prefer using dashes, where Python programmers
- use underlines. Otherwise, the second notation is used. Conversely,
- `lisp.SYMBOL' on the Python side yields an Emacs Lisp symbol with
- underscores replaced with hyphens, while `lisp[STRING]' corresponds
- to an Emacs Lisp symbol printed with that STRING which, of course,
- should then be a valid Emacs Lisp symbol name.
-
-. : Sequences.
-
- The case of strings has been discussed in the previous section.
-
- Proper Emacs Lisp lists, those for which the `cdr' of last
- cell is `nil', are normally transmitted opaquely to Python.
- If `pymacs-forget-mutability' is set, or if Python later asks for these
- to be expanded, proper Emacs Lisp lists get converted into Python lists,
- if we except the empty list, which is always converted as Python `None'.
- In the other direction, Python lists are always converted into proper
- Emacs Lisp lists.
-
- Emacs Lisp vectors are normally transmitted opaquely to Python. However,
- if `pymacs-forget-mutability' is set, or if Python later asks for these
- to be expanded, Emacs Lisp vectors get converted into Python tuples.
- In the other direction, Python tuples are always converted into Emacs
- Lisp vectors.
-
- Remember the rule: "Round parentheses correspond to square brackets!".
- It works for lists, vectors, tuples, seen from either Emacs Lisp or Python.
-
- The above choices were debatable. Since Emacs Lisp proper lists and
- Python lists are the bread-and-butter of algorithms modifying structures,
- at least in my experience, I guess they are more naturally mapped into
- one another, this spares many casts in practice. While in Python,
- the most usual idiom for growing lists is appending to their end,
- the most usual idiom in Emacs Lisp to grow a list is by cons'ing new
- items at its beginning:
-
- (setq accumulator (cons 'new-item accumulator))
-
- or more simply:
-
- (push accumulator 'new-item)
-
- So, in case speed is especially important and many modifications happen
- in a row on the same side, while order of elements ought to be preserved,
- some (nreverse ...) on the Emacs Lisp side or .reverse() on the Python
- side side might be needed. Surely, proper lists in Emacs Lisp and lists
- in Python are the normal structure for which length is easily modified.
-
- We cannot so easily change the size of a vector, the same as it is a
- bit more of a stunt to "modify" a tuple. The shape of these objects is
- fixed. Mapping vectors to tuples, which is admittedly strange, will only
- be done if the Python side requests an expanded copy, otherwise an opaque
- Emacs Lisp object is seen in Python. In the other direction, whenever
- an Emacs Lisp vector is needed, one has to write `tuple(python_list)'
- while transmitting the object. Such transmissions are most probably
- to be unusual, as people are not going to blindly transmit whole big
- structures back and forth between Emacs and Python, they would rather do
- it once in a while only, and do only local modifications afterwards.
- The infrequent casting to `tuple' for getting an Emacs Lisp vector
- seems to suggest that we did a reasonable compromise.
-
- In Python, both tuples and lists have O(1) access, so there is no real
- speed consideration there. Emacs Lisp is different: vectors have O(1)
- access while lists have O(N) access. The rigidity of Emacs Lisp
- vectors is such that people do not resort to vectors unless there
- is a speed issue, so in real Emacs Lisp practice, vectors are used
- rather parsimoniously. So much, in fact, that Emacs Lisp vectors are
- overloaded for what they are not meant: for example, very small vectors
- are used to represent X events in key-maps, programmers only want
- to test vectors for their type, or users just like bracketed syntax.
- The speed of access is hardly an issue then.
-
-. : Opaque objects.
-
-. , Emacs Lisp handles.
-
- When a Python function is called from Emacs Lisp, the function arguments
- have already been converted to Python types from Emacs Lisp types
- and the function result is going to be converted back to Emacs Lisp.
-
- Several Emacs Lisp objects do not have Python equivalents, like for
- Emacs windows, buffers, markers, overlays, etc. It is nevertheless
- useful to pass them to Python functions, hoping that these Python
- functions will "operate" on these Emacs Lisp objects. Of course,
- the Python side may not itself modify such objects, it has to call
- for Emacs services to do so. Emacs Lisp handles are a mean to ease
- this communication.
-
- Whenever an Emacs Lisp object may not be converted to a Python object, an
- Emacs Lisp handle is created and used instead. Whenever that Emacs Lisp
- handle is returned into Emacs Lisp from a Python function, or is used
- as an argument to an Emacs Lisp function from Python, the original Emacs
- Lisp object behind the Emacs Lisp handle is automatically retrieved.
-
- Emacs Lisp handles are either instances of the internal `Lisp' class,
- or of one of its subclasses. If `object' is an Emacs Lisp handle, and
- if the underlying Emacs Lisp object is an Emacs Lisp sequence, then
- whenever `object[index]', `object[index] = value' and `len(object)'
- are meaningful, these may be used to fetch or alter an element of the
- sequence directly in Emacs Lisp space. Also, if `object' corresponds
- to an Emacs Lisp function, `object(ARGUMENTS)' may be used to apply
- the Emacs Lisp function over the given arguments. Since arguments
- have been evaluated the Python way on the Python side, it would be
- conceptual overkill evaluating them again the Emacs Lisp way on the
- Emacs Lisp side, so Pymacs manage to quotes arguments for defeating
- Emacs Lisp evaluation. The same logic applies the other way around.
-
- Emacs Lisp handles have a `value()' method, which merely returns self.
- They also have a `copy()' method, which tries to "open the box"
- if possible. Emacs Lisp proper lists are turned into Python lists,
- Emacs Lisp vectors are turned into Python tuples. Then, modifying
- the structure of the copy on the Python side has no effect on the
- Emacs Lisp side.
-
- For Emacs Lisp handles, `str()' returns an Emacs Lisp representation
- of the handle which should be `eq' to the original object if read back
- and evaluated in Emacs Lisp. `repr()' returns a Python representation
- of the expanded Emacs Lisp object. If that Emacs Lisp object has
- an Emacs Lisp representation which Emacs Lisp could read back, then
- `repr()' value is such that it could be read back and evaluated in
- Python as well, this would result in another object which is `equal'
- to the original, but not neccessarily `eq'.
-
-. , Python handles.
-
- The same as Emacs Lisp handles are useful to handle Emacs Lisp objects
- on the Python side, Python handles are useful to handle Python objects
- on the Emacs Lisp side.
-
- Many Python objects do not have direct Emacs Lisp equivalents,
- including long integers, complex numbers, Unicode strings, modules,
- classes, instances and surely a lot of others. When such are being
- transmitted to the Emacs Lisp side, Pymacs use Python handles.
- These are automatically recovered into the original Python objects
- whenever transmitted back to Python, either as arguments to a Python
- function, as the Python function itself, or as the return value of
- an Emacs Lisp function called from Python.
-
- The objects represented by these Python handles may be inspected or
- modified using the basic library of Python functions. For example, in:
-
- (setq matcher (pymacs-eval "re.compile('PATTERN').match"))
- (pymacs-call matcher ARGUMENT)
-
- the initial `setq' above could be decomposed into:
-
- (setq compiled (pymacs-eval "re.compile('PATTERN')")
- matcher (pymacs-call "getattr" compiled "match"))
-
- This example shows that one may use `pymacs-call' with "getattr"
- as the function, to get a wanted attribute for a Python object.
-
-.. Usage on the Emacs Lisp side.
-
-. : `pymacs-eval'.
-
- Function `(pymacs-eval TEXT)' gets TEXT evaluated as a Python expression,
- and returns the value of that expression converted back to Emacs Lisp.
-
-. : `pymacs-call'.
-
- Function `(pymacs-call FUNCTION ARGUMENT...)' will get Python to apply
- the given FUNCTION over zero or more ARGUMENT. FUNCTION is either a
- string holding Python source code for a function (like a mere name, or
- even an expression), or else, a Python handle previously received from
- Python, and hopefully holding a callable Python object. Each ARGUMENT
- gets separately converted to Python before the function is called.
- `pymacs-call' returns the resulting value of the function call,
- converted back to Emacs Lisp.
-
-. : `pymacs-apply'.
-
- Function `(pymacs-apply FUNCTION ARGUMENTS)' will get Python to apply
- the given FUNCTION over the given ARGUMENTS. ARGUMENTS is a list
- containing all arguments, or `nil' if there is none. Besides arguments
- being bundled together instead of given separately, the function acts
- pretty much like `pymacs-call'.
-
-. : `pymacs-load'.
-
- Function `(pymacs-load MODULE PREFIX)' imports the Python MODULE into
- Emacs Lisp space. MODULE is the name of the file containing the module,
- without any `.py' or `.pyc' extension. If the directory part is omitted
- in MODULE, the module will be looked into the current Python search
- path. Dot notation may be used when the module is part of a package.
- Each top-level function in the module produces a trampoline function in
- Emacs Lisp having the same name, except that underlines in Python names
- are turned into dashes in Emacs Lisp, and that PREFIX is uniformly
- added before the Emacs Lisp name (as a way to avoid name clashes).
- PREFIX may be omitted, in which case it defaults to base name of MODULE
- with underlines turned into dashes, and followed by a dash.
-
- Whenever `pymacs_load_hook' is defined in the loaded Python module,
- `pymacs-load' calls it without arguments, but before creating the Emacs
- view for that module. So, the `pymacs_load_hook' function may create
- new definitions or even add `interaction' attributes to functions.
-
- The return value of a successful `pymacs-load' is the module object.
- An optional third argument, NOERROR, when given and not `nil', will
- have `pymacs-load' to return `nil' instead of raising an error, if
- the Python module could not be found.
-
- When later calling one of these trampoline functions, all provided
- arguments are converted to Python and transmitted, and the function
- return value is later converted back to Emacs Lisp. It is left to
- the Python side to check for argument consistency. However, for
- an interactive function, the interaction specification drives some
- checking on the Emacs Lisp side. Currently, there is no provision
- for collecting keyword arguments in Emacs Lisp.
-
-. : Expected usage.
-
- We do not expect that `pymacs-eval', `pymacs-call' or `pymacs-apply'
- will be much used, if ever. In practice, the Emacs Lisp side
- of a Pymacs application might call `pymacs-load' a few times for
- linking into the Python modules, with the indirect effect of defining
- trampoline functions for these modules on the Emacs Lisp side, which
- can later be called like usual Emacs Lisp functions.
-
- These imported functions are usually those which are of interest for
- the user, and the preferred way to call Python services with Pymacs.
-
-. : Special Emacs Lisp variables.
-
- Users could alter the inner working of Pymacs through a few variables,
- these are all documented here. Except for `pymacs-load-path', which
- should be set before calling any Pymacs function, the value of these
- variables can be changed at any time.
-
-. , pymacs-load-path
-
- Users might want to use special directories for holding their Python
- modules, when these modules are meant to be used from Emacs. Best is
- to preset `pymacs-load-path, `nil' by default, to a list of these
- directory names. (Tilde expansions and such occur automatically.)
-
- Here is how it works. The first time Pymacs is needed from Emacs,
- `pymacs-services' is called, and given as arguments all strings in the
- `pymacs-load-path' list. These arguments are added at the beginning
- of `sys.path', or moved at the beginning if they were already on
- `sys.path'. So in practice, nothing is removed from `sys.path'.
-
-. , pymacs-trace-transit
-
- The `*Pymacs*' buffer, within Emacs, holds a trace of transactions
- between Emacs and Python. When `pymacs-trace-transit' is `nil',
- and this is the default setting, the buffer only holds the last
- bi-directional transaction (a request and a reply). If that variable
- is not `nil', all transactions are kept. This could be useful for
- debugging, but the drawback is that this buffer could grow big over
- time, to the point of diminishing Emacs performance.
-
-. , pymacs-forget-mutability
-
- The default behaviour of Pymacs is to transmit Emacs Lisp objects to
- Python in such a way thay they are fully modifiable from the Python
- side, would it mean triggering Emacs Lisp functions to act on them.
- When `pymacs-forget-mutability' is not `nil', the behaviour is changed,
- and the flexibility is lost. Pymacs then tries to expand proper lists
- and vectors as full copies when transmitting them on the Python side.
- This variable, seen as a user setting, is best left to `nil'. It may
- be temporarily overriden within some functions, when deemed useful.
-
- There is no corresponding variable from objects transmitted to Emacs
- from Python. Pymacs automatically expands what gets transmitted.
- Mutability is preserved only as a side-effect of not having a natural
- Emacs Lisp representation for the Python object. This assymetry is on
- purpose, yet debatable. Maybe Pymacs could have a variable telling
- that mutability _is_ important for Python objects? That would give
- Pymacs users the capability of restoring the symmetry somewhat,
- yet so far, in our experience, this has never been needed.
-
-. , pymacs-mutable-strings
-
- Strictly speaking, Emacs Lisp strings are mutable. Yet, it does not
- come naturally to a Python programmer to modify a string "in-place",
- as Python strings are never mutable. When `pymacs-mutable-strings' is
- `nil', which is the default setting, Emacs Lisp strings are transmitted
- to Python as Python strings, and so, loose their mutability.
- Moreover, text properties are not reflected on the Python side.
- But if that variable is not `nil', Emacs Lisp strings are rather
- passed as Emacs Lisp handles. This variable is ignored whenever
- `pymacs-forget-mutability' is set.
-
-. , pymacs-timeout-at-start
-. , pymacs-timeout-at-reply
-. , pymacs-timeout-at-line
-
- Emacs needs to protect itself a bit, in case the Pymacs service program,
- which handles the Python side of requests, would not start correctly,
- or maybe later die unexpectedly. So, whenever Emacs reads data coming
- from that program, it sets a time limit, and take some action whenever
- that time limit expires. All times are expressed in seconds.
-
- The timeout at start defaults to 30 seconds, this time should only
- be increased if a given machine is so heavily loaded that the Pymacs
- service program has not enough of 30 seconds to start, in which case
- Pymacs refuses to work, with an appropriate message in the minibuffer.
-
- The two other variables almost never need to be changed in practice.
- When Emacs is expecting a reply from Python, it might repeatedly
- check the status of the Pymacs service program when that reply is not
- received fast enough, just to make sure that this program did not die.
- The timeout at reply, which defaults to 5, says how many seconds
- to wait without checking, while expecting the first line of a reply.
- The timeout at line, which defaults to 2, says how many seconds to wait
- without checking, while expecting a line of the reply after the first.
-
-.. Usage on the Python side.
-
-. : Python setup.
-
- Pymacs requires little or no setup in the Python modules which are
- meant to be used from Emacs, for the simple situations where these
- modules receive nothing but Emacs nil, numbers or strings, or return
- nothing but Python `None', numbers or strings.
-
- Otherwise, use `from Pymacs import lisp'. If you need more Pymacs
- features, like the `Let' class, write `from Pymacs import lisp, Let'.
-
-. : Response mode.
-
- When Python receives a request from Emacs in the context of Pymacs,
- and until it returns the reply, Emacs keeps listening to serve Python
- requests. Emacs is not listening otherwise. Other Python threads,
- if any, may not call Emacs without _very_ careful synchronisation.
-
-. : Emacs Lisp symbols.
-
- `lisp' is a special object which has useful built-in magic.
- Its attributes do nothing but represent Emacs Lisp symbols, created
- on the fly as needed (symbols also have their built-in magic).
-
- Except for `lisp.nil' or `lisp["nil"]', which are the same as `None',
- both `lisp.SYMBOL' and `lisp[STRING]' yield objects of the internal
- `Symbol' type. These are genuine Python objects, that could be referred
- to by simple Python variables. One may write `quote = lisp.quote',
- for example, and use `quote' afterwards to mean that Emacs Lisp symbol.
- If a Python function received an Emacs Lisp symbol as an argument, it
- can check with `==' if that argument is `lisp.never' or `lisp.ask', say.
- A Python function may well choose to return `lisp.t'.
-
- In Python, writing `lisp.SYMBOL = VALUE' or `lisp[STRING] = VALUE'
- does assign VALUE to the corresponding symbol in Emacs Lisp space.
- Beware that in such cases, the `lisp.' prefix may not be spared.
- After `result = lisp.result', one cannot hope that a later `result = 3'
- will have any effect in the Emacs Lisp space: this would merely change
- the Python variable `result', which was a reference to a `Symbol'
- instance, so it is now a reference to the number 3.
-
- The `Symbol' class has `value()' and `copy()' methods. One can use
- either `lisp.SYMBOL.value()' or `lisp.SYMBOL.copy()' to access the
- Emacs Lisp value of a symbol, after conversion to some Python object,
- of course. However, if `value()' would have given an Emacs Lisp handle,
- `lisp.SYMBOL.copy()' has the effect of `lisp.SYMBOL.value().copy()',
- that is, it returns the value of the symbol as opened as possible.
-
- A symbol may also be used as if it was a Python function, in which case
- it really names an Emacs Lisp function that should be applied over the
- following function arguments. The result of the Emacs Lisp function
- becomes the value of the call, with all due conversions of course.
-
-. : Dynamic bindings.
-
- As Emacs Lisp uses dynamic bindings, it is common that Emacs Lisp
- programs use `let' for temporarily setting new values for some Emacs
- Lisp variables having global scope. These variables recover their
- previous value automatically when the `let' gets completed, even if
- an error occurs which interrupts the normal flow of execution.
-
- Pymacs has a `Let' class to represent such temporary settings. Suppose
- for example that you want to recover the value of `lisp.mark()' when the
- transient mark mode is active on the Emacs Lisp side. One could surely
- use `lisp.mark(lisp.t)' to "force" reading the mark in such cases,
- but for the sake of illustration, let's ignore that, and temporarily
- deactivate transient mark mode instead. This could be done this way:
-
- try:
- let = Let()
- let.push(transient_mark_mode=None)
- ... USER CODE ...
- finally:
- let.pop()
-
- `let.push()' accepts any number of keywords arguments. Each keyword
- name is interpreted as an Emacs Lisp symbol written the Pymacs way,
- with underlines. The value of that Emacs Lisp symbol is saved on the
- Python side, and the value of the keyword becomes the new temporary value
- for this Emacs Lisp symbol. A later `let.pop()' restores the previous
- value for all symbols which were saved together at the time of the
- corresponding `let.push()'. There may be more than one `let.push()'
- call for a single `Let' instance, they stack within that instance.
- Each `let.pop()' will undo one and only one `let.push()' from the stack,
- in the reverse order or the pushes.
-
- When the `Let' instance disappears, either because the programmer does
- `del let' or `let = None', or just because the Python `let' variable
- goes out of scope, all remaining `let.pop()' get automatically executed,
- so the `try'/`finally' statement may be omitted in practice. For this
- omission to work flawlessly, the programmer should be careful at not
- keeping extra references to the `Let' instance.
-
- The constructor call `let = Let()' also has an implied initial `.push()'
- over all given arguments, so the explicit `let.push()' may be omitted
- as well. In practice, this sums up and the above code could be reduced
- to a mere:
-
- let = Let(transient_mark_mode=None)
- ... USER CODE ...
-
- Be careful at assigning the result of the constructor to some Python
- variable. Otherwise, the instance would disappear immediately after
- having been created, restoring the Emacs Lisp variable much too soon.
-
- Any variable to be bound with `Let' should have been bound in advance
- on the Emacs Lisp side. This restriction usually does no kind of harm.
- Yet, it will likely be lifted in some later version of Pymacs.
-
- The `Let' class has other methods meant for some macros which are
- common in Emacs Lisp programming, in the spirit of `let' bindings.
- These method names look like `push_*' or `pop_*', where Emacs
- Lisp macros are `save-*'. One has to use the matching `pop_*' for
- undoing the effect of a given `push_*' rather than a mere `.pop()':
- the Python code is clearer, this also ensures that things are undone
- in the proper order. The same `Let' instance may use many `push_*'
- methods, their effects nest.
-
- `push_excursion()' and `pop_excursion()' save and restore the current
- buffer, point and mark. `push_match_data()' and `pop_match_data()'
- save and restore the state of the last regular expression match.
- `push_restriction()' and `pop_restriction()' save and restore
- the current narrowing limits. `push_selected_window()' and
- `pop_selected_window()' save and restore the fact that a window holds
- the cursor. `push_window_excursion()' and `pop_window_excursion()'
- save and restore the current window configuration in the Emacs display.
-
- As a convenience, `let.push()' and all other `push_*' methods return
- the `Let' instance. This helps chaining various `push_*' right after
- the instance generation. For example, one may write:
-
- let = Let().push_excursion()
- if True:
- ... USER CODE ...
- del let
-
- The `if True:' (use `if 1:' with older Python releases, some people
- might prefer writing `if let:' anyway), has the only goal of indenting
- USER CODE, so the scope of the `let' variable is made very explicit.
- This is purely stylistic, and not at all necessary. The last `del let'
- might be omitted in a few circumstances, for example if the excursion
- lasts until the end of the Python function.
-
-. : Raw Emacs Lisp expressions.
-
- Pymacs offers a device for evaluating a raw Emacs Lisp expression,
- or a sequence of such, expressed as a string. One merely uses `lisp'
- as a function, like this:
-
- lisp("""
- ...
- POSSIBLY-LONG-SEQUENCE-OF-LISP-EXPRESSIONS
- ...
- """)
-
- The Emacs Lisp value of the last or only expression in the sequence
- becomes the value of the `lisp' call, after conversion back to Python.
-
-. : User interaction.
-
- Emacs functions have the concept of user interaction for completing
- the specification of their arguments while being called. This happens
- only when a function is interactively called by the user, it does
- not happen when a function is programmatically called by another.
- As Python does not have a corresponding facility, a bit of trickery
- was needed to retrofit that facility on the Python side.
-
- After loading a Python module but prior to creating an Emacs view
- for this module, Pymacs decides whether loaded functions will be
- interactively callable from Emacs, or not. Whenever a function has an
- `interaction' attribute, this attribute holds the Emacs interaction
- specification for this function. The specification is either another
- Python function or a string. In the former case, that other function
- is called without arguments and should, maybe after having consulted
- the user, return a list of the actual arguments to be used for the
- original function. In the latter case, the specification string is
- used verbatim as the argument to the `(interactive ...)' function
- on the Emacs side. To get a short reminder about how this string is
- interpreted on the Emacs side, try `C-h f interactive' within Emacs.
- Here is an example where an empty string is used to specify that an
- interactive has no arguments:
-
- from Pymacs import lisp
-
- def hello_world():
- "`Hello world' from Python."
- lisp.insert("Hello from Python!")
- hello_world.interaction = ''
-
- Versions of Python released before the integration of PEP 232 do not
- allow users to add attributes to functions, so there is a fallback
- mechanism. Let's presume that a given function does not have an
- `interaction' attribute as explained above. If the Python module
- contains an `interactions' global variable which is a dictionary,
- if that dictionary has an entry for the given function with a value
- other than `None', that function is going to be interactive on the
- Emacs side. Here is how the preceeding example should be written
- for an older version of Python, or when portability is at premium:
-
- from Pymacs import lisp
- interactions = {}
-
- def hello_world():
- "`Hello world' from Python."
- lisp.insert("Hello from Python!")
- interactions[hello_world] = ''
-
- One might wonder why we do not merely use `lisp.interactive(...)' from
- within Python. There is some magic in the Emacs Lisp interpreter
- itself, looking for that call _before_ the function is actually
- entered, this explains why "(interactive ...)" has to appear first in
- an Emacs Lisp `defun'. Pymacs could try to scan the already compiled
- form of the Python code, seeking for `lisp.interactive', but as the
- evaluation of `lisp.interactive' arguments could get arbitrarily
- complex, it would a real challenge un-compiling that evaluation into
- Emacs Lisp.
-
-. : Keybindings.
-
- An interactive function may be bound to a key sequence.
-
- To translate bindings like `C-x w', say, one might have to know a bit
- more how Emacs Lisp processes string escapes like `\C-x' or `\M-\C-x' in
- Emacs Lisp, and emulate it within Python strings, since Python does not
- have such escapes. `\C-L', where L is an upper case letter, produces a
- character which ordinal is the result of subtracting 0x40 from ordinal
- of `L'. `\M-' has the ordinal one gets by adding 0x80 to the ordinal
- of following described character. So people can use self-inserting
- non-ASCII characters, `\M-' is given another representation, which is
- to replace the addition of 0x80 by prefixing with `ESC', that is 0x1b.
-
- So "\C-x" in Emacs is '\x18' in Python. This is easily found, using an
- interactive Python session, by givin it: chr(ord('X') - ord('A') + 1).
- An easier way would be using the `kbd' function on the Emacs Lisp side,
- like with lisp.kbd('C-x w') or lisp.kbd('M-<f2>').
-
- To bind the F1 key to the `helper' function in some `module':
-
- lisp.global_set_key((lisp.f1,), lisp.module_helper)
-
- (item,) is a Python tuple yielding an Emacs Lisp vector. `lisp.f1'
- translates to the Emacs Lisp symbol `f1'. So, Python `(lisp.f1,)' is
- Emacs Lisp `[f1]'. Keys like `[M-f2]' might require some more ingenuity,
- one may write either (lisp['M-f2'],) or (lisp.M_f2,) on the Python side.
-
-.. Debugging.
-
-. : The `*Pymacs*' buffer.
-
- Emacs and Python are two separate processes (well, each may use more
- than one process). Pymacs implements a simple communication protocol
- between both, and does whatever needed so the programmers do not have
- to worry about details. The main debugging tool is the communication
- buffer between Emacs and Python, which is named `*Pymacs*'. To make
- good use of it, first set `pymacs-trace-transit' to `t', so all
- exchanges are accumulated in that buffer. As it is sometimes helpful
- to understand the communication protocol, it is briefly explained here,
- using an artificially complex example to do so. Consider:
-
- ---------------------------------------------------------------------->
- (pymacs-eval "lisp('(pymacs-eval \"`2L**111`\")')")
- "2596148429267413814265248164610048L"
- ----------------------------------------------------------------------<
-
- Here, Emacs asks Python to ask Emacs to ask Python for a simple bignum
- computation. Note that Emacs does not natively know how to handle big
- integers, nor has an internal representation for them. This is why I
- use backticks, so Python returns a string representation of the result,
- instead of the result itself. Here is a trace for this example. The `<'
- character flags a message going from Python to Emacs and is followed
- by an expression written in Emacs Lisp. The '>' character flags a
- message going from Emacs to Python and is followed by a expression
- written in Python. The number gives the length of the message.
-
- ---------------------------------------------------------------------->
- <22 (pymacs-version "0.3")
- >49 eval("lisp('(pymacs-eval \"`2L**111`\")')")
- <25 (pymacs-eval "`2L**111`")
- >18 eval("`2L**111`")
- <47 (pymacs-reply "2596148429267413814265248164610048L")
- >45 reply("2596148429267413814265248164610048L")
- <47 (pymacs-reply "2596148429267413814265248164610048L")
- ----------------------------------------------------------------------<
-
- Python evaluation is done in the context of the `Pymacs.pymacs' module,
- so for example a mere `reply' really means `Pymacs.pymacs.reply'. On the
- Emacs Lisp side, there is no concept of module namespaces, so we use
- the `pymacs-' prefix as an attempt to stay clean. Users should ideally
- refrain from naming their Emacs Lisp objects with a `pymacs-' prefix.
-
- `reply' and `pymacs-reply' are special functions meant to indicate that
- an expected result is finally transmitted. `error' and `pymacs-error'
- are special functions that introduce a string which explains an exception
- which recently occurred. `pymacs-expand' is a special function
- implementing the `copy()' methods of Emacs Lisp handles or symbols.
- In all other cases, the expression is a request for the other side,
- that request stacks until a corresponding reply is received.
-
- Part of the protocol manages memory, and this management generates
- some extra-noise in the `*Pymacs*' buffer. Whenever Emacs passes a
- structure to Python, an extra pointer is generated on the Emacs side to
- inhibit garbage collection by Emacs. Python garbage collector detects
- when the received structure is no longer needed on the Python side,
- at which time the next communication will tell Emacs to remove the
- extra pointer. It works symmetrically as well, that is, whenever Python
- passes a structure to Emacs, an extra Python reference is generated to
- inhibit garbage collection on the Python side. Emacs garbage collector
- detects when the received structure is no longer needed on the Emacs
- side, after which Python will be told to remove the extra reference.
- For efficiency, those allocation-related messages are delayed, merged and
- batched together within the next communication having another purpose.
-
-. : Emacs usual debugging.
-
- If cross-calls between Emacs Lisp and Python nest deeply, an error will
- raise successive exceptions alternatively on both sides as requests
- unstack, and the diagnostic gets transmitted back and forth, slightly
- growing as we go. So, errors will eventually be reported by Emacs.
- I made no kind of effort to transmit the Emacs Lisp backtrace on the
- Python side, as I do not see a purpose for it: all debugging is done
- within Emacs windows anyway.
-
- On recent Emacses, the Python backtrace gets displayed in the
- mini-buffer, and the Emacs Lisp backtrace is simultaneously shown in the
- `*Backtrace*' window. One useful thing is to allow to mini-buffer to
- grow big, so it has more chance to fully contain the Python backtrace,
- the last lines of which are often especially useful. Here, I use:
-
- (setq resize-mini-windows t
- max-mini-window-height .85)
-
- in my `.emacs' file, so the mini-buffer may use 85% of the screen,
- and quickly shrinks when fewer lines are needed. The mini-buffer
- contents disappear at the next keystroke, but you can recover the
- Python backtrace by looking at the end of the `*Messages*' buffer.
- In which case the `ffap' package in Emacs may be yet another friend!
- From the `*Messages*' buffer, once `ffap' activated, merely put the
- cursor on the file name of a Python module from the backtrace, and
- `C-x C-f RET' will quickly open that source for you.
-
-. : Auto-reloading on save.
-
- I found useful to automatically `pymacs-load' some Python files whenever
- they get saved from Emacs. Here is how I do it. The code below assumes
- that Python files meant for Pymacs are kept in `~/share/emacs/python'.
-
- (defun fp-maybe-pymacs-reload ()
- (let ((pymacsdir (expand-file-name "~/share/emacs/python/")))
- (when (and (string-equal (file-name-directory buffer-file-name)
- pymacsdir)
- (string-match "\\.py\\'" buffer-file-name))
- (pymacs-load (substring buffer-file-name 0 -3)))))
- (add-hook 'after-save-hook 'fp-maybe-pymacs-reload)
-
-.. Exemples.
-
-. : Paul Winkler's.
-
-. , The problem.
-
- Let's say I have a a module, call it `manglers.py', containing this
- simple python function:
-
- def break_on_whitespace(some_string):
- words = some_string.split()
- return '\n'.join(words)
-
- The goal is telling Emacs about this function so that I can call it on
- a region of text and replace the region with the result of the call.
- And bind this action to a key, of course, let's say `[f7]'.
-
- The Emacs buffer ought to be handled in some way. If this is not on the
- Emacs Lisp side, it has to be on the Python side, but we cannot escape
- handling the buffer. So, there is an equilibrium in the work to do for
- the user, that could be displaced towards Emacs Lisp or towards Python.
-
-. , Python side.
-
- Here is a first draft for the Python side of the problem:
-
- from Pymacs import lisp
-
- def break_on_whitespace():
- start = lisp.point()
- end = lisp.mark(lisp.t)
- if start > end:
- start, end = end, start
- text = lisp.buffer_substring(start, end)
- words = text.split()
- replacement = '\n'.join(words)
- lisp.delete_region(start, end)
- lisp.insert(replacement)
-
- interactions = {break_on_whitespace: ''}
-
- For various stylistic reasons, this could be rewritten into:
-
- from Pymacs import lisp
- interactions = {}
-
- def break_on_whitespace():
- start, end = lisp.point(), lisp.mark(lisp.t)
- words = lisp.buffer_substring(start, end).split()
- lisp.delete_region(start, end)
- lisp.insert('\n'.join(words))
-
- interactions[break_on_whitespace] = ''
-
- The above relies, in particular, on the fact that for those Emacs
- Lisp functions used here, `start' and `end' may be given in any order.
-
-. , Emacs side.
-
- On the Emacs side, one would do:
-
- (pymacs-load "manglers")
- (global-set-key [f7] 'manglers-break-on-whitespace)
-
-. : The `rebox' tool.
-
-. , The problem.
-
- For comments held within boxes, it is painful to fill paragraphs, while
- stretching or shrinking the surrounding box "by hand", as needed.
- This piece of Python code eases my life on this. It may be used
- interactively from within Emacs through the Pymacs interface, or in
- batch as a script which filters a single region to be reformatted.
-
- In batch, the reboxing is driven by command options and arguments
- and expects a complete, self-contained boxed comment from a file.
- Emacs function `rebox-region' also presumes that the region encloses
- a single boxed comment. Emacs `rebox-comment' is different, as it
- has to chase itself the extent of the surrounding boxed comment.
-
-. , Python side.
-
- The Python code is too big to be inserted in this documentation: see
- file `Pymacs/rebox.py' in the Pymacs distribution. You will observe
- in the code that Pymacs specific features are used exclusively from
- within the `pymacs_load_hook' function and the `Emacs_Rebox' class.
- In batch mode, `Pymacs' is not even imported. Here, we mean to
- discuss some of the design choices in the context of Pymacs.
-
- In batch mode, as well as with `rebox-region', the text to handle is
- turned over to Python, and fully processed in Python, with practically
- no Pymacs interaction while the work gets done. On the other hand,
- `rebox-comment' is rather Pymacs intensive: the comment boundaries
- are chased right from the Emacs buffer, as directed by the function
- `Emacs_Rebox.find_comment'. Once the boundaries are found, the
- remainder of the work is essentially done on the Python side.
-
- Once the boxed comment has been reformatted in Python, the old comment
- is removed in a single delete operation, the new comment is inserted in
- a second operation, this occurs in `Emacs_Rebox.process_emacs_region'.
- But by doing so, if point was within the boxed comment before the
- reformatting, its precise position is lost. To well preserve point,
- Python might have driven all reformatting details directly in the
- Emacs buffer. We really preferred doing it all on the Python side:
- as we gain legibility by expressing the algorithms in pure Python,
- the same Python code may be used in batch or interactively, and we
- avoid the slowdown that would result from heavy use of Emacs services.
-
- To avoid completely loosing point, I kludged a `Marker' class,
- which goal is to estimate the new value of point from the old.
- Reformatting may change the amount of white space, and either delete
- or insert an arbitrary number characters meant to draw the box.
- The idea is to initially count the number of characters between the
- beginning of the region and point, while ignoring any problematic
- character. Once the comment has been reboxed, point is advanced from
- the beginning of the region until we get the same count of characters,
- skipping all problematic characters. This `Marker' class works fully
- on the Python side, it does not involve Pymacs at all, but it does
- solve a problem that resulted from my choice of keeping the data on
- the Python side instead of handling it directly in the Emacs buffer.
-
- We want a comment reformatting to appear as a single operation, in
- the context of Emacs Undo. The method `Emacs_Rebox.clean_undo_after'
- handles the general case for this. Not that we do so much in practice:
- a reformatting implies one `delete-region' and one `insert', and maybe
- some other little adjustements at `Emacs_Rebox.find_comment' time.
- Even if this method scans and mofifies an Emacs Lisp list directly in
- the Emacs memory, the code doing this stays neat and legible. However,
- I found out that the undo list may grow quickly when the Emacs buffer
- use markers, with the consequence of making this routine so Pymacs
- intensive that most of the CPU is spent there. I rewrote that
- routine in Emacs Lisp so it executes in a single Pymacs interaction.
-
- Function `Emacs_Rebox.remainder_of_line' could have been written in
- Python, but it was probably not worth going away from this one-liner in
- Emacs Lisp. Also, given this routine is often called by `find_comment',
- a few Pymacs protocol interactions are spared this way. This function
- is useful when there is a need to apply a regexp already compiled on
- the Python side, it is probably better fetching the line from Emacs
- and do the pattern match on the Python side, than transmitting the
- source of the regexp to Emacs for it to compile and apply it.
-
- For refilling, I could have either used the refill algorithm built
- within in Emacs, programmed a new one in Python, or relied on Ross
- Paterson's `fmt', distributed by GNU and available on most Linuxes.
- In fact, `refill_lines' prefers the latter. My own Emacs setup is
- such that the built-in refill algorithm is _already_ overridden by GNU
- `fmt', and it really does a much better job. Experience taught me
- that calling an external program is fast enough to be very bearable,
- even interactively. If Python called Emacs to do the refilling, Emacs
- would itself call GNU `fmt' in my case, I preferred that Python calls
- GNU `fmt' directly. I could have reprogrammed GNU `fmt' in Python.
- Despite interesting, this is an uneasy project: `fmt' implements
- the Knuth refilling algorithm, which depends on dynamic programming
- techniques; Ross fine tuned them, and took care of many details.
- If GNU `fmt' fails, for not being available, say, `refill_lines'
- falls back on a dumb refilling algorithm, which is better than none.
-
-. , Emacs side.
-
- The Emacs recipe appears under the `Emacs usage' section, near the
- beginning of `Pymacs/rebox.py', so I do not repeat it here.
-
-..
- François Pinard,
- pinard@iro.umontreal.ca
--- a/vim/sadness/bike/ide-integration/Pymacs-0.20/README.html Thu Feb 10 17:11:26 2011 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,11 +0,0 @@
-<!doctype HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
-<!--: Faire
- from Webert import transform
- title, text = transform.transform('README')
-:-->
-<html>
- <head><title>%(title)s</title></head>
- <body>
-%(text)s
- </body>
-</html>
--- a/vim/sadness/bike/ide-integration/Pymacs-0.20/THANKS Thu Feb 10 17:11:26 2011 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,24 +0,0 @@
-Pymacs has been written by François Pinard after an idea from Cedric Adjih,
-and much influenced by Brian McErlean. Here is the list of contributors.
-
-Brian McErlean b.mcerlean@kainos.com
-Carel Fellinger cfelling@iae.nl
-Carey Evans careye@spamcop.net
-Cedric Adjih adjih-pam@crepuscule.com
- http://www.crepuscule.com/pyemacs/
-Christian Tanzer tanzer@swing.co.at
-Dave Sellars dsellars@windriver.com
-Dirk Vleugels dvl@2scale.net
-Eli Zaretskii eliz@is.elta.co.il
-François Pinard pinard@iro.umontreal.ca
- http://www.iro.umontreal.ca/~pinard
-Gerd Möllmann gerd@gnu.org
-John Wiegley johnw@gnu.org
-Marcin Qrczak Kowalczyk qrczak@knm.org.pl
-Paul Foley mycroft@actrix.gen.nz
- http://users.actrix.co.nz/mycroft/
-Paul Winkler slinkp23@yahoo.com
-Richard Stallman rms@gnu.org
-Stefan Reichör xsteve@riic.at
-Steffen Ries steffen.ries@sympatico.ca
-Syver Enstad syver.enstad@asker.online.no
--- a/vim/sadness/bike/ide-integration/Pymacs-0.20/THANKS-rebox Thu Feb 10 17:11:26 2011 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,8 +0,0 @@
-`rebox' has been written by François Pinard. Here is the list of
-contributors. Also see `ChangeLog-rebox' for a more details.
-
-Akim Demaille demaille@inf.enst.fr
-Marc Feeley feeley@iro.umontreal.ca
-Paul Eggert eggert@twinsun.com
-Paul Provost provost@virtualprototypes.ca
-Ulrich Drepper drepper@gnu.org
--- a/vim/sadness/bike/ide-integration/Pymacs-0.20/TODO Thu Feb 10 17:11:26 2011 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,34 +0,0 @@
-* TODO for `Pymacs' allout -*- outline -*-
-
-.. Internal cleanup.
-
-. : `(pymacs-eval "dir()")' shows too many things.
-
-.. Type conversions.
-
-. : Convert LISP hash tables into Python dicts and vice-versa.
-
-.. Iterator protocol.
-
-. : Allow iterating over vectors.
-
-.. Rebox.
-
-. : Debug the Undo list cleanup!
-
-. : Try the fall back refiller.
-
-. : Unicode boxes (suggested by Bruno).
-. , U+231C..U+231F
-. , U+25xx
-
-.. Debugging facilities.
-
-. : *Pymacs*
-. , Indent.
-. , Interpret numbers.
-. , Highlight.
-
-. : Test suite. (Brian has one.)
-
-. : Python shell link to helper.
--- a/vim/sadness/bike/ide-integration/Pymacs-0.20/pymacs-services Thu Feb 10 17:11:26 2011 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,27 +0,0 @@
-#!/usr/bin/env python
-# Copyright © 2001, 2002 Progiciels Bourbeau-Pinard inc.
-# François Pinard <pinard@iro.umontreal.ca>, 2001.
-
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2, or (at your option)
-# any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software Foundation,
-# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
-
-"""\
-Interface between Emacs LISP and Python - Python process starter.
-
-This small bootstrap is so Pymacs modules can be kept in compiled form.
-"""
-
-import sys
-from Pymacs import pymacs
-apply(pymacs.main, sys.argv[1:])
--- a/vim/sadness/bike/ide-integration/Pymacs-0.20/pymacs-services.bat Thu Feb 10 17:11:26 2011 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,1 +0,0 @@
-@python "%~dpn0" %*
--- a/vim/sadness/bike/ide-integration/Pymacs-0.20/pymacs.el Thu Feb 10 17:11:26 2011 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,631 +0,0 @@
-;;; Interface between Emacs Lisp and Python - Lisp part.
-;;; Copyright © 2001, 2002 Progiciels Bourbeau-Pinard inc.
-;;; François Pinard <pinard@iro.umontreal.ca>, 2001.
-
-;;; This program is free software; you can redistribute it and/or modify
-;;; it under the terms of the GNU General Public License as published by
-;;; the Free Software Foundation; either version 2, or (at your option)
-;;; any later version.
-;;;
-;;; This program is distributed in the hope that it will be useful,
-;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
-;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-;;; GNU General Public License for more details.
-;;;
-;;; You should have received a copy of the GNU General Public License
-;;; along with this program; if not, write to the Free Software Foundation,
-;;; Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
-
-;;; See the Pymacs documentation (in `README') for more information.
-
-;;; Published functions.
-
-(defvar pymacs-load-path nil
- "List of additional directories to search for Python modules.
-The directories listed will be searched first, in the order given.")
-
-(defvar pymacs-trace-transit nil
- "Keep the communication buffer growing, for debugging.
-When this variable is nil, the `*Pymacs*' communication buffer gets erased
-before each communication round-trip. Setting it to `t' guarantees that
-the full communication is saved, which is useful for debugging.")
-
-(defvar pymacs-forget-mutability nil
- "Transmit copies to Python instead of Lisp handles, as much as possible.
-When this variable is nil, most mutable objects are transmitted as handles.
-This variable is meant to be temporarily rebound to force copies.")
-
-(defvar pymacs-mutable-strings nil
- "Prefer transmitting Lisp strings to Python as handles.
-When this variable is nil, strings are transmitted as copies, and the
-Python side thus has no way for modifying the original Lisp strings.
-This variable is ignored whenever `forget-mutability' is set.")
-
-(defvar pymacs-timeout-at-start 30
- "Maximum reasonable time, in seconds, for starting `pymacs-services'.
-A machine should be pretty loaded before one needs to increment this.")
-
-(defvar pymacs-timeout-at-reply 5
- "Expected maximum time, in seconds, to get the first line of a reply.
-The status of `pymacs-services' is checked at every such timeout.")
-
-(defvar pymacs-timeout-at-line 2
- "Expected maximum time, in seconds, to get another line of a reply.
-The status of `pymacs-services' is checked at every such timeout.")
-
-(defun pymacs-load (module &optional prefix noerror)
- "Import the Python module named MODULE into Emacs.
-Each function in the Python module is made available as an Emacs function.
-The Lisp name of each function is the concatenation of PREFIX with
-the Python name, in which underlines are replaced by dashes. If PREFIX is
-not given, it defaults to MODULE followed by a dash.
-If NOERROR is not nil, do not raise error when the module is not found."
- (interactive
- (let* ((module (read-string "Python module? "))
- (default (concat (car (last (split-string module "\\."))) "-"))
- (prefix (read-string (format "Prefix? [%s] " default)
- nil nil default)))
- (list module prefix)))
- (message "Pymacs loading %s..." module)
- (let ((lisp-code (pymacs-call "pymacs_load_helper" module prefix)))
- (cond (lisp-code (let ((result (eval lisp-code)))
- (message "Pymacs loading %s...done" module)
- result))
- (noerror (message "Pymacs loading %s...failed" module) nil)
- (t (error "Pymacs loading %s...failed" module)))))
-
-(defun pymacs-eval (text)
- "Compile TEXT as a Python expression, and return its value."
- (interactive "sPython expression? ")
- (let ((value (pymacs-call "eval" text)))
- (when (interactive-p)
- (message "%S" value))
- value))
-
-(defun pymacs-exec (text)
- "Compile and execute TEXT as a sequence of Python statements.
-This functionality is experimental, and does not appear to be useful."
- (interactive "sPython statements? ")
- (let ((value (pymacs-serve-until-reply
- `(progn (princ "exec ") (prin1 ,text)))))
- (when (interactive-p)
- (message "%S" value))
- value))
-
-(defun pymacs-call (function &rest arguments)
- "Return the result of calling a Python function FUNCTION over ARGUMENTS.
-FUNCTION is a string denoting the Python function, ARGUMENTS are separate
-Lisp expressions, one per argument. Immutable Lisp constants are converted
-to Python equivalents, other structures are converted into Lisp handles."
- (pymacs-apply function arguments))
-
-(defun pymacs-apply (function arguments)
- "Return the result of calling a Python function FUNCTION over ARGUMENTS.
-FUNCTION is a string denoting the Python function, ARGUMENTS is a list of
-Lisp expressions. Immutable Lisp constants are converted to Python
-equivalents, other structures are converted into Lisp handles."
- (pymacs-serve-until-reply `(pymacs-print-for-apply ',function ',arguments)))
-
-;;; Integration details.
-
-;; Python functions and modules should ideally look like Lisp functions and
-;; modules. This page tries to increase the integration seamlessness.
-
-(defadvice documentation (around pymacs-ad-documentation activate)
- ;; Integration of doc-strings.
- (let* ((reference (pymacs-python-reference function))
- (python-doc (when reference
- (pymacs-eval (format "doc_string(%s)" reference)))))
- (if (or reference python-doc)
- (setq ad-return-value
- (concat
- "It interfaces to a Python function.\n\n"
- (when python-doc
- (if raw python-doc (substitute-command-keys python-doc)))))
- ad-do-it)))
-
-(defun pymacs-python-reference (object)
- ;; Return the text reference of a Python object if possible, else nil.
- (when (functionp object)
- (let* ((definition (indirect-function object))
- (body (and (pymacs-proper-list-p definition)
- (> (length definition) 2)
- (eq (car definition) 'lambda)
- (cddr definition))))
- (when (and body (listp (car body)) (eq (caar body) 'interactive))
- ;; Skip the interactive specification of a function.
- (setq body (cdr body)))
- (when (and body
- ;; Advised functions start with a string.
- (not (stringp (car body)))
- ;; Python trampolines hold exactly one expression.
- (= (length body) 1))
- (let ((expression (car body)))
- ;; EXPRESSION might now hold something like:
- ;; (pymacs-apply (quote (pymacs-python . N)) ARGUMENT-LIST)
- (when (and (pymacs-proper-list-p expression)
- (= (length expression) 3)
- (eq (car expression) 'pymacs-apply)
- (eq (car (cadr expression)) 'quote))
- (setq object (cadr (cadr expression))))))))
- (when (eq (car-safe object) 'pymacs-python)
- (format "python[%d]" (cdr object))))
-
-;; The following functions are experimental -- they are not satisfactory yet.
-
-(defun pymacs-file-handler (operation &rest arguments)
- ;; Integration of load-file, autoload, etc.
- ;; Emacs might want the contents of some `MODULE.el' which does not exist,
- ;; while there is a `MODULE.py' or `MODULE.pyc' file in the same directory.
- ;; The goal is to generate a virtual contents for this `MODULE.el' file, as
- ;; a set of Lisp trampoline functions to the Python module functions.
- ;; Python modules can then be loaded or autoloaded as if they were Lisp.
- ;(message "** %S %S" operation arguments)
- (cond ((and (eq operation 'file-readable-p)
- (let ((module (substring (car arguments) 0 -3)))
- (or (pymacs-file-force operation arguments)
- (file-readable-p (concat module ".py"))
- (file-readable-p (concat module ".pyc"))))))
- ((and (eq operation 'load)
- (not (pymacs-file-force
- 'file-readable-p (list (car arguments))))
- (file-readable-p (car arguments)))
- (let ((lisp-code (pymacs-call "pymacs_load_helper"
- (substring (car arguments) 0 -3)
- nil)))
- (unless lisp-code
- (error "Python import error"))
- (eval lisp-code)))
- ((and (eq operation 'insert-file-contents)
- (not (pymacs-file-force
- 'file-readable-p (list (car arguments))))
- (file-readable-p (car arguments)))
- (let ((lisp-code (pymacs-call "pymacs_load_helper"
- (substring (car arguments) 0 -3)
- nil)))
- (unless lisp-code
- (error "Python import error"))
- (insert (prin1-to-string lisp-code))))
- (t (pymacs-file-force operation arguments))))
-
-(defun pymacs-file-force (operation arguments)
- ;; Bypass the file handler.
- (let ((inhibit-file-name-handlers
- (cons 'pymacs-file-handler
- (and (eq inhibit-file-name-operation operation)
- inhibit-file-name-handlers)))
- (inhibit-file-name-operation operation))
- (apply operation arguments)))
-
-;(add-to-list 'file-name-handler-alist '("\\.el\\'" . pymacs-file-handler))
-
-;;; Gargabe collection of Python IDs.
-
-;; Python objects which have no Lisp representation are allocated on the
-;; Python side as `python[INDEX]', and INDEX is transmitted to Emacs, with
-;; the value to use on the Lisp side for it. Whenever Lisp does not need a
-;; Python object anymore, it should be freed on the Python side. The
-;; following variables and functions are meant to fill this duty.
-
-(defvar pymacs-use-hash-tables nil
- "Automatically set to t if hash tables are available.")
-
-(defvar pymacs-used-ids nil
- "List of received IDs, currently allocated on the Python side.")
-
-(defvar pymacs-weak-hash nil
- "Weak hash table, meant to find out which IDs are still needed.")
-
-(defvar pymacs-gc-wanted nil
- "Flag if it is time to clean up unused IDs on the Python side.")
-
-(defvar pymacs-gc-running nil
- "Flag telling that a Pymacs garbage collection is in progress.")
-
-(defvar pymacs-gc-timer nil
- "Timer to trigger Pymacs garbage collection at regular time intervals.
-The timer is used only if `post-gc-hook' is not available.")
-
-(defun pymacs-schedule-gc ()
- (unless pymacs-gc-running
- (setq pymacs-gc-wanted t)))
-
-(defun pymacs-garbage-collect ()
- ;; Clean up unused IDs on the Python side.
- (when pymacs-use-hash-tables
- (let ((pymacs-gc-running t)
- (pymacs-forget-mutability t)
- (ids pymacs-used-ids)
- used-ids unused-ids)
- (while ids
- (let ((id (car ids)))
- (setq ids (cdr ids))
- (if (gethash id pymacs-weak-hash)
- (setq used-ids (cons id used-ids))
- (setq unused-ids (cons id unused-ids)))))
- ;;(message "** pymacs-garbage-collect %d %d"
- ;; (length used-ids) (length unused-ids))
- (setq pymacs-used-ids used-ids
- pymacs-gc-wanted nil)
- (when unused-ids
- (pymacs-apply "free_python" unused-ids)))))
-
-(defun pymacs-defuns (arguments)
- ;; Take one argument, a list holding a number of items divisible by 3. The
- ;; first argument is an INDEX, the second is a NAME, the third is the
- ;; INTERACTION specification, and so forth. Register Python INDEX with a
- ;; function with that NAME and INTERACTION on the Lisp side. The strange
- ;; calling convention is to minimise quoting at call time.
- (while (>= (length arguments) 3)
- (let ((index (nth 0 arguments))
- (name (nth 1 arguments))
- (interaction (nth 2 arguments)))
- (fset name (pymacs-defun index interaction))
- (setq arguments (nthcdr 3 arguments)))))
-
-(defun pymacs-defun (index interaction)
- ;; Register INDEX on the Lisp side with a Python object that is a function,
- ;; and return a lambda form calling that function. If the INTERACTION
- ;; specification is nil, the function is not interactive. Otherwise, the
- ;; function is interactive, INTERACTION is then either a string, or the
- ;; index of an argument-less Python function returning the argument list.
- (let ((object (pymacs-python index)))
- (cond ((null interaction)
- `(lambda (&rest arguments)
- (pymacs-apply ',object arguments)))
- ((stringp interaction)
- `(lambda (&rest arguments)
- (interactive ,interaction)
- (pymacs-apply ',object arguments)))
- (t `(lambda (&rest arguments)
- (interactive (pymacs-call ',(pymacs-python interaction)))
- (pymacs-apply ',object arguments))))))
-
-(defun pymacs-python (index)
- ;; Register on the Lisp side a Python object having INDEX, and return it.
- ;; The result is meant to be recognised specially by `print-for-eval', and
- ;; in the function position by `print-for-apply'.
- (let ((object (cons 'pymacs-python index)))
- (when pymacs-use-hash-tables
- (puthash index object pymacs-weak-hash)
- (setq pymacs-used-ids (cons index pymacs-used-ids)))
- object))
-
-;;; Generating Python code.
-
-;; Many Lisp expressions cannot fully be represented in Python, at least
-;; because the object is mutable on the Lisp side. Such objects are allocated
-;; somewhere into a vector of handles, and the handle index is used for
-;; communication instead of the expression itself.
-
-(defvar pymacs-lisp nil
- "Vector of handles to hold transmitted expressions.")
-
-(defvar pymacs-freed-list nil
- "List of unallocated indices in Lisp.")
-
-;; When the Python CG is done with a Lisp object, a communication occurs so to
-;; free the object on the Lisp side as well.
-
-(defun pymacs-allocate-lisp (expression)
- ;; This function allocates some handle for an EXPRESSION, and return its
- ;; index.
- (unless pymacs-freed-list
- (let* ((previous pymacs-lisp)
- (old-size (length previous))
- (new-size (if (zerop old-size) 100 (+ old-size (/ old-size 2))))
- (counter new-size))
- (setq pymacs-lisp (make-vector new-size nil))
- (while (> counter 0)
- (setq counter (1- counter))
- (if (< counter old-size)
- (aset pymacs-lisp counter (aref previous counter))
- (setq pymacs-freed-list (cons counter pymacs-freed-list))))))
- (let ((index (car pymacs-freed-list)))
- (setq pymacs-freed-list (cdr pymacs-freed-list))
- (aset pymacs-lisp index expression)
- index))
-
-(defun pymacs-free-lisp (&rest indices)
- ;; This function is triggered from Python side for Lisp handles which lost
- ;; their last reference. These references should be cut on the Lisp side as
- ;; well, or else, the objects will never be garbage-collected.
- (while indices
- (let ((index (car indices)))
- (aset pymacs-lisp index nil)
- (setq pymacs-freed-list (cons index pymacs-freed-list)
- indices (cdr indices)))))
-
-(defun pymacs-print-for-apply-expanded (function arguments)
- ;; This function acts like `print-for-apply', but produce arguments which
- ;; are expanded copies whenever possible, instead of handles. Proper lists
- ;; are turned into Python lists, vectors are turned into Python tuples.
- (let ((pymacs-forget-mutability t))
- (pymacs-print-for-apply function arguments)))
-
-(defun pymacs-print-for-apply (function arguments)
- ;; This function prints a Python expression calling FUNCTION, which is a
- ;; string naming a Python function, or a Python reference, over all its
- ;; ARGUMENTS, which are Lisp expressions.
- (let ((separator "")
- argument)
- (if (eq (car-safe function) 'pymacs-python)
- (princ (format "python[%d]" (cdr function)))
- (princ function))
- (princ "(")
- (while arguments
- (setq argument (car arguments)
- arguments (cdr arguments))
- (princ separator)
- (setq separator ", ")
- (pymacs-print-for-eval argument))
- (princ ")")))
-
-(defun pymacs-print-for-eval (expression)
- ;; This function prints a Python expression out of a Lisp EXPRESSION.
- (let (done)
- (cond ((not expression)
- (princ "None")
- (setq done t))
- ((numberp expression)
- (princ expression)
- (setq done t))
- ((stringp expression)
- (when (or pymacs-forget-mutability
- (not pymacs-mutable-strings))
- (let ((text (copy-sequence expression)))
- (set-text-properties 0 (length text) nil text)
- (princ (mapconcat 'identity
- (split-string (prin1-to-string text) "\n")
- "\\n")))
- (setq done t)))
- ((symbolp expression)
- (let ((name (symbol-name expression)))
- ;; The symbol can only be transmitted when in the main oblist.
- (when (eq expression (intern-soft name))
- (cond
- ((save-match-data
- (string-match "^[A-Za-z][-A-Za-z0-9]*$" name))
- (princ "lisp.")
- (princ (mapconcat 'identity (split-string name "-") "_")))
- (t (princ "lisp[")
- (prin1 name)
- (princ "]")))
- (setq done t))))
- ((vectorp expression)
- (when pymacs-forget-mutability
- (let ((limit (length expression))
- (counter 0))
- (princ "(")
- (while (< counter limit)
- (unless (zerop counter)
- (princ ", "))
- (pymacs-print-for-eval (aref expression counter)))
- (when (= limit 1)
- (princ ","))
- (princ ")")
- (setq done t))))
- ((eq (car-safe expression) 'pymacs-python)
- (princ "python[")
- (princ (cdr expression))
- (princ "]"))
- ((pymacs-proper-list-p expression)
- (when pymacs-forget-mutability
- (princ "[")
- (pymacs-print-for-eval (car expression))
- (while (setq expression (cdr expression))
- (princ ", ")
- (pymacs-print-for-eval (car expression)))
- (princ "]")
- (setq done t))))
- (unless done
- (let ((class (cond ((vectorp expression) "Vector")
- ((and pymacs-use-hash-tables
- (hash-table-p expression))
- "Table")
- ((bufferp expression) "Buffer")
- ((pymacs-proper-list-p expression) "List")
- (t "Lisp"))))
- (princ class)
- (princ "(")
- (princ (pymacs-allocate-lisp expression))
- (princ ")")))))
-
-;;; Communication protocol.
-
-(defvar pymacs-transit-buffer nil
- "Communication buffer between Emacs and Python.")
-
-;; The principle behind the communication protocol is that it is easier to
-;; generate than parse, and that each language already has its own parser.
-;; So, the Emacs side generates Python text for the Python side to interpret,
-;; while the Python side generates Lisp text for the Lisp side to interpret.
-;; About nothing but expressions are transmitted, which are evaluated on
-;; arrival. The pseudo `reply' function is meant to signal the final result
-;; of a series of exchanges following a request, while the pseudo `error'
-;; function is meant to explain why an exchange could not have been completed.
-
-;; The protocol itself is rather simple, and contains human readable text
-;; only. A message starts at the beginning of a line in the communication
-;; buffer, either with `>' for the Lisp to Python direction, or `<' for the
-;; Python to Lisp direction. This is followed by a decimal number giving the
-;; length of the message text, a TAB character, and the message text itself.
-;; Message direction alternates systematically between messages, it never
-;; occurs that two successive messages are sent in the same direction. The
-;; first message is received from the Python side, it is `(version VERSION)'.
-
-(defun pymacs-start-services ()
- ;; This function gets called automatically, as needed.
- (let ((buffer (get-buffer-create "*Pymacs*")))
- (with-current-buffer buffer
- (buffer-disable-undo)
- (save-match-data
- ;; Launch the Python helper.
- (let ((process (apply 'start-process "pymacs" buffer "pymacs-services"
- (mapcar 'expand-file-name pymacs-load-path))))
- (process-kill-without-query process)
- ;; Receive the synchronising reply.
- (while (progn
- (goto-char (point-min))
- (not (re-search-forward "<\\([0-9]+\\)\t" nil t)))
- (unless (accept-process-output process pymacs-timeout-at-start)
- (error "Pymacs helper did not start within %d seconds."
- pymacs-timeout-at-start)))
- (let ((marker (process-mark process))
- (limit-position (+ (match-end 0)
- (string-to-number (match-string 1)))))
- (while (< (marker-position marker) limit-position)
- (unless (accept-process-output process pymacs-timeout-at-start)
- (error "Pymacs helper probably was interrupted at start.")))))
- ;; Check that synchronisation occurred.
- (goto-char (match-end 0))
- (let ((reply (read (current-buffer))))
- (if (and (pymacs-proper-list-p reply)
- (= (length reply) 2)
- (eq (car reply) 'pymacs-version))
- (unless (string-equal (cadr reply) "@VERSION@")
- (error "Pymacs Lisp version is @VERSION@, Python is %s."
- (cadr reply)))
- (error "Pymacs got an invalid initial reply.")))))
- (setq pymacs-use-hash-tables (and (fboundp 'make-hash-table)
- (fboundp 'gethash)
- (fboundp 'puthash)))
- (when pymacs-use-hash-tables
- (if pymacs-weak-hash
- ;; A previous Pymacs session occurred in *this* Emacs session. Some
- ;; IDs may hang around, which do not correspond to anything on the
- ;; Python side. Python should not recycle such IDs for new objects.
- (when pymacs-used-ids
- (let ((pymacs-transit-buffer buffer)
- (pymacs-forget-mutability t))
- (pymacs-apply "zombie_python" pymacs-used-ids)))
- (setq pymacs-weak-hash (make-hash-table :weakness 'value)))
- (if (boundp 'post-gc-hook)
- (add-hook 'post-gc-hook 'pymacs-schedule-gc)
- (setq pymacs-gc-timer (run-at-time 20 20 'pymacs-schedule-gc))))
- ;; If nothing failed, only then declare the Pymacs has started!
- (setq pymacs-transit-buffer buffer)))
-
-(defun pymacs-terminate-services ()
- ;; This function is mainly provided for documentation purposes.
- (interactive)
- (garbage-collect)
- (pymacs-garbage-collect)
- (when (or (not pymacs-used-ids)
- (yes-or-no-p "\
-Killing the helper might create zombie objects. Kill? "))
- (cond ((boundp 'post-gc-hook)
- (remove-hook 'post-gc-hook 'pymacs-schedule-gc))
- ((timerp pymacs-gc-timer)
- (cancel-timer pymacs-gc-timer)))
- (when pymacs-transit-buffer
- (kill-buffer pymacs-transit-buffer))
- (setq pymacs-gc-running nil
- pymacs-gc-timer nil
- pymacs-transit-buffer nil
- pymacs-lisp nil
- pymacs-freed-list nil)))
-
-(defun pymacs-serve-until-reply (inserter)
- ;; This function evals INSERTER to print a Python request. It sends it to
- ;; the Python helper, and serves all sub-requests coming from the
- ;; Python side, until either a reply or an error is finally received.
- (unless (and pymacs-transit-buffer
- (buffer-name pymacs-transit-buffer)
- (get-buffer-process pymacs-transit-buffer))
- (pymacs-start-services))
- (when pymacs-gc-wanted
- (pymacs-garbage-collect))
- (let (done value)
- (while (not done)
- (let* ((text (pymacs-round-trip inserter))
- (reply (condition-case info
- (eval text)
- (error (cons 'pymacs-oops (prin1-to-string info))))))
- (cond ((not (consp reply))
- (setq inserter
- `(pymacs-print-for-apply 'reply '(,reply))))
- ((eq 'pymacs-reply (car reply))
- (setq done t value (cdr reply)))
- ((eq 'pymacs-error (car reply))
- (error "Python: %s" (cdr reply)))
- ((eq 'pymacs-oops (car reply))
- (setq inserter
- `(pymacs-print-for-apply 'error '(,(cdr reply)))))
- ((eq 'pymacs-expand (car reply))
- (setq inserter
- `(pymacs-print-for-apply-expanded 'reply
- '(,(cdr reply)))))
- (t (setq inserter
- `(pymacs-print-for-apply 'reply '(,reply)))))))
- value))
-
-(defun pymacs-reply (expression)
- ;; This pseudo-function returns `(pymacs-reply . EXPRESSION)'.
- ;; `serve-until-reply' later recognises this form.
- (cons 'pymacs-reply expression))
-
-(defun pymacs-error (expression)
- ;; This pseudo-function returns `(pymacs-error . EXPRESSION)'.
- ;; `serve-until-reply' later recognises this form.
- (cons 'pymacs-error expression))
-
-(defun pymacs-expand (expression)
- ;; This pseudo-function returns `(pymacs-expand . EXPRESSION)'.
- ;; `serve-until-reply' later recognises this form.
- (cons 'pymacs-expand expression))
-
-(defun pymacs-round-trip (inserter)
- ;; This function evals INSERTER to print a Python request. It sends it to
- ;; the Python helper, awaits for any kind of reply, and returns it.
- (with-current-buffer pymacs-transit-buffer
- (unless pymacs-trace-transit
- (erase-buffer))
- (let* ((process (get-buffer-process pymacs-transit-buffer))
- (status (process-status process))
- (marker (process-mark process))
- (moving (= (point) marker))
- send-position reply-position reply)
- (save-excursion
- (save-match-data
- ;; Encode request.
- (setq send-position (marker-position marker))
- (let ((standard-output marker))
- (eval inserter))
- (goto-char marker)
- (unless (= (preceding-char) ?\n)
- (princ "\n" marker))
- ;; Send request text.
- (goto-char send-position)
- (insert (format ">%d\t" (- marker send-position)))
- (setq reply-position (marker-position marker))
- (process-send-region process send-position marker)
- ;; Receive reply text.
- (while (and (eq status 'run)
- (progn
- (goto-char reply-position)
- (not (re-search-forward "<\\([0-9]+\\)\t" nil t))))
- (unless (accept-process-output process pymacs-timeout-at-reply)
- (setq status (process-status process))))
- (when (eq status 'run)
- (let ((limit-position (+ (match-end 0)
- (string-to-number (match-string 1)))))
- (while (and (eq status 'run)
- (< (marker-position marker) limit-position))
- (unless (accept-process-output process pymacs-timeout-at-line)
- (setq status (process-status process))))))
- ;; Decode reply.
- (if (not (eq status 'run))
- (error "Pymacs helper status is `%S'." status)
- (goto-char (match-end 0))
- (setq reply (read (current-buffer))))))
- (when (and moving (not pymacs-trace-transit))
- (goto-char marker))
- reply)))
-
-(defun pymacs-proper-list-p (expression)
- ;; Tell if a list is proper, id est, that it is `nil, or ends with `nil'.
- (cond ((not expression))
- ((consp expression) (not (cdr (last expression))))))
-
-(provide 'pymacs)
--- a/vim/sadness/bike/ide-integration/Pymacs-0.20/rebox Thu Feb 10 17:11:26 2011 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,11 +0,0 @@
-#!/usr/bin/env python
-# Copyright © 2002 Progiciels Bourbeau-Pinard inc.
-# François Pinard <pinard@iro.umontreal.ca>, 2002.
-
-"""\
-Handling of boxed comments in various box styles.
-"""
-
-import sys
-from Pymacs import rebox
-apply(rebox.main, tuple(sys.argv[1:]))
--- a/vim/sadness/bike/ide-integration/Pymacs-0.20/setup-emacs.py Thu Feb 10 17:11:26 2011 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,235 +0,0 @@
-#!/usr/bin/env python
-# Copyright © 2001, 2002 Progiciels Bourbeau-Pinard inc.
-# François Pinard <pinard@iro.umontreal.ca>, 2001.
-
-"""\
-Installer tool for Pymacs `pymacs.el'.
-
-Usage: setup [OPTION]
-
- -H Display this help, then exit.
- -V Display package name and version, then exit.
-
- -i Interactively check selected options with user.
- -n Dry run: merely display selected options.
- -g GROUP Install with write permissions for that user GROUP.
- -e Load `.emacs' before checking Emacs `load-path'.
-
- -l LISPDIR Install `pymacs.el' in LISPDIR.
- -E EMACS Use that executable for EMACS, if not `emacs'.
-"""
-
-import os, string, sys
-
-sys.path.insert(0, '.')
-from Pymacs import package, version
-del sys.path[0]
-
-AUTOCONF = () # neither a string nor None
-
-class run:
- interactive = 0
- dry = 0
- group = None
- dot_emacs = 0
- lispdir = AUTOCONF
- emacs = 'emacs'
-
-def main(*arguments):
- import getopt
- options, arguments = getopt.getopt(arguments, 'E:HVeg:il:n')
- for option, value in options:
- if option == '-E' and value:
- run.emacs = value
- elif option == '-H':
- sys.stdout.write(__doc__)
- sys.exit(0)
- elif option == '-V':
- sys.stdout.write('%s-%s' % (package, version))
- sys.exit(0)
- elif option == '-e':
- run.dot_emacs = 1
- elif option == '-g' and value:
- run.group = value
- elif option == '-i':
- run.interactive = 1
- elif option == '-l' and value:
- if value in ('none', 'None'):
- run.lispdir = None
- else:
- run.lispdir = [value]
- auto_configure()
- if run.interactive:
- check_with_user()
- check_choices()
- if not run.dry:
- complete_install()
-
-def auto_configure():
- if run.lispdir is AUTOCONF:
- run.lispdir = []
- import tempfile
- script = tempfile.mktemp()
- if sys.platform == 'win32':
- # Win32 names starting with tilde and Emacs are unhappy together.
- path, file = os.path.split(script)
- script = os.path.join(path, 'a' + file)
- try:
- open(script, 'w').write('(message "%S" load-path)')
- load_config = ''
- if run.dot_emacs:
- config = os.path.join(os.environ['HOME'], '.emacs')
- for name in config, config + '.el', config + '.elc':
- if os.path.isfile(name):
- # Quote! Spaces are common in Win32 file names.
- load_config = ' -l "%s"' % name
- break
- # Quote! Spaces are common in Win32 file names.
- text = os.popen('%s -batch%s -l "%s" 2>&1'
- % (run.emacs, load_config, script)).read()
- finally:
- os.remove(script)
- position = string.find(text, '("')
- if position >= 0:
- text = text[position:]
- if text[-1] == '\n':
- text = text[:-1]
- assert text[0] == '(' and text[-1] == ')', text
- for path in string.split(text[1:-1]):
- assert path[0] == '"' and path[-1] == '"', path
- path = path[1:-1]
- if os.access(path, 7):
- run.lispdir.append(path)
-
-def check_with_user():
- sys.stderr.write("""\
-Install tool for %s version %s.
-"""
- % (package, version))
- run.lispdir = user_select('lispdir', run.lispdir, """\
-This is where `pymacs.el', the Emacs side code of Pymacs, should go:
-somewhere on your Emacs `load-path'.
-""")
-
-def user_select(name, values, message):
- write = sys.stderr.write
- readline = sys.stdin.readline
- if values is None:
- write("""\
-
-Enter a value for `%s', or merely type `Enter' if you do not want any.
-"""
- % name)
- write(message)
- while 1:
- write('%s? ' % name)
- text = string.strip(readline())
- if not text:
- return None
- if os.access(os.path.expanduser(text), 7):
- return [text]
- write("""\
-
-This directory does not exist, or is not writable. Please reenter it.
-""")
- if len(values) == 1:
- return values
- if values == []:
- write("""\
-
-Pymacs is not likely to install properly, as the installer may not currently
-write in any directory for `%s'. Running as `root' might help you.
-Or else, you will most probably have to revise a bit your work setup.
-"""
- % name)
- write(message)
- return values
- write("""\
-
-There are many possibilities for `%s', please select one of them by
-typing its number followed by `Enter'. A mere `Enter' selects the first.
-"""
- % name)
- write(message)
- write('\n')
- for counter in range(len(values)):
- write('%d. %s\n' % (counter + 1, values[counter]))
- while 1:
- write('[1-%d]? ' % len(values))
- text = string.strip(readline())
- if not text:
- return [values[0]]
- try:
- counter = int(text)
- except ValueError:
- pass
- else:
- if 1 <= counter <= len(values):
- return [values[counter-1]]
- write("""\
-This is not a valid choice. Please retry.
-""")
-
-def check_choices():
- write = sys.stderr.write
- error = 0
- if run.lispdir is not None:
- if run.lispdir and os.access(os.path.expanduser(run.lispdir[0]), 7):
- run.lispdir = run.lispdir[0]
- else:
- write("\
-Use `-l LISPDIR' to select where `pymacs.el' should go.\n")
- error = 1
- if error:
- write("ERROR: Installation aborted!\n"
- " Try `%s -i'.\n" % sys.argv[0])
- sys.exit(1)
- write(
- '\n'
- "Directory selection for installing Pymacs:\n"
- " lispdir = %(lispdir)s\n"
- '\n'
- % run.__dict__)
-
-def complete_install():
- run.substitute = {'PACKAGE': package, 'VERSION': version}
- if run.lispdir:
- goal = os.path.join(run.lispdir, 'pymacs.el')
- install('pymacs.el', goal, 0644)
- compile_lisp(goal)
-
-def install(source, destination, permissions):
- sys.stderr.write('Installing %s\n' % destination)
- write = open(destination, 'w').write
- produce_at = 0
- #print '*', run.substitute
- for fragment in string.split(open(source).read(), '@'):
- #print '**', produce_at, `fragment`
- if produce_at:
- replacement = run.substitute.get(fragment)
- #print '***', replacement
- if replacement is None:
- write('@')
- write(fragment)
- else:
- write(replacement)
- produce_at = 0
- else:
- write(fragment)
- produce_at = 1
- write = None
- set_attributes(destination, permissions)
-
-def compile_lisp(name):
- sys.stderr.write('Compiling %s\n' % name)
- os.system('%s -batch -f batch-byte-compile %s' % (run.emacs, name))
- set_attributes(name + 'c', 0644)
-
-def set_attributes(name, permissions):
- if run.group:
- os.chown(name, run.group)
- permissions = permissions | 0020
- os.chmod(name, permissions)
-
-if __name__ == '__main__':
- apply(main, sys.argv[1:])
--- a/vim/sadness/bike/ide-integration/Pymacs-0.20/setup.py Thu Feb 10 17:11:26 2011 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,17 +0,0 @@
-#!/usr/bin/env python
-
-import sys
-sys.path.insert(0, '.')
-from Pymacs import package, version
-del sys.path[0]
-
-from distutils.core import setup
-
-setup(name=package,
- version=version,
- description='Interface between Emacs LISP and Python.',
- author='François Pinard',
- author_email='pinard@iro.umontreal.ca',
- url='http://www.iro.umontreal.ca/~pinard',
- scripts=['pymacs-services', 'pymacs-services.bat', 'rebox'],
- packages=['Pymacs'])
--- a/vim/sadness/bike/ide-integration/bike.vim Thu Feb 10 17:11:26 2011 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,430 +0,0 @@
-" Bicycle Repair Man integration for Vim
-" Version 0.3
-" Copyright (c) 2003 Marius Gedminas <mgedmin@delfi.lt>
-"
-" Needs Vim 6.x with python interpreter (Python 2.2 or newer)
-" Installation instructions: just drop it into $HOME/.vim/plugin and you
-" should see the Bicycle Repair Menu appear in GVim (or you can check if
-" any of the BikeXxx commands are defined in console mode Vim). If bike.vim
-" fails to load and you want to see the reason, try
-" let g:bike_exceptions = 1
-" source ~/.vim/plugin/bike.vim
-"
-" Configuration options you can add to your .vimrc:
-" let g:bike_exceptions = 1 " show tracebacks on exceptions
-" let g:bike_progress = 1 " show import progress
-"
-" Commands defined:
-"
-" BikeShowScope
-" Show current scope. Sample of usage:
-" autocmd CursorHold *.py BikeShowScope
-"
-" <range> BikeShowType
-" Show selected expression type. The range is ignored, '<,'> is always
-" used. Use this in visual block mode.
-"
-" BikeFindRefs
-" Finds all references of the function/method/class defined in current
-" line.
-"
-" BikeFindDef
-" Finds the definition of the function/method/class under cursor.
-"
-" BikeRename
-" Renames the function/method/class defined in current line. Updates
-" all references in all files known (i.e. imported) to Bicycle Repair
-" Man.
-"
-" <range> BikeExtract
-" Extracts a part of the function/method into a new function/method.
-" The range is ignored, '<,'> is always used. Use this in visual mode.
-"
-" BikeUndo
-" Globally undoes the previous refactoring.
-"
-" Issues:
-" - Saves all modified buffers to disk without asking the user -- not nice
-" - Does not reimport files that were modified outside of Vim
-" - Uses mktemp() -- I think that produces deprecation warnings in Python 2.3
-" - BikeShowType, BikeExtract ignores the specified range, that's confusing.
-" At least BikeExtract ought to work...
-" - BikeShowType/BikeExtract or their GUI counterparts work when not in
-" visual mode by using the previous values of '<,'>. Might be confusing.
-" - Would be nice if :BikeImport<CR> asked to enter package
-" - Would be nice if :BikeRename myNewName<CR> worked
-" - The code is not very robust (grep for XXX)
-
-"
-" Default settings for global configuration variables {{{1
-"
-
-" Set to 1 to see full tracebacks
-if !exists("g:bike_exceptions")
- let g:bike_exceptions = 0
-endif
-
-" Set to 1 to see import progress
-if !exists("g:bike_progress")
- let g:bike_progress = 0
-endif
-
-"
-" Initialization {{{1
-"
-
-" First check that Vim is sufficiently recent, that we have python interpreted
-" support, and that Bicycle Repair Man is available.
-"
-" If something is wrong, fail silently, as error messages every time vim
-" starts are very annoying. But if the user wants to see why bike.vim failed
-" to load, she can let g:bike_exceptions = 1
-if version < 600
- if g:bike_exceptions
- echo 'Bicycle Repair Man needs Vim 6.0'
- endif
- finish
-endif
-
-if !has("python")
- if g:bike_exceptions
- echo 'Bicycle Repair Man needs Vim with Python interpreter support (2.2 or newer)'
- endif
- finish
-endif
-
-let s:has_bike=1
-python << END
-import vim
-import sys
-try:
- if sys.version_info < (2, 2):
- raise ImportError, 'Bicycle Repair Man needs Python 2.2 or newer'
- import bike
- bikectx = bike.init()
- bikectx.isLoaded # make sure bike package is recent enough
-except ImportError:
- vim.command("let s:has_bike=0")
- if vim.eval('g:bike_exceptions') not in (None, '', '0'):
- raise
-END
-if !s:has_bike
- finish
-endif
-
-" Use sane cpoptions
-let s:cpo_save = &cpo
-set cpo&vim
-
-"
-" Menu {{{1
-"
-silent! aunmenu Bicycle\ Repair\ Man
-
-" Shortcuts available: ab-----h-jk--nopq----vw--z
-amenu <silent> Bicycle\ &Repair\ Man.-SEP1-
-\ :
-amenu <silent> Bicycle\ &Repair\ Man.&Find\ References
-\ :call <SID>BikeFindRefs()<CR>
-amenu <silent> Bicycle\ &Repair\ Man.Find\ &Definition
-\ :call <SID>BikeFindDef()<CR>
-amenu <silent> Bicycle\ &Repair\ Man.Resu<s.&List<tab>:cl
-\ :cl<CR>
-amenu <silent> Bicycle\ &Repair\ Man.Resu<s.&Current<tab>:cc
-\ :cc<CR>
-amenu <silent> Bicycle\ &Repair\ Man.Resu<s.&Next<tab>:cn
-\ :cn<CR>
-amenu <silent> Bicycle\ &Repair\ Man.Resu<s.&Previous<tab>:cp
-\ :cp<CR>
-amenu <silent> Bicycle\ &Repair\ Man.Resu<s.&First<tab>:cfirst
-\ :cfirst<CR>
-amenu <silent> Bicycle\ &Repair\ Man.Resu<s.Las&t<tab>:clast
-\ :clast<CR>
-amenu <silent> Bicycle\ &Repair\ Man.Resu<s.&Older\ List<tab>:colder
-\ :colder<CR>
-amenu <silent> Bicycle\ &Repair\ Man.Resu<s.N&ewer\ List<tab>:cnewer
-\ :cnewer<CR>
-amenu <silent> Bicycle\ &Repair\ Man.Resu<s.&Window.&Update<tab>:cw
-\ :cw<CR>
-amenu <silent> Bicycle\ &Repair\ Man.Resu<s.&Window.&Open<tab>:copen
-\ :copen<CR>
-amenu <silent> Bicycle\ &Repair\ Man.Resu<s.&Window.&Close<tab>:cclose
-\ :cclose<CR>
-amenu <silent> Bicycle\ &Repair\ Man.-SEP2-
-\ :
-amenu <silent> Bicycle\ &Repair\ Man.&Rename
-\ :call <SID>BikeRename()<CR>
-amenu <silent> Bicycle\ &Repair\ Man.E&xtract\ Method
-\ :call <SID>BikeExtract('method')<CR>
-amenu <silent> Bicycle\ &Repair\ Man.&Extract\ Function
-\ :call <SID>BikeExtract('function')<CR>
-amenu <silent> Bicycle\ &Repair\ Man.&Undo
-\ :call <SID>BikeUndo()<CR>
-amenu <silent> Bicycle\ &Repair\ Man.-SEP3-
-\ :
-amenu <silent> Bicycle\ &Repair\ Man.Settin&gs.Import\ &Progress.&Enable
-\ :let g:bike_progress = 1<CR>
-amenu <silent> Bicycle\ &Repair\ Man.Settin&gs.Import\ &Progress.&Disable
-\ :let g:bike_progress = 0<CR>
-amenu <silent> Bicycle\ &Repair\ Man.Settin&gs.Full\ &Exceptions.&Enable
-\ :let g:bike_exceptions = 1<CR>
-amenu <silent> Bicycle\ &Repair\ Man.Settin&gs.Full\ &Exceptions.&Disable
-\ :let g:bike_exceptions = 0<CR>
-
-" Note: The three rename commands are basically identical. The two extract
-" commands are also identical behind the scenes.
-
-"
-" Commands {{{1
-"
-
-command! BikeShowScope call <SID>BikeShowScope()
-command! -range BikeShowType call <SID>BikeShowType()
-command! BikeFindRefs call <SID>BikeFindRefs()
-command! BikeFindDef call <SID>BikeFindDef()
-
-command! BikeRename call <SID>BikeRename()
-command! -range BikeExtract call <SID>BikeExtract('function')
-command! BikeUndo call <SID>BikeUndo()
-
-"
-" Implementation {{{1
-"
-
-" Query functions {{{2
-
-function! s:BikeShowScope()
-" Shows the scope under cursor
- python << END
-fn = vim.current.buffer.name
-row, col = vim.current.window.cursor
-try:
- print bikectx.getFullyQualifiedNameOfScope(fn, row)
-except:
- show_exc()
-END
-endf
-
-function! s:BikeShowType()
-" Shows the inferred type of the selected expression
- if col("'<") == 0 " mark not set
- echo "Select a region first!"
- return
- endif
- if line("'<") != line("'>") " multiline selection
- echo "Multi-line regions not supported"
- " XXX deficiency of bikefacade interface, expressions can easily span
- " several lines in Python
- return
- endif
- python << END
-fn = vim.current.buffer.name
-row1, col1 = vim.current.buffer.mark('<')
-row2, col2 = vim.current.buffer.mark('>')
-try:
- print bikectx.getTypeOfExpression(fn, row1, col1, col2)
-except:
- show_exc()
-END
-endf
-
-function! s:BikeFindRefs()
-" Find all references to the item defined on current line
- wall
- python << END
-fn = vim.current.buffer.name
-row, col = vim.current.window.cursor
-try:
- refs = bikectx.findReferencesByCoordinates(fn, row, col)
- quickfixdefs(refs)
-except:
- show_exc()
-END
-endf
-
-function! s:BikeFindDef()
-" Find all definitions of the item under cursor. Ideally there should be only
-" one.
- wall
- python << END
-fn = vim.current.buffer.name
-row, col = vim.current.window.cursor
-try:
- defs = bikectx.findDefinitionByCoordinates(fn, row, col)
- quickfixdefs(defs)
-except:
- show_exc()
-END
-endf
-
-" Refactoring commands {{{2
-
-function! s:BikeRename()
-" Rename a function/method/class.
-
- let newname = inputdialog('Rename to: ')
- wall
- python << END
-fn = vim.current.buffer.name
-row, col = vim.current.window.cursor
-newname = vim.eval("newname")
-if newname:
- try:
- bikectx.setRenameMethodPromptCallback(renameMethodPromptCallback)
- bikectx.renameByCoordinates(fn, row, col, newname)
- except:
- show_exc()
- saveChanges()
-else:
- print "Aborted"
-END
-endf
-
-function! s:BikeExtract(what)
-" Extract a piece of code into a separate function/method. The argument
-" a:what can be 'method' or 'function'.
- if col("'<") == 0 " mark not set
- echo "Select a region first!"
- return
- endif
- let newname = inputdialog('New function name: ')
- wall
- python << END
-fn = vim.current.buffer.name
-row1, col1 = vim.current.buffer.mark('<')
-row2, col2 = vim.current.buffer.mark('>')
-newname = vim.eval("newname")
-if newname:
- try:
- bikectx.extractMethod(fn, row1, col1, row2, col2, newname)
- except:
- show_exc()
- saveChanges()
-else:
- print "Aborted"
-END
-endf
-
-function! s:BikeUndo()
-" Undoes the last refactoring
- wall
-python << END
-try:
- bikectx.undo()
- saveChanges()
-except bike.UndoStackEmptyException, e:
- print "Nothing to undo"
-END
-endf
-
-"
-" Helper functions {{{1
-"
-
-" Python helpers
-
-python << END
-
-import tempfile
-import os
-import linecache
-
-modified = {} # a dictionary whose keys are the names of files modifed
- # in Vim since the last import
-
-def show_exc():
- """Print exception according to bike settings."""
- if vim.eval('g:bike_exceptions') not in (None, '', '0'):
- import traceback
- traceback.print_exc()
- else:
- type, value = sys.exc_info()[:2]
- if value is not None:
- print "%s: %s" % (type, value)
- else:
- print type
-
-def writedefs(defs, filename):
- """Write a list of file locations to a file."""
- ef = None
- curdir = os.getcwd()
- if not curdir.endswith(os.sep):
- curdir = curdir + os.sep
- for d in defs:
- if not ef:
- ef = open(filename, "w")
- fn = d.filename
- if fn.startswith(curdir):
- fn = fn[len(curdir):]
- line = linecache.getline(fn, d.lineno).strip()
- res ="%s:%d: %3d%%: %s" % (fn, d.lineno, d.confidence, line)
- print res
- print >> ef, res
- if ef:
- ef.close()
- return ef is not None
-
-def quickfixdefs(defs):
- """Import a list of file locations into vim error list."""
- fn = tempfile.mktemp() # XXX unsafe
- if writedefs(defs, fn):
- vim.command('let old_errorfile = &errorfile')
- vim.command('let old_errorformat = &errorformat')
- vim.command(r'set errorformat=\%f:\%l:\ \%m')
- vim.command("cfile %s" % fn)
- vim.command('let &errorformat = old_errorformat')
- vim.command('let &errorfile = old_errorfile')
- os.unlink(fn)
- else:
- print "Not found"
-
-def renameMethodPromptCallback(filename, line, col1, col2):
- """Verify that the call in a given file position should be renamed."""
- vim.command('e +%d %s' % (line, filename))
- vim.command('normal %d|' % col1)
- vim.command('match Search /\%%%dl\%%>%dc\%%<%dc' % (line, col1, col2+1))
- vim.command('redraw')
- ans = vim.eval('confirm("Cannot deduce instance type. Rename this call?",'
- ' "&Yes\n&No", 1, "Question")')
- vim.command('match none')
- if ans == '1':
- return 1
- else:
- return 0
-
-
-def saveChanges():
- """Save refactoring changes to the file system and reload the modified
- files in Vim."""
- # bikectx.save() returns a list of modified file names. We should make
- # sure that all those files are reloaded iff they were open in vim.
- files = map(os.path.abspath, bikectx.save())
-
- opened_files = {}
- for b in vim.buffers:
- if b.name is not None:
- opened_files[os.path.abspath(b.name)] = b.name
-
- for f in files:
- try:
- # XXX might fail when file name contains funny characters
- vim.command("sp %s | q" % opened_files[f])
- except KeyError:
- pass
-
- # Just in case:
- vim.command("checktime")
- vim.command("e")
-
-END
-
-" Make sure modified files are reimported into BRM
-autocmd BufWrite * python modified[os.path.abspath(vim.current.buffer.name)] = 1
-
-"
-" Cleanup {{{1
-"
-
-" Restore cpoptions
-let &cpo = s:cpo_save
-unlet s:cpo_save
--- a/vim/sadness/bike/ide-integration/bikeemacs.py Thu Feb 10 17:11:26 2011 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,333 +0,0 @@
-# Bicycle Repair Man integration with (X)Emacs
-# By Phil Dawes (2002)
-# Uses the fabulous Pymacs package by François Pinard
-
-from Pymacs import lisp, Let
-import bike
-reload(bike)
-from bike import bikefacade
-import StringIO, traceback
-import sys
-
-class EmacsLogger:
- def __init__(self):
- self.msg = ""
-
- def write(self,output):
- self.msg +=output
- if output.endswith("\n"):
- lisp.message(self.msg)
- self.msg = ""
-
-class NullLogger:
- def write(self,output):
- pass
-
-logger = EmacsLogger()
-
-
-class ExceptionCatcherWrapper:
-
- def __init__(self,myobj):
- self.myobj = myobj
-
- def __getattr__(self,name):
- return ExceptionInterceptor(self.myobj,name)
-
-
-class ExceptionInterceptor:
- def __init__(self,targetobj,name):
- self.targetobj = targetobj
- self.name = name
-
- def __call__(self, *params, **kwparams ):
- try:
- return self.makeCall(params)
- except:
- traceback.print_exc()
- lisp.error(str(sys.exc_info()[1]))
-
- def makeCall(self,params):
- argsstr="(self.targetobj"
- for i in range(len(params)):
- argsstr += ",params["+`i`+"]"
- argsstr+=")"
- return eval("self.targetobj.__class__."+self.name+argsstr)
-
-
-class BRMEmacs(object):
-
- def __init__(self,brmctx):
- self.ctx = brmctx
-
- lisp.require(lisp["python-mode"])
- lisp("""
- (defvar brm-menu nil "Menu for Bicycle Repair Man")
- (easy-menu-define
- brm-menu py-mode-map "Bicycle Repair Man"
- '("BicycleRepairMan"
- "Queries"
- ["Find-References" brm-find-references]
- ["Find-Definition" brm-find-definition]
- "---"
- "Refactoring"
- ["Rename" brm-rename t]
- ["Extract-Method" brm-extract-method t]
- ["Extract-Local-Variable" brm-extract-local-variable t]
- ["Inline-Local-Variable" brm-inline-local-variable t]
- ["Undo Last Refactoring" brm-undo t]
-
- ))
- (add-hook 'python-mode-hook (lambda () (easy-menu-add brm-menu)))
- """)
- # ["Move-Class-To-New-Module" brm-move-class t]
- # ["Move-Function-To-New-Module" brm-move-class t]
-
- self.ctx.setProgressLogger(logger)
-
-
- def rename(self,newname):
- lisp.save_some_buffers()
- filename = lisp.buffer_file_name()
- line,col = _getCoords()
- brmctx.setRenameMethodPromptCallback(promptCallback)
- try:
- self.ctx.renameByCoordinates(filename,line,col,newname)
- savedFiles = brmctx.save()
- _revertSavedFiles(savedFiles)
- lisp.set_marker(lisp.mark_marker(),None)
- except bikefacade.CouldntLocateASTNodeFromCoordinatesException:
- print >>logger,"Couldn't find AST Node. Are you renaming the declaration?"
-
- def kill(self):
- self.ctx = None
- self.ctx = bike.init()
- self.ctx.setProgressLogger(logger)
-
- def undo(self):
- brmctx.undo()
- savedFiles = brmctx.save()
- _revertSavedFiles(savedFiles)
-
- def find_references(self):
- lisp.save_some_buffers()
- filename = lisp.buffer_file_name()
- line,col = _getCoords()
- refs = brmctx.findReferencesByCoordinates(filename,line,col)
- _switchToConsole()
- numRefs = 0
- for ref in refs:
- _insertRefLineIntoConsole(ref)
- numRefs +=1
- lisp.insert("Done - %d refs found\n"%numRefs)
-
-
- def find_definition(self):
- lisp.save_some_buffers()
- filename = lisp.buffer_file_name()
- line,col = _getCoords()
- defns = brmctx.findDefinitionByCoordinates(filename,line,col)
-
- try:
- firstdefn = defns.next()
- lisp.find_file_other_window(firstdefn.filename)
- lisp.goto_line(firstdefn.lineno)
- lisp.forward_char(firstdefn.colno)
- except StopIteration:
- pass
- else:
- numRefs = 1
- for defn in defns:
- if numRefs == 1:
- _switchToConsole()
- _insertRefLineIntoConsole(firstdefn)
- _insertRefLineIntoConsole(defn)
- numRefs += 1
-
-
- def inline_local_variable(self):
- lisp.save_some_buffers()
- filename = lisp.buffer_file_name()
- line,col = _getCoords()
- brmctx.inlineLocalVariable(filename,line,col)
- lisp.set_marker(lisp.mark_marker(),None)
- _revertSavedFiles(brmctx.save())
-
- def extract_local_variable(self,name):
- lisp.save_some_buffers()
- filename = lisp.buffer_file_name()
-
- bline,bcol = _getPointCoords()
- lisp.exchange_point_and_mark()
- eline,ecol = _getPointCoords()
- lisp.exchange_point_and_mark()
-
- brmctx.extractLocalVariable(filename,bline,bcol,eline,ecol,name)
- lisp.set_marker(lisp.mark_marker(),None)
- _revertSavedFiles(brmctx.save())
-
- def extract_method(self,name):
- lisp.save_some_buffers()
- filename = lisp.buffer_file_name()
-
- bline,bcol = _getPointCoords()
- lisp.exchange_point_and_mark()
- eline,ecol = _getPointCoords()
- lisp.exchange_point_and_mark()
-
- brmctx.extract(filename,bline,bcol,eline,ecol,name)
- lisp.set_marker(lisp.mark_marker(),None)
- _revertSavedFiles(brmctx.save())
-
-
- def move_class(self,newfilename):
- lisp.save_some_buffers()
- filename = lisp.buffer_file_name()
- line,col = _getCoords()
- brmctx.moveClassToNewModule(filename,line,newfilename)
- _revertSavedFiles(brmctx.save())
-
-
-
-brmctx = bike.init()
-
-brmemacs = None
-
-is_xemacs = (lisp.emacs_version().find("GNU") == -1)
-currently_saving=0
-
-# fix pop_excursion to work with xemacs
-class Let(Let):
- def pop_excursion(self):
- method, (buffer, point_marker, mark_marker) = self.stack[-1]
- assert method == 'excursion', self.stack[-1]
- del self.stack[-1]
- lisp.set_buffer(buffer)
- lisp.goto_char(point_marker)
- lisp.set_mark(mark_marker)
- lisp.set_marker(point_marker, None)
- if mark_marker is not None: # needed for xemacs
- lisp.set_marker(mark_marker, None)
-
-
-
-def init():
- global brmemacs
- brmemacs = ExceptionCatcherWrapper(BRMEmacs(brmctx))
-
-
-def kill():
- """
- Removes the bicyclerepairman context (freeing the state),
- and reinitialises it.
- """
- brmemacs.kill()
-kill.interaction=""
-
-
-def promptCallback(filename,line,colbegin,colend):
- let = Let().push_excursion() # gets popped when let goes out of scope
- buffer = lisp.current_buffer()
- if let:
- ans = 0
- lisp.find_file(filename)
- lisp.goto_line(line)
- lisp.move_to_column(colbegin)
- lisp.set_mark(lisp.point() + (colend - colbegin))
- if is_xemacs:
- lisp.activate_region()
- ans = lisp.y_or_n_p("Couldn't deduce object type - rename this method reference? ")
- del let
- lisp.switch_to_buffer(buffer)
- return ans
-
-def rename(newname):
- return brmemacs.rename(newname)
-rename.interaction="sNew name: "
-
-
-def undo():
- return brmemacs.undo()
-undo.interaction=""
-
-
-def _revertSavedFiles(savedFiles):
- global currently_saving
- currently_saving = 1
- for file in savedFiles:
- buf = lisp.find_buffer_visiting(file)
- if buf:
- lisp.set_buffer(buf)
- lisp.revert_buffer(None,1)
- currently_saving = 0
-
-def find_references():
- brmemacs.find_references()
-find_references.interaction=""
-
-def _getCoords():
- line = lisp.count_lines(1,lisp.point())
- col = lisp.current_column()
- if col == 0:
- line += 1 # get round 'if col == 0, then line is 1 out' problem
-
- if mark_exists() and lisp.point() > lisp.mark():
- lisp.exchange_point_and_mark()
- col = lisp.current_column()
- lisp.exchange_point_and_mark()
- return line,col
-
-def mark_exists():
- if is_xemacs:
- return lisp.mark()
- else:
- return lisp("mark-active") and lisp.mark()
-
-
-
-def _switchToConsole():
- consolebuf = lisp.get_buffer_create("BicycleRepairManConsole")
- lisp.switch_to_buffer_other_window(consolebuf)
- lisp.compilation_mode("BicycleRepairMan")
- lisp.erase_buffer()
- lisp.insert("Bicycle Repair Man\n")
- lisp.insert("(Hint: Press Return a Link)\n")
-
-def find_definition():
- brmemacs.find_definition()
-find_definition.interaction=""
-
-def _insertRefLineIntoConsole(ref):
- lisp.insert(ref.filename+":"+str(ref.lineno)+": "+str(ref.confidence)+"% confidence\n")
- _redisplayFrame()
-
-def _redisplayFrame():
- lisp.sit_for(0)
-
-def inline_local_variable():
- brmemacs.inline_local_variable()
-inline_local_variable.interaction=""
-
-def extract_local_variable(name):
- brmemacs.extract_local_variable(name)
-extract_local_variable.interaction="sVariable name: "
-
-
-def extract_method(name):
- brmemacs.extract_method(name)
-extract_method.interaction="sName of function: "
-
-
-def move_class(newfilename):
- return brmemacs.move_class(newfilename)
-move_class.interaction="fTarget file: "
-
-
-
-def _getPointCoords():
- bline = lisp.count_lines(1,lisp.point())
- bcol = lisp.current_column()
- if bcol == 0: # get round line is one less if col is 0 problem
- bline += 1
- return bline,bcol
-
--- a/vim/sadness/bike/ide-integration/test/README Thu Feb 10 17:11:26 2011 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,89 +0,0 @@
-Test Steps for testing idle integration
----------------------------------------
-
-N.B. this test script is not expected to test all of bicyclerepairman
-- the pyunit tests do that. It is merely there to test the integration
-with idle (which doesnt get tested by pyunit).
-
-
-------------- Rename * -----------------------------------------
-
-- Load scrap.py
-
-- Rename Class to MyRenamedClass
- (Check it renames the class)
-
-- Undo the rename
-
-- Create scrap3.py, containing the following:
-
----------------------------
-import scrap
-
-a = scrap.MyClass()
-a.myMethod()
---------------------------
-
-- Go back to scrap.py and rename the method to MyRenamedMethod
- (Check that it prompts for rename in scrap2.py - rename the
- first, but not the second)
- (Check that it renames all the methods in scrap2.py and scrap3.py
- except for the one you said no to)
-
-- Undo the rename
- (Check that it undid all the renamings in all the files)
-
-------------- Find References ----------------------------------
-
-
-- Goto scrap.py, select 'find references'. Check that it tells you to
-highlight a class/function/method.
-
-- Highlight 'myMethod' and try again Check that it displays a list of
-references to this method.
-
-
-------------- Find Definition ----------------------------------
-
-- Goto scrap2.py, click 'myMethod' on d.myMethod(), then select 'find
-definition'. Check that it displays both the myMethod in MyClass and
-in AnotherClass.
-
-
-- Goto scrap2.py, click 'myMethod' on e.myMethod(), then select 'find
-definition'. Check that it takes you to the definition, and doesn't
-display a list of myMethod() references.
-
-
-------------- Extract Method / Function ------------------------
-
-- Load extractMethod.py into idle
-
-- select 'Extract Method' without first selecting a region
- (Check that it tells you to select the region)
-
-- Use extractMethod to extract the marked line from the function
-
-- Use extractMethod to extract the lines of code from the method
-
-- Undo the extract Method
-
-- Undo the extract Function
-
-- Undo again - confirm that a dialog box pops up telling you the stack
-is empty.
-
-
-------------- Extract / Inline local variable ------------------
-
-- Load extractMethod.py into the ide
-
-- In the function 'inlineVariableTest', extract the marked code into a
-variable
-
-- Inline the variable back into the code
-
-----------------------------------------------------------------
-
-- exit from the ide, and delete scrap3.py from the directory
-
--- a/vim/sadness/bike/ide-integration/test/extractmethod.py Thu Feb 10 17:11:26 2011 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,16 +0,0 @@
-def myFunction():
- a = 3
- print "hello"+a # extract me
-
-class MyClass:
- def myMethod(self):
- b = 12 # extract me
- c = 3 # and me
- d = 2 # and me
- print b, c
-
-
-def inlineVariableTest():
- a = b + 3 - 5
- # --^^^^^ - Extract this into variable
-
--- a/vim/sadness/bike/ide-integration/test/scrap.py Thu Feb 10 17:11:26 2011 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,19 +0,0 @@
-class MyClass:
- def myMethod(self, foo):
- pass
-
-a = MyClass()
-
-a.myMethod()
-
-
-class AnotherClass:
- def myMethod(self,foo):
- pass
-
-def testFunction():
- print "hello"
-
-
-print "hello"
-
--- a/vim/sadness/bike/ide-integration/test/scrap2.py Thu Feb 10 17:11:26 2011 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,20 +0,0 @@
-from scrap import MyClass, testFunction
-
-b = MyClass()
-
-b.myMethod()
-
-
-c = abcde()
-
-c.myMethod()
-
-
-d = defgh()
-
-d.myMethod()
-
-
-e = MyClass()
-
-e.myMethod()
--- a/vim/sadness/bike/setup.py Thu Feb 10 17:11:26 2011 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,22 +0,0 @@
-#!/usr/bin/env python
-
-import sys
-import os,glob
-from distutils.core import setup
-
-# check version
-if sys.version_info[0] < 2 or sys.version_info[0] == 2 and sys.version_info[1] < 2:
- print "Python versions below 2.2 not supported"
- sys.exit(0)
-
-
-setup(name="bicyclerepair",
- version="0.9",
- description="Bicycle Repair Man, the Python refactoring tool",
- maintainer="Phil Dawes",
- maintainer_email="pdawes@users.sourceforge.net",
- url="http://bicyclerepair.sourceforge.net",
- packages=['','bike','bike.refactor','bike.parsing','bike.query','bike.transformer'],
- package_dir = {'bike':'bike','':'ide-integration'}
- )
-
--- a/vim/sadness/bike/testall.py Thu Feb 10 17:11:26 2011 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,27 +0,0 @@
-#!/usr/bin/env python
-
-import sys,os
-
-# check version
-if sys.version_info[0] < 2 or sys.version_info[0] == 2 and sys.version_info[1] < 2:
- print "Python versions below 2.2 not supported"
- sys.exit(0)
-
-if not os.path.abspath(".") in sys.path:
- sys.path.append(os.path.abspath("."))
-
-
-from bike import logging
-
-from bike.test_testutils import *
-from bike.parsing.testall import *
-from bike.query.testall import *
-from bike.refactor.testall import *
-from bike.testall import *
-
-if __name__ == "__main__":
- from bike import logging
- logging.init()
- log = logging.getLogger("bike")
- log.setLevel(logging.WARN)
- unittest.main()
--- a/vim/sadness/sadness.vim Thu Feb 10 17:11:26 2011 -0500
+++ b/vim/sadness/sadness.vim Thu Feb 17 15:23:03 2011 -0500
@@ -1,7 +1,4 @@
let $rope_pypath = $HOME."/.vim/sadness/ropevim/pylibs"
-let $bike_pypath = $HOME."/.vim/sadness/bike"
-let $PYTHONPATH = $rope_pypath.":".$bike_pypath.":".$PYTHONPATH
+let $PYTHONPATH = $rope_pypath.":".$PYTHONPATH
source $HOME/.vim/sadness/ropevim/src/ropevim/ropevim.vim
-
-source $HOME/.vim/sadness/bike/ide-integration/bike.vim
--- a/zsh/misc.zsh Thu Feb 10 17:11:26 2011 -0500
+++ b/zsh/misc.zsh Thu Feb 17 15:23:03 2011 -0500
@@ -63,3 +63,13 @@
# hgd
alias h='~/src/hgd/hd'
+
+# What the hell did I do the other day?
+function whatthehelldididoon() {
+ for repo in `find . -name '.hg'`
+ do
+ echo $repo
+ h .. -R $repo/.. -d "$1" -u 'Steve Losh'
+ done
+}
+