# HG changeset patch # User Steve Losh # Date 1286382646 14400 # Node ID 48cacfdc2ca62ceaad263558145c0dc48ebd6231 # Parent e3054449657554c6819c7cf6921ec40b6f456aa2 vim: add ropevim diff -r e30544496575 -r 48cacfdc2ca6 vim/.vimrc --- a/vim/.vimrc Fri Oct 01 00:08:20 2010 -0400 +++ b/vim/.vimrc Wed Oct 06 12:30:46 2010 -0400 @@ -252,6 +252,9 @@ map :TlistToggle map T :!/usr/local/bin/ctags -R . +" Rope +source $HOME/.vim/sadness/ropevim/rope.vim + if has('gui_running') set guifont=Menlo:h12 colorscheme molokai diff -r e30544496575 -r 48cacfdc2ca6 vim/sadness/ropevim/install_ropevim.sh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vim/sadness/ropevim/install_ropevim.sh Wed Oct 06 12:30:46 2010 -0400 @@ -0,0 +1,64 @@ +#!/bin/bash + +# Plant rope vim's plugin +# This is a script to install or update 'ropevim' +# Copyright Alexander Artemenko, 2008 +# Contact me at svetlyak.40wt at gmail com + +function create_dirs +{ + mkdir -p src + mkdir -p pylibs +} + +function check_vim +{ + if vim --version | grep '\-python[^3]' > /dev/null + then + echo You vim does not support python plugins. + echo Please, install vim with python support. + echo On debian or ubuntu you can do this: + echo " sudo apt-get install vim-python" + exit 1 + fi +} + +function get_or_update +{ + if [ -e $1 ] + then + cd $1 + echo Pulling updates from $2 + hg pull > /dev/null + cd .. + else + echo Cloning $2 + hg clone $2 $1 > /dev/null + fi +} + +function pull_sources +{ + cd src + get_or_update rope http://bitbucket.org/agr/rope + get_or_update ropevim http://bitbucket.org/agr/ropevim + get_or_update ropemode http://bitbucket.org/agr/ropemode + + cd ../pylibs + ln -f -s ../src/rope/rope + ln -f -s ../src/ropemode/ropemode + ln -f -s ../src/ropevim/ropevim.py + cd .. +} + +function gen_vim_config +{ + echo "let \$PYTHONPATH .= \":`pwd`/pylibs\"" > rope.vim + echo "source `pwd`/src/ropevim/ropevim.vim" >> rope.vim + echo "Now, just add \"source `pwd`/rope.vim\" to your .vimrc" +} + +check_vim +create_dirs +pull_sources +gen_vim_config diff -r e30544496575 -r 48cacfdc2ca6 vim/sadness/ropevim/pylibs/rope --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vim/sadness/ropevim/pylibs/rope Wed Oct 06 12:30:46 2010 -0400 @@ -0,0 +1,1 @@ +../src/rope/rope \ No newline at end of file diff -r e30544496575 -r 48cacfdc2ca6 vim/sadness/ropevim/pylibs/ropemode --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vim/sadness/ropevim/pylibs/ropemode Wed Oct 06 12:30:46 2010 -0400 @@ -0,0 +1,1 @@ +../src/ropemode/ropemode \ No newline at end of file diff -r e30544496575 -r 48cacfdc2ca6 vim/sadness/ropevim/pylibs/ropevim.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vim/sadness/ropevim/pylibs/ropevim.py Wed Oct 06 12:30:46 2010 -0400 @@ -0,0 +1,1 @@ +../src/ropevim/ropevim.py \ No newline at end of file diff -r e30544496575 -r 48cacfdc2ca6 vim/sadness/ropevim/rope.vim --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vim/sadness/ropevim/rope.vim Wed Oct 06 12:30:46 2010 -0400 @@ -0,0 +1,2 @@ +let $PYTHONPATH = "/Users/sjl/lib/dotfiles/vim/sadness/ropevim/pylibs:".$PYTHONPATH +source /Users/sjl/lib/dotfiles/vim/sadness/ropevim/src/ropevim/ropevim.vim diff -r e30544496575 -r 48cacfdc2ca6 vim/sadness/ropevim/src/rope/.hgignore --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vim/sadness/ropevim/src/rope/.hgignore Wed Oct 06 12:30:46 2010 -0400 @@ -0,0 +1,4 @@ +syntax: glob + +*.pyc +rope.egg-info diff -r e30544496575 -r 48cacfdc2ca6 vim/sadness/ropevim/src/rope/.hgtags --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vim/sadness/ropevim/src/rope/.hgtags Wed Oct 06 12:30:46 2010 -0400 @@ -0,0 +1,19 @@ +2b74d75e4f0a15e9a728e9642fd1a5dc50343544 0.7 +21d026b272052bf6e5798294409a6fc58dfe95fe 0.7.1 +dea8b62c2141d7459e67086efacb20cf422b5977 0.7.2 +edabbceda687af4ad93687e8d08c1e2d45a6181d 0.7.3 +c229ca17b51c169c11207ded55c05bae96b12a3e 0.7.4 +d05b87226c5410cd5427deaaa38f3e6d93bce272 0.7.5 +72c14e80687543b55aa38fc00538888212f6f11a 0.7.6 +ffcd014a92164f5df2206949fecce09ccb9bde9e 0.7.7 +ef7c349beeed1d763e545bce89754cb0154b837c 0.7.8 +b5ee6eb7f245e9713a5a1e45892ce9e5021680f8 0.7.9 +19960b1c3511de606ede66125edb487d299b4eac 0.8 +4b4db07361c5f09f5f3efd419bdb9cdfdac17b97 0.8.1 +31646f5ab763f85df9b01ba025f1475ca4db324a 0.8.2 +b77bd0f68d3eca884ea5001ec4f95c247eab40d2 0.8.3 +02b9af86ce327745783a21c140a609bc860a31bb 0.8.4 +5938069e8ca2ea309c0b23784806b2dc1d9b90cf 0.9 +62727f11b9666ccef926b5e4e6b849fff36e30e0 0.9.1 +a4a74d4469eb3f7f027bdd0cae64cf8143f52d94 0.9.2 +f8e015405cf4dfd0e4c8486f5e88505060bc458c 0.9.3 diff -r e30544496575 -r 48cacfdc2ca6 vim/sadness/ropevim/src/rope/CONTRIBUTORS --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vim/sadness/ropevim/src/rope/CONTRIBUTORS Wed Oct 06 12:30:46 2010 -0400 @@ -0,0 +1,14 @@ +=================== + Rope Contributors +=================== + +See Mercurial logs and the mailing list for details. + +* Alexander Solovyov +* Sebastjan Trepca +* MATSUI Tetsushi +* Kevin Turner +* Darren Syzling +* Orestis Markou +* Ronny Pfannschmidt +* Anton Gritsay diff -r e30544496575 -r 48cacfdc2ca6 vim/sadness/ropevim/src/rope/COPYING --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vim/sadness/ropevim/src/rope/COPYING Wed Oct 06 12:30:46 2010 -0400 @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + 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 of the License, 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., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. diff -r e30544496575 -r 48cacfdc2ca6 vim/sadness/ropevim/src/rope/MANIFEST.in --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vim/sadness/ropevim/src/rope/MANIFEST.in Wed Oct 06 12:30:46 2010 -0400 @@ -0,0 +1,4 @@ +include README.txt COPYING setup.py MANIFEST.in +recursive-include rope *.py +recursive-include docs *.txt +recursive-include ropetest *.py diff -r e30544496575 -r 48cacfdc2ca6 vim/sadness/ropevim/src/rope/README.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vim/sadness/ropevim/src/rope/README.txt Wed Oct 06 12:30:46 2010 -0400 @@ -0,0 +1,56 @@ +======================================== + rope, a python refactoring library ... +======================================== + + +Overview +======== + +`Rope`_ is a python refactoring library. + +.. _`rope`: http://rope.sf.net/ + + +New Features +============ + +* codeassist: better handling of unicode in docstrings +* codeassist: handling builtin unknowns, such as sys.stdout +* codeassist: proposals scopes and types revised +* fscommands: handle hg crew ui changes +* patchedast: handle ExtSlice node + +Getting Started +=============== + +* List of features: `docs/rope.txt`_ +* Overview of some of rope's features: `docs/overview.txt`_ +* Using as a library: `docs/library.txt`_ +* Contributing: `docs/contributing.txt`_ + +To change your project preferences edit +``$PROJECT_ROOT/.ropeproject/config.py`` where ``$PROJECT_ROOT`` is +the root folder of your project (this file is created the first time +you open a project). + + +Bug Reports +=========== + +Send your bug reports and feature requests to `rope-dev (at) +googlegroups.com`_. + +.. _`rope-dev (at) googlegroups.com`: http://groups.google.com/group/rope-dev + + +License +======= + +This program is under the terms of GPL (GNU General Public License). +Have a look at ``COPYING`` file for more information. + + +.. _`docs/rope.txt`: docs/rope.html +.. _`docs/overview.txt`: docs/overview.html +.. _`docs/contributing.txt`: docs/contributing.html +.. _`docs/library.txt`: docs/library.html diff -r e30544496575 -r 48cacfdc2ca6 vim/sadness/ropevim/src/rope/docs/contributing.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vim/sadness/ropevim/src/rope/docs/contributing.txt Wed Oct 06 12:30:46 2010 -0400 @@ -0,0 +1,101 @@ +====================== + Contributing to Rope +====================== + + +Get Involved! +============= + +Rope's main goal is being a good refactoring tool for python. It also +provides some IDE helpers. If you like to contribute, you're welcome! + + +How to Help Rope? +================= + +Rope mailing list is `rope-dev (at) googlegroups.com`_. You can send +a mail to ``rope-dev-subscribe (at) googlegroups [dot] com`` to +subscribe. + +* Use rope +* Send bug reports and request features +* Submit patches for bugs or new features +* Discuss your ideas + +.. _`rope-dev (at) googlegroups.com`: http://groups.google.com/group/rope-dev + + +Wish List +========= + +You are welcome to send your patches to `rope-dev (at) +googlegroups.com`_ mailing list. Here is only a list of suggestions. + +Issues +------ + +The `dev/issues.txt`_ file is actually the main rope todo file. There +is a section called "unresolved issues"; it contains almost every kind +of task. Most of them need some thought or discussion. Pickup +whichever you are most interested in. If you have ideas or questions +about them, don't hesitate to discuss it in the mailing list. + +.. _`dev/issues.txt`: dev/issues.html + +Getting Ready For Python 3.0 +---------------------------- + +Checkout http://bitbucket.org/agr/rope_py3k Mercurial_ repository. +Contributions are welcome. + +Write Plugins For Other IDEs +---------------------------- + +See ropemacs_, ropevim_, eric4_ and ropeide_. + + +.. _ropemacs: http://rope.sf.net/ropemacs.html +.. _ropevim: http://rope.sf.net/ropevim.html +.. _ropeide: http://rope.sf.net/ropeide.html +.. _eric4: http://www.die-offenbachs.de/eric/index.html + + +Rope Structure +============== + +Rope package structure: + +* `rope.base`: the base part of rope +* `rope.refactor`: refactorings and tools used in them +* `rope.contrib`: IDE helpers + +Have a look at ``__init__.py`` of these packages or `library.txt`_ for +more information. + +.. _`library.txt`: library.html + + +Source Repository +================= + +Rope uses Mercurial_ CMS: + +* Rope main branch: http://bitbucket.org/agr/rope +* Rope py3k branch: http://bitbucket.org/agr/rope_py3k + +.. _Mercurial: http://selenic.com/mercurial + + +Submitting patches +================== + +Patches are welcome. + +Patch style +----------- + +* Follow :PEP:`8`. +* Use four spaces for indentation. +* Include good unit-tests if possible. +* Rope test suite should pass after patching +* Use ``hg export`` format to preserve your identity diff -r e30544496575 -r 48cacfdc2ca6 vim/sadness/ropevim/src/rope/docs/dev/issues.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vim/sadness/ropevim/src/rope/docs/dev/issues.txt Wed Oct 06 12:30:46 2010 -0400 @@ -0,0 +1,156 @@ +============= + Rope Issues +============= + + +Unresolved Issues +================= + +* purging out less accurate callinfos when better ones appear? +* using properties without calling its get? +* global variable inlines +* transform and extension modules +* merging extract and usefunction +* caching instances of PyObject +* moving a group of elements together +* temps might be read after body in usefunction or extract +* usefunction and function returns +* usefunction on methods +* extracted functions should be inserted before using class bodies +* adding "referenced later" wildcard argument to restructurings? +* adding "change references" wildcard argument to restructurings? +* ideas for more custom wildcards +* adapting future python 2.6 ast changes +* custom wildcards and recursive patterns +* custom restructuring wildcard patterns and replacements +* not reimporting back imports after moving +* importing compressed objectdb/history data? +* not applying all commenting mechanisms always in codeassist +* fixing try blocks before current line in code_assist +* better tests for patchedast +* import actions with more that one phase and filtering problems +* handle long imports should work on filtered imports unconditionally? +* extracting subexpressions; look at `extracttest` for more info +* switching to gplv3? +* unignored files that are not under version control +* inline fails when there is an arg mismatch +* evaluate function parameter defaults in staticoi? +* saving diffs instead of old contents in ChangeContents? +* handling tuple parameters +* extract class +* analyzing function decorators +* generate ... and implicit interfaces +* generate method and class hierarchies +* lambdas as functions; consider their parameters +* renaming similarly named variables +* handling the return type of ``yield`` keyword +* not writing unchanged objectdb and history? + + +To Be Reviewed +============== + +* review patchedast; make it faster +* lots of estimations in codeanalyze in WordRangeFinder +* review objectdb modules +* how concluded data are held for star imports + + +Insert Before In Restructurings +=============================== + +Consider a restructuring like this:: + + pattern: ${a} if ${b} else ${c} + goal: replacement + before: if ${b}:\n replacement = ${a}\nelse:\n replacement = ${c} + + +Memory Management +================= + +These are the places in which rope spends most of the memory it +consumes: + +* PyCore: for storing PyModules +* ObjectInfo: for storing object information +* History: for storing changes + +We should measure the amount of memory each of them use to make +decisions. + + +Custom Restructuring Wildcards +============================== + +There is a need to add more custom wildcards in restructuring +patterns. But adding all such needs to `similarfinder` module makes +it really complex. So I think adding the ability to extend them is +useful. + +Sometimes wildcards can be customized. For instance one might want to +match the function calls only if ``p1`` is passed in the arguments. +They can be specified in wildcard arguments. + +Since matched wildcards can appear in the goal pattern, each wildcard +should have a corresponding replacement wildcard. Each replacement +might be customized in each place it appears; for instance +``${mycall:-p1}`` might mean to remove ``p1`` argument. + + +Wildcard Format +--------------- + +All wildcards should appear as ``${name}``. The type of wildcards and +their parameters can be specified using the ``args`` argument of +``Restructuring()``. + +Ideas: + +* Maybe we can put checks inside args, too:: + + pattern: ${project:type=rope.base.project.Project}.pycore + + But what should be done when a variable appears twice:: + + pattern: ${a:type=__builtin__.int} + ${a} + + +Examples +-------- + +.. ... + + +Possible Module Renamings +========================= + +*First level*: + +These module names are somehow inconsistent. + +* change -> changes +* method_object -> methodobject +* default_config -> defaultconfig + +*Second level* + +Many modules use long names. They can be shortened without loss of +readability. + +* methodobject -> methobj or funcobj +* usefunction -> usefunc +* multiproject -> mulprj +* functionutils -> funcutils +* importutils -> imputils +* introduce_factory -> factory +* change_signature -> signature +* encapsulate_field -> encapsulate +* sourceutils -> srcutils +* resourceobserver -> observer + + +Getting Ready For Python 3.0 +============================ + +This has been moved to a separate branch. diff -r e30544496575 -r 48cacfdc2ca6 vim/sadness/ropevim/src/rope/docs/dev/todo.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vim/sadness/ropevim/src/rope/docs/dev/todo.txt Wed Oct 06 12:30:46 2010 -0400 @@ -0,0 +1,8 @@ +====== + TODO +====== + +See the `unresolved issues` section of ``issues.txt`` file for more. + + +> Public Release 1.0 diff -r e30544496575 -r 48cacfdc2ca6 vim/sadness/ropevim/src/rope/docs/done.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vim/sadness/ropevim/src/rope/docs/done.txt Wed Oct 06 12:30:46 2010 -0400 @@ -0,0 +1,1105 @@ +=========== + Done List +=========== + + +> Public Release 0.9.3 : February 4, 2010 + + +- codeassist: proposals scopes and types revised : January 26, 2010 + + +- codeassist: handling "builtin unknowns" : January 06, 2010 + + +- refactor: fixed arguments in extracted method : December 26, 2009 + + +- pycore: fixed project's property `source_folders` : October 26, 2009 + + +- codeassist: better handling of unicode docstrings : August 20, 2009 + + +- setup.py: don't include docs as package data : July 18, 2009 + + +- fscommands: handle hg crew ui changes : May 04, 2009 + + +- patchedast: handle ExtSlice node : April 29, 2009 + + +> Public Release 0.9.2 : February 19, 2009 + + +- caching all sub-modules in `autoimport` : February 18 : 2009 + + +- extract method handles conditional variable updates : February 10, 2009 + + +- added basic support for setuptools : January 15, 2009 + + +- added `CompletionProposal.parameters` : November 4, 2008 + + +- fix recursion when creating modules : October 31, 2008 + + +> Public Release 0.9.1 : October 29, 2008 + + +- added import_dynload_stdmods project variable : October 28, 2008 + + +- finding dynload standard modules on windows : October 15, 2008 + + +> Public Release 0.9 : October 3, 2008 + + +- supporting Darcs VCS : August 20, 2008 + + +- handling files with mac line-ending : July 25, 2008 + + +- not searching all files when inlining a local variable : July 24, 2008 + + +> Public Release 0.8.4 : June 24, 2008 + + +- handling only_current for inline in other modules : July 21, 2008 + + +- inlining variable in other modules : July 19, 2008 + + +- added `rope.contrib.finderrors` : July 17, 2008 + + +- added `rope.contrib.fixmodnames` : July 16, 2008 + + +- added `rope.contrib.changestack` : July 15, 2008 + + +- better extension module handling : June 29, 2008 + + +- added `findit.Location.region` field : June 26, 2008 + + +- added `rope.contrib.findit.find_definition()` : June 26, 2008 + + +- added ``remove_self`` argument to `get_calltip()` : June 20, 2008 + + +> Public Release 0.8.3 : June 20, 2008 + + +- handling builtin modules in autoimport : June 12, 2008 + + +- creating parent folders of ``.ropeproject`` if don't exist : June 6, 2008 + + +- fixed inlining functions with line-breaks in arguments : May 22, 2008 + + +- added lineno to `rope.contrib.findit.Location` : May 19, 2008 + + +- deprecated some of `ChangeSignature` methods : May 19, 2008 + + +- added `ChangeSignature.get_args()` : May 19, 2008 + + +> Public Release 0.8.2 : May 10, 2008 + + +- inlining parameters : May 10, 2008 + + +- automatic default insertion in change signature : May 10, 2008 + + +- adding underlined parameter to `AutoImport` : May 7, 2008 + + +- added `rope.contrib.findit.find_implementations()` : April 28, 2008 + + +- moved `find_occurrences()` to `rope.contrib.findit` : April 25, 2008 + + +> Public Release 0.8.1 : April 20, 2008 + + +- added GIT support in fscommands : April 19, 2008 + + +- back importing underlined names in move : April 19, 2008 + + +- added `codeassist.get_calltip()` : April 12, 2008 + + +- added `libutils.analyze_modules()` : April 12, 2008 + + +- added ``soa_followed_calls`` project config : April 11, 2008 + + +- `libutils.report_change()` reads `automatic_soa` : April 10, 2008 + + +- SOA can follow functions : April 10, 2008 + + +- better handling of for, with and except variables : April 7, 2008 + + +- not reparsing unchanged modules for code assists : April 6, 2008 + + +- handling property as decorator : April 5, 2008 + + +> Public Release 0.8 : April 5, 2008 + + +- ignore_bad_imports project config : March 28, 2008 + + +- added AutoImport.get_name_locations() : March 17, 2008 + + +> Public Release 0.7.9 : March 14, 2008 + + +- Deprecated codeassist templates : March 14, 2008 + + +- Added in_hierarchy option to find occurrences : March 10, 2008 + + +- Faster class hierarchy analysis for refactorings : March 10, 2008 + + +- Added maxfixes to get doc and get definition location : March 6, 2008 + + +- Added extension_modules project config : March 6, 2008 + + +- Supporting builtin and c-extension modules : March 6, 2008 + + +> Public Release 0.7.8 : March 1, 2008 + + +- Extracting functions with only one return statement : February 29, 2008 + + +- Reporting errors for exceptional conditions in usefunction : February 29, 2008 + + +- More intelligent import handling for factory and move : February 25, 2008 + + +- Handling future imports in organize imports : February 20, 2008 + + +- Codeanalyze ignores comments when finding primaries : February 17, 2008 + + +- Organize import and dynload builtin modules on unix : February 16, 2008 + + +- Moved ImportOrganizer to rope.refactor.importutils : February 14, 2008 + + +- Moved ModuleToPackage to rope.refactor.topackage : February 14, 2008 + + +> Public Release 0.7.7 : February 13, 2008 + + +- Added python_files project config : February 10, 2008 + + +- Added codeassist.starting_expression() : February 10, 2008 + + +- Added AutoImport.clear_cache() : February 7, 2008 + + +- Improved extract function : February 1, 2008 + + +- Handling except variables : January 29, 2008 + + +> Public Release 0.7.6 : January 28, 2008 + + +- Handling unsure matches in restructurings : January 27, 2008 + + +- Added rope.contrib.autoimport : January 26, 2008 + + +- Added use function refactoring : January 25, 2008 + + +- Completing names after from-imports : January 23, 2008 + + +- Adding resources parameter to some refactorings : January 22, 2008 + + +- Deprecated in_file argument of `Rename.get_changes()` : January 22, 2008 + + +> Public Release 0.7.5 : January 17, 2008 + + +- Checking isinstance in restructurings : January 11, 2008 + + +- Better handling of one-liners : January 10, 2008 + + +- Choosing which files to apply a restructuring on : January 9, 2008 + + +- Allowing customizable restructuring wildcards : January 7, 2008 + + +> Public Release 0.7.4 : January 3, 2008 + + +- Deprecated objectdb_type project config : December 23, 2007 + + +- Added save_objectdb config : December 23, 2007 + + +- Added compress_history and compress_objectdb configs : December 22, 2007 + + +> Public Release 0.7.3 : December 19, 2007 + + +- Inlining a single occurrence : December 13, 2007 + + +- Global extract method/variable : December 13, 2007 + + +> Public Release 0.7.2 : December 13, 2007 + + +- Specifying the number of fixes in code_assist : December 10, 2007 + + +- Deprecated `Pycore.create_(module|package)` : November 29, 2007 + + +- Performing refactorings across multiple projects : November 29, 2007 + + +> Public Release 0.7.1 : November 28, 2007 + + +- Better handling of symlinks in project path : November 27, 2007 + + +- Asking the user about unsure occurrences : November 10, 2007 + + +> Public Release 0.7 : November 1, 2007 + + +- ropemacs: moving elements, methods and modules : October 30, 2007 + + +- ropemacs: undoing refactorings : October 29, 2007 + + +- ropemacs: inline refactoring : October 29, 2007 + + +- ropemacs: extract method and local variable : October 29, 2007 + + +- ropemacs: goto definition : October 29, 2007 + + +- ropemacs: rename refactoring : October 29, 2007 + + +- A new open project dialog : October 10, 2007 + + +- Added `Core.add_extension()` : September 19, 2007 + + +> Public Release 0.6.2 : September 9, 2007 + + +- Setting statusbar, menu and bufferlist fonts in ``~/.rope`` : September 8, 2007 + + +- Better kill line : September 8, 2007 + + +- Using ``/``\s to match parent folders in find file : September 5, 2007 + + +- Fixed matching method implicit argument when extracting : September 5, 2007 + + +- An option for not removing the definition after inlining : September 1, 2007 + + +- Performing import actions on individual imports : September 1, 2007 + + +- ``C-u`` action prefix : September 1, 2007 + + +- Changing inline and move to use froms for back imports : August 27, 2007 + + +> Public Release 0.6.1 : August 19, 2007 + + +- Cleaning up `rope.ide.codeassist` : August 19, 2007 + + +- Showing unsure occurrences in show occurrences : August 17, 2007 + + +- Sorting scopes : August 9, 2007 + + +> Public Release 0.6 : August 5, 2007 + + +- Finding the scope in an overwritten scope : August 4, 2007 + + +- Added ``ignore_syntax_errors`` project config : August 2, 2007 + + +> Public Release 0.6m6 : July 29, 2007 + + +- Better diff highlighting : July 20, 2007 + + +- Handling imports when inlining : July 20, 2007 + + +- Handling recursive restructurings : July 18, 2007 + + +> Public Release 0.6m5 : July 15, 2007 + + +- Next/prev scope; ``M-C-e/M-C-a`` : July 9, 2007 + + +- Next/prev statement; ``M-e/M-a`` : July 8, 2007 + + +- Importing modules in restructurings : July 7, 2007 + + +- Auto-indentation in restructurings : July 6, 2007 + + +> Public Release 0.6m4 : July 1, 2007 + + +- Adding tools for making using rope library easier : June 23, 2007 + + +- Separating rope library from rope IDE : June 20, 2007 + + +- Restructuring checks for builtin objects using `__builtin__` : June 20, 2007 + + +> Public Release 0.6m3 : June 17, 2007 + + +- Self assignment warning : June 17, 2007 + + +- Adding support for Mercurial VCS : June 17, 2007 + + +- Inferring the object, list comprehensions hold : June 6, 2007 + + +> Public Release 0.6m2 : June 3, 2007 + + +- Enhancing extract method on staticmethods/classmethods : June 2, 2007 + + +- Extracting similar expressions/statements : May 30, 2007 + + +- Adding checks in restructuring dialog : May 23, 2007 + + +- Using `_ast` instead of `compiler` : May 23, 2007 + + +> Public Release 0.6m1 : May 20, 2007 + + +- Adding custom source folders in ``config.py`` : May 15, 2007 + + +- A simple UI for performing restructurings : May 15, 2007 + + +- Restructurings : May 14, 2007 + + +- Finding similar code : May 13, 2007 + + +- Patching ASTs to include formatting information : May 9, 2007 + + +> Public Release 0.5 : May 6, 2007 + + +- Better dialogs : May 2, 2007 + + +> Public Release 0.5rc1 : April 29, 2007 + + +- Showing current file history; ``C-x p 1 h`` : April 28, 2007 + + +- Open Type; ``C-x C-t`` : April 23, 2007 + + +- Adding persisted_memory objectdb : April 20, 2007 + + +- Adding sqlite objectdb : April 20, 2007 + + +> Public Release 0.5m5 : April 15, 2007 + + +- Encapsulating field in the defining class : April 13, 2007 + + +- Renaming occurrences in strings and comments : April 13, 2007 + + +- Stoppable refactorings : April 11, 2007 + + +- Faster automatic SOI analysis : April 9, 2007 + + +- Basic implicit interfaces : April 9, 2007 + + +- Automatic SOI analysis : April 6, 2007 + + +- Using a better object textual form : April 4, 2007 + + +- Spell-Checker : April 3, 2007 + + +> Public Release 0.5m4 : April 1, 2007 + + +- Incremental ObjectDB validation : March 31, 2007 + + +- Saving history across sessions : March 29, 2007 + + +- Saving object data to disk : March 28, 2007 + + +- Adding `.ropeproject` folder : Mark 26, 2007 + + +- Inlining `staticmethod`\s : March 23, 2007 + + +- Saving locations and texts : March 23, 2007 + + +- Generating python elements : March 21, 2007 + + +> Public Release 0.5m3 : March 18, 2007 + + +- Holding per name information for builtin containers : March 17, 2007 + + +- Filling paragraphs in text modes; ``M-q`` : March 15, 2007 + + +- Yanking; ``M-y`` : March 13, 2007 + + +- Repeating last command; ``C-x z`` : March 13, 2007 + + +- Adding 'rename when unsure' option : March 13, 2007 + + +- Change signature for constructors : March 11, 2007 + + +- Supporting generator functions : March 9, 2007 + + +- Enhancing show pydoc to include docs from superclasses : March 8, 2007 + + +- Enhanced returned object static object inference : March 8, 2007 + + +- Enhanced static object inference : March 8, 2007 + + +- Handling ``*args`` and ``**kwds`` arguments : March 7, 2007 + + +- Showing pydoc for some of builtin types and functions : March 7, 2007 + + +> Public Release 0.5m2 : March 4, 2007 + + +- Showing codetag/error/warning list : March 3, 2007 + + +- Registering templates in ``~/.rope`` : February 26, 2007 + + +- Auto-completing function keyword arguments when calling : February 26, 2007 + + +- Better status bar : February 23, 2007 + + +- Change occurrences : February 23, 2007 + + +- Moving methods : February 21, 2007 + + +> Public Release 0.5m1 : February 18, 2007 + + +- Handling ``with`` statements : February 15, 2007 + + +- Performing change signature in class hierarchies : February 14, 2007 + + +- Supporting builtin `zip` and `enumerate` : February 14, 2007 + + +- Replace method with method object : February 12, 2007 + + +- Enhancing searching : February 10, 2007 + + +- Execute command; ``M-x`` : February 10, 2007 + + +- Changing editor font and keybinding in ``~/.rope`` : February 9, 2007 + + +- Having two keybindings emacs/normal : February 9, 2007 + + +- Handling multi-key keyboard shortcuts : February 8, 2007 + + +- Fixing removing imports that eat the blank lines : February 8, 2007 + + +- Removing extra spaces and lines; ``C-c C-f`` : February 7, 2007 + + +> Public Release 0.4 : February 4, 2007 + + +- Reporting some of the refactoring problems in the UI : February 1, 2007 + + +> Public Release 0.4rc1 : January 28, 2007 + + +- Project History; Undoing refactorings in any order : January 25, 2007 + + +- Handling ``global`` keywords : January 22, 2007 + + +- Undoing everything; Project history : January 21, 2007 + + +- Removing `PythonRefactoring` facade : January 19, 2007 + + +- Basic lambdas handling : January 16, 2007 + + +- Handling builtin `property` : January 14, 2007 + + +> Public Release 0.4m5 : January 14, 2007 + + +- Handling long imports : January 11, 2007 + + +- Builtin functions : super, sorted, reversed, range : January 7, 2007 + + +- Support for file/open builtin type : January 7, 2007 + + +- Sorting imports; standard, third party, project : January 7, 2007 + + +- Enhanced dynamic object inference : January 5, 2007 + + +> Public Release 0.4m4 : December 31, 2006 + + +- Basic support for builtin types : December 29, 2006 + + +- Find occurrences; ``C-G`` : December 26, 2006 + + +- Ignoring ``*.pyc``, ``*~`` and ``.svn`` : December 26, 2006 + + +- Moving/renaming current module/package : December 25, 2006 + + +- Removing imports from the same module : December 22, 2006 + + +- Goto last edit location; ``C-q`` : December 20, 2006 + + +- Trying ``utf-8`` if defaults don't work : December 19, 2006 + + +- Comment line and region; ``C-c c``, ``C-c C-c`` : December 18, 2006 + + +> Public Release 0.4m3 : December 17, 2006 + + +- Introduce parameter : December 14, 2006 + + +- 8 spaces per tabs in `rope.base` and `rope.refactor` : December 8, 2006 + + +- Better support for other version control systems : December 8, 2006 + + +- Updating files that have been changed : December 8, 2006 + + +- Fixing module running on Windows : December 6, 2006 + + +> Public Release 0.4m2 : December 3, 2006 + + +- Change method signature : December 1, 2006 + + +- Change method signature dialog : November 30, 2006 + + +- Reordering parameters : November 28, 2006 + + +- Removing parameters : November 26, 2006 + + +- Inline parameter default value : November 26, 2006 + + +- Adding parameters : November 26, 2006 + + +- Normalizing function calls : November 26, 2006 + + +> Public Release 0.4m1 : November 19, 2006 + + +- Better help menu : November 15, 2006 + + +- Inline method refactoring : November 10, 2006 + + +> Public Release 0.3 : November 5, 2006 + + +- Better code assist proposal sorting and dialog : November 3, 2006 + + +- Extract method works with normal selection : October 31, 2006 + + +- Basic python file encoding support : October 31, 2006 + + +> Public Release 0.3rc1 : October 29, 2006 + + +- Unit-test running view : October 28, 2006 + + +- Previewing refactoring changes : October 25, 2006 + + +- Encapsulate field : October 19, 2006 + + +- Convert local variable to field refactoring : October 18, 2006 + + +> Public Release 0.3m5 : October 15, 2006 + + +- Code completions inside uncompleted ``try`` blocks : October 7, 2006 + + +- Single line extract method and variable : October 7, 2006 + + +- Hiding unappropriate menu items in different contexts : October 6, 2006 + + +- Inline local variable : October 5, 2006 + + +- Rename function parameters : October 5, 2006 + + +- Move a module or package to another package : October 4, 2006 + + +> Public Release 0.3m4 : October 1, 2006 + + +- Showing function signature in show doc : September 29, 2006 + + +- Goto line : September 29, 2006 + + +- Move refactoring for global class/function : September 29, 2006 + + +- Change relative imports to absolute : September 28, 2006 + + +- Changing from imports to normal imports : September 28, 2006 + + +- Removing duplicate imports : September 27, 2006 + + +- Expanding from-star-imports : September 27, 2006 + + +- Removing unused imports : September 27, 2006 + + +- Introduce factory method refactoring : September 25, 2006 + + +- Basic import tools : September 21, 2006 + + +- Separating concluded and structural data in `PyModule`\s : September 19, 2006 + + +> Public Release 0.3m3 : September 17, 2006 + + +- Basic subversion support using pysvn : September 14, 2006 + + +- Renaming methods in class hierarchy : September 12, 2006 + + +- Transform module to package refactoring : September 11, 2006 + + +> Public Release 0.3m2 : September 3, 2006 + + +- Better New ... Dialogs : September 2, 2006 + + +- Function argument dynamic object inference : September 2, 2006 + + +- Basic dynamic type inference : September 2, 2006 + + +- Better menus : August 27, 2006 + + +- Relative imports : August 23, 2006 + + +- Read ``__init__.py`` of packages : August 23, 2006 + + +- Extract function : August 22, 2006 + + +> Public Release 0.3m1 : August 20, 2006 + + +- Undoing refactorings : August 19, 2006 + + +- Making module dependancy graph : August 19, 2006 + + +- Rename modules/packages : August 18, 2006 + + +- Reloading changed editors after refactorings : August 17, 2006 + + +- Rename class/function : August 17, 2006 + + +- Function return object static type inference : August 15, 2006 + + +- Show PyDoc : August 15, 2006 + + +- Object inference for chained assignments : August 14, 2006 + + +> Public Release 0.2 : August 6, 2006 + + +- Resource tree view : August 5, 2006 + + +- Handle ``HTTPClient`` style names in go to next/prev word : August 2, 2006 + + +> Public Release 0.2RC : July 30, 2006 + + +- Asking whether to save modified buffers when exiting : July 29, 2006 + + +- Extending menus : July 25, 2006 + + +- ReST highlighting : July 24, 2006 + + +- Showing editor modified status : July 23, 2006 + + +- Sorting code assist proposals : July 22, 2006 + + +- Not renaming names in strings and comments in refactorings : July 22, 2006 + + +- Separating entering and correcting indentation : July 22, 2006 + + +> Public Release 0.2pre5 : July 16, 2006 + + +- Out of project modules : July 15, 2006 + + +- Handle circular from-imports : July 14, 2006 + + +- Completeing ``AClass(param).a_`` : July 11, 2006 + + +- We know the type of ``var = AClass()`` : July 4, 2006 + + +- Rename function parameter in the function : July 3, 2006 + + +> Public Release 0.2pre4 : July 2, 2006 + + +- Rename local variable : July 2, 2006 + + +- Complete as you type : July 2, 2006 + + +- Show quick outline; C-o : June 23, 2006 + + +- Go to definition; F3 : June 22, 2006 + + +> Public release 0.2pre3 : June 18, 2006 + + +- Auto-completing "self."s : June 13, 2006 + + +- Proposing base class attributes : June 12, 2006 + + +- Auto completion after "."s : June 8, 2006 + + +> Public Release 0.2pre2 : June 4, 2006 + + +- Next/prev word stops at underlines and capitals : May 29, 2006 + + +- Ignoring string and comment contents while indenting : May 29, 2006 + + +- Proposing templates in code-assist proposals : May 26, 2006 + + +- Auto-complete from-import imported objects : May 25, 2006 + + +- Not proposing variables which are not defined yet : May 23, 2006 + + +- Auto-completion should ignore current statement : May 23, 2006 + + +- Proposing function parameters in functions : May 22, 2006 + + +- Auto-complete local variable names : May 22, 2006 + + +> Public Release 0.2pre1 : May 20, 2006 + + +- Auto completing keywords and builtins : May 19, 2006 + + +- Auto-complete imported objects : May 19, 2006 + + +- Show searching status in the status bar : May 18, 2006 + + +- Auto-complete class and function names : May 16, 2006 + + +- Auto-complete global variables : May 14, 2006 + + +> Public Release 0.1 : May 8, 2006 + + +- Separating indenting and correcting indentation : May 7, 2006 + + +- Enhancing editor and indentation : May 4, 2006 + + - Pressing backspace should deindent + - Clearing undo list when opening a file; undoSeparator when saving + + +- Showing current line in status bar : April 28, 2006 + + +- Switch editor dialog; C-x b and C-F6 : April 27, 2006 + + +- Make new package dialog : April 25, 2006 + + +- Make new module dialog : April 25, 2006 + + +> Public Release 0.1pre : April 22, 2006 + + +- Extending syntax highlighted elements : April 22, 2006 + + +- Auto indentation; C-i : April 20, 2006 + + +- Basic searching; C-s : April 12, 2006 + + +> SF registration : April 10, 2006 + + +- Multiple buffers : April 8, 2006 + The editor should have a notebook view. + + +- Enhancing dialogs : April 7, 2006 + Using tkMessageBox, tkFileDialog, tkSimpleDialog, ScrolledText + + +- Running modules : April 6, 2006 + You should add the required directories to the python path. + + +- Guessing source folders in the project : April 5, 2006 + + +- Finding a file in a project : April 4, 2006 + + +- Highlighting keywords : March 21, 2006 + Only python files(``*.py``) should be highlighted. diff -r e30544496575 -r 48cacfdc2ca6 vim/sadness/ropevim/src/rope/docs/library.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vim/sadness/ropevim/src/rope/docs/library.txt Wed Oct 06 12:30:46 2010 -0400 @@ -0,0 +1,732 @@ +========================= + Using Rope As A Library +========================= + +If you need other features, send a feature request. Have a look at +`contributing.txt`_. + + +.. contents:: Table of Contents + + +Quick Start +=========== + +This section will help you get started as soon as possible. + + +Making A Project +---------------- + +The first thing you should do is to make a project:: + + import rope.base.project + + + myproject = rope.base.project.Project('/path/to/myproject') + +It's good to know that: + +* A project is a folder in the file-system. +* It can contain anything. +* Rope searches for python modules and packages inside a project when + needed. +* Refactorings only change files and folders inside the project that + has been passed to them. +* Out of project modules that are imported from a module inside a + project are handled but never changed by refactorings. +* Rope makes a rope folder inside projects. By default the name of + this folder is ``.ropeproject`` but that can be changed using the + constructor's `ropefolder` parameter (passing `None` will prevent + rope from making this folder). +* Rope uses ``.ropeproject`` folder for things like saving object + information and loading project configurations. +* Project preferences can be configured by passing options to the + constructor or in ``.ropeproject/config.py``. See the default + ``config.py``, `rope.base.default_config` module, for more + information. +* All configurations that are available in the ``config.py`` file can + be specified as keyword parameters to `Project` constructor. These + parameters override the ones in the ``config.py`` file. +* Each project has a set of ignored resource patterns; You can use it + to tell rope to ignore files and folders matching certain patterns. +* The ``.ropeproject`` folder can be safely copied in other clones of + a project if you don't want to lose your objectdb and history. + + +Library Utilities +----------------- + +The `rope.base.libutils` module provides tools for making using rope +as a library easier. We'll talk more about this module later. + + +What Are These `Resource`\s? +---------------------------- + +In rope, files and folders in a project are accessed through +`rope.base.resources.Resource` objects. It has two subclasses `File` +and `Folder`. What we care about is that refactorings and `Change`\s +(we'll talk about them later) use resources. + +In order to create a `Resource` for a path in a project we have two +options. The first approach uses the `Project` object (use +`Project.get_resource()`_ method). I prefer to describe the second +approach since it needs less to know. + +We can use `libutils` module. It has a function named +`path_to_resource()`. It takes a project and a path:: + + from rope.base import libutils + + myresource = libutils.path_to_resource(myproject, '/path/to/resource') + + +But this is only half of the answer. Consider we have a resource. +How can we know anything about it? The answer is to use its ``path`` +and ``real_path`` fields. `Resource.real_path` is the absolute path +of the resource in the file-system. `Resource.path` field contains +the address of a resource relative to project root (the same format as +needed by `Project.get_resource()`_). + + +Performing Refactorings +----------------------- + +There are examples at the end of this document. But as another +example we'll extract a variable in a file. First we need the +`Resource` object that points to a file in a project:: + + resource = libutils.path_to_resource(myproject, '/path/to/my/module.py') + +So we can make our Refactoring class:: + + from rope.refactor.extract import ExtractVariable + + + extractor = ExtractVariable(myproject, resource, start, end) + +Where `start` and `end` are the offsets of the region to extract in +resource. Be careful when calculating the offsets. Dos line-endings +and multi-byte characters are considered to be only one character. +This is actually easier for IDEs, since most GUI libraries do that +when calculating offsets. + +Next, IDE's usually pop up a dialog for letting the user configure +refactoring options like the name of the extracted variable. + +After that, we can calculate the changes:: + + changes = extractor.get_changes('extracted_variable') + +`changes` holds the changes this refactoring makes. Calculating it +might be time consuming; See `rope.base.taskhandle.TaskHandle`_ +section for measuring its progress or interrupting it. + + +Previewing And Performing Changes +--------------------------------- + +As mentioned in the last section each refactoring returns a +`rope.base.change.Change` object. Now how can we know what it +contains and how to perform it? + +*Previewing*: + +``str(changes)`` returns a short description of the changes. You can +use ``changes.get_description()`` to get a preview; it is useful when +you don't care much about the format. Otherwise you can use the +``changes`` object directly. See the documentation in +`rope.base.change` module. + +*Performing*: + +The easiest way for performing the refactoring is to use +`Project.do()`_ method:: + + myproject.do(changes) + +If you want to perform the changes yourself, you have two options. +Note that the main reason for performing the changes manually is +handling version control systems that are not supported by rope. + +The first approach is to use `rope.base.fscommands`_. See `Writing A +FileSystemCommands`_ section. The changes can be performed as before +using `Project.do()`. + +The other is to perform the changes manually based on the returned +`changes` object (again see the documentation in `rope.base.change` +module). If this approach is used you cannot undo the refactoring +using ``project.history.undo()``. + +*Updating Open Buffers In IDEs*: + +Usually editors need to reload the files changed by rope. You can use +``Change.get_changed_resources()`` to get the list of resources that +need to be reloaded. + + +Validating The Project +---------------------- + +When using rope as a library, you probably change the files in it in +parallel (for example in IDEs). To force rope to invalidate cached +information about resources that have been removed or changed outside +rope you should call `Project.validate()`_ method. You can pass a +resource to this method. For example:: + + myproject.validate() + +validates all files and directories in the project. So call this +function every time you want use rope (before performing refactorings, +for instance). + + +Activating Static Object Analysis +--------------------------------- + +One of the greatest strengths of rope is its static object analysis, +SOA. You can perform SOA on a module using `PyCore.analyze_module()` +method but performing SOA on a module is not cheap. So I decided that +the best time for performing SOA is when saving files and only +performing it on changed scopes. + +But since rope is not notified about the changes the IDE performs, you +should tell rope about the change. You can do so by using +`rope.base.libutils.report_change()`. That is, whenever you want to +change a module you can do something like:: + + # Do the actual writing + old_contents = read(path) + write(path, new_content) + + # Inform rope about the change + libutils.report_change(myproject, path, old_contents) + +Where `read` and `write` stand for methods used for reading and +writing files. + + +Closing The Project +------------------- + +`Project.close()`_ closes project open resources. Always call this +function when you don't need a project anymore:: + + myproject.close() + + +`rope.base.project.Project` +=========================== + +You can create a project by:: + + project = Project(root_address) + +Where the `root_address` is the root folder of your project. + +A project has some useful fields. `Project.address` is the address of +the root folder of a project. `Project.root` is a `Folder` object +that points to that folder. + + +`Project.get_resource()` +------------------------ + +You can use this method for getting a resource (that is file or +folder) inside a project. Uses ``'/'``s for separating directories. +For instance ``project.get_resource('my_folder/my_file.txt')`` returns +a `rope.base.resources.File` object that points to +``${projectroot}/my_folder/my_file.txt`` file. + +Note that this method assumes the resource exists. If it does not +exist you can use `Project.get_file()` and `Project.get_folder()` +methods. + + +`Project.do()` +-------------- + +For committing changes returned by refactorings. + + +`Project.history` +----------------- + +A `rope.base.history.History` object. You can use its `undo` and +`redo` methods for undoing or redoing changes. Note that you can use +it only if you have committed your changes using rope. + + +`Project.validate()` +-------------------- + +When using rope as a library you probably change the files in that +project in parallel (for example in IDEs). To force rope to +invalidate cached information about resources that have been +removed or changed outside rope you should call `Project.validate`. +You should pass a resource to this method. For example:: + + project.validate(project.root) + +validates all files and directories in the project. + + +`Project.close()` +----------------- + +Closes project open resources. Always call this function when you +don't need a project anymore. Currently it closes the files used for +storing object information and project history. Since some parts of +these files are in memory for efficiency not closing a project might +put them in an inconsistent state. + + +`rope.base.fscommands` +---------------------- + +The `rope.base.fscommands` module implements the basic file system +operations that rope needs to perform. The main reason for the +existence of this module is supporting version control systems. Have +a look at `FileSystemCommands` and `SubversionCommands` in the same +module. If you need other version control systems you can write a new +class that provides this interface. `rope.base.project.Project` +accepts a ``fscommands`` argument. You can use this argument to force +rope to use your new class. + + +``.ropeproject`` Folder +----------------------- + +From version ``0.5``, rope makes a ``.ropeproject`` folder in the +project by default for saving project configurations and data. The +name of this folder is passed to the constructor if you want to change +that. Also you can force rope not to make such a folder by passing +`None`. + +If such a folder exists rope loads the ``config.py`` file in that +folder. It might also use it for storing object information and +history. + + +`rope.base.pycore.PyCore` +========================= + +Provides useful methods for managing python modules and packages. +Each project has a `PyCore` that can be accessed using +`Project.pycore` attribute. + +`PyCore.run_module()` runs a resource. When running, it collects type +information to do dynamic object inference. For this reason modules +run much slower. + +Also `Pycore.analyze_module()` collects object information for a +module. The collected information can be used to enhance rope's +static object inference. + + +`rope.base.taskhandle.TaskHandle` +================================= + +Can be used for stopping and monitoring the progress of time consuming +tasks like some of refactorings. `Project.do()` and +`Refactoring.get_changes()` of most refactorings take a keyword +parameter called ``task_handle``. You can pass a `TaskHandle` object +to them. A `TaskHandle` can be used for interrupting or observing a +task. + +Always pass ``task_handle`` as keyword argument; it will always be the +last argument and new arguments of the refactoring are added before +it. + +A task might consist of a few `JobSet`\s. Each `JobSet` does a few +jobs. For instance calculating the changes for renaming a method in a +class hierarchy has two job sets; We need to find the classes for +constructing the class hierarchy and then we need to change the +occurrences. + +The `TaskHandle.current_jobset()` returns the most recent `JobSet` or +`None` if none has been started. You can use the methods of `JobSet` +for obtaining information about the current job. So you might want to +do something like:: + + import rope.base.taskhandle + + + handle = rope.base.taskhandle.TaskHandle("Test Task") + + def update_progress(): + jobset = handle.current_jobsets() + if jobset: + text = '' + # getting current job set name + if jobset.get_name() is not None: + text += jobset.get_name() + # getting active job name + if jobset.get_active_job_name() is not None: + text += ' : ' + jobset.get_active_job_name() + # adding done percent + percent = jobset.get_percent_done() + if percent is not None: + text += ' ... %s percent done' % percent + print text + + handle.add_observer(update_progress) + + changes = renamer.get_changes('new_name', task_handle=handle) + +Also you can use something like this for stopping the task:: + + def stop(): + handle.stop() + +After calling ``stop()``, the thread that is executing the task will +be interrupted by a `rope.base.exceptions.InterruptedTaskError` +exception. + + +Refactorings +============ + +Have a look at `rope.refactor` package and its sub-modules. For +example for performing a move refactoring you can create a +`Move` object like this:: + + mover = Move(project, resource, offset) + +Where `resource` and `offset` is the location to perform the +refactoring. + +Then you can commit the changes by it using `get_changes()` method:: + + project.do(mover.get_changes(destination)) + +Where `destination` module/package is the destination resource for +move refactoring. Other refactorings classes have a similar +interface. + + +List Of Refactorings +-------------------- + +Here is the list of refactorings rope provides. Note that this list +might be out of date. For more information about these refactoring +see pydocs in their modules and the unit-tests in the +``ropetest/refactor/`` folder. + +* `rope.refactor.rename`: + Rename something in the project. See the example below. + +* `rope.refactor.move`: + Move a python element in the project. + +* `rope.refactor.restructure`: + Restructure code. See the example below. + +* `rope.refactor.extract`: + Extract methods/variables. + +* `rope.refactor.inline`: + Inline occurrences of a method/variable/parameter. + +* `rope.refactor.usefunction`: + Try to use a function wherever possible. + +* `rope.refactor.method_object`: + Transform a function or a method to a method object. + +* `rope.refactor.change_signature`: + Change the signature of a function/method. + +* `rope.refactor.introduce_factory`: + Introduce a factory for a class and changes all constructors to use + it. + +* `rope.refactor.introduce_parameter`: + Introduce a parameter in a function. + +* `rope.refactor.encapsulate_field`: + Generate a getter/setter for a field and changes its occurrences to + use them. + +* `rope.refactor.localtofield`: + Change a local variable to field + +* `rope.refactor.topackage`: + Transform a module to a package with the same name. + +* `rope.refactor.importutils`: + Perform actions like organize imports. + + +Refactoring Resources Parameter +------------------------------- + +Some refactorings, restructure and find occurrences accept an argument +called ``resources``. If it is a list of `File`\s, all other +resources in the project are ignored and the refactoring only analyzes +them; if it is `None` all python modules in the project will be +analyzed. Using this parameter, IDEs can let the user limit the files +on which a refactoring should be applied. + + +Examples +======== + +Rename +------ + +Using rename refactoring:: + + # Creating a project + >>> from rope.base.project import Project + >>> project = Project('.') + + # Working with files to create a module + >>> mod1 = project.root.create_file('mod1.py') + >>> mod1.write('a_var = 10\n') + + # Alternatively you can use `generate` module. + # Creating modules and packages using `generate` module + >>> from rope.contrib import generate + >>> pycore = project.pycore + >>> pkg = generate.create_package(project, 'pkg') + >>> mod2 = generate.create_module(project, 'mod2', pkg) + >>> mod2.write('import mod1\nprint mod1.a_var\n') + + # We can use `PyCore.find_module` for finding modules, too + >>> assert mod2 == pycore.find_module('pkg.mod2') + + # Performing rename refactoring on `mod1.a_var` + >>> from rope.refactor.rename import Rename + >>> changes = Rename(project, mod1, 1).get_changes('new_var') + >>> project.do(changes) + >>> mod1.read() + u'new_var = 10\n' + >>> mod2.read() + u'import mod1\nprint mod1.new_var\n' + + # Undoing rename refactoring + >>> project.history.undo() + ... + >>> mod1.read() + u'a_var = 10\n' + >>> mod2.read() + u'import mod1\nprint mod1.a_var\n' + + # Cleaning up + >>> pkg.remove() + >>> mod1.remove() + >>> project.close() + + +Restructuring +------------- + +The example for replacing occurrences of our `pow` function to ``**`` +operator (see the restructuring section of `overview.txt`_):: + + # Setting up the project + >>> from rope.base.project import Project + >>> project = Project('.') + + >>> mod1 = project.root.create_file('mod1.py') + >>> mod1.write('def pow(x, y):\n result = 1\n' + ... ' for i in range(y):\n result *= x\n' + ... ' return result\n') + >>> mod2 = project.root.create_file('mod2.py') + >>> mod2.write('import mod1\nprint(mod1.pow(2, 3))\n') + + >>> from rope.refactor import restructure + + >>> pattern = '${pow_func}(${param1}, ${param2})' + >>> goal = '${param1} ** ${param2}' + >>> args = {'pow_func': 'name=mod1.pow'} + + >>> restructuring = restructure.Restructure(project, pattern, goal, args) + + >>> project.do(restructuring.get_changes()) + >>> mod2.read() + u'import mod1\nprint(2 ** 3)\n' + + # Cleaning up + >>> mod1.remove() + >>> mod2.remove() + >>> project.close() + + +See code documentation and test suites for more information. + +.. _overview.txt: overview.html +.. _contributing.txt: contributing.html + + +Other Topics +============ + + +Writing A `FileSystemCommands` +------------------------------ + +The `get_changes()` method of refactoring classes return a +`rope.base.change.Change` object. You perform these changes by +calling `Project.do()`. But as explained above some IDEs need to +perform the changes themselves. + +Every change to file-system in rope is commited using an object that +provides `rope.base.fscommands.FileSystemCommands` interface. As +explained above in `rope.base.fscommands`_ section, rope uses this +interface to handle different VCSs. + +You can implement your own fscommands object:: + + class MyFileSystemCommands(object): + + def create_file(self, path): + """Create a new file""" + # ... + + def create_folder(self, path): + """Create a new folder""" + # ... + + def move(self, path, new_location): + """Move resource at `path` to `new_location`""" + # ... + + def remove(self, path): + """Remove resource""" + # ... + + def write(self, path, data): + """Write `data` to file at `path`""" + # ... + +And you can create a project like this:: + + my_fscommands = MyFileSystemCommands() + project = rope.base.project.Project('~/myproject', + fscommands=my_fscommands) + + +`rope.contrib.codeassist` +------------------------- + +The `rope.contrib` package contains modules that use rope base parts +and provide useful features. `rope.contrib.codeassist` module can +be used in IDEs:: + + from rope.ide import codeassist + + + # Get the proposals; you might want to pass a Resource + proposals = codeassist.code_assist(project, source_code, offset) + # Sorting proposals; for changing the order see pydoc + proposals = codeassist.sorted_proposals(proposals) + + # Where to insert the completions + starting_offset = codeassist.starting_offset(source_code, offset) + + # Applying a proposal + proposal = proposals[x] + replacement = proposal.name + + new_source_code = (source_code[:starting_offset] + + replacement + source_code[offset:]) + +`maxfixes` parameter of `code_assist` decides how many syntax errors +to fix. The default value is one. For instance:: + + def f(): + g(my^ + + myvariable = None + + def g(p): + invalid syntax ... + +will report `myvariable`, only if `maxfixes` is bigger than 1. + +`later_locals`, if `True`, forces rope to propose names that are +defined later in current scope. It is `True` by default. For +instance:: + + def f(): + my^ + myvariable = None + +will not report `myvariable`, if `later_locals` is False. + +See pydocs and source code for more information (other functions in +this module might be interesting, too; like `get_doc`, +`get_definition_location`). + + +`rope.contrib.findit` +--------------------- + +`findit` module provides `find_occurrences()` for finding occurrences +of a name. Also `find_implementations()` function finds the places in +which a method is overridden. + + +`rope.contrib.autoimport` +------------------------- + +This module can be used to find the modules that provide a name. IDEs +can use this module to auto-import names. `AutoImport.get_modules()` +returns the list of modules with the given global name. +`AutoImport.import_assist()` tries to find the modules that have a +global name that starts with the given prefix. + + +Cross-Project Refactorings +-------------------------- + +`rope.refactor.multiproject` can be used to perform a refactoring +across multiple projects. + +Usually refactorings have a main project. That is the project that +contains the definition of the changing python name. Other projects +depend on the main one and uses of the changed name in them should be +updated. + +Each refactoring changes only one project (the project passed to its +constructor). But we can use `MultiProjectRefactoring` proxy to +perform a refactoring on other projects, too. + +First we need to create a multi-project refactoring constructor. As +an example consider we want to perform a rename refactoring:: + + from rope.refactor import multiproject, rename + + + CrossRename = multiproject.MultiProjectRefactoring(rename.Rename, + projects) + + +Here `projects` is the list of dependant projects; it does not include +the main project. The first argument is the refactoring class (such +as `Rename`) or factory function (like `create_move`). + +Next we can construct the refactoring:: + + renamer = CrossRename(project, resource, offset) + +We create the rename refactoring as we do for normal refactorings. +Note that `project` is the main project. + +As mentioned above, other projects use the main project; rope +automatically adds the main project to the python path of other +projects. + +Finally we can calculate the changes. But instead of calling +`get_changes()` (which returns main project changes, only), we can +call `get_all_changes()` with the same arguments. It returns a list +of ``(project, changes)`` tuples. You can perform them manually by +calling ``project.do(changes)`` for each tuple or use +`multiproject.perform()`:: + + project_and_changes = renamer.get_all_changes('newname') + + multiproject.perform(project_and_changes) diff -r e30544496575 -r 48cacfdc2ca6 vim/sadness/ropevim/src/rope/docs/overview.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vim/sadness/ropevim/src/rope/docs/overview.txt Wed Oct 06 12:30:46 2010 -0400 @@ -0,0 +1,1116 @@ +=============== + Rope Overview +=============== + + +The purpose of this file is to give an overview of some of rope's +features. It is incomplete. And some of the features shown here are +old and do not show what rope can do in extremes. So if you really +want to feel the power of rope try its features and see its unit +tests. + +This file is more suitable for the users. Developers who plan to use +rope as a library might find library.txt_ more useful. + +.. contents:: Table of Contents +.. _library.txt: library.html + + +``.ropeproject`` Folder +======================= + +Rope uses a folder inside projects for holding project configuration +and data. Its default name is ``.ropeproject``, but it can be +changed (you can even tell rope not to create this folder). + +Currently it is used for things such as: + +* There is a ``config.py`` file in this folder in which you can change + project configurations. Have look at the default ``config.py`` file + (is created when it does not exist) for more information. +* It can be used for saving project history, so that the next time you + open the project you can undo past changes. +* It can be used for saving object information to help rope object + inference. +* It can be used for saving global names cache which is used in + auto-import. + +You can change what to save and what not to in the ``config.py`` file. + + +Refactorings +============ + +This section shows some random refactorings that you can perform using +rope. + + +Renaming Attributes +------------------- + +Consider we have:: + + class AClass(object): + + def __init__(self): + self.an_attr = 1 + + def a_method(self, arg): + print self.an_attr, arg + + a_var = AClass() + a_var.a_method(a_var.an_attr) + +After renaming ``an_attr`` to ``new_attr`` and ``a_method`` to +``new_method`` we'll have:: + + class AClass(object): + + def __init__(self): + self.new_attr = 1 + + def new_method(self, arg): + print self.new_attr, arg + + a_var = AClass() + a_var.new_method(a_var.new_attr) + + +Renaming Function Keyword Parameters +------------------------------------ + +On:: + + def a_func(a_param): + print a_param + + a_func(a_param=10) + a_func(10) + +performing rename refactoring on any occurrence of ``a_param`` will +result in:: + + def a_func(new_param): + print new_param + + a_func(new_param=10) + a_func(10) + + +Renaming modules +---------------- + +Consider the project tree is something like:: + + root/ + mod1.py + mod2.py + +``mod1.py`` contains:: + + import mod2 + from mod2 import AClass + + mod2.a_func() + a_var = AClass() + +After performing rename refactoring one of the ``mod2`` occurrences in +`mod1` we'll get:: + + import newmod + from newmod import AClass + + newmod.a_func() + a_var = AClass() + +and the new project tree would be:: + + root/ + mod1.py + newmod.py + + +Renaming Occurrences In Strings And Comments +-------------------------------------------- + +You can tell rope to rename all occurrences of a name in comments and +strings. This can be done by passing ``docs=True`` to +`Rename.get_changes()` method. Rope renames names in comments and +strings only where the name is visible. For example in:: + + def f(): + a_var = 1 + # INFO: I'm printing `a_var` + print 'a_var = %s' % a_var + + # f prints a_var + +after we rename the `a_var` local variable in `f()` to `new_var` we +would get:: + + def f(): + new_var = 1 + # INFO: I'm printing `new_var` + print 'new_var = %s' % new_var + + # f prints a_var + +This makes it safe to assume that this option does not perform wrong +renames most of the time. + +This also changes occurrences inside evaluated strings:: + + def func(): + print 'func() called' + + eval('func()') + +After renaming `func` to `newfunc` we should have:: + + def newfunc(): + print 'newfunc() called' + + eval('newfunc()') + + +Rename When Unsure +------------------ + +This option tells rope to rename when it doesn't know whether it is an +exact match or not. For example after renaming `C.a_func` when the +'rename when unsure' option is set in:: + + class C(object): + + def a_func(self): + pass + + def a_func(arg): + arg.a_func() + + C().a_func() + +we would have:: + + class C(object): + + def new_func(self): + pass + + def a_func(arg): + arg.new_func() + + C().new_func() + +Note that the global `a_func` was not renamed because we are sure that +it is not a match. But when using this option there might be some +unexpected renames. So only use this option when the name is almost +unique and is not defined in other places. + +Move Method Refactoring +----------------------- + +It happens when you perform move refactoring on a method of a class. +In this refactoring, a method of a class is moved to the class of one +of its attributes. The old method will call the new method. If you +want to change all of the occurrences of the old method to use the new +method you can inline it afterwards. + +For instance if you perform move method on `a_method` in:: + + class A(object): + pass + + class B(object): + + def __init__(self): + self.attr = A() + + def a_method(self): + pass + + b = B() + b.a_method() + +You will be asked for the destination field and the name of the new +method. If you use ``attr`` and ``new_method`` in these fields +and press enter, you'll have:: + + class A(object): + + def new_method(self): + pass + + class B(object): + + def __init__(self): + self.attr = A() + + def a_method(self): + return self.attr.new_method() + + + b = B() + b.a_method() + +Now if you want to change the occurrences of `B.a_method()` to use +`A.new_method()`, you can inline `B.a_method()`:: + + class A(object): + + def new_method(self): + pass + + class B(object): + + def __init__(self): + self.attr = A() + + b = B() + b.attr.new_method() + + +Moving Fields +------------- + +Rope does not have a separate refactoring for moving fields. Rope's +refactorings are very flexible, though. You can use the rename +refactoring to move fields. For instance:: + + class A(object): + pass + + class B(object): + + def __init__(self): + self.a = A() + self.attr = 1 + + b = B() + print(b.attr) + +consider we want to move `attr` to `A`. We can do that by renaming `attr` +to `a.attr`:: + + class A(object): + pass + + class B(object): + + def __init__(self): + self.a = A() + self.a.attr = 1 + + b = B() + print(b.a.attr) + +You can move the definition of `attr` manually. + + +Extract Method +-------------- + +In these examples ``${region_start}`` and ``${region_end}`` show the +selected region for extraction:: + + def a_func(): + a = 1 + b = 2 * a + c = ${region_start}a * 2 + b * 3${region_end} + +After performing extract method we'll have:: + + def a_func(): + a = 1 + b = 2 * a + c = new_func(a, b) + + def new_func(a, b): + return a * 2 + b * 3 + +For multi-line extractions if we have:: + + def a_func(): + a = 1 + ${region_start}b = 2 * a + c = a * 2 + b * 3${region_end} + print b, c + +After performing extract method we'll have:: + + def a_func(): + a = 1 + b, c = new_func(a) + print b, c + + def new_func(a): + b = 2 * a + c = a * 2 + b * 3 + return b, c + + +Extracting Similar Expressions/Statements +----------------------------------------- + +When performing extract method or local variable refactorings you can +tell rope to extract similar expressions/statements. For instance +in:: + + if True: + x = 2 * 3 + else: + x = 2 * 3 + 1 + +Extracting ``2 * 3`` will result in:: + + six = 2 * 3 + if True: + x = six + else: + x = six + 1 + + +Extract Method In staticmethods/classmethods +-------------------------------------------- + +The extract method refactoring has been enhanced to handle static and +class methods better. For instance in:: + + class A(object): + + @staticmethod + def f(a): + b = a * 2 + +if you extract ``a * 2`` as a method you'll get:: + + class A(object): + + @staticmethod + def f(a): + b = A.twice(a) + + @staticmethod + def twice(a): + return a * 2 + + +Inline Method Refactoring +------------------------- + +Inline method refactoring can add imports when necessary. For +instance consider ``mod1.py`` is:: + + import sys + + + class C(object): + pass + + def do_something(): + print sys.version + return C() + +and ``mod2.py`` is:: + + import mod1 + + + c = mod1.do_something() + +After inlining `do_something`, ``mod2.py`` would be:: + + import mod1 + import sys + + + print sys.version + c = mod1.C() + +Rope can inline methods, too:: + + class C(object): + + var = 1 + + def f(self, p): + result = self.var + pn + return result + + + c = C() + x = c.f(1) + +After inlining `C.f()`, we'll have:: + + class C(object): + + var = 1 + + c = C() + result = c.var + pn + x = result + +As another example we will inline a `classmethod`:: + + class C(object): + @classmethod + def say_hello(cls, name): + return 'Saying hello to %s from %s' % (name, cls.__name__) + hello = C.say_hello('Rope') + +Inlining `say_hello` will result in:: + + class C(object): + pass + hello = 'Saying hello to %s from %s' % ('Rope', C.__name__) + + +Inlining Parameters +------------------- + +`rope.refactor.inline.create_inline()` creates an `InlineParameter` +object when performed on a parameter. It passes the default value of +the parameter wherever its function is called without passing it. For +instance in:: + + def f(p1=1, p2=1): + pass + + f(3) + f() + f(3, 4) + +after inlining p2 parameter will have:: + + def f(p1=1, p2=1): + pass + + f(3, 2) + f(p2=2) + f(3, 4) + + +Use Function Refactoring +------------------------ + +It tries to find the places in which a function can be used and +changes the code to call it instead. For instance if mod1 is:: + + def square(p): + return p ** 2 + + my_var = 3 ** 2 + + +and mod2 is:: + + another_var = 4 ** 2 + +if we perform "use function" on square function, mod1 will be:: + + def square(p): + return p ** 2 + + my_var = square(3) + +and mod2 will be:: + + import mod1 + another_var = mod1.square(4) + + +Automatic Default Insertion In Change Signature +----------------------------------------------- + +The `rope.refactor.change_signature.ArgumentReorderer` signature +changer takes a parameter called ``autodef``. If not `None`, its +value is used whenever rope needs to insert a default for a parameter +(that happens when an argument without default is moved after another +that has a default value). For instance in:: + + def f(p1, p2=2): + pass + +if we reorder using:: + + changers = [ArgumentReorderer([1, 0], autodef='1')] + +will result in:: + + def f(p2=2, p1=1): + pass + + +Sorting Imports +--------------- + +Organize imports sorts imports, too. It does that according to +:PEP:`8`:: + + [__future__ imports] + + [standard imports] + + [third-party imports] + + [project imports] + + + [the rest of module] + + +Handling Long Imports +--------------------- + +``Handle long imports`` command trys to make long imports look better by +transforming ``import pkg1.pkg2.pkg3.pkg4.mod1`` to ``from +pkg1.pkg2.pkg3.pkg4 import mod1``. Long imports can be identified +either by having lots of dots or being very long. The default +configuration considers imported modules with more than 2 dots or with +more than 27 characters to be long. + + +Stoppable Refactorings +---------------------- + +Some refactorings might take a long time to finish (based on the size +of your project). The `get_changes()` method of these refactorings +take a parameter called `task_handle`. If you want to monitor or stop +these refactoring you can pass a `rope.refactor. +taskhandle.TaskHandle` to this method. See `rope.refactor.taskhandle` +module for more information. + + +Basic Implicit Interfaces +------------------------- + +Implicit interfaces are the interfaces that you don't explicitly +define; But you expect a group of classes to have some common +attributes. These interfaces are very common in dynamic languages; +Since we only have implementation inheritance and not interface +inheritance. For instance:: + + class A(object): + + def count(self): + pass + + class B(object): + + def count(self): + pass + + def count_for(arg): + return arg.count() + + count_for(A()) + count_for(B()) + +Here we know that there is an implicit interface defined by the +function `count_for` that provides `count()`. Here when we rename +`A.count()` we expect `B.count()` to be renamed, too. Currently rope +supports a basic form of implicit interfaces. When you try to rename +an attribute of a parameter, rope renames that attribute for all +objects that have been passed to that function in different call +sites. That is renaming the occurrence of `count` in `count_for` +function to `newcount` will result in:: + + class A(object): + + def newcount(self): + pass + + class B(object): + + def newcount(self): + pass + + def count_for(arg): + return arg.newcount() + + count_for(A()) + count_for(B()) + +This also works for change method signature. Note that this feature +relies on rope's object analysis mechanisms to find out the parameters +that are passed to a function. + + +Restructurings +-------------- + +`rope.refactor.restructure` can be used for performing restructurings. +A restructuring is a program transformation; not as well defined as +other refactorings like rename. In this section, we'll see some +examples. After this example you might like to have a look at: + +* `rope.refactor.restructure` for more examples and features not + described here like adding imports to changed modules. +* `rope.refactor.wildcards` for an overview of the arguments the + default wildcard supports. + +Finally, restructurings can be improved in many ways (for instance +adding new wildcards). You might like to discuss your ideas in the +mailing list. + + +Example 1 +''''''''' + +In its basic form we have a pattern and a goal. Consider we were not +aware of the ``**`` operator and wrote our own :: + + def pow(x, y): + result = 1 + for i in range(y): + result *= x + return result + + print pow(2, 3) + +Now that we know ``**`` exists we want to use it wherever `pow` is +used (there might be hundreds of them!). We can use a pattern like:: + + pattern: pow(${param1}, ${param2}) + +Goal can be something like:: + + goal: ${param1} ** ${param2} + +Note that ``${...}`` can be used to match expressions. By default +every expression at that point will match. + +You can use the matched names in goal and they will be replaced with +the string that was matched in each occurrence. So the outcome of our +restructuring will be:: + + def pow(x, y): + result = 1 + for i in range(y): + result *= x + return result + + print 2 ** 3 + +It seems to be working but what if `pow` is imported in some module or +we have some other function defined in some other module that uses the +same name and we don't want to change it. Wildcard arguments come to +rescue. Wildcard arguments is a mapping; Its keys are wildcard names +that appear in the pattern (the names inside ``${...}``). + +The values are the parameters that are passed to wildcard matchers. +The arguments a wildcard takes is based on its type. + +For checking the type of a wildcard, we can pass ``type=value`` as an +argument; ``value`` should be resolved to a python variable (or +reference). For instance for specifying `pow` in this example we can +use `mod.pow`. As you see, this string should start from module name. +For referencing python builtin types and functions you can use +`__builtin__` module (for instance `__builtin__.int`). + +For solving the mentioned problem, we change our `pattern`. But +`goal` remains the same:: + + pattern: ${pow_func}(${param1}, ${param2}) + goal: ${param1} ** ${param2} + +Consider the name of the module containing our `pow` function is +`mod`. ``args`` can be:: + + pow_func: name=mod.pow + +If we need to pass more arguments to a wildcard matcher we can use +``,`` to separate them. Such as ``name: type=mod.MyClass,exact``. + +This restructuring handles aliases; like in:: + + mypow = pow + result = mypow(2, 3) + +Transforms into:: + + mypow = pow + result = 2 ** 3 + +If we want to ignore aliases we can pass ``exact`` as another wildcard +argument:: + + pattern: ${pow}(${param1}, ${param2}) + goal: ${param1} ** ${param2} + args: pow: name=mod.pow, exact + +``${name}``, by default, matches every expression at that point; if +``exact`` argument is passed to a wildcard only the specified name +will match (for instance, if ``exact`` is specified , ``${name}`` +matches ``name`` and ``x.name`` but not ``var`` nor ``(1 + 2)`` while +a normal ``${name}`` can match all of them). + +For performing this refactoring using rope library see `library.txt`_. + + +Example 2 +''''''''' + +As another example consider:: + + class A(object): + + def f(self, p1, p2): + print p1 + print p2 + + + a = A() + a.f(1, 2) + +Later we decide that `A.f()` is doing too much and we want to divide +it to `A.f1()` and `A.f2()`:: + + class A(object): + + def f(self, p1, p2): + print p1 + print p2 + + def f1(self, p): + print p + + def f2(self, p): + print p + + + a = A() + a.f(1, 2) + +But who's going to fix all those nasty occurrences (actually this +situation can be handled using inline method refactoring but this is +just an example; consider inline refactoring is not implemented yet!). +Restructurings come to rescue:: + + pattern: ${inst}.f(${p1}, ${p2}) + goal: + ${inst}.f1(${p1}) + ${inst}.f2(${p2}) + + args: + inst: type=mod.A + +After performing we will have:: + + class A(object): + + def f(self, p1, p2): + print p1 + print p2 + + def f1(self, p): + print p + + def f2(self, p): + print p + + + a = A() + a.f1(1) + a.f2(2) + + +Example 3 +''''''''' + +If you like to replace every occurrences of ``x.set(y)`` with ``x = +y`` when x is an instance of `mod.A` in:: + + from mod import A + + a = A() + b = A() + a.set(b) + +We can perform a restructuring with these information:: + + pattern: ${x}.set(${y}) + goal: ${x} = ${y} + + args: x: type=mod.A + +After performing the above restructuring we'll have:: + + from mod import A + + a = A() + b = A() + a = b + +Note that ``mod.py`` contains something like:: + + class A(object): + + def set(self, arg): + pass + +Issues +'''''' + +Pattern names can appear only at the start of an expression. For +instance ``var.${name}`` is invalid. These situations can usually be +fixed by specifying good checks, for example on the type of `var` and +using a ``${var}.name``. + + +Object Inference +================ + +This section is a bit out of date. Static object inference can do +more than described here (see unittests). Hope to update this +someday! + + +Static Object Inference +----------------------- + +:: + + class AClass(object): + + def __init__(self): + self.an_attr = 1 + + def call_a_func(self): + return a_func() + + def a_func(): + return AClass() + + a_var = a_func() + #a_var.${codeassist} + + another_var = a_var + #another_var.${codeassist} + #another_var.call_a_func().${codeassist} + + +Basic support for builtin types:: + + a_list = [AClass(), AClass()] + for x in a_list: + pass + #x.${codeassist} + #a_list.pop().${codeassist} + + a_dict = ['text': AClass()] + for key, value in a_dict.items(): + pass + #key.${codeassist} + #value.${codeassist} + +Enhanced static returned object inference:: + + class C(object): + + def c_func(self): + return [''] + + def a_func(arg): + return arg.c_func() + + a_var = a_func(C()) + +Here rope knows that the type of a_var is a `list` that holds `str`\s. + +Supporting generator functions:: + + class C(object): + pass + + def a_generator(): + yield C() + + + for c in a_generator(): + a_var = c + +Here the objects `a_var` and `c` hold are known. + +Rope collects different types of data during SOA, like per name data +for builtin container types:: + + l1 = [C()] + var1 = l1.pop() + + l2 = [] + l2.append(C()) + var2 = l2.pop() + +Here rope can easily infer the type of `var1`. But for knowing the +type of `var2`, it needs to analyze the items inserted into `l2` which +might happen in other modules. Rope can do that by running SOA on +that module. + +You might be wondering is there any reason for using DOA instead of +SOA. The answer is that DOA might be more accurate and handles +complex and dynamic situations. For example in:: + + def f(arg): + return eval(arg) + + a_var = f('C') + +SOA can no way conclude the object `a_var` holds but it is really +trivial for DOA. What's more SOA only analyzes calls in one module +while DOA analyzes any call that happens when running a module. That +is, for achieving the same result as DOA you might need to run SOA on +more than one module and more than once (not considering dynamic +situations.) One advantage of SOA is that it is much faster than DOA. + + +Dynamic Object Analysis +----------------------- + +`PyCore.run_module()` runs a module and collects object information if +``perform_doa`` project config is set. Since as the program runs rope +gathers type information, the program runs much slower. After the +program is run, you can get better code assists and some of the +refactorings perform much better. + +``mod1.py``:: + + def f1(param): + pass + #param.${codeassist} + #f2(param).${codeassist} + + def f2(param): + #param.${codeassist} + return param + +Using code assist in specified places does not give any information +and there is actually no information about the return type of `f2` or +`param` parameter of `f1`. + +``mod2.py``:: + + import mod1 + + class A(object): + + def a_method(self): + pass + + a_var = A() + mod1.f1(a_var) + +Retry those code assists after performing DOA on `mod2` module. + + +Builtin Container Types +''''''''''''''''''''''' + +Builtin types can be handled in a limited way, too:: + + class A(object): + + def a_method(self): + pass + + def f1(): + result = [] + result.append(A()) + return result + + returned = f() + #returned[0].${codeassist} + +Test the the proposed completions after running this module. + + +Guessing Function Returned Value Based On Parameters +---------------------------------------------------- + +``mod1.py``:: + + class C1(object): + + def c1_func(self): + pass + + class C2(object): + + def c2_func(self): + pass + + + def func(arg): + if isinstance(arg, C1): + return C2() + else: + return C1() + + func(C1()) + func(C2()) + +After running `mod1` either SOA or DOA on this module you can test: + +``mod2.py``:: + + import mod1 + + arg = mod1.C1() + a_var = mod1.func(arg) + a_var.${codeassist} + mod1.func(mod1.C2()).${codeassist} + + +Automatic SOA +------------- + +When turned on, it analyzes the changed scopes of a file when saving +for obtaining object information; So this might make saving files a +bit more time consuming. By default, this feature is turned on, but +you can turn it off by editing your project ``config.py`` file, though +that is not recommended. + + +Validating Object DB +-------------------- + +Since files on disk change over time project objectdb might hold +invalid information. Currently there is a basic incremental objectdb +validation that can be used to remove or fix out of date information. +Rope uses this feature by default but you can disable it by editing +``config.py``. + + +Custom Source Folders +===================== + +By default rope searches the project for finding source folders +(folders that should be searched for finding modules). You can add +paths to that list using ``source_folders`` project config. Note that +rope guesses project source folders correctly most of the time. You +can also extend python path using ``python_path`` config. + + +Version Control Systems Support +=============================== + +When performing refactorings some files might need to be moved (when +renaming a module) or new files might be created. When using a VCS, +rope detects and uses it to perform file system actions. + +Currently Mercurial_, GIT_, Darcs_ and SVN (using pysvn_ library) are +supported. They are selected based on dot files in project root +directory. For instance, Mercurial will be used if `mercurial` module +is available and there is a ``.hg`` folder in project root. Rope +assumes either all files are under version control in a project or +there is no version control at all. Also don't forget to commit your +changes yourself, rope doesn't do that. + +Adding support for other VCSs is easy; have a look at +`library.txt`_. + +.. _pysvn: http://pysvn.tigris.org +.. _Mercurial: http://selenic.com/mercurial +.. _GIT: http://git.or.cz +.. _darcs: http://darcs.net diff -r e30544496575 -r 48cacfdc2ca6 vim/sadness/ropevim/src/rope/docs/rope.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vim/sadness/ropevim/src/rope/docs/rope.txt Wed Oct 06 12:30:46 2010 -0400 @@ -0,0 +1,55 @@ +Features +======== + +Features implemented so far: + +* Refactorings + + * Rename everything! + * Extract method/local variable + * Move class/function/module/package/method + * Inline method/local variable/parameter + * Restructuring (like converting ``${a}.f(${b})`` to + ``${b}.g(${a})`` where ``a: type=mymod.A``) + * Introduce factory + * Change method signature + * Transform module to package + * Encapsulate field + * Replace method with method object + * And a few others + +* Refactoring Features + + * Extracting similar statements in extract refactorings + * Fixing imports when needed + * Previewing refactorings + * Undo/redo refactorings + * Stopping refactorings + * Cross-project refactorings + * Basic implicit interfaces handling in rename and change signature + * Mercurial_, GIT_, Darcs_ and SVN (pysvn_ library) support in + refactorings + +* IDE helpers + + * Auto-completion + * Definition location + * Get pydoc + * Find occurrences + * Organize imports (remove unused and duplicate imports and sort them) + * Generating python elements + +* Object Inference + + * Static and dynamic object analysis + * Handling built-in container types + * Saving object information on disk and validating them + +For more information see `overview.txt`_. + + +.. _overview.txt: overview.html +.. _pysvn: http://pysvn.tigris.org +.. _Mercurial: http://selenic.com/mercurial +.. _GIT: http://git.or.cz +.. _darcs: http://darcs.net diff -r e30544496575 -r 48cacfdc2ca6 vim/sadness/ropevim/src/rope/rope/__init__.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vim/sadness/ropevim/src/rope/rope/__init__.py Wed Oct 06 12:30:46 2010 -0400 @@ -0,0 +1,17 @@ +"""rope, a python refactoring library""" + +INFO = __doc__ +VERSION = '0.9.3' +COPYRIGHT = """\ +Copyright (C) 2006-2010 Ali Gholami Rudi +Copyright (C) 2009-2010 Anton Gritsay + +This program is free software; you can redistribute it and/or modify it +under the terms of GNU General Public License as published by the +Free Software Foundation; either version 2 of the license, or (at your +opinion) 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.""" diff -r e30544496575 -r 48cacfdc2ca6 vim/sadness/ropevim/src/rope/rope/base/__init__.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vim/sadness/ropevim/src/rope/rope/base/__init__.py Wed Oct 06 12:30:46 2010 -0400 @@ -0,0 +1,8 @@ +"""Base rope package + +This package contains rope core modules that are used by other modules +and packages. + +""" + +__all__ = ['project', 'libutils', 'exceptions'] diff -r e30544496575 -r 48cacfdc2ca6 vim/sadness/ropevim/src/rope/rope/base/arguments.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vim/sadness/ropevim/src/rope/rope/base/arguments.py Wed Oct 06 12:30:46 2010 -0400 @@ -0,0 +1,109 @@ +import rope.base.evaluate +from rope.base import ast + + +class Arguments(object): + """A class for evaluating parameters passed to a function + + You can use the `create_arguments` factory. It handles implicit + first arguments. + + """ + + def __init__(self, args, scope): + self.args = args + self.scope = scope + self.instance = None + + def get_arguments(self, parameters): + result = [] + for pyname in self.get_pynames(parameters): + if pyname is None: + result.append(None) + else: + result.append(pyname.get_object()) + return result + + def get_pynames(self, parameters): + result = [None] * max(len(parameters), len(self.args)) + for index, arg in enumerate(self.args): + if isinstance(arg, ast.keyword) and arg.arg in parameters: + result[parameters.index(arg.arg)] = self._evaluate(arg.value) + else: + result[index] = self._evaluate(arg) + return result + + def get_instance_pyname(self): + if self.args: + return self._evaluate(self.args[0]) + + def _evaluate(self, ast_node): + return rope.base.evaluate.eval_node(self.scope, ast_node) + + +def create_arguments(primary, pyfunction, call_node, scope): + """A factory for creating `Arguments`""" + args = list(call_node.args) + args.extend(call_node.keywords) + called = call_node.func + # XXX: Handle constructors + if _is_method_call(primary, pyfunction) and \ + isinstance(called, ast.Attribute): + args.insert(0, called.value) + return Arguments(args, scope) + + +class ObjectArguments(object): + + def __init__(self, pynames): + self.pynames = pynames + + def get_arguments(self, parameters): + result = [] + for pyname in self.pynames: + if pyname is None: + result.append(None) + else: + result.append(pyname.get_object()) + return result + + def get_pynames(self, parameters): + return self.pynames + + def get_instance_pyname(self): + return self.pynames[0] +class MixedArguments(object): + + def __init__(self, pyname, arguments, scope): + """`argumens` is an instance of `Arguments`""" + self.pyname = pyname + self.args = arguments + + def get_pynames(self, parameters): + return [self.pyname] + self.args.get_pynames(parameters[1:]) + + def get_arguments(self, parameters): + result = [] + for pyname in self.get_pynames(parameters): + if pyname is None: + result.append(None) + else: + result.append(pyname.get_object()) + return result + + def get_instance_pyname(self): + return self.pyname + + +def _is_method_call(primary, pyfunction): + if primary is None: + return False + pyobject = primary.get_object() + if isinstance(pyobject.get_type(), rope.base.pyobjects.PyClass) and \ + isinstance(pyfunction, rope.base.pyobjects.PyFunction) and \ + isinstance(pyfunction.parent, rope.base.pyobjects.PyClass): + return True + if isinstance(pyobject.get_type(), rope.base.pyobjects.AbstractClass) and \ + isinstance(pyfunction, rope.base.builtins.BuiltinFunction): + return True + return False diff -r e30544496575 -r 48cacfdc2ca6 vim/sadness/ropevim/src/rope/rope/base/ast.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vim/sadness/ropevim/src/rope/rope/base/ast.py Wed Oct 06 12:30:46 2010 -0400 @@ -0,0 +1,67 @@ +import _ast +from _ast import * + +from rope.base import fscommands + + +def parse(source, filename=''): + # NOTE: the raw string should be given to `compile` function + if isinstance(source, unicode): + source = fscommands.unicode_to_file_data(source) + if '\r' in source: + source = source.replace('\r\n', '\n').replace('\r', '\n') + if not source.endswith('\n'): + source += '\n' + try: + return compile(source, filename, 'exec', _ast.PyCF_ONLY_AST) + except (TypeError, ValueError), e: + error = SyntaxError() + error.lineno = 1 + error.filename = filename + error.msg = str(e) + raise error + + +def walk(node, walker): + """Walk the syntax tree""" + method_name = '_' + node.__class__.__name__ + method = getattr(walker, method_name, None) + if method is not None: + return method(node) + for child in get_child_nodes(node): + walk(child, walker) + + +def get_child_nodes(node): + if isinstance(node, _ast.Module): + return node.body + result = [] + if node._fields is not None: + for name in node._fields: + child = getattr(node, name) + if isinstance(child, list): + for entry in child: + if isinstance(entry, _ast.AST): + result.append(entry) + if isinstance(child, _ast.AST): + result.append(child) + return result + + +def call_for_nodes(node, callback, recursive=False): + """If callback returns `True` the child nodes are skipped""" + result = callback(node) + if recursive and not result: + for child in get_child_nodes(node): + call_for_nodes(child, callback, recursive) + + +def get_children(node): + result = [] + if node._fields is not None: + for name in node._fields: + if name in ['lineno', 'col_offset']: + continue + child = getattr(node, name) + result.append(child) + return result diff -r e30544496575 -r 48cacfdc2ca6 vim/sadness/ropevim/src/rope/rope/base/astutils.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vim/sadness/ropevim/src/rope/rope/base/astutils.py Wed Oct 06 12:30:46 2010 -0400 @@ -0,0 +1,61 @@ +from rope.base import ast + + +def get_name_levels(node): + """Return a list of ``(name, level)`` tuples for assigned names + + The `level` is `None` for simple assignments and is a list of + numbers for tuple assignments for example in:: + + a, (b, c) = x + + The levels for for `a` is ``[0]``, for `b` is ``[1, 0]`` and for + `c` is ``[1, 1]``. + + """ + visitor = _NodeNameCollector() + ast.walk(node, visitor) + return visitor.names + + +class _NodeNameCollector(object): + + def __init__(self, levels=None): + self.names = [] + self.levels = levels + self.index = 0 + + def _add_node(self, node): + new_levels = [] + if self.levels is not None: + new_levels = list(self.levels) + new_levels.append(self.index) + self.index += 1 + self._added(node, new_levels) + + def _added(self, node, levels): + if hasattr(node, 'id'): + self.names.append((node.id, levels)) + + def _Name(self, node): + self._add_node(node) + + def _Tuple(self, node): + new_levels = [] + if self.levels is not None: + new_levels = list(self.levels) + new_levels.append(self.index) + self.index += 1 + visitor = _NodeNameCollector(new_levels) + for child in ast.get_child_nodes(node): + ast.walk(child, visitor) + self.names.extend(visitor.names) + + def _Subscript(self, node): + self._add_node(node) + + def _Attribute(self, node): + self._add_node(node) + + def _Slice(self, node): + self._add_node(node) diff -r e30544496575 -r 48cacfdc2ca6 vim/sadness/ropevim/src/rope/rope/base/builtins.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vim/sadness/ropevim/src/rope/rope/base/builtins.py Wed Oct 06 12:30:46 2010 -0400 @@ -0,0 +1,762 @@ +"""This module trys to support builtin types and functions.""" +import inspect + +import rope.base.evaluate +from rope.base import pynames, pyobjects, arguments, utils, ast + + +class BuiltinModule(pyobjects.AbstractModule): + + def __init__(self, name, pycore=None, initial={}): + super(BuiltinModule, self).__init__() + self.name = name + self.pycore = pycore + self.initial = initial + + parent = None + + def get_attributes(self): + return self.attributes + + def get_doc(self): + if self.module: + return self.module.__doc__ + + def get_name(self): + return self.name.split('.')[-1] + + @property + @utils.saveit + def attributes(self): + result = _object_attributes(self.module, self) + result.update(self.initial) + if self.pycore is not None: + submodules = self.pycore._builtin_submodules(self.name) + for name, module in submodules.iteritems(): + result[name] = rope.base.builtins.BuiltinName(module) + return result + + @property + @utils.saveit + def module(self): + try: + result = __import__(self.name) + for token in self.name.split('.')[1:]: + result = getattr(result, token, None) + return result + except ImportError: + return + + +class _BuiltinElement(object): + + def __init__(self, builtin, parent=None): + self.builtin = builtin + self._parent = parent + + def get_doc(self): + if self.builtin: + return getattr(self.builtin, '__doc__', None) + + def get_name(self): + if self.builtin: + return getattr(self.builtin, '__name__', None) + + @property + def parent(self): + if self._parent is None: + return builtins + return self._parent + + +class BuiltinClass(_BuiltinElement, pyobjects.AbstractClass): + + def __init__(self, builtin, attributes, parent=None): + _BuiltinElement.__init__(self, builtin, parent) + pyobjects.AbstractClass.__init__(self) + self.initial = attributes + + @utils.saveit + def get_attributes(self): + result = _object_attributes(self.builtin, self) + result.update(self.initial) + return result + + +class BuiltinFunction(_BuiltinElement, pyobjects.AbstractFunction): + + def __init__(self, returned=None, function=None, builtin=None, + argnames=[], parent=None): + _BuiltinElement.__init__(self, builtin, parent) + pyobjects.AbstractFunction.__init__(self) + self.argnames = argnames + self.returned = returned + self.function = function + + def get_returned_object(self, args): + if self.function is not None: + return self.function(_CallContext(self.argnames, args)) + else: + return self.returned + + def get_param_names(self, special_args=True): + return self.argnames + + +class BuiltinUnknown(_BuiltinElement, pyobjects.PyObject): + + def __init__(self, builtin): + super(BuiltinUnknown, self).__init__(pyobjects.get_unknown()) + self.builtin = builtin + self.type = pyobjects.get_unknown() + + def get_name(self): + return getattr(type(self.builtin), '__name__', None) + + @utils.saveit + def get_attributes(self): + return _object_attributes(self.builtin, self) + + +def _object_attributes(obj, parent): + attributes = {} + for name in dir(obj): + if name == 'None': + continue + child = getattr(obj, name) + pyobject = None + if inspect.isclass(child): + pyobject = BuiltinClass(child, {}, parent=parent) + elif inspect.isroutine(child): + pyobject = BuiltinFunction(builtin=child, parent=parent) + else: + pyobject = BuiltinUnknown(builtin=child) + attributes[name] = BuiltinName(pyobject) + return attributes + + +def _create_builtin_type_getter(cls): + def _get_builtin(*args): + if not hasattr(cls, '_generated'): + cls._generated = {} + if args not in cls._generated: + cls._generated[args] = cls(*args) + return cls._generated[args] + return _get_builtin + +def _create_builtin_getter(cls): + type_getter = _create_builtin_type_getter(cls) + def _get_builtin(*args): + return pyobjects.PyObject(type_getter(*args)) + return _get_builtin + + +class _CallContext(object): + + def __init__(self, argnames, args): + self.argnames = argnames + self.args = args + + def _get_scope_and_pyname(self, pyname): + if pyname is not None and isinstance(pyname, pynames.AssignedName): + pymodule, lineno = pyname.get_definition_location() + if pymodule is None: + return None, None + if lineno is None: + lineno = 1 + scope = pymodule.get_scope().get_inner_scope_for_line(lineno) + name = None + while name is None and scope is not None: + for current in scope.get_names(): + if scope[current] is pyname: + name = current + break + else: + scope = scope.parent + return scope, name + return None, None + + def get_argument(self, name): + if self.args: + args = self.args.get_arguments(self.argnames) + return args[self.argnames.index(name)] + + def get_pyname(self, name): + if self.args: + args = self.args.get_pynames(self.argnames) + if name in self.argnames: + return args[self.argnames.index(name)] + + def get_arguments(self, argnames): + if self.args: + return self.args.get_arguments(argnames) + + def get_pynames(self, argnames): + if self.args: + return self.args.get_pynames(argnames) + + def get_per_name(self): + if self.args is None: + return None + pyname = self.args.get_instance_pyname() + scope, name = self._get_scope_and_pyname(pyname) + if name is not None: + pymodule = pyname.get_definition_location()[0] + return pymodule.pycore.object_info.get_per_name(scope, name) + return None + + def save_per_name(self, value): + if self.args is None: + return None + pyname = self.args.get_instance_pyname() + scope, name = self._get_scope_and_pyname(pyname) + if name is not None: + pymodule = pyname.get_definition_location()[0] + pymodule.pycore.object_info.save_per_name(scope, name, value) + + +class _AttributeCollector(object): + + def __init__(self, type): + self.attributes = {} + self.type = type + + def __call__(self, name, returned=None, function=None, + argnames=['self'], check_existence=True): + try: + builtin = getattr(self.type, name) + except AttributeError: + if check_existence: + raise + builtin=None + self.attributes[name] = BuiltinName( + BuiltinFunction(returned=returned, function=function, + argnames=argnames, builtin=builtin)) + + def __setitem__(self, name, value): + self.attributes[name] = value + + +class List(BuiltinClass): + + def __init__(self, holding=None): + self.holding = holding + collector = _AttributeCollector(list) + + collector('__iter__', function=self._iterator_get) + collector('__new__', function=self._new_list) + + # Adding methods + collector('append', function=self._list_add, argnames=['self', 'value']) + collector('__setitem__', function=self._list_add, + argnames=['self', 'index', 'value']) + collector('insert', function=self._list_add, + argnames=['self', 'index', 'value']) + collector('extend', function=self._self_set, + argnames=['self', 'iterable']) + + # Getting methods + collector('__getitem__', function=self._list_get) + collector('pop', function=self._list_get) + collector('__getslice__', function=self._self_get) + + super(List, self).__init__(list, collector.attributes) + + def _new_list(self, args): + return _create_builtin(args, get_list) + + def _list_add(self, context): + if self.holding is not None: + return + holding = context.get_argument('value') + if holding is not None and holding != pyobjects.get_unknown(): + context.save_per_name(holding) + + def _self_set(self, context): + if self.holding is not None: + return + iterable = context.get_pyname('iterable') + holding = _infer_sequence_for_pyname(iterable) + if holding is not None and holding != pyobjects.get_unknown(): + context.save_per_name(holding) + + def _list_get(self, context): + if self.holding is not None: + return self.holding + return context.get_per_name() + + def _iterator_get(self, context): + return get_iterator(self._list_get(context)) + + def _self_get(self, context): + return get_list(self._list_get(context)) + + +get_list = _create_builtin_getter(List) +get_list_type = _create_builtin_type_getter(List) + + +class Dict(BuiltinClass): + + def __init__(self, keys=None, values=None): + self.keys = keys + self.values = values + item = get_tuple(self.keys, self.values) + collector = _AttributeCollector(dict) + collector('__new__', function=self._new_dict) + collector('__setitem__', function=self._dict_add) + collector('popitem', function=self._item_get) + collector('pop', function=self._value_get) + collector('get', function=self._key_get) + collector('keys', function=self._key_list) + collector('values', function=self._value_list) + collector('items', function=self._item_list) + collector('copy', function=self._self_get) + collector('__getitem__', function=self._value_get) + collector('__iter__', function=self._key_iter) + collector('update', function=self._self_set) + super(Dict, self).__init__(dict, collector.attributes) + + def _new_dict(self, args): + def do_create(holding=None): + if holding is None: + return get_dict() + type = holding.get_type() + if isinstance(type, Tuple) and len(type.get_holding_objects()) == 2: + return get_dict(*type.get_holding_objects()) + return _create_builtin(args, do_create) + + def _dict_add(self, context): + if self.keys is not None: + return + key, value = context.get_arguments(['self', 'key', 'value'])[1:] + if key is not None and key != pyobjects.get_unknown(): + context.save_per_name(get_tuple(key, value)) + + def _item_get(self, context): + if self.keys is not None: + return get_tuple(self.keys, self.values) + item = context.get_per_name() + if item is None or not isinstance(item.get_type(), Tuple): + return get_tuple(self.keys, self.values) + return item + + def _value_get(self, context): + item = self._item_get(context).get_type() + return item.get_holding_objects()[1] + + def _key_get(self, context): + item = self._item_get(context).get_type() + return item.get_holding_objects()[0] + + def _value_list(self, context): + return get_list(self._value_get(context)) + + def _key_list(self, context): + return get_list(self._key_get(context)) + + def _item_list(self, context): + return get_list(self._item_get(context)) + + def _value_iter(self, context): + return get_iterator(self._value_get(context)) + + def _key_iter(self, context): + return get_iterator(self._key_get(context)) + + def _item_iter(self, context): + return get_iterator(self._item_get(context)) + + def _self_get(self, context): + item = self._item_get(context).get_type() + key, value = item.get_holding_objects()[:2] + return get_dict(key, value) + + def _self_set(self, context): + if self.keys is not None: + return + new_dict = context.get_pynames(['self', 'd'])[1] + if new_dict and isinstance(new_dict.get_object().get_type(), Dict): + args = arguments.ObjectArguments([new_dict]) + items = new_dict.get_object()['popitem'].\ + get_object().get_returned_object(args) + context.save_per_name(items) + else: + holding = _infer_sequence_for_pyname(new_dict) + if holding is not None and isinstance(holding.get_type(), Tuple): + context.save_per_name(holding) + + +get_dict = _create_builtin_getter(Dict) +get_dict_type = _create_builtin_type_getter(Dict) + + +class Tuple(BuiltinClass): + + def __init__(self, *objects): + self.objects = objects + first = None + if objects: + first = objects[0] + attributes = { + '__getitem__': BuiltinName(BuiltinFunction(first)), + '__getslice__': BuiltinName(BuiltinFunction(pyobjects.PyObject(self))), + '__new__': BuiltinName(BuiltinFunction(function=self._new_tuple)), + '__iter__': BuiltinName(BuiltinFunction(get_iterator(first)))} + super(Tuple, self).__init__(tuple, attributes) + + def get_holding_objects(self): + return self.objects + + def _new_tuple(self, args): + return _create_builtin(args, get_tuple) + + +get_tuple = _create_builtin_getter(Tuple) +get_tuple_type = _create_builtin_type_getter(Tuple) + + +class Set(BuiltinClass): + + def __init__(self, holding=None): + self.holding = holding + collector = _AttributeCollector(set) + collector('__new__', function=self._new_set) + + self_methods = ['copy', 'difference', 'intersection', + 'symmetric_difference', 'union'] + for method in self_methods: + collector(method, function=self._self_get) + collector('add', function=self._set_add) + collector('update', function=self._self_set) + collector('update', function=self._self_set) + collector('symmetric_difference_update', function=self._self_set) + collector('difference_update', function=self._self_set) + + collector('pop', function=self._set_get) + collector('__iter__', function=self._iterator_get) + super(Set, self).__init__(set, collector.attributes) + + def _new_set(self, args): + return _create_builtin(args, get_set) + + def _set_add(self, context): + if self.holding is not None: + return + holding = context.get_arguments(['self', 'value'])[1] + if holding is not None and holding != pyobjects.get_unknown(): + context.save_per_name(holding) + + def _self_set(self, context): + if self.holding is not None: + return + iterable = context.get_pyname('iterable') + holding = _infer_sequence_for_pyname(iterable) + if holding is not None and holding != pyobjects.get_unknown(): + context.save_per_name(holding) + + def _set_get(self, context): + if self.holding is not None: + return self.holding + return context.get_per_name() + + def _iterator_get(self, context): + return get_iterator(self._set_get(context)) + + def _self_get(self, context): + return get_list(self._set_get(context)) + + +get_set = _create_builtin_getter(Set) +get_set_type = _create_builtin_type_getter(Set) + + +class Str(BuiltinClass): + + def __init__(self): + self_object = pyobjects.PyObject(self) + collector = _AttributeCollector(str) + collector('__iter__', get_iterator(self_object), check_existence=False) + + self_methods = ['__getitem__', '__getslice__', 'capitalize', 'center', + 'decode', 'encode', 'expandtabs', 'join', 'ljust', + 'lower', 'lstrip', 'replace', 'rjust', 'rstrip', 'strip', + 'swapcase', 'title', 'translate', 'upper', 'zfill'] + for method in self_methods: + collector(method, self_object) + + for method in ['rsplit', 'split', 'splitlines']: + collector(method, get_list(self_object)) + + super(Str, self).__init__(str, collector.attributes) + + def get_doc(self): + return str.__doc__ + + +get_str = _create_builtin_getter(Str) +get_str_type = _create_builtin_type_getter(Str) + + +class BuiltinName(pynames.PyName): + + def __init__(self, pyobject): + self.pyobject = pyobject + + def get_object(self): + return self.pyobject + + def get_definition_location(self): + return (None, None) + +class Iterator(pyobjects.AbstractClass): + + def __init__(self, holding=None): + super(Iterator, self).__init__() + self.holding = holding + self.attributes = { + 'next': BuiltinName(BuiltinFunction(self.holding)), + '__iter__': BuiltinName(BuiltinFunction(self))} + + def get_attributes(self): + return self.attributes + + def get_returned_object(self, args): + return self.holding + +get_iterator = _create_builtin_getter(Iterator) + + +class Generator(pyobjects.AbstractClass): + + def __init__(self, holding=None): + super(Generator, self).__init__() + self.holding = holding + self.attributes = { + 'next': BuiltinName(BuiltinFunction(self.holding)), + '__iter__': BuiltinName(BuiltinFunction(get_iterator(self.holding))), + 'close': BuiltinName(BuiltinFunction()), + 'send': BuiltinName(BuiltinFunction()), + 'throw': BuiltinName(BuiltinFunction())} + + def get_attributes(self): + return self.attributes + + def get_returned_object(self, args): + return self.holding + +get_generator = _create_builtin_getter(Generator) + + +class File(BuiltinClass): + + def __init__(self): + self_object = pyobjects.PyObject(self) + str_object = get_str() + str_list = get_list(get_str()) + attributes = {} + def add(name, returned=None, function=None): + builtin = getattr(file, name, None) + attributes[name] = BuiltinName( + BuiltinFunction(returned=returned, function=function, + builtin=builtin)) + add('__iter__', get_iterator(str_object)) + for method in ['next', 'read', 'readline', 'readlines']: + add(method, str_list) + for method in ['close', 'flush', 'lineno', 'isatty', 'seek', 'tell', + 'truncate', 'write', 'writelines']: + add(method) + super(File, self).__init__(file, attributes) + + +get_file = _create_builtin_getter(File) +get_file_type = _create_builtin_type_getter(File) + + +class Property(BuiltinClass): + + def __init__(self, fget=None, fset=None, fdel=None, fdoc=None): + self._fget = fget + self._fdoc = fdoc + attributes = { + 'fget': BuiltinName(BuiltinFunction()), + 'fset': BuiltinName(pynames.UnboundName()), + 'fdel': BuiltinName(pynames.UnboundName()), + '__new__': BuiltinName(BuiltinFunction(function=_property_function))} + super(Property, self).__init__(property, attributes) + + def get_property_object(self, args): + if isinstance(self._fget, pyobjects.AbstractFunction): + return self._fget.get_returned_object(args) + + +def _property_function(args): + parameters = args.get_arguments(['fget', 'fset', 'fdel', 'fdoc']) + return pyobjects.PyObject(Property(parameters[0])) + + +class Lambda(pyobjects.AbstractFunction): + + def __init__(self, node, scope): + super(Lambda, self).__init__() + self.node = node + self.arguments = node.args + self.scope = scope + + def get_returned_object(self, args): + result = rope.base.evaluate.eval_node(self.scope, self.node.body) + if result is not None: + return result.get_object() + else: + return pyobjects.get_unknown() + + def get_module(self): + return self.parent.get_module() + + def get_scope(self): + return self.scope + + def get_kind(self): + return 'lambda' + + def get_ast(self): + return self.node + + def get_attributes(self): + return {} + + def get_name(self): + return 'lambda' + + def get_param_names(self, special_args=True): + result = [node.id for node in self.arguments.args + if isinstance(node, ast.Name)] + if self.arguments.vararg: + result.append('*' + self.arguments.vararg) + if self.arguments.kwarg: + result.append('**' + self.arguments.kwarg) + return result + + @property + def parent(self): + return self.scope.pyobject + + +class BuiltinObject(BuiltinClass): + + def __init__(self): + super(BuiltinObject, self).__init__(object, {}) + + +class BuiltinType(BuiltinClass): + + def __init__(self): + super(BuiltinType, self).__init__(type, {}) + + +def _infer_sequence_for_pyname(pyname): + if pyname is None: + return None + seq = pyname.get_object() + args = arguments.ObjectArguments([pyname]) + if '__iter__' in seq: + obj = seq['__iter__'].get_object() + if not isinstance(obj, pyobjects.AbstractFunction): + return None + iter = obj.get_returned_object(args) + if iter is not None and 'next' in iter: + holding = iter['next'].get_object().\ + get_returned_object(args) + return holding + + +def _create_builtin(args, creator): + passed = args.get_pynames(['sequence'])[0] + if passed is None: + holding = None + else: + holding = _infer_sequence_for_pyname(passed) + if holding is not None: + return creator(holding) + else: + return creator() + + +def _range_function(args): + return get_list() + +def _reversed_function(args): + return _create_builtin(args, get_iterator) + +def _sorted_function(args): + return _create_builtin(args, get_list) + +def _super_function(args): + passed_class, passed_self = args.get_arguments(['type', 'self']) + if passed_self is None: + return passed_class + else: + #pyclass = passed_self.get_type() + pyclass = passed_class + if isinstance(pyclass, pyobjects.AbstractClass): + supers = pyclass.get_superclasses() + if supers: + return pyobjects.PyObject(supers[0]) + return passed_self + +def _zip_function(args): + args = args.get_pynames(['sequence']) + objects = [] + for seq in args: + if seq is None: + holding = None + else: + holding = _infer_sequence_for_pyname(seq) + objects.append(holding) + tuple = get_tuple(*objects) + return get_list(tuple) + +def _enumerate_function(args): + passed = args.get_pynames(['sequence'])[0] + if passed is None: + holding = None + else: + holding = _infer_sequence_for_pyname(passed) + tuple = get_tuple(None, holding) + return get_iterator(tuple) + +def _iter_function(args): + passed = args.get_pynames(['sequence'])[0] + if passed is None: + holding = None + else: + holding = _infer_sequence_for_pyname(passed) + return get_iterator(holding) + +def _input_function(args): + return get_str() + + +_initial_builtins = { + 'list': BuiltinName(get_list_type()), + 'dict': BuiltinName(get_dict_type()), + 'tuple': BuiltinName(get_tuple_type()), + 'set': BuiltinName(get_set_type()), + 'str': BuiltinName(get_str_type()), + 'file': BuiltinName(get_file_type()), + 'open': BuiltinName(get_file_type()), + 'unicode': BuiltinName(get_str_type()), + 'range': BuiltinName(BuiltinFunction(function=_range_function, builtin=range)), + 'reversed': BuiltinName(BuiltinFunction(function=_reversed_function, builtin=reversed)), + 'sorted': BuiltinName(BuiltinFunction(function=_sorted_function, builtin=sorted)), + 'super': BuiltinName(BuiltinFunction(function=_super_function, builtin=super)), + 'property': BuiltinName(BuiltinFunction(function=_property_function, builtin=property)), + 'zip': BuiltinName(BuiltinFunction(function=_zip_function, builtin=zip)), + 'enumerate': BuiltinName(BuiltinFunction(function=_enumerate_function, builtin=enumerate)), + 'object': BuiltinName(BuiltinObject()), + 'type': BuiltinName(BuiltinType()), + 'iter': BuiltinName(BuiltinFunction(function=_iter_function, builtin=iter)), + 'raw_input': BuiltinName(BuiltinFunction(function=_input_function, builtin=raw_input)), + } + +builtins = BuiltinModule('__builtin__', initial=_initial_builtins) diff -r e30544496575 -r 48cacfdc2ca6 vim/sadness/ropevim/src/rope/rope/base/change.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vim/sadness/ropevim/src/rope/rope/base/change.py Wed Oct 06 12:30:46 2010 -0400 @@ -0,0 +1,448 @@ +import datetime +import difflib +import os +import time +import warnings + +import rope.base.fscommands +from rope.base import taskhandle, exceptions, utils + + +class Change(object): + """The base class for changes + + Rope refactorings return `Change` objects. They can be previewed, + committed or undone. + """ + + def do(self, job_set=None): + """Perform the change + + .. note:: Do use this directly. Use `Project.do()` instead. + """ + + def undo(self, job_set=None): + """Perform the change + + .. note:: Do use this directly. Use `History.undo()` instead. + """ + + def get_description(self): + """Return the description of this change + + This can be used for previewing the changes. + """ + return str(self) + + def get_changed_resources(self): + """Return the list of resources that will be changed""" + return [] + + @property + @utils.saveit + def _operations(self): + return _ResourceOperations(self.resource.project) + + +class ChangeSet(Change): + """A collection of `Change` objects + + This class holds a collection of changes. This class provides + these fields: + + * `changes`: the list of changes + * `description`: the goal of these changes + """ + + def __init__(self, description, timestamp=None): + self.changes = [] + self.description = description + self.time = timestamp + + def do(self, job_set=taskhandle.NullJobSet()): + try: + done = [] + for change in self.changes: + change.do(job_set) + done.append(change) + self.time = time.time() + except Exception: + for change in done: + change.undo() + raise + + def undo(self, job_set=taskhandle.NullJobSet()): + try: + done = [] + for change in reversed(self.changes): + change.undo(job_set) + done.append(change) + except Exception: + for change in done: + change.do() + raise + + def add_change(self, change): + self.changes.append(change) + + def get_description(self): + result = [str(self) + ':\n\n\n'] + for change in self.changes: + result.append(change.get_description()) + result.append('\n') + return ''.join(result) + + def __str__(self): + if self.time is not None: + date = datetime.datetime.fromtimestamp(self.time) + if date.date() == datetime.date.today(): + string_date = 'today' + elif date.date() == (datetime.date.today() - datetime.timedelta(1)): + string_date = 'yesterday' + elif date.year == datetime.date.today().year: + string_date = date.strftime('%b %d') + else: + string_date = date.strftime('%d %b, %Y') + string_time = date.strftime('%H:%M:%S') + string_time = '%s %s ' % (string_date, string_time) + return self.description + ' - ' + string_time + return self.description + + def get_changed_resources(self): + result = set() + for change in self.changes: + result.update(change.get_changed_resources()) + return result + + +def _handle_job_set(function): + """A decorator for handling `taskhandle.JobSet`\s + + A decorator for handling `taskhandle.JobSet`\s for `do` and `undo` + methods of `Change`\s. + """ + def call(self, job_set=taskhandle.NullJobSet()): + job_set.started_job(str(self)) + function(self) + job_set.finished_job() + return call + + +class ChangeContents(Change): + """A class to change the contents of a file + + Fields: + + * `resource`: The `rope.base.resources.File` to change + * `new_contents`: What to write in the file + """ + + def __init__(self, resource, new_contents, old_contents=None): + self.resource = resource + # IDEA: Only saving diffs; possible problems when undo/redoing + self.new_contents = new_contents + self.old_contents = old_contents + + @_handle_job_set + def do(self): + if self.old_contents is None: + self.old_contents = self.resource.read() + self._operations.write_file(self.resource, self.new_contents) + + @_handle_job_set + def undo(self): + if self.old_contents is None: + raise exceptions.HistoryError( + 'Undoing a change that is not performed yet!') + self._operations.write_file(self.resource, self.old_contents) + + def __str__(self): + return 'Change <%s>' % self.resource.path + + def get_description(self): + new = self.new_contents + old = self.old_contents + if old is None: + if self.resource.exists(): + old = self.resource.read() + else: + old = '' + result = difflib.unified_diff( + old.splitlines(True), new.splitlines(True), + 'a/' + self.resource.path, 'b/' + self.resource.path) + return ''.join(list(result)) + + def get_changed_resources(self): + return [self.resource] + + +class MoveResource(Change): + """Move a resource to a new location + + Fields: + + * `resource`: The `rope.base.resources.Resource` to move + * `new_resource`: The destination for move; It is the moved + resource not the folder containing that resource. + """ + + def __init__(self, resource, new_location, exact=False): + self.project = resource.project + self.resource = resource + if not exact: + new_location = _get_destination_for_move(resource, new_location) + if resource.is_folder(): + self.new_resource = self.project.get_folder(new_location) + else: + self.new_resource = self.project.get_file(new_location) + + @_handle_job_set + def do(self): + self._operations.move(self.resource, self.new_resource) + + @_handle_job_set + def undo(self): + self._operations.move(self.new_resource, self.resource) + + def __str__(self): + return 'Move <%s>' % self.resource.path + + def get_description(self): + return 'rename from %s\nrename to %s' % (self.resource.path, + self.new_resource.path) + + def get_changed_resources(self): + return [self.resource, self.new_resource] + + +class CreateResource(Change): + """A class to create a resource + + Fields: + + * `resource`: The resource to create + """ + + def __init__(self, resource): + self.resource = resource + + @_handle_job_set + def do(self): + self._operations.create(self.resource) + + @_handle_job_set + def undo(self): + self._operations.remove(self.resource) + + def __str__(self): + return 'Create Resource <%s>' % (self.resource.path) + + def get_description(self): + return 'new file %s' % (self.resource.path) + + def get_changed_resources(self): + return [self.resource] + + def _get_child_path(self, parent, name): + if parent.path == '': + return name + else: + return parent.path + '/' + name + + +class CreateFolder(CreateResource): + """A class to create a folder + + See docs for `CreateResource`. + """ + + def __init__(self, parent, name): + resource = parent.project.get_folder(self._get_child_path(parent, name)) + super(CreateFolder, self).__init__(resource) + + +class CreateFile(CreateResource): + """A class to create a file + + See docs for `CreateResource`. + """ + + def __init__(self, parent, name): + resource = parent.project.get_file(self._get_child_path(parent, name)) + super(CreateFile, self).__init__(resource) + + +class RemoveResource(Change): + """A class to remove a resource + + Fields: + + * `resource`: The resource to be removed + """ + + def __init__(self, resource): + self.resource = resource + + @_handle_job_set + def do(self): + self._operations.remove(self.resource) + + # TODO: Undoing remove operations + @_handle_job_set + def undo(self): + raise NotImplementedError( + 'Undoing `RemoveResource` is not implemented yet.') + + def __str__(self): + return 'Remove <%s>' % (self.resource.path) + + def get_changed_resources(self): + return [self.resource] + + +def count_changes(change): + """Counts the number of basic changes a `Change` will make""" + if isinstance(change, ChangeSet): + result = 0 + for child in change.changes: + result += count_changes(child) + return result + return 1 + +def create_job_set(task_handle, change): + return task_handle.create_jobset(str(change), count_changes(change)) + + +class _ResourceOperations(object): + + def __init__(self, project): + self.project = project + self.fscommands = project.fscommands + self.direct_commands = rope.base.fscommands.FileSystemCommands() + + def _get_fscommands(self, resource): + if self.project.is_ignored(resource): + return self.direct_commands + return self.fscommands + + def write_file(self, resource, contents): + data = rope.base.fscommands.unicode_to_file_data(contents) + fscommands = self._get_fscommands(resource) + fscommands.write(resource.real_path, data) + for observer in list(self.project.observers): + observer.resource_changed(resource) + + def move(self, resource, new_resource): + fscommands = self._get_fscommands(resource) + fscommands.move(resource.real_path, new_resource.real_path) + for observer in list(self.project.observers): + observer.resource_moved(resource, new_resource) + + def create(self, resource): + if resource.is_folder(): + self._create_resource(resource.path, kind='folder') + else: + self._create_resource(resource.path) + for observer in list(self.project.observers): + observer.resource_created(resource) + + def remove(self, resource): + fscommands = self._get_fscommands(resource) + fscommands.remove(resource.real_path) + for observer in list(self.project.observers): + observer.resource_removed(resource) + + def _create_resource(self, file_name, kind='file'): + resource_path = self.project._get_resource_path(file_name) + if os.path.exists(resource_path): + raise exceptions.RopeError('Resource <%s> already exists' + % resource_path) + resource = self.project.get_file(file_name) + if not resource.parent.exists(): + raise exceptions.ResourceNotFoundError( + 'Parent folder of <%s> does not exist' % resource.path) + fscommands = self._get_fscommands(resource) + try: + if kind == 'file': + fscommands.create_file(resource_path) + else: + fscommands.create_folder(resource_path) + except IOError, e: + raise exceptions.RopeError(e) + + +def _get_destination_for_move(resource, destination): + dest_path = resource.project._get_resource_path(destination) + if os.path.isdir(dest_path): + if destination != '': + return destination + '/' + resource.name + else: + return resource.name + return destination + + +class ChangeToData(object): + + def convertChangeSet(self, change): + description = change.description + changes = [] + for child in change.changes: + changes.append(self(child)) + return (description, changes, change.time) + + def convertChangeContents(self, change): + return (change.resource.path, change.new_contents, change.old_contents) + + def convertMoveResource(self, change): + return (change.resource.path, change.new_resource.path) + + def convertCreateResource(self, change): + return (change.resource.path, change.resource.is_folder()) + + def convertRemoveResource(self, change): + return (change.resource.path, change.resource.is_folder()) + + def __call__(self, change): + change_type = type(change) + if change_type in (CreateFolder, CreateFile): + change_type = CreateResource + method = getattr(self, 'convert' + change_type.__name__) + return (change_type.__name__, method(change)) + + +class DataToChange(object): + + def __init__(self, project): + self.project = project + + def makeChangeSet(self, description, changes, time=None): + result = ChangeSet(description, time) + for child in changes: + result.add_change(self(child)) + return result + + def makeChangeContents(self, path, new_contents, old_contents): + resource = self.project.get_file(path) + return ChangeContents(resource, new_contents, old_contents) + + def makeMoveResource(self, old_path, new_path): + resource = self.project.get_file(old_path) + return MoveResource(resource, new_path, exact=True) + + def makeCreateResource(self, path, is_folder): + if is_folder: + resource = self.project.get_folder(path) + else: + resource = self.project.get_file(path) + return CreateResource(resource) + + def makeRemoveResource(self, path, is_folder): + if is_folder: + resource = self.project.get_folder(path) + else: + resource = self.project.get_file(path) + return RemoveResource(resource) + + def __call__(self, data): + method = getattr(self, 'make' + data[0]) + return method(*data[1]) diff -r e30544496575 -r 48cacfdc2ca6 vim/sadness/ropevim/src/rope/rope/base/codeanalyze.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vim/sadness/ropevim/src/rope/rope/base/codeanalyze.py Wed Oct 06 12:30:46 2010 -0400 @@ -0,0 +1,358 @@ +import bisect +import re +import token +import tokenize + + +class ChangeCollector(object): + + def __init__(self, text): + self.text = text + self.changes = [] + + def add_change(self, start, end, new_text=None): + if new_text is None: + new_text = self.text[start:end] + self.changes.append((start, end, new_text)) + + def get_changed(self): + if not self.changes: + return None + def compare_changes(change1, change2): + return cmp(change1[:2], change2[:2]) + self.changes.sort(compare_changes) + pieces = [] + last_changed = 0 + for change in self.changes: + start, end, text = change + pieces.append(self.text[last_changed:start] + text) + last_changed = end + if last_changed < len(self.text): + pieces.append(self.text[last_changed:]) + result = ''.join(pieces) + if result != self.text: + return result + + +class SourceLinesAdapter(object): + """Adapts source to Lines interface + + Note: The creation of this class is expensive. + """ + + def __init__(self, source_code): + self.code = source_code + self.starts = None + self._initialize_line_starts() + + def _initialize_line_starts(self): + self.starts = [] + self.starts.append(0) + try: + i = 0 + while True: + i = self.code.index('\n', i) + 1 + self.starts.append(i) + except ValueError: + pass + self.starts.append(len(self.code) + 1) + + def get_line(self, lineno): + return self.code[self.starts[lineno - 1]: + self.starts[lineno] - 1] + + def length(self): + return len(self.starts) - 1 + + def get_line_number(self, offset): + return bisect.bisect(self.starts, offset) + + def get_line_start(self, lineno): + return self.starts[lineno - 1] + + def get_line_end(self, lineno): + return self.starts[lineno] - 1 + + +class ArrayLinesAdapter(object): + + def __init__(self, lines): + self.lines = lines + + def get_line(self, line_number): + return self.lines[line_number - 1] + + def length(self): + return len(self.lines) + + +class LinesToReadline(object): + + def __init__(self, lines, start): + self.lines = lines + self.current = start + + def readline(self): + if self.current <= self.lines.length(): + self.current += 1 + return self.lines.get_line(self.current - 1) + '\n' + return '' + + def __call__(self): + return self.readline() + + +class _CustomGenerator(object): + + def __init__(self, lines): + self.lines = lines + self.in_string = '' + self.open_count = 0 + self.continuation = False + + def __call__(self): + size = self.lines.length() + result = [] + i = 1 + while i <= size: + while i <= size and not self.lines.get_line(i).strip(): + i += 1 + if i <= size: + start = i + while True: + line = self.lines.get_line(i) + self._analyze_line(line) + if not (self.continuation or self.open_count or + self.in_string) or i == size: + break + i += 1 + result.append((start, i)) + i += 1 + return result + + _main_chars = re.compile(r'[\'|"|#|\\|\[|\]|\{|\}|\(|\)]') + def _analyze_line(self, line): + char = None + for match in self._main_chars.finditer(line): + char = match.group() + i = match.start() + if char in '\'"': + if not self.in_string: + self.in_string = char + if char * 3 == line[i:i + 3]: + self.in_string = char * 3 + elif self.in_string == line[i:i + len(self.in_string)] and \ + not (i > 0 and line[i - 1] == '\\' and + not (i > 1 and line[i - 2] == '\\')): + self.in_string = '' + if self.in_string: + continue + if char == '#': + break + if char in '([{': + self.open_count += 1 + elif char in ')]}': + self.open_count -= 1 + if line and char != '#' and line.endswith('\\'): + self.continuation = True + else: + self.continuation = False + +def custom_generator(lines): + return _CustomGenerator(lines)() + + +class LogicalLineFinder(object): + + def __init__(self, lines): + self.lines = lines + + def logical_line_in(self, line_number): + indents = count_line_indents(self.lines.get_line(line_number)) + tries = 0 + while True: + block_start = get_block_start(self.lines, line_number, indents) + try: + return self._block_logical_line(block_start, line_number) + except IndentationError, e: + tries += 1 + if tries == 5: + raise e + lineno = e.lineno + block_start - 1 + indents = count_line_indents(self.lines.get_line(lineno)) + + def generate_starts(self, start_line=1, end_line=None): + for start, end in self.generate_regions(start_line, end_line): + yield start + + def generate_regions(self, start_line=1, end_line=None): + # XXX: `block_start` should be at a better position! + block_start = 1 + readline = LinesToReadline(self.lines, block_start) + shifted = start_line - block_start + 1 + try: + for start, end in self._logical_lines(readline): + real_start = start + block_start - 1 + real_start = self._first_non_blank(real_start) + if end_line is not None and real_start >= end_line: + break + real_end = end + block_start - 1 + if real_start >= start_line: + yield (real_start, real_end) + except tokenize.TokenError, e: + pass + + def _block_logical_line(self, block_start, line_number): + readline = LinesToReadline(self.lines, block_start) + shifted = line_number - block_start + 1 + region = self._calculate_logical(readline, shifted) + start = self._first_non_blank(region[0] + block_start - 1) + if region[1] is None: + end = self.lines.length() + else: + end = region[1] + block_start - 1 + return start, end + + def _calculate_logical(self, readline, line_number): + last_end = 1 + try: + for start, end in self._logical_lines(readline): + if line_number <= end: + return (start, end) + last_end = end + 1 + except tokenize.TokenError, e: + current = e.args[1][0] + return (last_end, max(last_end, current - 1)) + return (last_end, None) + + def _logical_lines(self, readline): + last_end = 1 + for current_token in tokenize.generate_tokens(readline): + current = current_token[2][0] + if current_token[0] == token.NEWLINE: + yield (last_end, current) + last_end = current + 1 + + def _first_non_blank(self, line_number): + current = line_number + while current < self.lines.length(): + line = self.lines.get_line(current).strip() + if line and not line.startswith('#'): + return current + current += 1 + return current + + +def tokenizer_generator(lines): + return LogicalLineFinder(lines).generate_regions() + + +class CachingLogicalLineFinder(object): + + def __init__(self, lines, generate=custom_generator): + self.lines = lines + self._generate = generate + + _starts = None + @property + def starts(self): + if self._starts is None: + self._init_logicals() + return self._starts + + _ends = None + @property + def ends(self): + if self._ends is None: + self._init_logicals() + return self._ends + + def _init_logicals(self): + """Should initialize _starts and _ends attributes""" + size = self.lines.length() + 1 + self._starts = [None] * size + self._ends = [None] * size + for start, end in self._generate(self.lines): + self._starts[start] = True + self._ends[end] = True + + def logical_line_in(self, line_number): + start = line_number + while start > 0 and not self.starts[start]: + start -= 1 + if start == 0: + try: + start = self.starts.index(True, line_number) + except ValueError: + return (line_number, line_number) + return (start, self.ends.index(True, start)) + + def generate_starts(self, start_line=1, end_line=None): + if end_line is None: + end_line = self.lines.length() + for index in range(start_line, end_line): + if self.starts[index]: + yield index + + +def get_block_start(lines, lineno, maximum_indents=80): + """Approximate block start""" + pattern = get_block_start_patterns() + for i in range(lineno, 0, -1): + match = pattern.search(lines.get_line(i)) + if match is not None and \ + count_line_indents(lines.get_line(i)) <= maximum_indents: + striped = match.string.lstrip() + # Maybe we're in a list comprehension or generator expression + if i > 1 and striped.startswith('if') or striped.startswith('for'): + bracs = 0 + for j in range(i, min(i + 5, lines.length() + 1)): + for c in lines.get_line(j): + if c == '#': + break + if c in '[(': + bracs += 1 + if c in ')]': + bracs -= 1 + if bracs < 0: + break + if bracs < 0: + break + if bracs < 0: + continue + return i + return 1 + + +_block_start_pattern = None + +def get_block_start_patterns(): + global _block_start_pattern + if not _block_start_pattern: + pattern = '^\\s*(((def|class|if|elif|except|for|while|with)\\s)|'\ + '((try|else|finally|except)\\s*:))' + _block_start_pattern = re.compile(pattern, re.M) + return _block_start_pattern + + +def count_line_indents(line): + indents = 0 + for char in line: + if char == ' ': + indents += 1 + elif char == '\t': + indents += 8 + else: + return indents + return 0 + + +def get_string_pattern(): + start = r'(\b[uU]?[rR]?)?' + longstr = r'%s"""(\\.|"(?!"")|\\\n|[^"\\])*"""' % start + shortstr = r'%s"(\\.|[^"\\\n])*"' % start + return '|'.join([longstr, longstr.replace('"', "'"), + shortstr, shortstr.replace('"', "'")]) + +def get_comment_pattern(): + return r'#[^\n]*' diff -r e30544496575 -r 48cacfdc2ca6 vim/sadness/ropevim/src/rope/rope/base/default_config.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vim/sadness/ropevim/src/rope/rope/base/default_config.py Wed Oct 06 12:30:46 2010 -0400 @@ -0,0 +1,85 @@ +# The default ``config.py`` + + +def set_prefs(prefs): + """This function is called before opening the project""" + + # Specify which files and folders to ignore in the project. + # Changes to ignored resources are not added to the history and + # VCSs. Also they are not returned in `Project.get_files()`. + # Note that ``?`` and ``*`` match all characters but slashes. + # '*.pyc': matches 'test.pyc' and 'pkg/test.pyc' + # 'mod*.pyc': matches 'test/mod1.pyc' but not 'mod/1.pyc' + # '.svn': matches 'pkg/.svn' and all of its children + # 'build/*.o': matches 'build/lib.o' but not 'build/sub/lib.o' + # 'build//*.o': matches 'build/lib.o' and 'build/sub/lib.o' + prefs['ignored_resources'] = ['*.pyc', '*~', '.ropeproject', + '.hg', '.svn', '_svn', '.git'] + + # Specifies which files should be considered python files. It is + # useful when you have scripts inside your project. Only files + # ending with ``.py`` are considered to be python files by + # default. + #prefs['python_files'] = ['*.py'] + + # Custom source folders: By default rope searches the project + # for finding source folders (folders that should be searched + # for finding modules). You can add paths to that list. Note + # that rope guesses project source folders correctly most of the + # time; use this if you have any problems. + # The folders should be relative to project root and use '/' for + # separating folders regardless of the platform rope is running on. + # 'src/my_source_folder' for instance. + #prefs.add('source_folders', 'src') + + # You can extend python path for looking up modules + #prefs.add('python_path', '~/python/') + + # Should rope save object information or not. + prefs['save_objectdb'] = True + prefs['compress_objectdb'] = False + + # If `True`, rope analyzes each module when it is being saved. + prefs['automatic_soa'] = True + # The depth of calls to follow in static object analysis + prefs['soa_followed_calls'] = 0 + + # If `False` when running modules or unit tests "dynamic object + # analysis" is turned off. This makes them much faster. + prefs['perform_doa'] = True + + # Rope can check the validity of its object DB when running. + prefs['validate_objectdb'] = True + + # How many undos to hold? + prefs['max_history_items'] = 32 + + # Shows whether to save history across sessions. + prefs['save_history'] = True + prefs['compress_history'] = False + + # Set the number spaces used for indenting. According to + # :PEP:`8`, it is best to use 4 spaces. Since most of rope's + # unit-tests use 4 spaces it is more reliable, too. + prefs['indent_size'] = 4 + + # Builtin and c-extension modules that are allowed to be imported + # and inspected by rope. + prefs['extension_modules'] = [] + + # Add all standard c-extensions to extension_modules list. + prefs['import_dynload_stdmods'] = True + + # If `True` modules with syntax errors are considered to be empty. + # The default value is `False`; When `False` syntax errors raise + # `rope.base.exceptions.ModuleSyntaxError` exception. + prefs['ignore_syntax_errors'] = False + + # If `True`, rope ignores unresolvable imports. Otherwise, they + # appear in the importing namespace. + prefs['ignore_bad_imports'] = False + + +def project_opened(project): + """This function is called after opening the project""" + # Do whatever you like here! diff -r e30544496575 -r 48cacfdc2ca6 vim/sadness/ropevim/src/rope/rope/base/evaluate.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vim/sadness/ropevim/src/rope/rope/base/evaluate.py Wed Oct 06 12:30:46 2010 -0400 @@ -0,0 +1,321 @@ +import rope.base.builtins +import rope.base.pynames +import rope.base.pyobjects +from rope.base import ast, astutils, exceptions, pyobjects, arguments, worder + + +BadIdentifierError = exceptions.BadIdentifierError + +def eval_location(pymodule, offset): + """Find the pyname at the offset""" + return eval_location2(pymodule, offset)[1] + + +def eval_location2(pymodule, offset): + """Find the primary and pyname at offset""" + pyname_finder = ScopeNameFinder(pymodule) + return pyname_finder.get_primary_and_pyname_at(offset) + + +def eval_node(scope, node): + """Evaluate a `ast.AST` node and return a PyName + + Return `None` if the expression cannot be evaluated. + """ + return eval_node2(scope, node)[1] + + +def eval_node2(scope, node): + evaluator = StatementEvaluator(scope) + ast.walk(node, evaluator) + return evaluator.old_result, evaluator.result + + +def eval_str(holding_scope, name): + return eval_str2(holding_scope, name)[1] + + +def eval_str2(holding_scope, name): + try: + # parenthesizing for handling cases like 'a_var.\nattr' + node = ast.parse('(%s)' % name) + except SyntaxError: + raise BadIdentifierError('Not a resolvable python identifier selected.') + return eval_node2(holding_scope, node) + + +class ScopeNameFinder(object): + + def __init__(self, pymodule): + self.module_scope = pymodule.get_scope() + self.lines = pymodule.lines + self.worder = worder.Worder(pymodule.source_code, True) + + def _is_defined_in_class_body(self, holding_scope, offset, lineno): + if lineno == holding_scope.get_start() and \ + holding_scope.parent is not None and \ + holding_scope.parent.get_kind() == 'Class' and \ + self.worder.is_a_class_or_function_name_in_header(offset): + return True + if lineno != holding_scope.get_start() and \ + holding_scope.get_kind() == 'Class' and \ + self.worder.is_name_assigned_in_class_body(offset): + return True + return False + + def _is_function_name_in_function_header(self, scope, offset, lineno): + if scope.get_start() <= lineno <= scope.get_body_start() and \ + scope.get_kind() == 'Function' and \ + self.worder.is_a_class_or_function_name_in_header(offset): + return True + return False + + def get_pyname_at(self, offset): + return self.get_primary_and_pyname_at(offset)[1] + + def get_primary_and_pyname_at(self, offset): + lineno = self.lines.get_line_number(offset) + holding_scope = self.module_scope.get_inner_scope_for_line(lineno) + # function keyword parameter + if self.worder.is_function_keyword_parameter(offset): + keyword_name = self.worder.get_word_at(offset) + pyobject = self.get_enclosing_function(offset) + if isinstance(pyobject, pyobjects.PyFunction): + return (None, pyobject.get_parameters().get(keyword_name, None)) + # class body + if self._is_defined_in_class_body(holding_scope, offset, lineno): + class_scope = holding_scope + if lineno == holding_scope.get_start(): + class_scope = holding_scope.parent + name = self.worder.get_primary_at(offset).strip() + try: + return (None, class_scope.pyobject[name]) + except rope.base.exceptions.AttributeNotFoundError: + return (None, None) + # function header + if self._is_function_name_in_function_header(holding_scope, offset, lineno): + name = self.worder.get_primary_at(offset).strip() + return (None, holding_scope.parent[name]) + # from statement module + if self.worder.is_from_statement_module(offset): + module = self.worder.get_primary_at(offset) + module_pyname = self._find_module(module) + return (None, module_pyname) + if self.worder.is_from_aliased(offset): + name = self.worder.get_from_aliased(offset) + else: + name = self.worder.get_primary_at(offset) + return eval_str2(holding_scope, name) + + def get_enclosing_function(self, offset): + function_parens = self.worder.find_parens_start_from_inside(offset) + try: + function_pyname = self.get_pyname_at(function_parens - 1) + except BadIdentifierError: + function_pyname = None + if function_pyname is not None: + pyobject = function_pyname.get_object() + if isinstance(pyobject, pyobjects.AbstractFunction): + return pyobject + elif isinstance(pyobject, pyobjects.AbstractClass) and \ + '__init__' in pyobject: + return pyobject['__init__'].get_object() + elif '__call__' in pyobject: + return pyobject['__call__'].get_object() + return None + + def _find_module(self, module_name): + dots = 0 + while module_name[dots] == '.': + dots += 1 + return rope.base.pynames.ImportedModule( + self.module_scope.pyobject, module_name[dots:], dots) + + +class StatementEvaluator(object): + + def __init__(self, scope): + self.scope = scope + self.result = None + self.old_result = None + + def _Name(self, node): + self.result = self.scope.lookup(node.id) + + def _Attribute(self, node): + pyname = eval_node(self.scope, node.value) + if pyname is None: + pyname = rope.base.pynames.UnboundName() + self.old_result = pyname + if pyname.get_object() != rope.base.pyobjects.get_unknown(): + try: + self.result = pyname.get_object()[node.attr] + except exceptions.AttributeNotFoundError: + self.result = None + + def _Call(self, node): + primary, pyobject = self._get_primary_and_object_for_node(node.func) + if pyobject is None: + return + def _get_returned(pyobject): + args = arguments.create_arguments(primary, pyobject, + node, self.scope) + return pyobject.get_returned_object(args) + if isinstance(pyobject, rope.base.pyobjects.AbstractClass): + result = None + if '__new__' in pyobject: + new_function = pyobject['__new__'].get_object() + result = _get_returned(new_function) + if result is None or \ + result == rope.base.pyobjects.get_unknown(): + result = rope.base.pyobjects.PyObject(pyobject) + self.result = rope.base.pynames.UnboundName(pyobject=result) + return + + pyfunction = None + if isinstance(pyobject, rope.base.pyobjects.AbstractFunction): + pyfunction = pyobject + elif '__call__' in pyobject: + pyfunction = pyobject['__call__'].get_object() + if pyfunction is not None: + self.result = rope.base.pynames.UnboundName( + pyobject=_get_returned(pyfunction)) + + def _Str(self, node): + self.result = rope.base.pynames.UnboundName( + pyobject=rope.base.builtins.get_str()) + + def _Num(self, node): + type_name = type(node.n).__name__ + self.result = self._get_builtin_name(type_name) + + def _get_builtin_name(self, type_name): + pytype = rope.base.builtins.builtins[type_name].get_object() + return rope.base.pynames.UnboundName( + rope.base.pyobjects.PyObject(pytype)) + + def _BinOp(self, node): + self.result = rope.base.pynames.UnboundName( + self._get_object_for_node(node.left)) + + def _BoolOp(self, node): + pyobject = self._get_object_for_node(node.values[0]) + if pyobject is None: + pyobject = self._get_object_for_node(node.values[1]) + self.result = rope.base.pynames.UnboundName(pyobject) + + def _Repr(self, node): + self.result = self._get_builtin_name('str') + + def _UnaryOp(self, node): + self.result = rope.base.pynames.UnboundName( + self._get_object_for_node(node.operand)) + + def _Compare(self, node): + self.result = self._get_builtin_name('bool') + + def _Dict(self, node): + keys = None + values = None + if node.keys: + keys = self._get_object_for_node(node.keys[0]) + values = self._get_object_for_node(node.values[0]) + self.result = rope.base.pynames.UnboundName( + pyobject=rope.base.builtins.get_dict(keys, values)) + + def _List(self, node): + holding = None + if node.elts: + holding = self._get_object_for_node(node.elts[0]) + self.result = rope.base.pynames.UnboundName( + pyobject=rope.base.builtins.get_list(holding)) + + def _ListComp(self, node): + pyobject = self._what_does_comprehension_hold(node) + self.result = rope.base.pynames.UnboundName( + pyobject=rope.base.builtins.get_list(pyobject)) + + def _GeneratorExp(self, node): + pyobject = self._what_does_comprehension_hold(node) + self.result = rope.base.pynames.UnboundName( + pyobject=rope.base.builtins.get_iterator(pyobject)) + + def _what_does_comprehension_hold(self, node): + scope = self._make_comprehension_scope(node) + pyname = eval_node(scope, node.elt) + return pyname.get_object() if pyname is not None else None + + def _make_comprehension_scope(self, node): + scope = self.scope + module = scope.pyobject.get_module() + names = {} + for comp in node.generators: + new_names = _get_evaluated_names(comp.target, comp.iter, module, + '.__iter__().next()', node.lineno) + names.update(new_names) + return rope.base.pyscopes.TemporaryScope(scope.pycore, scope, names) + + def _Tuple(self, node): + objects = [] + if len(node.elts) < 4: + for stmt in node.elts: + pyobject = self._get_object_for_node(stmt) + objects.append(pyobject) + else: + objects.append(self._get_object_for_node(node.elts[0])) + self.result = rope.base.pynames.UnboundName( + pyobject=rope.base.builtins.get_tuple(*objects)) + + def _get_object_for_node(self, stmt): + pyname = eval_node(self.scope, stmt) + pyobject = None + if pyname is not None: + pyobject = pyname.get_object() + return pyobject + + def _get_primary_and_object_for_node(self, stmt): + primary, pyname = eval_node2(self.scope, stmt) + pyobject = None + if pyname is not None: + pyobject = pyname.get_object() + return primary, pyobject + + def _Subscript(self, node): + if isinstance(node.slice, ast.Index): + self._call_function(node.value, '__getitem__', + [node.slice.value]) + elif isinstance(node.slice, ast.Slice): + self._call_function(node.value, '__getslice__') + + def _call_function(self, node, function_name, other_args=None): + pyname = eval_node(self.scope, node) + if pyname is not None: + pyobject = pyname.get_object() + else: + return + if function_name in pyobject: + called = pyobject[function_name].get_object() + if not called or not isinstance(called, pyobjects.AbstractFunction): + return + args = [node] + if other_args: + args += other_args + arguments_ = arguments.Arguments(args, self.scope) + self.result = rope.base.pynames.UnboundName( + pyobject=called.get_returned_object(arguments_)) + + def _Lambda(self, node): + self.result = rope.base.pynames.UnboundName( + pyobject=rope.base.builtins.Lambda(node, self.scope)) + + +def _get_evaluated_names(targets, assigned, module, evaluation, lineno): + result = {} + for name, levels in astutils.get_name_levels(targets): + assignment = rope.base.pynames.AssignmentValue(assigned, levels, + evaluation) + # XXX: this module should not access `rope.base.pynamesdef`! + pyname = rope.base.pynamesdef.AssignedName(lineno, module) + pyname.assignments.append(assignment) + result[name] = pyname + return result diff -r e30544496575 -r 48cacfdc2ca6 vim/sadness/ropevim/src/rope/rope/base/exceptions.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vim/sadness/ropevim/src/rope/rope/base/exceptions.py Wed Oct 06 12:30:46 2010 -0400 @@ -0,0 +1,61 @@ +class RopeError(Exception): + """Base exception for rope""" + + +class ResourceNotFoundError(RopeError): + """Resource not found exception""" + + +class RefactoringError(RopeError): + """Errors for performing a refactoring""" + + +class InterruptedTaskError(RopeError): + """The task has been interrupted""" + + +class HistoryError(RopeError): + """Errors for history undo/redo operations""" + + +class ModuleNotFoundError(RopeError): + """Module not found exception""" + + +class AttributeNotFoundError(RopeError): + """Attribute not found exception""" + + +class NameNotFoundError(RopeError): + """Name not found exception""" + + +class BadIdentifierError(RopeError): + """The name cannot be resolved""" + + +class ModuleSyntaxError(RopeError): + """Module has syntax errors + + The `filename` and `lineno` fields indicate where the error has + occurred. + + """ + + def __init__(self, filename, lineno, message): + self.filename = filename + self.lineno = lineno + self.message_ = message + super(ModuleSyntaxError, self).__init__( + 'Syntax error in file <%s> line <%s>: %s' % + (filename, lineno, message)) + + +class ModuleDecodeError(RopeError): + """Cannot decode module""" + + def __init__(self, filename, message): + self.filename = filename + self.message_ = message + super(ModuleDecodeError, self).__init__( + 'Cannot decode file <%s>: %s' % (filename, message)) diff -r e30544496575 -r 48cacfdc2ca6 vim/sadness/ropevim/src/rope/rope/base/fscommands.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vim/sadness/ropevim/src/rope/rope/base/fscommands.py Wed Oct 06 12:30:46 2010 -0400 @@ -0,0 +1,268 @@ +"""Project file system commands. + +This modules implements file system operations used by rope. Different +version control systems can be supported by implementing the interface +provided by `FileSystemCommands` class. See `SubversionCommands` and +`MercurialCommands` for example. + +""" +import os +import shutil +import subprocess + + +def create_fscommands(root): + dirlist = os.listdir(root) + commands = {'.hg': MercurialCommands, + '.svn': SubversionCommands, + '.git': GITCommands, + '_svn': SubversionCommands, + '_darcs': DarcsCommands} + for key in commands: + if key in dirlist: + try: + return commands[key](root) + except (ImportError, OSError): + pass + return FileSystemCommands() + + +class FileSystemCommands(object): + + def create_file(self, path): + open(path, 'w').close() + + def create_folder(self, path): + os.mkdir(path) + + def move(self, path, new_location): + shutil.move(path, new_location) + + def remove(self, path): + if os.path.isfile(path): + os.remove(path) + else: + shutil.rmtree(path) + + def write(self, path, data): + file_ = open(path, 'wb') + try: + file_.write(data) + finally: + file_.close() + + +class SubversionCommands(object): + + def __init__(self, *args): + self.normal_actions = FileSystemCommands() + import pysvn + self.client = pysvn.Client() + + def create_file(self, path): + self.normal_actions.create_file(path) + self.client.add(path, force=True) + + def create_folder(self, path): + self.normal_actions.create_folder(path) + self.client.add(path, force=True) + + def move(self, path, new_location): + self.client.move(path, new_location, force=True) + + def remove(self, path): + self.client.remove(path, force=True) + + def write(self, path, data): + self.normal_actions.write(path, data) + + +class MercurialCommands(object): + + def __init__(self, root): + self.hg = self._import_mercurial() + self.normal_actions = FileSystemCommands() + try: + self.ui = self.hg.ui.ui( + verbose=False, debug=False, quiet=True, + interactive=False, traceback=False, report_untrusted=False) + except: + self.ui = self.hg.ui.ui() + self.ui.setconfig('ui', 'interactive', 'no') + self.ui.setconfig('ui', 'debug', 'no') + self.ui.setconfig('ui', 'traceback', 'no') + self.ui.setconfig('ui', 'verbose', 'no') + self.ui.setconfig('ui', 'report_untrusted', 'no') + self.ui.setconfig('ui', 'quiet', 'yes') + self.ui.setconfig('extensions', 'progress', '!') + + self.repo = self.hg.hg.repository(self.ui, root) + + def _import_mercurial(self): + import mercurial.commands + import mercurial.hg + import mercurial.ui + return mercurial + + def create_file(self, path): + self.normal_actions.create_file(path) + self.hg.commands.add(self.ui, self.repo, path) + + def create_folder(self, path): + self.normal_actions.create_folder(path) + + def move(self, path, new_location): + self.hg.commands.rename(self.ui, self.repo, path, + new_location, after=False) + + def remove(self, path): + self.hg.commands.remove(self.ui, self.repo, path) + + def write(self, path, data): + self.normal_actions.write(path, data) + + +class GITCommands(object): + + def __init__(self, root): + self.root = root + self._do(['version']) + self.normal_actions = FileSystemCommands() + + def create_file(self, path): + self.normal_actions.create_file(path) + self._do(['add', self._in_dir(path)]) + + def create_folder(self, path): + self.normal_actions.create_folder(path) + + def move(self, path, new_location): + self._do(['mv', self._in_dir(path), self._in_dir(new_location)]) + + def remove(self, path): + self._do(['rm', self._in_dir(path)]) + + def write(self, path, data): + # XXX: should we use ``git add``? + self.normal_actions.write(path, data) + + def _do(self, args): + _execute(['git'] + args, cwd=self.root) + + def _in_dir(self, path): + if path.startswith(self.root): + return path[len(self.root) + 1:] + return self.root + + +class DarcsCommands(object): + + def __init__(self, root): + self.root = root + self.normal_actions = FileSystemCommands() + + def create_file(self, path): + self.normal_actions.create_file(path) + self._do(['add', path]) + + def create_folder(self, path): + self.normal_actions.create_folder(path) + self._do(['add', path]) + + def move(self, path, new_location): + self._do(['mv', path, new_location]) + + def remove(self, path): + self.normal_actions.remove(path) + + def write(self, path, data): + self.normal_actions.write(path, data) + + def _do(self, args): + _execute(['darcs'] + args, cwd=self.root) + + +def _execute(args, cwd=None): + process = subprocess.Popen(args, cwd=cwd, stdout=subprocess.PIPE) + process.wait() + return process.returncode + + +def unicode_to_file_data(contents, encoding=None): + if not isinstance(contents, unicode): + return contents + if encoding is None: + encoding = read_str_coding(contents) + if encoding is not None: + return contents.encode(encoding) + try: + return contents.encode() + except UnicodeEncodeError: + return contents.encode('utf-8') + +def file_data_to_unicode(data, encoding=None): + result = _decode_data(data, encoding) + if '\r' in result: + result = result.replace('\r\n', '\n').replace('\r', '\n') + return result + +def _decode_data(data, encoding): + if isinstance(data, unicode): + return data + if encoding is None: + encoding = read_str_coding(data) + if encoding is None: + # there is no encoding tip, we need to guess. + # PEP263 says that "encoding not explicitly defined" means it is ascii, + # but we will use utf8 instead since utf8 fully covers ascii and btw is + # the only non-latin sane encoding. + encoding = 'utf-8' + try: + return data.decode(encoding) + except (UnicodeError, LookupError): + # fallback to latin1: it should never fail + return data.decode('latin1') + + +def read_file_coding(path): + file = open(path, 'b') + count = 0 + result = [] + buffsize = 10 + while True: + current = file.read(10) + if not current: + break + count += current.count('\n') + result.append(current) + file.close() + return _find_coding(''.join(result)) + + +def read_str_coding(source): + try: + first = source.index('\n') + 1 + second = source.index('\n', first) + 1 + except ValueError: + second = len(source) + return _find_coding(source[:second]) + + +def _find_coding(text): + coding = 'coding' + try: + start = text.index(coding) + len(coding) + if text[start] not in '=:': + return + start += 1 + while start < len(text) and text[start].isspace(): + start += 1 + end = start + while end < len(text): + c = text[end] + if not c.isalnum() and c not in '-_': + break + end += 1 + return text[start:end] + except ValueError: + pass diff -r e30544496575 -r 48cacfdc2ca6 vim/sadness/ropevim/src/rope/rope/base/history.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vim/sadness/ropevim/src/rope/rope/base/history.py Wed Oct 06 12:30:46 2010 -0400 @@ -0,0 +1,235 @@ +from rope.base import exceptions, change, taskhandle + + +class History(object): + """A class that holds project history""" + + def __init__(self, project, maxundos=None): + self.project = project + self._undo_list = [] + self._redo_list = [] + self._maxundos = maxundos + self._load_history() + self.project.data_files.add_write_hook(self.write) + self.current_change = None + + def _load_history(self): + if self.save: + result = self.project.data_files.read_data( + 'history', compress=self.compress, import_=True) + if result is not None: + to_change = change.DataToChange(self.project) + for data in result[0]: + self._undo_list.append(to_change(data)) + for data in result[1]: + self._redo_list.append(to_change(data)) + + def do(self, changes, task_handle=taskhandle.NullTaskHandle()): + """Perform the change and add it to the `self.undo_list` + + Note that uninteresting changes (changes to ignored files) + will not be appended to `self.undo_list`. + + """ + try: + self.current_change = changes + changes.do(change.create_job_set(task_handle, changes)) + finally: + self.current_change = None + if self._is_change_interesting(changes): + self.undo_list.append(changes) + self._remove_extra_items() + del self.redo_list[:] + + def _remove_extra_items(self): + if len(self.undo_list) > self.max_undos: + del self.undo_list[0:len(self.undo_list) - self.max_undos] + + def _is_change_interesting(self, changes): + for resource in changes.get_changed_resources(): + if not self.project.is_ignored(resource): + return True + return False + + def undo(self, change=None, drop=False, + task_handle=taskhandle.NullTaskHandle()): + """Redo done changes from the history + + When `change` is `None`, the last done change will be undone. + If change is not `None` it should be an item from + `self.undo_list`; this change and all changes that depend on + it will be undone. In both cases the list of undone changes + will be returned. + + If `drop` is `True`, the undone change will not be appended to + the redo list. + + """ + if not self._undo_list: + raise exceptions.HistoryError('Undo list is empty') + if change is None: + change = self.undo_list[-1] + dependencies = self._find_dependencies(self.undo_list, change) + self._move_front(self.undo_list, dependencies) + self._perform_undos(len(dependencies), task_handle) + result = self.redo_list[-len(dependencies):] + if drop: + del self.redo_list[-len(dependencies):] + return result + + def redo(self, change=None, task_handle=taskhandle.NullTaskHandle()): + """Redo undone changes from the history + + When `change` is `None`, the last undone change will be + redone. If change is not `None` it should be an item from + `self.redo_list`; this change and all changes that depend on + it will be redone. In both cases the list of redone changes + will be returned. + + """ + if not self.redo_list: + raise exceptions.HistoryError('Redo list is empty') + if change is None: + change = self.redo_list[-1] + dependencies = self._find_dependencies(self.redo_list, change) + self._move_front(self.redo_list, dependencies) + self._perform_redos(len(dependencies), task_handle) + return self.undo_list[-len(dependencies):] + + def _move_front(self, change_list, changes): + for change in changes: + change_list.remove(change) + change_list.append(change) + + def _find_dependencies(self, change_list, change): + index = change_list.index(change) + return _FindChangeDependencies(change_list[index:])() + + def _perform_undos(self, count, task_handle): + for i in range(count): + self.current_change = self.undo_list[-1] + try: + job_set = change.create_job_set(task_handle, + self.current_change) + self.current_change.undo(job_set) + finally: + self.current_change = None + self.redo_list.append(self.undo_list.pop()) + + def _perform_redos(self, count, task_handle): + for i in range(count): + self.current_change = self.redo_list[-1] + try: + job_set = change.create_job_set(task_handle, + self.current_change) + self.current_change.do(job_set) + finally: + self.current_change = None + self.undo_list.append(self.redo_list.pop()) + + def contents_before_current_change(self, file): + if self.current_change is None: + return None + result = self._search_for_change_contents([self.current_change], file) + if result is not None: + return result + if file.exists() and not file.is_folder(): + return file.read() + else: + return None + + def _search_for_change_contents(self, change_list, file): + for change_ in reversed(change_list): + if isinstance(change_, change.ChangeSet): + result = self._search_for_change_contents(change_.changes, + file) + if result is not None: + return result + if isinstance(change_, change.ChangeContents) and \ + change_.resource == file: + return change_.old_contents + + def write(self): + if self.save: + data = [] + to_data = change.ChangeToData() + self._remove_extra_items() + data.append([to_data(change_) for change_ in self.undo_list]) + data.append([to_data(change_) for change_ in self.redo_list]) + self.project.data_files.write_data('history', data, + compress=self.compress) + + def get_file_undo_list(self, resource): + result = [] + for change in self.undo_list: + if resource in change.get_changed_resources(): + result.append(change) + return result + + def __str__(self): + return 'History holds %s changes in memory' % \ + (len(self.undo_list) + len(self.redo_list)) + + undo_list = property(lambda self: self._undo_list) + redo_list = property(lambda self: self._redo_list) + + @property + def tobe_undone(self): + """The last done change if available, `None` otherwise""" + if self.undo_list: + return self.undo_list[-1] + + @property + def tobe_redone(self): + """The last undone change if available, `None` otherwise""" + if self.redo_list: + return self.redo_list[-1] + + @property + def max_undos(self): + if self._maxundos is None: + return self.project.prefs.get('max_history_items', 100) + else: + return self._maxundos + + @property + def save(self): + return self.project.prefs.get('save_history', False) + + @property + def compress(self): + return self.project.prefs.get('compress_history', False) + + def clear(self): + """Forget all undo and redo information""" + del self.undo_list[:] + del self.redo_list[:] + + +class _FindChangeDependencies(object): + + def __init__(self, change_list): + self.change = change_list[0] + self.change_list = change_list + self.changed_resources = set(self.change.get_changed_resources()) + + def __call__(self): + result = [self.change] + for change in self.change_list[1:]: + if self._depends_on(change, result): + result.append(change) + self.changed_resources.update(change.get_changed_resources()) + return result + + def _depends_on(self, changes, result): + for resource in changes.get_changed_resources(): + if resource is None: + continue + if resource in self.changed_resources: + return True + for changed in self.changed_resources: + if resource.is_folder() and resource.contains(changed): + return True + if changed.is_folder() and changed.contains(resource): + return True + return False diff -r e30544496575 -r 48cacfdc2ca6 vim/sadness/ropevim/src/rope/rope/base/libutils.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vim/sadness/ropevim/src/rope/rope/base/libutils.py Wed Oct 06 12:30:46 2010 -0400 @@ -0,0 +1,65 @@ +"""A few useful functions for using rope as a library""" +import os.path + +import rope.base.project +import rope.base.pycore +from rope.base import taskhandle + + +def path_to_resource(project, path, type=None): + """Get the resource at path + + You only need to specify `type` if `path` does not exist. It can + be either 'file' or 'folder'. If the type is `None` it is assumed + that the resource already exists. + + Note that this function uses `Project.get_resource()`, + `Project.get_file()`, and `Project.get_folder()` methods. + + """ + project_path = relative(project.address, path) + if project_path is None: + project_path = rope.base.project._realpath(path) + project = rope.base.project.get_no_project() + if type is None: + return project.get_resource(project_path) + if type == 'file': + return project.get_file(project_path) + if type == 'folder': + return project.get_folder(project_path) + return None + +def relative(root, path): + root = rope.base.project._realpath(root).replace(os.path.sep, '/') + path = rope.base.project._realpath(path).replace(os.path.sep, '/') + if path == root: + return '' + if path.startswith(root + '/'): + return path[len(root) + 1:] + +def report_change(project, path, old_content): + """Report that the contents of file at `path` was changed + + The new contents of file is retrieved by reading the file. + + """ + resource = path_to_resource(project, path) + if resource is None: + return + for observer in list(project.observers): + observer.resource_changed(resource) + if project.pycore.automatic_soa: + rope.base.pycore.perform_soa_on_changed_scopes(project, resource, + old_content) + +def analyze_modules(project, task_handle=taskhandle.NullTaskHandle()): + """Perform static object analysis on all python files in the project + + Note that this might be really time consuming. + """ + resources = project.pycore.get_python_files() + job_set = task_handle.create_jobset('Analyzing Modules', len(resources)) + for resource in resources: + job_set.started_job(resource.path) + project.pycore.analyze_module(resource) + job_set.finished_job() diff -r e30544496575 -r 48cacfdc2ca6 vim/sadness/ropevim/src/rope/rope/base/oi/__init__.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vim/sadness/ropevim/src/rope/rope/base/oi/__init__.py Wed Oct 06 12:30:46 2010 -0400 @@ -0,0 +1,38 @@ +"""Rope object analysis and inference package + +Rope makes some simplifying assumptions about a python program. It +assumes that a program only performs assignments and function calls. +Tracking assignments is simple and `PyName` objects handle that. The +main problem is function calls. Rope uses these two approaches for +obtaining call information: + +* Static object analysis: `rope.base.pycore.PyCore.analyze_module()` + + It can analyze modules to obtain information about functions. This + is done by analyzing function calls in a module or scope. Currently + SOA analyzes the scopes that are changed while saving or when the + user asks to analyze a module. That is mainly because static + analysis is time-consuming. + +* Dynamic object analysis: `rope.base.pycore.PyCore.run_module()` + + When you run a module or your testsuite, when DOA is enabled, it + collects information about parameters passed to and objects returned + from functions. The main problem with this approach is that it is + quite slow; Not when looking up the information but when collecting + them. + +An instance of `rope.base.oi.objectinfo.ObjectInfoManager` can be used +for accessing these information. It saves the data in a +`rope.base.oi.objectdb.ObjectDB` internally. + +Now if our objectdb does not know anything about a function and we +need the value returned by it, static object inference, SOI, comes +into play. It analyzes function body and tries to infer the object +that is returned from it (we usually need the returned value for the +given parameter objects). + +Rope might collect and store information for other `PyName`\s, too. +For instance rope stores the object builtin containers hold. + +""" diff -r e30544496575 -r 48cacfdc2ca6 vim/sadness/ropevim/src/rope/rope/base/oi/doa.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vim/sadness/ropevim/src/rope/rope/base/oi/doa.py Wed Oct 06 12:30:46 2010 -0400 @@ -0,0 +1,162 @@ +import cPickle as pickle +import marshal +import os +import socket +import subprocess +import sys +import tempfile +import threading + + +class PythonFileRunner(object): + """A class for running python project files""" + + def __init__(self, pycore, file_, args=None, stdin=None, + stdout=None, analyze_data=None): + self.pycore = pycore + self.file = file_ + self.analyze_data = analyze_data + self.observers = [] + self.args = args + self.stdin = stdin + self.stdout = stdout + + def run(self): + """Execute the process""" + env = dict(os.environ) + file_path = self.file.real_path + path_folders = self.pycore.get_source_folders() + \ + self.pycore.get_python_path_folders() + env['PYTHONPATH'] = os.pathsep.join(folder.real_path + for folder in path_folders) + runmod_path = self.pycore.find_module('rope.base.oi.runmod').real_path + self.receiver = None + self._init_data_receiving() + send_info = '-' + if self.receiver: + send_info = self.receiver.get_send_info() + args = [sys.executable, runmod_path, send_info, + self.pycore.project.address, self.file.real_path] + if self.analyze_data is None: + del args[1:4] + if self.args is not None: + args.extend(self.args) + self.process = subprocess.Popen( + executable=sys.executable, args=args, env=env, + cwd=os.path.split(file_path)[0], stdin=self.stdin, + stdout=self.stdout, stderr=self.stdout, close_fds=os.name != 'nt') + + def _init_data_receiving(self): + if self.analyze_data is None: + return + # Disabling FIFO data transfer due to blocking when running + # unittests in the GUI. + # XXX: Handle FIFO data transfer for `rope.ui.testview` + if True or os.name == 'nt': + self.receiver = _SocketReceiver() + else: + self.receiver = _FIFOReceiver() + self.receiving_thread = threading.Thread(target=self._receive_information) + self.receiving_thread.setDaemon(True) + self.receiving_thread.start() + + def _receive_information(self): + #temp = open('/dev/shm/info', 'w') + for data in self.receiver.receive_data(): + self.analyze_data(data) + #temp.write(str(data) + '\n') + #temp.close() + for observer in self.observers: + observer() + + def wait_process(self): + """Wait for the process to finish""" + self.process.wait() + if self.analyze_data: + self.receiving_thread.join() + + def kill_process(self): + """Stop the process""" + if self.process.poll() is not None: + return + try: + if hasattr(self.process, 'terminate'): + self.process.terminate() + elif os.name != 'nt': + os.kill(self.process.pid, 9) + else: + import ctypes + handle = int(self.process._handle) + ctypes.windll.kernel32.TerminateProcess(handle, -1) + except OSError: + pass + + def add_finishing_observer(self, observer): + """Notify this observer when execution finishes""" + self.observers.append(observer) + + +class _MessageReceiver(object): + + def receive_data(self): + pass + + def get_send_info(self): + pass + + +class _SocketReceiver(_MessageReceiver): + + def __init__(self): + self.server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + self.data_port = 3037 + while self.data_port < 4000: + try: + self.server_socket.bind(('', self.data_port)) + break + except socket.error, e: + self.data_port += 1 + self.server_socket.listen(1) + + def get_send_info(self): + return str(self.data_port) + + def receive_data(self): + conn, addr = self.server_socket.accept() + self.server_socket.close() + my_file = conn.makefile('r') + while True: + try: + yield pickle.load(my_file) + except EOFError: + break + my_file.close() + conn.close() + + +class _FIFOReceiver(_MessageReceiver): + + def __init__(self): + # XXX: this is insecure and might cause race conditions + self.file_name = self._get_file_name() + os.mkfifo(self.file_name) + + def _get_file_name(self): + prefix = tempfile.gettempdir() + '/__rope_' + i = 0 + while os.path.exists(prefix + str(i).rjust(4, '0')): + i += 1 + return prefix + str(i).rjust(4, '0') + + def get_send_info(self): + return self.file_name + + def receive_data(self): + my_file = open(self.file_name, 'rb') + while True: + try: + yield marshal.load(my_file) + except EOFError: + break + my_file.close() + os.remove(self.file_name) diff -r e30544496575 -r 48cacfdc2ca6 vim/sadness/ropevim/src/rope/rope/base/oi/memorydb.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vim/sadness/ropevim/src/rope/rope/base/oi/memorydb.py Wed Oct 06 12:30:46 2010 -0400 @@ -0,0 +1,106 @@ +from rope.base.oi import objectdb + + +class MemoryDB(objectdb.FileDict): + + def __init__(self, project, persist=None): + self.project = project + self._persist = persist + self.files = self + self._load_files() + self.project.data_files.add_write_hook(self.write) + + def _load_files(self): + self._files = {} + if self.persist: + result = self.project.data_files.read_data( + 'objectdb', compress=self.compress, import_=True) + if result is not None: + self._files = result + + def keys(self): + return self._files.keys() + + def __contains__(self, key): + return key in self._files + + def __getitem__(self, key): + return FileInfo(self._files[key]) + + def create(self, path): + self._files[path] = {} + + def rename(self, file, newfile): + if file not in self._files: + return + self._files[newfile] = self._files[file] + del self[file] + + def __delitem__(self, file): + del self._files[file] + + def write(self): + if self.persist: + self.project.data_files.write_data('objectdb', self._files, + self.compress) + + @property + def compress(self): + return self.project.prefs.get('compress_objectdb', False) + + @property + def persist(self): + if self._persist is not None: + return self._persist + else: + return self.project.prefs.get('save_objectdb', False) + + +class FileInfo(objectdb.FileInfo): + + def __init__(self, scopes): + self.scopes = scopes + + def create_scope(self, key): + self.scopes[key] = ScopeInfo() + + def keys(self): + return self.scopes.keys() + + def __contains__(self, key): + return key in self.scopes + + def __getitem__(self, key): + return self.scopes[key] + + def __delitem__(self, key): + del self.scopes[key] + + +class ScopeInfo(objectdb.ScopeInfo): + + def __init__(self): + self.call_info = {} + self.per_name = {} + + def get_per_name(self, name): + return self.per_name.get(name, None) + + def save_per_name(self, name, value): + self.per_name[name] = value + + def get_returned(self, parameters): + return self.call_info.get(parameters, None) + + def get_call_infos(self): + for args, returned in self.call_info.items(): + yield objectdb.CallInfo(args, returned) + + def add_call(self, parameters, returned): + self.call_info[parameters] = returned + + def __getstate__(self): + return (self.call_info, self.per_name) + + def __setstate__(self, data): + self.call_info, self.per_name = data diff -r e30544496575 -r 48cacfdc2ca6 vim/sadness/ropevim/src/rope/rope/base/oi/objectdb.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vim/sadness/ropevim/src/rope/rope/base/oi/objectdb.py Wed Oct 06 12:30:46 2010 -0400 @@ -0,0 +1,175 @@ +import UserDict + + +class ObjectDB(object): + + def __init__(self, db, validation): + self.db = db + self.validation = validation + self.observers = [] + self.files = db.files + + def validate_files(self): + for file in list(self.files): + if not self.validation.is_file_valid(file): + del self.files[file] + self._file_removed(file) + + def validate_file(self, file): + if file not in self.files: + return + for key in list(self.files[file]): + if not self.validation.is_scope_valid(file, key): + del self.files[file][key] + + def file_moved(self, file, newfile): + if file not in self.files: + return + self.files.rename(file, newfile) + self._file_removed(file) + self._file_added(newfile) + + def get_files(self): + return self.files.keys() + + def get_returned(self, path, key, args): + scope_info = self._get_scope_info(path, key, readonly=True) + result = scope_info.get_returned(args) + if self.validation.is_value_valid(result): + return result + + def get_pername(self, path, key, name): + scope_info = self._get_scope_info(path, key, readonly=True) + result = scope_info.get_per_name(name) + if self.validation.is_value_valid(result): + return result + + def get_callinfos(self, path, key): + scope_info = self._get_scope_info(path, key, readonly=True) + return scope_info.get_call_infos() + + def add_callinfo(self, path, key, args, returned): + scope_info = self._get_scope_info(path, key, readonly=False) + old_returned = scope_info.get_returned(args) + if self.validation.is_more_valid(returned, old_returned): + scope_info.add_call(args, returned) + + def add_pername(self, path, key, name, value): + scope_info = self._get_scope_info(path, key, readonly=False) + old_value = scope_info.get_per_name(name) + if self.validation.is_more_valid(value, old_value): + scope_info.save_per_name(name, value) + + def add_file_list_observer(self, observer): + self.observers.append(observer) + + def write(self): + self.db.write() + + def _get_scope_info(self, path, key, readonly=True): + if path not in self.files: + if readonly: + return _NullScopeInfo() + self.files.create(path) + self._file_added(path) + if key not in self.files[path]: + if readonly: + return _NullScopeInfo() + self.files[path].create_scope(key) + result = self.files[path][key] + if isinstance(result, dict): + print self.files, self.files[path], self.files[path][key] + return result + + def _file_removed(self, path): + for observer in self.observers: + observer.removed(path) + + def _file_added(self, path): + for observer in self.observers: + observer.added(path) + + def __str__(self): + scope_count = 0 + for file_dict in self.files.values(): + scope_count += len(file_dict) + return 'ObjectDB holds %s file and %s scope infos' % \ + (len(self.files), scope_count) + + +class _NullScopeInfo(object): + + def __init__(self, error_on_write=True): + self.error_on_write = error_on_write + + def get_per_name(self, name): + pass + + def save_per_name(self, name, value): + if self.error_on_write: + raise NotImplementedError() + + def get_returned(self, parameters): + pass + + def get_call_infos(self): + return [] + + def add_call(self, parameters, returned): + if self.error_on_write: + raise NotImplementedError() + + +class FileInfo(UserDict.DictMixin): + + def create_scope(self, key): + pass + + +class FileDict(UserDict.DictMixin): + + def create(self, key): + pass + + def rename(self, key, new_key): + pass + + +class ScopeInfo(object): + + def get_per_name(self, name): + pass + + def save_per_name(self, name, value): + pass + + def get_returned(self, parameters): + pass + + def get_call_infos(self): + pass + + def add_call(self, parameters, returned): + pass + + +class CallInfo(object): + + def __init__(self, args, returned): + self.args = args + self.returned = returned + + def get_parameters(self): + return self.args + + def get_returned(self): + return self.returned + + +class FileListObserver(object): + + def added(self, path): + pass + + def removed(self, path): + pass diff -r e30544496575 -r 48cacfdc2ca6 vim/sadness/ropevim/src/rope/rope/base/oi/objectinfo.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vim/sadness/ropevim/src/rope/rope/base/oi/objectinfo.py Wed Oct 06 12:30:46 2010 -0400 @@ -0,0 +1,232 @@ +import warnings + +from rope.base import exceptions, resourceobserver +from rope.base.oi import objectdb, memorydb, transform + + +class ObjectInfoManager(object): + """Stores object information + + It uses an instance of `objectdb.ObjectDB` for storing + information. + + """ + + def __init__(self, project): + self.project = project + self.to_textual = transform.PyObjectToTextual(project) + self.to_pyobject = transform.TextualToPyObject(project) + self.doi_to_pyobject = transform.DOITextualToPyObject(project) + self._init_objectdb() + if project.prefs.get('validate_objectdb', False): + self._init_validation() + + def _init_objectdb(self): + dbtype = self.project.get_prefs().get('objectdb_type', None) + persist = None + if dbtype is not None: + warnings.warn( + '"objectdb_type" project config is deprecated;\n' + 'Use "save_objectdb" instead in your project ' + 'config file.\n(".ropeproject/config.py" by default)\n', + DeprecationWarning) + if dbtype != 'memory' and self.project.ropefolder is not None: + persist = True + self.validation = TextualValidation(self.to_pyobject) + db = memorydb.MemoryDB(self.project, persist=persist) + self.objectdb = objectdb.ObjectDB(db, self.validation) + + def _init_validation(self): + self.objectdb.validate_files() + observer = resourceobserver.ResourceObserver( + changed=self._resource_changed, moved=self._resource_moved, + removed=self._resource_moved) + files = [] + for path in self.objectdb.get_files(): + resource = self.to_pyobject.path_to_resource(path) + if resource is not None and resource.project == self.project: + files.append(resource) + self.observer = resourceobserver.FilteredResourceObserver(observer, + files) + self.objectdb.add_file_list_observer(_FileListObserver(self)) + self.project.add_observer(self.observer) + + def _resource_changed(self, resource): + try: + self.objectdb.validate_file( + self.to_textual.resource_to_path(resource)) + except exceptions.ModuleSyntaxError: + pass + + def _resource_moved(self, resource, new_resource=None): + self.observer.remove_resource(resource) + if new_resource is not None: + old = self.to_textual.resource_to_path(resource) + new = self.to_textual.resource_to_path(new_resource) + self.objectdb.file_moved(old, new) + self.observer.add_resource(new_resource) + + def get_returned(self, pyobject, args): + result = self.get_exact_returned(pyobject, args) + if result is not None: + return result + path, key = self._get_scope(pyobject) + if path is None: + return None + for call_info in self.objectdb.get_callinfos(path, key): + returned = call_info.get_returned() + if returned and returned[0] not in ('unknown', 'none'): + result = returned + break + if result is None: + result = returned + if result is not None: + return self.to_pyobject(result) + + def get_exact_returned(self, pyobject, args): + path, key = self._get_scope(pyobject) + if path is not None: + returned = self.objectdb.get_returned( + path, key, self._args_to_textual(pyobject, args)) + if returned is not None: + return self.to_pyobject(returned) + + def _args_to_textual(self, pyfunction, args): + parameters = list(pyfunction.get_param_names(special_args=False)) + arguments = args.get_arguments(parameters)[:len(parameters)] + textual_args = tuple([self.to_textual(arg) + for arg in arguments]) + return textual_args + + def get_parameter_objects(self, pyobject): + path, key = self._get_scope(pyobject) + if path is None: + return None + arg_count = len(pyobject.get_param_names(special_args=False)) + unknowns = arg_count + parameters = [None] * arg_count + for call_info in self.objectdb.get_callinfos(path, key): + args = call_info.get_parameters() + for index, arg in enumerate(args[:arg_count]): + old = parameters[index] + if self.validation.is_more_valid(arg, old): + parameters[index] = arg + if self.validation.is_value_valid(arg): + unknowns -= 1 + if unknowns == 0: + break + if unknowns < arg_count: + return [self.to_pyobject(parameter) + for parameter in parameters] + + def get_passed_objects(self, pyfunction, parameter_index): + path, key = self._get_scope(pyfunction) + if path is None: + return [] + result = [] + for call_info in self.objectdb.get_callinfos(path, key): + args = call_info.get_parameters() + if len(args) > parameter_index: + parameter = self.to_pyobject(args[parameter_index]) + if parameter is not None: + result.append(parameter) + return result + + def doa_data_received(self, data): + def doi_to_normal(textual): + pyobject = self.doi_to_pyobject(textual) + return self.to_textual(pyobject) + function = doi_to_normal(data[0]) + args = tuple([doi_to_normal(textual) for textual in data[1]]) + returned = doi_to_normal(data[2]) + if function[0] == 'defined' and len(function) == 3: + self._save_data(function, args, returned) + + def function_called(self, pyfunction, params, returned=None): + function_text = self.to_textual(pyfunction) + params_text = tuple([self.to_textual(param) + for param in params]) + returned_text = ('unknown',) + if returned is not None: + returned_text = self.to_textual(returned) + self._save_data(function_text, params_text, returned_text) + + def save_per_name(self, scope, name, data): + path, key = self._get_scope(scope.pyobject) + if path is not None: + self.objectdb.add_pername(path, key, name, self.to_textual(data)) + + def get_per_name(self, scope, name): + path, key = self._get_scope(scope.pyobject) + if path is not None: + result = self.objectdb.get_pername(path, key, name) + if result is not None: + return self.to_pyobject(result) + + def _save_data(self, function, args, returned=('unknown',)): + self.objectdb.add_callinfo(function[1], function[2], args, returned) + + def _get_scope(self, pyobject): + resource = pyobject.get_module().get_resource() + if resource is None: + return None, None + textual = self.to_textual(pyobject) + if textual[0] == 'defined': + path = textual[1] + if len(textual) == 3: + key = textual[2] + else: + key = '' + return path, key + return None, None + + def sync(self): + self.objectdb.sync() + + def __str__(self): + return str(self.objectdb) + + +class TextualValidation(object): + + def __init__(self, to_pyobject): + self.to_pyobject = to_pyobject + + def is_value_valid(self, value): + # ???: Should none and unknown be considered valid? + if value is None or value[0] in ('none', 'unknown'): + return False + return self.to_pyobject(value) is not None + + def is_more_valid(self, new, old): + if old is None: + return True + return new[0] not in ('unknown', 'none') + + def is_file_valid(self, path): + return self.to_pyobject.path_to_resource(path) is not None + + def is_scope_valid(self, path, key): + if key == '': + textual = ('defined', path) + else: + textual = ('defined', path, key) + return self.to_pyobject(textual) is not None + + +class _FileListObserver(object): + + def __init__(self, object_info): + self.object_info = object_info + self.observer = self.object_info.observer + self.to_pyobject = self.object_info.to_pyobject + + def removed(self, path): + resource = self.to_pyobject.path_to_resource(path) + if resource is not None: + self.observer.remove_resource(resource) + + def added(self, path): + resource = self.to_pyobject.path_to_resource(path) + if resource is not None: + self.observer.add_resource(resource) diff -r e30544496575 -r 48cacfdc2ca6 vim/sadness/ropevim/src/rope/rope/base/oi/runmod.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vim/sadness/ropevim/src/rope/rope/base/oi/runmod.py Wed Oct 06 12:30:46 2010 -0400 @@ -0,0 +1,210 @@ + +def __rope_start_everything(): + import os + import sys + import socket + import cPickle as pickle + import marshal + import inspect + import types + import threading + + class _MessageSender(object): + + def send_data(self, data): + pass + + class _SocketSender(_MessageSender): + + def __init__(self, port): + s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + s.connect(('127.0.0.1', port)) + self.my_file = s.makefile('w') + + def send_data(self, data): + if not self.my_file.closed: + pickle.dump(data, self.my_file) + + def close(self): + self.my_file.close() + + class _FileSender(_MessageSender): + + def __init__(self, file_name): + self.my_file = open(file_name, 'wb') + + def send_data(self, data): + if not self.my_file.closed: + marshal.dump(data, self.my_file) + + def close(self): + self.my_file.close() + + + def _cached(func): + cache = {} + def newfunc(self, arg): + if arg in cache: + return cache[arg] + result = func(self, arg) + cache[arg] = result + return result + return newfunc + + class _FunctionCallDataSender(object): + + def __init__(self, send_info, project_root): + self.project_root = project_root + if send_info.isdigit(): + self.sender = _SocketSender(int(send_info)) + else: + self.sender = _FileSender(send_info) + + def global_trace(frame, event, arg): + # HACK: Ignoring out->in calls + # This might lose some information + if self._is_an_interesting_call(frame): + return self.on_function_call + sys.settrace(global_trace) + threading.settrace(global_trace) + + def on_function_call(self, frame, event, arg): + if event != 'return': + return + args = [] + returned = ('unknown',) + code = frame.f_code + for argname in code.co_varnames[:code.co_argcount]: + try: + args.append(self._object_to_persisted_form(frame.f_locals[argname])) + except (TypeError, AttributeError): + args.append(('unknown',)) + try: + returned = self._object_to_persisted_form(arg) + except (TypeError, AttributeError): + pass + try: + data = (self._object_to_persisted_form(frame.f_code), + tuple(args), returned) + self.sender.send_data(data) + except (TypeError): + pass + return self.on_function_call + + def _is_an_interesting_call(self, frame): + #if frame.f_code.co_name in ['?', '']: + # return False + #return not frame.f_back or not self._is_code_inside_project(frame.f_back.f_code) + + if not self._is_code_inside_project(frame.f_code) and \ + (not frame.f_back or not self._is_code_inside_project(frame.f_back.f_code)): + return False + return True + + def _is_code_inside_project(self, code): + source = self._path(code.co_filename) + return source is not None and os.path.exists(source) and \ + _realpath(source).startswith(self.project_root) + + @_cached + def _get_persisted_code(self, object_): + source = self._path(object_.co_filename) + if not os.path.exists(source): + raise TypeError('no source') + return ('defined', _realpath(source), str(object_.co_firstlineno)) + + @_cached + def _get_persisted_class(self, object_): + try: + return ('defined', _realpath(inspect.getsourcefile(object_)), + object_.__name__) + except (TypeError, AttributeError): + return ('unknown',) + + def _get_persisted_builtin(self, object_): + if isinstance(object_, (str, unicode)): + return ('builtin', 'str') + if isinstance(object_, list): + holding = None + if len(object_) > 0: + holding = object_[0] + return ('builtin', 'list', self._object_to_persisted_form(holding)) + if isinstance(object_, dict): + keys = None + values = None + if len(object_) > 0: + keys = object_.keys()[0] + values = object_[keys] + return ('builtin', 'dict', + self._object_to_persisted_form(keys), + self._object_to_persisted_form(values)) + if isinstance(object_, tuple): + objects = [] + if len(object_) < 3: + for holding in object_: + objects.append(self._object_to_persisted_form(holding)) + else: + objects.append(self._object_to_persisted_form(object_[0])) + return tuple(['builtin', 'tuple'] + objects) + if isinstance(object_, set): + holding = None + if len(object_) > 0: + for o in object_: + holding = o + break + return ('builtin', 'set', self._object_to_persisted_form(holding)) + return ('unknown',) + + def _object_to_persisted_form(self, object_): + if object_ is None: + return ('none',) + if isinstance(object_, types.CodeType): + return self._get_persisted_code(object_) + if isinstance(object_, types.FunctionType): + return self._get_persisted_code(object_.func_code) + if isinstance(object_, types.MethodType): + return self._get_persisted_code(object_.im_func.func_code) + if isinstance(object_, types.ModuleType): + return self._get_persisted_module(object_) + if isinstance(object_, (str, unicode, list, dict, tuple, set)): + return self._get_persisted_builtin(object_) + if isinstance(object_, (types.TypeType, types.ClassType)): + return self._get_persisted_class(object_) + return ('instance', self._get_persisted_class(type(object_))) + + @_cached + def _get_persisted_module(self, object_): + path = self._path(object_.__file__) + if path and os.path.exists(path): + return ('defined', _realpath(path)) + return ('unknown',) + + def _path(self, path): + if path.endswith('.pyc'): + path = path[:-1] + if path.endswith('.py'): + return path + + def close(self): + self.sender.close() + + def _realpath(path): + return os.path.realpath(os.path.abspath(os.path.expanduser(path))) + + send_info = sys.argv[1] + project_root = sys.argv[2] + file_to_run = sys.argv[3] + run_globals = globals() + run_globals.update({'__name__': '__main__', + '__builtins__': __builtins__, + '__file__': file_to_run}) + if send_info != '-': + data_sender = _FunctionCallDataSender(send_info, project_root) + del sys.argv[1:4] + execfile(file_to_run, run_globals) + if send_info != '-': + data_sender.close() + + +if __name__ == '__main__': + __rope_start_everything() diff -r e30544496575 -r 48cacfdc2ca6 vim/sadness/ropevim/src/rope/rope/base/oi/soa.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vim/sadness/ropevim/src/rope/rope/base/oi/soa.py Wed Oct 06 12:30:46 2010 -0400 @@ -0,0 +1,136 @@ +import rope.base.ast +import rope.base.oi.soi +import rope.base.pynames +from rope.base import pyobjects, evaluate, astutils, arguments + + +def analyze_module(pycore, pymodule, should_analyze, + search_subscopes, followed_calls): + """Analyze `pymodule` for static object inference + + Analyzes scopes for collecting object information. The analysis + starts from inner scopes. + + """ + _analyze_node(pycore, pymodule, should_analyze, + search_subscopes, followed_calls) + + +def _analyze_node(pycore, pydefined, should_analyze, + search_subscopes, followed_calls): + if search_subscopes(pydefined): + for scope in pydefined.get_scope().get_scopes(): + _analyze_node(pycore, scope.pyobject, should_analyze, + search_subscopes, followed_calls) + if should_analyze(pydefined): + new_followed_calls = max(0, followed_calls - 1) + return_true = lambda pydefined: True + return_false = lambda pydefined: False + def _follow(pyfunction): + _analyze_node(pycore, pyfunction, return_true, + return_false, new_followed_calls) + if not followed_calls: + _follow = None + visitor = SOAVisitor(pycore, pydefined, _follow) + for child in rope.base.ast.get_child_nodes(pydefined.get_ast()): + rope.base.ast.walk(child, visitor) + + +class SOAVisitor(object): + + def __init__(self, pycore, pydefined, follow_callback=None): + self.pycore = pycore + self.pymodule = pydefined.get_module() + self.scope = pydefined.get_scope() + self.follow = follow_callback + + def _FunctionDef(self, node): + pass + + def _ClassDef(self, node): + pass + + def _Call(self, node): + for child in rope.base.ast.get_child_nodes(node): + rope.base.ast.walk(child, self) + primary, pyname = evaluate.eval_node2(self.scope, node.func) + if pyname is None: + return + pyfunction = pyname.get_object() + if isinstance(pyfunction, pyobjects.AbstractFunction): + args = arguments.create_arguments(primary, pyfunction, + node, self.scope) + elif isinstance(pyfunction, pyobjects.PyClass): + pyclass = pyfunction + if '__init__' in pyfunction: + pyfunction = pyfunction['__init__'].get_object() + pyname = rope.base.pynames.UnboundName(pyobjects.PyObject(pyclass)) + args = self._args_with_self(primary, pyname, pyfunction, node) + elif '__call__' in pyfunction: + pyfunction = pyfunction['__call__'].get_object() + args = self._args_with_self(primary, pyname, pyfunction, node) + else: + return + self._call(pyfunction, args) + + def _args_with_self(self, primary, self_pyname, pyfunction, node): + base_args = arguments.create_arguments(primary, pyfunction, + node, self.scope) + return arguments.MixedArguments(self_pyname, base_args, self.scope) + + def _call(self, pyfunction, args): + if isinstance(pyfunction, pyobjects.PyFunction): + if self.follow is not None: + before = self._parameter_objects(pyfunction) + self.pycore.object_info.function_called( + pyfunction, args.get_arguments(pyfunction.get_param_names())) + pyfunction._set_parameter_pyobjects(None) + if self.follow is not None: + after = self._parameter_objects(pyfunction) + if after != before: + self.follow(pyfunction) + # XXX: Maybe we should not call every builtin function + if isinstance(pyfunction, rope.base.builtins.BuiltinFunction): + pyfunction.get_returned_object(args) + + def _parameter_objects(self, pyfunction): + result = [] + for i in range(len(pyfunction.get_param_names(False))): + result.append(pyfunction.get_parameter(i)) + return result + + def _Assign(self, node): + for child in rope.base.ast.get_child_nodes(node): + rope.base.ast.walk(child, self) + visitor = _SOAAssignVisitor() + nodes = [] + for child in node.targets: + rope.base.ast.walk(child, visitor) + nodes.extend(visitor.nodes) + for subscript, levels in nodes: + instance = evaluate.eval_node(self.scope, subscript.value) + args_pynames = [] + args_pynames.append(evaluate.eval_node(self.scope, + subscript.slice.value)) + value = rope.base.oi.soi._infer_assignment( + rope.base.pynames.AssignmentValue(node.value, levels), self.pymodule) + args_pynames.append(rope.base.pynames.UnboundName(value)) + if instance is not None and value is not None: + pyobject = instance.get_object() + if '__setitem__' in pyobject: + pyfunction = pyobject['__setitem__'].get_object() + args = arguments.ObjectArguments([instance] + args_pynames) + self._call(pyfunction, args) + # IDEA: handle `__setslice__`, too + + +class _SOAAssignVisitor(astutils._NodeNameCollector): + + def __init__(self): + super(_SOAAssignVisitor, self).__init__() + self.nodes = [] + + def _added(self, node, levels): + if isinstance(node, rope.base.ast.Subscript) and \ + isinstance(node.slice, rope.base.ast.Index): + self.nodes.append((node, levels)) diff -r e30544496575 -r 48cacfdc2ca6 vim/sadness/ropevim/src/rope/rope/base/oi/soi.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vim/sadness/ropevim/src/rope/rope/base/oi/soi.py Wed Oct 06 12:30:46 2010 -0400 @@ -0,0 +1,186 @@ +"""A module for inferring objects + +For more information see the documentation in `rope.base.oi` +package. + +""" +import rope.base.builtins +import rope.base.pynames +import rope.base.pyobjects +from rope.base import evaluate, utils, arguments + + +_ignore_inferred = utils.ignore_exception( + rope.base.pyobjects.IsBeingInferredError) + + +@_ignore_inferred +def infer_returned_object(pyfunction, args): + """Infer the `PyObject` this `PyFunction` returns after calling""" + object_info = pyfunction.pycore.object_info + result = object_info.get_exact_returned(pyfunction, args) + if result is not None: + return result + result = _infer_returned(pyfunction, args) + if result is not None: + if args and pyfunction.get_module().get_resource() is not None: + params = args.get_arguments( + pyfunction.get_param_names(special_args=False)) + object_info.function_called(pyfunction, params, result) + return result + return object_info.get_returned(pyfunction, args) + +@_ignore_inferred +def infer_parameter_objects(pyfunction): + """Infer the `PyObject`\s of parameters of this `PyFunction`""" + object_info = pyfunction.pycore.object_info + result = object_info.get_parameter_objects(pyfunction) + if result is None: + result = _parameter_objects(pyfunction) + _handle_first_parameter(pyfunction, result) + return result + +def _handle_first_parameter(pyobject, parameters): + kind = pyobject.get_kind() + if parameters is None or kind not in ['method', 'classmethod']: + pass + if not parameters: + if not pyobject.get_param_names(special_args=False): + return + parameters.append(rope.base.pyobjects.get_unknown()) + if kind == 'method': + parameters[0] = rope.base.pyobjects.PyObject(pyobject.parent) + if kind == 'classmethod': + parameters[0] = pyobject.parent + +@_ignore_inferred +def infer_assigned_object(pyname): + if not pyname.assignments: + return + for assignment in reversed(pyname.assignments): + result = _infer_assignment(assignment, pyname.module) + if result is not None: + return result + +def get_passed_objects(pyfunction, parameter_index): + object_info = pyfunction.pycore.object_info + result = object_info.get_passed_objects(pyfunction, + parameter_index) + if not result: + statically_inferred = _parameter_objects(pyfunction) + if len(statically_inferred) > parameter_index: + result.append(statically_inferred[parameter_index]) + return result + +def _infer_returned(pyobject, args): + if args: + # HACK: Setting parameter objects manually + # This is not thread safe and might cause problems if `args` + # does not come from a good call site + pyobject.get_scope().invalidate_data() + pyobject._set_parameter_pyobjects( + args.get_arguments(pyobject.get_param_names(special_args=False))) + scope = pyobject.get_scope() + if not scope._get_returned_asts(): + return + maxtries = 3 + for returned_node in reversed(scope._get_returned_asts()[-maxtries:]): + try: + resulting_pyname = evaluate.eval_node(scope, returned_node) + if resulting_pyname is None: + continue + pyobject = resulting_pyname.get_object() + if pyobject == rope.base.pyobjects.get_unknown(): + continue + if not scope._is_generator(): + return pyobject + else: + return rope.base.builtins.get_generator(pyobject) + except rope.base.pyobjects.IsBeingInferredError: + pass + +def _parameter_objects(pyobject): + params = pyobject.get_param_names(special_args=False) + return [rope.base.pyobjects.get_unknown()] * len(params) + +# handling `rope.base.pynames.AssignmentValue` + +@_ignore_inferred +def _infer_assignment(assignment, pymodule): + result = _follow_pyname(assignment, pymodule) + if result is None: + return None + pyname, pyobject = result + pyobject = _follow_evaluations(assignment, pyname, pyobject) + if pyobject is None: + return None + return _follow_levels(assignment, pyobject) + +def _follow_levels(assignment, pyobject): + for index in assignment.levels: + if isinstance(pyobject.get_type(), rope.base.builtins.Tuple): + holdings = pyobject.get_type().get_holding_objects() + if holdings: + pyobject = holdings[min(len(holdings) - 1, index)] + else: + pyobject = None + elif isinstance(pyobject.get_type(), rope.base.builtins.List): + pyobject = pyobject.get_type().holding + else: + pyobject = None + if pyobject is None: + break + return pyobject + +@_ignore_inferred +def _follow_pyname(assignment, pymodule, lineno=None): + assign_node = assignment.ast_node + if lineno is None: + lineno = _get_lineno_for_node(assign_node) + holding_scope = pymodule.get_scope().get_inner_scope_for_line(lineno) + pyname = evaluate.eval_node(holding_scope, assign_node) + if pyname is not None: + result = pyname.get_object() + if isinstance(result.get_type(), rope.base.builtins.Property) and \ + holding_scope.get_kind() == 'Class': + arg = rope.base.pynames.UnboundName( + rope.base.pyobjects.PyObject(holding_scope.pyobject)) + return pyname, result.get_type().get_property_object( + arguments.ObjectArguments([arg])) + return pyname, result + +@_ignore_inferred +def _follow_evaluations(assignment, pyname, pyobject): + new_pyname = pyname + tokens = assignment.evaluation.split('.') + for token in tokens: + call = token.endswith('()') + if call: + token = token[:-2] + if token: + pyname = new_pyname + new_pyname = _get_attribute(pyobject, token) + if new_pyname is not None: + pyobject = new_pyname.get_object() + if pyobject is not None and call: + if isinstance(pyobject, rope.base.pyobjects.AbstractFunction): + args = arguments.ObjectArguments([pyname]) + pyobject = pyobject.get_returned_object(args) + else: + pyobject = None + if pyobject is None: + break + if pyobject is not None and assignment.assign_type: + return rope.base.pyobjects.PyObject(pyobject) + return pyobject + + +def _get_lineno_for_node(assign_node): + if hasattr(assign_node, 'lineno') and \ + assign_node.lineno is not None: + return assign_node.lineno + return 1 + +def _get_attribute(pyobject, name): + if pyobject is not None and name in pyobject: + return pyobject[name] diff -r e30544496575 -r 48cacfdc2ca6 vim/sadness/ropevim/src/rope/rope/base/oi/transform.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vim/sadness/ropevim/src/rope/rope/base/oi/transform.py Wed Oct 06 12:30:46 2010 -0400 @@ -0,0 +1,285 @@ +"""Provides classes for persisting `PyObject`\s""" +import os +import re + +import rope.base.builtins +from rope.base import exceptions + + +class PyObjectToTextual(object): + """For transforming `PyObject` to textual form + + This can be used for storing `PyObjects` in files. Use + `TextualToPyObject` for converting back. + + """ + + def __init__(self, project): + self.project = project + + def transform(self, pyobject): + """Transform a `PyObject` to textual form""" + if pyobject is None: + return ('none',) + object_type = type(pyobject) + try: + method = getattr(self, object_type.__name__ + '_to_textual') + return method(pyobject) + except AttributeError: + return ('unknown',) + + def __call__(self, pyobject): + return self.transform(pyobject) + + def PyObject_to_textual(self, pyobject): + if isinstance(pyobject.get_type(), rope.base.pyobjects.AbstractClass): + result = self.transform(pyobject.get_type()) + if result[0] == 'defined': + return ('instance', result) + return result + return ('unknown',) + + def PyFunction_to_textual(self, pyobject): + return self._defined_to_textual(pyobject) + + def PyClass_to_textual(self, pyobject): + return self._defined_to_textual(pyobject) + + def _defined_to_textual(self, pyobject): + address = [] + while pyobject.parent is not None: + address.insert(0, pyobject.get_name()) + pyobject = pyobject.parent + return ('defined', self._get_pymodule_path(pyobject.get_module()), + '.'.join(address)) + + def PyModule_to_textual(self, pyobject): + return ('defined', self._get_pymodule_path(pyobject)) + + def PyPackage_to_textual(self, pyobject): + return ('defined', self._get_pymodule_path(pyobject)) + + def List_to_textual(self, pyobject): + return ('builtin', 'list', self.transform(pyobject.holding)) + + def Dict_to_textual(self, pyobject): + return ('builtin', 'dict', self.transform(pyobject.keys), + self.transform(pyobject.values)) + + def Tuple_to_textual(self, pyobject): + objects = [self.transform(holding) + for holding in pyobject.get_holding_objects()] + return tuple(['builtin', 'tuple'] + objects) + + def Set_to_textual(self, pyobject): + return ('builtin', 'set', self.transform(pyobject.holding)) + + def Iterator_to_textual(self, pyobject): + return ('builtin', 'iter', self.transform(pyobject.holding)) + + def Generator_to_textual(self, pyobject): + return ('builtin', 'generator', self.transform(pyobject.holding)) + + def Str_to_textual(self, pyobject): + return ('builtin', 'str') + + def File_to_textual(self, pyobject): + return ('builtin', 'file') + + def BuiltinFunction_to_textual(self, pyobject): + return ('builtin', 'function', pyobject.get_name()) + + def _get_pymodule_path(self, pymodule): + return self.resource_to_path(pymodule.get_resource()) + + def resource_to_path(self, resource): + if resource.project == self.project: + return resource.path + else: + return resource.real_path + + +class TextualToPyObject(object): + """For transforming textual form to `PyObject`""" + + def __init__(self, project, allow_in_project_absolutes=False): + self.project = project + + def __call__(self, textual): + return self.transform(textual) + + def transform(self, textual): + """Transform an object from textual form to `PyObject`""" + if textual is None: + return None + type = textual[0] + try: + method = getattr(self, type + '_to_pyobject') + return method(textual) + except AttributeError: + return None + + def builtin_to_pyobject(self, textual): + name = textual[1] + method = getattr(self, 'builtin_%s_to_pyobject' % textual[1], None) + if method is not None: + return method(textual) + + def builtin_str_to_pyobject(self, textual): + return rope.base.builtins.get_str() + + def builtin_list_to_pyobject(self, textual): + holding = self.transform(textual[2]) + return rope.base.builtins.get_list(holding) + + def builtin_dict_to_pyobject(self, textual): + keys = self.transform(textual[2]) + values = self.transform(textual[3]) + return rope.base.builtins.get_dict(keys, values) + + def builtin_tuple_to_pyobject(self, textual): + objects = [] + for holding in textual[2:]: + objects.append(self.transform(holding)) + return rope.base.builtins.get_tuple(*objects) + + def builtin_set_to_pyobject(self, textual): + holding = self.transform(textual[2]) + return rope.base.builtins.get_set(holding) + + def builtin_iter_to_pyobject(self, textual): + holding = self.transform(textual[2]) + return rope.base.builtins.get_iterator(holding) + + def builtin_generator_to_pyobject(self, textual): + holding = self.transform(textual[2]) + return rope.base.builtins.get_generator(holding) + + def builtin_file_to_pyobject(self, textual): + return rope.base.builtins.get_file() + + def builtin_function_to_pyobject(self, textual): + if textual[2] in rope.base.builtins.builtins: + return rope.base.builtins.builtins[textual[2]].get_object() + + def unknown_to_pyobject(self, textual): + return None + + def none_to_pyobject(self, textual): + return None + + def _module_to_pyobject(self, textual): + path = textual[1] + return self._get_pymodule(path) + + def _hierarchical_defined_to_pyobject(self, textual): + path = textual[1] + names = textual[2].split('.') + pymodule = self._get_pymodule(path) + pyobject = pymodule + for name in names: + if pyobject is None: + return None + if isinstance(pyobject, rope.base.pyobjects.PyDefinedObject): + try: + pyobject = pyobject.get_scope()[name].get_object() + except exceptions.NameNotFoundError: + return None + else: + return None + return pyobject + + def defined_to_pyobject(self, textual): + if len(textual) == 2 or textual[2] == '': + return self._module_to_pyobject(textual) + else: + return self._hierarchical_defined_to_pyobject(textual) + + def instance_to_pyobject(self, textual): + type = self.transform(textual[1]) + if type is not None: + return rope.base.pyobjects.PyObject(type) + + def _get_pymodule(self, path): + resource = self.path_to_resource(path) + if resource is not None: + return self.project.pycore.resource_to_pyobject(resource) + + def path_to_resource(self, path): + try: + root = self.project.address + if not os.path.isabs(path): + return self.project.get_resource(path) + if path == root or path.startswith(root + os.sep): + # INFO: This is a project file; should not be absolute + return None + import rope.base.project + return rope.base.project.get_no_project().get_resource(path) + except exceptions.ResourceNotFoundError: + return None + + +class DOITextualToPyObject(TextualToPyObject): + """For transforming textual form to `PyObject` + + The textual form DOI uses is different from rope's standard + textual form. The reason is that we cannot find the needed + information by analyzing live objects. This class can be + used to transform DOI textual form to `PyObject` and later + we can convert it to standard textual form using + `TextualToPyObject` class. + + """ + + def _function_to_pyobject(self, textual): + path = textual[1] + lineno = int(textual[2]) + pymodule = self._get_pymodule(path) + if pymodule is not None: + scope = pymodule.get_scope() + inner_scope = scope.get_inner_scope_for_line(lineno) + return inner_scope.pyobject + + def _class_to_pyobject(self, textual): + path, name = textual[1:] + pymodule = self._get_pymodule(path) + if pymodule is None: + return None + module_scope = pymodule.get_scope() + suspected = None + if name in module_scope.get_names(): + suspected = module_scope[name].get_object() + if suspected is not None and \ + isinstance(suspected, rope.base.pyobjects.PyClass): + return suspected + else: + lineno = self._find_occurrence(name, pymodule.get_resource().read()) + if lineno is not None: + inner_scope = module_scope.get_inner_scope_for_line(lineno) + return inner_scope.pyobject + + def defined_to_pyobject(self, textual): + if len(textual) == 2: + return self._module_to_pyobject(textual) + else: + if textual[2].isdigit(): + result = self._function_to_pyobject(textual) + else: + result = self._class_to_pyobject(textual) + if not isinstance(result, rope.base.pyobjects.PyModule): + return result + + def _find_occurrence(self, name, source): + pattern = re.compile(r'^\s*class\s*' + name + r'\b') + lines = source.split('\n') + for i in range(len(lines)): + if pattern.match(lines[i]): + return i + 1 + + def path_to_resource(self, path): + import rope.base.libutils + root = self.project.address + relpath = rope.base.libutils.relative(root, path) + if relpath is not None: + path = relpath + return super(DOITextualToPyObject, self).path_to_resource(path) diff -r e30544496575 -r 48cacfdc2ca6 vim/sadness/ropevim/src/rope/rope/base/prefs.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vim/sadness/ropevim/src/rope/rope/base/prefs.py Wed Oct 06 12:30:46 2010 -0400 @@ -0,0 +1,41 @@ +class Prefs(object): + + def __init__(self): + self.prefs = {} + self.callbacks = {} + + def set(self, key, value): + """Set the value of `key` preference to `value`.""" + if key in self.callbacks: + self.callbacks[key](value) + else: + self.prefs[key] = value + + def add(self, key, value): + """Add an entry to a list preference + + Add `value` to the list of entries for the `key` preference. + + """ + if not key in self.prefs: + self.prefs[key] = [] + self.prefs[key].append(value) + + def get(self, key, default=None): + """Get the value of the key preference""" + return self.prefs.get(key, default) + + def add_callback(self, key, callback): + """Add `key` preference with `callback` function + + Whenever `key` is set the callback is called with the + given `value` as parameter. + + """ + self.callbacks[key] = callback + + def __setitem__(self, key, value): + self.set(key, value) + + def __getitem__(self, key): + return self.get(key) diff -r e30544496575 -r 48cacfdc2ca6 vim/sadness/ropevim/src/rope/rope/base/project.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vim/sadness/ropevim/src/rope/rope/base/project.py Wed Oct 06 12:30:46 2010 -0400 @@ -0,0 +1,375 @@ +import cPickle as pickle +import os +import shutil +import sys +import warnings + +import rope.base.fscommands +from rope.base import exceptions, taskhandle, prefs, history, pycore, utils +from rope.base.resourceobserver import * +from rope.base.resources import File, Folder, _ResourceMatcher + + +class _Project(object): + + def __init__(self, fscommands): + self.observers = [] + self.fscommands = fscommands + self.prefs = prefs.Prefs() + self.data_files = _DataFiles(self) + + def get_resource(self, resource_name): + """Get a resource in a project. + + `resource_name` is the path of a resource in a project. It is + the path of a resource relative to project root. Project root + folder address is an empty string. If the resource does not + exist a `exceptions.ResourceNotFound` exception would be + raised. Use `get_file()` and `get_folder()` when you need to + get nonexistent `Resource`\s. + + """ + path = self._get_resource_path(resource_name) + if not os.path.exists(path): + raise exceptions.ResourceNotFoundError( + 'Resource <%s> does not exist' % resource_name) + elif os.path.isfile(path): + return File(self, resource_name) + elif os.path.isdir(path): + return Folder(self, resource_name) + else: + raise exceptions.ResourceNotFoundError('Unknown resource ' + + resource_name) + + def validate(self, folder): + """Validate files and folders contained in this folder + + It validates all of the files and folders contained in this + folder if some observers are interested in them. + + """ + for observer in list(self.observers): + observer.validate(folder) + + def add_observer(self, observer): + """Register a `ResourceObserver` + + See `FilteredResourceObserver`. + """ + self.observers.append(observer) + + def remove_observer(self, observer): + """Remove a registered `ResourceObserver`""" + if observer in self.observers: + self.observers.remove(observer) + + def do(self, changes, task_handle=taskhandle.NullTaskHandle()): + """Apply the changes in a `ChangeSet` + + Most of the time you call this function for committing the + changes for a refactoring. + """ + self.history.do(changes, task_handle=task_handle) + + def get_pycore(self): + return self.pycore + + def get_file(self, path): + """Get the file with `path` (it may not exist)""" + return File(self, path) + + def get_folder(self, path): + """Get the folder with `path` (it may not exist)""" + return Folder(self, path) + + def is_ignored(self, resource): + return False + + def get_prefs(self): + return self.prefs + + def _get_resource_path(self, name): + pass + + @property + @utils.saveit + def history(self): + return history.History(self) + + @property + @utils.saveit + def pycore(self): + return pycore.PyCore(self) + + def close(self): + warnings.warn('Cannot close a NoProject', + DeprecationWarning, stacklevel=2) + + ropefolder = None + + +class Project(_Project): + """A Project containing files and folders""" + + def __init__(self, projectroot, fscommands=None, + ropefolder='.ropeproject', **prefs): + """A rope project + + :parameters: + - `projectroot`: The address of the root folder of the project + - `fscommands`: Implements the file system operations used + by rope; have a look at `rope.base.fscommands` + - `ropefolder`: The name of the folder in which rope stores + project configurations and data. Pass `None` for not using + such a folder at all. + - `prefs`: Specify project preferences. These values + overwrite config file preferences. + + """ + if projectroot != '/': + projectroot = _realpath(projectroot).rstrip('/\\') + self._address = projectroot + self._ropefolder_name = ropefolder + if not os.path.exists(self._address): + os.mkdir(self._address) + elif not os.path.isdir(self._address): + raise exceptions.RopeError('Project root exists and' + ' is not a directory') + if fscommands is None: + fscommands = rope.base.fscommands.create_fscommands(self._address) + super(Project, self).__init__(fscommands) + self.ignored = _ResourceMatcher() + self.file_list = _FileListCacher(self) + self.prefs.add_callback('ignored_resources', self.ignored.set_patterns) + if ropefolder is not None: + self.prefs['ignored_resources'] = [ropefolder] + self._init_prefs(prefs) + + def get_files(self): + return self.file_list.get_files() + + def _get_resource_path(self, name): + return os.path.join(self._address, *name.split('/')) + + def _init_ropefolder(self): + if self.ropefolder is not None: + if not self.ropefolder.exists(): + self._create_recursively(self.ropefolder) + if not self.ropefolder.has_child('config.py'): + config = self.ropefolder.create_file('config.py') + config.write(self._default_config()) + + def _create_recursively(self, folder): + if folder.parent != self.root and not folder.parent.exists(): + self._create_recursively(folder.parent) + folder.create() + + def _init_prefs(self, prefs): + run_globals = {} + if self.ropefolder is not None: + config = self.get_file(self.ropefolder.path + '/config.py') + run_globals.update({'__name__': '__main__', + '__builtins__': __builtins__, + '__file__': config.real_path}) + if config.exists(): + config = self.ropefolder.get_child('config.py') + execfile(config.real_path, run_globals) + else: + exec(self._default_config(), run_globals) + if 'set_prefs' in run_globals: + run_globals['set_prefs'](self.prefs) + for key, value in prefs.items(): + self.prefs[key] = value + self._init_other_parts() + self._init_ropefolder() + if 'project_opened' in run_globals: + run_globals['project_opened'](self) + + def _default_config(self): + import rope.base.default_config + import inspect + return inspect.getsource(rope.base.default_config) + + def _init_other_parts(self): + # Forcing the creation of `self.pycore` to register observers + self.pycore + + def is_ignored(self, resource): + return self.ignored.does_match(resource) + + def sync(self): + """Closes project open resources""" + self.close() + + def close(self): + """Closes project open resources""" + self.data_files.write() + + def set(self, key, value): + """Set the `key` preference to `value`""" + self.prefs.set(key, value) + + @property + def ropefolder(self): + if self._ropefolder_name is not None: + return self.get_folder(self._ropefolder_name) + + def validate(self, folder=None): + if folder is None: + folder = self.root + super(Project, self).validate(folder) + + root = property(lambda self: self.get_resource('')) + address = property(lambda self: self._address) + + +class NoProject(_Project): + """A null object for holding out of project files. + + This class is singleton use `get_no_project` global function + """ + + def __init__(self): + fscommands = rope.base.fscommands.FileSystemCommands() + super(NoProject, self).__init__(fscommands) + + def _get_resource_path(self, name): + real_name = name.replace('/', os.path.sep) + return _realpath(real_name) + + def get_resource(self, name): + universal_name = _realpath(name).replace(os.path.sep, '/') + return super(NoProject, self).get_resource(universal_name) + + def get_files(self): + return [] + + _no_project = None + + +def get_no_project(): + if NoProject._no_project is None: + NoProject._no_project = NoProject() + return NoProject._no_project + + +class _FileListCacher(object): + + def __init__(self, project): + self.project = project + self.files = None + rawobserver = ResourceObserver( + self._changed, self._invalid, self._invalid, + self._invalid, self._invalid) + self.project.add_observer(rawobserver) + + def get_files(self): + if self.files is None: + self.files = set() + self._add_files(self.project.root) + return self.files + + def _add_files(self, folder): + for child in folder.get_children(): + if child.is_folder(): + self._add_files(child) + elif not self.project.is_ignored(child): + self.files.add(child) + + def _changed(self, resource): + if resource.is_folder(): + self.files = None + + def _invalid(self, resource, new_resource=None): + self.files = None + + +class _DataFiles(object): + + def __init__(self, project): + self.project = project + self.hooks = [] + + def read_data(self, name, compress=False, import_=False): + if self.project.ropefolder is None: + return None + compress = compress and self._can_compress() + opener = self._get_opener(compress) + file = self._get_file(name, compress) + if not compress and import_: + self._import_old_files(name) + if file.exists(): + input = opener(file.real_path, 'rb') + try: + result = [] + try: + while True: + result.append(pickle.load(input)) + except EOFError: + pass + if len(result) == 1: + return result[0] + if len(result) > 1: + return result + finally: + input.close() + + def write_data(self, name, data, compress=False): + if self.project.ropefolder is not None: + compress = compress and self._can_compress() + file = self._get_file(name, compress) + opener = self._get_opener(compress) + output = opener(file.real_path, 'wb') + try: + pickle.dump(data, output, 2) + finally: + output.close() + + def add_write_hook(self, hook): + self.hooks.append(hook) + + def write(self): + for hook in self.hooks: + hook() + + def _can_compress(self): + try: + import gzip + return True + except ImportError: + return False + + def _import_old_files(self, name): + old = self._get_file(name + '.pickle', False) + new = self._get_file(name, False) + if old.exists() and not new.exists(): + shutil.move(old.real_path, new.real_path) + + def _get_opener(self, compress): + if compress: + try: + import gzip + return gzip.open + except ImportError: + pass + return open + + def _get_file(self, name, compress): + path = self.project.ropefolder.path + '/' + name + if compress: + path += '.gz' + return self.project.get_file(path) + + +def _realpath(path): + """Return the real path of `path` + + Is equivalent to ``realpath(abspath(expanduser(path)))``. + + """ + # there is a bug in cygwin for os.path.abspath() for abs paths + if sys.platform == 'cygwin': + if path[1:3] == ':\\': + return path + return os.path.abspath(os.path.expanduser(path)) + return os.path.realpath(os.path.abspath(os.path.expanduser(path))) diff -r e30544496575 -r 48cacfdc2ca6 vim/sadness/ropevim/src/rope/rope/base/pycore.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vim/sadness/ropevim/src/rope/rope/base/pycore.py Wed Oct 06 12:30:46 2010 -0400 @@ -0,0 +1,409 @@ +import bisect +import difflib +import sys +import warnings + +import rope.base.oi.doa +import rope.base.oi.objectinfo +import rope.base.oi.soa +from rope.base import ast, exceptions, taskhandle, utils, stdmods +from rope.base.exceptions import ModuleNotFoundError +from rope.base.pyobjectsdef import PyModule, PyPackage, PyClass +import rope.base.resources +import rope.base.resourceobserver +from rope.base import builtins + + +class PyCore(object): + + def __init__(self, project): + self.project = project + self._init_resource_observer() + self.cache_observers = [] + self.module_cache = _ModuleCache(self) + self.extension_cache = _ExtensionCache(self) + self.object_info = rope.base.oi.objectinfo.ObjectInfoManager(project) + self._init_python_files() + self._init_automatic_soa() + self._init_source_folders() + + def _init_python_files(self): + self.python_matcher = None + patterns = self.project.prefs.get('python_files', None) + if patterns is not None: + self.python_matcher = rope.base.resources._ResourceMatcher() + self.python_matcher.set_patterns(patterns) + + def _init_resource_observer(self): + callback = self._invalidate_resource_cache + observer = rope.base.resourceobserver.ResourceObserver( + changed=callback, moved=callback, removed=callback) + self.observer = rope.base.resourceobserver.FilteredResourceObserver(observer) + self.project.add_observer(self.observer) + + def _init_source_folders(self): + self._custom_source_folders = [] + for path in self.project.prefs.get('source_folders', []): + folder = self.project.get_resource(path) + self._custom_source_folders.append(folder) + + def _init_automatic_soa(self): + if not self.automatic_soa: + return + callback = self._file_changed_for_soa + observer = rope.base.resourceobserver.ResourceObserver( + changed=callback, moved=callback, removed=callback) + self.project.add_observer(observer) + + @property + def automatic_soa(self): + auto_soa = self.project.prefs.get('automatic_soi', None) + return self.project.prefs.get('automatic_soa', auto_soa) + + def _file_changed_for_soa(self, resource, new_resource=None): + old_contents = self.project.history.\ + contents_before_current_change(resource) + if old_contents is not None: + perform_soa_on_changed_scopes(self.project, resource, old_contents) + + def is_python_file(self, resource): + if resource.is_folder(): + return False + if self.python_matcher is None: + return resource.name.endswith('.py') + return self.python_matcher.does_match(resource) + + def get_module(self, name, folder=None): + """Returns a `PyObject` if the module was found.""" + module = self.find_module(name, folder) + if module is None: + module = self._builtin_module(name) + if module is None: + raise ModuleNotFoundError('Module %s not found' % name) + return module + return self.resource_to_pyobject(module) + + def _builtin_submodules(self, modname): + result = {} + for extension in self.extension_modules: + if extension.startswith(modname + '.'): + name = extension[len(modname) + 1:] + if '.' not in name: + result[name] = self._builtin_module(extension) + return result + + def _builtin_module(self, name): + return self.extension_cache.get_pymodule(name) + + def get_relative_module(self, name, folder, level): + module = self.find_relative_module(name, folder, level) + if module is None: + raise ModuleNotFoundError('Module %s not found' % name) + return self.resource_to_pyobject(module) + + def get_string_module(self, code, resource=None, force_errors=False): + """Returns a `PyObject` object for the given code + + If `force_errors` is `True`, `exceptions.ModuleSyntaxError` is + raised if module has syntax errors. This overrides + ``ignore_syntax_errors`` project config. + + """ + return PyModule(self, code, resource, force_errors=force_errors) + + def get_string_scope(self, code, resource=None): + """Returns a `Scope` object for the given code""" + return self.get_string_module(code, resource).get_scope() + + def _invalidate_resource_cache(self, resource, new_resource=None): + for observer in self.cache_observers: + observer(resource) + + def _find_module_in_folder(self, folder, modname): + module = folder + packages = modname.split('.') + for pkg in packages[:-1]: + if module.is_folder() and module.has_child(pkg): + module = module.get_child(pkg) + else: + return None + if module.is_folder(): + if module.has_child(packages[-1]) and \ + module.get_child(packages[-1]).is_folder(): + return module.get_child(packages[-1]) + elif module.has_child(packages[-1] + '.py') and \ + not module.get_child(packages[-1] + '.py').is_folder(): + return module.get_child(packages[-1] + '.py') + + def get_python_path_folders(self): + import rope.base.project + result = [] + for src in self.project.prefs.get('python_path', []) + sys.path: + try: + src_folder = rope.base.project.get_no_project().get_resource(src) + result.append(src_folder) + except rope.base.exceptions.ResourceNotFoundError: + pass + return result + + def find_module(self, modname, folder=None): + """Returns a resource corresponding to the given module + + returns None if it can not be found + """ + return self._find_module(modname, folder) + + def find_relative_module(self, modname, folder, level): + for i in range(level - 1): + folder = folder.parent + if modname == '': + return folder + else: + return self._find_module_in_folder(folder, modname) + + def _find_module(self, modname, folder=None): + """Return `modname` module resource""" + for src in self.get_source_folders(): + module = self._find_module_in_folder(src, modname) + if module is not None: + return module + for src in self.get_python_path_folders(): + module = self._find_module_in_folder(src, modname) + if module is not None: + return module + if folder is not None: + module = self._find_module_in_folder(folder, modname) + if module is not None: + return module + return None + + # INFO: It was decided not to cache source folders, since: + # - Does not take much time when the root folder contains + # packages, that is most of the time + # - We need a separate resource observer; `self.observer` + # does not get notified about module and folder creations + def get_source_folders(self): + """Returns project source folders""" + if self.project.root is None: + return [] + result = list(self._custom_source_folders) + result.extend(self._find_source_folders(self.project.root)) + return result + + def resource_to_pyobject(self, resource, force_errors=False): + return self.module_cache.get_pymodule(resource, force_errors) + + def get_python_files(self): + """Returns all python files available in the project""" + return [resource for resource in self.project.get_files() + if self.is_python_file(resource)] + + def _is_package(self, folder): + if folder.has_child('__init__.py') and \ + not folder.get_child('__init__.py').is_folder(): + return True + else: + return False + + def _find_source_folders(self, folder): + for resource in folder.get_folders(): + if self._is_package(resource): + return [folder] + result = [] + for resource in folder.get_files(): + if resource.name.endswith('.py'): + result.append(folder) + break + for resource in folder.get_folders(): + result.extend(self._find_source_folders(resource)) + return result + + def run_module(self, resource, args=None, stdin=None, stdout=None): + """Run `resource` module + + Returns a `rope.base.oi.doa.PythonFileRunner` object for + controlling the process. + + """ + perform_doa = self.project.prefs.get('perform_doi', True) + perform_doa = self.project.prefs.get('perform_doa', perform_doa) + receiver = self.object_info.doa_data_received + if not perform_doa: + receiver = None + runner = rope.base.oi.doa.PythonFileRunner( + self, resource, args, stdin, stdout, receiver) + runner.add_finishing_observer(self.module_cache.forget_all_data) + runner.run() + return runner + + def analyze_module(self, resource, should_analyze=lambda py: True, + search_subscopes=lambda py: True, followed_calls=None): + """Analyze `resource` module for static object inference + + This function forces rope to analyze this module to collect + information about function calls. `should_analyze` is a + function that is called with a `PyDefinedObject` argument. If + it returns `True` the element is analyzed. If it is `None` or + returns `False` the element is not analyzed. + + `search_subscopes` is like `should_analyze`; The difference is + that if it returns `False` the sub-scopes are all ignored. + That is it is assumed that `should_analyze` returns `False` + for all of its subscopes. + + `followed_calls` override the value of ``soa_followed_calls`` + project config. + """ + if followed_calls is None: + followed_calls = self.project.prefs.get('soa_followed_calls', 0) + pymodule = self.resource_to_pyobject(resource) + self.module_cache.forget_all_data() + rope.base.oi.soa.analyze_module( + self, pymodule, should_analyze, search_subscopes, followed_calls) + + def get_classes(self, task_handle=taskhandle.NullTaskHandle()): + warnings.warn('`PyCore.get_classes()` is deprecated', + DeprecationWarning, stacklevel=2) + return [] + + def __str__(self): + return str(self.module_cache) + str(self.object_info) + + def modname(self, resource): + if resource.is_folder(): + module_name = resource.name + source_folder = resource.parent + elif resource.name == '__init__.py': + module_name = resource.parent.name + source_folder = resource.parent.parent + else: + module_name = resource.name[:-3] + source_folder = resource.parent + + while source_folder != source_folder.parent and \ + source_folder.has_child('__init__.py'): + module_name = source_folder.name + '.' + module_name + source_folder = source_folder.parent + return module_name + + @property + @utils.cacheit + def extension_modules(self): + result = set(self.project.prefs.get('extension_modules', [])) + if self.project.prefs.get('import_dynload_stdmods', False): + result.update(stdmods.dynload_modules()) + return result + + +class _ModuleCache(object): + + def __init__(self, pycore): + self.pycore = pycore + self.module_map = {} + self.pycore.cache_observers.append(self._invalidate_resource) + self.observer = self.pycore.observer + + def _invalidate_resource(self, resource): + if resource in self.module_map: + self.forget_all_data() + self.observer.remove_resource(resource) + del self.module_map[resource] + + def get_pymodule(self, resource, force_errors=False): + if resource in self.module_map: + return self.module_map[resource] + if resource.is_folder(): + result = PyPackage(self.pycore, resource, + force_errors=force_errors) + else: + result = PyModule(self.pycore, resource=resource, + force_errors=force_errors) + if result.has_errors: + return result + self.module_map[resource] = result + self.observer.add_resource(resource) + return result + + def forget_all_data(self): + for pymodule in self.module_map.values(): + pymodule._forget_concluded_data() + + def __str__(self): + return 'PyCore caches %d PyModules\n' % len(self.module_map) + + +class _ExtensionCache(object): + + def __init__(self, pycore): + self.pycore = pycore + self.extensions = {} + + def get_pymodule(self, name): + if name == '__builtin__': + return builtins.builtins + allowed = self.pycore.extension_modules + if name not in self.extensions and name in allowed: + self.extensions[name] = builtins.BuiltinModule(name, self.pycore) + return self.extensions.get(name) + + +def perform_soa_on_changed_scopes(project, resource, old_contents): + pycore = project.pycore + if resource.exists() and pycore.is_python_file(resource): + try: + new_contents = resource.read() + # detecting changes in new_contents relative to old_contents + detector = _TextChangeDetector(new_contents, old_contents) + def search_subscopes(pydefined): + scope = pydefined.get_scope() + return detector.is_changed(scope.get_start(), scope.get_end()) + def should_analyze(pydefined): + scope = pydefined.get_scope() + start = scope.get_start() + end = scope.get_end() + return detector.consume_changes(start, end) + pycore.analyze_module(resource, should_analyze, search_subscopes) + except exceptions.ModuleSyntaxError: + pass + + +class _TextChangeDetector(object): + + def __init__(self, old, new): + self.old = old + self.new = new + self._set_diffs() + + def _set_diffs(self): + differ = difflib.Differ() + self.lines = [] + lineno = 0 + for line in differ.compare(self.old.splitlines(True), + self.new.splitlines(True)): + if line.startswith(' '): + lineno += 1 + elif line.startswith('-'): + lineno += 1 + self.lines.append(lineno) + + def is_changed(self, start, end): + """Tell whether any of start till end lines have changed + + The end points are inclusive and indices start from 1. + """ + left, right = self._get_changed(start, end) + if left < right: + return True + return False + + def consume_changes(self, start, end): + """Clear the changed status of lines from start till end""" + left, right = self._get_changed(start, end) + if left < right: + del self.lines[left:right] + return left < right + + def _get_changed(self, start, end): + left = bisect.bisect_left(self.lines, start) + right = bisect.bisect_right(self.lines, end) + return left, right diff -r e30544496575 -r 48cacfdc2ca6 vim/sadness/ropevim/src/rope/rope/base/pynames.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vim/sadness/ropevim/src/rope/rope/base/pynames.py Wed Oct 06 12:30:46 2010 -0400 @@ -0,0 +1,199 @@ +import rope.base.pyobjects +from rope.base import exceptions, utils + + +class PyName(object): + """References to `PyObject`\s inside python programs""" + + def get_object(self): + """Return the `PyObject` object referenced by this `PyName`""" + + def get_definition_location(self): + """Return a (module, lineno) tuple""" + + +class DefinedName(PyName): + + def __init__(self, pyobject): + self.pyobject = pyobject + + def get_object(self): + return self.pyobject + + def get_definition_location(self): + return (self.pyobject.get_module(), self.pyobject.get_ast().lineno) + + +class AssignedName(PyName): + """Only a placeholder""" + + +class UnboundName(PyName): + + def __init__(self, pyobject=None): + self.pyobject = pyobject + if self.pyobject is None: + self.pyobject = rope.base.pyobjects.get_unknown() + + def get_object(self): + return self.pyobject + + def get_definition_location(self): + return (None, None) + + +class AssignmentValue(object): + """An assigned expression""" + + def __init__(self, ast_node, levels=None, evaluation='', + assign_type=False): + """The `level` is `None` for simple assignments and is + a list of numbers for tuple assignments for example in:: + + a, (b, c) = x + + The levels for for `a` is ``[0]``, for `b` is ``[1, 0]`` and for + `c` is ``[1, 1]``. + + """ + self.ast_node = ast_node + if levels == None: + self.levels = [] + else: + self.levels = levels + self.evaluation = evaluation + self.assign_type = assign_type + + def get_lineno(self): + return self.ast_node.lineno + + +class EvaluatedName(PyName): + """A name whose object will be evaluated later""" + + def __init__(self, callback, module=None, lineno=None): + self.module = module + self.lineno = lineno + self.callback = callback + self.pyobject = _Inferred(callback, _get_concluded_data(module)) + + def get_object(self): + return self.pyobject.get() + + def get_definition_location(self): + return (self.module, self.lineno) + + def invalidate(self): + """Forget the `PyObject` this `PyName` holds""" + self.pyobject.set(None) + + +class ParameterName(PyName): + """Only a placeholder""" + + +class ImportedModule(PyName): + + def __init__(self, importing_module, module_name=None, + level=0, resource=None): + self.importing_module = importing_module + self.module_name = module_name + self.level = level + self.resource = resource + self.pymodule = _get_concluded_data(self.importing_module) + + def _current_folder(self): + resource = self.importing_module.get_module().get_resource() + if resource is None: + return None + return resource.parent + + def _get_pymodule(self): + if self.pymodule.get() is None: + pycore = self.importing_module.pycore + if self.resource is not None: + self.pymodule.set(pycore.resource_to_pyobject(self.resource)) + elif self.module_name is not None: + try: + if self.level == 0: + pymodule = pycore.get_module(self.module_name, + self._current_folder()) + else: + pymodule = pycore.get_relative_module( + self.module_name, self._current_folder(), self.level) + self.pymodule.set(pymodule) + except exceptions.ModuleNotFoundError: + pass + return self.pymodule.get() + + def get_object(self): + if self._get_pymodule() is None: + return rope.base.pyobjects.get_unknown() + return self._get_pymodule() + + def get_definition_location(self): + pymodule = self._get_pymodule() + if not isinstance(pymodule, rope.base.pyobjects.PyDefinedObject): + return (None, None) + return (pymodule.get_module(), 1) + + +class ImportedName(PyName): + + def __init__(self, imported_module, imported_name): + self.imported_module = imported_module + self.imported_name = imported_name + + def _get_imported_pyname(self): + try: + result = self.imported_module.get_object()[self.imported_name] + if result != self: + return result + except exceptions.AttributeNotFoundError: + pass + return UnboundName() + + @utils.prevent_recursion(rope.base.pyobjects.get_unknown) + def get_object(self): + return self._get_imported_pyname().get_object() + + @utils.prevent_recursion(lambda: (None, None)) + def get_definition_location(self): + return self._get_imported_pyname().get_definition_location() + + +def _get_concluded_data(module): + if module is None: + return rope.base.pyobjects._ConcludedData() + return module._get_concluded_data() + + +def _circular_inference(): + raise rope.base.pyobjects.IsBeingInferredError( + 'Circular Object Inference') + +class _Inferred(object): + + def __init__(self, get_inferred, concluded=None): + self.get_inferred = get_inferred + self.concluded = concluded + if self.concluded is None: + self.temp = None + + @utils.prevent_recursion(_circular_inference) + def get(self, *args, **kwds): + if self.concluded is None or self.concluded.get() is None: + self.set(self.get_inferred(*args, **kwds)) + if self._get() is None: + self.set(rope.base.pyobjects.get_unknown()) + return self._get() + + def set(self, pyobject): + if self.concluded is not None: + self.concluded.set(pyobject) + self.temp = pyobject + + def _get(self): + if self.concluded is not None: + return self.concluded.get() + return self.temp diff -r e30544496575 -r 48cacfdc2ca6 vim/sadness/ropevim/src/rope/rope/base/pynamesdef.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vim/sadness/ropevim/src/rope/rope/base/pynamesdef.py Wed Oct 06 12:30:46 2010 -0400 @@ -0,0 +1,55 @@ +import rope.base.oi.soi +from rope.base import pynames +from rope.base.pynames import * + + +class AssignedName(pynames.AssignedName): + + def __init__(self, lineno=None, module=None, pyobject=None): + self.lineno = lineno + self.module = module + self.assignments = [] + self.pyobject = _Inferred(self._get_inferred, + pynames._get_concluded_data(module)) + self.pyobject.set(pyobject) + + @utils.prevent_recursion(lambda: None) + def _get_inferred(self): + if self.module is not None: + return rope.base.oi.soi.infer_assigned_object(self) + + def get_object(self): + return self.pyobject.get() + + def get_definition_location(self): + """Returns a (module, lineno) tuple""" + if self.lineno is None and self.assignments: + self.lineno = self.assignments[0].get_lineno() + return (self.module, self.lineno) + + def invalidate(self): + """Forget the `PyObject` this `PyName` holds""" + self.pyobject.set(None) + + +class ParameterName(pynames.ParameterName): + + def __init__(self, pyfunction, index): + self.pyfunction = pyfunction + self.index = index + + def get_object(self): + result = self.pyfunction.get_parameter(self.index) + if result is None: + result = rope.base.pyobjects.get_unknown() + return result + + def get_objects(self): + """Returns the list of objects passed as this parameter""" + return rope.base.oi.soi.get_passed_objects( + self.pyfunction, self.index) + + def get_definition_location(self): + return (self.pyfunction.get_module(), self.pyfunction.get_ast().lineno) + +_Inferred = pynames._Inferred diff -r e30544496575 -r 48cacfdc2ca6 vim/sadness/ropevim/src/rope/rope/base/pyobjects.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vim/sadness/ropevim/src/rope/rope/base/pyobjects.py Wed Oct 06 12:30:46 2010 -0400 @@ -0,0 +1,311 @@ +from rope.base.fscommands import _decode_data +from rope.base import ast, exceptions, utils + + +class PyObject(object): + + def __init__(self, type_): + if type_ is None: + type_ = self + self.type = type_ + + def get_attributes(self): + if self.type is self: + return {} + return self.type.get_attributes() + + def get_attribute(self, name): + if name not in self.get_attributes(): + raise exceptions.AttributeNotFoundError( + 'Attribute %s not found' % name) + return self.get_attributes()[name] + + def get_type(self): + return self.type + + def __getitem__(self, key): + """The same as ``get_attribute(key)``""" + return self.get_attribute(key) + + def __contains__(self, key): + """The same as ``key in self.get_attributes()``""" + return key in self.get_attributes() + + def __eq__(self, obj): + """Check the equality of two `PyObject`\s + + Currently it is assumed that instances (the direct instances + of `PyObject`, not the instances of its subclasses) are equal + if their types are equal. For every other object like + defineds or builtins rope assumes objects are reference + objects and their identities should match. + + """ + if self.__class__ != obj.__class__: + return False + if type(self) == PyObject: + if self is not self.type: + return self.type == obj.type + else: + return self.type is obj.type + return self is obj + + def __ne__(self, obj): + return not self.__eq__(obj) + + def __hash__(self): + """See docs for `__eq__()` method""" + if type(self) == PyObject and self != self.type: + return hash(self.type) + 1 + else: + return super(PyObject, self).__hash__() + + def __iter__(self): + """The same as ``iter(self.get_attributes())``""" + return iter(self.get_attributes()) + + _types = None + _unknown = None + + @staticmethod + def _get_base_type(name): + if PyObject._types is None: + PyObject._types = {} + base_type = PyObject(None) + PyObject._types['Type'] = base_type + PyObject._types['Module'] = PyObject(base_type) + PyObject._types['Function'] = PyObject(base_type) + PyObject._types['Unknown'] = PyObject(base_type) + return PyObject._types[name] + + +def get_base_type(name): + """Return the base type with name `name`. + + The base types are 'Type', 'Function', 'Module' and 'Unknown'. It + was used to check the type of a `PyObject` but currently its use + is discouraged. Use classes defined in this module instead. + For example instead of + ``pyobject.get_type() == get_base_type('Function')`` use + ``isinstance(pyobject, AbstractFunction)``. + + You can use `AbstractClass` for classes, `AbstractFunction` for + functions, and `AbstractModule` for modules. You can also use + `PyFunction` and `PyClass` for testing if an object is + defined somewhere and rope can access its source. These classes + provide more methods. + + """ + return PyObject._get_base_type(name) + + +def get_unknown(): + """Return a pyobject whose type is unknown + + Note that two unknown objects are equal. So for example you can + write:: + + if pyname.get_object() == get_unknown(): + print 'cannot determine what this pyname holds' + + Rope could have used `None` for indicating unknown objects but + we had to check that in many places. So actually this method + returns a null object. + + """ + if PyObject._unknown is None: + PyObject._unknown = PyObject(get_base_type('Unknown')) + return PyObject._unknown + + +class AbstractClass(PyObject): + + def __init__(self): + super(AbstractClass, self).__init__(get_base_type('Type')) + + def get_name(self): + pass + + def get_doc(self): + pass + + def get_superclasses(self): + return [] + + +class AbstractFunction(PyObject): + + def __init__(self): + super(AbstractFunction, self).__init__(get_base_type('Function')) + + def get_name(self): + pass + + def get_doc(self): + pass + + def get_param_names(self, special_args=True): + return [] + + def get_returned_object(self, args): + return get_unknown() + + +class AbstractModule(PyObject): + + def __init__(self, doc=None): + super(AbstractModule, self).__init__(get_base_type('Module')) + + def get_doc(self): + pass + + def get_resource(self): + pass + + +class PyDefinedObject(object): + """Python defined names that rope can access their sources""" + + def __init__(self, pycore, ast_node, parent): + self.pycore = pycore + self.ast_node = ast_node + self.scope = None + self.parent = parent + self.structural_attributes = None + self.concluded_attributes = self.get_module()._get_concluded_data() + self.attributes = self.get_module()._get_concluded_data() + self.defineds = None + + visitor_class = None + + @utils.prevent_recursion(lambda: {}) + def _get_structural_attributes(self): + if self.structural_attributes is None: + self.structural_attributes = self._create_structural_attributes() + return self.structural_attributes + + @utils.prevent_recursion(lambda: {}) + def _get_concluded_attributes(self): + if self.concluded_attributes.get() is None: + self._get_structural_attributes() + self.concluded_attributes.set(self._create_concluded_attributes()) + return self.concluded_attributes.get() + + def get_attributes(self): + if self.attributes.get() is None: + result = dict(self._get_concluded_attributes()) + result.update(self._get_structural_attributes()) + self.attributes.set(result) + return self.attributes.get() + + def get_attribute(self, name): + if name in self._get_structural_attributes(): + return self._get_structural_attributes()[name] + if name in self._get_concluded_attributes(): + return self._get_concluded_attributes()[name] + raise exceptions.AttributeNotFoundError('Attribute %s not found' % + name) + + def get_scope(self): + if self.scope is None: + self.scope = self._create_scope() + return self.scope + + def get_module(self): + current_object = self + while current_object.parent is not None: + current_object = current_object.parent + return current_object + + def get_doc(self): + if len(self.get_ast().body) > 0: + expr = self.get_ast().body[0] + if isinstance(expr, ast.Expr) and \ + isinstance(expr.value, ast.Str): + docstring = expr.value.s + coding = self.get_module().coding + return _decode_data(docstring, coding) + + def _get_defined_objects(self): + if self.defineds is None: + self._get_structural_attributes() + return self.defineds + + def _create_structural_attributes(self): + if self.visitor_class is None: + return {} + new_visitor = self.visitor_class(self.pycore, self) + for child in ast.get_child_nodes(self.ast_node): + ast.walk(child, new_visitor) + self.defineds = new_visitor.defineds + return new_visitor.names + + def _create_concluded_attributes(self): + return {} + + def get_ast(self): + return self.ast_node + + def _create_scope(self): + pass + + +class PyFunction(PyDefinedObject, AbstractFunction): + """Only a placeholder""" + + +class PyClass(PyDefinedObject, AbstractClass): + """Only a placeholder""" + + +class _ConcludedData(object): + + def __init__(self): + self.data_ = None + + def set(self, data): + self.data_ = data + + def get(self): + return self.data_ + + data = property(get, set) + + def _invalidate(self): + self.data = None + + def __str__(self): + return '<' + str(self.data) + '>' + + +class _PyModule(PyDefinedObject, AbstractModule): + + def __init__(self, pycore, ast_node, resource): + self.resource = resource + self.concluded_data = [] + AbstractModule.__init__(self) + PyDefinedObject.__init__(self, pycore, ast_node, None) + + def _get_concluded_data(self): + new_data = _ConcludedData() + self.concluded_data.append(new_data) + return new_data + + def _forget_concluded_data(self): + for data in self.concluded_data: + data._invalidate() + + def get_resource(self): + return self.resource + + +class PyModule(_PyModule): + """Only a placeholder""" + + +class PyPackage(_PyModule): + """Only a placeholder""" + + +class IsBeingInferredError(exceptions.RopeError): + pass diff -r e30544496575 -r 48cacfdc2ca6 vim/sadness/ropevim/src/rope/rope/base/pyobjectsdef.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vim/sadness/ropevim/src/rope/rope/base/pyobjectsdef.py Wed Oct 06 12:30:46 2010 -0400 @@ -0,0 +1,537 @@ +import rope.base.codeanalyze +import rope.base.evaluate +import rope.base.builtins +import rope.base.oi.soi +import rope.base.pyscopes +from rope.base import (pynamesdef as pynames, exceptions, ast, + astutils, pyobjects, fscommands, arguments, utils) +from rope.base.pyobjects import * + + +class PyFunction(pyobjects.PyFunction): + + def __init__(self, pycore, ast_node, parent): + AbstractFunction.__init__(self) + PyDefinedObject.__init__(self, pycore, ast_node, parent) + self.arguments = self.ast_node.args + self.parameter_pyobjects = pynames._Inferred( + self._infer_parameters, self.get_module()._get_concluded_data()) + self.returned = pynames._Inferred(self._infer_returned) + self.parameter_pynames = None + + def _create_structural_attributes(self): + return {} + + def _create_concluded_attributes(self): + return {} + + def _create_scope(self): + return rope.base.pyscopes.FunctionScope(self.pycore, self, + _FunctionVisitor) + + def _infer_parameters(self): + pyobjects = rope.base.oi.soi.infer_parameter_objects(self) + self._handle_special_args(pyobjects) + return pyobjects + + def _infer_returned(self, args=None): + return rope.base.oi.soi.infer_returned_object(self, args) + + def _handle_special_args(self, pyobjects): + if len(pyobjects) == len(self.arguments.args): + if self.arguments.vararg: + pyobjects.append(rope.base.builtins.get_list()) + if self.arguments.kwarg: + pyobjects.append(rope.base.builtins.get_dict()) + + def _set_parameter_pyobjects(self, pyobjects): + if pyobjects is not None: + self._handle_special_args(pyobjects) + self.parameter_pyobjects.set(pyobjects) + + def get_parameters(self): + if self.parameter_pynames is None: + result = {} + for index, name in enumerate(self.get_param_names()): + # TODO: handle tuple parameters + result[name] = pynames.ParameterName(self, index) + self.parameter_pynames = result + return self.parameter_pynames + + def get_parameter(self, index): + if index < len(self.parameter_pyobjects.get()): + return self.parameter_pyobjects.get()[index] + + def get_returned_object(self, args): + return self.returned.get(args) + + def get_name(self): + return self.get_ast().name + + def get_param_names(self, special_args=True): + # TODO: handle tuple parameters + result = [node.id for node in self.arguments.args + if isinstance(node, ast.Name)] + if special_args: + if self.arguments.vararg: + result.append(self.arguments.vararg) + if self.arguments.kwarg: + result.append(self.arguments.kwarg) + return result + + def get_kind(self): + """Get function type + + It returns one of 'function', 'method', 'staticmethod' or + 'classmethod' strs. + + """ + scope = self.parent.get_scope() + if isinstance(self.parent, PyClass): + for decorator in self.decorators: + pyname = rope.base.evaluate.eval_node(scope, decorator) + if pyname == rope.base.builtins.builtins['staticmethod']: + return 'staticmethod' + if pyname == rope.base.builtins.builtins['classmethod']: + return 'classmethod' + return 'method' + return 'function' + + @property + def decorators(self): + try: + return getattr(self.ast_node, 'decorator_list') + except AttributeError: + return getattr(self.ast_node, 'decorators', None) + + +class PyClass(pyobjects.PyClass): + + def __init__(self, pycore, ast_node, parent): + self.visitor_class = _ClassVisitor + AbstractClass.__init__(self) + PyDefinedObject.__init__(self, pycore, ast_node, parent) + self.parent = parent + self._superclasses = self.get_module()._get_concluded_data() + + def get_superclasses(self): + if self._superclasses.get() is None: + self._superclasses.set(self._get_bases()) + return self._superclasses.get() + + def get_name(self): + return self.get_ast().name + + def _create_concluded_attributes(self): + result = {} + for base in reversed(self.get_superclasses()): + result.update(base.get_attributes()) + return result + + def _get_bases(self): + result = [] + for base_name in self.ast_node.bases: + base = rope.base.evaluate.eval_node(self.parent.get_scope(), + base_name) + if base is not None and \ + base.get_object().get_type() == get_base_type('Type'): + result.append(base.get_object()) + return result + + def _create_scope(self): + return rope.base.pyscopes.ClassScope(self.pycore, self) + + +class PyModule(pyobjects.PyModule): + + def __init__(self, pycore, source=None, + resource=None, force_errors=False): + ignore = pycore.project.prefs.get('ignore_syntax_errors', False) + syntax_errors = force_errors or not ignore + self.has_errors = False + try: + source, node = self._init_source(pycore, source, resource) + except exceptions.ModuleSyntaxError: + self.has_errors = True + if syntax_errors: + raise + else: + source = '\n' + node = ast.parse('\n') + self.source_code = source + self.star_imports = [] + self.visitor_class = _GlobalVisitor + self.coding = fscommands.read_str_coding(self.source_code) + super(PyModule, self).__init__(pycore, node, resource) + + def _init_source(self, pycore, source_code, resource): + filename = 'string' + if resource: + filename = resource.path + try: + if source_code is None: + source_bytes = resource.read_bytes() + source_code = fscommands.file_data_to_unicode(source_bytes) + else: + if isinstance(source_code, unicode): + source_bytes = fscommands.unicode_to_file_data(source_code) + else: + source_bytes = source_code + ast_node = ast.parse(source_bytes, filename=filename) + except SyntaxError, e: + raise exceptions.ModuleSyntaxError(filename, e.lineno, e.msg) + except UnicodeDecodeError, e: + raise exceptions.ModuleSyntaxError(filename, 1, '%s' % (e.reason)) + return source_code, ast_node + + @utils.prevent_recursion(lambda: {}) + def _create_concluded_attributes(self): + result = {} + for star_import in self.star_imports: + result.update(star_import.get_names()) + return result + + def _create_scope(self): + return rope.base.pyscopes.GlobalScope(self.pycore, self) + + @property + @utils.saveit + def lines(self): + """A `SourceLinesAdapter`""" + return rope.base.codeanalyze.SourceLinesAdapter(self.source_code) + + @property + @utils.saveit + def logical_lines(self): + """A `LogicalLinesFinder`""" + return rope.base.codeanalyze.CachingLogicalLineFinder(self.lines) + + +class PyPackage(pyobjects.PyPackage): + + def __init__(self, pycore, resource=None, force_errors=False): + self.resource = resource + init_dot_py = self._get_init_dot_py() + if init_dot_py is not None: + ast_node = pycore.resource_to_pyobject( + init_dot_py, force_errors=force_errors).get_ast() + else: + ast_node = ast.parse('\n') + super(PyPackage, self).__init__(pycore, ast_node, resource) + + def _create_structural_attributes(self): + result = {} + modname = self.pycore.modname(self.resource) + extension_submodules = self.pycore._builtin_submodules(modname) + for name, module in extension_submodules.iteritems(): + result[name] = rope.base.builtins.BuiltinName(module) + if self.resource is None: + return result + for name, resource in self._get_child_resources().items(): + result[name] = pynames.ImportedModule(self, resource=resource) + return result + + def _create_concluded_attributes(self): + result = {} + init_dot_py = self._get_init_dot_py() + if init_dot_py: + init_object = self.pycore.resource_to_pyobject(init_dot_py) + result.update(init_object.get_attributes()) + return result + + def _get_child_resources(self): + result = {} + for child in self.resource.get_children(): + if child.is_folder(): + result[child.name] = child + elif child.name.endswith('.py') and \ + child.name != '__init__.py': + name = child.name[:-3] + result[name] = child + return result + + def _get_init_dot_py(self): + if self.resource is not None and self.resource.has_child('__init__.py'): + return self.resource.get_child('__init__.py') + else: + return None + + def _create_scope(self): + return self.get_module().get_scope() + + def get_module(self): + init_dot_py = self._get_init_dot_py() + if init_dot_py: + return self.pycore.resource_to_pyobject(init_dot_py) + return self + + +class _AssignVisitor(object): + + def __init__(self, scope_visitor): + self.scope_visitor = scope_visitor + self.assigned_ast = None + + def _Assign(self, node): + self.assigned_ast = node.value + for child_node in node.targets: + ast.walk(child_node, self) + + def _assigned(self, name, assignment=None): + self.scope_visitor._assigned(name, assignment) + + def _Name(self, node): + assignment = None + if self.assigned_ast is not None: + assignment = pynames.AssignmentValue(self.assigned_ast) + self._assigned(node.id, assignment) + + def _Tuple(self, node): + names = astutils.get_name_levels(node) + for name, levels in names: + assignment = None + if self.assigned_ast is not None: + assignment = pynames.AssignmentValue(self.assigned_ast, levels) + self._assigned(name, assignment) + + def _Attribute(self, node): + pass + + def _Subscript(self, node): + pass + + def _Slice(self, node): + pass + + +class _ScopeVisitor(object): + + def __init__(self, pycore, owner_object): + self.pycore = pycore + self.owner_object = owner_object + self.names = {} + self.defineds = [] + + def get_module(self): + if self.owner_object is not None: + return self.owner_object.get_module() + else: + return None + + def _ClassDef(self, node): + pyclass = PyClass(self.pycore, node, self.owner_object) + self.names[node.name] = pynames.DefinedName(pyclass) + self.defineds.append(pyclass) + + def _FunctionDef(self, node): + pyfunction = PyFunction(self.pycore, node, self.owner_object) + for decorator in pyfunction.decorators: + if isinstance(decorator, ast.Name) and decorator.id == 'property': + if isinstance(self, _ClassVisitor): + type_ = rope.base.builtins.Property(pyfunction) + arg = pynames.UnboundName(PyObject(self.owner_object)) + def _eval(type_=type_, arg=arg): + return type_.get_property_object( + arguments.ObjectArguments([arg])) + self.names[node.name] = pynames.EvaluatedName( + _eval, module=self.get_module(), lineno=node.lineno) + break + else: + self.names[node.name] = pynames.DefinedName(pyfunction) + self.defineds.append(pyfunction) + + def _Assign(self, node): + ast.walk(node, _AssignVisitor(self)) + + def _AugAssign(self, node): + pass + + def _For(self, node): + names = self._update_evaluated(node.target, node.iter, + '.__iter__().next()') + for child in node.body + node.orelse: + ast.walk(child, self) + + def _assigned(self, name, assignment): + pyname = self.names.get(name, None) + if pyname is None: + pyname = pynames.AssignedName(module=self.get_module()) + if isinstance(pyname, pynames.AssignedName): + if assignment is not None: + pyname.assignments.append(assignment) + self.names[name] = pyname + + def _update_evaluated(self, targets, assigned, + evaluation= '', eval_type=False): + result = {} + names = astutils.get_name_levels(targets) + for name, levels in names: + assignment = pynames.AssignmentValue(assigned, levels, + evaluation, eval_type) + self._assigned(name, assignment) + return result + + def _With(self, node): + if node.optional_vars: + self._update_evaluated(node.optional_vars, + node.context_expr, '.__enter__()') + for child in node.body: + ast.walk(child, self) + + def _excepthandler(self, node): + if node.name is not None and isinstance(node.name, ast.Name): + type_node = node.type + if isinstance(node.type, ast.Tuple) and type_node.elts: + type_node = type_node.elts[0] + self._update_evaluated(node.name, type_node, eval_type=True) + for child in node.body: + ast.walk(child, self) + + def _ExceptHandler(self, node): + self._excepthandler(node) + + def _Import(self, node): + for import_pair in node.names: + module_name = import_pair.name + alias = import_pair.asname + first_package = module_name.split('.')[0] + if alias is not None: + imported = pynames.ImportedModule(self.get_module(), + module_name) + if not self._is_ignored_import(imported): + self.names[alias] = imported + else: + imported = pynames.ImportedModule(self.get_module(), + first_package) + if not self._is_ignored_import(imported): + self.names[first_package] = imported + + def _ImportFrom(self, node): + level = 0 + if node.level: + level = node.level + imported_module = pynames.ImportedModule(self.get_module(), + node.module, level) + if self._is_ignored_import(imported_module): + return + if len(node.names) == 1 and node.names[0].name == '*': + if isinstance(self.owner_object, PyModule): + self.owner_object.star_imports.append( + StarImport(imported_module)) + else: + for imported_name in node.names: + imported = imported_name.name + alias = imported_name.asname + if alias is not None: + imported = alias + self.names[imported] = pynames.ImportedName(imported_module, + imported_name.name) + + def _is_ignored_import(self, imported_module): + if not self.pycore.project.prefs.get('ignore_bad_imports', False): + return False + return not isinstance(imported_module.get_object(), AbstractModule) + + def _Global(self, node): + module = self.get_module() + for name in node.names: + if module is not None: + try: + pyname = module[name] + except exceptions.AttributeNotFoundError: + pyname = pynames.AssignedName(node.lineno) + self.names[name] = pyname + + +class _GlobalVisitor(_ScopeVisitor): + + def __init__(self, pycore, owner_object): + super(_GlobalVisitor, self).__init__(pycore, owner_object) + + +class _ClassVisitor(_ScopeVisitor): + + def __init__(self, pycore, owner_object): + super(_ClassVisitor, self).__init__(pycore, owner_object) + + def _FunctionDef(self, node): + _ScopeVisitor._FunctionDef(self, node) + if len(node.args.args) > 0: + first = node.args.args[0] + if isinstance(first, ast.Name): + new_visitor = _ClassInitVisitor(self, first.id) + for child in ast.get_child_nodes(node): + ast.walk(child, new_visitor) + + +class _FunctionVisitor(_ScopeVisitor): + + def __init__(self, pycore, owner_object): + super(_FunctionVisitor, self).__init__(pycore, owner_object) + self.returned_asts = [] + self.generator = False + + def _Return(self, node): + if node.value is not None: + self.returned_asts.append(node.value) + + def _Yield(self, node): + if node.value is not None: + self.returned_asts.append(node.value) + self.generator = True + + +class _ClassInitVisitor(_AssignVisitor): + + def __init__(self, scope_visitor, self_name): + super(_ClassInitVisitor, self).__init__(scope_visitor) + self.self_name = self_name + + def _Attribute(self, node): + if not isinstance(node.ctx, ast.Store): + return + if isinstance(node.value, ast.Name) and \ + node.value.id == self.self_name: + if node.attr not in self.scope_visitor.names: + self.scope_visitor.names[node.attr] = pynames.AssignedName( + lineno=node.lineno, module=self.scope_visitor.get_module()) + if self.assigned_ast is not None: + pyname = self.scope_visitor.names[node.attr] + if isinstance(pyname, pynames.AssignedName): + pyname.assignments.append( + pynames.AssignmentValue(self.assigned_ast)) + + def _Tuple(self, node): + if not isinstance(node.ctx, ast.Store): + return + for child in ast.get_child_nodes(node): + ast.walk(child, self) + + def _Name(self, node): + pass + + def _FunctionDef(self, node): + pass + + def _ClassDef(self, node): + pass + + def _For(self, node): + pass + + def _With(self, node): + pass + + +class StarImport(object): + + def __init__(self, imported_module): + self.imported_module = imported_module + + def get_names(self): + result = {} + imported = self.imported_module.get_object() + for name in imported: + if not name.startswith('_'): + result[name] = pynames.ImportedName(self.imported_module, name) + return result diff -r e30544496575 -r 48cacfdc2ca6 vim/sadness/ropevim/src/rope/rope/base/pyscopes.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vim/sadness/ropevim/src/rope/rope/base/pyscopes.py Wed Oct 06 12:30:46 2010 -0400 @@ -0,0 +1,313 @@ +import rope.base.builtins +import rope.base.codeanalyze +import rope.base.pynames +from rope.base import ast, exceptions, utils + + +class Scope(object): + + def __init__(self, pycore, pyobject, parent_scope): + self.pycore = pycore + self.pyobject = pyobject + self.parent = parent_scope + + def get_names(self): + """Return the names defined or imported in this scope""" + return self.pyobject.get_attributes() + + def get_defined_names(self): + """Return the names defined in this scope""" + return self.pyobject._get_structural_attributes() + + def get_name(self, name): + """Return name `PyName` defined in this scope""" + if name not in self.get_names(): + raise exceptions.NameNotFoundError('name %s not found' % name) + return self.get_names()[name] + + def __getitem__(self, key): + """The same as ``get_name(key)``""" + return self.get_name(key) + + def __contains__(self, key): + """The same as ``key in self.get_names()``""" + return key in self.get_names() + + @utils.saveit + def get_scopes(self): + """Return the subscopes of this scope + + The returned scopes should be sorted by the order they appear. + """ + return self._create_scopes() + + def lookup(self, name): + if name in self.get_names(): + return self.get_names()[name] + if self.parent is not None: + return self.parent._propagated_lookup(name) + return None + + def get_propagated_names(self): + """Return the visible names of this scope + + Return the names defined in this scope that are visible from + scopes containing this scope. This method returns the same + dictionary returned by `get_names()` except for `ClassScope` + which returns an empty dict. + """ + return self.get_names() + + def _propagated_lookup(self, name): + if name in self.get_propagated_names(): + return self.get_propagated_names()[name] + if self.parent is not None: + return self.parent._propagated_lookup(name) + return None + + def _create_scopes(self): + return [pydefined.get_scope() + for pydefined in self.pyobject._get_defined_objects()] + + def _get_global_scope(self): + current = self + while current.parent is not None: + current = current.parent + return current + + def get_start(self): + return self.pyobject.get_ast().lineno + + def get_body_start(self): + body = self.pyobject.get_ast().body + if body: + return body[0].lineno + return self.get_start() + + def get_end(self): + pymodule = self._get_global_scope().pyobject + return pymodule.logical_lines.logical_line_in(self.logical_end)[1] + + @utils.saveit + def get_logical_end(self): + global_scope = self._get_global_scope() + return global_scope._scope_finder.find_scope_end(self) + + start = property(get_start) + end = property(get_end) + logical_end = property(get_logical_end) + + def get_kind(self): + pass + + +class GlobalScope(Scope): + + def __init__(self, pycore, module): + super(GlobalScope, self).__init__(pycore, module, None) + self.names = module._get_concluded_data() + + def get_start(self): + return 1 + + def get_kind(self): + return 'Module' + + def get_name(self, name): + try: + return self.pyobject[name] + except exceptions.AttributeNotFoundError: + if name in self.builtin_names: + return self.builtin_names[name] + raise exceptions.NameNotFoundError('name %s not found' % name) + + def get_names(self): + if self.names.get() is None: + result = dict(self.builtin_names) + result.update(super(GlobalScope, self).get_names()) + self.names.set(result) + return self.names.get() + + def get_inner_scope_for_line(self, lineno, indents=None): + return self._scope_finder.get_holding_scope(self, lineno, indents) + + def get_inner_scope_for_offset(self, offset): + return self._scope_finder.get_holding_scope_for_offset(self, offset) + + @property + @utils.saveit + def _scope_finder(self): + return _HoldingScopeFinder(self.pyobject) + + @property + def builtin_names(self): + return rope.base.builtins.builtins.get_attributes() + + +class FunctionScope(Scope): + + def __init__(self, pycore, pyobject, visitor): + super(FunctionScope, self).__init__(pycore, pyobject, + pyobject.parent.get_scope()) + self.names = None + self.returned_asts = None + self.is_generator = None + self.defineds = None + self.visitor = visitor + + def _get_names(self): + if self.names is None: + self._visit_function() + return self.names + + def _visit_function(self): + if self.names is None: + new_visitor = self.visitor(self.pycore, self.pyobject) + for n in ast.get_child_nodes(self.pyobject.get_ast()): + ast.walk(n, new_visitor) + self.names = new_visitor.names + self.names.update(self.pyobject.get_parameters()) + self.returned_asts = new_visitor.returned_asts + self.is_generator = new_visitor.generator + self.defineds = new_visitor.defineds + + def _get_returned_asts(self): + if self.names is None: + self._visit_function() + return self.returned_asts + + def _is_generator(self): + if self.is_generator is None: + self._get_returned_asts() + return self.is_generator + + def get_names(self): + return self._get_names() + + def _create_scopes(self): + if self.defineds is None: + self._visit_function() + return [pydefined.get_scope() for pydefined in self.defineds] + + def get_kind(self): + return 'Function' + + def invalidate_data(self): + for pyname in self.get_names().values(): + if isinstance(pyname, (rope.base.pynames.AssignedName, + rope.base.pynames.EvaluatedName)): + pyname.invalidate() + + +class ClassScope(Scope): + + def __init__(self, pycore, pyobject): + super(ClassScope, self).__init__(pycore, pyobject, + pyobject.parent.get_scope()) + + def get_kind(self): + return 'Class' + + def get_propagated_names(self): + return {} + + +class _HoldingScopeFinder(object): + + def __init__(self, pymodule): + self.pymodule = pymodule + + def get_indents(self, lineno): + return rope.base.codeanalyze.count_line_indents( + self.lines.get_line(lineno)) + + def _get_scope_indents(self, scope): + return self.get_indents(scope.get_start()) + + def get_holding_scope(self, module_scope, lineno, line_indents=None): + if line_indents is None: + line_indents = self.get_indents(lineno) + current_scope = module_scope + new_scope = current_scope + while new_scope is not None and \ + (new_scope.get_kind() == 'Module' or + self._get_scope_indents(new_scope) <= line_indents): + current_scope = new_scope + if current_scope.get_start() == lineno and \ + current_scope.get_kind() != 'Module': + return current_scope + new_scope = None + for scope in current_scope.get_scopes(): + if scope.get_start() <= lineno: + if lineno <= scope.get_end(): + new_scope = scope + break + else: + break + return current_scope + + def _is_empty_line(self, lineno): + line = self.lines.get_line(lineno) + return line.strip() == '' or line.lstrip().startswith('#') + + def _get_body_indents(self, scope): + return self.get_indents(scope.get_body_start()) + + def get_holding_scope_for_offset(self, scope, offset): + return self.get_holding_scope( + scope, self.lines.get_line_number(offset)) + + def find_scope_end(self, scope): + if not scope.parent: + return self.lines.length() + end = scope.pyobject.get_ast().body[-1].lineno + scope_start = self.pymodule.logical_lines.logical_line_in(scope.start) + if scope_start[1] >= end: + # handling one-liners + body_indents = self._get_scope_indents(scope) + 4 + else: + body_indents = self._get_body_indents(scope) + for l in self.logical_lines.generate_starts( + min(end + 1, self.lines.length()), self.lines.length() + 1): + if not self._is_empty_line(l): + if self.get_indents(l) < body_indents: + return end + else: + end = l + return end + + @property + def lines(self): + return self.pymodule.lines + + @property + def code(self): + return self.pymodule.source_code + + @property + def logical_lines(self): + return self.pymodule.logical_lines + +class TemporaryScope(Scope): + """Currently used for list comprehensions and generator expressions + + These scopes do not appear in the `get_scopes()` method of their + parent scopes. + """ + + def __init__(self, pycore, parent_scope, names): + super(TemporaryScope, self).__init__( + pycore, parent_scope.pyobject, parent_scope) + self.names = names + + def get_names(self): + return self.names + + def get_defined_names(self): + return self.names + + def _create_scopes(self): + return [] + + def get_kind(self): + return 'Temporary' diff -r e30544496575 -r 48cacfdc2ca6 vim/sadness/ropevim/src/rope/rope/base/resourceobserver.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vim/sadness/ropevim/src/rope/rope/base/resourceobserver.py Wed Oct 06 12:30:46 2010 -0400 @@ -0,0 +1,271 @@ +import os + + +class ResourceObserver(object): + """Provides the interface for observing resources + + `ResourceObserver`\s can be registered using `Project. + add_observer()`. But most of the time `FilteredResourceObserver` + should be used. `ResourceObserver`\s report all changes passed + to them and they don't report changes to all resources. For + example if a folder is removed, it only calls `removed()` for that + folder and not its contents. You can use + `FilteredResourceObserver` if you are interested in changes only + to a list of resources. And you want changes to be reported on + individual resources. + + """ + + def __init__(self, changed=None, moved=None, created=None, + removed=None, validate=None): + self.changed = changed + self.moved = moved + self.created = created + self.removed = removed + self._validate = validate + + def resource_changed(self, resource): + """It is called when the resource changes""" + if self.changed is not None: + self.changed(resource) + + def resource_moved(self, resource, new_resource): + """It is called when a resource is moved""" + if self.moved is not None: + self.moved(resource, new_resource) + + def resource_created(self, resource): + """Is called when a new resource is created""" + if self.created is not None: + self.created(resource) + + def resource_removed(self, resource): + """Is called when a new resource is removed""" + if self.removed is not None: + self.removed(resource) + + def validate(self, resource): + """Validate the existence of this resource and its children. + + This function is called when rope need to update its resource + cache about the files that might have been changed or removed + by other processes. + + """ + if self._validate is not None: + self._validate(resource) + + +class FilteredResourceObserver(object): + """A useful decorator for `ResourceObserver` + + Most resource observers have a list of resources and are + interested only in changes to those files. This class satisfies + this need. It dispatches resource changed and removed messages. + It performs these tasks: + + * Changes to files and folders are analyzed to check whether any + of the interesting resources are changed or not. If they are, + it reports these changes to `resource_observer` passed to the + constructor. + * When a resource is removed it checks whether any of the + interesting resources are contained in that folder and reports + them to `resource_observer`. + * When validating a folder it validates all of the interesting + files in that folder. + + Since most resource observers are interested in a list of + resources that change over time, `add_resource` and + `remove_resource` might be useful. + + """ + + def __init__(self, resource_observer, initial_resources=None, + timekeeper=None): + self.observer = resource_observer + self.resources = {} + if timekeeper is not None: + self.timekeeper = timekeeper + else: + self.timekeeper = ChangeIndicator() + if initial_resources is not None: + for resource in initial_resources: + self.add_resource(resource) + + def add_resource(self, resource): + """Add a resource to the list of interesting resources""" + if resource.exists(): + self.resources[resource] = self.timekeeper.get_indicator(resource) + else: + self.resources[resource] = None + + def remove_resource(self, resource): + """Add a resource to the list of interesting resources""" + if resource in self.resources: + del self.resources[resource] + + def clear_resources(self): + """Removes all registered resources""" + self.resources.clear() + + def resource_changed(self, resource): + changes = _Changes() + self._update_changes_caused_by_changed(changes, resource) + self._perform_changes(changes) + + def _update_changes_caused_by_changed(self, changes, changed): + if changed in self.resources: + changes.add_changed(changed) + if self._is_parent_changed(changed): + changes.add_changed(changed.parent) + + def _update_changes_caused_by_moved(self, changes, resource, + new_resource=None): + if resource in self.resources: + changes.add_removed(resource, new_resource) + if new_resource in self.resources: + changes.add_created(new_resource) + if resource.is_folder(): + for file in list(self.resources): + if resource.contains(file): + new_file = self._calculate_new_resource( + resource, new_resource, file) + changes.add_removed(file, new_file) + if self._is_parent_changed(resource): + changes.add_changed(resource.parent) + if new_resource is not None: + if self._is_parent_changed(new_resource): + changes.add_changed(new_resource.parent) + + def _is_parent_changed(self, child): + return child.parent in self.resources + + def resource_moved(self, resource, new_resource): + changes = _Changes() + self._update_changes_caused_by_moved(changes, resource, new_resource) + self._perform_changes(changes) + + def resource_created(self, resource): + changes = _Changes() + self._update_changes_caused_by_created(changes, resource) + self._perform_changes(changes) + + def _update_changes_caused_by_created(self, changes, resource): + if resource in self.resources: + changes.add_created(resource) + if self._is_parent_changed(resource): + changes.add_changed(resource.parent) + + def resource_removed(self, resource): + changes = _Changes() + self._update_changes_caused_by_moved(changes, resource) + self._perform_changes(changes) + + def _perform_changes(self, changes): + for resource in changes.changes: + self.observer.resource_changed(resource) + self.resources[resource] = self.timekeeper.get_indicator(resource) + for resource, new_resource in changes.moves.items(): + self.resources[resource] = None + if new_resource is not None: + self.observer.resource_moved(resource, new_resource) + else: + self.observer.resource_removed(resource) + for resource in changes.creations: + self.observer.resource_created(resource) + self.resources[resource] = self.timekeeper.get_indicator(resource) + + def validate(self, resource): + changes = _Changes() + for file in self._search_resource_moves(resource): + if file in self.resources: + self._update_changes_caused_by_moved(changes, file) + for file in self._search_resource_changes(resource): + if file in self.resources: + self._update_changes_caused_by_changed(changes, file) + for file in self._search_resource_creations(resource): + if file in self.resources: + changes.add_created(file) + self._perform_changes(changes) + + def _search_resource_creations(self, resource): + creations = set() + if resource in self.resources and resource.exists() and \ + self.resources[resource] is None: + creations.add(resource) + if resource.is_folder(): + for file in self.resources: + if file.exists() and resource.contains(file) and \ + self.resources[file] is None: + creations.add(file) + return creations + + def _search_resource_moves(self, resource): + all_moved = set() + if resource in self.resources and not resource.exists(): + all_moved.add(resource) + if resource.is_folder(): + for file in self.resources: + if resource.contains(file): + if not file.exists(): + all_moved.add(file) + moved = set(all_moved) + for folder in [file for file in all_moved if file.is_folder()]: + if folder in moved: + for file in list(moved): + if folder.contains(file): + moved.remove(file) + return moved + + def _search_resource_changes(self, resource): + changed = set() + if resource in self.resources and self._is_changed(resource): + changed.add(resource) + if resource.is_folder(): + for file in self.resources: + if file.exists() and resource.contains(file): + if self._is_changed(file): + changed.add(file) + return changed + + def _is_changed(self, resource): + if self.resources[resource] is None: + return False + return self.resources[resource] != self.timekeeper.get_indicator(resource) + + def _calculate_new_resource(self, main, new_main, resource): + if new_main is None: + return None + diff = resource.path[len(main.path):] + return resource.project.get_resource(new_main.path + diff) + + +class ChangeIndicator(object): + + def get_indicator(self, resource): + """Return the modification time and size of a `Resource`.""" + path = resource.real_path + # on dos, mtime does not change for a folder when files are added + if os.name != 'posix' and os.path.isdir(path): + return (os.path.getmtime(path), + len(os.listdir(path)), + os.path.getsize(path)) + return (os.path.getmtime(path), + os.path.getsize(path)) + + +class _Changes(object): + + def __init__(self): + self.changes = set() + self.creations = set() + self.moves = {} + + def add_changed(self, resource): + self.changes.add(resource) + + def add_removed(self, resource, new_resource=None): + self.moves[resource] = new_resource + + def add_created(self, resource): + self.creations.add(resource) diff -r e30544496575 -r 48cacfdc2ca6 vim/sadness/ropevim/src/rope/rope/base/resources.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vim/sadness/ropevim/src/rope/rope/base/resources.py Wed Oct 06 12:30:46 2010 -0400 @@ -0,0 +1,211 @@ +import os +import re + +import rope.base.change +import rope.base.fscommands +from rope.base import exceptions + + +class Resource(object): + """Represents files and folders in a project""" + + def __init__(self, project, path): + self.project = project + self._path = path + + def move(self, new_location): + """Move resource to `new_location`""" + self._perform_change(rope.base.change.MoveResource(self, new_location), + 'Moving <%s> to <%s>' % (self.path, new_location)) + + def remove(self): + """Remove resource from the project""" + self._perform_change(rope.base.change.RemoveResource(self), + 'Removing <%s>' % self.path) + + def is_folder(self): + """Return true if the resource is a folder""" + + def create(self): + """Create this resource""" + + def exists(self): + return os.path.exists(self.real_path) + + @property + def parent(self): + parent = '/'.join(self.path.split('/')[0:-1]) + return self.project.get_folder(parent) + + @property + def path(self): + """Return the path of this resource relative to the project root + + The path is the list of parent directories separated by '/' followed + by the resource name. + """ + return self._path + + @property + def name(self): + """Return the name of this resource""" + return self.path.split('/')[-1] + + @property + def real_path(self): + """Return the file system path of this resource""" + return self.project._get_resource_path(self.path) + + def __eq__(self, obj): + return self.__class__ == obj.__class__ and self.path == obj.path + + def __ne__(self, obj): + return not self.__eq__(obj) + + def __hash__(self): + return hash(self.path) + + def _perform_change(self, change_, description): + changes = rope.base.change.ChangeSet(description) + changes.add_change(change_) + self.project.do(changes) + + +class File(Resource): + """Represents a file""" + + def __init__(self, project, name): + super(File, self).__init__(project, name) + + def read(self): + data = self.read_bytes() + try: + return rope.base.fscommands.file_data_to_unicode(data) + except UnicodeDecodeError, e: + raise exceptions.ModuleDecodeError(self.path, e.reason) + + def read_bytes(self): + return open(self.real_path, 'rb').read() + + def write(self, contents): + try: + if contents == self.read(): + return + except IOError: + pass + self._perform_change(rope.base.change.ChangeContents(self, contents), + 'Writing file <%s>' % self.path) + + def is_folder(self): + return False + + def create(self): + self.parent.create_file(self.name) + + +class Folder(Resource): + """Represents a folder""" + + def __init__(self, project, name): + super(Folder, self).__init__(project, name) + + def is_folder(self): + return True + + def get_children(self): + """Return the children of this folder""" + result = [] + for name in os.listdir(self.real_path): + try: + child = self.get_child(name) + except exceptions.ResourceNotFoundError: + continue + if not self.project.is_ignored(child): + result.append(self.get_child(name)) + return result + + def create_file(self, file_name): + self._perform_change( + rope.base.change.CreateFile(self, file_name), + 'Creating file <%s>' % self._get_child_path(file_name)) + return self.get_child(file_name) + + def create_folder(self, folder_name): + self._perform_change( + rope.base.change.CreateFolder(self, folder_name), + 'Creating folder <%s>' % self._get_child_path(folder_name)) + return self.get_child(folder_name) + + def _get_child_path(self, name): + if self.path: + return self.path + '/' + name + else: + return name + + def get_child(self, name): + return self.project.get_resource(self._get_child_path(name)) + + def has_child(self, name): + try: + self.get_child(name) + return True + except exceptions.ResourceNotFoundError: + return False + + def get_files(self): + return [resource for resource in self.get_children() + if not resource.is_folder()] + + def get_folders(self): + return [resource for resource in self.get_children() + if resource.is_folder()] + + def contains(self, resource): + if self == resource: + return False + return self.path == '' or resource.path.startswith(self.path + '/') + + def create(self): + self.parent.create_folder(self.name) + + +class _ResourceMatcher(object): + + def __init__(self): + self.patterns = [] + self._compiled_patterns = [] + + def set_patterns(self, patterns): + """Specify which resources to match + + `patterns` is a `list` of `str`\s that can contain ``*`` and + ``?`` signs for matching resource names. + + """ + self._compiled_patterns = None + self.patterns = patterns + + def _add_pattern(self, pattern): + re_pattern = pattern.replace('.', '\\.').\ + replace('*', '[^/]*').replace('?', '[^/]').\ + replace('//', '/(.*/)?') + re_pattern = '^(.*/)?' + re_pattern + '(/.*)?$' + self.compiled_patterns.append(re.compile(re_pattern)) + + def does_match(self, resource): + for pattern in self.compiled_patterns: + if pattern.match(resource.path): + return True + path = os.path.join(resource.project.address, + *resource.path.split('/')) + if os.path.islink(path): + return True + return False + + @property + def compiled_patterns(self): + if self._compiled_patterns is None: + self._compiled_patterns = [] + for pattern in self.patterns: + self._add_pattern(pattern) + return self._compiled_patterns diff -r e30544496575 -r 48cacfdc2ca6 vim/sadness/ropevim/src/rope/rope/base/simplify.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vim/sadness/ropevim/src/rope/rope/base/simplify.py Wed Oct 06 12:30:46 2010 -0400 @@ -0,0 +1,55 @@ +"""A module to ease code analysis + +This module is here to help source code analysis. +""" +import re + +from rope.base import codeanalyze, utils + + +@utils.cached(7) +def real_code(source): + """Simplify `source` for analysis + + It replaces: + + * comments with spaces + * strs with a new str filled with spaces + * implicit and explicit continuations with spaces + * tabs and semicolons with spaces + + The resulting code is a lot easier to analyze if we are interested + only in offsets. + """ + collector = codeanalyze.ChangeCollector(source) + for start, end in ignored_regions(source): + if source[start] == '#': + replacement = ' ' * (end - start) + else: + replacement = '"%s"' % (' ' * (end - start - 2)) + collector.add_change(start, end, replacement) + source = collector.get_changed() or source + collector = codeanalyze.ChangeCollector(source) + parens = 0 + for match in _parens.finditer(source): + i = match.start() + c = match.group() + if c in '({[': + parens += 1 + if c in ')}]': + parens -= 1 + if c == '\n' and parens > 0: + collector.add_change(i, i + 1, ' ') + source = collector.get_changed() or source + return source.replace('\\\n', ' ').replace('\t', ' ').replace(';', '\n') + + +@utils.cached(7) +def ignored_regions(source): + """Return ignored regions like strings and comments in `source` """ + return [(match.start(), match.end()) for match in _str.finditer(source)] + + +_str = re.compile('%s|%s' % (codeanalyze.get_comment_pattern(), + codeanalyze.get_string_pattern())) +_parens = re.compile(r'[\({\[\]}\)\n]') diff -r e30544496575 -r 48cacfdc2ca6 vim/sadness/ropevim/src/rope/rope/base/stdmods.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vim/sadness/ropevim/src/rope/rope/base/stdmods.py Wed Oct 06 12:30:46 2010 -0400 @@ -0,0 +1,40 @@ +import os +import sys + +from rope.base import utils + + +def _stdlib_path(): + import inspect + return os.path.dirname(inspect.getsourcefile(inspect)) + +@utils.cached(1) +def standard_modules(): + return python_modules() | dynload_modules() + +@utils.cached(1) +def python_modules(): + result = set() + lib_path = _stdlib_path() + if os.path.exists(lib_path): + for name in os.listdir(lib_path): + path = os.path.join(lib_path, name) + if os.path.isdir(path): + if '-' not in name: + result.add(name) + else: + if name.endswith('.py'): + result.add(name[:-3]) + return result + +@utils.cached(1) +def dynload_modules(): + result = set(sys.builtin_module_names) + dynload_path = os.path.join(_stdlib_path(), 'lib-dynload') + if os.path.exists(dynload_path): + for name in os.listdir(dynload_path): + path = os.path.join(dynload_path, name) + if os.path.isfile(path): + if name.endswith('.so') or name.endswith('.dll'): + result.add(os.path.splitext(name)[0]) + return result diff -r e30544496575 -r 48cacfdc2ca6 vim/sadness/ropevim/src/rope/rope/base/taskhandle.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vim/sadness/ropevim/src/rope/rope/base/taskhandle.py Wed Oct 06 12:30:46 2010 -0400 @@ -0,0 +1,133 @@ +import warnings + +from rope.base import exceptions + + +class TaskHandle(object): + + def __init__(self, name='Task', interrupts=True): + """Construct a TaskHandle + + If `interrupts` is `False` the task won't be interrupted by + calling `TaskHandle.stop()`. + + """ + self.name = name + self.interrupts = interrupts + self.stopped = False + self.job_sets = [] + self.observers = [] + + def stop(self): + """Interrupts the refactoring""" + if self.interrupts: + self.stopped = True + self._inform_observers() + + def current_jobset(self): + """Return the current `JobSet`""" + if self.job_sets: + return self.job_sets[-1] + + def add_observer(self, observer): + """Register an observer for this task handle + + The observer is notified whenever the task is stopped or + a job gets finished. + + """ + self.observers.append(observer) + + def is_stopped(self): + return self.stopped + + def get_jobsets(self): + return self.job_sets + + def create_jobset(self, name='JobSet', count=None): + result = JobSet(self, name=name, count=count) + self.job_sets.append(result) + self._inform_observers() + return result + + def _inform_observers(self): + for observer in list(self.observers): + observer() + + +class JobSet(object): + + def __init__(self, handle, name, count): + self.handle = handle + self.name = name + self.count = count + self.done = 0 + self.job_name = None + + def started_job(self, name): + self.check_status() + self.job_name = name + self.handle._inform_observers() + + def finished_job(self): + self.check_status() + self.done += 1 + self.handle._inform_observers() + self.job_name = None + + def check_status(self): + if self.handle.is_stopped(): + raise exceptions.InterruptedTaskError() + + def get_active_job_name(self): + return self.job_name + + def get_percent_done(self): + if self.count is not None and self.count > 0: + percent = self.done * 100 // self.count + return min(percent, 100) + + def get_name(self): + return self.name + + +class NullTaskHandle(object): + + def __init__(self): + pass + + def is_stopped(self): + return False + + def stop(self): + pass + + def create_jobset(self, *args, **kwds): + return NullJobSet() + + def get_jobsets(self): + return [] + + def add_observer(self, observer): + pass + + +class NullJobSet(object): + + def started_job(self, name): + pass + + def finished_job(self): + pass + + def check_status(self): + pass + + def get_active_job_name(self): + pass + + def get_percent_done(self): + pass + + def get_name(self): + pass diff -r e30544496575 -r 48cacfdc2ca6 vim/sadness/ropevim/src/rope/rope/base/utils.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vim/sadness/ropevim/src/rope/rope/base/utils.py Wed Oct 06 12:30:46 2010 -0400 @@ -0,0 +1,78 @@ +import warnings + + +def saveit(func): + """A decorator that caches the return value of a function""" + + name = '_' + func.__name__ + def _wrapper(self, *args, **kwds): + if not hasattr(self, name): + setattr(self, name, func(self, *args, **kwds)) + return getattr(self, name) + return _wrapper + +cacheit = saveit + +def prevent_recursion(default): + """A decorator that returns the return value of `default` in recursions""" + def decorator(func): + name = '_calling_%s_' % func.__name__ + def newfunc(self, *args, **kwds): + if getattr(self, name, False): + return default() + setattr(self, name, True) + try: + return func(self, *args, **kwds) + finally: + setattr(self, name, False) + return newfunc + return decorator + + +def ignore_exception(exception_class): + """A decorator that ignores `exception_class` exceptions""" + def _decorator(func): + def newfunc(*args, **kwds): + try: + return func(*args, **kwds) + except exception_class: + pass + return newfunc + return _decorator + + +def deprecated(message=None): + """A decorator for deprecated functions""" + def _decorator(func, message=message): + if message is None: + message = '%s is deprecated' % func.__name__ + def newfunc(*args, **kwds): + warnings.warn(message, DeprecationWarning, stacklevel=2) + return func(*args, **kwds) + return newfunc + return _decorator + + +def cached(count): + """A caching decorator based on parameter objects""" + def decorator(func): + return _Cached(func, count) + return decorator + +class _Cached(object): + + def __init__(self, func, count): + self.func = func + self.cache = [] + self.count = count + + def __call__(self, *args, **kwds): + key = (args, kwds) + for cached_key, cached_result in self.cache: + if cached_key == key: + return cached_result + result = self.func(*args, **kwds) + self.cache.append((key, result)) + if len(self.cache) > self.count: + del self.cache[0] + return result diff -r e30544496575 -r 48cacfdc2ca6 vim/sadness/ropevim/src/rope/rope/base/worder.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vim/sadness/ropevim/src/rope/rope/base/worder.py Wed Oct 06 12:30:46 2010 -0400 @@ -0,0 +1,521 @@ +import bisect +import keyword + +import rope.base.simplify + + +def get_name_at(resource, offset): + source_code = resource.read() + word_finder = Worder(source_code) + return word_finder.get_word_at(offset) + + +class Worder(object): + """A class for finding boundaries of words and expressions + + Note that in these methods, offset should be the index of the + character not the index of the character after it. + """ + + def __init__(self, code, handle_ignores=False): + simplified = rope.base.simplify.real_code(code) + self.code_finder = _RealFinder(simplified, code) + self.handle_ignores = handle_ignores + self.code = code + + def _init_ignores(self): + ignores = rope.base.simplify.ignored_regions(self.code) + self.dumb_finder = _RealFinder(self.code, self.code) + self.starts = [ignored[0] for ignored in ignores] + self.ends = [ignored[1] for ignored in ignores] + + def _context_call(self, name, offset): + if self.handle_ignores: + if not hasattr(self, 'starts'): + self._init_ignores() + start = bisect.bisect(self.starts, offset) + if start > 0 and offset < self.ends[start - 1]: + return getattr(self.dumb_finder, name)(offset) + return getattr(self.code_finder, name)(offset) + + def get_primary_at(self, offset): + return self._context_call('get_primary_at', offset) + + def get_word_at(self, offset): + return self._context_call('get_word_at', offset) + + def get_primary_range(self, offset): + return self._context_call('get_primary_range', offset) + + def get_splitted_primary_before(self, offset): + return self._context_call('get_splitted_primary_before', offset) + + def get_word_range(self, offset): + return self._context_call('get_word_range', offset) + + def is_function_keyword_parameter(self, offset): + return self.code_finder.is_function_keyword_parameter(offset) + + def is_a_class_or_function_name_in_header(self, offset): + return self.code_finder.is_a_class_or_function_name_in_header(offset) + + def is_from_statement_module(self, offset): + return self.code_finder.is_from_statement_module(offset) + + def is_from_aliased(self, offset): + return self.code_finder.is_from_aliased(offset) + + def find_parens_start_from_inside(self, offset): + return self.code_finder.find_parens_start_from_inside(offset) + + def is_a_name_after_from_import(self, offset): + return self.code_finder.is_a_name_after_from_import(offset) + + def is_from_statement(self, offset): + return self.code_finder.is_from_statement(offset) + + def get_from_aliased(self, offset): + return self.code_finder.get_from_aliased(offset) + + def is_import_statement(self, offset): + return self.code_finder.is_import_statement(offset) + + def is_assigned_here(self, offset): + return self.code_finder.is_assigned_here(offset) + + def is_a_function_being_called(self, offset): + return self.code_finder.is_a_function_being_called(offset) + + def get_word_parens_range(self, offset): + return self.code_finder.get_word_parens_range(offset) + + def is_name_assigned_in_class_body(self, offset): + return self.code_finder.is_name_assigned_in_class_body(offset) + + def is_on_function_call_keyword(self, offset): + return self.code_finder.is_on_function_call_keyword(offset) + + def _find_parens_start(self, offset): + return self.code_finder._find_parens_start(offset) + + def get_parameters(self, first, last): + return self.code_finder.get_parameters(first, last) + + def get_from_module(self, offset): + return self.code_finder.get_from_module(offset) + + def is_assigned_in_a_tuple_assignment(self, offset): + return self.code_finder.is_assigned_in_a_tuple_assignment(offset) + + def get_assignment_type(self, offset): + return self.code_finder.get_assignment_type(offset) + + def get_function_and_args_in_header(self, offset): + return self.code_finder.get_function_and_args_in_header(offset) + + def get_lambda_and_args(self, offset): + return self.code_finder.get_lambda_and_args(offset) + + def find_function_offset(self, offset): + return self.code_finder.find_function_offset(offset) + + +class _RealFinder(object): + + def __init__(self, code, raw): + self.code = code + self.raw = raw + + def _find_word_start(self, offset): + current_offset = offset + while current_offset >= 0 and self._is_id_char(current_offset): + current_offset -= 1 + return current_offset + 1 + + def _find_word_end(self, offset): + while offset + 1 < len(self.code) and self._is_id_char(offset + 1): + offset += 1 + return offset + + def _find_last_non_space_char(self, offset): + while offset >= 0 and self.code[offset].isspace(): + if self.code[offset] == '\n': + return offset + offset -= 1 + return max(-1, offset) + + def get_word_at(self, offset): + offset = self._get_fixed_offset(offset) + return self.raw[self._find_word_start(offset): + self._find_word_end(offset) + 1] + + def _get_fixed_offset(self, offset): + if offset >= len(self.code): + return offset - 1 + if not self._is_id_char(offset): + if offset > 0 and self._is_id_char(offset - 1): + return offset - 1 + if offset < len(self.code) - 1 and self._is_id_char(offset + 1): + return offset + 1 + return offset + + def _is_id_char(self, offset): + return self.code[offset].isalnum() or self.code[offset] == '_' + + def _find_string_start(self, offset): + kind = self.code[offset] + try: + return self.code.rindex(kind, 0, offset) + except ValueError: + return 0 + + def _find_parens_start(self, offset): + offset = self._find_last_non_space_char(offset - 1) + while offset >= 0 and self.code[offset] not in '[({': + if self.code[offset] not in ':,': + offset = self._find_primary_start(offset) + offset = self._find_last_non_space_char(offset - 1) + return offset + + def _find_atom_start(self, offset): + old_offset = offset + if self.code[offset] == '\n': + return offset + 1 + if self.code[offset].isspace(): + offset = self._find_last_non_space_char(offset) + if self.code[offset] in '\'"': + return self._find_string_start(offset) + if self.code[offset] in ')]}': + return self._find_parens_start(offset) + if self._is_id_char(offset): + return self._find_word_start(offset) + return old_offset + + def _find_primary_without_dot_start(self, offset): + """It tries to find the undotted primary start + + It is different from `self._get_atom_start()` in that it + follows function calls, too; such as in ``f(x)``. + + """ + last_atom = offset + offset = self._find_last_non_space_char(last_atom) + while offset > 0 and self.code[offset] in ')]': + last_atom = self._find_parens_start(offset) + offset = self._find_last_non_space_char(last_atom - 1) + if offset >= 0 and (self.code[offset] in '"\'})]' or + self._is_id_char(offset)): + atom_start = self._find_atom_start(offset) + if not keyword.iskeyword(self.code[atom_start:offset + 1]): + return atom_start + return last_atom + + def _find_primary_start(self, offset): + if offset >= len(self.code): + offset = len(self.code) - 1 + if self.code[offset] != '.': + offset = self._find_primary_without_dot_start(offset) + else: + offset = offset + 1 + while offset > 0: + prev = self._find_last_non_space_char(offset - 1) + if offset <= 0 or self.code[prev] != '.': + break + offset = self._find_primary_without_dot_start(prev - 1) + if not self._is_id_char(offset): + break + + return offset + + def get_primary_at(self, offset): + offset = self._get_fixed_offset(offset) + start, end = self.get_primary_range(offset) + return self.raw[start:end].strip() + + def get_splitted_primary_before(self, offset): + """returns expression, starting, starting_offset + + This function is used in `rope.codeassist.assist` function. + """ + if offset == 0: + return ('', '', 0) + end = offset - 1 + word_start = self._find_atom_start(end) + real_start = self._find_primary_start(end) + if self.code[word_start:offset].strip() == '': + word_start = end + if self.code[end].isspace(): + word_start = end + if self.code[real_start:word_start].strip() == '': + real_start = word_start + if real_start == word_start == end and not self._is_id_char(end): + return ('', '', offset) + if real_start == word_start: + return ('', self.raw[word_start:offset], word_start) + else: + if self.code[end] == '.': + return (self.raw[real_start:end], '', offset) + last_dot_position = word_start + if self.code[word_start] != '.': + last_dot_position = self._find_last_non_space_char(word_start - 1) + last_char_position = self._find_last_non_space_char(last_dot_position - 1) + if self.code[word_start].isspace(): + word_start = offset + return (self.raw[real_start:last_char_position + 1], + self.raw[word_start:offset], word_start) + + def _get_line_start(self, offset): + try: + return self.code.rindex('\n', 0, offset + 1) + except ValueError: + return 0 + + def _get_line_end(self, offset): + try: + return self.code.index('\n', offset) + except ValueError: + return len(self.code) + + def is_name_assigned_in_class_body(self, offset): + word_start = self._find_word_start(offset - 1) + word_end = self._find_word_end(offset) + 1 + if '.' in self.code[word_start:word_end]: + return False + line_start = self._get_line_start(word_start) + line = self.code[line_start:word_start].strip() + return not line and self.get_assignment_type(offset) == '=' + + def is_a_class_or_function_name_in_header(self, offset): + word_start = self._find_word_start(offset - 1) + line_start = self._get_line_start(word_start) + prev_word = self.code[line_start:word_start].strip() + return prev_word in ['def', 'class'] + + def _find_first_non_space_char(self, offset): + if offset >= len(self.code): + return len(self.code) + while offset < len(self.code) and self.code[offset].isspace(): + if self.code[offset] == '\n': + return offset + offset += 1 + return offset + + def is_a_function_being_called(self, offset): + word_end = self._find_word_end(offset) + 1 + next_char = self._find_first_non_space_char(word_end) + return next_char < len(self.code) and \ + self.code[next_char] == '(' and \ + not self.is_a_class_or_function_name_in_header(offset) + + def _find_import_end(self, start): + return self._get_line_end(start) + + def is_import_statement(self, offset): + try: + last_import = self.code.rindex('import ', 0, offset) + except ValueError: + return False + return self._find_import_end(last_import + 7) >= offset + + def is_from_statement(self, offset): + try: + last_from = self.code.rindex('from ', 0, offset) + from_import = self.code.index(' import ', last_from) + from_names = from_import + 8 + except ValueError: + return False + from_names = self._find_first_non_space_char(from_names) + return self._find_import_end(from_names) >= offset + + def is_from_statement_module(self, offset): + if offset >= len(self.code) - 1: + return False + stmt_start = self._find_primary_start(offset) + line_start = self._get_line_start(stmt_start) + prev_word = self.code[line_start:stmt_start].strip() + return prev_word == 'from' + + def is_a_name_after_from_import(self, offset): + try: + line_start = self._get_line_start(offset) + last_from = self.code.rindex('from ', line_start, offset) + from_import = self.code.index(' import ', last_from) + from_names = from_import + 8 + except ValueError: + return False + if from_names - 1 > offset: + return False + return self._find_import_end(from_names) >= offset + + def get_from_module(self, offset): + try: + last_from = self.code.rindex('from ', 0, offset) + import_offset = self.code.index(' import ', last_from) + end = self._find_last_non_space_char(import_offset) + return self.get_primary_at(end) + except ValueError: + pass + + def is_from_aliased(self, offset): + if not self.is_a_name_after_from_import(offset): + return False + try: + end = self._find_word_end(offset) + as_end = min(self._find_word_end(end + 1), len(self.code)) + as_start = self._find_word_start(as_end) + if self.code[as_start:as_end + 1] == 'as': + return True + except ValueError: + return False + + def get_from_aliased(self, offset): + try: + end = self._find_word_end(offset) + as_ = self._find_word_end(end + 1) + alias = self._find_word_end(as_ + 1) + start = self._find_word_start(alias) + return self.raw[start:alias + 1] + except ValueError: + pass + + def is_function_keyword_parameter(self, offset): + word_end = self._find_word_end(offset) + if word_end + 1 == len(self.code): + return False + next_char = self._find_first_non_space_char(word_end + 1) + equals = self.code[next_char:next_char + 2] + if equals == '==' or not equals.startswith('='): + return False + word_start = self._find_word_start(offset) + prev_char = self._find_last_non_space_char(word_start - 1) + return prev_char - 1 >= 0 and self.code[prev_char] in ',(' + + def is_on_function_call_keyword(self, offset): + stop = self._get_line_start(offset) + if self._is_id_char(offset): + offset = self._find_word_start(offset) - 1 + offset = self._find_last_non_space_char(offset) + if offset <= stop or self.code[offset] not in '(,': + return False + parens_start = self.find_parens_start_from_inside(offset) + return stop < parens_start + + def find_parens_start_from_inside(self, offset): + stop = self._get_line_start(offset) + opens = 1 + while offset > stop: + if self.code[offset] == '(': + break + if self.code[offset] != ',': + offset = self._find_primary_start(offset) + offset -= 1 + return max(stop, offset) + + def is_assigned_here(self, offset): + return self.get_assignment_type(offset) is not None + + def get_assignment_type(self, offset): + # XXX: does not handle tuple assignments + word_end = self._find_word_end(offset) + next_char = self._find_first_non_space_char(word_end + 1) + single = self.code[next_char:next_char + 1] + double = self.code[next_char:next_char + 2] + triple = self.code[next_char:next_char + 3] + if double not in ('==', '<=', '>=', '!='): + for op in [single, double, triple]: + if op.endswith('='): + return op + + def get_primary_range(self, offset): + start = self._find_primary_start(offset) + end = self._find_word_end(offset) + 1 + return (start, end) + + def get_word_range(self, offset): + offset = max(0, offset) + start = self._find_word_start(offset) + end = self._find_word_end(offset) + 1 + return (start, end) + + def get_word_parens_range(self, offset, opening='(', closing=')'): + end = self._find_word_end(offset) + start_parens = self.code.index(opening, end) + index = start_parens + open_count = 0 + while index < len(self.code): + if self.code[index] == opening: + open_count += 1 + if self.code[index] == closing: + open_count -= 1 + if open_count == 0: + return (start_parens, index + 1) + index += 1 + return (start_parens, index) + + def get_parameters(self, first, last): + keywords = [] + args = [] + current = self._find_last_non_space_char(last - 1) + while current > first: + primary_start = current + current = self._find_primary_start(current) + while current != first and self.code[current] not in '=,': + current = self._find_last_non_space_char(current - 1) + primary = self.raw[current + 1:primary_start + 1].strip() + if self.code[current] == '=': + primary_start = current - 1 + current -= 1 + while current != first and self.code[current] not in ',': + current = self._find_last_non_space_char(current - 1) + param_name = self.raw[current + 1:primary_start + 1].strip() + keywords.append((param_name, primary)) + else: + args.append(primary) + current = self._find_last_non_space_char(current - 1) + args.reverse() + keywords.reverse() + return args, keywords + + def is_assigned_in_a_tuple_assignment(self, offset): + start = self._get_line_start(offset) + end = self._get_line_end(offset) + primary_start = self._find_primary_start(offset) + primary_end = self._find_word_end(offset) + + prev_char_offset = self._find_last_non_space_char(primary_start - 1) + next_char_offset = self._find_first_non_space_char(primary_end + 1) + next_char = prev_char = '' + if prev_char_offset >= start: + prev_char = self.code[prev_char_offset] + if next_char_offset < end: + next_char = self.code[next_char_offset] + try: + equals_offset = self.code.index('=', start, end) + except ValueError: + return False + if prev_char not in '(,' and next_char not in ',)': + return False + parens_start = self.find_parens_start_from_inside(offset) + # XXX: only handling (x, y) = value + return offset < equals_offset and \ + self.code[start:parens_start].strip() == '' + + def get_function_and_args_in_header(self, offset): + offset = self.find_function_offset(offset) + lparens, rparens = self.get_word_parens_range(offset) + return self.raw[offset:rparens + 1] + + def find_function_offset(self, offset, definition='def '): + while True: + offset = self.code.index(definition, offset) + if offset == 0 or not self._is_id_char(offset - 1): + break + offset += 1 + def_ = offset + 4 + return self._find_first_non_space_char(def_) + + def get_lambda_and_args(self, offset): + offset = self.find_function_offset(offset, definition = 'lambda ') + lparens, rparens = self.get_word_parens_range(offset, opening=' ', closing=':') + return self.raw[offset:rparens + 1] + diff -r e30544496575 -r 48cacfdc2ca6 vim/sadness/ropevim/src/rope/rope/contrib/__init__.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vim/sadness/ropevim/src/rope/rope/contrib/__init__.py Wed Oct 06 12:30:46 2010 -0400 @@ -0,0 +1,7 @@ +"""rope IDE tools package + +This package contains modules that can be used in IDEs +but do not depend on the UI. So these modules will be used +by `rope.ui` modules. + +""" diff -r e30544496575 -r 48cacfdc2ca6 vim/sadness/ropevim/src/rope/rope/contrib/autoimport.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vim/sadness/ropevim/src/rope/rope/contrib/autoimport.py Wed Oct 06 12:30:46 2010 -0400 @@ -0,0 +1,217 @@ +import re + +from rope.base import (exceptions, pynames, resourceobserver, + taskhandle, pyobjects, builtins, resources) +from rope.refactor import importutils + + +class AutoImport(object): + """A class for finding the module that provides a name + + This class maintains a cache of global names in python modules. + Note that this cache is not accurate and might be out of date. + + """ + + def __init__(self, project, observe=True, underlined=False): + """Construct an AutoImport object + + If `observe` is `True`, listen for project changes and update + the cache. + + If `underlined` is `True`, underlined names are cached, too. + """ + self.project = project + self.underlined = underlined + self.names = project.data_files.read_data('globalnames') + if self.names is None: + self.names = {} + project.data_files.add_write_hook(self._write) + # XXX: using a filtered observer + observer = resourceobserver.ResourceObserver( + changed=self._changed, moved=self._moved, removed=self._removed) + if observe: + project.add_observer(observer) + + def import_assist(self, starting): + """Return a list of ``(name, module)`` tuples + + This function tries to find modules that have a global name + that starts with `starting`. + """ + # XXX: breaking if gave up! use generators + result = [] + for module in self.names: + for global_name in self.names[module]: + if global_name.startswith(starting): + result.append((global_name, module)) + return result + + def get_modules(self, name): + """Return the list of modules that have global `name`""" + result = [] + for module in self.names: + if name in self.names[module]: + result.append(module) + return result + + def get_all_names(self): + """Return the list of all cached global names""" + result = set() + for module in self.names: + result.update(set(self.names[module])) + return result + + def get_name_locations(self, name): + """Return a list of ``(resource, lineno)`` tuples""" + result = [] + pycore = self.project.pycore + for module in self.names: + if name in self.names[module]: + try: + pymodule = pycore.get_module(module) + if name in pymodule: + pyname = pymodule[name] + module, lineno = pyname.get_definition_location() + if module is not None: + resource = module.get_module().get_resource() + if resource is not None and lineno is not None: + result.append((resource, lineno)) + except exceptions.ModuleNotFoundError: + pass + return result + + def generate_cache(self, resources=None, underlined=None, + task_handle=taskhandle.NullTaskHandle()): + """Generate global name cache for project files + + If `resources` is a list of `rope.base.resource.File`\s, only + those files are searched; otherwise all python modules in the + project are cached. + + """ + if resources is None: + resources = self.project.pycore.get_python_files() + job_set = task_handle.create_jobset( + 'Generatig autoimport cache', len(resources)) + for file in resources: + job_set.started_job('Working on <%s>' % file.path) + self.update_resource(file, underlined) + job_set.finished_job() + + def generate_modules_cache(self, modules, underlined=None, + task_handle=taskhandle.NullTaskHandle()): + """Generate global name cache for modules listed in `modules`""" + job_set = task_handle.create_jobset( + 'Generatig autoimport cache for modules', len(modules)) + for modname in modules: + job_set.started_job('Working on <%s>' % modname) + if modname.endswith('.*'): + mod = self.project.pycore.find_module(modname[:-2]) + if mod: + for sub in submodules(mod): + self.update_resource(sub, underlined) + else: + self.update_module(modname, underlined) + job_set.finished_job() + + def clear_cache(self): + """Clear all entries in global-name cache + + It might be a good idea to use this function before + regenerating global names. + + """ + self.names.clear() + + def find_insertion_line(self, code): + """Guess at what line the new import should be inserted""" + match = re.search(r'^(def|class)\s+', code) + if match is not None: + code = code[:match.start()] + try: + pymodule = self.project.pycore.get_string_module(code) + except exceptions.ModuleSyntaxError: + return 1 + testmodname = '__rope_testmodule_rope' + importinfo = importutils.NormalImport(((testmodname, None),)) + module_imports = importutils.get_module_imports( + self.project.pycore, pymodule) + module_imports.add_import(importinfo) + code = module_imports.get_changed_source() + offset = code.index(testmodname) + lineno = code.count('\n', 0, offset) + 1 + return lineno + + def update_resource(self, resource, underlined=None): + """Update the cache for global names in `resource`""" + try: + pymodule = self.project.pycore.resource_to_pyobject(resource) + modname = self._module_name(resource) + self._add_names(pymodule, modname, underlined) + except exceptions.ModuleSyntaxError: + pass + + def update_module(self, modname, underlined=None): + """Update the cache for global names in `modname` module + + `modname` is the name of a module. + """ + try: + pymodule = self.project.pycore.get_module(modname) + self._add_names(pymodule, modname, underlined) + except exceptions.ModuleNotFoundError: + pass + + def _module_name(self, resource): + return self.project.pycore.modname(resource) + + def _add_names(self, pymodule, modname, underlined): + if underlined is None: + underlined = self.underlined + globals = [] + if isinstance(pymodule, pyobjects.PyDefinedObject): + attributes = pymodule._get_structural_attributes() + else: + attributes = pymodule.get_attributes() + for name, pyname in attributes.items(): + if not underlined and name.startswith('_'): + continue + if isinstance(pyname, (pynames.AssignedName, pynames.DefinedName)): + globals.append(name) + if isinstance(pymodule, builtins.BuiltinModule): + globals.append(name) + self.names[modname] = globals + + def _write(self): + self.project.data_files.write_data('globalnames', self.names) + + def _changed(self, resource): + if not resource.is_folder(): + self.update_resource(resource) + + def _moved(self, resource, newresource): + if not resource.is_folder(): + modname = self._module_name(resource) + if modname in self.names: + del self.names[modname] + self.update_resource(newresource) + + def _removed(self, resource): + if not resource.is_folder(): + modname = self._module_name(resource) + if modname in self.names: + del self.names[modname] + + +def submodules(mod): + if isinstance(mod, resources.File): + if mod.name.endswith('.py') and mod.name != '__init__.py': + return set([mod]) + return set() + if not mod.has_child('__init__.py'): + return set() + result = set([mod]) + for child in mod.get_children(): + result |= submodules(child) + return result diff -r e30544496575 -r 48cacfdc2ca6 vim/sadness/ropevim/src/rope/rope/contrib/changestack.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vim/sadness/ropevim/src/rope/rope/contrib/changestack.py Wed Oct 06 12:30:46 2010 -0400 @@ -0,0 +1,52 @@ +"""For performing many refactorings as a single command + +`changestack` module can be used to perform many refactorings on top +of each other as one bigger command. It can be used like:: + + stack = ChangeStack(project, 'my big command') + + #.. + stack.push(refactoring1.get_changes()) + #.. + stack.push(refactoring2.get_changes()) + #.. + stack.push(refactoringX.get_changes()) + + stack.pop_all() + changes = stack.merged() + +Now `changes` can be previewed or performed as before. +""" + +from rope.base import change + + +class ChangeStack(object): + + def __init__(self, project, description='merged changes'): + self.project = project + self.description = description + self.stack = [] + + def push(self, changes): + self.stack.append(changes) + self.project.do(changes) + + def pop_all(self): + for i in range(len(self.stack)): + self.project.history.undo(drop=True) + + def merged(self): + result = change.ChangeSet(self.description) + for changes in self.stack: + for c in self._basic_changes(changes): + result.add_change(c) + return result + + def _basic_changes(self, changes): + if isinstance(changes, change.ChangeSet): + for child in changes.changes: + for atom in self._basic_changes(child): + yield atom + else: + yield changes diff -r e30544496575 -r 48cacfdc2ca6 vim/sadness/ropevim/src/rope/rope/contrib/codeassist.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vim/sadness/ropevim/src/rope/rope/contrib/codeassist.py Wed Oct 06 12:30:46 2010 -0400 @@ -0,0 +1,647 @@ +import keyword +import sys +import warnings + +import rope.base.codeanalyze +import rope.base.evaluate +from rope.base import pyobjects, pyobjectsdef, pynames, builtins, exceptions, worder +from rope.base.codeanalyze import SourceLinesAdapter +from rope.contrib import fixsyntax +from rope.refactor import functionutils + + +def code_assist(project, source_code, offset, resource=None, + templates=None, maxfixes=1, later_locals=True): + """Return python code completions as a list of `CodeAssistProposal`\s + + `resource` is a `rope.base.resources.Resource` object. If + provided, relative imports are handled. + + `maxfixes` is the maximum number of errors to fix if the code has + errors in it. + + If `later_locals` is `False` names defined in this scope and after + this line is ignored. + + """ + if templates is not None: + warnings.warn('Codeassist no longer supports templates', + DeprecationWarning, stacklevel=2) + assist = _PythonCodeAssist( + project, source_code, offset, resource=resource, + maxfixes=maxfixes, later_locals=later_locals) + return assist() + + +def starting_offset(source_code, offset): + """Return the offset in which the completion should be inserted + + Usually code assist proposals should be inserted like:: + + completion = proposal.name + result = (source_code[:starting_offset] + + completion + source_code[offset:]) + + Where starting_offset is the offset returned by this function. + + """ + word_finder = worder.Worder(source_code, True) + expression, starting, starting_offset = \ + word_finder.get_splitted_primary_before(offset) + return starting_offset + + +def get_doc(project, source_code, offset, resource=None, maxfixes=1): + """Get the pydoc""" + fixer = fixsyntax.FixSyntax(project.pycore, source_code, + resource, maxfixes) + pymodule = fixer.get_pymodule() + pyname = fixer.pyname_at(offset) + if pyname is None: + return None + pyobject = pyname.get_object() + return PyDocExtractor().get_doc(pyobject) + + +def get_calltip(project, source_code, offset, resource=None, + maxfixes=1, ignore_unknown=False, remove_self=False): + """Get the calltip of a function + + The format of the returned string is + ``module_name.holding_scope_names.function_name(arguments)``. For + classes `__init__()` and for normal objects `__call__()` function + is used. + + Note that the offset is on the function itself *not* after the its + open parenthesis. (Actually it used to be the other way but it + was easily confused when string literals were involved. So I + decided it is better for it not to try to be too clever when it + cannot be clever enough). You can use a simple search like:: + + offset = source_code.rindex('(', 0, offset) - 1 + + to handle simple situations. + + If `ignore_unknown` is `True`, `None` is returned for functions + without source-code like builtins and extensions. + + If `remove_self` is `True`, the first parameter whose name is self + will be removed for methods. + """ + fixer = fixsyntax.FixSyntax(project.pycore, source_code, + resource, maxfixes) + pymodule = fixer.get_pymodule() + pyname = fixer.pyname_at(offset) + if pyname is None: + return None + pyobject = pyname.get_object() + return PyDocExtractor().get_calltip(pyobject, ignore_unknown, remove_self) + + +def get_definition_location(project, source_code, offset, + resource=None, maxfixes=1): + """Return the definition location of the python name at `offset` + + Return a (`rope.base.resources.Resource`, lineno) tuple. If no + `resource` is given and the definition is inside the same module, + the first element of the returned tuple would be `None`. If the + location cannot be determined ``(None, None)`` is returned. + + """ + fixer = fixsyntax.FixSyntax(project.pycore, source_code, + resource, maxfixes) + pymodule = fixer.get_pymodule() + pyname = fixer.pyname_at(offset) + if pyname is not None: + module, lineno = pyname.get_definition_location() + if module is not None: + return module.get_module().get_resource(), lineno + return (None, None) + + +def find_occurrences(*args, **kwds): + import rope.contrib.findit + warnings.warn('Use `rope.contrib.findit.find_occurrences()` instead', + DeprecationWarning, stacklevel=2) + return rope.contrib.findit.find_occurrences(*args, **kwds) + + +class CompletionProposal(object): + """A completion proposal + + The `scope` instance variable shows where proposed name came from + and can be 'global', 'local', 'builtin', 'attribute', 'keyword', + 'imported', 'parameter_keyword'. + + The `type` instance variable shows the approximate type of the + proposed object and can be 'instance', 'class', 'function', 'module', + and `None`. + + All possible relations between proposal's `scope` and `type` are shown + in the table below (different scopes in rows and types in columns): + + | instance | class | function | module | None + local | + | + | + | + | + global | + | + | + | + | + builtin | + | + | + | | + attribute | + | + | + | + | + imported | + | + | + | + | + keyword | | | | | + + parameter_keyword | | | | | + + + """ + + def __init__(self, name, scope, pyname=None): + self.name = name + self.pyname = pyname + self.scope = self._get_scope(scope) + + def __str__(self): + return '%s (%s, %s)' % (self.name, self.scope, self.type) + + def __repr__(self): + return str(self) + + @property + def parameters(self): + """The names of the parameters the function takes. + + Returns None if this completion is not a function. + """ + pyname = self.pyname + if isinstance(pyname, pynames.ImportedName): + pyname = pyname._get_imported_pyname() + if isinstance(pyname, pynames.DefinedName): + pyobject = pyname.get_object() + if isinstance(pyobject, pyobjects.AbstractFunction): + return pyobject.get_param_names() + + @property + def type(self): + pyname = self.pyname + if isinstance(pyname, builtins.BuiltinName): + pyobject = pyname.get_object() + if isinstance(pyobject, builtins.BuiltinFunction): + return 'function' + elif isinstance(pyobject, builtins.BuiltinClass): + clsobj = pyobject.builtin + return 'class' + elif isinstance(pyobject, builtins.BuiltinObject) or \ + isinstance(pyobject, builtins.BuiltinName): + return 'instance' + elif isinstance(pyname, pynames.ImportedModule): + return 'module' + elif isinstance(pyname, pynames.ImportedName) or \ + isinstance(pyname, pynames.DefinedName): + pyobject = pyname.get_object() + if isinstance(pyobject, pyobjects.AbstractFunction): + return 'function' + if isinstance(pyobject, pyobjects.AbstractClass): + return 'class' + return 'instance' + + def _get_scope(self, scope): + if isinstance(self.pyname, builtins.BuiltinName): + return 'builtin' + if isinstance(self.pyname, pynames.ImportedModule) or \ + isinstance(self.pyname, pynames.ImportedName): + return 'imported' + return scope + + def get_doc(self): + """Get the proposed object's docstring. + + Returns None if it can not be get. + """ + if not self.pyname: + return None + pyobject = self.pyname.get_object() + if not hasattr(pyobject, 'get_doc'): + return None + return self.pyname.get_object().get_doc() + + @property + def kind(self): + warnings.warn("the proposal's `kind` property is deprecated, " \ + "use `scope` instead") + return self.scope + + +# leaved for backward compatibility +CodeAssistProposal = CompletionProposal + + +class NamedParamProposal(CompletionProposal): + """A parameter keyword completion proposal + + Holds reference to ``_function`` -- the function which + parameter ``name`` belongs to. This allows to determine + default value for this parameter. + """ + def __init__(self, name, function): + self.argname = name + name = '%s=' % name + super(NamedParamProposal, self).__init__(name, 'parameter_keyword') + self._function = function + + def get_default(self): + """Get a string representation of a param's default value. + + Returns None if there is no default value for this param. + """ + definfo = functionutils.DefinitionInfo.read(self._function) + for arg, default in definfo.args_with_defaults: + if self.argname == arg: + return default + return None + + +def sorted_proposals(proposals, scopepref=None, typepref=None): + """Sort a list of proposals + + Return a sorted list of the given `CodeAssistProposal`\s. + + `scopepref` can be a list of proposal scopes. Defaults to + ``['parameter_keyword', 'local', 'global', 'imported', + 'attribute', 'builtin', 'keyword']``. + + `typepref` can be a list of proposal types. Defaults to + ``['class', 'function', 'instance', 'module', None]``. + (`None` stands for completions with no type like keywords.) + """ + sorter = _ProposalSorter(proposals, scopepref, typepref) + return sorter.get_sorted_proposal_list() + + +def starting_expression(source_code, offset): + """Return the expression to complete""" + word_finder = worder.Worder(source_code, True) + expression, starting, starting_offset = \ + word_finder.get_splitted_primary_before(offset) + if expression: + return expression + '.' + starting + return starting + + +def default_templates(): + warnings.warn('default_templates() is deprecated.', + DeprecationWarning, stacklevel=2) + return {} + + +class _PythonCodeAssist(object): + + def __init__(self, project, source_code, offset, resource=None, + maxfixes=1, later_locals=True): + self.project = project + self.pycore = self.project.pycore + self.code = source_code + self.resource = resource + self.maxfixes = maxfixes + self.later_locals = later_locals + self.word_finder = worder.Worder(source_code, True) + self.expression, self.starting, self.offset = \ + self.word_finder.get_splitted_primary_before(offset) + + keywords = keyword.kwlist + + def _find_starting_offset(self, source_code, offset): + current_offset = offset - 1 + while current_offset >= 0 and (source_code[current_offset].isalnum() or + source_code[current_offset] in '_'): + current_offset -= 1; + return current_offset + 1 + + def _matching_keywords(self, starting): + result = [] + for kw in self.keywords: + if kw.startswith(starting): + result.append(CompletionProposal(kw, 'keyword')) + return result + + def __call__(self): + if self.offset > len(self.code): + return [] + completions = list(self._code_completions().values()) + if self.expression.strip() == '' and self.starting.strip() != '': + completions.extend(self._matching_keywords(self.starting)) + return completions + + def _dotted_completions(self, module_scope, holding_scope): + result = {} + found_pyname = rope.base.evaluate.eval_str(holding_scope, + self.expression) + if found_pyname is not None: + element = found_pyname.get_object() + compl_scope = 'attribute' + if isinstance(element, (pyobjectsdef.PyModule, + pyobjectsdef.PyPackage)): + compl_scope = 'imported' + for name, pyname in element.get_attributes().items(): + if name.startswith(self.starting): + result[name] = CompletionProposal(name, compl_scope, pyname) + return result + + def _undotted_completions(self, scope, result, lineno=None): + if scope.parent != None: + self._undotted_completions(scope.parent, result) + if lineno is None: + names = scope.get_propagated_names() + else: + names = scope.get_names() + for name, pyname in names.items(): + if name.startswith(self.starting): + compl_scope = 'local' + if scope.get_kind() == 'Module': + compl_scope = 'global' + if lineno is None or self.later_locals or \ + not self._is_defined_after(scope, pyname, lineno): + result[name] = CompletionProposal(name, compl_scope, + pyname) + + def _from_import_completions(self, pymodule): + module_name = self.word_finder.get_from_module(self.offset) + if module_name is None: + return {} + pymodule = self._find_module(pymodule, module_name) + result = {} + for name in pymodule: + if name.startswith(self.starting): + result[name] = CompletionProposal(name, scope='global', + pyname=pymodule[name]) + return result + + def _find_module(self, pymodule, module_name): + dots = 0 + while module_name[dots] == '.': + dots += 1 + pyname = pynames.ImportedModule(pymodule, + module_name[dots:], dots) + return pyname.get_object() + + def _is_defined_after(self, scope, pyname, lineno): + location = pyname.get_definition_location() + if location is not None and location[1] is not None: + if location[0] == scope.pyobject.get_module() and \ + lineno <= location[1] <= scope.get_end(): + return True + + def _code_completions(self): + lineno = self.code.count('\n', 0, self.offset) + 1 + fixer = fixsyntax.FixSyntax(self.pycore, self.code, + self.resource, self.maxfixes) + pymodule = fixer.get_pymodule() + module_scope = pymodule.get_scope() + code = pymodule.source_code + lines = code.split('\n') + result = {} + start = fixsyntax._logical_start(lines, lineno) + indents = fixsyntax._get_line_indents(lines[start - 1]) + inner_scope = module_scope.get_inner_scope_for_line(start, indents) + if self.word_finder.is_a_name_after_from_import(self.offset): + return self._from_import_completions(pymodule) + if self.expression.strip() != '': + result.update(self._dotted_completions(module_scope, inner_scope)) + else: + result.update(self._keyword_parameters(module_scope.pyobject, + inner_scope)) + self._undotted_completions(inner_scope, result, lineno=lineno) + return result + + def _keyword_parameters(self, pymodule, scope): + offset = self.offset + if offset == 0: + return {} + word_finder = worder.Worder(self.code, True) + lines = SourceLinesAdapter(self.code) + lineno = lines.get_line_number(offset) + if word_finder.is_on_function_call_keyword(offset - 1): + name_finder = rope.base.evaluate.ScopeNameFinder(pymodule) + function_parens = word_finder.\ + find_parens_start_from_inside(offset - 1) + primary = word_finder.get_primary_at(function_parens - 1) + try: + function_pyname = rope.base.evaluate.\ + eval_str(scope, primary) + except exceptions.BadIdentifierError, e: + return {} + if function_pyname is not None: + pyobject = function_pyname.get_object() + if isinstance(pyobject, pyobjects.AbstractFunction): + pass + elif isinstance(pyobject, pyobjects.AbstractClass) and \ + '__init__' in pyobject: + pyobject = pyobject['__init__'].get_object() + elif '__call__' in pyobject: + pyobject = pyobject['__call__'].get_object() + if isinstance(pyobject, pyobjects.AbstractFunction): + param_names = [] + param_names.extend( + pyobject.get_param_names(special_args=False)) + result = {} + for name in param_names: + if name.startswith(self.starting): + result[name + '='] = NamedParamProposal( + name, pyobject + ) + return result + return {} + + +class _ProposalSorter(object): + """Sort a list of code assist proposals""" + + def __init__(self, code_assist_proposals, scopepref=None, typepref=None): + self.proposals = code_assist_proposals + if scopepref is None: + scopepref = ['parameter_keyword', 'local', 'global', 'imported', + 'attribute', 'builtin', 'keyword'] + self.scopepref = scopepref + if typepref is None: + typepref = ['class', 'function', 'instance', 'module', None] + self.typerank = dict((type, index) + for index, type in enumerate(typepref)) + + def get_sorted_proposal_list(self): + """Return a list of `CodeAssistProposal`""" + proposals = {} + for proposal in self.proposals: + proposals.setdefault(proposal.scope, []).append(proposal) + result = [] + for scope in self.scopepref: + scope_proposals = proposals.get(scope, []) + scope_proposals = [proposal for proposal in scope_proposals + if proposal.type in self.typerank] + scope_proposals.sort(self._proposal_cmp) + result.extend(scope_proposals) + return result + + def _proposal_cmp(self, proposal1, proposal2): + if proposal1.type != proposal2.type: + return cmp(self.typerank.get(proposal1.type, 100), + self.typerank.get(proposal2.type, 100)) + return self._compare_underlined_names(proposal1.name, + proposal2.name) + + def _compare_underlined_names(self, name1, name2): + def underline_count(name): + result = 0 + while result < len(name) and name[result] == '_': + result += 1 + return result + underline_count1 = underline_count(name1) + underline_count2 = underline_count(name2) + if underline_count1 != underline_count2: + return cmp(underline_count1, underline_count2) + return cmp(name1, name2) + + +class PyDocExtractor(object): + + def get_doc(self, pyobject): + if isinstance(pyobject, pyobjects.AbstractFunction): + return self._get_function_docstring(pyobject) + elif isinstance(pyobject, pyobjects.AbstractClass): + return self._get_class_docstring(pyobject) + elif isinstance(pyobject, pyobjects.AbstractModule): + return self._trim_docstring(pyobject.get_doc()) + return None + + def get_calltip(self, pyobject, ignore_unknown=False, remove_self=False): + try: + if isinstance(pyobject, pyobjects.AbstractClass): + pyobject = pyobject['__init__'].get_object() + if not isinstance(pyobject, pyobjects.AbstractFunction): + pyobject = pyobject['__call__'].get_object() + except exceptions.AttributeNotFoundError: + return None + if ignore_unknown and not isinstance(pyobject, pyobjects.PyFunction): + return + if isinstance(pyobject, pyobjects.AbstractFunction): + result = self._get_function_signature(pyobject, add_module=True) + if remove_self and self._is_method(pyobject): + return result.replace('(self)', '()').replace('(self, ', '(') + return result + + def _get_class_docstring(self, pyclass): + contents = self._trim_docstring(pyclass.get_doc(), 2) + supers = [super.get_name() for super in pyclass.get_superclasses()] + doc = 'class %s(%s):\n\n' % (pyclass.get_name(), ', '.join(supers)) + contents + + if '__init__' in pyclass: + init = pyclass['__init__'].get_object() + if isinstance(init, pyobjects.AbstractFunction): + doc += '\n\n' + self._get_single_function_docstring(init) + return doc + + def _get_function_docstring(self, pyfunction): + functions = [pyfunction] + if self._is_method(pyfunction): + functions.extend(self._get_super_methods(pyfunction.parent, + pyfunction.get_name())) + return '\n\n'.join([self._get_single_function_docstring(function) + for function in functions]) + + def _is_method(self, pyfunction): + return isinstance(pyfunction, pyobjects.PyFunction) and \ + isinstance(pyfunction.parent, pyobjects.PyClass) + + def _get_single_function_docstring(self, pyfunction): + signature = self._get_function_signature(pyfunction) + docs = self._trim_docstring(pyfunction.get_doc(), indents=2) + return signature + ':\n\n' + docs + + def _get_super_methods(self, pyclass, name): + result = [] + for super_class in pyclass.get_superclasses(): + if name in super_class: + function = super_class[name].get_object() + if isinstance(function, pyobjects.AbstractFunction): + result.append(function) + result.extend(self._get_super_methods(super_class, name)) + return result + + def _get_function_signature(self, pyfunction, add_module=False): + location = self._location(pyfunction, add_module) + if isinstance(pyfunction, pyobjects.PyFunction): + info = functionutils.DefinitionInfo.read(pyfunction) + return location + info.to_string() + else: + return '%s(%s)' % (location + pyfunction.get_name(), + ', '.join(pyfunction.get_param_names())) + + def _location(self, pyobject, add_module=False): + location = [] + parent = pyobject.parent + while parent and not isinstance(parent, pyobjects.AbstractModule): + location.append(parent.get_name()) + location.append('.') + parent = parent.parent + if add_module: + if isinstance(pyobject, pyobjects.PyFunction): + module = pyobject.get_module() + location.insert(0, self._get_module(pyobject)) + if isinstance(parent, builtins.BuiltinModule): + location.insert(0, parent.get_name() + '.') + return ''.join(location) + + def _get_module(self, pyfunction): + module = pyfunction.get_module() + if module is not None: + resource = module.get_resource() + if resource is not None: + return pyfunction.pycore.modname(resource) + '.' + return '' + + def _trim_docstring(self, docstring, indents=0): + """The sample code from :PEP:`257`""" + if not docstring: + return '' + # Convert tabs to spaces (following normal Python rules) + # and split into a list of lines: + lines = docstring.expandtabs().splitlines() + # Determine minimum indentation (first line doesn't count): + indent = sys.maxint + for line in lines[1:]: + stripped = line.lstrip() + if stripped: + indent = min(indent, len(line) - len(stripped)) + # Remove indentation (first line is special): + trimmed = [lines[0].strip()] + if indent < sys.maxint: + for line in lines[1:]: + trimmed.append(line[indent:].rstrip()) + # Strip off trailing and leading blank lines: + while trimmed and not trimmed[-1]: + trimmed.pop() + while trimmed and not trimmed[0]: + trimmed.pop(0) + # Return a single string: + return '\n'.join((' ' * indents + line for line in trimmed)) + + +# Deprecated classes + +class TemplateProposal(CodeAssistProposal): + def __init__(self, name, template): + warnings.warn('TemplateProposal is deprecated.', + DeprecationWarning, stacklevel=2) + super(TemplateProposal, self).__init__(name, 'template') + self.template = template + + +class Template(object): + + def __init__(self, template): + self.template = template + warnings.warn('Template is deprecated.', + DeprecationWarning, stacklevel=2) + + def variables(self): + return [] + + def substitute(self, mapping): + return self.template + + def get_cursor_location(self, mapping): + return len(self.template) diff -r e30544496575 -r 48cacfdc2ca6 vim/sadness/ropevim/src/rope/rope/contrib/finderrors.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vim/sadness/ropevim/src/rope/rope/contrib/finderrors.py Wed Oct 06 12:30:46 2010 -0400 @@ -0,0 +1,91 @@ +"""Finding bad name and attribute accesses + +`find_errors` function can be used to find possible bad name and +attribute accesses. As an example:: + + errors = find_errors(project, project.get_resource('mod.py')) + for error in errors: + print '%s: %s' % (error.lineno, error.error) + +prints possible errors for ``mod.py`` file. + +TODO: + +* use task handles +* reporting names at most once +* attributes of extension modules that don't appear in + extension_modules project config can be ignored +* not calling `PyScope.get_inner_scope_for_line()` if it is a + bottleneck; needs profiling +* not reporting occurrences where rope cannot infer the object +* rope saves multiple objects for some of the names in its objectdb + use all of them not to give false positives +* ... ;-) + +""" +from rope.base import ast, evaluate, pyobjects + + +def find_errors(project, resource): + """Find possible bad name and attribute accesses + + It returns a list of `Error`\s. + """ + pymodule = project.pycore.resource_to_pyobject(resource) + finder = _BadAccessFinder(pymodule) + ast.walk(pymodule.get_ast(), finder) + return finder.errors + + +class _BadAccessFinder(object): + + def __init__(self, pymodule): + self.pymodule = pymodule + self.scope = pymodule.get_scope() + self.errors = [] + + def _Name(self, node): + if isinstance(node.ctx, (ast.Store, ast.Param)): + return + scope = self.scope.get_inner_scope_for_line(node.lineno) + pyname = scope.lookup(node.id) + if pyname is None: + self._add_error(node, 'Unresolved variable') + elif self._is_defined_after(scope, pyname, node.lineno): + self._add_error(node, 'Defined later') + + def _Attribute(self, node): + if not isinstance(node.ctx, ast.Store): + scope = self.scope.get_inner_scope_for_line(node.lineno) + pyname = evaluate.eval_node(scope, node.value) + if pyname is not None and \ + pyname.get_object() != pyobjects.get_unknown(): + if node.attr not in pyname.get_object(): + self._add_error(node, 'Unresolved attribute') + ast.walk(node.value, self) + + def _add_error(self, node, msg): + if isinstance(node, ast.Attribute): + name = node.attr + else: + name = node.id + if name != 'None': + error = Error(node.lineno, msg + ' ' + name) + self.errors.append(error) + + def _is_defined_after(self, scope, pyname, lineno): + location = pyname.get_definition_location() + if location is not None and location[1] is not None: + if location[0] == self.pymodule and \ + lineno <= location[1] <= scope.get_end(): + return True + + +class Error(object): + + def __init__(self, lineno, error): + self.lineno = lineno + self.error = error + + def __str__(self): + return '%s: %s' % (self.lineno, self.error) diff -r e30544496575 -r 48cacfdc2ca6 vim/sadness/ropevim/src/rope/rope/contrib/findit.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vim/sadness/ropevim/src/rope/rope/contrib/findit.py Wed Oct 06 12:30:46 2010 -0400 @@ -0,0 +1,110 @@ +import rope.base.codeanalyze +import rope.base.evaluate +import rope.base.pyobjects +from rope.base import taskhandle, exceptions, worder +from rope.contrib import fixsyntax +from rope.refactor import occurrences + + +def find_occurrences(project, resource, offset, unsure=False, resources=None, + in_hierarchy=False, task_handle=taskhandle.NullTaskHandle()): + """Return a list of `Location`\s + + If `unsure` is `True`, possible matches are returned, too. You + can use `Location.unsure` to see which are unsure occurrences. + `resources` can be a list of `rope.base.resource.File`\s that + should be searched for occurrences; if `None` all python files + in the project are searched. + + """ + name = worder.get_name_at(resource, offset) + this_pymodule = project.pycore.resource_to_pyobject(resource) + primary, pyname = rope.base.evaluate.eval_location2( + this_pymodule, offset) + def is_match(occurrence): + return unsure + finder = occurrences.create_finder( + project.pycore, name, pyname, unsure=is_match, + in_hierarchy=in_hierarchy, instance=primary) + if resources is None: + resources = project.pycore.get_python_files() + job_set = task_handle.create_jobset('Finding Occurrences', + count=len(resources)) + return _find_locations(finder, resources, job_set) + + +def find_implementations(project, resource, offset, resources=None, + task_handle=taskhandle.NullTaskHandle()): + """Find the places a given method is overridden. + + Finds the places a method is implemented. Returns a list of + `Location`\s. + """ + name = worder.get_name_at(resource, offset) + this_pymodule = project.pycore.resource_to_pyobject(resource) + pyname = rope.base.evaluate.eval_location(this_pymodule, offset) + if pyname is not None: + pyobject = pyname.get_object() + if not isinstance(pyobject, rope.base.pyobjects.PyFunction) or \ + pyobject.get_kind() != 'method': + raise exceptions.BadIdentifierError('Not a method!') + else: + raise exceptions.BadIdentifierError('Cannot resolve the identifier!') + def is_defined(occurrence): + if not occurrence.is_defined(): + return False + def not_self(occurrence): + if occurrence.get_pyname().get_object() == pyname.get_object(): + return False + filters = [is_defined, not_self, + occurrences.InHierarchyFilter(pyname, True)] + finder = occurrences.Finder(project.pycore, name, filters=filters) + if resources is None: + resources = project.pycore.get_python_files() + job_set = task_handle.create_jobset('Finding Implementations', + count=len(resources)) + return _find_locations(finder, resources, job_set) + + +def find_definition(project, code, offset, resource=None, maxfixes=1): + """Return the definition location of the python name at `offset` + + A `Location` object is returned if the definition location can be + determined, otherwise ``None`` is returned. + """ + fixer = fixsyntax.FixSyntax(project.pycore, code, resource, maxfixes) + main_module = fixer.get_pymodule() + pyname = fixer.pyname_at(offset) + if pyname is not None: + module, lineno = pyname.get_definition_location() + name = rope.base.worder.Worder(code).get_word_at(offset) + if lineno is not None: + start = module.lines.get_line_start(lineno) + def check_offset(occurrence): + if occurrence.offset < start: + return False + pyname_filter = occurrences.PyNameFilter(pyname) + finder = occurrences.Finder(project.pycore, name, + [check_offset, pyname_filter]) + for occurrence in finder.find_occurrences(pymodule=module): + return Location(occurrence) + + +class Location(object): + + def __init__(self, occurrence): + self.resource = occurrence.resource + self.region = occurrence.get_word_range() + self.offset = self.region[0] + self.unsure = occurrence.is_unsure() + self.lineno = occurrence.lineno + + +def _find_locations(finder, resources, job_set): + result = [] + for resource in resources: + job_set.started_job(resource.path) + for occurrence in finder.find_occurrences(resource): + result.append(Location(occurrence)) + job_set.finished_job() + return result diff -r e30544496575 -r 48cacfdc2ca6 vim/sadness/ropevim/src/rope/rope/contrib/fixmodnames.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vim/sadness/ropevim/src/rope/rope/contrib/fixmodnames.py Wed Oct 06 12:30:46 2010 -0400 @@ -0,0 +1,69 @@ +"""Fix the name of modules + +This module is useful when you want to rename many of the modules in +your project. That can happen specially when you want to change their +naming style. + +For instance:: + + fixer = FixModuleNames(project) + changes = fixer.get_changes(fixer=str.lower) + project.do(changes) + +Here it renames all modules and packages to use lower-cased chars. +You can tell it to use any other style by using the ``fixer`` +argument. + +""" +from rope.base import change, taskhandle +from rope.contrib import changestack +from rope.refactor import rename + + +class FixModuleNames(object): + + def __init__(self, project): + self.project = project + + def get_changes(self, fixer=str.lower, + task_handle=taskhandle.NullTaskHandle()): + """Fix module names + + `fixer` is a function that takes and returns a `str`. Given + the name of a module, it should return the fixed name. + + """ + stack = changestack.ChangeStack(self.project, 'Fixing module names') + jobset = task_handle.create_jobset('Fixing module names', + self._count_fixes(fixer) + 1) + try: + while True: + for resource in self._tobe_fixed(fixer): + jobset.started_job(resource.path) + renamer = rename.Rename(self.project, resource) + changes = renamer.get_changes(fixer(self._name(resource))) + stack.push(changes) + jobset.finished_job() + break + else: + break + finally: + jobset.started_job('Reverting to original state') + stack.pop_all() + jobset.finished_job() + return stack.merged() + + def _count_fixes(self, fixer): + return len(list(self._tobe_fixed(fixer))) + + def _tobe_fixed(self, fixer): + for resource in self.project.pycore.get_python_files(): + modname = self._name(resource) + if modname != fixer(modname): + yield resource + + def _name(self, resource): + modname = resource.name.rsplit('.', 1)[0] + if modname == '__init__': + modname = resource.parent.name + return modname diff -r e30544496575 -r 48cacfdc2ca6 vim/sadness/ropevim/src/rope/rope/contrib/fixsyntax.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vim/sadness/ropevim/src/rope/rope/contrib/fixsyntax.py Wed Oct 06 12:30:46 2010 -0400 @@ -0,0 +1,178 @@ +import rope.base.codeanalyze +import rope.base.evaluate +from rope.base import worder, exceptions, utils +from rope.base.codeanalyze import ArrayLinesAdapter, LogicalLineFinder + + +class FixSyntax(object): + + def __init__(self, pycore, code, resource, maxfixes=1): + self.pycore = pycore + self.code = code + self.resource = resource + self.maxfixes = maxfixes + + @utils.saveit + def get_pymodule(self): + """Get a `PyModule`""" + errors = [] + code = self.code + tries = 0 + while True: + try: + if tries == 0 and self.resource is not None and \ + self.resource.read() == code: + return self.pycore.resource_to_pyobject(self.resource, + force_errors=True) + return self.pycore.get_string_module( + code, resource=self.resource, force_errors=True) + except exceptions.ModuleSyntaxError, e: + if tries < self.maxfixes: + tries += 1 + self.commenter.comment(e.lineno) + code = '\n'.join(self.commenter.lines) + errors.append(' * line %s: %s ... fixed' % (e.lineno, + e.message_)) + else: + errors.append(' * line %s: %s ... raised!' % (e.lineno, + e.message_)) + new_message = ('\nSyntax errors in file %s:\n' % e.filename) \ + + '\n'.join(errors) + raise exceptions.ModuleSyntaxError(e.filename, e.lineno, + new_message) + + @property + @utils.saveit + def commenter(self): + return _Commenter(self.code) + + def pyname_at(self, offset): + pymodule = self.get_pymodule() + def old_pyname(): + word_finder = worder.Worder(self.code, True) + expression = word_finder.get_primary_at(offset) + expression = expression.replace('\\\n', ' ').replace('\n', ' ') + lineno = self.code.count('\n', 0, offset) + scope = pymodule.get_scope().get_inner_scope_for_line(lineno) + return rope.base.evaluate.eval_str(scope, expression) + new_code = pymodule.source_code + def new_pyname(): + newoffset = self.commenter.transfered_offset(offset) + return rope.base.evaluate.eval_location(pymodule, newoffset) + if new_code.startswith(self.code[:offset + 1]): + return new_pyname() + result = old_pyname() + if result is None: + return new_pyname() + return result + + +class _Commenter(object): + + def __init__(self, code): + self.code = code + self.lines = self.code.split('\n') + self.lines.append('\n') + self.origs = range(len(self.lines) + 1) + self.diffs = [0] * (len(self.lines) + 1) + + def comment(self, lineno): + start = _logical_start(self.lines, lineno, check_prev=True) - 1 + # using self._get_stmt_end() instead of self._get_block_end() + # to lower commented lines + end = self._get_stmt_end(start) + indents = _get_line_indents(self.lines[start]) + if 0 < start: + last_lineno = self._last_non_blank(start - 1) + last_line = self.lines[last_lineno] + if last_line.rstrip().endswith(':'): + indents = _get_line_indents(last_line) + 4 + self._set(start, ' ' * indents + 'pass') + for line in range(start + 1, end + 1): + self._set(line, self.lines[start]) + self._fix_incomplete_try_blocks(lineno, indents) + + def transfered_offset(self, offset): + lineno = self.code.count('\n', 0, offset) + diff = sum(self.diffs[:lineno]) + return offset + diff + + def _last_non_blank(self, start): + while start > 0 and self.lines[start].strip() == '': + start -= 1 + return start + + def _get_block_end(self, lineno): + end_line = lineno + base_indents = _get_line_indents(self.lines[lineno]) + for i in range(lineno + 1, len(self.lines)): + if _get_line_indents(self.lines[i]) >= base_indents: + end_line = i + else: + break + return end_line + + def _get_stmt_end(self, lineno): + end_line = lineno + base_indents = _get_line_indents(self.lines[lineno]) + for i in range(lineno + 1, len(self.lines)): + if _get_line_indents(self.lines[i]) <= base_indents: + return i - 1 + return lineno + + def _fix_incomplete_try_blocks(self, lineno, indents): + block_start = lineno + last_indents = current_indents = indents + while block_start > 0: + block_start = rope.base.codeanalyze.get_block_start( + ArrayLinesAdapter(self.lines), block_start) - 1 + if self.lines[block_start].strip().startswith('try:'): + indents = _get_line_indents(self.lines[block_start]) + if indents > last_indents: + continue + last_indents = indents + block_end = self._find_matching_deindent(block_start) + line = self.lines[block_end].strip() + if not (line.startswith('finally:') or + line.startswith('except ') or + line.startswith('except:')): + self._insert(block_end, ' ' * indents + 'finally:') + self._insert(block_end + 1, ' ' * indents + ' pass') + + def _find_matching_deindent(self, line_number): + indents = _get_line_indents(self.lines[line_number]) + current_line = line_number + 1 + while current_line < len(self.lines): + line = self.lines[current_line] + if not line.strip().startswith('#') and not line.strip() == '': + # HACK: We should have used logical lines here + if _get_line_indents(self.lines[current_line]) <= indents: + return current_line + current_line += 1 + return len(self.lines) - 1 + + def _set(self, lineno, line): + self.diffs[self.origs[lineno]] += len(line) - len(self.lines[lineno]) + self.lines[lineno] = line + + def _insert(self, lineno, line): + self.diffs[self.origs[lineno]] += len(line) + 1 + self.origs.insert(lineno, self.origs[lineno]) + self.lines.insert(lineno, line) + +def _logical_start(lines, lineno, check_prev=False): + logical_finder = LogicalLineFinder(ArrayLinesAdapter(lines)) + if check_prev: + prev = lineno - 1 + while prev > 0: + start, end = logical_finder.logical_line_in(prev) + if end is None or start <= lineno < end: + return start + if start <= prev: + break + prev -= 1 + return logical_finder.logical_line_in(lineno)[0] + + +def _get_line_indents(line): + return rope.base.codeanalyze.count_line_indents(line) diff -r e30544496575 -r 48cacfdc2ca6 vim/sadness/ropevim/src/rope/rope/contrib/generate.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vim/sadness/ropevim/src/rope/rope/contrib/generate.py Wed Oct 06 12:30:46 2010 -0400 @@ -0,0 +1,355 @@ +import rope.base.evaluate +from rope.base import change, pyobjects, exceptions, pynames, worder, codeanalyze +from rope.refactor import sourceutils, importutils, functionutils, suites + + +def create_generate(kind, project, resource, offset): + """A factory for creating `Generate` objects + + `kind` can be 'variable', 'function', 'class', 'module' or + 'package'. + + """ + generate = eval('Generate' + kind.title()) + return generate(project, resource, offset) + + +def create_module(project, name, sourcefolder=None): + """Creates a module and returns a `rope.base.resources.File`""" + if sourcefolder is None: + sourcefolder = project.root + packages = name.split('.') + parent = sourcefolder + for package in packages[:-1]: + parent = parent.get_child(package) + return parent.create_file(packages[-1] + '.py') + +def create_package(project, name, sourcefolder=None): + """Creates a package and returns a `rope.base.resources.Folder`""" + if sourcefolder is None: + sourcefolder = project.root + packages = name.split('.') + parent = sourcefolder + for package in packages[:-1]: + parent = parent.get_child(package) + made_packages = parent.create_folder(packages[-1]) + made_packages.create_file('__init__.py') + return made_packages + + +class _Generate(object): + + def __init__(self, project, resource, offset): + self.project = project + self.resource = resource + self.info = self._generate_info(project, resource, offset) + self.name = self.info.get_name() + self._check_exceptional_conditions() + + def _generate_info(self, project, resource, offset): + return _GenerationInfo(project.pycore, resource, offset) + + def _check_exceptional_conditions(self): + if self.info.element_already_exists(): + raise exceptions.RefactoringError( + 'Element <%s> already exists.' % self.name) + if not self.info.primary_is_found(): + raise exceptions.RefactoringError( + 'Cannot determine the scope <%s> should be defined in.' % self.name) + + def get_changes(self): + changes = change.ChangeSet('Generate %s <%s>' % + (self._get_element_kind(), self.name)) + indents = self.info.get_scope_indents() + blanks = self.info.get_blank_lines() + base_definition = sourceutils.fix_indentation(self._get_element(), indents) + definition = '\n' * blanks[0] + base_definition + '\n' * blanks[1] + + resource = self.info.get_insertion_resource() + start, end = self.info.get_insertion_offsets() + + collector = codeanalyze.ChangeCollector(resource.read()) + collector.add_change(start, end, definition) + changes.add_change(change.ChangeContents( + resource, collector.get_changed())) + return changes + + def get_location(self): + return (self.info.get_insertion_resource(), + self.info.get_insertion_lineno()) + + def _get_element_kind(self): + raise NotImplementedError() + + def _get_element(self): + raise NotImplementedError() + + +class GenerateFunction(_Generate): + + def _generate_info(self, project, resource, offset): + return _FunctionGenerationInfo(project.pycore, resource, offset) + + def _get_element(self): + decorator = '' + args = [] + if self.info.is_static_method(): + decorator = '@staticmethod\n' + if self.info.is_method() or self.info.is_constructor() or \ + self.info.is_instance(): + args.append('self') + args.extend(self.info.get_passed_args()) + definition = '%sdef %s(%s):\n pass\n' % (decorator, self.name, + ', '.join(args)) + return definition + + def _get_element_kind(self): + return 'Function' + + +class GenerateVariable(_Generate): + + def _get_element(self): + return '%s = None\n' % self.name + + def _get_element_kind(self): + return 'Variable' + + +class GenerateClass(_Generate): + + def _get_element(self): + return 'class %s(object):\n pass\n' % self.name + + def _get_element_kind(self): + return 'Class' + + +class GenerateModule(_Generate): + + def get_changes(self): + package = self.info.get_package() + changes = change.ChangeSet('Generate Module <%s>' % self.name) + new_resource = self.project.get_file('%s/%s.py' % (package.path, self.name)) + if new_resource.exists(): + raise exceptions.RefactoringError( + 'Module <%s> already exists' % new_resource.path) + changes.add_change(change.CreateResource(new_resource)) + changes.add_change(_add_import_to_module( + self.project.pycore, self.resource, new_resource)) + return changes + + def get_location(self): + package = self.info.get_package() + return (package.get_child('%s.py' % self.name) , 1) + + +class GeneratePackage(_Generate): + + def get_changes(self): + package = self.info.get_package() + changes = change.ChangeSet('Generate Package <%s>' % self.name) + new_resource = self.project.get_folder('%s/%s' % (package.path, self.name)) + if new_resource.exists(): + raise exceptions.RefactoringError( + 'Package <%s> already exists' % new_resource.path) + changes.add_change(change.CreateResource(new_resource)) + changes.add_change(_add_import_to_module( + self.project.pycore, self.resource, new_resource)) + child = self.project.get_folder(package.path + '/' + self.name) + changes.add_change(change.CreateFile(child, '__init__.py')) + return changes + + def get_location(self): + package = self.info.get_package() + child = package.get_child(self.name) + return (child.get_child('__init__.py') , 1) + + +def _add_import_to_module(pycore, resource, imported): + pymodule = pycore.resource_to_pyobject(resource) + import_tools = importutils.ImportTools(pycore) + module_imports = import_tools.module_imports(pymodule) + module_name = pycore.modname(imported) + new_import = importutils.NormalImport(((module_name, None), )) + module_imports.add_import(new_import) + return change.ChangeContents(resource, module_imports.get_changed_source()) + + +class _GenerationInfo(object): + + def __init__(self, pycore, resource, offset): + self.pycore = pycore + self.resource = resource + self.offset = offset + self.source_pymodule = self.pycore.resource_to_pyobject(resource) + finder = rope.base.evaluate.ScopeNameFinder(self.source_pymodule) + self.primary, self.pyname = finder.get_primary_and_pyname_at(offset) + self._init_fields() + + def _init_fields(self): + self.source_scope = self._get_source_scope() + self.goal_scope = self._get_goal_scope() + self.goal_pymodule = self._get_goal_module(self.goal_scope) + + def _get_goal_scope(self): + if self.primary is None: + return self._get_source_scope() + pyobject = self.primary.get_object() + if isinstance(pyobject, pyobjects.PyDefinedObject): + return pyobject.get_scope() + elif isinstance(pyobject.get_type(), pyobjects.PyClass): + return pyobject.get_type().get_scope() + + def _get_goal_module(self, scope): + if scope is None: + return + while scope.parent is not None: + scope = scope.parent + return scope.pyobject + + def _get_source_scope(self): + module_scope = self.source_pymodule.get_scope() + lineno = self.source_pymodule.lines.get_line_number(self.offset) + return module_scope.get_inner_scope_for_line(lineno) + + def get_insertion_lineno(self): + lines = self.goal_pymodule.lines + if self.goal_scope == self.source_scope: + line_finder = self.goal_pymodule.logical_lines + lineno = lines.get_line_number(self.offset) + lineno = line_finder.logical_line_in(lineno)[0] + root = suites.ast_suite_tree(self.goal_scope.pyobject.get_ast()) + suite = root.find_suite(lineno) + indents = sourceutils.get_indents(lines, lineno) + while self.get_scope_indents() < indents: + lineno = suite.get_start() + indents = sourceutils.get_indents(lines, lineno) + suite = suite.parent + return lineno + else: + return min(self.goal_scope.get_end() + 1, lines.length()) + + def get_insertion_resource(self): + return self.goal_pymodule.get_resource() + + def get_insertion_offsets(self): + if self.goal_scope.get_kind() == 'Class': + start, end = sourceutils.get_body_region(self.goal_scope.pyobject) + if self.goal_pymodule.source_code[start:end].strip() == 'pass': + return start, end + lines = self.goal_pymodule.lines + start = lines.get_line_start(self.get_insertion_lineno()) + return (start, start) + + def get_scope_indents(self): + if self.goal_scope.get_kind() == 'Module': + return 0 + return sourceutils.get_indents(self.goal_pymodule.lines, + self.goal_scope.get_start()) + 4 + + def get_blank_lines(self): + if self.goal_scope.get_kind() == 'Module': + base_blanks = 2 + if self.goal_pymodule.source_code.strip() == '': + base_blanks = 0 + if self.goal_scope.get_kind() == 'Class': + base_blanks = 1 + if self.goal_scope.get_kind() == 'Function': + base_blanks = 0 + if self.goal_scope == self.source_scope: + return (0, base_blanks) + return (base_blanks, 0) + + def get_package(self): + primary = self.primary + if self.primary is None: + return self.pycore.get_source_folders()[0] + if isinstance(primary.get_object(), pyobjects.PyPackage): + return primary.get_object().get_resource() + raise exceptions.RefactoringError( + 'A module/package can be only created in a package.') + + def primary_is_found(self): + return self.goal_scope is not None + + def element_already_exists(self): + if self.pyname is None or isinstance(self.pyname, pynames.UnboundName): + return False + return self.get_name() in self.goal_scope.get_defined_names() + + def get_name(self): + return worder.get_name_at(self.resource, self.offset) + + +class _FunctionGenerationInfo(_GenerationInfo): + + def _get_goal_scope(self): + if self.is_constructor(): + return self.pyname.get_object().get_scope() + if self.is_instance(): + return self.pyname.get_object().get_type().get_scope() + if self.primary is None: + return self._get_source_scope() + pyobject = self.primary.get_object() + if isinstance(pyobject, pyobjects.PyDefinedObject): + return pyobject.get_scope() + elif isinstance(pyobject.get_type(), pyobjects.PyClass): + return pyobject.get_type().get_scope() + + def element_already_exists(self): + if self.pyname is None or isinstance(self.pyname, pynames.UnboundName): + return False + return self.get_name() in self.goal_scope.get_defined_names() + + def is_static_method(self): + return self.primary is not None and \ + isinstance(self.primary.get_object(), pyobjects.PyClass) + + def is_method(self): + return self.primary is not None and \ + isinstance(self.primary.get_object().get_type(), pyobjects.PyClass) + + def is_constructor(self): + return self.pyname is not None and \ + isinstance(self.pyname.get_object(), pyobjects.PyClass) + + def is_instance(self): + if self.pyname is None: + return False + pyobject = self.pyname.get_object() + return isinstance(pyobject.get_type(), pyobjects.PyClass) + + def get_name(self): + if self.is_constructor(): + return '__init__' + if self.is_instance(): + return '__call__' + return worder.get_name_at(self.resource, self.offset) + + def get_passed_args(self): + result = [] + source = self.source_pymodule.source_code + finder = worder.Worder(source) + if finder.is_a_function_being_called(self.offset): + start, end = finder.get_primary_range(self.offset) + parens_start, parens_end = finder.get_word_parens_range(end - 1) + call = source[start:parens_end] + parser = functionutils._FunctionParser(call, False) + args, keywords = parser.get_parameters() + for arg in args: + if self._is_id(arg): + result.append(arg) + else: + result.append('arg%d' % len(result)) + for name, value in keywords: + result.append(name) + return result + + def _is_id(self, arg): + def id_or_underline(c): + return c.isalpha() or c == '_' + for c in arg: + if not id_or_underline(c) and not c.isdigit(): + return False + return id_or_underline(arg[0]) diff -r e30544496575 -r 48cacfdc2ca6 vim/sadness/ropevim/src/rope/rope/refactor/__init__.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vim/sadness/ropevim/src/rope/rope/refactor/__init__.py Wed Oct 06 12:30:46 2010 -0400 @@ -0,0 +1,55 @@ +"""rope refactor package + +This package contains modules that perform python refactorings. +Refactoring classes perform refactorings in 4 steps: + +1. Collect some data for performing the refactoring and use them + to construct a refactoring class. Like:: + + renamer = Rename(project, resource, offset) + +2. Some refactorings give you useful information about the + refactoring after their construction. Like:: + + print(renamer.get_old_name()) + +3. Give the refactoring class more information about how to + perform the refactoring and get the changes this refactoring is + going to make. This is done by calling `get_changes` method of the + refactoring class. Like:: + + changes = renamer.get_changes(new_name) + +4. You can commit the changes. Like:: + + project.do(changes) + +These steps are like the steps IDEs usually do for performing a +refactoring. These are the things an IDE does in each step: + +1. Construct a refactoring object by giving it information like + resource, offset and ... . Some of the refactoring problems (like + performing rename refactoring on language keywords) can be reported + here. +2. Print some information about the refactoring and ask the user + about the information that are necessary for completing the + refactoring (like new name). +3. Call the `get_changes` by passing it information asked from + the user (if necessary) and get and preview the changes returned by + it. +4. perform the refactoring. + +From ``0.5m5`` release the `get_changes()` method of some time- +consuming refactorings take an optional `rope.base.taskhandle. +TaskHandle` parameter. You can use this object for stopping or +monitoring the progress of refactorings. + +""" +from rope.refactor.importutils import ImportOrganizer +from rope.refactor.topackage import ModuleToPackage + + +__all__ = ['rename', 'move', 'inline', 'extract', 'restructure', 'topackage', + 'importutils', 'usefunction', 'change_signature', + 'encapsulate_field', 'introduce_factory', 'introduce_parameter', + 'localtofield', 'method_object', 'multiproject'] diff -r e30544496575 -r 48cacfdc2ca6 vim/sadness/ropevim/src/rope/rope/refactor/change_signature.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vim/sadness/ropevim/src/rope/rope/refactor/change_signature.py Wed Oct 06 12:30:46 2010 -0400 @@ -0,0 +1,342 @@ +import copy + +import rope.base.exceptions +from rope.base import pyobjects, taskhandle, evaluate, worder, codeanalyze, utils +from rope.base.change import ChangeContents, ChangeSet +from rope.refactor import occurrences, functionutils + + +class ChangeSignature(object): + + def __init__(self, project, resource, offset): + self.pycore = project.pycore + self.resource = resource + self.offset = offset + self._set_name_and_pyname() + if self.pyname is None or self.pyname.get_object() is None or \ + not isinstance(self.pyname.get_object(), pyobjects.PyFunction): + raise rope.base.exceptions.RefactoringError( + 'Change method signature should be performed on functions') + + def _set_name_and_pyname(self): + self.name = worder.get_name_at(self.resource, self.offset) + this_pymodule = self.pycore.resource_to_pyobject(self.resource) + self.primary, self.pyname = evaluate.eval_location2( + this_pymodule, self.offset) + if self.pyname is None: + return + pyobject = self.pyname.get_object() + if isinstance(pyobject, pyobjects.PyClass) and \ + '__init__' in pyobject: + self.pyname = pyobject['__init__'] + self.name = '__init__' + pyobject = self.pyname.get_object() + self.others = None + if self.name == '__init__' and \ + isinstance(pyobject, pyobjects.PyFunction) and \ + isinstance(pyobject.parent, pyobjects.PyClass): + pyclass = pyobject.parent + self.others = (pyclass.get_name(), + pyclass.parent[pyclass.get_name()]) + + def _change_calls(self, call_changer, in_hierarchy=None, resources=None, + handle=taskhandle.NullTaskHandle()): + if resources is None: + resources = self.pycore.get_python_files() + changes = ChangeSet('Changing signature of <%s>' % self.name) + job_set = handle.create_jobset('Collecting Changes', len(resources)) + finder = occurrences.create_finder( + self.pycore, self.name, self.pyname, instance=self.primary, + in_hierarchy=in_hierarchy and self.is_method()) + if self.others: + name, pyname = self.others + constructor_finder = occurrences.create_finder( + self.pycore, name, pyname, only_calls=True) + finder = _MultipleFinders([finder, constructor_finder]) + for file in resources: + job_set.started_job(file.path) + change_calls = _ChangeCallsInModule( + self.pycore, finder, file, call_changer) + changed_file = change_calls.get_changed_module() + if changed_file is not None: + changes.add_change(ChangeContents(file, changed_file)) + job_set.finished_job() + return changes + + def get_args(self): + """Get function arguments. + + Return a list of ``(name, default)`` tuples for all but star + and double star arguments. For arguments that don't have a + default, `None` will be used. + """ + return self._definfo().args_with_defaults + + def is_method(self): + pyfunction = self.pyname.get_object() + return isinstance(pyfunction.parent, pyobjects.PyClass) + + @utils.deprecated('Use `ChangeSignature.get_args()` instead') + def get_definition_info(self): + return self._definfo() + + def _definfo(self): + return functionutils.DefinitionInfo.read(self.pyname.get_object()) + + @utils.deprecated() + def normalize(self): + changer = _FunctionChangers( + self.pyname.get_object(), self.get_definition_info(), + [ArgumentNormalizer()]) + return self._change_calls(changer) + + @utils.deprecated() + def remove(self, index): + changer = _FunctionChangers( + self.pyname.get_object(), self.get_definition_info(), + [ArgumentRemover(index)]) + return self._change_calls(changer) + + @utils.deprecated() + def add(self, index, name, default=None, value=None): + changer = _FunctionChangers( + self.pyname.get_object(), self.get_definition_info(), + [ArgumentAdder(index, name, default, value)]) + return self._change_calls(changer) + + @utils.deprecated() + def inline_default(self, index): + changer = _FunctionChangers( + self.pyname.get_object(), self.get_definition_info(), + [ArgumentDefaultInliner(index)]) + return self._change_calls(changer) + + @utils.deprecated() + def reorder(self, new_ordering): + changer = _FunctionChangers( + self.pyname.get_object(), self.get_definition_info(), + [ArgumentReorderer(new_ordering)]) + return self._change_calls(changer) + + def get_changes(self, changers, in_hierarchy=False, resources=None, + task_handle=taskhandle.NullTaskHandle()): + """Get changes caused by this refactoring + + `changers` is a list of `_ArgumentChanger`\s. If `in_hierarchy` + is `True` the changers are applyed to all matching methods in + the class hierarchy. + `resources` can be a list of `rope.base.resource.File`\s that + should be searched for occurrences; if `None` all python files + in the project are searched. + + """ + function_changer = _FunctionChangers(self.pyname.get_object(), + self._definfo(), changers) + return self._change_calls(function_changer, in_hierarchy, + resources, task_handle) + + +class _FunctionChangers(object): + + def __init__(self, pyfunction, definition_info, changers=None): + self.pyfunction = pyfunction + self.definition_info = definition_info + self.changers = changers + self.changed_definition_infos = self._get_changed_definition_infos() + + def _get_changed_definition_infos(self): + result = [] + definition_info = self.definition_info + result.append(definition_info) + for changer in self.changers: + definition_info = copy.deepcopy(definition_info) + changer.change_definition_info(definition_info) + result.append(definition_info) + return result + + def change_definition(self, call): + return self.changed_definition_infos[-1].to_string() + + def change_call(self, primary, pyname, call): + call_info = functionutils.CallInfo.read( + primary, pyname, self.definition_info, call) + mapping = functionutils.ArgumentMapping(self.definition_info, call_info) + + for definition_info, changer in zip(self.changed_definition_infos, self.changers): + changer.change_argument_mapping(definition_info, mapping) + + return mapping.to_call_info(self.changed_definition_infos[-1]).to_string() + + +class _ArgumentChanger(object): + + def change_definition_info(self, definition_info): + pass + + def change_argument_mapping(self, definition_info, argument_mapping): + pass + + +class ArgumentNormalizer(_ArgumentChanger): + pass + + +class ArgumentRemover(_ArgumentChanger): + + def __init__(self, index): + self.index = index + + def change_definition_info(self, call_info): + if self.index < len(call_info.args_with_defaults): + del call_info.args_with_defaults[self.index] + elif self.index == len(call_info.args_with_defaults) and \ + call_info.args_arg is not None: + call_info.args_arg = None + elif (self.index == len(call_info.args_with_defaults) and + call_info.args_arg is None and call_info.keywords_arg is not None) or \ + (self.index == len(call_info.args_with_defaults) + 1 and + call_info.args_arg is not None and call_info.keywords_arg is not None): + call_info.keywords_arg = None + + def change_argument_mapping(self, definition_info, mapping): + if self.index < len(definition_info.args_with_defaults): + name = definition_info.args_with_defaults[0] + if name in mapping.param_dict: + del mapping.param_dict[name] + + +class ArgumentAdder(_ArgumentChanger): + + def __init__(self, index, name, default=None, value=None): + self.index = index + self.name = name + self.default = default + self.value = value + + def change_definition_info(self, definition_info): + for pair in definition_info.args_with_defaults: + if pair[0] == self.name: + raise rope.base.exceptions.RefactoringError( + 'Adding duplicate parameter: <%s>.' % self.name) + definition_info.args_with_defaults.insert(self.index, + (self.name, self.default)) + + def change_argument_mapping(self, definition_info, mapping): + if self.value is not None: + mapping.param_dict[self.name] = self.value + + +class ArgumentDefaultInliner(_ArgumentChanger): + + def __init__(self, index): + self.index = index + self.remove = False + + def change_definition_info(self, definition_info): + if self.remove: + definition_info.args_with_defaults[self.index] = \ + (definition_info.args_with_defaults[self.index][0], None) + + def change_argument_mapping(self, definition_info, mapping): + default = definition_info.args_with_defaults[self.index][1] + name = definition_info.args_with_defaults[self.index][0] + if default is not None and name not in mapping.param_dict: + mapping.param_dict[name] = default + + +class ArgumentReorderer(_ArgumentChanger): + + def __init__(self, new_order, autodef=None): + """Construct an `ArgumentReorderer` + + Note that the `new_order` is a list containing the new + position of parameters; not the position each parameter + is going to be moved to. (changed in ``0.5m4``) + + For example changing ``f(a, b, c)`` to ``f(c, a, b)`` + requires passing ``[2, 0, 1]`` and *not* ``[1, 2, 0]``. + + The `autodef` (automatic default) argument, forces rope to use + it as a default if a default is needed after the change. That + happens when an argument without default is moved after + another that has a default value. Note that `autodef` should + be a string or `None`; the latter disables adding automatic + default. + + """ + self.new_order = new_order + self.autodef = autodef + + def change_definition_info(self, definition_info): + new_args = list(definition_info.args_with_defaults) + for new_index, index in enumerate(self.new_order): + new_args[new_index] = definition_info.args_with_defaults[index] + seen_default = False + for index, (arg, default) in enumerate(list(new_args)): + if default is not None: + seen_default = True + if seen_default and default is None and self.autodef is not None: + new_args[index] = (arg, self.autodef) + definition_info.args_with_defaults = new_args + + +class _ChangeCallsInModule(object): + + def __init__(self, pycore, occurrence_finder, resource, call_changer): + self.pycore = pycore + self.occurrence_finder = occurrence_finder + self.resource = resource + self.call_changer = call_changer + + def get_changed_module(self): + word_finder = worder.Worder(self.source) + change_collector = codeanalyze.ChangeCollector(self.source) + for occurrence in self.occurrence_finder.find_occurrences(self.resource): + if not occurrence.is_called() and not occurrence.is_defined(): + continue + start, end = occurrence.get_primary_range() + begin_parens, end_parens = word_finder.get_word_parens_range(end - 1) + if occurrence.is_called(): + primary, pyname = occurrence.get_primary_and_pyname() + changed_call = self.call_changer.change_call( + primary, pyname, self.source[start:end_parens]) + else: + changed_call = self.call_changer.change_definition( + self.source[start:end_parens]) + if changed_call is not None: + change_collector.add_change(start, end_parens, changed_call) + return change_collector.get_changed() + + @property + @utils.saveit + def pymodule(self): + return self.pycore.resource_to_pyobject(self.resource) + + @property + @utils.saveit + def source(self): + if self.resource is not None: + return self.resource.read() + else: + return self.pymodule.source_code + + @property + @utils.saveit + def lines(self): + return self.pymodule.lines + + +class _MultipleFinders(object): + + def __init__(self, finders): + self.finders = finders + + def find_occurrences(self, resource=None, pymodule=None): + all_occurrences = [] + for finder in self.finders: + all_occurrences.extend(finder.find_occurrences(resource, pymodule)) + all_occurrences.sort(self._cmp_occurrences) + return all_occurrences + + def _cmp_occurrences(self, o1, o2): + return cmp(o1.get_primary_range(), o2.get_primary_range()) diff -r e30544496575 -r 48cacfdc2ca6 vim/sadness/ropevim/src/rope/rope/refactor/encapsulate_field.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vim/sadness/ropevim/src/rope/rope/refactor/encapsulate_field.py Wed Oct 06 12:30:46 2010 -0400 @@ -0,0 +1,202 @@ +from rope.base import pynames, taskhandle, evaluate, exceptions, worder, utils +from rope.base.change import ChangeSet, ChangeContents +from rope.refactor import sourceutils, occurrences + + +class EncapsulateField(object): + + def __init__(self, project, resource, offset): + self.pycore = project.pycore + self.name = worder.get_name_at(resource, offset) + this_pymodule = self.pycore.resource_to_pyobject(resource) + self.pyname = evaluate.eval_location(this_pymodule, offset) + if not self._is_an_attribute(self.pyname): + raise exceptions.RefactoringError( + 'Encapsulate field should be performed on class attributes.') + self.resource = self.pyname.get_definition_location()[0].get_resource() + + def get_changes(self, getter=None, setter=None, resources=None, + task_handle=taskhandle.NullTaskHandle()): + """Get the changes this refactoring makes + + If `getter` is not `None`, that will be the name of the + getter, otherwise ``get_${field_name}`` will be used. The + same is true for `setter` and if it is None set_${field_name} is + used. + + `resources` can be a list of `rope.base.resource.File`\s that + the refactoring should be applied on; if `None` all python + files in the project are searched. + + """ + if resources is None: + resources = self.pycore.get_python_files() + changes = ChangeSet('Encapsulate field <%s>' % self.name) + job_set = task_handle.create_jobset('Collecting Changes', + len(resources)) + if getter is None: + getter = 'get_' + self.name + if setter is None: + setter = 'set_' + self.name + renamer = GetterSetterRenameInModule( + self.pycore, self.name, self.pyname, getter, setter) + for file in resources: + job_set.started_job(file.path) + if file == self.resource: + result = self._change_holding_module(changes, renamer, + getter, setter) + changes.add_change(ChangeContents(self.resource, result)) + else: + result = renamer.get_changed_module(file) + if result is not None: + changes.add_change(ChangeContents(file, result)) + job_set.finished_job() + return changes + + def get_field_name(self): + """Get the name of the field to be encapsulated""" + return self.name + + def _is_an_attribute(self, pyname): + if pyname is not None and isinstance(pyname, pynames.AssignedName): + pymodule, lineno = self.pyname.get_definition_location() + scope = pymodule.get_scope().\ + get_inner_scope_for_line(lineno) + if scope.get_kind() == 'Class': + return pyname in scope.get_names().values() + parent = scope.parent + if parent is not None and parent.get_kind() == 'Class': + return pyname in parent.get_names().values() + return False + + def _get_defining_class_scope(self): + defining_scope = self._get_defining_scope() + if defining_scope.get_kind() == 'Function': + defining_scope = defining_scope.parent + return defining_scope + + def _get_defining_scope(self): + pymodule, line = self.pyname.get_definition_location() + return pymodule.get_scope().get_inner_scope_for_line(line) + + def _change_holding_module(self, changes, renamer, getter, setter): + pymodule = self.pycore.resource_to_pyobject(self.resource) + class_scope = self._get_defining_class_scope() + defining_object = self._get_defining_scope().pyobject + start, end = sourceutils.get_body_region(defining_object) + + new_source = renamer.get_changed_module(pymodule=pymodule, + skip_start=start, skip_end=end) + if new_source is not None: + pymodule = self.pycore.get_string_module(new_source, self.resource) + class_scope = pymodule.get_scope().\ + get_inner_scope_for_line(class_scope.get_start()) + indents = sourceutils.get_indent(self.pycore) * ' ' + getter = 'def %s(self):\n%sreturn self.%s' % \ + (getter, indents, self.name) + setter = 'def %s(self, value):\n%sself.%s = value' % \ + (setter, indents, self.name) + new_source = sourceutils.add_methods(pymodule, class_scope, + [getter, setter]) + return new_source + + +class GetterSetterRenameInModule(object): + + def __init__(self, pycore, name, pyname, getter, setter): + self.pycore = pycore + self.name = name + self.finder = occurrences.create_finder(pycore, name, pyname) + self.getter = getter + self.setter = setter + + def get_changed_module(self, resource=None, pymodule=None, + skip_start=0, skip_end=0): + change_finder = _FindChangesForModule(self, resource, pymodule, + skip_start, skip_end) + return change_finder.get_changed_module() + + +class _FindChangesForModule(object): + + def __init__(self, finder, resource, pymodule, skip_start, skip_end): + self.pycore = finder.pycore + self.finder = finder.finder + self.getter = finder.getter + self.setter = finder.setter + self.resource = resource + self.pymodule = pymodule + self.last_modified = 0 + self.last_set = None + self.set_index = None + self.skip_start = skip_start + self.skip_end = skip_end + + def get_changed_module(self): + result = [] + for occurrence in self.finder.find_occurrences(self.resource, + self.pymodule): + start, end = occurrence.get_word_range() + if self.skip_start <= start < self.skip_end: + continue + self._manage_writes(start, result) + result.append(self.source[self.last_modified:start]) + if self._is_assigned_in_a_tuple_assignment(occurrence): + raise exceptions.RefactoringError( + 'Cannot handle tuple assignments in encapsulate field.') + if occurrence.is_written(): + assignment_type = self.worder.get_assignment_type(start) + if assignment_type == '=': + result.append(self.setter + '(') + else: + var_name = self.source[occurrence.get_primary_range()[0]: + start] + self.getter + '()' + result.append(self.setter + '(' + var_name + + ' %s ' % assignment_type[:-1]) + current_line = self.lines.get_line_number(start) + start_line, end_line = self.pymodule.logical_lines.\ + logical_line_in(current_line) + self.last_set = self.lines.get_line_end(end_line) + end = self.source.index('=', end) + 1 + self.set_index = len(result) + else: + result.append(self.getter + '()') + self.last_modified = end + if self.last_modified != 0: + self._manage_writes(len(self.source), result) + result.append(self.source[self.last_modified:]) + return ''.join(result) + return None + + def _manage_writes(self, offset, result): + if self.last_set is not None and self.last_set <= offset: + result.append(self.source[self.last_modified:self.last_set]) + set_value = ''.join(result[self.set_index:]).strip() + del result[self.set_index:] + result.append(set_value + ')') + self.last_modified = self.last_set + self.last_set = None + + def _is_assigned_in_a_tuple_assignment(self, occurance): + offset = occurance.get_word_range()[0] + return self.worder.is_assigned_in_a_tuple_assignment(offset) + + @property + @utils.saveit + def source(self): + if self.resource is not None: + return self.resource.read() + else: + return self.pymodule.source_code + + @property + @utils.saveit + def lines(self): + if self.pymodule is None: + self.pymodule = self.pycore.resource_to_pyobject(self.resource) + return self.pymodule.lines + + @property + @utils.saveit + def worder(self): + return worder.Worder(self.source) diff -r e30544496575 -r 48cacfdc2ca6 vim/sadness/ropevim/src/rope/rope/refactor/extract.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vim/sadness/ropevim/src/rope/rope/refactor/extract.py Wed Oct 06 12:30:46 2010 -0400 @@ -0,0 +1,789 @@ +import re + +from rope.base import ast, codeanalyze +from rope.base.change import ChangeSet, ChangeContents +from rope.base.exceptions import RefactoringError +from rope.refactor import (sourceutils, similarfinder, + patchedast, suites, usefunction) + + +# Extract refactoring has lots of special cases. I tried to split it +# to smaller parts to make it more manageable: +# +# _ExtractInfo: holds information about the refactoring; it is passed +# to the parts that need to have information about the refactoring +# +# _ExtractCollector: merely saves all of the information necessary for +# performing the refactoring. +# +# _DefinitionLocationFinder: finds where to insert the definition. +# +# _ExceptionalConditionChecker: checks for exceptional conditions in +# which the refactoring cannot be applied. +# +# _ExtractMethodParts: generates the pieces of code (like definition) +# needed for performing extract method. +# +# _ExtractVariableParts: like _ExtractMethodParts for variables. +# +# _ExtractPerformer: Uses above classes to collect refactoring +# changes. +# +# There are a few more helper functions and classes used by above +# classes. +class _ExtractRefactoring(object): + + def __init__(self, project, resource, start_offset, end_offset, + variable=False): + self.project = project + self.pycore = project.pycore + self.resource = resource + self.start_offset = self._fix_start(resource.read(), start_offset) + self.end_offset = self._fix_end(resource.read(), end_offset) + + def _fix_start(self, source, offset): + while offset < len(source) and source[offset].isspace(): + offset += 1 + return offset + + def _fix_end(self, source, offset): + while offset > 0 and source[offset - 1].isspace(): + offset -= 1 + return offset + + def get_changes(self, extracted_name, similar=False, global_=False): + """Get the changes this refactoring makes + + :parameters: + - `similar`: if `True`, similar expressions/statements are also + replaced. + - `global_`: if `True`, the extracted method/variable will + be global. + + """ + info = _ExtractInfo( + self.project, self.resource, self.start_offset, self.end_offset, + extracted_name, variable=self.kind == 'variable', + similar=similar, make_global=global_) + new_contents = _ExtractPerformer(info).extract() + changes = ChangeSet('Extract %s <%s>' % (self.kind, + extracted_name)) + changes.add_change(ChangeContents(self.resource, new_contents)) + return changes + + +class ExtractMethod(_ExtractRefactoring): + + def __init__(self, *args, **kwds): + super(ExtractMethod, self).__init__(*args, **kwds) + + kind = 'method' + + +class ExtractVariable(_ExtractRefactoring): + + def __init__(self, *args, **kwds): + kwds = dict(kwds) + kwds['variable'] = True + super(ExtractVariable, self).__init__(*args, **kwds) + + kind = 'variable' + + +class _ExtractInfo(object): + """Holds information about the extract to be performed""" + + def __init__(self, project, resource, start, end, new_name, + variable, similar, make_global): + self.pycore = project.pycore + self.resource = resource + self.pymodule = self.pycore.resource_to_pyobject(resource) + self.global_scope = self.pymodule.get_scope() + self.source = self.pymodule.source_code + self.lines = self.pymodule.lines + self.new_name = new_name + self.variable = variable + self.similar = similar + self._init_parts(start, end) + self._init_scope() + self.make_global = make_global + + def _init_parts(self, start, end): + self.region = (self._choose_closest_line_end(start), + self._choose_closest_line_end(end, end=True)) + + start = self.logical_lines.logical_line_in( + self.lines.get_line_number(self.region[0]))[0] + end = self.logical_lines.logical_line_in( + self.lines.get_line_number(self.region[1]))[1] + self.region_lines = (start, end) + + self.lines_region = (self.lines.get_line_start(self.region_lines[0]), + self.lines.get_line_end(self.region_lines[1])) + + @property + def logical_lines(self): + return self.pymodule.logical_lines + + def _init_scope(self): + start_line = self.region_lines[0] + scope = self.global_scope.get_inner_scope_for_line(start_line) + if scope.get_kind() != 'Module' and scope.get_start() == start_line: + scope = scope.parent + self.scope = scope + self.scope_region = self._get_scope_region(self.scope) + + def _get_scope_region(self, scope): + return (self.lines.get_line_start(scope.get_start()), + self.lines.get_line_end(scope.get_end()) + 1) + + def _choose_closest_line_end(self, offset, end=False): + lineno = self.lines.get_line_number(offset) + line_start = self.lines.get_line_start(lineno) + line_end = self.lines.get_line_end(lineno) + if self.source[line_start:offset].strip() == '': + if end: + return line_start - 1 + else: + return line_start + elif self.source[offset:line_end].strip() == '': + return min(line_end, len(self.source)) + return offset + + @property + def one_line(self): + return self.region != self.lines_region and \ + (self.logical_lines.logical_line_in(self.region_lines[0]) == + self.logical_lines.logical_line_in(self.region_lines[1])) + + @property + def global_(self): + return self.scope.parent is None + + @property + def method(self): + return self.scope.parent is not None and \ + self.scope.parent.get_kind() == 'Class' + + @property + def indents(self): + return sourceutils.get_indents(self.pymodule.lines, + self.region_lines[0]) + + @property + def scope_indents(self): + if self.global_: + return 0 + return sourceutils.get_indents(self.pymodule.lines, + self.scope.get_start()) + + @property + def extracted(self): + return self.source[self.region[0]:self.region[1]] + + _returned = None + @property + def returned(self): + """Does the extracted piece contain return statement""" + if self._returned is None: + node = _parse_text(self.extracted) + self._returned = usefunction._returns_last(node) + return self._returned + + +class _ExtractCollector(object): + """Collects information needed for performing the extract""" + + def __init__(self, info): + self.definition = None + self.body_pattern = None + self.checks = {} + self.replacement_pattern = None + self.matches = None + self.replacements = None + self.definition_location = None + + +class _ExtractPerformer(object): + + def __init__(self, info): + self.info = info + _ExceptionalConditionChecker()(self.info) + + def extract(self): + extract_info = self._collect_info() + content = codeanalyze.ChangeCollector(self.info.source) + definition = extract_info.definition + lineno, indents = extract_info.definition_location + offset = self.info.lines.get_line_start(lineno) + indented = sourceutils.fix_indentation(definition, indents) + content.add_change(offset, offset, indented) + self._replace_occurrences(content, extract_info) + return content.get_changed() + + def _replace_occurrences(self, content, extract_info): + for match in extract_info.matches: + replacement = similarfinder.CodeTemplate( + extract_info.replacement_pattern) + mapping = {} + for name in replacement.get_names(): + node = match.get_ast(name) + if node: + start, end = patchedast.node_region(match.get_ast(name)) + mapping[name] = self.info.source[start:end] + else: + mapping[name] = name + region = match.get_region() + content.add_change(region[0], region[1], + replacement.substitute(mapping)) + + def _collect_info(self): + extract_collector = _ExtractCollector(self.info) + self._find_definition(extract_collector) + self._find_matches(extract_collector) + self._find_definition_location(extract_collector) + return extract_collector + + def _find_matches(self, collector): + regions = self._where_to_search() + finder = similarfinder.SimilarFinder(self.info.pymodule) + matches = [] + for start, end in regions: + matches.extend((finder.get_matches(collector.body_pattern, + collector.checks, start, end))) + collector.matches = matches + + def _where_to_search(self): + if self.info.similar: + if self.info.make_global or self.info.global_: + return [(0, len(self.info.pymodule.source_code))] + if self.info.method and not self.info.variable: + class_scope = self.info.scope.parent + regions = [] + method_kind = _get_function_kind(self.info.scope) + for scope in class_scope.get_scopes(): + if method_kind == 'method' and \ + _get_function_kind(scope) != 'method': + continue + start = self.info.lines.get_line_start(scope.get_start()) + end = self.info.lines.get_line_end(scope.get_end()) + regions.append((start, end)) + return regions + else: + if self.info.variable: + return [self.info.scope_region] + else: + return [self.info._get_scope_region(self.info.scope.parent)] + else: + return [self.info.region] + + def _find_definition_location(self, collector): + matched_lines = [] + for match in collector.matches: + start = self.info.lines.get_line_number(match.get_region()[0]) + start_line = self.info.logical_lines.logical_line_in(start)[0] + matched_lines.append(start_line) + location_finder = _DefinitionLocationFinder(self.info, matched_lines) + collector.definition_location = (location_finder.find_lineno(), + location_finder.find_indents()) + + def _find_definition(self, collector): + if self.info.variable: + parts = _ExtractVariableParts(self.info) + else: + parts = _ExtractMethodParts(self.info) + collector.definition = parts.get_definition() + collector.body_pattern = parts.get_body_pattern() + collector.replacement_pattern = parts.get_replacement_pattern() + collector.checks = parts.get_checks() + + +class _DefinitionLocationFinder(object): + + def __init__(self, info, matched_lines): + self.info = info + self.matched_lines = matched_lines + # This only happens when subexpressions cannot be matched + if not matched_lines: + self.matched_lines.append(self.info.region_lines[0]) + + def find_lineno(self): + if self.info.variable and not self.info.make_global: + return self._get_before_line() + if self.info.make_global or self.info.global_: + toplevel = self._find_toplevel(self.info.scope) + ast = self.info.pymodule.get_ast() + newlines = sorted(self.matched_lines + [toplevel.get_end() + 1]) + return suites.find_visible(ast, newlines) + return self._get_after_scope() + + def _find_toplevel(self, scope): + toplevel = scope + if toplevel.parent is not None: + while toplevel.parent.parent is not None: + toplevel = toplevel.parent + return toplevel + + def find_indents(self): + if self.info.variable and not self.info.make_global: + return sourceutils.get_indents(self.info.lines, + self._get_before_line()) + else: + if self.info.global_ or self.info.make_global: + return 0 + return self.info.scope_indents + + def _get_before_line(self): + ast = self.info.scope.pyobject.get_ast() + return suites.find_visible(ast, self.matched_lines) + + def _get_after_scope(self): + return self.info.scope.get_end() + 1 + + +class _ExceptionalConditionChecker(object): + + def __call__(self, info): + self.base_conditions(info) + if info.one_line: + self.one_line_conditions(info) + else: + self.multi_line_conditions(info) + + def base_conditions(self, info): + if info.region[1] > info.scope_region[1]: + raise RefactoringError('Bad region selected for extract method') + end_line = info.region_lines[1] + end_scope = info.global_scope.get_inner_scope_for_line(end_line) + if end_scope != info.scope and end_scope.get_end() != end_line: + raise RefactoringError('Bad region selected for extract method') + try: + extracted = info.source[info.region[0]:info.region[1]] + if info.one_line: + extracted = '(%s)' % extracted + if _UnmatchedBreakOrContinueFinder.has_errors(extracted): + raise RefactoringError('A break/continue without having a ' + 'matching for/while loop.') + except SyntaxError: + raise RefactoringError('Extracted piece should ' + 'contain complete statements.') + + def one_line_conditions(self, info): + if self._is_region_on_a_word(info): + raise RefactoringError('Should extract complete statements.') + if info.variable and not info.one_line: + raise RefactoringError('Extract variable should not ' + 'span multiple lines.') + + def multi_line_conditions(self, info): + node = _parse_text(info.source[info.region[0]:info.region[1]]) + count = usefunction._return_count(node) + if count > 1: + raise RefactoringError('Extracted piece can have only one ' + 'return statement.') + if usefunction._yield_count(node): + raise RefactoringError('Extracted piece cannot ' + 'have yield statements.') + if count == 1 and not usefunction._returns_last(node): + raise RefactoringError('Return should be the last statement.') + if info.region != info.lines_region: + raise RefactoringError('Extracted piece should ' + 'contain complete statements.') + + def _is_region_on_a_word(self, info): + if info.region[0] > 0 and self._is_on_a_word(info, info.region[0] - 1) or \ + self._is_on_a_word(info, info.region[1] - 1): + return True + + def _is_on_a_word(self, info, offset): + prev = info.source[offset] + if not (prev.isalnum() or prev == '_') or \ + offset + 1 == len(info.source): + return False + next = info.source[offset + 1] + return next.isalnum() or next == '_' + + +class _ExtractMethodParts(object): + + def __init__(self, info): + self.info = info + self.info_collector = self._create_info_collector() + + def get_definition(self): + if self.info.global_: + return '\n%s\n' % self._get_function_definition() + else: + return '\n%s' % self._get_function_definition() + + def get_replacement_pattern(self): + variables = [] + variables.extend(self._find_function_arguments()) + variables.extend(self._find_function_returns()) + return similarfinder.make_pattern(self._get_call(), variables) + + def get_body_pattern(self): + variables = [] + variables.extend(self._find_function_arguments()) + variables.extend(self._find_function_returns()) + variables.extend(self._find_temps()) + return similarfinder.make_pattern(self._get_body(), variables) + + def _get_body(self): + result = sourceutils.fix_indentation(self.info.extracted, 0) + if self.info.one_line: + result = '(%s)' % result + return result + + def _find_temps(self): + return usefunction.find_temps(self.info.pycore.project, + self._get_body()) + + def get_checks(self): + if self.info.method and not self.info.make_global: + if _get_function_kind(self.info.scope) == 'method': + class_name = similarfinder._pydefined_to_str( + self.info.scope.parent.pyobject) + return {self._get_self_name(): 'type=' + class_name} + return {} + + def _create_info_collector(self): + zero = self.info.scope.get_start() - 1 + start_line = self.info.region_lines[0] - zero + end_line = self.info.region_lines[1] - zero + info_collector = _FunctionInformationCollector(start_line, end_line, + self.info.global_) + body = self.info.source[self.info.scope_region[0]: + self.info.scope_region[1]] + node = _parse_text(body) + ast.walk(node, info_collector) + return info_collector + + def _get_function_definition(self): + args = self._find_function_arguments() + returns = self._find_function_returns() + result = [] + if self.info.method and not self.info.make_global and \ + _get_function_kind(self.info.scope) != 'method': + result.append('@staticmethod\n') + result.append('def %s:\n' % self._get_function_signature(args)) + unindented_body = self._get_unindented_function_body(returns) + indents = sourceutils.get_indent(self.info.pycore) + function_body = sourceutils.indent_lines(unindented_body, indents) + result.append(function_body) + definition = ''.join(result) + + return definition + '\n' + + def _get_function_signature(self, args): + args = list(args) + prefix = '' + if self._extracting_method(): + self_name = self._get_self_name() + if self_name is None: + raise RefactoringError('Extracting a method from a function ' + 'with no self argument.') + if self_name in args: + args.remove(self_name) + args.insert(0, self_name) + return prefix + self.info.new_name + \ + '(%s)' % self._get_comma_form(args) + + def _extracting_method(self): + return self.info.method and not self.info.make_global and \ + _get_function_kind(self.info.scope) == 'method' + + def _get_self_name(self): + param_names = self.info.scope.pyobject.get_param_names() + if param_names: + return param_names[0] + + def _get_function_call(self, args): + prefix = '' + if self.info.method and not self.info.make_global: + if _get_function_kind(self.info.scope) == 'method': + self_name = self._get_self_name() + if self_name in args: + args.remove(self_name) + prefix = self_name + '.' + else: + prefix = self.info.scope.parent.pyobject.get_name() + '.' + return prefix + '%s(%s)' % (self.info.new_name, + self._get_comma_form(args)) + + def _get_comma_form(self, names): + result = '' + if names: + result += names[0] + for name in names[1:]: + result += ', ' + name + return result + + def _get_call(self): + if self.info.one_line: + args = self._find_function_arguments() + return self._get_function_call(args) + args = self._find_function_arguments() + returns = self._find_function_returns() + call_prefix = '' + if returns: + call_prefix = self._get_comma_form(returns) + ' = ' + if self.info.returned: + call_prefix = 'return ' + return call_prefix + self._get_function_call(args) + + def _find_function_arguments(self): + # if not make_global, do not pass any global names; they are + # all visible. + if self.info.global_ and not self.info.make_global: + return () + if not self.info.one_line: + result = (self.info_collector.prewritten & + self.info_collector.read) + result |= (self.info_collector.prewritten & + self.info_collector.postread & + (self.info_collector.maybe_written - + self.info_collector.written)) + return list(result) + start = self.info.region[0] + if start == self.info.lines_region[0]: + start = start + re.search('\S', self.info.extracted).start() + function_definition = self.info.source[start:self.info.region[1]] + read = _VariableReadsAndWritesFinder.find_reads_for_one_liners( + function_definition) + return list(self.info_collector.prewritten.intersection(read)) + + def _find_function_returns(self): + if self.info.one_line or self.info.returned: + return [] + written = self.info_collector.written | \ + self.info_collector.maybe_written + return list(written & self.info_collector.postread) + + def _get_unindented_function_body(self, returns): + if self.info.one_line: + return 'return ' + _join_lines(self.info.extracted) + extracted_body = self.info.extracted + unindented_body = sourceutils.fix_indentation(extracted_body, 0) + if returns: + unindented_body += '\nreturn %s' % self._get_comma_form(returns) + return unindented_body + + +class _ExtractVariableParts(object): + + def __init__(self, info): + self.info = info + + def get_definition(self): + result = self.info.new_name + ' = ' + \ + _join_lines(self.info.extracted) + '\n' + return result + + def get_body_pattern(self): + return '(%s)' % self.info.extracted.strip() + + def get_replacement_pattern(self): + return self.info.new_name + + def get_checks(self): + return {} + + +class _FunctionInformationCollector(object): + + def __init__(self, start, end, is_global): + self.start = start + self.end = end + self.is_global = is_global + self.prewritten = set() + self.maybe_written = set() + self.written = set() + self.read = set() + self.postread = set() + self.postwritten = set() + self.host_function = True + self.conditional = False + + def _read_variable(self, name, lineno): + if self.start <= lineno <= self.end: + if name not in self.written: + self.read.add(name) + if self.end < lineno: + if name not in self.postwritten: + self.postread.add(name) + + def _written_variable(self, name, lineno): + if self.start <= lineno <= self.end: + if self.conditional: + self.maybe_written.add(name) + else: + self.written.add(name) + if self.start > lineno: + self.prewritten.add(name) + if self.end < lineno: + self.postwritten.add(name) + + def _FunctionDef(self, node): + if not self.is_global and self.host_function: + self.host_function = False + for name in _get_argnames(node.args): + self._written_variable(name, node.lineno) + for child in node.body: + ast.walk(child, self) + else: + self._written_variable(node.name, node.lineno) + visitor = _VariableReadsAndWritesFinder() + for child in node.body: + ast.walk(child, visitor) + for name in visitor.read - visitor.written: + self._read_variable(name, node.lineno) + + def _Name(self, node): + if isinstance(node.ctx, (ast.Store, ast.AugStore)): + self._written_variable(node.id, node.lineno) + if not isinstance(node.ctx, ast.Store): + self._read_variable(node.id, node.lineno) + + def _Assign(self, node): + ast.walk(node.value, self) + for child in node.targets: + ast.walk(child, self) + + def _ClassDef(self, node): + self._written_variable(node.name, node.lineno) + + def _handle_conditional_node(self, node): + self.conditional = True + try: + for child in ast.get_child_nodes(node): + ast.walk(child, self) + finally: + self.conditional = False + + def _If(self, node): + self._handle_conditional_node(node) + + def _While(self, node): + self._handle_conditional_node(node) + + def _For(self, node): + self._handle_conditional_node(node) + + + +def _get_argnames(arguments): + result = [node.id for node in arguments.args + if isinstance(node, ast.Name)] + if arguments.vararg: + result.append(arguments.vararg) + if arguments.kwarg: + result.append(arguments.kwarg) + return result + + +class _VariableReadsAndWritesFinder(object): + + def __init__(self): + self.written = set() + self.read = set() + + def _Name(self, node): + if isinstance(node.ctx, (ast.Store, ast.AugStore)): + self.written.add(node.id) + if not isinstance(node, ast.Store): + self.read.add(node.id) + + def _FunctionDef(self, node): + self.written.add(node.name) + visitor = _VariableReadsAndWritesFinder() + for child in ast.get_child_nodes(node): + ast.walk(child, visitor) + self.read.update(visitor.read - visitor.written) + + def _Class(self, node): + self.written.add(node.name) + + @staticmethod + def find_reads_and_writes(code): + if code.strip() == '': + return set(), set() + if isinstance(code, unicode): + code = code.encode('utf-8') + node = _parse_text(code) + visitor = _VariableReadsAndWritesFinder() + ast.walk(node, visitor) + return visitor.read, visitor.written + + @staticmethod + def find_reads_for_one_liners(code): + if code.strip() == '': + return set(), set() + node = _parse_text(code) + visitor = _VariableReadsAndWritesFinder() + ast.walk(node, visitor) + return visitor.read + + +class _UnmatchedBreakOrContinueFinder(object): + + def __init__(self): + self.error = False + self.loop_count = 0 + + def _For(self, node): + self.loop_encountered(node) + + def _While(self, node): + self.loop_encountered(node) + + def loop_encountered(self, node): + self.loop_count += 1 + for child in node.body: + ast.walk(child, self) + self.loop_count -= 1 + if node.orelse: + ast.walk(node.orelse, self) + + def _Break(self, node): + self.check_loop() + + def _Continue(self, node): + self.check_loop() + + def check_loop(self): + if self.loop_count < 1: + self.error = True + + def _FunctionDef(self, node): + pass + + def _ClassDef(self, node): + pass + + @staticmethod + def has_errors(code): + if code.strip() == '': + return False + node = _parse_text(code) + visitor = _UnmatchedBreakOrContinueFinder() + ast.walk(node, visitor) + return visitor.error + +def _get_function_kind(scope): + return scope.pyobject.get_kind() + + +def _parse_text(body): + body = sourceutils.fix_indentation(body, 0) + node = ast.parse(body) + return node + +def _join_lines(code): + lines = [] + for line in code.splitlines(): + if line.endswith('\\'): + lines.append(line[:-1].strip()) + else: + lines.append(line.strip()) + return ' '.join(lines) diff -r e30544496575 -r 48cacfdc2ca6 vim/sadness/ropevim/src/rope/rope/refactor/functionutils.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vim/sadness/ropevim/src/rope/rope/refactor/functionutils.py Wed Oct 06 12:30:46 2010 -0400 @@ -0,0 +1,222 @@ +import rope.base.exceptions +import rope.base.pyobjects +from rope.base.builtins import Lambda +from rope.base import worder + + +class DefinitionInfo(object): + + def __init__(self, function_name, is_method, args_with_defaults, + args_arg, keywords_arg): + self.function_name = function_name + self.is_method = is_method + self.args_with_defaults = args_with_defaults + self.args_arg = args_arg + self.keywords_arg = keywords_arg + + def to_string(self): + return '%s(%s)' % (self.function_name, self.arguments_to_string()) + + def arguments_to_string(self, from_index=0): + params = [] + for arg, default in self.args_with_defaults: + if default is not None: + params.append('%s=%s' % (arg, default)) + else: + params.append(arg) + if self.args_arg is not None: + params.append('*' + self.args_arg) + if self.keywords_arg: + params.append('**' + self.keywords_arg) + return ', '.join(params[from_index:]) + + @staticmethod + def _read(pyfunction, code): + scope = pyfunction.get_scope() + parent = scope.parent + parameter_names = pyfunction.get_param_names() + kind = pyfunction.get_kind() + is_method = kind == 'method' + is_lambda = kind == 'lambda' + info = _FunctionParser(code, is_method, is_lambda) + args, keywords = info.get_parameters() + args_arg = None + keywords_arg = None + if args and args[-1].startswith('**'): + keywords_arg = args[-1][2:] + del args[-1] + if args and args[-1].startswith('*'): + args_arg = args[-1][1:] + del args[-1] + args_with_defaults = [(name, None) for name in args] + args_with_defaults.extend(keywords) + return DefinitionInfo(info.get_function_name(), is_method, + args_with_defaults, args_arg, keywords_arg) + + @staticmethod + def read(pyfunction): + pymodule = pyfunction.get_module() + word_finder = worder.Worder(pymodule.source_code) + lineno = pyfunction.get_ast().lineno + start = pymodule.lines.get_line_start(lineno) + if isinstance(pyfunction, Lambda): + call = word_finder.get_lambda_and_args(start) + else: + call = word_finder.get_function_and_args_in_header(start) + return DefinitionInfo._read(pyfunction, call) + + +class CallInfo(object): + + def __init__(self, function_name, args, keywords, args_arg, + keywords_arg, implicit_arg, constructor): + self.function_name = function_name + self.args = args + self.keywords = keywords + self.args_arg = args_arg + self.keywords_arg = keywords_arg + self.implicit_arg = implicit_arg + self.constructor = constructor + + def to_string(self): + function = self.function_name + if self.implicit_arg: + function = self.args[0] + '.' + self.function_name + params = [] + start = 0 + if self.implicit_arg or self.constructor: + start = 1 + if self.args[start:]: + params.extend(self.args[start:]) + if self.keywords: + params.extend(['%s=%s' % (name, value) for name, value in self.keywords]) + if self.args_arg is not None: + params.append('*' + self.args_arg) + if self.keywords_arg: + params.append('**' + self.keywords_arg) + return '%s(%s)' % (function, ', '.join(params)) + + @staticmethod + def read(primary, pyname, definition_info, code): + is_method_call = CallInfo._is_method_call(primary, pyname) + is_constructor = CallInfo._is_class(pyname) + is_classmethod = CallInfo._is_classmethod(pyname) + info = _FunctionParser(code, is_method_call or is_classmethod) + args, keywords = info.get_parameters() + args_arg = None + keywords_arg = None + if args and args[-1].startswith('**'): + keywords_arg = args[-1][2:] + del args[-1] + if args and args[-1].startswith('*'): + args_arg = args[-1][1:] + del args[-1] + if is_constructor: + args.insert(0, definition_info.args_with_defaults[0][0]) + return CallInfo(info.get_function_name(), args, keywords, args_arg, + keywords_arg, is_method_call or is_classmethod, + is_constructor) + + @staticmethod + def _is_method_call(primary, pyname): + return primary is not None and \ + isinstance(primary.get_object().get_type(), + rope.base.pyobjects.PyClass) and \ + CallInfo._is_method(pyname) + + @staticmethod + def _is_class(pyname): + return pyname is not None and \ + isinstance(pyname.get_object(), + rope.base.pyobjects.PyClass) + + @staticmethod + def _is_method(pyname): + if pyname is not None and \ + isinstance(pyname.get_object(), rope.base.pyobjects.PyFunction): + return pyname.get_object().get_kind() == 'method' + return False + + @staticmethod + def _is_classmethod(pyname): + if pyname is not None and \ + isinstance(pyname.get_object(), rope.base.pyobjects.PyFunction): + return pyname.get_object().get_kind() == 'classmethod' + return False + + +class ArgumentMapping(object): + + def __init__(self, definition_info, call_info): + self.call_info = call_info + self.param_dict = {} + self.keyword_args = [] + self.args_arg = [] + for index, value in enumerate(call_info.args): + if index < len(definition_info.args_with_defaults): + name = definition_info.args_with_defaults[index][0] + self.param_dict[name] = value + else: + self.args_arg.append(value) + for name, value in call_info.keywords: + index = -1 + for pair in definition_info.args_with_defaults: + if pair[0] == name: + self.param_dict[name] = value + break + else: + self.keyword_args.append((name, value)) + + def to_call_info(self, definition_info): + args = [] + keywords = [] + for index in range(len(definition_info.args_with_defaults)): + name = definition_info.args_with_defaults[index][0] + if name in self.param_dict: + args.append(self.param_dict[name]) + else: + for i in range(index, len(definition_info.args_with_defaults)): + name = definition_info.args_with_defaults[i][0] + if name in self.param_dict: + keywords.append((name, self.param_dict[name])) + break + args.extend(self.args_arg) + keywords.extend(self.keyword_args) + return CallInfo(self.call_info.function_name, args, keywords, + self.call_info.args_arg, self.call_info.keywords_arg, + self.call_info.implicit_arg, self.call_info.constructor) + + +class _FunctionParser(object): + + def __init__(self, call, implicit_arg, is_lambda=False): + self.call = call + self.implicit_arg = implicit_arg + self.word_finder = worder.Worder(self.call) + if is_lambda: + self.last_parens = self.call.rindex(':') + else: + self.last_parens = self.call.rindex(')') + self.first_parens = self.word_finder._find_parens_start(self.last_parens) + + def get_parameters(self): + args, keywords = self.word_finder.get_parameters(self.first_parens, + self.last_parens) + if self.is_called_as_a_method(): + instance = self.call[:self.call.rindex('.', 0, self.first_parens)] + args.insert(0, instance.strip()) + return args, keywords + + def get_instance(self): + if self.is_called_as_a_method(): + return self.word_finder.get_primary_at( + self.call.rindex('.', 0, self.first_parens) - 1) + + def get_function_name(self): + if self.is_called_as_a_method(): + return self.word_finder.get_word_at(self.first_parens - 1) + else: + return self.word_finder.get_primary_at(self.first_parens - 1) + + def is_called_as_a_method(self): + return self.implicit_arg and '.' in self.call[:self.first_parens] diff -r e30544496575 -r 48cacfdc2ca6 vim/sadness/ropevim/src/rope/rope/refactor/importutils/__init__.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vim/sadness/ropevim/src/rope/rope/refactor/importutils/__init__.py Wed Oct 06 12:30:46 2010 -0400 @@ -0,0 +1,299 @@ +"""A package for handling imports + +This package provides tools for modifying module imports after +refactorings or as a separate task. + +""" +import rope.base.evaluate +from rope.base.change import ChangeSet, ChangeContents +from rope.refactor import occurrences, rename +from rope.refactor.importutils import module_imports, actions +from rope.refactor.importutils.importinfo import NormalImport, FromImport +import rope.base.codeanalyze + + +class ImportOrganizer(object): + """Perform some import-related commands + + Each method returns a `rope.base.change.Change` object. + + """ + + def __init__(self, project): + self.project = project + self.pycore = project.pycore + self.import_tools = ImportTools(self.pycore) + + def organize_imports(self, resource, offset=None): + return self._perform_command_on_import_tools( + self.import_tools.organize_imports, resource, offset) + + def expand_star_imports(self, resource, offset=None): + return self._perform_command_on_import_tools( + self.import_tools.expand_stars, resource, offset) + + def froms_to_imports(self, resource, offset=None): + return self._perform_command_on_import_tools( + self.import_tools.froms_to_imports, resource, offset) + + def relatives_to_absolutes(self, resource, offset=None): + return self._perform_command_on_import_tools( + self.import_tools.relatives_to_absolutes, resource, offset) + + def handle_long_imports(self, resource, offset=None): + return self._perform_command_on_import_tools( + self.import_tools.handle_long_imports, resource, offset) + + def _perform_command_on_import_tools(self, method, resource, offset): + pymodule = self.pycore.resource_to_pyobject(resource) + before_performing = pymodule.source_code + import_filter = None + if offset is not None: + import_filter = self._line_filter( + pymodule.lines.get_line_number(offset)) + result = method(pymodule, import_filter=import_filter) + if result is not None and result != before_performing: + changes = ChangeSet(method.__name__.replace('_', ' ') + + ' in <%s>' % resource.path) + changes.add_change(ChangeContents(resource, result)) + return changes + + def _line_filter(self, lineno): + def import_filter(import_stmt): + return import_stmt.start_line <= lineno < import_stmt.end_line + return import_filter + + +class ImportTools(object): + + def __init__(self, pycore): + self.pycore = pycore + + def get_import(self, resource): + """The import statement for `resource`""" + module_name = self.pycore.modname(resource) + return NormalImport(((module_name, None), )) + + def get_from_import(self, resource, name): + """The from import statement for `name` in `resource`""" + module_name = self.pycore.modname(resource) + names = [] + if isinstance(name, list): + names = [(imported, None) for imported in name] + else: + names = [(name, None),] + return FromImport(module_name, 0, tuple(names)) + + def module_imports(self, module, imports_filter=None): + return module_imports.ModuleImports(self.pycore, module, + imports_filter) + + def froms_to_imports(self, pymodule, import_filter=None): + pymodule = self._clean_up_imports(pymodule, import_filter) + module_imports = self.module_imports(pymodule, import_filter) + for import_stmt in module_imports.imports: + if import_stmt.readonly or \ + not self._is_transformable_to_normal(import_stmt.import_info): + continue + pymodule = self._from_to_normal(pymodule, import_stmt) + + # Adding normal imports in place of froms + module_imports = self.module_imports(pymodule, import_filter) + for import_stmt in module_imports.imports: + if not import_stmt.readonly and \ + self._is_transformable_to_normal(import_stmt.import_info): + import_stmt.import_info = \ + NormalImport(((import_stmt.import_info.module_name, None),)) + module_imports.remove_duplicates() + return module_imports.get_changed_source() + + def expand_stars(self, pymodule, import_filter=None): + module_imports = self.module_imports(pymodule, import_filter) + module_imports.expand_stars() + return module_imports.get_changed_source() + + def _from_to_normal(self, pymodule, import_stmt): + resource = pymodule.get_resource() + from_import = import_stmt.import_info + module_name = from_import.module_name + for name, alias in from_import.names_and_aliases: + imported = name + if alias is not None: + imported = alias + occurrence_finder = occurrences.create_finder( + self.pycore, imported, pymodule[imported], imports=False) + source = rename.rename_in_module( + occurrence_finder, module_name + '.' + name, + pymodule=pymodule, replace_primary=True) + if source is not None: + pymodule = self.pycore.get_string_module(source, resource) + return pymodule + + def _clean_up_imports(self, pymodule, import_filter): + resource = pymodule.get_resource() + module_with_imports = self.module_imports(pymodule, import_filter) + module_with_imports.expand_stars() + source = module_with_imports.get_changed_source() + if source is not None: + pymodule = self.pycore.get_string_module(source, resource) + source = self.relatives_to_absolutes(pymodule) + if source is not None: + pymodule = self.pycore.get_string_module(source, resource) + + module_with_imports = self.module_imports(pymodule, import_filter) + module_with_imports.remove_duplicates() + module_with_imports.remove_unused_imports() + source = module_with_imports.get_changed_source() + if source is not None: + pymodule = self.pycore.get_string_module(source, resource) + return pymodule + + def relatives_to_absolutes(self, pymodule, import_filter=None): + module_imports = self.module_imports(pymodule, import_filter) + to_be_absolute_list = module_imports.get_relative_to_absolute_list() + for name, absolute_name in to_be_absolute_list: + pymodule = self._rename_in_module(pymodule, name, absolute_name) + module_imports = self.module_imports(pymodule, import_filter) + module_imports.get_relative_to_absolute_list() + source = module_imports.get_changed_source() + if source is None: + source = pymodule.source_code + return source + + def _is_transformable_to_normal(self, import_info): + if not isinstance(import_info, FromImport): + return False + return True + + def organize_imports(self, pymodule, + unused=True, duplicates=True, + selfs=True, sort=True, import_filter=None): + if unused or duplicates: + module_imports = self.module_imports(pymodule, import_filter) + if unused: + module_imports.remove_unused_imports() + if duplicates: + module_imports.remove_duplicates() + source = module_imports.get_changed_source() + if source is not None: + pymodule = self.pycore.get_string_module( + source, pymodule.get_resource()) + if selfs: + pymodule = self._remove_self_imports(pymodule, import_filter) + if sort: + return self.sort_imports(pymodule, import_filter) + else: + return pymodule.source_code + + def _remove_self_imports(self, pymodule, import_filter=None): + module_imports = self.module_imports(pymodule, import_filter) + to_be_fixed, to_be_renamed = module_imports.get_self_import_fix_and_rename_list() + for name in to_be_fixed: + try: + pymodule = self._rename_in_module(pymodule, name, '', till_dot=True) + except ValueError: + # There is a self import with direct access to it + return pymodule + for name, new_name in to_be_renamed: + pymodule = self._rename_in_module(pymodule, name, new_name) + module_imports = self.module_imports(pymodule, import_filter) + module_imports.get_self_import_fix_and_rename_list() + source = module_imports.get_changed_source() + if source is not None: + pymodule = self.pycore.get_string_module(source, pymodule.get_resource()) + return pymodule + + def _rename_in_module(self, pymodule, name, new_name, till_dot=False): + old_name = name.split('.')[-1] + old_pyname = rope.base.evaluate.eval_str(pymodule.get_scope(), name) + occurrence_finder = occurrences.create_finder( + self.pycore, old_name, old_pyname, imports=False) + changes = rope.base.codeanalyze.ChangeCollector(pymodule.source_code) + for occurrence in occurrence_finder.find_occurrences(pymodule=pymodule): + start, end = occurrence.get_primary_range() + if till_dot: + new_end = pymodule.source_code.index('.', end) + 1 + space = pymodule.source_code[end:new_end - 1].strip() + if not space == '': + for c in space: + if not c.isspace() and c not in '\\': + raise ValueError() + end = new_end + changes.add_change(start, end, new_name) + source = changes.get_changed() + if source is not None: + pymodule = self.pycore.get_string_module(source, pymodule.get_resource()) + return pymodule + + def sort_imports(self, pymodule, import_filter=None): + module_imports = self.module_imports(pymodule, import_filter) + module_imports.sort_imports() + return module_imports.get_changed_source() + + def handle_long_imports(self, pymodule, maxdots=2, maxlength=27, + import_filter=None): + # IDEA: `maxdots` and `maxlength` can be specified in project config + # adding new from imports + module_imports = self.module_imports(pymodule, import_filter) + to_be_fixed = module_imports.handle_long_imports(maxdots, maxlength) + # performing the renaming + pymodule = self.pycore.get_string_module( + module_imports.get_changed_source(), + resource=pymodule.get_resource()) + for name in to_be_fixed: + pymodule = self._rename_in_module(pymodule, name, + name.split('.')[-1]) + # organizing imports + return self.organize_imports(pymodule, selfs=False, sort=False, + import_filter=import_filter) + + +def get_imports(pycore, pydefined): + """A shortcut for getting the `ImportInfo`\s used in a scope""" + pymodule = pydefined.get_module() + module = module_imports.ModuleImports(pycore, pymodule) + if pymodule == pydefined: + return [stmt.import_info for stmt in module.imports] + return module.get_used_imports(pydefined) + + +def get_module_imports(pycore, pymodule): + """A shortcut for creating a `module_imports.ModuleImports` object""" + return module_imports.ModuleImports(pycore, pymodule) + + +def add_import(pycore, pymodule, module_name, name=None): + imports = get_module_imports(pycore, pymodule) + candidates = [] + names = [] + # from mod import name + if name is not None: + from_import = FromImport(module_name, 0, [(name, None)]) + names.append(name) + candidates.append(from_import) + # from pkg import mod + if '.' in module_name: + pkg, mod = module_name.rsplit('.', 1) + candidates.append(FromImport(pkg, 0, [(mod, None)])) + if name: + names.append(mod + '.' + name) + else: + names.append(mod) + # import mod + normal_import = NormalImport([(module_name, None)]) + if name: + names.append(module_name + '.' + name) + else: + names.append(module_name) + + candidates.append(normal_import) + + visitor = actions.AddingVisitor(pycore, candidates) + selected_import = normal_import + for import_statement in imports.imports: + if import_statement.accept(visitor): + selected_import = visitor.import_info + break + imports.add_import(selected_import) + imported_name = names[candidates.index(selected_import)] + return imports.get_changed_source(), imported_name diff -r e30544496575 -r 48cacfdc2ca6 vim/sadness/ropevim/src/rope/rope/refactor/importutils/actions.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vim/sadness/ropevim/src/rope/rope/refactor/importutils/actions.py Wed Oct 06 12:30:46 2010 -0400 @@ -0,0 +1,359 @@ +import os +import sys + +from rope.base import pyobjects, exceptions, stdmods +from rope.refactor import occurrences +from rope.refactor.importutils import importinfo + + +class ImportInfoVisitor(object): + + def dispatch(self, import_): + try: + method_name = 'visit' + import_.import_info.__class__.__name__ + method = getattr(self, method_name) + return method(import_, import_.import_info) + except exceptions.ModuleNotFoundError: + pass + + def visitEmptyImport(self, import_stmt, import_info): + pass + + def visitNormalImport(self, import_stmt, import_info): + pass + + def visitFromImport(self, import_stmt, import_info): + pass + + +class RelativeToAbsoluteVisitor(ImportInfoVisitor): + + def __init__(self, pycore, current_folder): + self.to_be_absolute = [] + self.pycore = pycore + self.folder = current_folder + self.context = importinfo.ImportContext(pycore, current_folder) + + def visitNormalImport(self, import_stmt, import_info): + self.to_be_absolute.extend(self._get_relative_to_absolute_list(import_info)) + new_pairs = [] + for name, alias in import_info.names_and_aliases: + resource = self.pycore.find_module(name, folder=self.folder) + if resource is None: + new_pairs.append((name, alias)) + continue + absolute_name = self.pycore.modname(resource) + new_pairs.append((absolute_name, alias)) + if not import_info._are_name_and_alias_lists_equal( + new_pairs, import_info.names_and_aliases): + import_stmt.import_info = importinfo.NormalImport(new_pairs) + + def _get_relative_to_absolute_list(self, import_info): + result = [] + for name, alias in import_info.names_and_aliases: + if alias is not None: + continue + resource = self.pycore.find_module(name, folder=self.folder) + if resource is None: + continue + absolute_name = self.pycore.modname(resource) + if absolute_name != name: + result.append((name, absolute_name)) + return result + + def visitFromImport(self, import_stmt, import_info): + resource = import_info.get_imported_resource(self.context) + if resource is None: + return None + absolute_name = self.pycore.modname(resource) + if import_info.module_name != absolute_name: + import_stmt.import_info = importinfo.FromImport( + absolute_name, 0, import_info.names_and_aliases) + + +class FilteringVisitor(ImportInfoVisitor): + + def __init__(self, pycore, folder, can_select): + self.to_be_absolute = [] + self.pycore = pycore + self.can_select = self._transform_can_select(can_select) + self.context = importinfo.ImportContext(pycore, folder) + + def _transform_can_select(self, can_select): + def can_select_name_and_alias(name, alias): + imported = name + if alias is not None: + imported = alias + return can_select(imported) + return can_select_name_and_alias + + def visitNormalImport(self, import_stmt, import_info): + new_pairs = [] + for name, alias in import_info.names_and_aliases: + if self.can_select(name, alias): + new_pairs.append((name, alias)) + return importinfo.NormalImport(new_pairs) + + def visitFromImport(self, import_stmt, import_info): + if _is_future(import_info): + return import_info + new_pairs = [] + if import_info.is_star_import(): + for name in import_info.get_imported_names(self.context): + if self.can_select(name, None): + new_pairs.append(import_info.names_and_aliases[0]) + break + else: + for name, alias in import_info.names_and_aliases: + if self.can_select(name, alias): + new_pairs.append((name, alias)) + return importinfo.FromImport( + import_info.module_name, import_info.level, new_pairs) + + +class RemovingVisitor(ImportInfoVisitor): + + def __init__(self, pycore, folder, can_select): + self.to_be_absolute = [] + self.pycore = pycore + self.filtering = FilteringVisitor(pycore, folder, can_select) + + def dispatch(self, import_): + result = self.filtering.dispatch(import_) + if result is not None: + import_.import_info = result + + +class AddingVisitor(ImportInfoVisitor): + """A class for adding imports + + Given a list of `ImportInfo`\s, it tries to add each import to the + module and returns `True` and gives up when an import can be added + to older ones. + + """ + + def __init__(self, pycore, import_list): + self.pycore = pycore + self.import_list = import_list + self.import_info = None + + def dispatch(self, import_): + for import_info in self.import_list: + self.import_info = import_info + if ImportInfoVisitor.dispatch(self, import_): + return True + + # TODO: Handle adding relative and absolute imports + def visitNormalImport(self, import_stmt, import_info): + if not isinstance(self.import_info, import_info.__class__): + return False + # Adding ``import x`` and ``import x.y`` that results ``import x.y`` + if len(import_info.names_and_aliases) == \ + len(self.import_info.names_and_aliases) == 1: + imported1 = import_info.names_and_aliases[0] + imported2 = self.import_info.names_and_aliases[0] + if imported1[1] == imported2[1] is None: + if imported1[0].startswith(imported2[0] + '.'): + return True + if imported2[0].startswith(imported1[0] + '.'): + import_stmt.import_info = self.import_info + return True + # Multiple imports using a single import statement is discouraged + # so we won't bother adding them. + if self.import_info._are_name_and_alias_lists_equal( + import_info.names_and_aliases, self.import_info.names_and_aliases): + return True + + def visitFromImport(self, import_stmt, import_info): + if isinstance(self.import_info, import_info.__class__) and \ + import_info.module_name == self.import_info.module_name and \ + import_info.level == self.import_info.level: + if import_info.is_star_import(): + return True + if self.import_info.is_star_import(): + import_stmt.import_info = self.import_info + return True + new_pairs = list(import_info.names_and_aliases) + for pair in self.import_info.names_and_aliases: + if pair not in new_pairs: + new_pairs.append(pair) + import_stmt.import_info = importinfo.FromImport( + import_info.module_name, import_info.level, new_pairs) + return True + + +class ExpandStarsVisitor(ImportInfoVisitor): + + def __init__(self, pycore, folder, can_select): + self.pycore = pycore + self.filtering = FilteringVisitor(pycore, folder, can_select) + self.context = importinfo.ImportContext(pycore, folder) + + def visitNormalImport(self, import_stmt, import_info): + self.filtering.dispatch(import_stmt) + + def visitFromImport(self, import_stmt, import_info): + if import_info.is_star_import(): + new_pairs = [] + for name in import_info.get_imported_names(self.context): + new_pairs.append((name, None)) + new_import = importinfo.FromImport( + import_info.module_name, import_info.level, new_pairs) + import_stmt.import_info = \ + self.filtering.visitFromImport(None, new_import) + else: + self.filtering.dispatch(import_stmt) + + +class SelfImportVisitor(ImportInfoVisitor): + + def __init__(self, pycore, current_folder, resource): + self.pycore = pycore + self.folder = current_folder + self.resource = resource + self.to_be_fixed = set() + self.to_be_renamed = set() + self.context = importinfo.ImportContext(pycore, current_folder) + + def visitNormalImport(self, import_stmt, import_info): + new_pairs = [] + for name, alias in import_info.names_and_aliases: + resource = self.pycore.find_module(name, folder=self.folder) + if resource is not None and resource == self.resource: + imported = name + if alias is not None: + imported = alias + self.to_be_fixed.add(imported) + else: + new_pairs.append((name, alias)) + if not import_info._are_name_and_alias_lists_equal( + new_pairs, import_info.names_and_aliases): + import_stmt.import_info = importinfo.NormalImport(new_pairs) + + def visitFromImport(self, import_stmt, import_info): + resource = import_info.get_imported_resource(self.context) + if resource is None: + return + if resource == self.resource: + self._importing_names_from_self(import_info, import_stmt) + return + pymodule = self.pycore.resource_to_pyobject(resource) + new_pairs = [] + for name, alias in import_info.names_and_aliases: + try: + result = pymodule[name].get_object() + if isinstance(result, pyobjects.PyModule) and \ + result.get_resource() == self.resource: + imported = name + if alias is not None: + imported = alias + self.to_be_fixed.add(imported) + else: + new_pairs.append((name, alias)) + except exceptions.AttributeNotFoundError: + new_pairs.append((name, alias)) + if not import_info._are_name_and_alias_lists_equal( + new_pairs, import_info.names_and_aliases): + import_stmt.import_info = importinfo.FromImport( + import_info.module_name, import_info.level, new_pairs) + + def _importing_names_from_self(self, import_info, import_stmt): + if not import_info.is_star_import(): + for name, alias in import_info.names_and_aliases: + if alias is not None: + self.to_be_renamed.add((alias, name)) + import_stmt.empty_import() + + +class SortingVisitor(ImportInfoVisitor): + + def __init__(self, pycore, current_folder): + self.pycore = pycore + self.folder = current_folder + self.standard = set() + self.third_party = set() + self.in_project = set() + self.future = set() + self.context = importinfo.ImportContext(pycore, current_folder) + + def visitNormalImport(self, import_stmt, import_info): + if import_info.names_and_aliases: + name, alias = import_info.names_and_aliases[0] + resource = self.pycore.find_module( + name, folder=self.folder) + self._check_imported_resource(import_stmt, resource, name) + + def visitFromImport(self, import_stmt, import_info): + resource = import_info.get_imported_resource(self.context) + self._check_imported_resource(import_stmt, resource, + import_info.module_name) + + def _check_imported_resource(self, import_stmt, resource, imported_name): + info = import_stmt.import_info + if resource is not None and resource.project == self.pycore.project: + self.in_project.add(import_stmt) + elif _is_future(info): + self.future.add(import_stmt) + elif imported_name.split('.')[0] in stdmods.standard_modules(): + self.standard.add(import_stmt) + else: + self.third_party.add(import_stmt) + + +class LongImportVisitor(ImportInfoVisitor): + + def __init__(self, current_folder, pycore, maxdots, maxlength): + self.maxdots = maxdots + self.maxlength = maxlength + self.to_be_renamed = set() + self.current_folder = current_folder + self.pycore = pycore + self.new_imports = [] + + def visitNormalImport(self, import_stmt, import_info): + new_pairs = [] + for name, alias in import_info.names_and_aliases: + if alias is None and self._is_long(name): + self.to_be_renamed.add(name) + last_dot = name.rindex('.') + from_ = name[:last_dot] + imported = name[last_dot + 1:] + self.new_imports.append( + importinfo.FromImport(from_, 0, ((imported, None), ))) + + def _is_long(self, name): + return name.count('.') > self.maxdots or \ + ('.' in name and len(name) > self.maxlength) + + +class RemovePyNameVisitor(ImportInfoVisitor): + + def __init__(self, pycore, pymodule, pyname, folder): + self.pymodule = pymodule + self.pyname = pyname + self.context = importinfo.ImportContext(pycore, folder) + + def visitFromImport(self, import_stmt, import_info): + new_pairs = [] + if not import_info.is_star_import(): + for name, alias in import_info.names_and_aliases: + try: + pyname = self.pymodule[alias or name] + if occurrences.same_pyname(self.pyname, pyname): + continue + except exceptions.AttributeNotFoundError: + pass + new_pairs.append((name, alias)) + return importinfo.FromImport( + import_info.module_name, import_info.level, new_pairs) + + def dispatch(self, import_): + result = ImportInfoVisitor.dispatch(self, import_) + if result is not None: + import_.import_info = result + + +def _is_future(info): + return isinstance(info, importinfo.FromImport) and \ + info.module_name == '__future__' diff -r e30544496575 -r 48cacfdc2ca6 vim/sadness/ropevim/src/rope/rope/refactor/importutils/importinfo.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vim/sadness/ropevim/src/rope/rope/refactor/importutils/importinfo.py Wed Oct 06 12:30:46 2010 -0400 @@ -0,0 +1,201 @@ +class ImportStatement(object): + """Represent an import in a module + + `readonly` attribute controls whether this import can be changed + by import actions or not. + + """ + + def __init__(self, import_info, start_line, end_line, + main_statement=None, blank_lines=0): + self.start_line = start_line + self.end_line = end_line + self.readonly = False + self.main_statement = main_statement + self._import_info = None + self.import_info = import_info + self._is_changed = False + self.new_start = None + self.blank_lines = blank_lines + + def _get_import_info(self): + return self._import_info + + def _set_import_info(self, new_import): + if not self.readonly and \ + new_import is not None and not new_import == self._import_info: + self._is_changed = True + self._import_info = new_import + + import_info = property(_get_import_info, _set_import_info) + + def get_import_statement(self): + if self._is_changed or self.main_statement is None: + return self.import_info.get_import_statement() + else: + return self.main_statement + + def empty_import(self): + self.import_info = ImportInfo.get_empty_import() + + def move(self, lineno, blank_lines=0): + self.new_start = lineno + self.blank_lines = blank_lines + + def get_old_location(self): + return self.start_line, self.end_line + + def get_new_start(self): + return self.new_start + + def is_changed(self): + return self._is_changed or (self.new_start is not None or + self.new_start != self.start_line) + + def accept(self, visitor): + return visitor.dispatch(self) + + +class ImportInfo(object): + + def get_imported_primaries(self, context): + pass + + def get_imported_names(self, context): + return [primary.split('.')[0] + for primary in self.get_imported_primaries(context)] + + def get_import_statement(self): + pass + + def is_empty(self): + pass + + def __hash__(self): + return hash(self.get_import_statement()) + + def _are_name_and_alias_lists_equal(self, list1, list2): + if len(list1) != len(list2): + return False + for pair1, pair2 in zip(list1, list2): + if pair1 != pair2: + return False + return True + + def __eq__(self, obj): + return isinstance(obj, self.__class__) and \ + self.get_import_statement() == obj.get_import_statement() + + def __ne__(self, obj): + return not self.__eq__(obj) + + @staticmethod + def get_empty_import(): + return EmptyImport() + + +class NormalImport(ImportInfo): + + def __init__(self, names_and_aliases): + self.names_and_aliases = names_and_aliases + + def get_imported_primaries(self, context): + result = [] + for name, alias in self.names_and_aliases: + if alias: + result.append(alias) + else: + result.append(name) + return result + + def get_import_statement(self): + result = 'import ' + for name, alias in self.names_and_aliases: + result += name + if alias: + result += ' as ' + alias + result += ', ' + return result[:-2] + + def is_empty(self): + return len(self.names_and_aliases) == 0 + + +class FromImport(ImportInfo): + + def __init__(self, module_name, level, names_and_aliases): + self.module_name = module_name + self.level = level + self.names_and_aliases = names_and_aliases + + def get_imported_primaries(self, context): + if self.names_and_aliases[0][0] == '*': + module = self.get_imported_module(context) + return [name for name in module + if not name.startswith('_')] + result = [] + for name, alias in self.names_and_aliases: + if alias: + result.append(alias) + else: + result.append(name) + return result + + def get_imported_resource(self, context): + """Get the imported resource + + Returns `None` if module was not found. + """ + if self.level == 0: + return context.pycore.find_module( + self.module_name, folder=context.folder) + else: + return context.pycore.find_relative_module( + self.module_name, context.folder, self.level) + + def get_imported_module(self, context): + """Get the imported `PyModule` + + Raises `rope.base.exceptions.ModuleNotFoundError` if module + could not be found. + """ + if self.level == 0: + return context.pycore.get_module( + self.module_name, context.folder) + else: + return context.pycore.get_relative_module( + self.module_name, context.folder, self.level) + + def get_import_statement(self): + result = 'from ' + '.' * self.level + self.module_name + ' import ' + for name, alias in self.names_and_aliases: + result += name + if alias: + result += ' as ' + alias + result += ', ' + return result[:-2] + + def is_empty(self): + return len(self.names_and_aliases) == 0 + + def is_star_import(self): + return len(self.names_and_aliases) > 0 and \ + self.names_and_aliases[0][0] == '*' + + +class EmptyImport(ImportInfo): + + names_and_aliases = [] + + def is_empty(self): + return True + + def get_imported_primaries(self, context): + return [] + + +class ImportContext(object): + + def __init__(self, pycore, folder): + self.pycore = pycore + self.folder = folder diff -r e30544496575 -r 48cacfdc2ca6 vim/sadness/ropevim/src/rope/rope/refactor/importutils/module_imports.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vim/sadness/ropevim/src/rope/rope/refactor/importutils/module_imports.py Wed Oct 06 12:30:46 2010 -0400 @@ -0,0 +1,454 @@ +import rope.base.pynames +from rope.base import ast, utils +from rope.refactor.importutils import importinfo +from rope.refactor.importutils import actions + + +class ModuleImports(object): + + def __init__(self, pycore, pymodule, import_filter=None): + self.pycore = pycore + self.pymodule = pymodule + self.separating_lines = 0 + self.filter = import_filter + + @property + @utils.saveit + def imports(self): + finder = _GlobalImportFinder(self.pymodule, self.pycore) + result = finder.find_import_statements() + self.separating_lines = finder.get_separating_line_count() + if self.filter is not None: + for import_stmt in result: + if not self.filter(import_stmt): + import_stmt.readonly = True + return result + + def _get_unbound_names(self, defined_pyobject): + visitor = _GlobalUnboundNameFinder(self.pymodule, defined_pyobject) + ast.walk(self.pymodule.get_ast(), visitor) + return visitor.unbound + + def remove_unused_imports(self): + can_select = _OneTimeSelector(self._get_unbound_names(self.pymodule)) + visitor = actions.RemovingVisitor( + self.pycore, self._current_folder(), can_select) + for import_statement in self.imports: + import_statement.accept(visitor) + + def get_used_imports(self, defined_pyobject): + result = [] + can_select = _OneTimeSelector(self._get_unbound_names(defined_pyobject)) + visitor = actions.FilteringVisitor( + self.pycore, self._current_folder(), can_select) + for import_statement in self.imports: + new_import = import_statement.accept(visitor) + if new_import is not None and not new_import.is_empty(): + result.append(new_import) + return result + + def get_changed_source(self): + imports = self.imports + after_removing = self._remove_imports(imports) + imports = [stmt for stmt in imports + if not stmt.import_info.is_empty()] + + first_non_blank = self._first_non_blank_line(after_removing, 0) + first_import = self._first_import_line() - 1 + result = [] + # Writing module docs + result.extend(after_removing[first_non_blank:first_import]) + # Writing imports + sorted_imports = sorted(imports, self._compare_import_locations) + for stmt in sorted_imports: + start = self._get_import_location(stmt) + if stmt != sorted_imports[0]: + result.append('\n' * stmt.blank_lines) + result.append(stmt.get_import_statement() + '\n') + if sorted_imports and first_non_blank < len(after_removing): + result.append('\n' * self.separating_lines) + + # Writing the body + first_after_imports = self._first_non_blank_line(after_removing, + first_import) + result.extend(after_removing[first_after_imports:]) + return ''.join(result) + + def _get_import_location(self, stmt): + start = stmt.get_new_start() + if start is None: + start = stmt.get_old_location()[0] + return start + + def _compare_import_locations(self, stmt1, stmt2): + def get_location(stmt): + if stmt.get_new_start() is not None: + return stmt.get_new_start() + else: + return stmt.get_old_location()[0] + return cmp(get_location(stmt1), get_location(stmt2)) + + def _remove_imports(self, imports): + lines = self.pymodule.source_code.splitlines(True) + after_removing = [] + last_index = 0 + for stmt in imports: + start, end = stmt.get_old_location() + after_removing.extend(lines[last_index:start - 1]) + last_index = end - 1 + for i in range(start, end): + after_removing.append('') + after_removing.extend(lines[last_index:]) + return after_removing + + def _first_non_blank_line(self, lines, lineno): + result = lineno + for line in lines[lineno:]: + if line.strip() == '': + result += 1 + else: + break + return result + + def add_import(self, import_info): + visitor = actions.AddingVisitor(self.pycore, [import_info]) + for import_statement in self.imports: + if import_statement.accept(visitor): + break + else: + lineno = self._get_new_import_lineno() + blanks = self._get_new_import_blanks() + self.imports.append(importinfo.ImportStatement( + import_info, lineno, lineno, + blank_lines=blanks)) + + def _get_new_import_blanks(self): + return 0 + + def _get_new_import_lineno(self): + if self.imports: + return self.imports[-1].end_line + return 1 + + def filter_names(self, can_select): + visitor = actions.RemovingVisitor( + self.pycore, self._current_folder(), can_select) + for import_statement in self.imports: + import_statement.accept(visitor) + + def expand_stars(self): + can_select = _OneTimeSelector(self._get_unbound_names(self.pymodule)) + visitor = actions.ExpandStarsVisitor( + self.pycore, self._current_folder(), can_select) + for import_statement in self.imports: + import_statement.accept(visitor) + + def remove_duplicates(self): + added_imports = [] + for import_stmt in self.imports: + visitor = actions.AddingVisitor(self.pycore, + [import_stmt.import_info]) + for added_import in added_imports: + if added_import.accept(visitor): + import_stmt.empty_import() + else: + added_imports.append(import_stmt) + + def get_relative_to_absolute_list(self): + visitor = rope.refactor.importutils.actions.RelativeToAbsoluteVisitor( + self.pycore, self._current_folder()) + for import_stmt in self.imports: + if not import_stmt.readonly: + import_stmt.accept(visitor) + return visitor.to_be_absolute + + def get_self_import_fix_and_rename_list(self): + visitor = rope.refactor.importutils.actions.SelfImportVisitor( + self.pycore, self._current_folder(), self.pymodule.get_resource()) + for import_stmt in self.imports: + if not import_stmt.readonly: + import_stmt.accept(visitor) + return visitor.to_be_fixed, visitor.to_be_renamed + + def _current_folder(self): + return self.pymodule.get_resource().parent + + def sort_imports(self): + # IDEA: Sort from import list + visitor = actions.SortingVisitor(self.pycore, self._current_folder()) + for import_statement in self.imports: + import_statement.accept(visitor) + in_projects = sorted(visitor.in_project, self._compare_imports) + third_party = sorted(visitor.third_party, self._compare_imports) + standards = sorted(visitor.standard, self._compare_imports) + future = sorted(visitor.future, self._compare_imports) + blank_lines = 0 + last_index = self._first_import_line() + last_index = self._move_imports(future, last_index, 0) + last_index = self._move_imports(standards, last_index, 1) + last_index = self._move_imports(third_party, last_index, 1) + last_index = self._move_imports(in_projects, last_index, 1) + self.separating_lines = 2 + + def _first_import_line(self): + nodes = self.pymodule.get_ast().body + lineno = 0 + if self.pymodule.get_doc() is not None: + lineno = 1 + if len(nodes) > lineno: + lineno = self.pymodule.logical_lines.logical_line_in( + nodes[lineno].lineno)[0] + else: + lineno = self.pymodule.lines.length() + while lineno > 1: + line = self.pymodule.lines.get_line(lineno - 1) + if line.strip() == '': + lineno -= 1 + else: + break + return lineno + + def _compare_imports(self, stmt1, stmt2): + str1 = stmt1.get_import_statement() + str2 = stmt2.get_import_statement() + if str1.startswith('from ') and not str2.startswith('from '): + return 1 + if not str1.startswith('from ') and str2.startswith('from '): + return -1 + return cmp(str1, str2) + + def _move_imports(self, imports, index, blank_lines): + if imports: + imports[0].move(index, blank_lines) + index += 1 + if len(imports) > 1: + for stmt in imports[1:]: + stmt.move(index) + index += 1 + return index + + def handle_long_imports(self, maxdots, maxlength): + visitor = actions.LongImportVisitor( + self._current_folder(), self.pycore, maxdots, maxlength) + for import_statement in self.imports: + if not import_statement.readonly: + import_statement.accept(visitor) + for import_info in visitor.new_imports: + self.add_import(import_info) + return visitor.to_be_renamed + + def remove_pyname(self, pyname): + """Removes pyname when imported in ``from mod import x``""" + visitor = actions.RemovePyNameVisitor(self.pycore, self.pymodule, + pyname, self._current_folder()) + for import_stmt in self.imports: + import_stmt.accept(visitor) + + +class _OneTimeSelector(object): + + def __init__(self, names): + self.names = names + self.selected_names = set() + + def __call__(self, imported_primary): + if self._can_name_be_added(imported_primary): + for name in self._get_dotted_tokens(imported_primary): + self.selected_names.add(name) + return True + return False + + def _get_dotted_tokens(self, imported_primary): + tokens = imported_primary.split('.') + for i in range(len(tokens)): + yield '.'.join(tokens[:i + 1]) + + def _can_name_be_added(self, imported_primary): + for name in self._get_dotted_tokens(imported_primary): + if name in self.names and name not in self.selected_names: + return True + return False + + +class _UnboundNameFinder(object): + + def __init__(self, pyobject): + self.pyobject = pyobject + + def _visit_child_scope(self, node): + pyobject = self.pyobject.get_module().get_scope().\ + get_inner_scope_for_line(node.lineno).pyobject + visitor = _LocalUnboundNameFinder(pyobject, self) + for child in ast.get_child_nodes(node): + ast.walk(child, visitor) + + def _FunctionDef(self, node): + self._visit_child_scope(node) + + def _ClassDef(self, node): + self._visit_child_scope(node) + + def _Name(self, node): + if self._get_root()._is_node_interesting(node) and \ + not self.is_bound(node.id): + self.add_unbound(node.id) + + def _Attribute(self, node): + result = [] + while isinstance(node, ast.Attribute): + result.append(node.attr) + node = node.value + if isinstance(node, ast.Name): + result.append(node.id) + primary = '.'.join(reversed(result)) + if self._get_root()._is_node_interesting(node) and \ + not self.is_bound(primary): + self.add_unbound(primary) + else: + ast.walk(node, self) + + def _get_root(self): + pass + + def is_bound(self, name, propagated=False): + pass + + def add_unbound(self, name): + pass + + +class _GlobalUnboundNameFinder(_UnboundNameFinder): + + def __init__(self, pymodule, wanted_pyobject): + super(_GlobalUnboundNameFinder, self).__init__(pymodule) + self.unbound = set() + self.names = set() + for name, pyname in pymodule._get_structural_attributes().items(): + if not isinstance(pyname, (rope.base.pynames.ImportedName, + rope.base.pynames.ImportedModule)): + self.names.add(name) + wanted_scope = wanted_pyobject.get_scope() + self.start = wanted_scope.get_start() + self.end = wanted_scope.get_end() + 1 + + def _get_root(self): + return self + + def is_bound(self, primary, propagated=False): + name = primary.split('.')[0] + if name in self.names: + return True + return False + + def add_unbound(self, name): + names = name.split('.') + for i in range(len(names)): + self.unbound.add('.'.join(names[:i + 1])) + + def _is_node_interesting(self, node): + return self.start <= node.lineno < self.end + + +class _LocalUnboundNameFinder(_UnboundNameFinder): + + def __init__(self, pyobject, parent): + super(_LocalUnboundNameFinder, self).__init__(pyobject) + self.parent = parent + + def _get_root(self): + return self.parent._get_root() + + def is_bound(self, primary, propagated=False): + name = primary.split('.')[0] + if propagated: + names = self.pyobject.get_scope().get_propagated_names() + else: + names = self.pyobject.get_scope().get_names() + if name in names or self.parent.is_bound(name, propagated=True): + return True + return False + + def add_unbound(self, name): + self.parent.add_unbound(name) + + +class _GlobalImportFinder(object): + + def __init__(self, pymodule, pycore): + self.current_folder = None + if pymodule.get_resource(): + self.current_folder = pymodule.get_resource().parent + self.pymodule = pymodule + self.pycore = pycore + self.imports = [] + self.pymodule = pymodule + self.lines = self.pymodule.lines + + def visit_import(self, node, end_line): + start_line = node.lineno + import_statement = importinfo.ImportStatement( + importinfo.NormalImport(self._get_names(node.names)), + start_line, end_line, self._get_text(start_line, end_line), + blank_lines=self._count_empty_lines_before(start_line)) + self.imports.append(import_statement) + + def _count_empty_lines_before(self, lineno): + result = 0 + for current in range(lineno - 1, 0, -1): + line = self.lines.get_line(current) + if line.strip() == '': + result += 1 + else: + break + return result + + def _count_empty_lines_after(self, lineno): + result = 0 + for current in range(lineno + 1, self.lines.length()): + line = self.lines.get_line(current) + if line.strip() == '': + result += 1 + else: + break + return result + + def get_separating_line_count(self): + if not self.imports: + return 0 + return self._count_empty_lines_after(self.imports[-1].end_line - 1) + + def _get_text(self, start_line, end_line): + result = [] + for index in range(start_line, end_line): + result.append(self.lines.get_line(index)) + return '\n'.join(result) + + def visit_from(self, node, end_line): + level = 0 + if node.level: + level = node.level + import_info = importinfo.FromImport( + node.module, level, self._get_names(node.names)) + start_line = node.lineno + self.imports.append(importinfo.ImportStatement( + import_info, node.lineno, end_line, + self._get_text(start_line, end_line), + blank_lines=self._count_empty_lines_before(start_line))) + + def _get_names(self, alias_names): + result = [] + for alias in alias_names: + result.append((alias.name, alias.asname)) + return result + + def find_import_statements(self): + nodes = self.pymodule.get_ast().body + for index, node in enumerate(nodes): + if isinstance(node, (ast.Import, ast.ImportFrom)): + lines = self.pymodule.logical_lines + end_line = lines.logical_line_in(node.lineno)[1] + 1 + if isinstance(node, ast.Import): + self.visit_import(node, end_line) + if isinstance(node, ast.ImportFrom): + self.visit_from(node, end_line) + return self.imports diff -r e30544496575 -r 48cacfdc2ca6 vim/sadness/ropevim/src/rope/rope/refactor/inline.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vim/sadness/ropevim/src/rope/rope/refactor/inline.py Wed Oct 06 12:30:46 2010 -0400 @@ -0,0 +1,615 @@ +# Known Bugs when inlining a function/method +# The values passed to function are inlined using _inlined_variable. +# This may cause two problems, illustrated in the examples below +# +# def foo(var1): +# var1 = var1*10 +# return var1 +# +# If a call to foo(20) is inlined, the result of inlined function is 20, +# but it should be 200. +# +# def foo(var1): +# var2 = var1*10 +# return var2 +# +# 2- If a call to foo(10+10) is inlined the result of inlined function is 110 +# but it should be 200. + +import re + +import rope.base.exceptions +import rope.refactor.functionutils +from rope.base import (pynames, pyobjects, codeanalyze, + taskhandle, evaluate, worder, utils) +from rope.base.change import ChangeSet, ChangeContents +from rope.refactor import (occurrences, rename, sourceutils, + importutils, move, change_signature) + +def unique_prefix(): + n = 0 + while True: + yield "__" + str(n) + "__" + n += 1 + +def create_inline(project, resource, offset): + """Create a refactoring object for inlining + + Based on `resource` and `offset` it returns an instance of + `InlineMethod`, `InlineVariable` or `InlineParameter`. + + """ + pycore = project.pycore + pyname = _get_pyname(pycore, resource, offset) + message = 'Inline refactoring should be performed on ' \ + 'a method, local variable or parameter.' + if pyname is None: + raise rope.base.exceptions.RefactoringError(message) + if isinstance(pyname, pynames.ImportedName): + pyname = pyname._get_imported_pyname() + if isinstance(pyname, pynames.AssignedName): + return InlineVariable(project, resource, offset) + if isinstance(pyname, pynames.ParameterName): + return InlineParameter(project, resource, offset) + if isinstance(pyname.get_object(), pyobjects.PyFunction): + return InlineMethod(project, resource, offset) + else: + raise rope.base.exceptions.RefactoringError(message) + + +class _Inliner(object): + + def __init__(self, project, resource, offset): + self.project = project + self.pycore = project.pycore + self.pyname = _get_pyname(self.pycore, resource, offset) + range_finder = worder.Worder(resource.read()) + self.region = range_finder.get_primary_range(offset) + self.name = range_finder.get_word_at(offset) + self.offset = offset + self.original = resource + + def get_changes(self, *args, **kwds): + pass + + def get_kind(self): + """Return either 'variable', 'method' or 'parameter'""" + + +class InlineMethod(_Inliner): + + def __init__(self, *args, **kwds): + super(InlineMethod, self).__init__(*args, **kwds) + self.pyfunction = self.pyname.get_object() + self.pymodule = self.pyfunction.get_module() + self.resource = self.pyfunction.get_module().get_resource() + self.occurrence_finder = occurrences.create_finder( + self.pycore, self.name, self.pyname) + self.normal_generator = _DefinitionGenerator(self.project, + self.pyfunction) + self._init_imports() + + def _init_imports(self): + body = sourceutils.get_body(self.pyfunction) + body, imports = move.moving_code_with_imports( + self.pycore, self.resource, body) + self.imports = imports + self.others_generator = _DefinitionGenerator( + self.project, self.pyfunction, body=body) + + def _get_scope_range(self): + scope = self.pyfunction.get_scope() + lines = self.pymodule.lines + logicals = self.pymodule.logical_lines + start_line = scope.get_start() + if self.pyfunction.decorators: + decorators = self.pyfunction.decorators + if hasattr(decorators[0], 'lineno'): + start_line = decorators[0].lineno + start_offset = lines.get_line_start(start_line) + end_offset = min(lines.get_line_end(scope.end) + 1, + len(self.pymodule.source_code)) + return (start_offset, end_offset) + + def get_changes(self, remove=True, only_current=False, resources=None, + task_handle=taskhandle.NullTaskHandle()): + """Get the changes this refactoring makes + + If `remove` is `False` the definition will not be removed. If + `only_current` is `True`, the the current occurrence will be + inlined, only. + """ + changes = ChangeSet('Inline method <%s>' % self.name) + if resources is None: + resources = self.pycore.get_python_files() + if only_current: + resources = [self.original] + if remove: + resources.append(self.resource) + job_set = task_handle.create_jobset('Collecting Changes', + len(resources)) + for file in resources: + job_set.started_job(file.path) + if file == self.resource: + changes.add_change(self._defining_file_changes( + changes, remove=remove, only_current=only_current)) + else: + aim = None + if only_current and self.original == file: + aim = self.offset + handle = _InlineFunctionCallsForModuleHandle( + self.pycore, file, self.others_generator, aim) + result = move.ModuleSkipRenamer( + self.occurrence_finder, file, handle).get_changed_module() + if result is not None: + result = _add_imports(self.pycore, result, + file, self.imports) + if remove: + result = _remove_from(self.pycore, self.pyname, + result, file) + changes.add_change(ChangeContents(file, result)) + job_set.finished_job() + return changes + + def _get_removed_range(self): + scope = self.pyfunction.get_scope() + lines = self.pymodule.lines + logical = self.pymodule.logical_lines + start_line = scope.get_start() + start, end = self._get_scope_range() + end_line = scope.get_end() + for i in range(end_line + 1, lines.length()): + if lines.get_line(i).strip() == '': + end_line = i + else: + break + end = min(lines.get_line_end(end_line) + 1, + len(self.pymodule.source_code)) + return (start, end) + + def _defining_file_changes(self, changes, remove, only_current): + start_offset, end_offset = self._get_removed_range() + aim = None + if only_current: + if self.resource == self.original: + aim = self.offset + else: + # we don't want to change any of them + aim = len(self.resource.read()) + 100 + handle = _InlineFunctionCallsForModuleHandle( + self.pycore, self.resource, + self.normal_generator, aim_offset=aim) + replacement = None + if remove: + replacement = self._get_method_replacement() + result = move.ModuleSkipRenamer( + self.occurrence_finder, self.resource, handle, start_offset, + end_offset, replacement).get_changed_module() + return ChangeContents(self.resource, result) + + def _get_method_replacement(self): + if self._is_the_last_method_of_a_class(): + indents = sourceutils.get_indents( + self.pymodule.lines, self.pyfunction.get_scope().get_start()) + return ' ' * indents + 'pass\n' + return '' + + def _is_the_last_method_of_a_class(self): + pyclass = self.pyfunction.parent + if not isinstance(pyclass, pyobjects.PyClass): + return False + class_start, class_end = sourceutils.get_body_region(pyclass) + source = self.pymodule.source_code + lines = self.pymodule.lines + func_start, func_end = self._get_scope_range() + if source[class_start:func_start].strip() == '' and \ + source[func_end:class_end].strip() == '': + return True + return False + + def get_kind(self): + return 'method' + + +class InlineVariable(_Inliner): + + def __init__(self, *args, **kwds): + super(InlineVariable, self).__init__(*args, **kwds) + self.pymodule = self.pyname.get_definition_location()[0] + self.resource = self.pymodule.get_resource() + self._check_exceptional_conditions() + self._init_imports() + + def _check_exceptional_conditions(self): + if len(self.pyname.assignments) != 1: + raise rope.base.exceptions.RefactoringError( + 'Local variable should be assigned once for inlining.') + + def get_changes(self, remove=True, only_current=False, resources=None, + task_handle=taskhandle.NullTaskHandle()): + if resources is None: + if rename._is_local(self.pyname): + resources = [self.resource] + else: + resources = self.pycore.get_python_files() + if only_current: + resources = [self.original] + if remove and self.original != self.resource: + resources.append(self.resource) + changes = ChangeSet('Inline variable <%s>' % self.name) + jobset = task_handle.create_jobset('Calculating changes', + len(resources)) + + for resource in resources: + jobset.started_job(resource.path) + if resource == self.resource: + source = self._change_main_module(remove, only_current) + changes.add_change(ChangeContents(self.resource, source)) + else: + result = self._change_module(resource, remove, only_current) + if result is not None: + result = _add_imports(self.pycore, result, + resource, self.imports) + changes.add_change(ChangeContents(resource, result)) + jobset.finished_job() + return changes + + def _change_main_module(self, remove, only_current): + region = None + if only_current and self.original == self.resource: + region = self.region + return _inline_variable(self.pycore, self.pymodule, self.pyname, + self.name, remove=remove, region=region) + + def _init_imports(self): + vardef = _getvardef(self.pymodule, self.pyname) + self.imported, self.imports = move.moving_code_with_imports( + self.pycore, self.resource, vardef) + + def _change_module(self, resource, remove, only_current): + filters = [occurrences.NoImportsFilter(), + occurrences.PyNameFilter(self.pyname)] + if only_current and resource == self.original: + def check_aim(occurrence): + start, end = occurrence.get_primary_range() + if self.offset < start or end < self.offset: + return False + filters.insert(0, check_aim) + finder = occurrences.Finder(self.pycore, self.name, filters=filters) + changed = rename.rename_in_module( + finder, self.imported, resource=resource, replace_primary=True) + if changed and remove: + changed = _remove_from(self.pycore, self.pyname, changed, resource) + return changed + + def get_kind(self): + return 'variable' + + +class InlineParameter(_Inliner): + + def __init__(self, *args, **kwds): + super(InlineParameter, self).__init__(*args, **kwds) + resource, offset = self._function_location() + index = self.pyname.index + self.changers = [change_signature.ArgumentDefaultInliner(index)] + self.signature = change_signature.ChangeSignature(self.project, + resource, offset) + + def _function_location(self): + pymodule, lineno = self.pyname.get_definition_location() + resource = pymodule.get_resource() + start = pymodule.lines.get_line_start(lineno) + word_finder = worder.Worder(pymodule.source_code) + offset = word_finder.find_function_offset(start) + return resource, offset + + def get_changes(self, **kwds): + """Get the changes needed by this refactoring + + See `rope.refactor.change_signature.ChangeSignature.get_changes()` + for arguments. + """ + return self.signature.get_changes(self.changers, **kwds) + + def get_kind(self): + return 'parameter' + + +def _join_lines(lines): + definition_lines = [] + for unchanged_line in lines: + line = unchanged_line.strip() + if line.endswith('\\'): + line = line[:-1].strip() + definition_lines.append(line) + joined = ' '.join(definition_lines) + return joined + + +class _DefinitionGenerator(object): + unique_prefix = unique_prefix() + def __init__(self, project, pyfunction, body=None): + self.pycore = project.pycore + self.pyfunction = pyfunction + self.pymodule = pyfunction.get_module() + self.resource = self.pymodule.get_resource() + self.definition_info = self._get_definition_info() + self.definition_params = self._get_definition_params() + self._calculated_definitions = {} + if body is not None: + self.body = body + else: + self.body = sourceutils.get_body(self.pyfunction) + + def _get_definition_info(self): + return rope.refactor.functionutils.DefinitionInfo.read(self.pyfunction) + + def _get_definition_params(self): + definition_info = self.definition_info + paramdict = dict([pair for pair in definition_info.args_with_defaults]) + if definition_info.args_arg is not None or \ + definition_info.keywords_arg is not None: + raise rope.base.exceptions.RefactoringError( + 'Cannot inline functions with list and keyword arguements.') + if self.pyfunction.get_kind() == 'classmethod': + paramdict[definition_info.args_with_defaults[0][0]] = \ + self.pyfunction.parent.get_name() + return paramdict + + def get_function_name(self): + return self.pyfunction.get_name() + + def get_definition(self, primary, pyname, call, host_vars=[],returns=False): + # caching already calculated definitions + return self._calculate_definition(primary, pyname, call, + host_vars, returns) + + def _calculate_header(self, primary, pyname, call): + # A header is created which initializes parameters + # to the values passed to the function. + call_info = rope.refactor.functionutils.CallInfo.read( + primary, pyname, self.definition_info, call) + paramdict = self.definition_params + mapping = rope.refactor.functionutils.ArgumentMapping( + self.definition_info, call_info) + for param_name, value in mapping.param_dict.items(): + paramdict[param_name] = value + header = '' + to_be_inlined = [] + mod = self.pycore.get_string_module(self.body) + all_names = mod.get_scope().get_names() + assigned_names = [name for name in all_names if + isinstance(all_names[name], rope.base.pynamesdef.AssignedName)] + for name, value in paramdict.items(): + if name != value and value is not None: + header += name + ' = ' + value.replace('\n', ' ') + '\n' + to_be_inlined.append(name) + return header, to_be_inlined + + def _calculate_definition(self, primary, pyname, call, host_vars, returns): + + header, to_be_inlined = self._calculate_header(primary, pyname, call) + + source = header + self.body + mod = self.pycore.get_string_module(source) + name_dict = mod.get_scope().get_names() + all_names = [x for x in name_dict if + not isinstance(name_dict[x], rope.base.builtins.BuiltinName)] + + # If there is a name conflict, all variable names + # inside the inlined function are renamed + if len(set(all_names).intersection(set(host_vars))) > 0: + + prefix = _DefinitionGenerator.unique_prefix.next() + guest = self.pycore.get_string_module(source, self.resource) + + to_be_inlined = [prefix+item for item in to_be_inlined] + for item in all_names: + pyname = guest[item] + occurrence_finder = occurrences.create_finder( + self.pycore, item, pyname) + source = rename.rename_in_module(occurrence_finder, + prefix+item, pymodule=guest) + guest = self.pycore.get_string_module(source, self.resource) + + #parameters not reassigned inside the functions are now inlined. + for name in to_be_inlined: + pymodule = self.pycore.get_string_module(source, self.resource) + pyname = pymodule[name] + source = _inline_variable(self.pycore, pymodule, pyname, name) + + return self._replace_returns_with(source, returns) + + def _replace_returns_with(self, source, returns): + result = [] + returned = None + last_changed = 0 + for match in _DefinitionGenerator._get_return_pattern().finditer(source): + for key, value in match.groupdict().items(): + if value and key == 'return': + result.append(source[last_changed:match.start('return')]) + if returns: + self._check_nothing_after_return(source, + match.end('return')) + returned = _join_lines( + source[match.end('return'): len(source)].splitlines()) + last_changed = len(source) + else: + current = match.end('return') + while current < len(source) and source[current] in ' \t': + current += 1 + last_changed = current + if current == len(source) or source[current] == '\n': + result.append('pass') + result.append(source[last_changed:]) + return ''.join(result), returned + + def _check_nothing_after_return(self, source, offset): + lines = codeanalyze.SourceLinesAdapter(source) + lineno = lines.get_line_number(offset) + logical_lines = codeanalyze.LogicalLineFinder(lines) + lineno = logical_lines.logical_line_in(lineno)[1] + if source[lines.get_line_end(lineno):len(source)].strip() != '': + raise rope.base.exceptions.RefactoringError( + 'Cannot inline functions with statements after return statement.') + + @classmethod + def _get_return_pattern(cls): + if not hasattr(cls, '_return_pattern'): + def named_pattern(name, list_): + return "(?P<%s>" % name + "|".join(list_) + ")" + comment_pattern = named_pattern('comment', [r'#[^\n]*']) + string_pattern = named_pattern('string', + [codeanalyze.get_string_pattern()]) + return_pattern = r'\b(?Preturn)\b' + cls._return_pattern = re.compile(comment_pattern + "|" + + string_pattern + "|" + + return_pattern) + return cls._return_pattern + + +class _InlineFunctionCallsForModuleHandle(object): + + def __init__(self, pycore, resource, + definition_generator, aim_offset=None): + """Inlines occurrences + + If `aim` is not `None` only the occurrences that intersect + `aim` offset will be inlined. + + """ + self.pycore = pycore + self.generator = definition_generator + self.resource = resource + self.aim = aim_offset + + def occurred_inside_skip(self, change_collector, occurrence): + if not occurrence.is_defined(): + raise rope.base.exceptions.RefactoringError( + 'Cannot inline functions that reference themselves') + + def occurred_outside_skip(self, change_collector, occurrence): + start, end = occurrence.get_primary_range() + # we remove out of date imports later + if occurrence.is_in_import_statement(): + return + # the function is referenced outside an import statement + if not occurrence.is_called(): + raise rope.base.exceptions.RefactoringError( + 'Reference to inlining function other than function call' + ' in ' % (self.resource.path, start)) + if self.aim is not None and (self.aim < start or self.aim > end): + return + end_parens = self._find_end_parens(self.source, end - 1) + lineno = self.lines.get_line_number(start) + start_line, end_line = self.pymodule.logical_lines.\ + logical_line_in(lineno) + line_start = self.lines.get_line_start(start_line) + line_end = self.lines.get_line_end(end_line) + + + returns = self.source[line_start:start].strip() != '' or \ + self.source[end_parens:line_end].strip() != '' + indents = sourceutils.get_indents(self.lines, start_line) + primary, pyname = occurrence.get_primary_and_pyname() + + host = self.pycore.resource_to_pyobject(self.resource) + scope = host.scope.get_inner_scope_for_line(lineno) + definition, returned = self.generator.get_definition( + primary, pyname, self.source[start:end_parens], scope.get_names(), returns=returns) + + end = min(line_end + 1, len(self.source)) + change_collector.add_change(line_start, end, + sourceutils.fix_indentation(definition, indents)) + if returns: + name = returned + if name is None: + name = 'None' + change_collector.add_change( + line_end, end, self.source[line_start:start] + name + + self.source[end_parens:end]) + + def _find_end_parens(self, source, offset): + finder = worder.Worder(source) + return finder.get_word_parens_range(offset)[1] + + @property + @utils.saveit + def pymodule(self): + return self.pycore.resource_to_pyobject(self.resource) + + @property + @utils.saveit + def source(self): + if self.resource is not None: + return self.resource.read() + else: + return self.pymodule.source_code + + @property + @utils.saveit + def lines(self): + return self.pymodule.lines + + +def _inline_variable(pycore, pymodule, pyname, name, + remove=True, region=None): + definition = _getvardef(pymodule, pyname) + start, end = _assigned_lineno(pymodule, pyname) + + occurrence_finder = occurrences.create_finder(pycore, name, pyname) + changed_source = rename.rename_in_module( + occurrence_finder, definition, pymodule=pymodule, + replace_primary=True, writes=False, region=region) + if changed_source is None: + changed_source = pymodule.source_code + if remove: + lines = codeanalyze.SourceLinesAdapter(changed_source) + source = changed_source[:lines.get_line_start(start)] + \ + changed_source[lines.get_line_end(end) + 1:] + else: + source = changed_source + return source + +def _getvardef(pymodule, pyname): + assignment = pyname.assignments[0] + lines = pymodule.lines + start, end = _assigned_lineno(pymodule, pyname) + definition_with_assignment = _join_lines( + [lines.get_line(n) for n in range(start, end + 1)]) + if assignment.levels: + raise rope.base.exceptions.RefactoringError( + 'Cannot inline tuple assignments.') + definition = definition_with_assignment[definition_with_assignment.\ + index('=') + 1:].strip() + return definition + +def _assigned_lineno(pymodule, pyname): + definition_line = pyname.assignments[0].ast_node.lineno + return pymodule.logical_lines.logical_line_in(definition_line) + +def _add_imports(pycore, source, resource, imports): + if not imports: + return source + pymodule = pycore.get_string_module(source, resource) + module_import = importutils.get_module_imports(pycore, pymodule) + for import_info in imports: + module_import.add_import(import_info) + source = module_import.get_changed_source() + pymodule = pycore.get_string_module(source, resource) + import_tools = importutils.ImportTools(pycore) + return import_tools.organize_imports(pymodule, unused=False, sort=False) + +def _get_pyname(pycore, resource, offset): + pymodule = pycore.resource_to_pyobject(resource) + pyname = evaluate.eval_location(pymodule, offset) + if isinstance(pyname, pynames.ImportedName): + pyname = pyname._get_imported_pyname() + return pyname + +def _remove_from(pycore, pyname, source, resource): + pymodule = pycore.get_string_module(source, resource) + module_import = importutils.get_module_imports(pycore, pymodule) + module_import.remove_pyname(pyname) + return module_import.get_changed_source() diff -r e30544496575 -r 48cacfdc2ca6 vim/sadness/ropevim/src/rope/rope/refactor/introduce_factory.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vim/sadness/ropevim/src/rope/rope/refactor/introduce_factory.py Wed Oct 06 12:30:46 2010 -0400 @@ -0,0 +1,133 @@ +import rope.base.exceptions +import rope.base.pyobjects +from rope.base import taskhandle, evaluate +from rope.base.change import (ChangeSet, ChangeContents) +from rope.refactor import rename, occurrences, sourceutils, importutils + + +class IntroduceFactory(object): + + def __init__(self, project, resource, offset): + self.pycore = project.pycore + self.offset = offset + + this_pymodule = self.pycore.resource_to_pyobject(resource) + self.old_pyname = evaluate.eval_location(this_pymodule, offset) + if self.old_pyname is None or not isinstance(self.old_pyname.get_object(), + rope.base.pyobjects.PyClass): + raise rope.base.exceptions.RefactoringError( + 'Introduce factory should be performed on a class.') + self.old_name = self.old_pyname.get_object().get_name() + self.pymodule = self.old_pyname.get_object().get_module() + self.resource = self.pymodule.get_resource() + + def get_changes(self, factory_name, global_factory=False, resources=None, + task_handle=taskhandle.NullTaskHandle()): + """Get the changes this refactoring makes + + `factory_name` indicates the name of the factory function to + be added. If `global_factory` is `True` the factory will be + global otherwise a static method is added to the class. + + `resources` can be a list of `rope.base.resource.File`\s that + this refactoring should be applied on; if `None` all python + files in the project are searched. + + """ + if resources is None: + resources = self.pycore.get_python_files() + changes = ChangeSet('Introduce factory method <%s>' % factory_name) + job_set = task_handle.create_jobset('Collecting Changes', + len(resources)) + self._change_module(resources, changes, factory_name, + global_factory, job_set) + return changes + + def get_name(self): + """Return the name of the class""" + return self.old_name + + def _change_module(self, resources, changes, + factory_name, global_, job_set): + if global_: + replacement = '__rope_factory_%s_' % factory_name + else: + replacement = self._new_function_name(factory_name, global_) + + for file_ in resources: + job_set.started_job(file_.path) + if file_ == self.resource: + self._change_resource(changes, factory_name, global_) + job_set.finished_job() + continue + changed_code = self._rename_occurrences(file_, replacement, + global_) + if changed_code is not None: + if global_: + new_pymodule = self.pycore.get_string_module(changed_code, + self.resource) + modname = self.pycore.modname(self.resource) + changed_code, imported = importutils.add_import( + self.pycore, new_pymodule, modname, factory_name) + changed_code = changed_code.replace(replacement, imported) + changes.add_change(ChangeContents(file_, changed_code)) + job_set.finished_job() + + def _change_resource(self, changes, factory_name, global_): + class_scope = self.old_pyname.get_object().get_scope() + source_code = self._rename_occurrences( + self.resource, self._new_function_name(factory_name, + global_), global_) + if source_code is None: + source_code = self.pymodule.source_code + else: + self.pymodule = self.pycore.get_string_module( + source_code, resource=self.resource) + lines = self.pymodule.lines + start = self._get_insertion_offset(class_scope, lines) + result = source_code[:start] + result += self._get_factory_method(lines, class_scope, + factory_name, global_) + result += source_code[start:] + changes.add_change(ChangeContents(self.resource, result)) + + def _get_insertion_offset(self, class_scope, lines): + start_line = class_scope.get_end() + if class_scope.get_scopes(): + start_line = class_scope.get_scopes()[-1].get_end() + start = lines.get_line_end(start_line) + 1 + return start + + def _get_factory_method(self, lines, class_scope, + factory_name, global_): + unit_indents = ' ' * sourceutils.get_indent(self.pycore) + if global_: + if self._get_scope_indents(lines, class_scope) > 0: + raise rope.base.exceptions.RefactoringError( + 'Cannot make global factory method for nested classes.') + return ('\ndef %s(*args, **kwds):\n%sreturn %s(*args, **kwds)\n' % + (factory_name, unit_indents, self.old_name)) + unindented_factory = \ + ('@staticmethod\ndef %s(*args, **kwds):\n' % factory_name + + '%sreturn %s(*args, **kwds)\n' % (unit_indents, self.old_name)) + indents = self._get_scope_indents(lines, class_scope) + \ + sourceutils.get_indent(self.pycore) + return '\n' + sourceutils.indent_lines(unindented_factory, indents) + + def _get_scope_indents(self, lines, scope): + return sourceutils.get_indents(lines, scope.get_start()) + + def _new_function_name(self, factory_name, global_): + if global_: + return factory_name + else: + return self.old_name + '.' + factory_name + + def _rename_occurrences(self, file_, changed_name, global_factory): + finder = occurrences.create_finder(self.pycore, self.old_name, + self.old_pyname, only_calls=True) + result = rename.rename_in_module(finder, changed_name, resource=file_, + replace_primary=global_factory) + return result + +IntroduceFactoryRefactoring = IntroduceFactory diff -r e30544496575 -r 48cacfdc2ca6 vim/sadness/ropevim/src/rope/rope/refactor/introduce_parameter.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vim/sadness/ropevim/src/rope/rope/refactor/introduce_parameter.py Wed Oct 06 12:30:46 2010 -0400 @@ -0,0 +1,95 @@ +import rope.base.change +from rope.base import exceptions, evaluate, worder, codeanalyze +from rope.refactor import functionutils, sourceutils, occurrences + + +class IntroduceParameter(object): + """Introduce parameter refactoring + + This refactoring adds a new parameter to a function and replaces + references to an expression in it with the new parameter. + + The parameter finding part is different from finding similar + pieces in extract refactorings. In this refactoring parameters + are found based on the object they reference to. For instance + in:: + + class A(object): + var = None + + class B(object): + a = A() + + b = B() + a = b.a + + def f(a): + x = b.a.var + a.var + + using this refactoring on ``a.var`` with ``p`` as the new + parameter name, will result in:: + + def f(p=a.var): + x = p + p + + """ + + def __init__(self, project, resource, offset): + self.pycore = project.pycore + self.resource = resource + self.offset = offset + self.pymodule = self.pycore.resource_to_pyobject(self.resource) + scope = self.pymodule.get_scope().get_inner_scope_for_offset(offset) + if scope.get_kind() != 'Function': + raise exceptions.RefactoringError( + 'Introduce parameter should be performed inside functions') + self.pyfunction = scope.pyobject + self.name, self.pyname = self._get_name_and_pyname() + if self.pyname is None: + raise exceptions.RefactoringError( + 'Cannot find the definition of <%s>' % self.name) + + def _get_primary(self): + word_finder = worder.Worder(self.resource.read()) + return word_finder.get_primary_at(self.offset) + + def _get_name_and_pyname(self): + return (worder.get_name_at(self.resource, self.offset), + evaluate.eval_location(self.pymodule, self.offset)) + + def get_changes(self, new_parameter): + definition_info = functionutils.DefinitionInfo.read(self.pyfunction) + definition_info.args_with_defaults.append((new_parameter, + self._get_primary())) + collector = codeanalyze.ChangeCollector(self.resource.read()) + header_start, header_end = self._get_header_offsets() + body_start, body_end = sourceutils.get_body_region(self.pyfunction) + collector.add_change(header_start, header_end, + definition_info.to_string()) + self._change_function_occurances(collector, body_start, + body_end, new_parameter) + changes = rope.base.change.ChangeSet('Introduce parameter <%s>' % + new_parameter) + change = rope.base.change.ChangeContents(self.resource, + collector.get_changed()) + changes.add_change(change) + return changes + + def _get_header_offsets(self): + lines = self.pymodule.lines + start_line = self.pyfunction.get_scope().get_start() + end_line = self.pymodule.logical_lines.\ + logical_line_in(start_line)[1] + start = lines.get_line_start(start_line) + end = lines.get_line_end(end_line) + start = self.pymodule.source_code.find('def', start) + 4 + end = self.pymodule.source_code.rfind(':', start, end) + return start, end + + def _change_function_occurances(self, collector, function_start, + function_end, new_name): + finder = occurrences.create_finder(self.pycore, self.name, self.pyname) + for occurrence in finder.find_occurrences(resource=self.resource): + start, end = occurrence.get_primary_range() + if function_start <= start < function_end: + collector.add_change(start, end, new_name) diff -r e30544496575 -r 48cacfdc2ca6 vim/sadness/ropevim/src/rope/rope/refactor/localtofield.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vim/sadness/ropevim/src/rope/rope/refactor/localtofield.py Wed Oct 06 12:30:46 2010 -0400 @@ -0,0 +1,50 @@ +from rope.base import pynames, evaluate, exceptions, worder +from rope.refactor.rename import Rename + + +class LocalToField(object): + + def __init__(self, project, resource, offset): + self.project = project + self.pycore = project.pycore + self.resource = resource + self.offset = offset + + def get_changes(self): + name = worder.get_name_at(self.resource, self.offset) + this_pymodule = self.pycore.resource_to_pyobject(self.resource) + pyname = evaluate.eval_location(this_pymodule, self.offset) + if not self._is_a_method_local(pyname): + raise exceptions.RefactoringError( + 'Convert local variable to field should be performed on \n' + 'a local variable of a method.') + + pymodule, lineno = pyname.get_definition_location() + function_scope = pymodule.get_scope().get_inner_scope_for_line(lineno) + # Not checking redefinition + #self._check_redefinition(name, function_scope) + + new_name = self._get_field_name(function_scope.pyobject, name) + changes = Rename(self.project, self.resource, self.offset).\ + get_changes(new_name, resources=[self.resource]) + return changes + + def _check_redefinition(self, name, function_scope): + class_scope = function_scope.parent + if name in class_scope.pyobject: + raise exceptions.RefactoringError( + 'The field %s already exists' % name) + + def _get_field_name(self, pyfunction, name): + self_name = pyfunction.get_param_names()[0] + new_name = self_name + '.' + name + return new_name + + def _is_a_method_local(self, pyname): + pymodule, lineno = pyname.get_definition_location() + holding_scope = pymodule.get_scope().get_inner_scope_for_line(lineno) + parent = holding_scope.parent + return isinstance(pyname, pynames.AssignedName) and \ + pyname in holding_scope.get_names().values() and \ + holding_scope.get_kind() == 'Function' and \ + parent is not None and parent.get_kind() == 'Class' diff -r e30544496575 -r 48cacfdc2ca6 vim/sadness/ropevim/src/rope/rope/refactor/method_object.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vim/sadness/ropevim/src/rope/rope/refactor/method_object.py Wed Oct 06 12:30:46 2010 -0400 @@ -0,0 +1,87 @@ +import warnings + +from rope.base import pyobjects, exceptions, change, evaluate, codeanalyze +from rope.refactor import sourceutils, occurrences, rename + + +class MethodObject(object): + + def __init__(self, project, resource, offset): + self.pycore = project.pycore + this_pymodule = self.pycore.resource_to_pyobject(resource) + pyname = evaluate.eval_location(this_pymodule, offset) + if pyname is None or not isinstance(pyname.get_object(), + pyobjects.PyFunction): + raise exceptions.RefactoringError( + 'Replace method with method object refactoring should be ' + 'performed on a function.') + self.pyfunction = pyname.get_object() + self.pymodule = self.pyfunction.get_module() + self.resource = self.pymodule.get_resource() + + def get_new_class(self, name): + body = sourceutils.fix_indentation( + self._get_body(), sourceutils.get_indent(self.pycore) * 2) + return 'class %s(object):\n\n%s%sdef __call__(self):\n%s' % \ + (name, self._get_init(), + ' ' * sourceutils.get_indent(self.pycore), body) + + def get_changes(self, classname=None, new_class_name=None): + if new_class_name is not None: + warnings.warn( + 'new_class_name parameter is deprecated; use classname', + DeprecationWarning, stacklevel=2) + classname = new_class_name + collector = codeanalyze.ChangeCollector(self.pymodule.source_code) + start, end = sourceutils.get_body_region(self.pyfunction) + indents = sourceutils.get_indents( + self.pymodule.lines, self.pyfunction.get_scope().get_start()) + \ + sourceutils.get_indent(self.pycore) + new_contents = ' ' * indents + 'return %s(%s)()\n' % \ + (classname, ', '.join(self._get_parameter_names())) + collector.add_change(start, end, new_contents) + insertion = self._get_class_insertion_point() + collector.add_change(insertion, insertion, + '\n\n' + self.get_new_class(classname)) + changes = change.ChangeSet('Replace method with method object refactoring') + changes.add_change(change.ChangeContents(self.resource, + collector.get_changed())) + return changes + + def _get_class_insertion_point(self): + current = self.pyfunction + while current.parent != self.pymodule: + current = current.parent + end = self.pymodule.lines.get_line_end(current.get_scope().get_end()) + return min(end + 1, len(self.pymodule.source_code)) + + def _get_body(self): + body = sourceutils.get_body(self.pyfunction) + for param in self._get_parameter_names(): + body = param + ' = None\n' + body + pymod = self.pycore.get_string_module(body, self.resource) + pyname = pymod[param] + finder = occurrences.create_finder(self.pycore, param, pyname) + result = rename.rename_in_module(finder, 'self.' + param, + pymodule=pymod) + body = result[result.index('\n') + 1:] + return body + + def _get_init(self): + params = self._get_parameter_names() + indents = ' ' * sourceutils.get_indent(self.pycore) + if not params: + return '' + header = indents + 'def __init__(self' + body = '' + for arg in params: + new_name = arg + if arg == 'self': + new_name = 'host' + header += ', %s' % new_name + body += indents * 2 + 'self.%s = %s\n' % (arg, new_name) + header += '):' + return '%s\n%s\n' % (header, body) + + def _get_parameter_names(self): + return self.pyfunction.get_param_names() diff -r e30544496575 -r 48cacfdc2ca6 vim/sadness/ropevim/src/rope/rope/refactor/move.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vim/sadness/ropevim/src/rope/rope/refactor/move.py Wed Oct 06 12:30:46 2010 -0400 @@ -0,0 +1,625 @@ +"""A module containing classes for move refactoring + +`create_move()` is a factory for creating move refactoring objects +based on inputs. + +""" +from rope.base import pyobjects, codeanalyze, exceptions, pynames, taskhandle, evaluate, worder +from rope.base.change import ChangeSet, ChangeContents, MoveResource +from rope.refactor import importutils, rename, occurrences, sourceutils, functionutils + + +def create_move(project, resource, offset=None): + """A factory for creating Move objects + + Based on `resource` and `offset`, return one of `MoveModule`, + `MoveGlobal` or `MoveMethod` for performing move refactoring. + + """ + if offset is None: + return MoveModule(project, resource) + this_pymodule = project.pycore.resource_to_pyobject(resource) + pyname = evaluate.eval_location(this_pymodule, offset) + if pyname is None: + raise exceptions.RefactoringError( + 'Move only works on classes, functions, modules and methods.') + pyobject = pyname.get_object() + if isinstance(pyobject, pyobjects.PyModule) or \ + isinstance(pyobject, pyobjects.PyPackage): + return MoveModule(project, pyobject.get_resource()) + if isinstance(pyobject, pyobjects.PyFunction) and \ + isinstance(pyobject.parent, pyobjects.PyClass): + return MoveMethod(project, resource, offset) + if isinstance(pyobject, pyobjects.PyDefinedObject) and \ + isinstance(pyobject.parent, pyobjects.PyModule): + return MoveGlobal(project, resource, offset) + raise exceptions.RefactoringError( + 'Move only works on global classes/functions, modules and methods.') + + +class MoveMethod(object): + """For moving methods + + It makes a new method in the destination class and changes + the body of the old method to call the new method. You can + inline the old method to change all of its occurrences. + + """ + + def __init__(self, project, resource, offset): + self.project = project + self.pycore = project.pycore + this_pymodule = self.pycore.resource_to_pyobject(resource) + pyname = evaluate.eval_location(this_pymodule, offset) + self.method_name = worder.get_name_at(resource, offset) + self.pyfunction = pyname.get_object() + if self.pyfunction.get_kind() != 'method': + raise exceptions.RefactoringError('Only normal methods' + ' can be moved.') + + def get_changes(self, dest_attr, new_name=None, resources=None, + task_handle=taskhandle.NullTaskHandle()): + """Return the changes needed for this refactoring + + Parameters: + + - `dest_attr`: the name of the destination attribute + - `new_name`: the name of the new method; if `None` uses + the old name + - `resources` can be a list of `rope.base.resources.File`\s to + apply this refactoring on. If `None`, the restructuring + will be applied to all python files. + + """ + changes = ChangeSet('Moving method <%s>' % self.method_name) + if resources is None: + resources = self.pycore.get_python_files() + if new_name is None: + new_name = self.get_method_name() + resource1, start1, end1, new_content1 = \ + self._get_changes_made_by_old_class(dest_attr, new_name) + collector1 = codeanalyze.ChangeCollector(resource1.read()) + collector1.add_change(start1, end1, new_content1) + + resource2, start2, end2, new_content2 = \ + self._get_changes_made_by_new_class(dest_attr, new_name) + if resource1 == resource2: + collector1.add_change(start2, end2, new_content2) + else: + collector2 = codeanalyze.ChangeCollector(resource2.read()) + collector2.add_change(start2, end2, new_content2) + result = collector2.get_changed() + import_tools = importutils.ImportTools(self.pycore) + new_imports = self._get_used_imports(import_tools) + if new_imports: + goal_pymodule = self.pycore.get_string_module(result, + resource2) + result = _add_imports_to_module( + import_tools, goal_pymodule, new_imports) + if resource2 in resources: + changes.add_change(ChangeContents(resource2, result)) + + if resource1 in resources: + changes.add_change(ChangeContents(resource1, + collector1.get_changed())) + return changes + + def get_method_name(self): + return self.method_name + + def _get_used_imports(self, import_tools): + return importutils.get_imports(self.pycore, self.pyfunction) + + def _get_changes_made_by_old_class(self, dest_attr, new_name): + pymodule = self.pyfunction.get_module() + indents = self._get_scope_indents(self.pyfunction) + body = 'return self.%s.%s(%s)\n' % (dest_attr, new_name, + self._get_passed_arguments_string()) + region = sourceutils.get_body_region(self.pyfunction) + return (pymodule.get_resource(), region[0], region[1], + sourceutils.fix_indentation(body, indents)) + + def _get_scope_indents(self, pyobject): + pymodule = pyobject.get_module() + return sourceutils.get_indents( + pymodule.lines, pyobject.get_scope().get_start()) + \ + sourceutils.get_indent(self.pycore) + + def _get_changes_made_by_new_class(self, dest_attr, new_name): + old_pyclass = self.pyfunction.parent + if dest_attr not in old_pyclass: + raise exceptions.RefactoringError( + 'Destination attribute <%s> not found' % dest_attr) + pyclass = old_pyclass[dest_attr].get_object().get_type() + if not isinstance(pyclass, pyobjects.PyClass): + raise exceptions.RefactoringError( + 'Unknown class type for attribute <%s>' % dest_attr) + pymodule = pyclass.get_module() + resource = pyclass.get_module().get_resource() + start, end = sourceutils.get_body_region(pyclass) + pre_blanks = '\n' + if pymodule.source_code[start:end].strip() != 'pass': + pre_blanks = '\n\n' + start = end + indents = self._get_scope_indents(pyclass) + body = pre_blanks + sourceutils.fix_indentation( + self.get_new_method(new_name), indents) + return resource, start, end, body + + def get_new_method(self, name): + return '%s\n%s' % ( + self._get_new_header(name), + sourceutils.fix_indentation(self._get_body(), + sourceutils.get_indent(self.pycore))) + + def _get_unchanged_body(self): + return sourceutils.get_body(self.pyfunction) + + def _get_body(self, host='host'): + self_name = self._get_self_name() + body = self_name + ' = None\n' + self._get_unchanged_body() + pymodule = self.pycore.get_string_module(body) + finder = occurrences.create_finder( + self.pycore, self_name, pymodule[self_name]) + result = rename.rename_in_module(finder, host, pymodule=pymodule) + if result is None: + result = body + return result[result.index('\n') + 1:] + + def _get_self_name(self): + return self.pyfunction.get_param_names()[0] + + def _get_new_header(self, name): + header = 'def %s(self' % name + if self._is_host_used(): + header += ', host' + definition_info = functionutils.DefinitionInfo.read(self.pyfunction) + others = definition_info.arguments_to_string(1) + if others: + header += ', ' + others + return header + '):' + + def _get_passed_arguments_string(self): + result = '' + if self._is_host_used(): + result = 'self' + definition_info = functionutils.DefinitionInfo.read(self.pyfunction) + others = definition_info.arguments_to_string(1) + if others: + if result: + result += ', ' + result += others + return result + + def _is_host_used(self): + return self._get_body('__old_self') != self._get_unchanged_body() + + +class MoveGlobal(object): + """For moving global function and classes""" + + def __init__(self, project, resource, offset): + self.pycore = project.pycore + this_pymodule = self.pycore.resource_to_pyobject(resource) + self.old_pyname = evaluate.eval_location(this_pymodule, offset) + self.old_name = self.old_pyname.get_object().get_name() + pymodule = self.old_pyname.get_object().get_module() + self.source = pymodule.get_resource() + self.tools = _MoveTools(self.pycore, self.source, + self.old_pyname, self.old_name) + self.import_tools = self.tools.import_tools + self._check_exceptional_conditions() + + def _check_exceptional_conditions(self): + if self.old_pyname is None or \ + not isinstance(self.old_pyname.get_object(), pyobjects.PyDefinedObject): + raise exceptions.RefactoringError( + 'Move refactoring should be performed on a class/function.') + moving_pyobject = self.old_pyname.get_object() + if not self._is_global(moving_pyobject): + raise exceptions.RefactoringError( + 'Move refactoring should be performed on a global class/function.') + + def _is_global(self, pyobject): + return pyobject.get_scope().parent == pyobject.get_module().get_scope() + + def get_changes(self, dest, resources=None, + task_handle=taskhandle.NullTaskHandle()): + if resources is None: + resources = self.pycore.get_python_files() + if dest is None or not dest.exists(): + raise exceptions.RefactoringError( + 'Move destination does not exist.') + if dest.is_folder() and dest.has_child('__init__.py'): + dest = dest.get_child('__init__.py') + if dest.is_folder(): + raise exceptions.RefactoringError( + 'Move destination for non-modules should not be folders.') + if self.source == dest: + raise exceptions.RefactoringError( + 'Moving global elements to the same module.') + return self._calculate_changes(dest, resources, task_handle) + + def _calculate_changes(self, dest, resources, task_handle): + changes = ChangeSet('Moving global <%s>' % self.old_name) + job_set = task_handle.create_jobset('Collecting Changes', + len(resources)) + for file_ in resources: + job_set.started_job(file_.path) + if file_ == self.source: + changes.add_change(self._source_module_changes(dest)) + elif file_ == dest: + changes.add_change(self._dest_module_changes(dest)) + elif self.tools.occurs_in_module(resource=file_): + pymodule = self.pycore.resource_to_pyobject(file_) + # Changing occurrences + placeholder = '__rope_renaming_%s_' % self.old_name + source = self.tools.rename_in_module(placeholder, + resource=file_) + should_import = source is not None + # Removing out of date imports + pymodule = self.tools.new_pymodule(pymodule, source) + source = self.tools.remove_old_imports(pymodule) + # Adding new import + if should_import: + pymodule = self.tools.new_pymodule(pymodule, source) + source, imported = importutils.add_import( + self.pycore, pymodule, self._new_modname(dest), self.old_name) + source = source.replace(placeholder, imported) + source = self.tools.new_source(pymodule, source) + if source != file_.read(): + changes.add_change(ChangeContents(file_, source)) + job_set.finished_job() + return changes + + def _source_module_changes(self, dest): + placeholder = '__rope_moving_%s_' % self.old_name + handle = _ChangeMoveOccurrencesHandle(placeholder) + occurrence_finder = occurrences.create_finder( + self.pycore, self.old_name, self.old_pyname) + start, end = self._get_moving_region() + renamer = ModuleSkipRenamer(occurrence_finder, self.source, + handle, start, end) + source = renamer.get_changed_module() + if handle.occurred: + pymodule = self.pycore.get_string_module(source, self.source) + # Adding new import + source, imported = importutils.add_import( + self.pycore, pymodule, self._new_modname(dest), self.old_name) + source = source.replace(placeholder, imported) + return ChangeContents(self.source, source) + + def _new_modname(self, dest): + return self.pycore.modname(dest) + + def _dest_module_changes(self, dest): + # Changing occurrences + pymodule = self.pycore.resource_to_pyobject(dest) + source = self.tools.rename_in_module(self.old_name, pymodule) + pymodule = self.tools.new_pymodule(pymodule, source) + + moving, imports = self._get_moving_element_with_imports() + source = self.tools.remove_old_imports(pymodule) + pymodule = self.tools.new_pymodule(pymodule, source) + pymodule, has_changed = self._add_imports2(pymodule, imports) + + module_with_imports = self.import_tools.module_imports(pymodule) + source = pymodule.source_code + if module_with_imports.imports: + start = pymodule.lines.get_line_end( + module_with_imports.imports[-1].end_line - 1) + result = source[:start + 1] + '\n\n' + else: + result = '' + start = -1 + result += moving + source[start + 1:] + + # Organizing imports + source = result + pymodule = self.pycore.get_string_module(source, dest) + source = self.import_tools.organize_imports(pymodule, sort=False, + unused=False) + return ChangeContents(dest, source) + + def _get_moving_element_with_imports(self): + return moving_code_with_imports( + self.pycore, self.source, self._get_moving_element()) + + def _get_module_with_imports(self, source_code, resource): + pymodule = self.pycore.get_string_module(source_code, resource) + return self.import_tools.module_imports(pymodule) + + def _get_moving_element(self): + start, end = self._get_moving_region() + moving = self.source.read()[start:end] + return moving.rstrip() + '\n' + + def _get_moving_region(self): + pymodule = self.pycore.resource_to_pyobject(self.source) + lines = pymodule.lines + scope = self.old_pyname.get_object().get_scope() + start = lines.get_line_start(scope.get_start()) + end_line = scope.get_end() + while end_line < lines.length() and \ + lines.get_line(end_line + 1).strip() == '': + end_line += 1 + end = min(lines.get_line_end(end_line) + 1, len(pymodule.source_code)) + return start, end + + def _add_imports2(self, pymodule, new_imports): + source = self.tools.add_imports(pymodule, new_imports) + if source is None: + return pymodule, False + else: + resource = pymodule.get_resource() + pymodule = self.pycore.get_string_module(source, resource) + return pymodule, True + + +class MoveModule(object): + """For moving modules and packages""" + + def __init__(self, project, resource): + self.project = project + self.pycore = project.pycore + if not resource.is_folder() and resource.name == '__init__.py': + resource = resource.parent + if resource.is_folder() and not resource.has_child('__init__.py'): + raise exceptions.RefactoringError( + 'Cannot move non-package folder.') + dummy_pymodule = self.pycore.get_string_module('') + self.old_pyname = pynames.ImportedModule(dummy_pymodule, + resource=resource) + self.source = self.old_pyname.get_object().get_resource() + if self.source.is_folder(): + self.old_name = self.source.name + else: + self.old_name = self.source.name[:-3] + self.tools = _MoveTools(self.pycore, self.source, + self.old_pyname, self.old_name) + self.import_tools = self.tools.import_tools + + def get_changes(self, dest, resources=None, + task_handle=taskhandle.NullTaskHandle()): + moving_pyobject = self.old_pyname.get_object() + if resources is None: + resources = self.pycore.get_python_files() + if dest is None or not dest.is_folder(): + raise exceptions.RefactoringError( + 'Move destination for modules should be packages.') + return self._calculate_changes(dest, resources, task_handle) + + def _calculate_changes(self, dest, resources, task_handle): + changes = ChangeSet('Moving module <%s>' % self.old_name) + job_set = task_handle.create_jobset('Collecting changes', + len(resources)) + for module in resources: + job_set.started_job(module.path) + if module == self.source: + self._change_moving_module(changes, dest) + else: + source = self._change_occurrences_in_module(dest, + resource=module) + if source is not None: + changes.add_change(ChangeContents(module, source)) + job_set.finished_job() + if self.project == self.source.project: + changes.add_change(MoveResource(self.source, dest.path)) + return changes + + def _new_modname(self, dest): + destname = self.pycore.modname(dest) + if destname: + return destname + '.' + self.old_name + return self.old_name + + def _new_import(self, dest): + return importutils.NormalImport([(self._new_modname(dest), None)]) + + def _change_moving_module(self, changes, dest): + if not self.source.is_folder(): + pymodule = self.pycore.resource_to_pyobject(self.source) + source = self.import_tools.relatives_to_absolutes(pymodule) + pymodule = self.tools.new_pymodule(pymodule, source) + source = self._change_occurrences_in_module(dest, pymodule) + source = self.tools.new_source(pymodule, source) + if source != self.source.read(): + changes.add_change(ChangeContents(self.source, source)) + + def _change_occurrences_in_module(self, dest, pymodule=None, + resource=None): + if not self.tools.occurs_in_module(pymodule=pymodule, + resource=resource): + return + if pymodule is None: + pymodule = self.pycore.resource_to_pyobject(resource) + new_name = self._new_modname(dest) + new_import = self._new_import(dest) + source = self.tools.rename_in_module( + new_name, imports=True, pymodule=pymodule, resource=resource) + should_import = self.tools.occurs_in_module( + pymodule=pymodule, resource=resource, imports=False) + pymodule = self.tools.new_pymodule(pymodule, source) + source = self.tools.remove_old_imports(pymodule) + if should_import: + pymodule = self.tools.new_pymodule(pymodule, source) + source = self.tools.add_imports(pymodule, [new_import]) + source = self.tools.new_source(pymodule, source) + if source != pymodule.resource.read(): + return source + + +class _ChangeMoveOccurrencesHandle(object): + + def __init__(self, new_name): + self.new_name = new_name + self.occurred = False + + def occurred_inside_skip(self, change_collector, occurrence): + pass + + def occurred_outside_skip(self, change_collector, occurrence): + start, end = occurrence.get_primary_range() + change_collector.add_change(start, end, self.new_name) + self.occurred = True + + +class _MoveTools(object): + + def __init__(self, pycore, source, pyname, old_name): + self.pycore = pycore + self.source = source + self.old_pyname = pyname + self.old_name = old_name + self.import_tools = importutils.ImportTools(self.pycore) + + def remove_old_imports(self, pymodule): + old_source = pymodule.source_code + module_with_imports = self.import_tools.module_imports(pymodule) + class CanSelect(object): + changed = False + old_name = self.old_name + old_pyname = self.old_pyname + def __call__(self, name): + try: + if name == self.old_name and \ + pymodule[name].get_object() == \ + self.old_pyname.get_object(): + self.changed = True + return False + except exceptions.AttributeNotFoundError: + pass + return True + can_select = CanSelect() + module_with_imports.filter_names(can_select) + new_source = module_with_imports.get_changed_source() + if old_source != new_source: + return new_source + + def rename_in_module(self, new_name, pymodule=None, + imports=False, resource=None): + occurrence_finder = self._create_finder(imports) + source = rename.rename_in_module( + occurrence_finder, new_name, replace_primary=True, + pymodule=pymodule, resource=resource) + return source + + def occurs_in_module(self, pymodule=None, resource=None, imports=True): + finder = self._create_finder(imports) + for occurrence in finder.find_occurrences(pymodule=pymodule, + resource=resource): + return True + return False + + def _create_finder(self, imports): + return occurrences.create_finder(self.pycore, self.old_name, + self.old_pyname, imports=imports) + + def new_pymodule(self, pymodule, source): + if source is not None: + return self.pycore.get_string_module( + source, pymodule.get_resource()) + return pymodule + + def new_source(self, pymodule, source): + if source is None: + return pymodule.source_code + return source + + def add_imports(self, pymodule, new_imports): + return _add_imports_to_module(self.import_tools, pymodule, new_imports) + + +def _add_imports_to_module(import_tools, pymodule, new_imports): + module_with_imports = import_tools.module_imports(pymodule) + for new_import in new_imports: + module_with_imports.add_import(new_import) + return module_with_imports.get_changed_source() + + +def moving_code_with_imports(pycore, resource, source): + import_tools = importutils.ImportTools(pycore) + pymodule = pycore.get_string_module(source, resource) + origin = pycore.resource_to_pyobject(resource) + + imports = [] + for stmt in import_tools.module_imports(origin).imports: + imports.append(stmt.import_info) + + back_names = [] + for name in origin: + if name not in pymodule: + back_names.append(name) + imports.append(import_tools.get_from_import(resource, back_names)) + + source = _add_imports_to_module(import_tools, pymodule, imports) + pymodule = pycore.get_string_module(source, resource) + + source = import_tools.relatives_to_absolutes(pymodule) + pymodule = pycore.get_string_module(source, resource) + source = import_tools.organize_imports(pymodule, selfs=False) + pymodule = pycore.get_string_module(source, resource) + + # extracting imports after changes + module_imports = import_tools.module_imports(pymodule) + imports = [import_stmt.import_info + for import_stmt in module_imports.imports] + start = 1 + if module_imports.imports: + start = module_imports.imports[-1].end_line + lines = codeanalyze.SourceLinesAdapter(source) + while start < lines.length() and not lines.get_line(start).strip(): + start += 1 + moving = source[lines.get_line_start(start):] + return moving, imports + + +class ModuleSkipRenamerHandle(object): + + def occurred_outside_skip(self, change_collector, occurrence): + pass + + def occurred_inside_skip(self, change_collector, occurrence): + pass + + +class ModuleSkipRenamer(object): + """Rename occurrences in a module + + This class can be used when you want to treat a region in a file + separately from other parts when renaming. + + """ + + def __init__(self, occurrence_finder, resource, handle=None, + skip_start=0, skip_end=0, replacement=''): + """Constructor + + if replacement is `None` the region is not changed. Otherwise + it is replaced with `replacement`. + + """ + self.occurrence_finder = occurrence_finder + self.resource = resource + self.skip_start = skip_start + self.skip_end = skip_end + self.replacement = replacement + self.handle = handle + if self.handle is None: + self.handle = ModuleSkipHandle() + + def get_changed_module(self): + source = self.resource.read() + change_collector = codeanalyze.ChangeCollector(source) + if self.replacement is not None: + change_collector.add_change(self.skip_start, self.skip_end, + self.replacement) + for occurrence in self.occurrence_finder.find_occurrences(self.resource): + start, end = occurrence.get_primary_range() + if self.skip_start <= start < self.skip_end: + self.handle.occurred_inside_skip(change_collector, occurrence) + else: + self.handle.occurred_outside_skip(change_collector, occurrence) + result = change_collector.get_changed() + if result is not None and result != source: + return result diff -r e30544496575 -r 48cacfdc2ca6 vim/sadness/ropevim/src/rope/rope/refactor/multiproject.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vim/sadness/ropevim/src/rope/rope/refactor/multiproject.py Wed Oct 06 12:30:46 2010 -0400 @@ -0,0 +1,78 @@ +"""This module can be used for performing cross-project refactorings + +See the "cross-project refactorings" section of ``docs/library.txt`` +file. + +""" + +from rope.base import resources, project, libutils + + +class MultiProjectRefactoring(object): + + def __init__(self, refactoring, projects, addpath=True): + """Create a multiproject proxy for the main refactoring + + `projects` are other project. + + """ + self.refactoring = refactoring + self.projects = projects + self.addpath = addpath + + def __call__(self, project, *args, **kwds): + """Create the refactoring""" + return _MultiRefactoring(self.refactoring, self.projects, + self.addpath, project, *args, **kwds) + + +class _MultiRefactoring(object): + + def __init__(self, refactoring, other_projects, addpath, + project, *args, **kwds): + self.refactoring = refactoring + self.projects = [project] + other_projects + for other_project in other_projects: + for folder in self.project.pycore.get_source_folders(): + other_project.get_prefs().add('python_path', folder.real_path) + self.refactorings = [] + for other in self.projects: + args, kwds = self._resources_for_args(other, args, kwds) + self.refactorings.append( + self.refactoring(other, *args, **kwds)) + + def get_all_changes(self, *args, **kwds): + """Get a project to changes dict""" + result = [] + for project, refactoring in zip(self.projects, self.refactorings): + args, kwds = self._resources_for_args(project, args, kwds) + result.append((project, refactoring.get_changes(*args, **kwds))) + return result + + def __getattr__(self, name): + return getattr(self.main_refactoring, name) + + def _resources_for_args(self, project, args, kwds): + newargs = [self._change_project_resource(project, arg) for arg in args] + newkwds = dict((name, self._change_project_resource(project, value)) + for name, value in kwds.items()) + return newargs, newkwds + + def _change_project_resource(self, project, obj): + if isinstance(obj, resources.Resource) and \ + obj.project != project: + return libutils.path_to_resource(project, obj.real_path) + return obj + + @property + def project(self): + return self.projects[0] + + @property + def main_refactoring(self): + return self.refactorings[0] + + +def perform(project_changes): + for project, changes in project_changes: + project.do(changes) diff -r e30544496575 -r 48cacfdc2ca6 vim/sadness/ropevim/src/rope/rope/refactor/occurrences.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vim/sadness/ropevim/src/rope/rope/refactor/occurrences.py Wed Oct 06 12:30:46 2010 -0400 @@ -0,0 +1,334 @@ +import re + +import rope.base.pynames +from rope.base import pynames, pyobjects, codeanalyze, evaluate, exceptions, utils, worder + + +class Finder(object): + """For finding occurrences of a name + + The constructor takes a `filters` argument. It should be a list + of functions that take a single argument. For each possible + occurrence, these functions are called in order with the an + instance of `Occurrence`: + + * If it returns `None` other filters are tried. + * If it returns `True`, the occurrence will be a match. + * If it returns `False`, the occurrence will be skipped. + * If all of the filters return `None`, it is skipped also. + + """ + + def __init__(self, pycore, name, filters=[lambda o: True], docs=False): + self.pycore = pycore + self.name = name + self.docs = docs + self.filters = filters + self._textual_finder = _TextualFinder(name, docs=docs) + + def find_occurrences(self, resource=None, pymodule=None): + """Generate `Occurrence` instances""" + tools = _OccurrenceToolsCreator(self.pycore, resource=resource, + pymodule=pymodule, docs=self.docs) + for offset in self._textual_finder.find_offsets(tools.source_code): + occurrence = Occurrence(tools, offset) + for filter in self.filters: + result = filter(occurrence) + if result is None: + continue + if result: + yield occurrence + break + + +def create_finder(pycore, name, pyname, only_calls=False, imports=True, + unsure=None, docs=False, instance=None, in_hierarchy=False): + """A factory for `Finder` + + Based on the arguments it creates a list of filters. `instance` + argument is needed only when you want implicit interfaces to be + considered. + + """ + pynames = set([pyname]) + filters = [] + if only_calls: + filters.append(CallsFilter()) + if not imports: + filters.append(NoImportsFilter()) + if isinstance(instance, rope.base.pynames.ParameterName): + for pyobject in instance.get_objects(): + try: + pynames.add(pyobject[name]) + except exceptions.AttributeNotFoundError: + pass + for pyname in pynames: + filters.append(PyNameFilter(pyname)) + if in_hierarchy: + filters.append(InHierarchyFilter(pyname)) + if unsure: + filters.append(UnsureFilter(unsure)) + return Finder(pycore, name, filters=filters, docs=docs) + + +class Occurrence(object): + + def __init__(self, tools, offset): + self.tools = tools + self.offset = offset + self.resource = tools.resource + + @utils.saveit + def get_word_range(self): + return self.tools.word_finder.get_word_range(self.offset) + + @utils.saveit + def get_primary_range(self): + return self.tools.word_finder.get_primary_range(self.offset) + + @utils.saveit + def get_pyname(self): + try: + return self.tools.name_finder.get_pyname_at(self.offset) + except exceptions.BadIdentifierError: + pass + + @utils.saveit + def get_primary_and_pyname(self): + try: + return self.tools.name_finder.get_primary_and_pyname_at(self.offset) + except exceptions.BadIdentifierError: + pass + + @utils.saveit + def is_in_import_statement(self): + return (self.tools.word_finder.is_from_statement(self.offset) or + self.tools.word_finder.is_import_statement(self.offset)) + + def is_called(self): + return self.tools.word_finder.is_a_function_being_called(self.offset) + + def is_defined(self): + return self.tools.word_finder.is_a_class_or_function_name_in_header(self.offset) + + def is_a_fixed_primary(self): + return self.tools.word_finder.is_a_class_or_function_name_in_header(self.offset) or \ + self.tools.word_finder.is_a_name_after_from_import(self.offset) + + def is_written(self): + return self.tools.word_finder.is_assigned_here(self.offset) + + def is_unsure(self): + return unsure_pyname(self.get_pyname()) + + @property + @utils.saveit + def lineno(self): + offset = self.get_word_range()[0] + return self.tools.pymodule.lines.get_line_number(offset) + + +def same_pyname(expected, pyname): + """Check whether `expected` and `pyname` are the same""" + if expected is None or pyname is None: + return False + if expected == pyname: + return True + if type(expected) not in (pynames.ImportedModule, pynames.ImportedName) and \ + type(pyname) not in (pynames.ImportedModule, pynames.ImportedName): + return False + return expected.get_definition_location() == pyname.get_definition_location() and \ + expected.get_object() == pyname.get_object() + +def unsure_pyname(pyname, unbound=True): + """Return `True` if we don't know what this name references""" + if pyname is None: + return True + if unbound and not isinstance(pyname, pynames.UnboundName): + return False + if pyname.get_object() == pyobjects.get_unknown(): + return True + + +class PyNameFilter(object): + """For finding occurrences of a name""" + + def __init__(self, pyname): + self.pyname = pyname + + def __call__(self, occurrence): + if same_pyname(self.pyname, occurrence.get_pyname()): + return True + + +class InHierarchyFilter(object): + """For finding occurrences of a name""" + + def __init__(self, pyname, implementations_only=False): + self.pyname = pyname + self.impl_only = implementations_only + self.pyclass = self._get_containing_class(pyname) + if self.pyclass is not None: + self.name = pyname.get_object().get_name() + self.roots = self._get_root_classes(self.pyclass, self.name) + else: + self.roots = None + + def __call__(self, occurrence): + if self.roots is None: + return + pyclass = self._get_containing_class(occurrence.get_pyname()) + if pyclass is not None: + roots = self._get_root_classes(pyclass, self.name) + if self.roots.intersection(roots): + return True + + def _get_containing_class(self, pyname): + if isinstance(pyname, pynames.DefinedName): + scope = pyname.get_object().get_scope() + parent = scope.parent + if parent is not None and parent.get_kind() == 'Class': + return parent.pyobject + + def _get_root_classes(self, pyclass, name): + if self.impl_only and pyclass == self.pyclass: + return set([pyclass]) + result = set() + for superclass in pyclass.get_superclasses(): + if name in superclass: + result.update(self._get_root_classes(superclass, name)) + if not result: + return set([pyclass]) + return result + + +class UnsureFilter(object): + + def __init__(self, unsure): + self.unsure = unsure + + def __call__(self, occurrence): + if occurrence.is_unsure() and self.unsure(occurrence): + return True + + +class NoImportsFilter(object): + + def __call__(self, occurrence): + if occurrence.is_in_import_statement(): + return False + + +class CallsFilter(object): + + def __call__(self, occurrence): + if not occurrence.is_called(): + return False + + +class _TextualFinder(object): + + def __init__(self, name, docs=False): + self.name = name + self.docs = docs + self.comment_pattern = _TextualFinder.any('comment', [r'#[^\n]*']) + self.string_pattern = _TextualFinder.any( + 'string', [codeanalyze.get_string_pattern()]) + self.pattern = self._get_occurrence_pattern(self.name) + + def find_offsets(self, source): + if not self._fast_file_query(source): + return + if self.docs: + searcher = self._normal_search + else: + searcher = self._re_search + for matched in searcher(source): + yield matched + + def _re_search(self, source): + for match in self.pattern.finditer(source): + for key, value in match.groupdict().items(): + if value and key == 'occurrence': + yield match.start(key) + + def _normal_search(self, source): + current = 0 + while True: + try: + found = source.index(self.name, current) + current = found + len(self.name) + if (found == 0 or not self._is_id_char(source[found - 1])) and \ + (current == len(source) or not self._is_id_char(source[current])): + yield found + except ValueError: + break + + def _is_id_char(self, c): + return c.isalnum() or c == '_' + + def _fast_file_query(self, source): + try: + source.index(self.name) + return True + except ValueError: + return False + + def _get_source(self, resource, pymodule): + if resource is not None: + return resource.read() + else: + return pymodule.source_code + + def _get_occurrence_pattern(self, name): + occurrence_pattern = _TextualFinder.any('occurrence', + ['\\b' + name + '\\b']) + pattern = re.compile(occurrence_pattern + '|' + self.comment_pattern + + '|' + self.string_pattern) + return pattern + + @staticmethod + def any(name, list_): + return '(?P<%s>' % name + '|'.join(list_) + ')' + + +class _OccurrenceToolsCreator(object): + + def __init__(self, pycore, resource=None, pymodule=None, docs=False): + self.pycore = pycore + self.__resource = resource + self.__pymodule = pymodule + self.docs = docs + + @property + @utils.saveit + def name_finder(self): + return evaluate.ScopeNameFinder(self.pymodule) + + @property + @utils.saveit + def source_code(self): + if self.__resource is not None: + return self.resource.read() + else: + return self.pymodule.source_code + + @property + @utils.saveit + def word_finder(self): + return worder.Worder(self.source_code, self.docs) + + @property + @utils.saveit + def resource(self): + if self.__resource is not None: + return self.__resource + if self.__pymodule is not None: + return self.__pymodule.resource + + @property + @utils.saveit + def pymodule(self): + if self.__pymodule is not None: + return self.__pymodule + return self.pycore.resource_to_pyobject(self.resource) diff -r e30544496575 -r 48cacfdc2ca6 vim/sadness/ropevim/src/rope/rope/refactor/patchedast.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vim/sadness/ropevim/src/rope/rope/refactor/patchedast.py Wed Oct 06 12:30:46 2010 -0400 @@ -0,0 +1,732 @@ +import collections +import re +import warnings + +from rope.base import ast, codeanalyze, exceptions + + +def get_patched_ast(source, sorted_children=False): + """Adds ``region`` and ``sorted_children`` fields to nodes + + Adds ``sorted_children`` field only if `sorted_children` is True. + + """ + return patch_ast(ast.parse(source), source, sorted_children) + + +def patch_ast(node, source, sorted_children=False): + """Patches the given node + + After calling, each node in `node` will have a new field named + `region` that is a tuple containing the start and end offsets + of the code that generated it. + + If `sorted_children` is true, a `sorted_children` field will + be created for each node, too. It is a list containing child + nodes as well as whitespaces and comments that occur between + them. + + """ + if hasattr(node, 'region'): + return node + walker = _PatchingASTWalker(source, children=sorted_children) + ast.call_for_nodes(node, walker) + return node + + +def node_region(patched_ast_node): + """Get the region of a patched ast node""" + return patched_ast_node.region + + +def write_ast(patched_ast_node): + """Extract source form a patched AST node with `sorted_children` field + + If the node is patched with sorted_children turned off you can use + `node_region` function for obtaining code using module source code. + """ + result = [] + for child in patched_ast_node.sorted_children: + if isinstance(child, ast.AST): + result.append(write_ast(child)) + else: + result.append(child) + return ''.join(result) + + +class MismatchedTokenError(exceptions.RopeError): + pass + + +class _PatchingASTWalker(object): + + def __init__(self, source, children=False): + self.source = _Source(source) + self.children = children + self.lines = codeanalyze.SourceLinesAdapter(source) + self.children_stack = [] + + Number = object() + String = object() + + def __call__(self, node): + method = getattr(self, '_' + node.__class__.__name__, None) + if method is not None: + return method(node) + # ???: Unknown node; what should we do here? + warnings.warn('Unknown node type <%s>; please report!' + % node.__class__.__name__, RuntimeWarning) + node.region = (self.source.offset, self.source.offset) + if self.children: + node.sorted_children = ast.get_children(node) + + def _handle(self, node, base_children, eat_parens=False, eat_spaces=False): + if hasattr(node, 'region'): + # ???: The same node was seen twice; what should we do? + warnings.warn( + 'Node <%s> has been already patched; please report!' % + node.__class__.__name__, RuntimeWarning) + return + base_children = collections.deque(base_children) + self.children_stack.append(base_children) + children = collections.deque() + formats = [] + suspected_start = self.source.offset + start = suspected_start + first_token = True + while base_children: + child = base_children.popleft() + if child is None: + continue + offset = self.source.offset + if isinstance(child, ast.AST): + ast.call_for_nodes(child, self) + token_start = child.region[0] + else: + if child is self.String: + region = self.source.consume_string( + end=self._find_next_statement_start()) + elif child is self.Number: + region = self.source.consume_number() + elif child == '!=': + # INFO: This has been added to handle deprecated ``<>`` + region = self.source.consume_not_equal() + else: + region = self.source.consume(child) + child = self.source[region[0]:region[1]] + token_start = region[0] + if not first_token: + formats.append(self.source[offset:token_start]) + if self.children: + children.append(self.source[offset:token_start]) + else: + first_token = False + start = token_start + if self.children: + children.append(child) + start = self._handle_parens(children, start, formats) + if eat_parens: + start = self._eat_surrounding_parens( + children, suspected_start, start) + if eat_spaces: + if self.children: + children.appendleft(self.source[0:start]) + end_spaces = self.source[self.source.offset:] + self.source.consume(end_spaces) + if self.children: + children.append(end_spaces) + start = 0 + if self.children: + node.sorted_children = children + node.region = (start, self.source.offset) + self.children_stack.pop() + + def _handle_parens(self, children, start, formats): + """Changes `children` and returns new start""" + opens, closes = self._count_needed_parens(formats) + old_end = self.source.offset + new_end = None + for i in range(closes): + new_end = self.source.consume(')')[1] + if new_end is not None: + if self.children: + children.append(self.source[old_end:new_end]) + new_start = start + for i in range(opens): + new_start = self.source.rfind_token('(', 0, new_start) + if new_start != start: + if self.children: + children.appendleft(self.source[new_start:start]) + start = new_start + return start + + def _eat_surrounding_parens(self, children, suspected_start, start): + index = self.source.rfind_token('(', suspected_start, start) + if index is not None: + old_start = start + old_offset = self.source.offset + start = index + if self.children: + children.appendleft(self.source[start + 1:old_start]) + children.appendleft('(') + token_start, token_end = self.source.consume(')') + if self.children: + children.append(self.source[old_offset:token_start]) + children.append(')') + return start + + def _count_needed_parens(self, children): + start = 0 + opens = 0 + for child in children: + if not isinstance(child, basestring): + continue + if child == '' or child[0] in '\'"': + continue + index = 0 + while index < len(child): + if child[index] == ')': + if opens > 0: + opens -= 1 + else: + start += 1 + if child[index] == '(': + opens += 1 + if child[index] == '#': + try: + index = child.index('\n', index) + except ValueError: + break + index += 1 + return start, opens + + def _find_next_statement_start(self): + for children in reversed(self.children_stack): + for child in children: + if isinstance(child, ast.stmt): + return self.lines.get_line_start(child.lineno) + return len(self.source.source) + + _operators = {'And': 'and', 'Or': 'or', 'Add': '+', 'Sub': '-', 'Mult': '*', + 'Div': '/', 'Mod': '%', 'Pow': '**', 'LShift': '<<', + 'RShift': '>>', 'BitOr': '|', 'BitAnd': '&', 'BitXor': '^', + 'FloorDiv': '//', 'Invert': '~', 'Not': 'not', 'UAdd': '+', + 'USub': '-', 'Eq': '==', 'NotEq': '!=', 'Lt': '<', + 'LtE': '<=', 'Gt': '>', 'GtE': '>=', 'Is': 'is', + 'IsNot': 'is not', 'In': 'in', 'NotIn': 'not in'} + + def _get_op(self, node): + return self._operators[node.__class__.__name__].split(' ') + + def _Attribute(self, node): + self._handle(node, [node.value, '.', node.attr]) + + def _Assert(self, node): + children = ['assert', node.test] + if node.msg: + children.append(',') + children.append(node.msg) + self._handle(node, children) + + def _Assign(self, node): + children = self._child_nodes(node.targets, '=') + children.append('=') + children.append(node.value) + self._handle(node, children) + + def _AugAssign(self, node): + children = [node.target] + children.extend(self._get_op(node.op)) + children.extend(['=', node.value]) + self._handle(node, children) + + def _Repr(self, node): + self._handle(node, ['`', node.value, '`']) + + def _BinOp(self, node): + children = [node.left] + self._get_op(node.op) + [node.right] + self._handle(node, children) + + def _BoolOp(self, node): + self._handle(node, self._child_nodes(node.values, + self._get_op(node.op)[0])) + + def _Break(self, node): + self._handle(node, ['break']) + + def _Call(self, node): + children = [node.func, '('] + args = list(node.args) + node.keywords + children.extend(self._child_nodes(args, ',')) + if node.starargs is not None: + if args: + children.append(',') + children.extend(['*', node.starargs]) + if node.kwargs is not None: + if args or node.starargs is not None: + children.append(',') + children.extend(['**', node.kwargs]) + children.append(')') + self._handle(node, children) + + def _ClassDef(self, node): + children = [] + if getattr(node, 'decorator_list', None): + for decorator in node.decorator_list: + children.append('@') + children.append(decorator) + children.extend(['class', node.name]) + if node.bases: + children.append('(') + children.extend(self._child_nodes(node.bases, ',')) + children.append(')') + children.append(':') + children.extend(node.body) + self._handle(node, children) + + def _Compare(self, node): + children = [] + children.append(node.left) + for op, expr in zip(node.ops, node.comparators): + children.extend(self._get_op(op)) + children.append(expr) + self._handle(node, children) + + def _Delete(self, node): + self._handle(node, ['del'] + self._child_nodes(node.targets, ',')) + + def _Num(self, node): + self._handle(node, [self.Number]) + + def _Str(self, node): + self._handle(node, [self.String]) + + def _Continue(self, node): + self._handle(node, ['continue']) + + def _Dict(self, node): + children = [] + children.append('{') + if node.keys: + for index, (key, value) in enumerate(zip(node.keys, node.values)): + children.extend([key, ':', value]) + if index < len(node.keys) - 1: + children.append(',') + children.append('}') + self._handle(node, children) + + def _Ellipsis(self, node): + self._handle(node, ['...']) + + def _Expr(self, node): + self._handle(node, [node.value]) + + def _Exec(self, node): + children = [] + children.extend(['exec', node.body]) + if node.globals: + children.extend(['in', node.globals]) + if node.locals: + children.extend([',', node.locals]) + self._handle(node, children) + + def _ExtSlice(self, node): + children = [] + for index, dim in enumerate(node.dims): + if index > 0: + children.append(',') + children.append(dim) + self._handle(node, children) + + def _For(self, node): + children = ['for', node.target, 'in', node.iter, ':'] + children.extend(node.body) + if node.orelse: + children.extend(['else', ':']) + children.extend(node.orelse) + self._handle(node, children) + + def _ImportFrom(self, node): + children = ['from'] + if node.level: + children.append('.' * node.level) + children.extend([node.module, 'import']) + children.extend(self._child_nodes(node.names, ',')) + self._handle(node, children) + + def _alias(self, node): + children = [node.name] + if node.asname: + children.extend(['as', node.asname]) + self._handle(node, children) + + def _FunctionDef(self, node): + children = [] + try: + decorators = getattr(node, 'decorator_list') + except AttributeError: + decorators = getattr(node, 'decorators', None) + if decorators: + for decorator in decorators: + children.append('@') + children.append(decorator) + children.extend(['def', node.name, '(', node.args]) + children.extend([')', ':']) + children.extend(node.body) + self._handle(node, children) + + def _arguments(self, node): + children = [] + args = list(node.args) + defaults = [None] * (len(args) - len(node.defaults)) + list(node.defaults) + for index, (arg, default) in enumerate(zip(args, defaults)): + if index > 0: + children.append(',') + self._add_args_to_children(children, arg, default) + if node.vararg is not None: + if args: + children.append(',') + children.extend(['*', node.vararg]) + if node.kwarg is not None: + if args or node.vararg is not None: + children.append(',') + children.extend(['**', node.kwarg]) + self._handle(node, children) + + def _add_args_to_children(self, children, arg, default): + if isinstance(arg, (list, tuple)): + self._add_tuple_parameter(children, arg) + else: + children.append(arg) + if default is not None: + children.append('=') + children.append(default) + + def _add_tuple_parameter(self, children, arg): + children.append('(') + for index, token in enumerate(arg): + if index > 0: + children.append(',') + if isinstance(token, (list, tuple)): + self._add_tuple_parameter(children, token) + else: + children.append(token) + children.append(')') + + def _GeneratorExp(self, node): + children = [node.elt] + children.extend(node.generators) + self._handle(node, children, eat_parens=True) + + def _comprehension(self, node): + children = ['for', node.target, 'in', node.iter] + if node.ifs: + for if_ in node.ifs: + children.append('if') + children.append(if_) + self._handle(node, children) + + def _Global(self, node): + children = self._child_nodes(node.names, ',') + children.insert(0, 'global') + self._handle(node, children) + + def _If(self, node): + if self._is_elif(node): + children = ['elif'] + else: + children = ['if'] + children.extend([node.test, ':']) + children.extend(node.body) + if node.orelse: + if len(node.orelse) == 1 and self._is_elif(node.orelse[0]): + pass + else: + children.extend(['else', ':']) + children.extend(node.orelse) + self._handle(node, children) + + def _is_elif(self, node): + if not isinstance(node, ast.If): + return False + offset = self.lines.get_line_start(node.lineno) + node.col_offset + word = self.source[offset:offset + 4] + # XXX: This is a bug; the offset does not point to the first + alt_word = self.source[offset - 5:offset - 1] + return 'elif' in (word, alt_word) + + def _IfExp(self, node): + return self._handle(node, [node.body, 'if', node.test, + 'else', node.orelse]) + + def _Import(self, node): + children = ['import'] + children.extend(self._child_nodes(node.names, ',')) + self._handle(node, children) + + def _keyword(self, node): + self._handle(node, [node.arg, '=', node.value]) + + def _Lambda(self, node): + self._handle(node, ['lambda', node.args, ':', node.body]) + + def _List(self, node): + self._handle(node, ['['] + self._child_nodes(node.elts, ',') + [']']) + + def _ListComp(self, node): + children = ['[', node.elt] + children.extend(node.generators) + children.append(']') + self._handle(node, children) + + def _Module(self, node): + self._handle(node, list(node.body), eat_spaces=True) + + def _Name(self, node): + self._handle(node, [node.id]) + + def _Pass(self, node): + self._handle(node, ['pass']) + + def _Print(self, node): + children = ['print'] + if node.dest: + children.extend(['>>', node.dest]) + if node.values: + children.append(',') + children.extend(self._child_nodes(node.values, ',')) + if not node.nl: + children.append(',') + self._handle(node, children) + + def _Raise(self, node): + children = ['raise'] + if node.type: + children.append(node.type) + if node.inst: + children.append(',') + children.append(node.inst) + if node.tback: + children.append(',') + children.append(node.tback) + self._handle(node, children) + + def _Return(self, node): + children = ['return'] + if node.value: + children.append(node.value) + self._handle(node, children) + + def _Sliceobj(self, node): + children = [] + for index, slice in enumerate(node.nodes): + if index > 0: + children.append(':') + if slice: + children.append(slice) + self._handle(node, children) + + def _Index(self, node): + self._handle(node, [node.value]) + + def _Subscript(self, node): + self._handle(node, [node.value, '[', node.slice, ']']) + + def _Slice(self, node): + children = [] + if node.lower: + children.append(node.lower) + children.append(':') + if node.upper: + children.append(node.upper) + if node.step: + children.append(':') + children.append(node.step) + self._handle(node, children) + + def _TryFinally(self, node): + children = [] + if len(node.body) != 1 or not isinstance(node.body[0], ast.TryExcept): + children.extend(['try', ':']) + children.extend(node.body) + children.extend(['finally', ':']) + children.extend(node.finalbody) + self._handle(node, children) + + def _TryExcept(self, node): + children = ['try', ':'] + children.extend(node.body) + children.extend(node.handlers) + if node.orelse: + children.extend(['else', ':']) + children.extend(node.orelse) + self._handle(node, children) + + def _ExceptHandler(self, node): + self._excepthandler(node) + + def _excepthandler(self, node): + children = ['except'] + if node.type: + children.append(node.type) + if node.name: + children.extend([',', node.name]) + children.append(':') + children.extend(node.body) + self._handle(node, children) + + def _Tuple(self, node): + if node.elts: + self._handle(node, self._child_nodes(node.elts, ','), + eat_parens=True) + else: + self._handle(node, ['(', ')']) + + def _UnaryOp(self, node): + children = self._get_op(node.op) + children.append(node.operand) + self._handle(node, children) + + def _Yield(self, node): + children = ['yield'] + if node.value: + children.append(node.value) + self._handle(node, children) + + def _While(self, node): + children = ['while', node.test, ':'] + children.extend(node.body) + if node.orelse: + children.extend(['else', ':']) + children.extend(node.orelse) + self._handle(node, children) + + def _With(self, node): + children = ['with', node.context_expr] + if node.optional_vars: + children.extend(['as', node.optional_vars]) + children.append(':') + children.extend(node.body) + self._handle(node, children) + + def _child_nodes(self, nodes, separator): + children = [] + for index, child in enumerate(nodes): + children.append(child) + if index < len(nodes) - 1: + children.append(separator) + return children + + +class _Source(object): + + def __init__(self, source): + self.source = source + self.offset = 0 + + def consume(self, token): + try: + while True: + new_offset = self.source.index(token, self.offset) + if self._good_token(token, new_offset): + break + else: + self._skip_comment() + except (ValueError, TypeError): + raise MismatchedTokenError( + 'Token <%s> at %s cannot be matched' % + (token, self._get_location())) + self.offset = new_offset + len(token) + return (new_offset, self.offset) + + def consume_string(self, end=None): + if _Source._string_pattern is None: + original = codeanalyze.get_string_pattern() + pattern = r'(%s)((\s|\\\n|#[^\n]*\n)*(%s))*' % \ + (original, original) + _Source._string_pattern = re.compile(pattern) + repattern = _Source._string_pattern + return self._consume_pattern(repattern, end) + + def consume_number(self): + if _Source._number_pattern is None: + _Source._number_pattern = re.compile( + self._get_number_pattern()) + repattern = _Source._number_pattern + return self._consume_pattern(repattern) + + def consume_not_equal(self): + if _Source._not_equals_pattern is None: + _Source._not_equals_pattern = re.compile(r'<>|!=') + repattern = _Source._not_equals_pattern + return self._consume_pattern(repattern) + + def _good_token(self, token, offset, start=None): + """Checks whether consumed token is in comments""" + if start is None: + start = self.offset + try: + comment_index = self.source.rindex('#', start, offset) + except ValueError: + return True + try: + new_line_index = self.source.rindex('\n', start, offset) + except ValueError: + return False + return comment_index < new_line_index + + def _skip_comment(self): + self.offset = self.source.index('\n', self.offset + 1) + + def _get_location(self): + lines = self.source[:self.offset].split('\n') + return (len(lines), len(lines[-1])) + + def _consume_pattern(self, repattern, end=None): + while True: + if end is None: + end = len(self.source) + match = repattern.search(self.source, self.offset, end) + if self._good_token(match.group(), match.start()): + break + else: + self._skip_comment() + self.offset = match.end() + return match.start(), match.end() + + def till_token(self, token): + new_offset = self.source.index(token, self.offset) + return self[self.offset:new_offset] + + def rfind_token(self, token, start, end): + index = start + while True: + try: + index = self.source.rindex(token, start, end) + if self._good_token(token, index, start=start): + return index + else: + end = index + except ValueError: + return None + + def from_offset(self, offset): + return self[offset:self.offset] + + def find_backwards(self, pattern, offset): + return self.source.rindex(pattern, 0, offset) + + def __getitem__(self, index): + return self.source[index] + + def __getslice__(self, i, j): + return self.source[i:j] + + def _get_number_pattern(self): + # HACK: It is merely an approaximation and does the job + integer = r'(0|0x)?[\da-fA-F]+[lL]?' + return r'(%s(\.\d*)?|(\.\d+))([eE][-+]?\d*)?[jJ]?' % integer + + _string_pattern = None + _number_pattern = None + _not_equals_pattern = None diff -r e30544496575 -r 48cacfdc2ca6 vim/sadness/ropevim/src/rope/rope/refactor/rename.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vim/sadness/ropevim/src/rope/rope/refactor/rename.py Wed Oct 06 12:30:46 2010 -0400 @@ -0,0 +1,216 @@ +import warnings + +from rope.base import exceptions, pyobjects, pynames, taskhandle, evaluate, worder, codeanalyze +from rope.base.change import ChangeSet, ChangeContents, MoveResource +from rope.refactor import occurrences, sourceutils + + +class Rename(object): + """A class for performing rename refactoring + + It can rename everything: classes, functions, modules, packages, + methods, variables and keyword arguments. + + """ + + def __init__(self, project, resource, offset=None): + """If `offset` is None, the `resource` itself will be renamed""" + self.project = project + self.pycore = project.pycore + self.resource = resource + if offset is not None: + self.old_name = worder.get_name_at(self.resource, offset) + this_pymodule = self.pycore.resource_to_pyobject(self.resource) + self.old_instance, self.old_pyname = \ + evaluate.eval_location2(this_pymodule, offset) + if self.old_pyname is None: + raise exceptions.RefactoringError( + 'Rename refactoring should be performed' + ' on resolvable python identifiers.') + else: + if not resource.is_folder() and resource.name == '__init__.py': + resource = resource.parent + dummy_pymodule = self.pycore.get_string_module('') + self.old_instance = None + self.old_pyname = pynames.ImportedModule(dummy_pymodule, + resource=resource) + if resource.is_folder(): + self.old_name = resource.name + else: + self.old_name = resource.name[:-3] + + def get_old_name(self): + return self.old_name + + def get_changes(self, new_name, in_file=None, in_hierarchy=False, + unsure=None, docs=False, resources=None, + task_handle=taskhandle.NullTaskHandle()): + """Get the changes needed for this refactoring + + Parameters: + + - `in_hierarchy`: when renaming a method this keyword forces + to rename all matching methods in the hierarchy + - `docs`: when `True` rename refactoring will rename + occurrences in comments and strings where the name is + visible. Setting it will make renames faster, too. + - `unsure`: decides what to do about unsure occurrences. + If `None`, they are ignored. Otherwise `unsure` is + called with an instance of `occurrence.Occurrence` as + parameter. If it returns `True`, the occurrence is + considered to be a match. + - `resources` can be a list of `rope.base.resources.File`\s to + apply this refactoring on. If `None`, the restructuring + will be applied to all python files. + - `in_file`: this argument has been deprecated; use + `resources` instead. + + """ + if unsure in (True, False): + warnings.warn( + 'unsure parameter should be a function that returns ' + 'True or False', DeprecationWarning, stacklevel=2) + def unsure_func(value=unsure): + return value + unsure = unsure_func + if in_file is not None: + warnings.warn( + '`in_file` argument has been deprecated; use `resources` ' + 'instead. ', DeprecationWarning, stacklevel=2) + if in_file: + resources = [self.resource] + if _is_local(self.old_pyname): + resources = [self.resource] + if resources is None: + resources = self.pycore.get_python_files() + changes = ChangeSet('Renaming <%s> to <%s>' % + (self.old_name, new_name)) + finder = occurrences.create_finder( + self.pycore, self.old_name, self.old_pyname, unsure=unsure, + docs=docs, instance=self.old_instance, + in_hierarchy=in_hierarchy and self.is_method()) + job_set = task_handle.create_jobset('Collecting Changes', len(resources)) + for file_ in resources: + job_set.started_job(file_.path) + new_content = rename_in_module(finder, new_name, resource=file_) + if new_content is not None: + changes.add_change(ChangeContents(file_, new_content)) + job_set.finished_job() + if self._is_renaming_a_module(): + resource = self.old_pyname.get_object().get_resource() + if self._is_allowed_to_move(resources, resource): + self._rename_module(resource, new_name, changes) + return changes + + def _is_allowed_to_move(self, resources, resource): + if resource.is_folder(): + try: + return resource.get_child('__init__.py') in resources + except exceptions.ResourceNotFoundError: + return False + else: + return resource in resources + + def _is_renaming_a_module(self): + if isinstance(self.old_pyname.get_object(), pyobjects.AbstractModule): + return True + return False + + def is_method(self): + pyname = self.old_pyname + return isinstance(pyname, pynames.DefinedName) and \ + isinstance(pyname.get_object(), pyobjects.PyFunction) and \ + isinstance(pyname.get_object().parent, pyobjects.PyClass) + + def _rename_module(self, resource, new_name, changes): + if not resource.is_folder(): + new_name = new_name + '.py' + parent_path = resource.parent.path + if parent_path == '': + new_location = new_name + else: + new_location = parent_path + '/' + new_name + changes.add_change(MoveResource(resource, new_location)) + + +class ChangeOccurrences(object): + """A class for changing the occurrences of a name in a scope + + This class replaces the occurrences of a name. Note that it only + changes the scope containing the offset passed to the constructor. + What's more it does not have any side-effects. That is for + example changing occurrences of a module does not rename the + module; it merely replaces the occurrences of that module in a + scope with the given expression. This class is useful for + performing many custom refactorings. + + """ + + def __init__(self, project, resource, offset): + self.pycore = project.pycore + self.resource = resource + self.offset = offset + self.old_name = worder.get_name_at(resource, offset) + self.pymodule = self.pycore.resource_to_pyobject(self.resource) + self.old_pyname = evaluate.eval_location(self.pymodule, offset) + + def get_old_name(self): + word_finder = worder.Worder(self.resource.read()) + return word_finder.get_primary_at(self.offset) + + def _get_scope_offset(self): + lines = self.pymodule.lines + scope = self.pymodule.get_scope().\ + get_inner_scope_for_line(lines.get_line_number(self.offset)) + start = lines.get_line_start(scope.get_start()) + end = lines.get_line_end(scope.get_end()) + return start, end + + def get_changes(self, new_name, only_calls=False, reads=True, writes=True): + changes = ChangeSet('Changing <%s> occurrences to <%s>' % + (self.old_name, new_name)) + scope_start, scope_end = self._get_scope_offset() + finder = occurrences.create_finder( + self.pycore, self.old_name, self.old_pyname, + imports=False, only_calls=only_calls) + new_contents = rename_in_module( + finder, new_name, pymodule=self.pymodule, replace_primary=True, + region=(scope_start, scope_end), reads=reads, writes=writes) + if new_contents is not None: + changes.add_change(ChangeContents(self.resource, new_contents)) + return changes + + +def rename_in_module(occurrences_finder, new_name, resource=None, pymodule=None, + replace_primary=False, region=None, reads=True, writes=True): + """Returns the changed source or `None` if there is no changes""" + if resource is not None: + source_code = resource.read() + else: + source_code = pymodule.source_code + change_collector = codeanalyze.ChangeCollector(source_code) + for occurrence in occurrences_finder.find_occurrences(resource, pymodule): + if replace_primary and occurrence.is_a_fixed_primary(): + continue + if replace_primary: + start, end = occurrence.get_primary_range() + else: + start, end = occurrence.get_word_range() + if (not reads and not occurrence.is_written()) or \ + (not writes and occurrence.is_written()): + continue + if region is None or region[0] <= start < region[1]: + change_collector.add_change(start, end, new_name) + return change_collector.get_changed() + +def _is_local(pyname): + module, lineno = pyname.get_definition_location() + if lineno is None: + return False + scope = module.get_scope().get_inner_scope_for_line(lineno) + if isinstance(pyname, pynames.DefinedName) and \ + scope.get_kind() in ('Function', 'Class'): + scope = scope.parent + return scope.get_kind() == 'Function' and \ + pyname in scope.get_names().values() and \ + isinstance(pyname, pynames.AssignedName) diff -r e30544496575 -r 48cacfdc2ca6 vim/sadness/ropevim/src/rope/rope/refactor/restructure.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vim/sadness/ropevim/src/rope/rope/refactor/restructure.py Wed Oct 06 12:30:46 2010 -0400 @@ -0,0 +1,307 @@ +import warnings + +from rope.base import change, taskhandle, builtins, ast, codeanalyze +from rope.refactor import patchedast, similarfinder, sourceutils +from rope.refactor.importutils import module_imports + + +class Restructure(object): + """A class to perform python restructurings + + A restructuring transforms pieces of code matching `pattern` to + `goal`. In the `pattern` wildcards can appear. Wildcards match + some piece of code based on their kind and arguments that are + passed to them through `args`. + + `args` is a dictionary of wildcard names to wildcard arguments. + If the argument is a tuple, the first item of the tuple is + considered to be the name of the wildcard to use; otherwise the + "default" wildcard is used. For getting the list arguments a + wildcard supports, see the pydoc of the wildcard. (see + `rope.refactor.wildcard.DefaultWildcard` for the default + wildcard.) + + `wildcards` is the list of wildcard types that can appear in + `pattern`. See `rope.refactor.wildcards`. If a wildcard does not + specify its kind (by using a tuple in args), the wildcard named + "default" is used. So there should be a wildcard with "default" + name in `wildcards`. + + `imports` is the list of imports that changed modules should + import. Note that rope handles duplicate imports and does not add + the import if it already appears. + + Example #1:: + + pattern ${pyobject}.get_attribute(${name}) + goal ${pyobject}[${name}] + args pyobject: instance=rope.base.pyobjects.PyObject + + Example #2:: + + pattern ${name} in ${pyobject}.get_attributes() + goal ${name} in {pyobject} + args pyobject: instance=rope.base.pyobjects.PyObject + + Example #3:: + + pattern ${pycore}.create_module(${project}.root, ${name}) + goal generate.create_module(${project}, ${name}) + + imports + from rope.contrib import generate + + args + pycore: type=rope.base.pycore.PyCore + project: type=rope.base.project.Project + + Example #4:: + + pattern ${pow}(${param1}, ${param2}) + goal ${param1} ** ${param2} + args pow: name=mod.pow, exact + + Example #5:: + + pattern ${inst}.longtask(${p1}, ${p2}) + goal + ${inst}.subtask1(${p1}) + ${inst}.subtask2(${p2}) + args + inst: type=mod.A,unsure + + """ + + def __init__(self, project, pattern, goal, args=None, + imports=None, wildcards=None): + """Construct a restructuring + + See class pydoc for more info about the arguments. + + """ + self.pycore = project.pycore + self.pattern = pattern + self.goal = goal + self.args = args + if self.args is None: + self.args = {} + self.imports = imports + if self.imports is None: + self.imports = [] + self.wildcards = wildcards + self.template = similarfinder.CodeTemplate(self.goal) + + def get_changes(self, checks=None, imports=None, resources=None, + task_handle=taskhandle.NullTaskHandle()): + """Get the changes needed by this restructuring + + `resources` can be a list of `rope.base.resources.File`\s to + apply the restructuring on. If `None`, the restructuring will + be applied to all python files. + + `checks` argument has been deprecated. Use the `args` argument + of the constructor. The usage of:: + + strchecks = {'obj1.type': 'mod.A', 'obj2': 'mod.B', + 'obj3.object': 'mod.C'} + checks = restructuring.make_checks(strchecks) + + can be replaced with:: + + args = {'obj1': 'type=mod.A', 'obj2': 'name=mod.B', + 'obj3': 'object=mod.C'} + + where obj1, obj2 and obj3 are wildcard names that appear + in restructuring pattern. + + """ + if checks is not None: + warnings.warn( + 'The use of checks parameter is deprecated; ' + 'use the args parameter of the constructor instead.', + DeprecationWarning, stacklevel=2) + for name, value in checks.items(): + self.args[name] = similarfinder._pydefined_to_str(value) + if imports is not None: + warnings.warn( + 'The use of imports parameter is deprecated; ' + 'use imports parameter of the constructor, instead.', + DeprecationWarning, stacklevel=2) + self.imports = imports + changes = change.ChangeSet('Restructuring <%s> to <%s>' % + (self.pattern, self.goal)) + if resources is not None: + files = [resource for resource in resources + if self.pycore.is_python_file(resource)] + else: + files = self.pycore.get_python_files() + job_set = task_handle.create_jobset('Collecting Changes', len(files)) + for resource in files: + job_set.started_job(resource.path) + pymodule = self.pycore.resource_to_pyobject(resource) + finder = similarfinder.SimilarFinder(pymodule, + wildcards=self.wildcards) + matches = list(finder.get_matches(self.pattern, self.args)) + computer = self._compute_changes(matches, pymodule) + result = computer.get_changed() + if result is not None: + imported_source = self._add_imports(resource, result, + self.imports) + changes.add_change(change.ChangeContents(resource, + imported_source)) + job_set.finished_job() + return changes + + def _compute_changes(self, matches, pymodule): + return _ChangeComputer( + pymodule.source_code, pymodule.get_ast(), + pymodule.lines, self.template, matches) + + def _add_imports(self, resource, source, imports): + if not imports: + return source + import_infos = self._get_import_infos(resource, imports) + pymodule = self.pycore.get_string_module(source, resource) + imports = module_imports.ModuleImports(self.pycore, pymodule) + for import_info in import_infos: + imports.add_import(import_info) + return imports.get_changed_source() + + def _get_import_infos(self, resource, imports): + pymodule = self.pycore.get_string_module('\n'.join(imports), + resource) + imports = module_imports.ModuleImports(self.pycore, pymodule) + return [imports.import_info + for imports in imports.imports] + + def make_checks(self, string_checks): + """Convert str to str dicts to str to PyObject dicts + + This function is here to ease writing a UI. + + """ + checks = {} + for key, value in string_checks.items(): + is_pyname = not key.endswith('.object') and \ + not key.endswith('.type') + evaluated = self._evaluate(value, is_pyname=is_pyname) + if evaluated is not None: + checks[key] = evaluated + return checks + + def _evaluate(self, code, is_pyname=True): + attributes = code.split('.') + pyname = None + if attributes[0] in ('__builtin__', '__builtins__'): + class _BuiltinsStub(object): + def get_attribute(self, name): + return builtins.builtins[name] + pyobject = _BuiltinsStub() + else: + pyobject = self.pycore.get_module(attributes[0]) + for attribute in attributes[1:]: + pyname = pyobject[attribute] + if pyname is None: + return None + pyobject = pyname.get_object() + return pyname if is_pyname else pyobject + + +def replace(code, pattern, goal): + """used by other refactorings""" + finder = similarfinder.RawSimilarFinder(code) + matches = list(finder.get_matches(pattern)) + ast = patchedast.get_patched_ast(code) + lines = codeanalyze.SourceLinesAdapter(code) + template = similarfinder.CodeTemplate(goal) + computer = _ChangeComputer(code, ast, lines, template, matches) + result = computer.get_changed() + if result is None: + return code + return result + + +class _ChangeComputer(object): + + def __init__(self, code, ast, lines, goal, matches): + self.source = code + self.goal = goal + self.matches = matches + self.ast = ast + self.lines = lines + self.matched_asts = {} + self._nearest_roots = {} + if self._is_expression(): + for match in self.matches: + self.matched_asts[match.ast] = match + + def get_changed(self): + if self._is_expression(): + result = self._get_node_text(self.ast) + if result == self.source: + return None + return result + else: + collector = codeanalyze.ChangeCollector(self.source) + last_end = -1 + for match in self.matches: + start, end = match.get_region() + if start < last_end: + if not self._is_expression(): + continue + last_end = end + replacement = self._get_matched_text(match) + collector.add_change(start, end, replacement) + return collector.get_changed() + + def _is_expression(self): + return self.matches and isinstance(self.matches[0], + similarfinder.ExpressionMatch) + + def _get_matched_text(self, match): + mapping = {} + for name in self.goal.get_names(): + node = match.get_ast(name) + if node is None: + raise similarfinder.BadNameInCheckError( + 'Unknown name <%s>' % name) + force = self._is_expression() and match.ast == node + mapping[name] = self._get_node_text(node, force) + unindented = self.goal.substitute(mapping) + return self._auto_indent(match.get_region()[0], unindented) + + def _get_node_text(self, node, force=False): + if not force and node in self.matched_asts: + return self._get_matched_text(self.matched_asts[node]) + start, end = patchedast.node_region(node) + main_text = self.source[start:end] + collector = codeanalyze.ChangeCollector(main_text) + for node in self._get_nearest_roots(node): + sub_start, sub_end = patchedast.node_region(node) + collector.add_change(sub_start - start, sub_end - start, + self._get_node_text(node)) + result = collector.get_changed() + if result is None: + return main_text + return result + + def _auto_indent(self, offset, text): + lineno = self.lines.get_line_number(offset) + indents = sourceutils.get_indents(self.lines, lineno) + result = [] + for index, line in enumerate(text.splitlines(True)): + if index != 0 and line.strip(): + result.append(' ' * indents) + result.append(line) + return ''.join(result) + + def _get_nearest_roots(self, node): + if node not in self._nearest_roots: + result = [] + for child in ast.get_child_nodes(node): + if child in self.matched_asts: + result.append(child) + else: + result.extend(self._get_nearest_roots(child)) + self._nearest_roots[node] = result + return self._nearest_roots[node] diff -r e30544496575 -r 48cacfdc2ca6 vim/sadness/ropevim/src/rope/rope/refactor/similarfinder.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vim/sadness/ropevim/src/rope/rope/refactor/similarfinder.py Wed Oct 06 12:30:46 2010 -0400 @@ -0,0 +1,362 @@ +"""This module can be used for finding similar code""" +import re + +import rope.refactor.wildcards +from rope.base import codeanalyze, evaluate, exceptions, ast, builtins +from rope.refactor import (patchedast, sourceutils, occurrences, + wildcards, importutils) + + +class BadNameInCheckError(exceptions.RefactoringError): + pass + + +class SimilarFinder(object): + """`SimilarFinder` can be used to find similar pieces of code + + See the notes in the `rope.refactor.restructure` module for more + info. + + """ + + def __init__(self, pymodule, wildcards=None): + """Construct a SimilarFinder""" + self.source = pymodule.source_code + self.raw_finder = RawSimilarFinder( + pymodule.source_code, pymodule.get_ast(), self._does_match) + self.pymodule = pymodule + if wildcards is None: + self.wildcards = {} + for wildcard in [rope.refactor.wildcards. + DefaultWildcard(pymodule.pycore.project)]: + self.wildcards[wildcard.get_name()] = wildcard + else: + self.wildcards = wildcards + + def get_matches(self, code, args={}, start=0, end=None): + self.args = args + if end is None: + end = len(self.source) + skip_region = None + if 'skip' in args.get('', {}): + resource, region = args['']['skip'] + if resource == self.pymodule.get_resource(): + skip_region = region + return self.raw_finder.get_matches(code, start=start, end=end, + skip=skip_region) + + def get_match_regions(self, *args, **kwds): + for match in self.get_matches(*args, **kwds): + yield match.get_region() + + def _does_match(self, node, name): + arg = self.args.get(name, '') + kind = 'default' + if isinstance(arg, (tuple, list)): + kind = arg[0] + arg = arg[1] + suspect = wildcards.Suspect(self.pymodule, node, name) + return self.wildcards[kind].matches(suspect, arg) + + +class RawSimilarFinder(object): + """A class for finding similar expressions and statements""" + + def __init__(self, source, node=None, does_match=None): + if node is None: + node = ast.parse(source) + if does_match is None: + self.does_match = self._simple_does_match + else: + self.does_match = does_match + self._init_using_ast(node, source) + + def _simple_does_match(self, node, name): + return isinstance(node, (ast.expr, ast.Name)) + + def _init_using_ast(self, node, source): + self.source = source + self._matched_asts = {} + if not hasattr(node, 'region'): + patchedast.patch_ast(node, source) + self.ast = node + + def get_matches(self, code, start=0, end=None, skip=None): + """Search for `code` in source and return a list of `Match`\es + + `code` can contain wildcards. ``${name}`` matches normal + names and ``${?name} can match any expression. You can use + `Match.get_ast()` for getting the node that has matched a + given pattern. + + """ + if end is None: + end = len(self.source) + for match in self._get_matched_asts(code): + match_start, match_end = match.get_region() + if start <= match_start and match_end <= end: + if skip is not None and (skip[0] < match_end and + skip[1] > match_start): + continue + yield match + + def _get_matched_asts(self, code): + if code not in self._matched_asts: + wanted = self._create_pattern(code) + matches = _ASTMatcher(self.ast, wanted, + self.does_match).find_matches() + self._matched_asts[code] = matches + return self._matched_asts[code] + + def _create_pattern(self, expression): + expression = self._replace_wildcards(expression) + node = ast.parse(expression) + # Getting Module.Stmt.nodes + nodes = node.body + if len(nodes) == 1 and isinstance(nodes[0], ast.Expr): + # Getting Discard.expr + wanted = nodes[0].value + else: + wanted = nodes + return wanted + + def _replace_wildcards(self, expression): + ropevar = _RopeVariable() + template = CodeTemplate(expression) + mapping = {} + for name in template.get_names(): + mapping[name] = ropevar.get_var(name) + return template.substitute(mapping) + + +class _ASTMatcher(object): + + def __init__(self, body, pattern, does_match): + """Searches the given pattern in the body AST. + + body is an AST node and pattern can be either an AST node or + a list of ASTs nodes + """ + self.body = body + self.pattern = pattern + self.matches = None + self.ropevar = _RopeVariable() + self.matches_callback = does_match + + def find_matches(self): + if self.matches is None: + self.matches = [] + ast.call_for_nodes(self.body, self._check_node, recursive=True) + return self.matches + + def _check_node(self, node): + if isinstance(self.pattern, list): + self._check_statements(node) + else: + self._check_expression(node) + + def _check_expression(self, node): + mapping = {} + if self._match_nodes(self.pattern, node, mapping): + self.matches.append(ExpressionMatch(node, mapping)) + + def _check_statements(self, node): + for child in ast.get_children(node): + if isinstance(child, (list, tuple)): + self.__check_stmt_list(child) + + def __check_stmt_list(self, nodes): + for index in range(len(nodes)): + if len(nodes) - index >= len(self.pattern): + current_stmts = nodes[index:index + len(self.pattern)] + mapping = {} + if self._match_stmts(current_stmts, mapping): + self.matches.append(StatementMatch(current_stmts, mapping)) + + def _match_nodes(self, expected, node, mapping): + if isinstance(expected, ast.Name): + if self.ropevar.is_var(expected.id): + return self._match_wildcard(expected, node, mapping) + if not isinstance(expected, ast.AST): + return expected == node + if expected.__class__ != node.__class__: + return False + + children1 = self._get_children(expected) + children2 = self._get_children(node) + if len(children1) != len(children2): + return False + for child1, child2 in zip(children1, children2): + if isinstance(child1, ast.AST): + if not self._match_nodes(child1, child2, mapping): + return False + elif isinstance(child1, (list, tuple)): + if not isinstance(child2, (list, tuple)) or \ + len(child1) != len(child2): + return False + for c1, c2 in zip(child1, child2): + if not self._match_nodes(c1, c2, mapping): + return False + else: + if child1 != child2: + return False + return True + + def _get_children(self, node): + """Return not `ast.expr_context` children of `node`""" + children = ast.get_children(node) + return [child for child in children + if not isinstance(child, ast.expr_context)] + + def _match_stmts(self, current_stmts, mapping): + if len(current_stmts) != len(self.pattern): + return False + for stmt, expected in zip(current_stmts, self.pattern): + if not self._match_nodes(expected, stmt, mapping): + return False + return True + + def _match_wildcard(self, node1, node2, mapping): + name = self.ropevar.get_base(node1.id) + if name not in mapping: + if self.matches_callback(node2, name): + mapping[name] = node2 + return True + return False + else: + return self._match_nodes(mapping[name], node2, {}) + + +class Match(object): + + def __init__(self, mapping): + self.mapping = mapping + + def get_region(self): + """Returns match region""" + + def get_ast(self, name): + """Return the ast node that has matched rope variables""" + return self.mapping.get(name, None) + + +class ExpressionMatch(Match): + + def __init__(self, ast, mapping): + super(ExpressionMatch, self).__init__(mapping) + self.ast = ast + + def get_region(self): + return self.ast.region + + +class StatementMatch(Match): + + def __init__(self, ast_list, mapping): + super(StatementMatch, self).__init__(mapping) + self.ast_list = ast_list + + def get_region(self): + return self.ast_list[0].region[0], self.ast_list[-1].region[1] + + +class CodeTemplate(object): + + def __init__(self, template): + self.template = template + self._find_names() + + def _find_names(self): + self.names = {} + for match in CodeTemplate._get_pattern().finditer(self.template): + if 'name' in match.groupdict() and \ + match.group('name') is not None: + start, end = match.span('name') + name = self.template[start + 2:end - 1] + if name not in self.names: + self.names[name] = [] + self.names[name].append((start, end)) + + def get_names(self): + return self.names.keys() + + def substitute(self, mapping): + collector = codeanalyze.ChangeCollector(self.template) + for name, occurrences in self.names.items(): + for region in occurrences: + collector.add_change(region[0], region[1], mapping[name]) + result = collector.get_changed() + if result is None: + return self.template + return result + + _match_pattern = None + + @classmethod + def _get_pattern(cls): + if cls._match_pattern is None: + pattern = codeanalyze.get_comment_pattern() + '|' + \ + codeanalyze.get_string_pattern() + '|' + \ + r'(?P\$\{[^\s\$\}]*\})' + cls._match_pattern = re.compile(pattern) + return cls._match_pattern + + +class _RopeVariable(object): + """Transform and identify rope inserted wildcards""" + + _normal_prefix = '__rope__variable_normal_' + _any_prefix = '__rope__variable_any_' + + def get_var(self, name): + if name.startswith('?'): + return self._get_any(name) + else: + return self._get_normal(name) + + def is_var(self, name): + return self._is_normal(name) or self._is_var(name) + + def get_base(self, name): + if self._is_normal(name): + return name[len(self._normal_prefix):] + if self._is_var(name): + return '?' + name[len(self._any_prefix):] + + def _get_normal(self, name): + return self._normal_prefix + name + + def _get_any(self, name): + return self._any_prefix + name[1:] + + def _is_normal(self, name): + return name.startswith(self._normal_prefix) + + def _is_var(self, name): + return name.startswith(self._any_prefix) + + +def make_pattern(code, variables): + variables = set(variables) + collector = codeanalyze.ChangeCollector(code) + def does_match(node, name): + return isinstance(node, ast.Name) and node.id == name + finder = RawSimilarFinder(code, does_match=does_match) + for variable in variables: + for match in finder.get_matches('${%s}' % variable): + start, end = match.get_region() + collector.add_change(start, end, '${%s}' % variable) + result = collector.get_changed() + return result if result is not None else code + + +def _pydefined_to_str(pydefined): + address = [] + if isinstance(pydefined, (builtins.BuiltinClass, builtins.BuiltinFunction)): + return '__builtins__.' + pydefined.get_name() + else: + while pydefined.parent is not None: + address.insert(0, pydefined.get_name()) + pydefined = pydefined.parent + module_name = pydefined.pycore.modname(pydefined.resource) + return '.'.join(module_name.split('.') + address) diff -r e30544496575 -r 48cacfdc2ca6 vim/sadness/ropevim/src/rope/rope/refactor/sourceutils.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vim/sadness/ropevim/src/rope/rope/refactor/sourceutils.py Wed Oct 06 12:30:46 2010 -0400 @@ -0,0 +1,92 @@ +from rope.base import ast, codeanalyze + + +def get_indents(lines, lineno): + return codeanalyze.count_line_indents(lines.get_line(lineno)) + + +def find_minimum_indents(source_code): + result = 80 + lines = source_code.split('\n') + for line in lines: + if line.strip() == '': + continue + result = min(result, codeanalyze.count_line_indents(line)) + return result + + +def indent_lines(source_code, amount): + if amount == 0: + return source_code + lines = source_code.splitlines(True) + result = [] + for l in lines: + if l.strip() == '': + result.append('\n') + continue + if amount < 0: + indents = codeanalyze.count_line_indents(l) + result.append(max(0, indents + amount) * ' ' + l.lstrip()) + else: + result.append(' ' * amount + l) + return ''.join(result) + + +def fix_indentation(code, new_indents): + """Change the indentation of `code` to `new_indents`""" + min_indents = find_minimum_indents(code) + return indent_lines(code, new_indents - min_indents) + + +def add_methods(pymodule, class_scope, methods_sources): + source_code = pymodule.source_code + lines = pymodule.lines + insertion_line = class_scope.get_end() + if class_scope.get_scopes(): + insertion_line = class_scope.get_scopes()[-1].get_end() + insertion_offset = lines.get_line_end(insertion_line) + methods = '\n\n' + '\n\n'.join(methods_sources) + indented_methods = fix_indentation( + methods, get_indents(lines, class_scope.get_start()) + + get_indent(pymodule.pycore)) + result = [] + result.append(source_code[:insertion_offset]) + result.append(indented_methods) + result.append(source_code[insertion_offset:]) + return ''.join(result) + + +def get_body(pyfunction): + """Return unindented function body""" + scope = pyfunction.get_scope() + pymodule = pyfunction.get_module() + start, end = get_body_region(pyfunction) + return fix_indentation(pymodule.source_code[start:end], 0) + + +def get_body_region(defined): + """Return the start and end offsets of function body""" + scope = defined.get_scope() + pymodule = defined.get_module() + lines = pymodule.lines + node = defined.get_ast() + start_line = node.lineno + if defined.get_doc() is None: + start_line = node.body[0].lineno + elif len(node.body) > 1: + start_line = node.body[1].lineno + start = lines.get_line_start(start_line) + scope_start = pymodule.logical_lines.logical_line_in(scope.start) + if scope_start[1] >= start_line: + # a one-liner! + # XXX: what if colon appears in a string + start = pymodule.source_code.index(':', start) + 1 + while pymodule.source_code[start].isspace(): + start += 1 + end = min(lines.get_line_end(scope.end) + 1, len(pymodule.source_code)) + return start, end + + +def get_indent(pycore): + project = pycore.project + return project.prefs.get('indent_size', 4) diff -r e30544496575 -r 48cacfdc2ca6 vim/sadness/ropevim/src/rope/rope/refactor/suites.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vim/sadness/ropevim/src/rope/rope/refactor/suites.py Wed Oct 06 12:30:46 2010 -0400 @@ -0,0 +1,142 @@ +from rope.base import ast + + +def find_visible(node, lines): + """Return the line which is visible from all `lines`""" + root = ast_suite_tree(node) + return find_visible_for_suite(root, lines) + + +def find_visible_for_suite(root, lines): + if len(lines) == 1: + return lines[0] + line1 = lines[0] + line2 = find_visible_for_suite(root, lines[1:]) + suite1 = root.find_suite(line1) + suite2 = root.find_suite(line2) + def valid(suite): + return suite is not None and not suite.ignored + if valid(suite1) and not valid(suite2): + return line1 + if not valid(suite1) and valid(suite2): + return line2 + if not valid(suite1) and not valid(suite2): + return None + while suite1 != suite2 and suite1.parent != suite2.parent: + if suite1._get_level() < suite2._get_level(): + line2 = suite2.get_start() + suite2 = suite2.parent + elif suite1._get_level() > suite2._get_level(): + line1 = suite1.get_start() + suite1 = suite1.parent + else: + line1 = suite1.get_start() + line2 = suite2.get_start() + suite1 = suite1.parent + suite2 = suite2.parent + if suite1 == suite2: + return min(line1, line2) + return min(suite1.get_start(), suite2.get_start()) + + +def ast_suite_tree(node): + if hasattr(node, 'lineno'): + lineno = node.lineno + else: + lineno = 1 + return Suite(node.body, lineno) + + +class Suite(object): + + def __init__(self, child_nodes, lineno, parent=None, ignored=False): + self.parent = parent + self.lineno = lineno + self.child_nodes = child_nodes + self._children = None + self.ignored = ignored + + def get_start(self): + if self.parent is None: + if self.child_nodes: + return self.local_start() + else: + return 1 + return self.lineno + + def get_children(self): + if self._children is None: + walker = _SuiteWalker(self) + for child in self.child_nodes: + ast.walk(child, walker) + self._children = walker.suites + return self._children + + def local_start(self): + return self.child_nodes[0].lineno + + def local_end(self): + end = self.child_nodes[-1].lineno + if self.get_children(): + end = max(end, self.get_children()[-1].local_end()) + return end + + def find_suite(self, line): + if line is None: + return None + for child in self.get_children(): + if child.local_start() <= line <= child.local_end(): + return child.find_suite(line) + return self + + def _get_level(self): + if self.parent is None: + return 0 + return self.parent._get_level() + 1 + + +class _SuiteWalker(object): + + def __init__(self, suite): + self.suite = suite + self.suites = [] + + def _If(self, node): + self._add_if_like_node(node) + + def _For(self, node): + self._add_if_like_node(node) + + def _While(self, node): + self._add_if_like_node(node) + + def _With(self, node): + self.suites.append(Suite(node.body, node.lineno, self.suite)) + + def _TryFinally(self, node): + if len(node.finalbody) == 1 and \ + isinstance(node.body[0], ast.TryExcept): + self._TryExcept(node.body[0]) + else: + self.suites.append(Suite(node.body, node.lineno, self.suite)) + self.suites.append(Suite(node.finalbody, node.lineno, self.suite)) + + def _TryExcept(self, node): + self.suites.append(Suite(node.body, node.lineno, self.suite)) + for handler in node.handlers: + self.suites.append(Suite(handler.body, node.lineno, self.suite)) + if node.orelse: + self.suites.append(Suite(node.orelse, node.lineno, self.suite)) + + def _add_if_like_node(self, node): + self.suites.append(Suite(node.body, node.lineno, self.suite)) + if node.orelse: + self.suites.append(Suite(node.orelse, node.lineno, self.suite)) + + def _FunctionDef(self, node): + self.suites.append(Suite(node.body, node.lineno, + self.suite, ignored=True)) + + def _ClassDef(self, node): + self.suites.append(Suite(node.body, node.lineno, + self.suite, ignored=True)) diff -r e30544496575 -r 48cacfdc2ca6 vim/sadness/ropevim/src/rope/rope/refactor/topackage.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vim/sadness/ropevim/src/rope/rope/refactor/topackage.py Wed Oct 06 12:30:46 2010 -0400 @@ -0,0 +1,32 @@ +import rope.refactor.importutils +from rope.base.change import ChangeSet, ChangeContents, MoveResource, CreateFolder + + +class ModuleToPackage(object): + + def __init__(self, project, resource): + self.project = project + self.pycore = project.pycore + self.resource = resource + + def get_changes(self): + changes = ChangeSet('Transform <%s> module to package' % + self.resource.path) + new_content = self._transform_relatives_to_absolute(self.resource) + if new_content is not None: + changes.add_change(ChangeContents(self.resource, new_content)) + parent = self.resource.parent + name = self.resource.name[:-3] + changes.add_change(CreateFolder(parent, name)) + parent_path = parent.path + '/' + if not parent.path: + parent_path = '' + new_path = parent_path + '%s/__init__.py' % name + if self.resource.project == self.project: + changes.add_change(MoveResource(self.resource, new_path)) + return changes + + def _transform_relatives_to_absolute(self, resource): + pymodule = self.pycore.resource_to_pyobject(resource) + import_tools = rope.refactor.importutils.ImportTools(self.pycore) + return import_tools.relatives_to_absolutes(pymodule) diff -r e30544496575 -r 48cacfdc2ca6 vim/sadness/ropevim/src/rope/rope/refactor/usefunction.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vim/sadness/ropevim/src/rope/rope/refactor/usefunction.py Wed Oct 06 12:30:46 2010 -0400 @@ -0,0 +1,171 @@ +from rope.base import (change, taskhandle, evaluate, + exceptions, pyobjects, pynames, ast) +from rope.refactor import restructure, sourceutils, similarfinder, importutils + + +class UseFunction(object): + """Try to use a function wherever possible""" + + def __init__(self, project, resource, offset): + self.project = project + self.offset = offset + this_pymodule = project.pycore.resource_to_pyobject(resource) + pyname = evaluate.eval_location(this_pymodule, offset) + if pyname is None: + raise exceptions.RefactoringError('Unresolvable name selected') + self.pyfunction = pyname.get_object() + if not isinstance(self.pyfunction, pyobjects.PyFunction) or \ + not isinstance(self.pyfunction.parent, pyobjects.PyModule): + raise exceptions.RefactoringError( + 'Use function works for global functions, only.') + self.resource = self.pyfunction.get_module().get_resource() + self._check_returns() + + def _check_returns(self): + node = self.pyfunction.get_ast() + if _yield_count(node): + raise exceptions.RefactoringError('Use function should not ' + 'be used on generators.') + returns = _return_count(node) + if returns > 1: + raise exceptions.RefactoringError('usefunction: Function has more ' + 'than one return statement.') + if returns == 1 and not _returns_last(node): + raise exceptions.RefactoringError('usefunction: return should ' + 'be the last statement.') + + def get_changes(self, resources=None, + task_handle=taskhandle.NullTaskHandle()): + if resources is None: + resources = self.project.pycore.get_python_files() + changes = change.ChangeSet('Using function <%s>' % + self.pyfunction.get_name()) + if self.resource in resources: + newresources = list(resources) + newresources.remove(self.resource) + for c in self._restructure(newresources, task_handle).changes: + changes.add_change(c) + if self.resource in resources: + for c in self._restructure([self.resource], task_handle, + others=False).changes: + changes.add_change(c) + return changes + + def get_function_name(self): + return self.pyfunction.get_name() + + def _restructure(self, resources, task_handle, others=True): + body = self._get_body() + pattern = self._make_pattern() + goal = self._make_goal(import_=others) + imports = None + if others: + imports = ['import %s' % self._module_name()] + + body_region = sourceutils.get_body_region(self.pyfunction) + args_value = {'skip': (self.resource, body_region)} + args = {'': args_value} + + restructuring = restructure.Restructure( + self.project, pattern, goal, args=args, imports=imports) + return restructuring.get_changes(resources=resources, + task_handle=task_handle) + + def _find_temps(self): + return find_temps(self.project, self._get_body()) + + def _module_name(self): + return self.project.pycore.modname(self.resource) + + def _make_pattern(self): + params = self.pyfunction.get_param_names() + body = self._get_body() + body = restructure.replace(body, 'return', 'pass') + wildcards = list(params) + wildcards.extend(self._find_temps()) + if self._does_return(): + if self._is_expression(): + replacement = '${%s}' % self._rope_returned + else: + replacement = '%s = ${%s}' % (self._rope_result, + self._rope_returned) + body = restructure.replace( + body, 'return ${%s}' % self._rope_returned, + replacement) + wildcards.append(self._rope_result) + return similarfinder.make_pattern(body, wildcards) + + def _get_body(self): + return sourceutils.get_body(self.pyfunction) + + def _make_goal(self, import_=False): + params = self.pyfunction.get_param_names() + function_name = self.pyfunction.get_name() + if import_: + function_name = self._module_name() + '.' + function_name + goal = '%s(%s)' % (function_name, + ', ' .join(('${%s}' % p) for p in params)) + if self._does_return() and not self._is_expression(): + goal = '${%s} = %s' % (self._rope_result, goal) + return goal + + def _does_return(self): + body = self._get_body() + removed_return = restructure.replace(body, 'return ${result}', '') + return removed_return != body + + def _is_expression(self): + return len(self.pyfunction.get_ast().body) == 1 + + _rope_result = '_rope__result' + _rope_returned = '_rope__returned' + + +def find_temps(project, code): + code = 'def f():\n' + sourceutils.indent_lines(code, 4) + pymodule = project.pycore.get_string_module(code) + result = [] + function_scope = pymodule.get_scope().get_scopes()[0] + for name, pyname in function_scope.get_names().items(): + if isinstance(pyname, pynames.AssignedName): + result.append(name) + return result + + +def _returns_last(node): + return node.body and isinstance(node.body[-1], ast.Return) + +def _yield_count(node): + visitor = _ReturnOrYieldFinder() + visitor.start_walking(node) + return visitor.yields + +def _return_count(node): + visitor = _ReturnOrYieldFinder() + visitor.start_walking(node) + return visitor.returns + +class _ReturnOrYieldFinder(object): + + def __init__(self): + self.returns = 0 + self.yields = 0 + + def _Return(self, node): + self.returns += 1 + + def _Yield(self, node): + self.yields += 1 + + def _FunctionDef(self, node): + pass + + def _ClassDef(self, node): + pass + + def start_walking(self, node): + nodes = [node] + if isinstance(node, ast.FunctionDef): + nodes = ast.get_child_nodes(node) + for child in nodes: + ast.walk(child, self) diff -r e30544496575 -r 48cacfdc2ca6 vim/sadness/ropevim/src/rope/rope/refactor/wildcards.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vim/sadness/ropevim/src/rope/rope/refactor/wildcards.py Wed Oct 06 12:30:46 2010 -0400 @@ -0,0 +1,176 @@ +from rope.base import ast, evaluate, builtins, pyobjects +from rope.refactor import patchedast, occurrences + + +class Wildcard(object): + + def get_name(self): + """Return the name of this wildcard""" + + def matches(self, suspect, arg): + """Return `True` if `suspect` matches this wildcard""" + + +class Suspect(object): + + def __init__(self, pymodule, node, name): + self.name = name + self.pymodule = pymodule + self.node = node + + +class DefaultWildcard(object): + """The default restructuring wildcard + + The argument passed to this wildcard is in the + ``key1=value1,key2=value2,...`` format. Possible keys are: + + * name - for checking the reference + * type - for checking the type + * object - for checking the object + * instance - for checking types but similar to builtin isinstance + * exact - matching only occurrences with the same name as the wildcard + * unsure - matching unsure occurrences + + """ + + def __init__(self, project): + self.project = project + + def get_name(self): + return 'default' + + def matches(self, suspect, arg=''): + args = parse_arg(arg) + + if not self._check_exact(args, suspect): + return False + if not self._check_object(args, suspect): + return False + return True + + def _check_object(self, args, suspect): + kind = None + expected = None + unsure = args.get('unsure', False) + for check in ['name', 'object', 'type', 'instance']: + if check in args: + kind = check + expected = args[check] + if expected is not None: + checker = _CheckObject(self.project, expected, + kind, unsure=unsure) + return checker(suspect.pymodule, suspect.node) + return True + + def _check_exact(self, args, suspect): + node = suspect.node + if args.get('exact'): + if not isinstance(node, ast.Name) or not node.id == suspect.name: + return False + else: + if not isinstance(node, ast.expr): + return False + return True + + +def parse_arg(arg): + if isinstance(arg, dict): + return arg + result = {} + tokens = arg.split(',') + for token in tokens: + if '=' in token: + parts = token.split('=', 1) + result[parts[0].strip()] = parts[1].strip() + else: + result[token.strip()] = True + return result + + +class _CheckObject(object): + + def __init__(self, project, expected, kind='object', unsure=False): + self.project = project + self.kind = kind + self.unsure = unsure + self.expected = self._evaluate(expected) + + def __call__(self, pymodule, node): + pyname = self._evaluate_node(pymodule, node) + if pyname is None or self.expected is None: + return self.unsure + if self._unsure_pyname(pyname, unbound=self.kind=='name'): + return True + if self.kind == 'name': + return self._same_pyname(self.expected, pyname) + else: + pyobject = pyname.get_object() + if self.kind == 'object': + objects = [pyobject] + if self.kind == 'type': + objects = [pyobject.get_type()] + if self.kind == 'instance': + objects = [pyobject] + objects.extend(self._get_super_classes(pyobject)) + objects.extend(self._get_super_classes(pyobject.get_type())) + for pyobject in objects: + if self._same_pyobject(self.expected.get_object(), pyobject): + return True + return False + + def _get_super_classes(self, pyobject): + result = [] + if isinstance(pyobject, pyobjects.AbstractClass): + for superclass in pyobject.get_superclasses(): + result.append(superclass) + result.extend(self._get_super_classes(superclass)) + return result + + def _same_pyobject(self, expected, pyobject): + return expected == pyobject + + def _same_pyname(self, expected, pyname): + return occurrences.same_pyname(expected, pyname) + + def _unsure_pyname(self, pyname, unbound=True): + return self.unsure and occurrences.unsure_pyname(pyname, unbound) + + def _split_name(self, name): + parts = name.split('.') + expression, kind = parts[0], parts[-1] + if len(parts) == 1: + kind = 'name' + return expression, kind + + def _evaluate_node(self, pymodule, node): + scope = pymodule.get_scope().get_inner_scope_for_line(node.lineno) + expression = node + if isinstance(expression, ast.Name) and \ + isinstance(expression.ctx, ast.Store): + start, end = patchedast.node_region(expression) + text = pymodule.source_code[start:end] + return evaluate.eval_str(scope, text) + else: + return evaluate.eval_node(scope, expression) + + def _evaluate(self, code): + attributes = code.split('.') + pyname = None + if attributes[0] in ('__builtin__', '__builtins__'): + class _BuiltinsStub(object): + def get_attribute(self, name): + return builtins.builtins[name] + def __getitem__(self, name): + return builtins.builtins[name] + def __contains__(self, name): + return name in builtins.builtins + pyobject = _BuiltinsStub() + else: + pyobject = self.project.pycore.get_module(attributes[0]) + for attribute in attributes[1:]: + pyname = pyobject[attribute] + if pyname is None: + return None + pyobject = pyname.get_object() + return pyname diff -r e30544496575 -r 48cacfdc2ca6 vim/sadness/ropevim/src/rope/ropetest/__init__.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vim/sadness/ropevim/src/rope/ropetest/__init__.py Wed Oct 06 12:30:46 2010 -0400 @@ -0,0 +1,36 @@ +import sys +import unittest + +import ropetest.projecttest +import ropetest.codeanalyzetest +import ropetest.pycoretest +import ropetest.pyscopestest +import ropetest.objectinfertest +import ropetest.objectdbtest +import ropetest.advanced_oi_test +import ropetest.runmodtest +import ropetest.builtinstest +import ropetest.historytest +import ropetest.simplifytest + + +def suite(): + result = unittest.TestSuite() + result.addTests(ropetest.projecttest.suite()) + result.addTests(ropetest.codeanalyzetest.suite()) + result.addTests(ropetest.pycoretest.suite()) + result.addTests(ropetest.pyscopestest.suite()) + result.addTests(ropetest.objectinfertest.suite()) + result.addTests(ropetest.objectdbtest.suite()) + result.addTests(ropetest.advanced_oi_test.suite()) + result.addTests(ropetest.runmodtest.suite()) + result.addTests(ropetest.builtinstest.suite()) + result.addTests(ropetest.historytest.suite()) + result.addTests(ropetest.simplifytest.suite()) + return result + + +if __name__ == '__main__': + runner = unittest.TextTestRunner() + result = runner.run(suite()) + sys.exit(not result.wasSuccessful()) diff -r e30544496575 -r 48cacfdc2ca6 vim/sadness/ropevim/src/rope/ropetest/advanced_oi_test.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vim/sadness/ropevim/src/rope/ropetest/advanced_oi_test.py Wed Oct 06 12:30:46 2010 -0400 @@ -0,0 +1,740 @@ +import unittest + +import rope.base.oi +import rope.base.libutils +from ropetest import testutils + + +class DynamicOITest(unittest.TestCase): + + def setUp(self): + super(DynamicOITest, self).setUp() + self.project = testutils.sample_project(validate_objectdb=True) + self.pycore = self.project.pycore + + def tearDown(self): + testutils.remove_project(self.project) + super(DynamicOITest, self).tearDown() + + def test_simple_dti(self): + mod = testutils.create_module(self.project, 'mod') + code = 'def a_func(arg):\n return eval("arg")\n' \ + 'a_var = a_func(a_func)\n' + mod.write(code) + self.pycore.run_module(mod).wait_process() + pymod = self.pycore.resource_to_pyobject(mod) + self.assertEquals(pymod['a_func'].get_object(), + pymod['a_var'].get_object()) + + def test_module_dti(self): + mod1 = testutils.create_module(self.project, 'mod1') + mod2 = testutils.create_module(self.project, 'mod2') + code = 'import mod1\ndef a_func(arg):\n return eval("arg")\n' \ + 'a_var = a_func(mod1)\n' + mod2.write(code) + self.pycore.run_module(mod2).wait_process() + pymod2 = self.pycore.resource_to_pyobject(mod2) + self.assertEquals(self.pycore.resource_to_pyobject(mod1), + pymod2['a_var'].get_object()) + + def test_class_from_another_module_dti(self): + mod1 = testutils.create_module(self.project, 'mod1') + mod2 = testutils.create_module(self.project, 'mod2') + code1 = 'class AClass(object):\n pass\n' + code2 = 'from mod1 import AClass\n' \ + '\ndef a_func(arg):\n return eval("arg")\n' \ + 'a_var = a_func(AClass)\n' + mod1.write(code1) + mod2.write(code2) + self.pycore.run_module(mod2).wait_process() + pymod1 = self.pycore.resource_to_pyobject(mod1) + pymod2 = self.pycore.resource_to_pyobject(mod2) + self.assertEquals(pymod2['AClass'].get_object(), + pymod2['a_var'].get_object()) + + + def test_class_dti(self): + mod = testutils.create_module(self.project, 'mod') + code = 'class AClass(object):\n pass\n' \ + '\ndef a_func(arg):\n return eval("arg")\n' \ + 'a_var = a_func(AClass)\n' + mod.write(code) + self.pycore.run_module(mod).wait_process() + pymod = self.pycore.resource_to_pyobject(mod) + self.assertEquals(pymod['AClass'].get_object(), + pymod['a_var'].get_object()) + + def test_instance_dti(self): + mod = testutils.create_module(self.project, 'mod') + code = 'class AClass(object):\n pass\n' \ + '\ndef a_func(arg):\n return eval("arg()")\n' \ + 'a_var = a_func(AClass)\n' + mod.write(code) + self.pycore.run_module(mod).wait_process() + pymod = self.pycore.resource_to_pyobject(mod) + self.assertEquals(pymod['AClass'].get_object(), + pymod['a_var'].get_object().get_type()) + + def test_method_dti(self): + mod = testutils.create_module(self.project, 'mod') + code = 'class AClass(object):\n def a_method(self, arg):\n' \ + ' return eval("arg()")\n' \ + 'an_instance = AClass()\n' \ + 'a_var = an_instance.a_method(AClass)\n' + mod.write(code) + self.pycore.run_module(mod).wait_process() + pymod = self.pycore.resource_to_pyobject(mod) + self.assertEquals(pymod['AClass'].get_object(), + pymod['a_var'].get_object().get_type()) + + def test_function_argument_dti(self): + mod = testutils.create_module(self.project, 'mod') + code = 'def a_func(arg):\n pass\n' \ + 'a_func(a_func)\n' + mod.write(code) + self.pycore.run_module(mod).wait_process() + pyscope = self.pycore.resource_to_pyobject(mod).get_scope() + self.assertEquals(pyscope['a_func'].get_object(), + pyscope.get_scopes()[0]['arg'].get_object()) + + def test_classes_with_the_same_name(self): + mod = testutils.create_module(self.project, 'mod') + code = 'def a_func(arg):\n class AClass(object):\n' \ + ' pass\n return eval("arg")\n' \ + 'class AClass(object):\n pass\n' \ + 'a_var = a_func(AClass)\n' + mod.write(code) + self.pycore.run_module(mod).wait_process() + pymod = self.pycore.resource_to_pyobject(mod) + self.assertEquals(pymod['AClass'].get_object(), + pymod['a_var'].get_object()) + + def test_nested_classes(self): + mod = testutils.create_module(self.project, 'mod') + code = 'def a_func():\n class AClass(object):\n' \ + ' pass\n return AClass\n' \ + 'def another_func(arg):\n return eval("arg")\n' \ + 'a_var = another_func(a_func())\n' + mod.write(code) + self.pycore.run_module(mod).wait_process() + pyscope = self.pycore.resource_to_pyobject(mod).get_scope() + self.assertEquals(pyscope.get_scopes()[0]['AClass'].get_object(), + pyscope['a_var'].get_object()) + + def test_function_argument_dti2(self): + mod = testutils.create_module(self.project, 'mod') + code = 'def a_func(arg, a_builtin_type):\n pass\n' \ + 'a_func(a_func, [])\n' + mod.write(code) + self.pycore.run_module(mod).wait_process() + pyscope = self.pycore.resource_to_pyobject(mod).get_scope() + self.assertEquals(pyscope['a_func'].get_object(), + pyscope.get_scopes()[0]['arg'].get_object()) + + def test_dti_and_concluded_data_invalidation(self): + mod = testutils.create_module(self.project, 'mod') + code = 'def a_func(arg):\n return eval("arg")\n' \ + 'a_var = a_func(a_func)\n' + mod.write(code) + pymod = self.pycore.resource_to_pyobject(mod) + pymod['a_var'].get_object() + self.pycore.run_module(mod).wait_process() + self.assertEquals(pymod['a_func'].get_object(), + pymod['a_var'].get_object()) + + def test_list_objects_and_dynamicoi(self): + mod = testutils.create_module(self.project, 'mod') + code = 'class C(object):\n pass\n' \ + 'def a_func(arg):\n return eval("arg")\n' \ + 'a_var = a_func([C()])[0]\n' + mod.write(code) + self.pycore.run_module(mod).wait_process() + pymod = self.pycore.resource_to_pyobject(mod) + c_class = pymod['C'].get_object() + a_var = pymod['a_var'].get_object() + self.assertEquals(c_class, a_var.get_type()) + + def test_for_loops_and_dynamicoi(self): + mod = testutils.create_module(self.project, 'mod') + code = 'class C(object):\n pass\n' \ + 'def a_func(arg):\n return eval("arg")\n' \ + 'for c in a_func([C()]):\n a_var = c\n' + mod.write(code) + self.pycore.run_module(mod).wait_process() + pymod = self.pycore.resource_to_pyobject(mod) + c_class = pymod['C'].get_object() + a_var = pymod['a_var'].get_object() + self.assertEquals(c_class, a_var.get_type()) + + def test_dict_objects_and_dynamicoi(self): + mod = testutils.create_module(self.project, 'mod') + code = 'class C(object):\n pass\n' \ + 'def a_func(arg):\n return eval("arg")\n' \ + 'a_var = a_func({1: C()})[1]\n' + mod.write(code) + self.pycore.run_module(mod).wait_process() + pymod = self.pycore.resource_to_pyobject(mod) + c_class = pymod['C'].get_object() + a_var = pymod['a_var'].get_object() + self.assertEquals(c_class, a_var.get_type()) + + def test_dict_keys_and_dynamicoi(self): + mod = testutils.create_module(self.project, 'mod') + code = 'class C(object):\n pass\n' \ + 'def a_func(arg):\n return eval("arg")\n' \ + 'a_var = a_func({C(): 1}).keys()[0]\n' + mod.write(code) + self.pycore.run_module(mod).wait_process() + pymod = self.pycore.resource_to_pyobject(mod) + c_class = pymod['C'].get_object() + a_var = pymod['a_var'].get_object() + self.assertEquals(c_class, a_var.get_type()) + + def test_dict_keys_and_dynamicoi2(self): + mod = testutils.create_module(self.project, 'mod') + code = 'class C1(object):\n pass\nclass C2(object):\n pass\n' \ + 'def a_func(arg):\n return eval("arg")\n' \ + 'a, b = a_func((C1(), C2()))\n' + mod.write(code) + self.pycore.run_module(mod).wait_process() + pymod = self.pycore.resource_to_pyobject(mod) + c1_class = pymod['C1'].get_object() + c2_class = pymod['C2'].get_object() + a_var = pymod['a'].get_object() + b_var = pymod['b'].get_object() + self.assertEquals(c1_class, a_var.get_type()) + self.assertEquals(c2_class, b_var.get_type()) + + def test_strs_and_dynamicoi(self): + mod = testutils.create_module(self.project, 'mod') + code = 'def a_func(arg):\n return eval("arg")\n' \ + 'a_var = a_func("hey")\n' + mod.write(code) + self.pycore.run_module(mod).wait_process() + pymod = self.pycore.resource_to_pyobject(mod) + a_var = pymod['a_var'].get_object() + self.assertTrue(isinstance(a_var.get_type(), rope.base.builtins.Str)) + + def test_textual_transformations(self): + mod = testutils.create_module(self.project, 'mod') + code = 'class C(object):\n pass\ndef f():\n pass\na_var = C()\n' \ + 'a_list = [C()]\na_str = "hey"\na_file = open("file.txt")\n' + mod.write(code) + to_pyobject = rope.base.oi.transform.TextualToPyObject(self.project) + to_textual = rope.base.oi.transform.PyObjectToTextual(self.project) + pymod = self.pycore.resource_to_pyobject(mod) + def complex_to_textual(pyobject): + return to_textual.transform( + to_pyobject.transform(to_textual.transform(pyobject))) + for name in ('C', 'f', 'a_var', 'a_list', 'a_str', 'a_file'): + var = pymod[name].get_object() + self.assertEquals(to_textual.transform(var), complex_to_textual(var)) + self.assertEquals(to_textual.transform(pymod), complex_to_textual(pymod)) + enumerate_func = rope.base.builtins.builtins['enumerate'].get_object() + self.assertEquals(to_textual.transform(enumerate_func), + complex_to_textual(enumerate_func)) + + def test_arguments_with_keywords(self): + mod = testutils.create_module(self.project, 'mod') + code = 'class C1(object):\n pass\nclass C2(object):\n pass\n' \ + 'def a_func(arg):\n return eval("arg")\n' \ + 'a = a_func(arg=C1())\nb = a_func(arg=C2())\n' + mod.write(code) + self.pycore.run_module(mod).wait_process() + pymod = self.pycore.resource_to_pyobject(mod) + c1_class = pymod['C1'].get_object() + c2_class = pymod['C2'].get_object() + a_var = pymod['a'].get_object() + b_var = pymod['b'].get_object() + self.assertEquals(c1_class, a_var.get_type()) + self.assertEquals(c2_class, b_var.get_type()) + + def test_a_function_with_different_returns(self): + mod = testutils.create_module(self.project, 'mod') + code = 'class C1(object):\n pass\nclass C2(object):\n pass\n' \ + 'def a_func(arg):\n return eval("arg")\n' \ + 'a = a_func(C1())\nb = a_func(C2())\n' + mod.write(code) + self.pycore.run_module(mod).wait_process() + pymod = self.pycore.resource_to_pyobject(mod) + c1_class = pymod['C1'].get_object() + c2_class = pymod['C2'].get_object() + a_var = pymod['a'].get_object() + b_var = pymod['b'].get_object() + self.assertEquals(c1_class, a_var.get_type()) + self.assertEquals(c2_class, b_var.get_type()) + + def test_a_function_with_different_returns2(self): + mod = testutils.create_module(self.project, 'mod') + code = 'class C1(object):\n pass\nclass C2(object):\n pass\n' \ + 'def a_func(p):\n if p == C1:\n return C1()\n' \ + ' else:\n return C2()\n' \ + 'a = a_func(C1)\nb = a_func(C2)\n' + mod.write(code) + self.pycore.run_module(mod).wait_process() + pymod = self.pycore.resource_to_pyobject(mod) + c1_class = pymod['C1'].get_object() + c2_class = pymod['C2'].get_object() + a_var = pymod['a'].get_object() + b_var = pymod['b'].get_object() + self.assertEquals(c1_class, a_var.get_type()) + self.assertEquals(c2_class, b_var.get_type()) + + def test_ignoring_star_args(self): + mod = testutils.create_module(self.project, 'mod') + code = 'class C1(object):\n pass\nclass C2(object):\n pass\n' \ + 'def a_func(p, *args):\n if p == C1:\n return C1()\n' \ + ' else:\n return C2()\n' \ + 'a = a_func(C1, 1)\nb = a_func(C2, 2)\n' + mod.write(code) + self.pycore.run_module(mod).wait_process() + pymod = self.pycore.resource_to_pyobject(mod) + c1_class = pymod['C1'].get_object() + c2_class = pymod['C2'].get_object() + a_var = pymod['a'].get_object() + b_var = pymod['b'].get_object() + self.assertEquals(c1_class, a_var.get_type()) + self.assertEquals(c2_class, b_var.get_type()) + + def test_ignoring_double_star_args(self): + mod = testutils.create_module(self.project, 'mod') + code = 'class C1(object):\n pass\nclass C2(object):\n pass\n' \ + 'def a_func(p, *kwds, **args):\n if p == C1:\n return C1()\n' \ + ' else:\n return C2()\n' \ + 'a = a_func(C1, kwd=1)\nb = a_func(C2, kwd=2)\n' + mod.write(code) + self.pycore.run_module(mod).wait_process() + pymod = self.pycore.resource_to_pyobject(mod) + c1_class = pymod['C1'].get_object() + c2_class = pymod['C2'].get_object() + a_var = pymod['a'].get_object() + b_var = pymod['b'].get_object() + self.assertEquals(c1_class, a_var.get_type()) + self.assertEquals(c2_class, b_var.get_type()) + + def test_invalidating_data_after_changing(self): + mod = testutils.create_module(self.project, 'mod') + code = 'def a_func(arg):\n return eval("arg")\n' \ + 'a_var = a_func(a_func)\n' + mod.write(code) + self.pycore.run_module(mod).wait_process() + mod.write(code.replace('a_func', 'newfunc')) + mod.write(code) + pymod = self.pycore.resource_to_pyobject(mod) + self.assertNotEquals(pymod['a_func'].get_object(), + pymod['a_var'].get_object()) + + def test_invalidating_data_after_moving(self): + mod2 = testutils.create_module(self.project, 'mod2') + mod2.write('class C(object):\n pass\n') + mod = testutils.create_module(self.project, 'mod') + code = 'import mod2\ndef a_func(arg):\n return eval(arg)\n' \ + 'a_var = a_func("mod2.C")\n' + mod.write(code) + self.pycore.run_module(mod).wait_process() + mod.move('newmod.py') + pymod = self.pycore.get_module('newmod') + pymod2 = self.pycore.resource_to_pyobject(mod2) + self.assertEquals(pymod2['C'].get_object(), + pymod['a_var'].get_object()) + + +class NewStaticOITest(unittest.TestCase): + + def setUp(self): + super(NewStaticOITest, self).setUp() + self.project = testutils.sample_project(validate_objectdb=True) + self.pycore = self.project.pycore + self.mod = testutils.create_module(self.project, 'mod') + + def tearDown(self): + testutils.remove_project(self.project) + super(NewStaticOITest, self).tearDown() + + def test_static_oi_for_simple_function_calls(self): + code = 'class C(object):\n pass\ndef f(p):\n pass\nf(C())\n' + self.mod.write(code) + self.pycore.analyze_module(self.mod) + pymod = self.pycore.resource_to_pyobject(self.mod) + c_class = pymod['C'].get_object() + f_scope = pymod['f'].get_object().get_scope() + p_type = f_scope['p'].get_object().get_type() + self.assertEquals(c_class, p_type) + + def test_static_oi_not_failing_when_callin_callables(self): + code = 'class C(object):\n pass\nC()\n' + self.mod.write(code) + self.pycore.analyze_module(self.mod) + + def test_static_oi_for_nested_calls(self): + code = 'class C(object):\n pass\ndef f(p):\n pass\n' \ + 'def g(p):\n return p\nf(g(C()))\n' + self.mod.write(code) + self.pycore.analyze_module(self.mod) + pymod = self.pycore.resource_to_pyobject(self.mod) + c_class = pymod['C'].get_object() + f_scope = pymod['f'].get_object().get_scope() + p_type = f_scope['p'].get_object().get_type() + self.assertEquals(c_class, p_type) + + def test_static_oi_class_methods(self): + code = 'class C(object):\n def f(self, p):\n pass\n' \ + 'C().f(C())' + self.mod.write(code) + self.pycore.analyze_module(self.mod) + pymod = self.pycore.resource_to_pyobject(self.mod) + c_class = pymod['C'].get_object() + f_scope = c_class['f'].get_object().get_scope() + p_type = f_scope['p'].get_object().get_type() + self.assertEquals(c_class, p_type) + + def test_static_oi_preventing_soi_maximum_recursion_exceptions(self): + code = 'item = {}\nfor item in item.keys():\n pass\n' + self.mod.write(code) + try: + self.pycore.analyze_module(self.mod) + except RuntimeError, e: + self.fail(str(e)) + + def test_static_oi_for_infering_returned_types_from_functions_based_on_parameters(self): + code = 'class C(object):\n pass\ndef func(p):\n return p\n' \ + 'a_var = func(C())\n' + self.mod.write(code) + pymod = self.pycore.resource_to_pyobject(self.mod) + c_class = pymod['C'].get_object() + a_var = pymod['a_var'].get_object() + self.assertEquals(c_class, a_var.get_type()) + + def test_a_function_with_different_returns(self): + code = 'class C1(object):\n pass\nclass C2(object):\n pass\n' \ + 'def a_func(arg):\n return arg\n' \ + 'a = a_func(C1())\nb = a_func(C2())\n' + self.mod.write(code) + pymod = self.pycore.resource_to_pyobject(self.mod) + c1_class = pymod['C1'].get_object() + c2_class = pymod['C2'].get_object() + a_var = pymod['a'].get_object() + b_var = pymod['b'].get_object() + self.assertEquals(c1_class, a_var.get_type()) + self.assertEquals(c2_class, b_var.get_type()) + + def test_not_reporting_out_of_date_information(self): + code = 'class C1(object):\n pass\n' \ + 'def f(arg):\n return C1()\na_var = f('')\n' + self.mod.write(code) + pymod = self.pycore.resource_to_pyobject(self.mod) + c1_class = pymod['C1'].get_object() + a_var = pymod['a_var'].get_object() + self.assertEquals(c1_class, a_var.get_type()) + + self.mod.write(code.replace('C1', 'C2')) + pymod = self.pycore.resource_to_pyobject(self.mod) + c2_class = pymod['C2'].get_object() + a_var = pymod['a_var'].get_object() + self.assertEquals(c2_class, a_var.get_type()) + + def test_invalidating_concluded_data_in_a_function(self): + mod1 = testutils.create_module(self.project, 'mod1') + mod2 = testutils.create_module(self.project, 'mod2') + mod1.write('def func(arg):\n temp = arg\n return temp\n') + mod2.write('import mod1\n' + 'class C1(object):\n pass\n' + 'class C2(object):\n pass\n' + 'a_var = mod1.func(C1())\n') + pymod2 = self.pycore.resource_to_pyobject(mod2) + c1_class = pymod2['C1'].get_object() + a_var = pymod2['a_var'].get_object() + self.assertEquals(c1_class, a_var.get_type()) + + mod2.write(mod2.read()[:mod2.read().rfind('C1()')] + 'C2())\n') + pymod2 = self.pycore.resource_to_pyobject(mod2) + c2_class = pymod2['C2'].get_object() + a_var = pymod2['a_var'].get_object() + self.assertEquals(c2_class, a_var.get_type()) + + def test_handling_generator_functions_for_strs(self): + self.mod.write('class C(object):\n pass\ndef f(p):\n yield p()\n' + 'for c in f(C):\n a_var = c\n') + pymod = self.pycore.resource_to_pyobject(self.mod) + c_class = pymod['C'].get_object() + a_var = pymod['a_var'].get_object() + self.assertEquals(c_class, a_var.get_type()) + + # TODO: Returning a generator for functions that yield unknowns + def xxx_test_handling_generator_functions_when_unknown_type_is_yielded(self): + self.mod.write('class C(object):\n pass\ndef f():\n yield eval("C()")\n' + 'a_var = f()\n') + pymod = self.pycore.resource_to_pyobject(self.mod) + a_var = pymod['a_var'].get_object() + self.assertTrue(isinstance(a_var.get_type(), + rope.base.builtins.Generator)) + + def test_static_oi_for_lists_depending_on_append_function(self): + code = 'class C(object):\n pass\nl = list()\n' \ + 'l.append(C())\na_var = l.pop()\n' + self.mod.write(code) + self.pycore.analyze_module(self.mod) + pymod = self.pycore.resource_to_pyobject(self.mod) + c_class = pymod['C'].get_object() + a_var = pymod['a_var'].get_object() + self.assertEquals(c_class, a_var.get_type()) + + def test_static_oi_for_lists_per_object_for_get_item(self): + code = 'class C(object):\n pass\nl = list()\n' \ + 'l.append(C())\na_var = l[0]\n' + self.mod.write(code) + self.pycore.analyze_module(self.mod) + pymod = self.pycore.resource_to_pyobject(self.mod) + c_class = pymod['C'].get_object() + a_var = pymod['a_var'].get_object() + self.assertEquals(c_class, a_var.get_type()) + + def test_static_oi_for_lists_per_object_for_fields(self): + code = 'class C(object):\n pass\n' \ + 'class A(object):\n def __init__(self):\n self.l = []\n' \ + ' def set(self):\n self.l.append(C())\n' \ + 'a = A()\na.set()\na_var = a.l[0]\n' + self.mod.write(code) + self.pycore.analyze_module(self.mod) + pymod = self.pycore.resource_to_pyobject(self.mod) + c_class = pymod['C'].get_object() + a_var = pymod['a_var'].get_object() + self.assertEquals(c_class, a_var.get_type()) + + def test_static_oi_for_lists_per_object_for_set_item(self): + code = 'class C(object):\n pass\nl = [None]\n' \ + 'l[0] = C()\na_var = l[0]\n' + self.mod.write(code) + self.pycore.analyze_module(self.mod) + pymod = self.pycore.resource_to_pyobject(self.mod) + c_class = pymod['C'].get_object() + a_var = pymod['a_var'].get_object() + self.assertEquals(c_class, a_var.get_type()) + + def test_static_oi_for_lists_per_object_for_extending_lists(self): + code = 'class C(object):\n pass\nl = []\n' \ + 'l.append(C())\nl2 = []\nl2.extend(l)\na_var = l2[0]\n' + self.mod.write(code) + self.pycore.analyze_module(self.mod) + pymod = self.pycore.resource_to_pyobject(self.mod) + c_class = pymod['C'].get_object() + a_var = pymod['a_var'].get_object() + self.assertEquals(c_class, a_var.get_type()) + + def test_static_oi_for_lists_per_object_for_iters(self): + code = 'class C(object):\n pass\n' \ + 'l = []\nl.append(C())\n' \ + 'for c in l:\n a_var = c\n' + self.mod.write(code) + self.pycore.analyze_module(self.mod) + pymod = self.pycore.resource_to_pyobject(self.mod) + c_class = pymod['C'].get_object() + a_var = pymod['a_var'].get_object() + self.assertEquals(c_class, a_var.get_type()) + + def test_static_oi_for_dicts_depending_on_append_function(self): + code = 'class C1(object):\n pass\nclass C2(object):\n pass\n' \ + 'd = {}\nd[C1()] = C2()\na, b = d.popitem()\n' + self.mod.write(code) + self.pycore.analyze_module(self.mod) + pymod = self.pycore.resource_to_pyobject(self.mod) + c1_class = pymod['C1'].get_object() + c2_class = pymod['C2'].get_object() + a_var = pymod['a'].get_object() + b_var = pymod['b'].get_object() + self.assertEquals(c1_class, a_var.get_type()) + self.assertEquals(c2_class, b_var.get_type()) + + def test_static_oi_for_dicts_depending_on_for_loops(self): + code = 'class C1(object):\n pass\nclass C2(object):\n pass\n' \ + 'd = {}\nd[C1()] = C2()\nfor k, v in d.items():\n a = k\n b = v\n' + self.mod.write(code) + self.pycore.analyze_module(self.mod) + pymod = self.pycore.resource_to_pyobject(self.mod) + c1_class = pymod['C1'].get_object() + c2_class = pymod['C2'].get_object() + a_var = pymod['a'].get_object() + b_var = pymod['b'].get_object() + self.assertEquals(c1_class, a_var.get_type()) + self.assertEquals(c2_class, b_var.get_type()) + + def test_static_oi_for_dicts_depending_on_update(self): + code = 'class C1(object):\n pass\nclass C2(object):\n pass\n' \ + 'd = {}\nd[C1()] = C2()\nd2 = {}\nd2.update(d)\na, b = d2.popitem()\n' + self.mod.write(code) + self.pycore.analyze_module(self.mod) + pymod = self.pycore.resource_to_pyobject(self.mod) + c1_class = pymod['C1'].get_object() + c2_class = pymod['C2'].get_object() + a_var = pymod['a'].get_object() + b_var = pymod['b'].get_object() + self.assertEquals(c1_class, a_var.get_type()) + self.assertEquals(c2_class, b_var.get_type()) + + def test_static_oi_for_dicts_depending_on_update_on_seqs(self): + code = 'class C1(object):\n pass\nclass C2(object):\n pass\n' \ + 'd = {}\nd.update([(C1(), C2())])\na, b = d.popitem()\n' + self.mod.write(code) + self.pycore.analyze_module(self.mod) + pymod = self.pycore.resource_to_pyobject(self.mod) + c1_class = pymod['C1'].get_object() + c2_class = pymod['C2'].get_object() + a_var = pymod['a'].get_object() + b_var = pymod['b'].get_object() + self.assertEquals(c1_class, a_var.get_type()) + self.assertEquals(c2_class, b_var.get_type()) + + def test_static_oi_for_sets_per_object_for_set_item(self): + code = 'class C(object):\n pass\ns = set()\n' \ + 's.add(C())\na_var = s.pop() \n' + self.mod.write(code) + self.pycore.analyze_module(self.mod) + pymod = self.pycore.resource_to_pyobject(self.mod) + c_class = pymod['C'].get_object() + a_var = pymod['a_var'].get_object() + self.assertEquals(c_class, a_var.get_type()) + + def test_properties_and_calling_get_property(self): + code = 'class C1(object):\n pass\n' \ + 'class C2(object):\n c1 = C1()\n' \ + ' def get_c1(self):\n return self.c1\n' \ + ' p = property(get_c1)\nc2 = C2()\na_var = c2.p\n' + self.mod.write(code) + pymod = self.pycore.resource_to_pyobject(self.mod) + c1_class = pymod['C1'].get_object() + a_var = pymod['a_var'].get_object() + self.assertEquals(c1_class, a_var.get_type()) + + def test_soi_on_constructors(self): + code = 'class C1(object):\n pass\n' \ + 'class C2(object):\n' \ + ' def __init__(self, arg):\n self.attr = arg\n' \ + 'c2 = C2(C1())\na_var = c2.attr' + self.mod.write(code) + self.pycore.analyze_module(self.mod) + pymod = self.pycore.resource_to_pyobject(self.mod) + c1_class = pymod['C1'].get_object() + a_var = pymod['a_var'].get_object() + self.assertEquals(c1_class, a_var.get_type()) + + def test_not_saving_unknown_function_returns(self): + mod2 = testutils.create_module(self.project, 'mod2') + self.mod.write('class C(object):\n pass\nl = []\nl.append(C())\n') + mod2.write('import mod\ndef f():\n return mod.l.pop()\na_var = f()\n') + pymod = self.pycore.resource_to_pyobject(self.mod) + pymod2 = self.pycore.resource_to_pyobject(mod2) + c_class = pymod['C'].get_object() + a_var = pymod2['a_var'] + + self.pycore.analyze_module(mod2) + self.assertNotEquals(c_class, a_var.get_object().get_type()) + + self.pycore.analyze_module(self.mod) + self.assertEquals(c_class, a_var.get_object().get_type()) + + def test_using_the_best_callinfo(self): + code = 'class C1(object):\n pass\n' \ + 'def f(arg1, arg2, arg3):\n pass\n' \ + 'f("", None, C1())\nf("", C1(), None)\n' + self.mod.write(code) + self.pycore.analyze_module(self.mod) + pymod = self.pycore.resource_to_pyobject(self.mod) + c1_class = pymod['C1'].get_object() + f_scope = pymod['f'].get_object().get_scope() + arg2 = f_scope['arg2'].get_object() + self.assertEquals(c1_class, arg2.get_type()) + + def test_call_function_and_parameters(self): + code = 'class A(object):\n def __call__(self, p):\n pass\n' \ + 'A()("")\n' + self.mod.write(code) + self.pycore.analyze_module(self.mod) + scope = self.pycore.resource_to_pyobject(self.mod).get_scope() + p_object = scope.get_scopes()[0].get_scopes()[0]['p'].get_object() + self.assertTrue(isinstance(p_object.get_type(), + rope.base.builtins.Str)) + + def test_report_change_in_libutils(self): + self.project.prefs['automatic_soa'] = True + code = 'class C(object):\n pass\ndef f(p):\n pass\nf(C())\n' + mod_file = open(self.mod.real_path, 'w') + mod_file.write(code) + mod_file.close() + rope.base.libutils.report_change(self.project, self.mod.real_path, '') + pymod = self.pycore.resource_to_pyobject(self.mod) + c_class = pymod['C'].get_object() + f_scope = pymod['f'].get_object().get_scope() + p_type = f_scope['p'].get_object().get_type() + self.assertEquals(c_class, p_type) + + def test_report_libutils_and_analyze_all_modules(self): + code = 'class C(object):\n pass\ndef f(p):\n pass\nf(C())\n' + self.mod.write(code) + rope.base.libutils.analyze_modules(self.project) + pymod = self.pycore.resource_to_pyobject(self.mod) + c_class = pymod['C'].get_object() + f_scope = pymod['f'].get_object().get_scope() + p_type = f_scope['p'].get_object().get_type() + self.assertEquals(c_class, p_type) + + def test_validation_problems_for_objectdb_retrievals(self): + mod1 = testutils.create_module(self.project, 'mod1') + mod2 = testutils.create_module(self.project, 'mod2') + mod1.write('l = []\nvar = l.pop()\n') + mod2.write('import mod1\n\nclass C(object):\n pass\n' + 'mod1.l.append(C())\n') + self.pycore.analyze_module(mod2) + + pymod2 = self.pycore.resource_to_pyobject(mod2) + c_class = pymod2['C'].get_object() + pymod1 = self.pycore.resource_to_pyobject(mod1) + var_pyname = pymod1['var'] + self.assertEquals(c_class, var_pyname.get_object().get_type()) + mod2.write('import mod1\n\nmod1.l.append("")\n') + self.assertNotEquals(c_class, var_pyname.get_object().get_type(), + 'Class `C` no more exists') + + def test_validation_problems_for_changing_builtin_types(self): + mod1 = testutils.create_module(self.project, 'mod1') + mod1.write('l = []\nl.append("")\n') + self.pycore.analyze_module(mod1) + + mod1.write('l = {}\nv = l["key"]\n') + pymod1 = self.pycore.resource_to_pyobject(mod1) + var = pymod1['v'].get_object() + + def test_always_returning_containing_class_for_selfs(self): + code = 'class A(object):\n def f(p):\n return p\n' \ + 'class B(object):\n pass\nb = B()\nb.f()\n' + self.mod.write(code) + self.pycore.analyze_module(self.mod) + pymod = self.pycore.resource_to_pyobject(self.mod) + a_class = pymod['A'].get_object() + f_scope = a_class.get_scope().get_scopes()[0] + p_type = f_scope['p'].get_object().get_type() + self.assertEquals(a_class, p_type) + + def test_following_function_calls_when_asked_to(self): + code = 'class A(object):\n pass\n' \ + 'class C(object):\n' \ + ' def __init__(self, arg):\n' \ + ' self.attr = arg\n' \ + 'def f(p):\n return C(p)\n' \ + 'c = f(A())\nx = c.attr\n' + self.mod.write(code) + self.pycore.analyze_module(self.mod, followed_calls=1) + pymod = self.pycore.resource_to_pyobject(self.mod) + a_class = pymod['A'].get_object() + x_var = pymod['x'].get_object().get_type() + self.assertEquals(a_class, x_var) + + +def suite(): + result = unittest.TestSuite() + result.addTests(unittest.makeSuite(DynamicOITest)) + result.addTests(unittest.makeSuite(NewStaticOITest)) + return result + + +if __name__ == '__main__': + unittest.main() diff -r e30544496575 -r 48cacfdc2ca6 vim/sadness/ropevim/src/rope/ropetest/builtinstest.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vim/sadness/ropevim/src/rope/ropetest/builtinstest.py Wed Oct 06 12:30:46 2010 -0400 @@ -0,0 +1,482 @@ +import unittest + +from rope.base import pyobjects, builtins +from ropetest import testutils + + +class BuiltinTypesTest(unittest.TestCase): + + def setUp(self): + super(BuiltinTypesTest, self).setUp() + self.project = testutils.sample_project() + self.pycore = self.project.pycore + self.mod = testutils.create_module(self.project, 'mod') + + def tearDown(self): + testutils.remove_project(self.project) + super(BuiltinTypesTest, self).tearDown() + + def test_simple_case(self): + self.mod.write('l = []\n') + pymod = self.pycore.resource_to_pyobject(self.mod) + self.assertTrue('append' in pymod['l'].get_object()) + + def test_holding_type_information(self): + self.mod.write('class C(object):\n pass\nl = [C()]\na_var = l.pop()\n') + pymod = self.pycore.resource_to_pyobject(self.mod) + c_class = pymod['C'].get_object() + a_var = pymod['a_var'].get_object() + self.assertEquals(c_class, a_var.get_type()) + + def test_get_items(self): + self.mod.write('class C(object):\n def __getitem__(self, i):\n return C()\n' + 'c = C()\na_var = c[0]') + pymod = self.pycore.resource_to_pyobject(self.mod) + c_class = pymod['C'].get_object() + a_var = pymod['a_var'].get_object() + self.assertEquals(c_class, a_var.get_type()) + + def test_get_items_for_lists(self): + self.mod.write('class C(object):\n pass\nl = [C()]\na_var = l[0]\n') + pymod = self.pycore.resource_to_pyobject(self.mod) + c_class = pymod['C'].get_object() + a_var = pymod['a_var'].get_object() + self.assertEquals(c_class, a_var.get_type()) + + def test_get_items_from_slices(self): + self.mod.write('class C(object):\n pass\nl = [C()]\na_var = l[:].pop()\n') + pymod = self.pycore.resource_to_pyobject(self.mod) + c_class = pymod['C'].get_object() + a_var = pymod['a_var'].get_object() + self.assertEquals(c_class, a_var.get_type()) + + def test_simple_for_loops(self): + self.mod.write('class C(object):\n pass\nl = [C()]\n' + 'for c in l:\n a_var = c\n') + pymod = self.pycore.resource_to_pyobject(self.mod) + c_class = pymod['C'].get_object() + a_var = pymod['a_var'].get_object() + self.assertEquals(c_class, a_var.get_type()) + + def test_definition_location_for_loop_variables(self): + self.mod.write('class C(object):\n pass\nl = [C()]\n' + 'for c in l:\n pass\n') + pymod = self.pycore.resource_to_pyobject(self.mod) + c_var = pymod['c'] + self.assertEquals((pymod, 4), c_var.get_definition_location()) + + def test_simple_case_for_dicts(self): + self.mod.write('d = {}\n') + pymod = self.pycore.resource_to_pyobject(self.mod) + self.assertTrue('get' in pymod['d'].get_object()) + + def test_get_item_for_dicts(self): + self.mod.write('class C(object):\n pass\nd = {1: C()}\na_var = d[1]\n') + pymod = self.pycore.resource_to_pyobject(self.mod) + c_class = pymod['C'].get_object() + a_var = pymod['a_var'].get_object() + self.assertEquals(c_class, a_var.get_type()) + + def test_popping_dicts(self): + self.mod.write('class C(object):\n pass\nd = {1: C()}\na_var = d.pop(1)\n') + pymod = self.pycore.resource_to_pyobject(self.mod) + c_class = pymod['C'].get_object() + a_var = pymod['a_var'].get_object() + self.assertEquals(c_class, a_var.get_type()) + + def test_getting_keys_from_dicts(self): + self.mod.write('class C1(object):\n pass\nclass C2(object):\n pass\n' + 'd = {C1(): C2()}\nfor c in d.keys():\n a_var = c\n') + pymod = self.pycore.resource_to_pyobject(self.mod) + c_class = pymod['C1'].get_object() + a_var = pymod['a_var'].get_object() + self.assertEquals(c_class, a_var.get_type()) + + def test_getting_values_from_dicts(self): + self.mod.write('class C1(object):\n pass\nclass C2(object):\n pass\n' + 'd = {C1(): C2()}\nfor c in d.values():\n a_var = c\n') + pymod = self.pycore.resource_to_pyobject(self.mod) + c_class = pymod['C2'].get_object() + a_var = pymod['a_var'].get_object() + self.assertEquals(c_class, a_var.get_type()) + + def test_getting_iterkeys_from_dicts(self): + self.mod.write('class C1(object):\n pass\nclass C2(object):\n pass\n' + 'd = {C1(): C2()}\nfor c in d.keys():\n a_var = c\n') + pymod = self.pycore.resource_to_pyobject(self.mod) + c_class = pymod['C1'].get_object() + a_var = pymod['a_var'].get_object() + self.assertEquals(c_class, a_var.get_type()) + + def test_getting_itervalues_from_dicts(self): + self.mod.write('class C1(object):\n pass\nclass C2(object):\n pass\n' + 'd = {C1(): C2()}\nfor c in d.values():\n a_var = c\n') + pymod = self.pycore.resource_to_pyobject(self.mod) + c_class = pymod['C2'].get_object() + a_var = pymod['a_var'].get_object() + self.assertEquals(c_class, a_var.get_type()) + + def test_using_copy_for_dicts(self): + self.mod.write('class C1(object):\n pass\nclass C2(object):\n pass\n' + 'd = {C1(): C2()}\nfor c in d.copy():\n a_var = c\n') + pymod = self.pycore.resource_to_pyobject(self.mod) + c_class = pymod['C1'].get_object() + a_var = pymod['a_var'].get_object() + self.assertEquals(c_class, a_var.get_type()) + + def test_tuple_assignments_for_items(self): + self.mod.write('class C1(object):\n pass\nclass C2(object):\n pass\n' + 'd = {C1(): C2()}\nkey, value = d.items()[0]\n') + pymod = self.pycore.resource_to_pyobject(self.mod) + c1_class = pymod['C1'].get_object() + c2_class = pymod['C2'].get_object() + key = pymod['key'].get_object() + value = pymod['value'].get_object() + self.assertEquals(c1_class, key.get_type()) + self.assertEquals(c2_class, value.get_type()) + + def test_tuple_assignment_for_lists(self): + self.mod.write('class C(object):\n pass\nl = [C(), C()]\na, b = l\n') + pymod = self.pycore.resource_to_pyobject(self.mod) + c_class = pymod['C'].get_object() + a_var = pymod['a'].get_object() + b_var = pymod['b'].get_object() + self.assertEquals(c_class, a_var.get_type()) + self.assertEquals(c_class, b_var.get_type()) + + def test_tuple_assignments_for_iteritems_in_fors(self): + self.mod.write('class C1(object):\n pass\nclass C2(object):\n pass\n' + 'd = {C1(): C2()}\nfor x, y in d.items():\n a = x;\n b = y\n') + pymod = self.pycore.resource_to_pyobject(self.mod) + c1_class = pymod['C1'].get_object() + c2_class = pymod['C2'].get_object() + a_var = pymod['a'].get_object() + b_var = pymod['b'].get_object() + self.assertEquals(c1_class, a_var.get_type()) + self.assertEquals(c2_class, b_var.get_type()) + + def test_simple_tuple_assignments(self): + self.mod.write('class C1(object):\n pass\nclass C2(object):\n pass\n' + 'a, b = C1(), C2()\n') + pymod = self.pycore.resource_to_pyobject(self.mod) + c1_class = pymod['C1'].get_object() + c2_class = pymod['C2'].get_object() + a_var = pymod['a'].get_object() + b_var = pymod['b'].get_object() + self.assertEquals(c1_class, a_var.get_type()) + self.assertEquals(c2_class, b_var.get_type()) + + def test_overriding_builtin_names(self): + self.mod.write('class C(object):\n pass\nlist = C\n') + pymod = self.pycore.resource_to_pyobject(self.mod) + c_class = pymod['C'].get_object() + list_var = pymod['list'].get_object() + self.assertEquals(c_class, list_var) + + def test_simple_builtin_scope_test(self): + self.mod.write('l = list()\n') + pymod = self.pycore.resource_to_pyobject(self.mod) + self.assertTrue('append' in pymod['l'].get_object()) + + def test_simple_sets(self): + self.mod.write('s = set()\n') + pymod = self.pycore.resource_to_pyobject(self.mod) + self.assertTrue('add' in pymod['s'].get_object()) + + def test_making_lists_using_the_passed_argument_to_init(self): + self.mod.write('class C(object):\n pass\nl1 = [C()]\n' + 'l2 = list(l1)\na_var = l2.pop()') + pymod = self.pycore.resource_to_pyobject(self.mod) + c_class = pymod['C'].get_object() + a_var = pymod['a_var'].get_object() + self.assertEquals(c_class, a_var.get_type()) + + def test_making_tuples_using_the_passed_argument_to_init(self): + self.mod.write('class C(object):\n pass\nl1 = [C()]\n' + 'l2 = tuple(l1)\na_var = l2[0]') + pymod = self.pycore.resource_to_pyobject(self.mod) + c_class = pymod['C'].get_object() + a_var = pymod['a_var'].get_object() + self.assertEquals(c_class, a_var.get_type()) + + def test_making_sets_using_the_passed_argument_to_init(self): + self.mod.write('class C(object):\n pass\nl1 = [C()]\n' + 'l2 = set(l1)\na_var = l2.pop()') + pymod = self.pycore.resource_to_pyobject(self.mod) + c_class = pymod['C'].get_object() + a_var = pymod['a_var'].get_object() + self.assertEquals(c_class, a_var.get_type()) + + def test_making_dicts_using_the_passed_argument_to_init(self): + self.mod.write('class C1(object):\n pass\nclass C2(object):\n pass\n' + 'l1 = [(C1(), C2())]\n' + 'l2 = dict(l1)\na, b = l2.items()[0]') + pymod = self.pycore.resource_to_pyobject(self.mod) + c1_class = pymod['C1'].get_object() + c2_class = pymod['C2'].get_object() + a_var = pymod['a'].get_object() + b_var = pymod['b'].get_object() + self.assertEquals(c1_class, a_var.get_type()) + self.assertEquals(c2_class, b_var.get_type()) + + def test_range_builtin_function(self): + self.mod.write('l = range(1)\n') + pymod = self.pycore.resource_to_pyobject(self.mod) + l = pymod['l'].get_object() + self.assertTrue('append' in l) + + def test_reversed_builtin_function(self): + self.mod.write('class C(object):\n pass\nl = [C()]\n' + 'for x in reversed(l):\n a_var = x\n') + pymod = self.pycore.resource_to_pyobject(self.mod) + c_class = pymod['C'].get_object() + a_var = pymod['a_var'].get_object() + self.assertEquals(c_class, a_var.get_type()) + + def test_sorted_builtin_function(self): + self.mod.write('class C(object):\n pass\nl = [C()]\n' + 'a_var = sorted(l).pop()\n') + pymod = self.pycore.resource_to_pyobject(self.mod) + c_class = pymod['C'].get_object() + a_var = pymod['a_var'].get_object() + self.assertEquals(c_class, a_var.get_type()) + + def test_super_builtin_function(self): + self.mod.write( + 'class C(object):\n pass\n' + 'class A(object):\n def a_f(self):\n return C()\n' + 'class B(A):\n def b_f(self):\n return super(B, self).a_f()\n' + 'a_var = B.b_f()\n') + pymod = self.pycore.resource_to_pyobject(self.mod) + c_class = pymod['C'].get_object() + a_var = pymod['a_var'].get_object() + self.assertEquals(c_class, a_var.get_type()) + + def test_file_builtin_type(self): + self.mod.write('for line in open("file.txt"):\n a_var = line\n') + pymod = self.pycore.resource_to_pyobject(self.mod) + a_var = pymod['a_var'].get_object() + self.assertTrue(isinstance(a_var.get_type(), builtins.Str)) + + def test_property_builtin_type(self): + self.mod.write('p = property()\n') + pymod = self.pycore.resource_to_pyobject(self.mod) + p_var = pymod['p'].get_object() + self.assertTrue('fget' in p_var) + + def test_lambda_functions(self): + self.mod.write('l = lambda: 1\n') + pymod = self.pycore.resource_to_pyobject(self.mod) + l_var = pymod['l'].get_object() + self.assertEquals(pyobjects.get_base_type('Function'), + l_var.get_type()) + + def test_lambda_function_definition(self): + self.mod.write('l = lambda x, y = 2, *a, **b: x + y\n') + pymod = self.pycore.resource_to_pyobject(self.mod) + l_var = pymod['l'].get_object() + self.assertTrue(l_var.get_name() is not None) + self.assertEquals(len(l_var.get_param_names()), 4) + self.assertEquals((pymod, 1), + pymod['l'].get_definition_location()) + + def test_lambdas_that_return_unknown(self): + self.mod.write('a_var = (lambda: None)()\n') + pymod = self.pycore.resource_to_pyobject(self.mod) + a_var = pymod['a_var'].get_object() + self.assertTrue(a_var is not None) + + def test_builtin_zip_function(self): + self.mod.write( + 'class C1(object):\n pass\nclass C2(object):\n pass\n' + 'c1_list = [C1()]\nc2_list = [C2()]\n' + 'a, b = zip(c1_list, c2_list)[0]') + pymod = self.pycore.resource_to_pyobject(self.mod) + c1_class = pymod['C1'].get_object() + c2_class = pymod['C2'].get_object() + a_var = pymod['a'].get_object() + b_var = pymod['b'].get_object() + self.assertEquals(c1_class, a_var.get_type()) + self.assertEquals(c2_class, b_var.get_type()) + + def test_builtin_zip_function_with_more_than_two_args(self): + self.mod.write( + 'class C1(object):\n pass\nclass C2(object):\n pass\n' + 'c1_list = [C1()]\nc2_list = [C2()]\n' + 'a, b, c = zip(c1_list, c2_list, c1_list)[0]') + pymod = self.pycore.resource_to_pyobject(self.mod) + c1_class = pymod['C1'].get_object() + c2_class = pymod['C2'].get_object() + a_var = pymod['a'].get_object() + b_var = pymod['b'].get_object() + c_var = pymod['c'].get_object() + self.assertEquals(c1_class, a_var.get_type()) + self.assertEquals(c2_class, b_var.get_type()) + self.assertEquals(c1_class, c_var.get_type()) + + def test_wrong_arguments_to_zip_function(self): + self.mod.write( + 'class C1(object):\n pass\nc1_list = [C1()]\n' + 'a, b = zip(c1_list, 1)[0]') + pymod = self.pycore.resource_to_pyobject(self.mod) + c1_class = pymod['C1'].get_object() + a_var = pymod['a'].get_object() + b_var = pymod['b'].get_object() + self.assertEquals(c1_class, a_var.get_type()) + + def test_enumerate_builtin_function(self): + self.mod.write('class C(object):\n pass\nl = [C()]\n' + 'for i, x in enumerate(l):\n a_var = x\n') + pymod = self.pycore.resource_to_pyobject(self.mod) + c_class = pymod['C'].get_object() + a_var = pymod['a_var'].get_object() + self.assertEquals(c_class, a_var.get_type()) + + def test_builtin_class_get_name(self): + self.assertEquals('object', + builtins.builtins['object'].get_object().get_name()) + self.assertEquals('property', + builtins.builtins['property'].get_object().get_name()) + + def test_star_args_and_double_star_args(self): + self.mod.write('def func(p, *args, **kwds):\n pass\n') + pymod = self.pycore.resource_to_pyobject(self.mod) + func_scope = pymod['func'].get_object().get_scope() + args = func_scope['args'].get_object() + kwds = func_scope['kwds'].get_object() + self.assertTrue(isinstance(args.get_type(), builtins.List)) + self.assertTrue(isinstance(kwds.get_type(), builtins.Dict)) + + def test_simple_list_comprehension_test(self): + self.mod.write('a_var = [i for i in range(10)]\n') + pymod = self.pycore.resource_to_pyobject(self.mod) + a_var = pymod['a_var'].get_object() + self.assertTrue(isinstance(a_var.get_type(), builtins.List)) + + def test_simple_list_generator_expression(self): + self.mod.write('a_var = (i for i in range(10))\n') + pymod = self.pycore.resource_to_pyobject(self.mod) + a_var = pymod['a_var'].get_object() + self.assertTrue(isinstance(a_var.get_type(), builtins.Iterator)) + + def test_iter_builtin_function(self): + self.mod.write('class C(object):\n pass\nl = [C()]\n' + 'for c in iter(l):\n a_var = c\n') + pymod = self.pycore.resource_to_pyobject(self.mod) + c_class = pymod['C'].get_object() + a_var = pymod['a_var'].get_object() + self.assertEquals(c_class, a_var.get_type()) + + def test_simple_int_type(self): + self.mod.write('l = 1\n') + pymod = self.pycore.resource_to_pyobject(self.mod) + self.assertEquals(builtins.builtins['int'].get_object(), + pymod['l'].get_object().get_type()) + + def test_simple_float_type(self): + self.mod.write('l = 1.0\n') + pymod = self.pycore.resource_to_pyobject(self.mod) + self.assertEquals(builtins.builtins['float'].get_object(), + pymod['l'].get_object().get_type()) + + def test_simple_float_type2(self): + self.mod.write('l = 1e1\n') + pymod = self.pycore.resource_to_pyobject(self.mod) + self.assertEquals(builtins.builtins['float'].get_object(), + pymod['l'].get_object().get_type()) + + def test_simple_complex_type(self): + self.mod.write('l = 1.0j\n') + pymod = self.pycore.resource_to_pyobject(self.mod) + self.assertEquals(builtins.builtins['complex'].get_object(), + pymod['l'].get_object().get_type()) + + def test_handling_unaryop_on_ints(self): + self.mod.write('l = -(1)\n') + pymod = self.pycore.resource_to_pyobject(self.mod) + self.assertEquals(builtins.builtins['int'].get_object(), + pymod['l'].get_object().get_type()) + + def test_handling_binop_on_ints(self): + self.mod.write('l = 1 + 1\n') + pymod = self.pycore.resource_to_pyobject(self.mod) + self.assertEquals(builtins.builtins['int'].get_object(), + pymod['l'].get_object().get_type()) + + def test_handling_compares(self): + self.mod.write('l = 1 == 1\n') + pymod = self.pycore.resource_to_pyobject(self.mod) + self.assertEquals(builtins.builtins['bool'].get_object(), + pymod['l'].get_object().get_type()) + + def test_handling_boolops(self): + self.mod.write('l = 1 and 2\n') + pymod = self.pycore.resource_to_pyobject(self.mod) + self.assertEquals(builtins.builtins['int'].get_object(), + pymod['l'].get_object().get_type()) + + def test_binary_or_left_value_unknown(self): + code = 'var = (asdsd or 3)\n' + pymod = self.pycore.get_string_module(code) + self.assertEquals(builtins.builtins['int'].get_object(), + pymod['var'].get_object().get_type()) + + def test_unknown_return_object(self): + src = 'import sys\n' \ + 'def foo():\n' \ + ' res = set(sys.builtin_module_names)\n' \ + ' if foo: res.add(bar)\n' + self.project.prefs['import_dynload_stdmods'] = True + self.mod.write(src) + self.project.pycore.analyze_module(self.mod) + + +class BuiltinModulesTest(unittest.TestCase): + + def setUp(self): + super(BuiltinModulesTest, self).setUp() + self.project = testutils.sample_project( + extension_modules=['time', 'invalid', 'invalid.sub']) + self.pycore = self.project.pycore + self.mod = testutils.create_module(self.project, 'mod') + + def tearDown(self): + testutils.remove_project(self.project) + super(BuiltinModulesTest, self).tearDown() + + def test_simple_case(self): + self.mod.write('import time') + pymod = self.pycore.resource_to_pyobject(self.mod) + self.assertTrue('time' in pymod['time'].get_object()) + + def test_ignored_extensions(self): + self.mod.write('import os') + pymod = self.pycore.resource_to_pyobject(self.mod) + self.assertTrue('rename' not in pymod['os'].get_object()) + + def test_ignored_extensions(self): + self.mod.write('import os') + pymod = self.pycore.resource_to_pyobject(self.mod) + self.assertTrue('rename' not in pymod['os'].get_object()) + + def test_nonexistent_modules(self): + self.mod.write('import invalid') + pymod = self.pycore.resource_to_pyobject(self.mod) + pymod['invalid'].get_object() + + def test_nonexistent_modules(self): + self.mod.write('import invalid\nimport invalid.sub') + pymod = self.pycore.resource_to_pyobject(self.mod) + invalid = pymod['invalid'].get_object() + self.assertTrue('sub' in invalid) + + +def suite(): + result = unittest.TestSuite() + result.addTests(unittest.makeSuite(BuiltinTypesTest)) + result.addTests(unittest.makeSuite(BuiltinModulesTest)) + return result + + +if __name__ == '__main__': + unittest.main() diff -r e30544496575 -r 48cacfdc2ca6 vim/sadness/ropevim/src/rope/ropetest/codeanalyzetest.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vim/sadness/ropevim/src/rope/ropetest/codeanalyzetest.py Wed Oct 06 12:30:46 2010 -0400 @@ -0,0 +1,616 @@ +import unittest + +import rope.base.evaluate +from rope.base import exceptions, ast, worder, codeanalyze +from rope.base.codeanalyze import SourceLinesAdapter, LogicalLineFinder, get_block_start +from ropetest import testutils + + +class SourceLinesAdapterTest(unittest.TestCase): + + def setUp(self): + super(SourceLinesAdapterTest, self).setUp() + + def tearDown(self): + super(SourceLinesAdapterTest, self).tearDown() + + def test_source_lines_simple(self): + to_lines = SourceLinesAdapter('line1\nline2\n') + self.assertEquals('line1', to_lines.get_line(1)) + self.assertEquals('line2', to_lines.get_line(2)) + self.assertEquals('', to_lines.get_line(3)) + self.assertEquals(3, to_lines.length()) + + def test_source_lines_get_line_number(self): + to_lines = SourceLinesAdapter('line1\nline2\n') + self.assertEquals(1, to_lines.get_line_number(0)) + self.assertEquals(1, to_lines.get_line_number(5)) + self.assertEquals(2, to_lines.get_line_number(7)) + self.assertEquals(3, to_lines.get_line_number(12)) + + def test_source_lines_get_line_start(self): + to_lines = SourceLinesAdapter('line1\nline2\n') + self.assertEquals(0, to_lines.get_line_start(1)) + self.assertEquals(6, to_lines.get_line_start(2)) + self.assertEquals(12, to_lines.get_line_start(3)) + + def test_source_lines_get_line_end(self): + to_lines = SourceLinesAdapter('line1\nline2\n') + self.assertEquals(5, to_lines.get_line_end(1)) + self.assertEquals(11, to_lines.get_line_end(2)) + self.assertEquals(12, to_lines.get_line_end(3)) + + def test_source_lines_last_line_with_no_new_line(self): + to_lines = SourceLinesAdapter('line1') + self.assertEquals(1, to_lines.get_line_number(5)) + + +class WordRangeFinderTest(unittest.TestCase): + + def setUp(self): + super(WordRangeFinderTest, self).setUp() + + def tearDown(self): + super(WordRangeFinderTest, self).tearDown() + + def _find_primary(self, code, offset): + word_finder = worder.Worder(code) + result = word_finder.get_primary_at(offset) + return result + + def test_keyword_before_parens(self): + code = 'if (a_var).an_attr:\n pass\n' + self.assertEquals('(a_var).an_attr', + self._find_primary(code, code.index(':'))) + + def test_inside_parans(self): + code = 'a_func(a_var)' + self.assertEquals('a_var', self._find_primary(code, 10)) + + def test_simple_names(self): + code = 'a_var = 10' + self.assertEquals('a_var', self._find_primary(code, 3)) + + def test_function_calls(self): + code = 'sample_function()' + self.assertEquals('sample_function', self._find_primary(code, 10)) + + def test_attribute_accesses(self): + code = 'a_var.an_attr' + self.assertEquals('a_var.an_attr', self._find_primary(code, 10)) + + def test_word_finder_on_word_beginning(self): + code = 'print a_var\n' + word_finder = worder.Worder(code) + result = word_finder.get_word_at(code.index('a_var')) + self.assertEquals('a_var', result) + + def test_word_finder_on_primary_beginning(self): + code = 'print a_var\n' + result = self._find_primary(code, code.index('a_var')) + self.assertEquals('a_var', result) + + def test_word_finder_on_word_ending(self): + code = 'print a_var\n' + word_finder = worder.Worder(code) + result = word_finder.get_word_at(code.index('a_var') + 5) + self.assertEquals('a_var', result) + + def test_word_finder_on_primary_ending(self): + code = 'print a_var\n' + result = self._find_primary(code, code.index('a_var') + 5) + self.assertEquals('a_var', result) + + def test_word_finder_on_primaries_with_dots_inside_parens(self): + code = '(a_var.\nattr)' + result = self._find_primary(code, code.index('attr') + 1) + self.assertEquals('a_var.\nattr', result) + + def test_strings(self): + code = '"a string".split()' + self.assertEquals('"a string".split', self._find_primary(code, 14)) + + def test_function_calls2(self): + code = 'file("afile.txt").read()' + self.assertEquals('file("afile.txt").read', self._find_primary(code, 18)) + + def test_parens(self): + code = '("afile.txt").split()' + self.assertEquals('("afile.txt").split', self._find_primary(code, 18)) + + def test_function_with_no_param(self): + code = 'AClass().a_func()' + self.assertEquals('AClass().a_func', self._find_primary(code, 12)) + + def test_function_with_multiple_param(self): + code = 'AClass(a_param, another_param, "a string").a_func()' + self.assertEquals('AClass(a_param, another_param, "a string").a_func', + self._find_primary(code, 44)) + + def test_param_expressions(self): + code = 'AClass(an_object.an_attr).a_func()' + self.assertEquals('an_object.an_attr', self._find_primary(code, 20)) + + def test_string_parens(self): + code = 'a_func("(").an_attr' + self.assertEquals('a_func("(").an_attr', self._find_primary(code, 16)) + + def test_extra_spaces(self): + code = 'a_func ( "(" ) . an_attr' + self.assertEquals('a_func ( "(" ) . an_attr', + self._find_primary(code, 26)) + + def test_functions_on_ending_parens(self): + code = 'A()' + self.assertEquals('A()', self._find_primary(code, 2)) + + def test_splitted_statement(self): + word_finder = worder.Worder('an_object.an_attr') + self.assertEquals(('an_object', 'an_at', 10), + word_finder.get_splitted_primary_before(15)) + + def test_empty_splitted_statement(self): + word_finder = worder.Worder('an_attr') + self.assertEquals(('', 'an_at', 0), + word_finder.get_splitted_primary_before(5)) + + def test_empty_splitted_statement2(self): + word_finder = worder.Worder('an_object.') + self.assertEquals(('an_object', '', 10), + word_finder.get_splitted_primary_before(10)) + + def test_empty_splitted_statement3(self): + word_finder = worder.Worder('') + self.assertEquals(('', '', 0), + word_finder.get_splitted_primary_before(0)) + + def test_empty_splitted_statement4(self): + word_finder = worder.Worder('a_var = ') + self.assertEquals(('', '', 8), + word_finder.get_splitted_primary_before(8)) + + def test_empty_splitted_statement5(self): + word_finder = worder.Worder('a.') + self.assertEquals(('a', '', 2), + word_finder.get_splitted_primary_before(2)) + + def test_operators_inside_parens(self): + code = '(a_var + another_var).reverse()' + self.assertEquals('(a_var + another_var).reverse', + self._find_primary(code, 25)) + + def test_dictionaries(self): + code = 'print {1: "one", 2: "two"}.keys()' + self.assertEquals('{1: "one", 2: "two"}.keys', + self._find_primary(code, 29)) + + def test_following_parens(self): + code = 'a_var = a_func()()' + result = self._find_primary(code, code.index(')(') + 3) + self.assertEquals('a_func()()', result) + + def test_comments_for_finding_statements(self): + code = '# var2 . \n var3' + self.assertEquals('var3', self._find_primary(code, code.index('3'))) + + def test_str_in_comments_for_finding_statements(self): + code = '# "var2" . \n var3' + self.assertEquals('var3', self._find_primary(code, code.index('3'))) + + def test_comments_for_finding_statements2(self): + code = 'var1 + "# var2".\n var3' + self.assertEquals('var3', self._find_primary(code, 21)) + + def test_comments_for_finding_statements3(self): + code = '"" + # var2.\n var3' + self.assertEquals('var3', self._find_primary(code, 21)) + + def test_import_statement_finding(self): + code = 'import mod\na_var = 10\n' + word_finder = worder.Worder(code) + self.assertTrue(word_finder.is_import_statement(code.index('mod') + 1)) + self.assertFalse(word_finder.is_import_statement(code.index('a_var') + 1)) + + def test_import_statement_finding2(self): + code = 'import a.b.c.d\nresult = a.b.c.d.f()\n' + word_finder = worder.Worder(code) + self.assertFalse(word_finder.is_import_statement(code.rindex('d') + 1)) + + def test_word_parens_range(self): + code = 's = str()\ns.title()\n' + word_finder = worder.Worder(code) + result = word_finder.get_word_parens_range(code.rindex('()') - 1) + self.assertEquals((len(code) - 3, len(code) - 1), result) + + def test_getting_primary_before_get_index(self): + code = '\na = (b + c).d[0]()\n' + result = self._find_primary(code, len(code) - 2) + self.assertEquals('(b + c).d[0]()', result) + + def test_getting_primary_and_strings_at_the_end_of_line(self): + code = 'f(\'\\\'\')\n' + result = self._find_primary(code, len(code) - 1) + + def test_getting_primary_and_not_crossing_newlines(self): + code = '\na = (b + c)\n(4 + 1).x\n' + result = self._find_primary(code, len(code) - 1) + self.assertEquals('(4 + 1).x', result) + + # XXX: cancatenated string literals + def xxx_test_getting_primary_cancatenating_strs(self): + code = 's = "a"\n"b" "c"\n' + result = self._find_primary(code, len(code) - 2) + self.assertEquals('"b" "c"', result) + + def test_is_a_function_being_called_with_parens_on_next_line(self): + code = 'func\n(1, 2)\n' + word_finder = worder.Worder(code) + self.assertFalse(word_finder.is_a_function_being_called(1)) + + # XXX: handling triple quotes + def xxx_test_triple_quotes(self): + code = 's = """string"""\n' + result = self._find_primary(code, len(code) - 1) + self.assertEquals('"""string"""', result) + + def test_triple_quotes_spanning_multiple_lines(self): + code = 's = """\\\nl1\nl2\n """\n' + result = self._find_primary(code, len(code) - 2) + self.assertEquals('"""\\\nl1\nl2\n """', result) + + def test_get_word_parens_range_and_string_literals(self): + code = 'f(1, ")", 2)\n' + word_finder = worder.Worder(code) + result = word_finder.get_word_parens_range(0) + self.assertEquals((1, len(code) - 1), result) + + def test_is_assigned_here_for_equality_test(self): + code = 'a == 1\n' + word_finder = worder.Worder(code) + self.assertFalse(word_finder.is_assigned_here(0)) + + def test_is_assigned_here_for_not_equal_test(self): + code = 'a != 1\n' + word_finder = worder.Worder(code) + self.assertFalse(word_finder.is_assigned_here(0)) + + # XXX: is_assigned_here should work for tuple assignments + def xxx_test_is_assigned_here_for_tuple_assignment(self): + code = 'a, b = (1, 2)\n' + word_finder = worder.Worder(code) + self.assertTrue(word_finder.is_assigned_here(0)) + + def test_is_from_with_from_import_and_multiline_parens(self): + code = 'from mod import \\\n (f,\n g, h)\n' + word_finder = worder.Worder(code) + self.assertTrue(word_finder.is_from_statement(code.rindex('g'))) + + def test_is_from_with_from_import_and_line_breaks_in_the_middle(self): + code = 'from mod import f,\\\n g\n' + word_finder = worder.Worder(code) + self.assertTrue(word_finder.is_from_statement(code.rindex('g'))) + + def test_one_letter_function_keyword_arguments(self): + code = 'f(p=1)\n' + word_finder = worder.Worder(code) + index = code.rindex('p') + self.assertTrue(word_finder.is_function_keyword_parameter(index)) + + def test_find_parens_start(self): + code = 'f(p)\n' + finder = worder.Worder(code) + self.assertEquals(1, finder.find_parens_start_from_inside(2)) + + def test_underlined_find_parens_start(self): + code = 'f(p="")\n' + finder = worder.Worder(code) + self.assertEquals(1, finder._find_parens_start(len(code) - 2)) + + def test_find_parens_start_with_multiple_entries(self): + code = 'myfunc(p1, p2, p3\n' + finder = worder.Worder(code) + self.assertEquals(code.index('('), + finder.find_parens_start_from_inside(len(code) - 1)) + + def test_find_parens_start_with_nested_parens(self): + code = 'myfunc(p1, (p2, p3), p4\n' + finder = worder.Worder(code) + self.assertEquals(code.index('('), + finder.find_parens_start_from_inside(len(code) - 1)) + + def test_find_parens_start_with_parens_in_strs(self): + code = 'myfunc(p1, "(", p4\n' + finder = worder.Worder(code) + self.assertEquals(code.index('('), + finder.find_parens_start_from_inside(len(code) - 1)) + + def test_find_parens_start_with_parens_in_strs_in_multiple_lines(self): + code = 'myfunc (\np1\n , \n "(" \n, \np4\n' + finder = worder.Worder(code) + self.assertEquals(code.index('('), + finder.find_parens_start_from_inside(len(code) - 1)) + + def test_is_on_function_keyword(self): + code = 'myfunc(va' + finder = worder.Worder(code) + self.assertTrue(finder.is_on_function_call_keyword(len(code) - 1)) + + +class ScopeNameFinderTest(unittest.TestCase): + + def setUp(self): + super(ScopeNameFinderTest, self).setUp() + self.project = testutils.sample_project() + self.pycore = self.project.pycore + + def tearDown(self): + testutils.remove_project(self.project) + super(ScopeNameFinderTest, self).tearDown() + + # FIXME: in normal scopes the interpreter raises `UnboundLocalName` + # exception, but not in class bodies + def xxx_test_global_name_in_class_body(self): + code = 'a_var = 10\nclass C(object):\n a_var = a_var\n' + scope = self.pycore.get_string_scope(code) + name_finder = rope.base.evaluate.ScopeNameFinder(scope.pyobject) + result = name_finder.get_pyname_at(len(code) - 3) + self.assertEquals(scope['a_var'], result) + + def test_class_variable_attribute_in_class_body(self): + code = 'a_var = 10\nclass C(object):\n a_var = a_var\n' + scope = self.pycore.get_string_scope(code) + name_finder = rope.base.evaluate.ScopeNameFinder(scope.pyobject) + a_var_pyname = scope['C'].get_object()['a_var'] + result = name_finder.get_pyname_at(len(code) - 12) + self.assertEquals(a_var_pyname, result) + + def test_class_variable_attribute_in_class_body2(self): + code = 'a_var = 10\nclass C(object):\n a_var \\\n= a_var\n' + scope = self.pycore.get_string_scope(code) + name_finder = rope.base.evaluate.ScopeNameFinder(scope.pyobject) + a_var_pyname = scope['C'].get_object()['a_var'] + result = name_finder.get_pyname_at(len(code) - 12) + self.assertEquals(a_var_pyname, result) + + def test_class_method_attribute_in_class_body(self): + code = 'class C(object):\n def a_method(self):\n pass\n' + scope = self.pycore.get_string_scope(code) + name_finder = rope.base.evaluate.ScopeNameFinder(scope.pyobject) + a_method_pyname = scope['C'].get_object()['a_method'] + result = name_finder.get_pyname_at(code.index('a_method') + 2) + self.assertEquals(a_method_pyname, result) + + def test_inner_class_attribute_in_class_body(self): + code = 'class C(object):\n class CC(object):\n pass\n' + scope = self.pycore.get_string_scope(code) + name_finder = rope.base.evaluate.ScopeNameFinder(scope.pyobject) + a_class_pyname = scope['C'].get_object()['CC'] + result = name_finder.get_pyname_at(code.index('CC') + 2) + self.assertEquals(a_class_pyname, result) + + def test_class_method_in_class_body_but_not_indexed(self): + code = 'class C(object):\n def func(self, func):\n pass\n' + scope = self.pycore.get_string_scope(code) + a_func_pyname = scope.get_scopes()[0].get_scopes()[0]['func'] + name_finder = rope.base.evaluate.ScopeNameFinder(scope.pyobject) + result = name_finder.get_pyname_at(code.index(', func') + 3) + self.assertEquals(a_func_pyname, result) + + def test_function_but_not_indexed(self): + code = 'def a_func(a_func):\n pass\n' + scope = self.pycore.get_string_scope(code) + a_func_pyname = scope['a_func'] + name_finder = rope.base.evaluate.ScopeNameFinder(scope.pyobject) + result = name_finder.get_pyname_at(code.index('a_func') + 3) + self.assertEquals(a_func_pyname, result) + + def test_modules_after_from_statements(self): + root_folder = self.project.root + mod = testutils.create_module(self.project, 'mod', root_folder) + mod.write('def a_func():\n pass\n') + code = 'from mod import a_func\n' + scope = self.pycore.get_string_scope(code) + name_finder = rope.base.evaluate.ScopeNameFinder(scope.pyobject) + mod_pyobject = self.pycore.resource_to_pyobject(mod) + found_pyname = name_finder.get_pyname_at(code.index('mod') + 1) + self.assertEquals(mod_pyobject, found_pyname.get_object()) + + def test_renaming_functions_with_from_import_and_parens(self): + mod1 = testutils.create_module(self.project, 'mod1') + mod1.write('def afunc():\n pass\n') + code = 'from mod1 import (\n afunc as func)\n' + scope = self.pycore.get_string_scope(code) + name_finder = rope.base.evaluate.ScopeNameFinder(scope.pyobject) + mod_pyobject = self.pycore.resource_to_pyobject(mod1) + afunc = mod_pyobject['afunc'] + found_pyname = name_finder.get_pyname_at(code.index('afunc') + 1) + self.assertEquals(afunc.get_object(), found_pyname.get_object()) + + @testutils.run_only_for_25 + def test_relative_modules_after_from_statements(self): + pkg1 = testutils.create_package(self.project, 'pkg1') + pkg2 = testutils.create_package(self.project, 'pkg2', pkg1) + mod1 = testutils.create_module(self.project, 'mod1', pkg1) + mod2 = testutils.create_module(self.project, 'mod2', pkg2) + mod1.write('def a_func():\n pass\n') + code = 'from ..mod1 import a_func\n' + mod2.write(code) + mod2_scope = self.pycore.resource_to_pyobject(mod2).get_scope() + name_finder = rope.base.evaluate.ScopeNameFinder(mod2_scope.pyobject) + mod1_pyobject = self.pycore.resource_to_pyobject(mod1) + found_pyname = name_finder.get_pyname_at(code.index('mod1') + 1) + self.assertEquals(mod1_pyobject, found_pyname.get_object()) + + def test_relative_modules_after_from_statements2(self): + mod1 = testutils.create_module(self.project, 'mod1') + pkg1 = testutils.create_package(self.project, 'pkg1') + pkg2 = testutils.create_package(self.project, 'pkg2', pkg1) + mod2 = testutils.create_module(self.project, 'mod2', pkg2) + mod1.write('import pkg1.pkg2.mod2') + + mod1_scope = self.pycore.resource_to_pyobject(mod1).get_scope() + name_finder = rope.base.evaluate.ScopeNameFinder(mod1_scope.pyobject) + pkg2_pyobject = self.pycore.resource_to_pyobject(pkg2) + found_pyname = name_finder.get_pyname_at(mod1.read().index('pkg2') + 1) + self.assertEquals(pkg2_pyobject, found_pyname.get_object()) + + @testutils.assert_raises(exceptions.RopeError) + def test_get_pyname_at_on_language_keywords(self): + code = 'def a_func(a_func):\n pass\n' + pymod = self.pycore.get_string_module(code) + name_finder = rope.base.evaluate.ScopeNameFinder(pymod) + name_finder.get_pyname_at(code.index('pass')) + + def test_one_liners(self): + code = 'var = 1\ndef f(): var = 2\nprint var\n' + pymod = self.pycore.get_string_module(code) + name_finder = rope.base.evaluate.ScopeNameFinder(pymod) + pyname = name_finder.get_pyname_at(code.rindex('var')) + self.assertEquals(pymod['var'], pyname) + + def test_one_liners_with_line_breaks(self): + code = 'var = 1\ndef f(\n): var = 2\nprint var\n' + pymod = self.pycore.get_string_module(code) + name_finder = rope.base.evaluate.ScopeNameFinder(pymod) + pyname = name_finder.get_pyname_at(code.rindex('var')) + self.assertEquals(pymod['var'], pyname) + + def test_one_liners_with_line_breaks2(self): + code = 'var = 1\ndef f(\np): var = 2\nprint var\n' + pymod = self.pycore.get_string_module(code) + name_finder = rope.base.evaluate.ScopeNameFinder(pymod) + pyname = name_finder.get_pyname_at(code.rindex('var')) + self.assertEquals(pymod['var'], pyname) + + +class LogicalLineFinderTest(unittest.TestCase): + + def setUp(self): + super(LogicalLineFinderTest, self).setUp() + + def tearDown(self): + super(LogicalLineFinderTest, self).tearDown() + + def _logical_finder(self, code): + return LogicalLineFinder(SourceLinesAdapter(code)) + + def test_normal_lines(self): + code = 'a_var = 10' + line_finder = self._logical_finder(code) + self.assertEquals((1, 1), line_finder.logical_line_in(1)) + + def test_normal_lines2(self): + code = 'another = 10\na_var = 20\n' + line_finder = self._logical_finder(code) + self.assertEquals((1, 1), line_finder.logical_line_in(1)) + self.assertEquals((2, 2), line_finder.logical_line_in(2)) + + def test_implicit_continuation(self): + code = 'a_var = 3 + \\\n 4 + \\\n 5' + line_finder = self._logical_finder(code) + self.assertEquals((1, 3), line_finder.logical_line_in(2)) + + def test_explicit_continuation(self): + code = 'print 2\na_var = (3 + \n 4, \n 5)\n' + line_finder = self._logical_finder(code) + self.assertEquals((2, 4), line_finder.logical_line_in(2)) + + def test_explicit_continuation_comments(self): + code = '#\na_var = 3\n' + line_finder = self._logical_finder(code) + self.assertEquals((2, 2), line_finder.logical_line_in(2)) + + def test_multiple_indented_ifs(self): + code = 'if True:\n if True:\n if True:\n pass\n a = 10\n' + line_finder = self._logical_finder(code) + self.assertEquals((5, 5), line_finder.logical_line_in(5)) + + def test_list_comprehensions_and_fors(self): + code = 'a_list = [i\n for i in range(10)]\n' + line_finder = self._logical_finder(code) + self.assertEquals((1, 2), line_finder.logical_line_in(2)) + + def test_generator_expressions_and_fors(self): + code = 'a_list = (i\n for i in range(10))\n' + line_finder = self._logical_finder(code) + self.assertEquals((1, 2), line_finder.logical_line_in(2)) + + def test_fors_and_block_start(self): + code = 'l = range(10)\nfor i in l:\n print i\n' + self.assertEquals(2, get_block_start(SourceLinesAdapter(code), 2)) + + def test_problems_with_inner_indentations(self): + code = 'if True:\n if True:\n if True:\n pass\n' \ + ' a = \\\n 1\n' + line_finder = self._logical_finder(code) + self.assertEquals((5, 6), line_finder.logical_line_in(6)) + + def test_problems_with_inner_indentations2(self): + code = 'if True:\n if True:\n pass\n' \ + 'a = 1\n' + line_finder = self._logical_finder(code) + self.assertEquals((4, 4), line_finder.logical_line_in(4)) + + def test_logical_lines_for_else(self): + code = 'if True:\n pass\nelse:\n pass\n' + line_finder = self._logical_finder(code) + self.assertEquals((3, 3), line_finder.logical_line_in(3)) + + def test_logical_lines_for_lines_with_wrong_continues(self): + code = 'var = 1 + \\' + line_finder = self._logical_finder(code) + self.assertEquals((1, 1), line_finder.logical_line_in(1)) + + def test_generating_line_starts(self): + code = 'a = 1\na = 2\n\na = 3\n' + line_finder = self._logical_finder(code) + self.assertEquals([1, 2, 4], list(line_finder.generate_starts())) + + def test_generating_line_starts2(self): + code = 'a = 1\na = 2\n\na = \\ 3\n' + line_finder = LogicalLineFinder(SourceLinesAdapter(code)) + self.assertEquals([2, 4], list(line_finder.generate_starts(2))) + + def test_generating_line_starts3(self): + code = 'a = 1\na = 2\n\na = \\ 3\n' + line_finder = LogicalLineFinder(SourceLinesAdapter(code)) + self.assertEquals([2], list(line_finder.generate_starts(2, 3))) + + def test_generating_line_starts_for_multi_line_statements(self): + code = '\na = \\\n 1 + \\\n 1\n' + line_finder = self._logical_finder(code) + self.assertEquals([2], list(line_finder.generate_starts())) + + def test_generating_line_starts_and_unmatched_deindents(self): + code = 'if True:\n if True:\n if True:\n' \ + ' a = 1\n b = 1\n' + line_finder = self._logical_finder(code) + self.assertEquals([4, 5], list(line_finder.generate_starts(4))) + +class TokenizerLogicalLineFinderTest(LogicalLineFinderTest): + + def _logical_finder(self, code): + lines = SourceLinesAdapter(code) + return codeanalyze.CachingLogicalLineFinder( + lines, codeanalyze.tokenizer_generator) + +class CustomLogicalLineFinderTest(LogicalLineFinderTest): + + def _logical_finder(self, code): + lines = SourceLinesAdapter(code) + return codeanalyze.CachingLogicalLineFinder( + lines, codeanalyze.custom_generator) + + +def suite(): + result = unittest.TestSuite() + result.addTests(unittest.makeSuite(SourceLinesAdapterTest)) + result.addTests(unittest.makeSuite(WordRangeFinderTest)) + result.addTests(unittest.makeSuite(ScopeNameFinderTest)) + result.addTests(unittest.makeSuite(LogicalLineFinderTest)) + result.addTests(unittest.makeSuite(TokenizerLogicalLineFinderTest)) + result.addTests(unittest.makeSuite(CustomLogicalLineFinderTest)) + return result + +if __name__ == '__main__': + unittest.main() diff -r e30544496575 -r 48cacfdc2ca6 vim/sadness/ropevim/src/rope/ropetest/contrib/__init__.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vim/sadness/ropevim/src/rope/ropetest/contrib/__init__.py Wed Oct 06 12:30:46 2010 -0400 @@ -0,0 +1,32 @@ +import sys +import unittest + +import ropetest.contrib.autoimporttest +import ropetest.contrib.changestacktest +import ropetest.contrib.codeassisttest +import ropetest.contrib.finderrorstest +import ropetest.contrib.findittest +import ropetest.contrib.fixmodnamestest +import ropetest.contrib.generatetest + + +def suite(): + result = unittest.TestSuite() + result.addTests(unittest.makeSuite(ropetest.contrib.generatetest. + GenerateTest)) + result.addTests(ropetest.contrib.codeassisttest.suite()) + result.addTests(ropetest.contrib.autoimporttest.suite()) + result.addTests(ropetest.contrib.findittest.suite()) + result.addTests(unittest.makeSuite(ropetest.contrib.changestacktest. + ChangeStackTest)) + result.addTests(unittest.makeSuite(ropetest.contrib.fixmodnamestest. + FixModuleNamesTest)) + result.addTests(unittest.makeSuite(ropetest.contrib.finderrorstest. + FindErrorsTest)) + return result + + +if __name__ == '__main__': + runner = unittest.TextTestRunner() + result = runner.run(suite()) + sys.exit(not result.wasSuccessful()) diff -r e30544496575 -r 48cacfdc2ca6 vim/sadness/ropevim/src/rope/ropetest/contrib/autoimporttest.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vim/sadness/ropevim/src/rope/ropetest/contrib/autoimporttest.py Wed Oct 06 12:30:46 2010 -0400 @@ -0,0 +1,166 @@ +import unittest + +from ropetest import testutils +from rope.contrib import autoimport + + +class AutoImportTest(unittest.TestCase): + + def setUp(self): + super(AutoImportTest, self).setUp() + self.project = testutils.sample_project(extension_modules=['sys']) + self.mod1 = testutils.create_module(self.project, 'mod1') + self.pkg = testutils.create_package(self.project, 'pkg') + self.mod2 = testutils.create_module(self.project, 'mod2', self.pkg) + self.importer = autoimport.AutoImport(self.project, observe=False) + + def tearDown(self): + testutils.remove_project(self.project) + super(AutoImportTest, self).tearDown() + + def test_simple_case(self): + self.assertEquals([], self.importer.import_assist('A')) + + def test_update_resource(self): + self.mod1.write('myvar = None\n') + self.importer.update_resource(self.mod1) + self.assertEquals([('myvar', 'mod1')], + self.importer.import_assist('myva')) + + def test_update_module(self): + self.mod1.write('myvar = None') + self.importer.update_module('mod1') + self.assertEquals([('myvar', 'mod1')], + self.importer.import_assist('myva')) + + def test_update_non_existent_module(self): + self.importer.update_module('does_not_exists_this') + self.assertEquals([], self.importer.import_assist('myva')) + + def test_module_with_syntax_errors(self): + self.mod1.write('this is a syntax error\n') + self.importer.update_resource(self.mod1) + self.assertEquals([], self.importer.import_assist('myva')) + + def test_excluding_imported_names(self): + self.mod1.write('import pkg\n') + self.importer.update_resource(self.mod1) + self.assertEquals([], self.importer.import_assist('pkg')) + + def test_get_modules(self): + self.mod1.write('myvar = None\n') + self.importer.update_resource(self.mod1) + self.assertEquals(['mod1'], self.importer.get_modules('myvar')) + + def test_get_modules_inside_packages(self): + self.mod1.write('myvar = None\n') + self.mod2.write('myvar = None\n') + self.importer.update_resource(self.mod1) + self.importer.update_resource(self.mod2) + self.assertEquals(set(['mod1', 'pkg.mod2']), + set(self.importer.get_modules('myvar'))) + + def test_trivial_insertion_line(self): + result = self.importer.find_insertion_line('') + self.assertEquals(1, result) + + def test_insertion_line(self): + result = self.importer.find_insertion_line('import mod\n') + self.assertEquals(2, result) + + def test_insertion_line_with_pydocs(self): + result = self.importer.find_insertion_line( + '"""docs\n\ndocs"""\nimport mod\n') + self.assertEquals(5, result) + + def test_insertion_line_with_multiple_imports(self): + result = self.importer.find_insertion_line( + 'import mod1\n\nimport mod2\n') + self.assertEquals(4, result) + + def test_insertion_line_with_blank_lines(self): + result = self.importer.find_insertion_line( + 'import mod1\n\n# comment\n') + self.assertEquals(2, result) + + def test_empty_cache(self): + self.mod1.write('myvar = None\n') + self.importer.update_resource(self.mod1) + self.assertEquals(['mod1'], self.importer.get_modules('myvar')) + self.importer.clear_cache() + self.assertEquals([], self.importer.get_modules('myvar')) + + def test_not_caching_underlined_names(self): + self.mod1.write('_myvar = None\n') + self.importer.update_resource(self.mod1, underlined=False) + self.assertEquals([], self.importer.get_modules('_myvar')) + self.importer.update_resource(self.mod1, underlined=True) + self.assertEquals(['mod1'], self.importer.get_modules('_myvar')) + + def test_caching_underlined_names_passing_to_the_constructor(self): + importer = autoimport.AutoImport(self.project, False, True) + self.mod1.write('_myvar = None\n') + importer.update_resource(self.mod1) + self.assertEquals(['mod1'], importer.get_modules('_myvar')) + + def test_name_locations(self): + self.mod1.write('myvar = None\n') + self.importer.update_resource(self.mod1) + self.assertEquals([(self.mod1, 1)], + self.importer.get_name_locations('myvar')) + + def test_name_locations_with_multiple_occurrences(self): + self.mod1.write('myvar = None\n') + self.mod2.write('\nmyvar = None\n') + self.importer.update_resource(self.mod1) + self.importer.update_resource(self.mod2) + self.assertEquals(set([(self.mod1, 1), (self.mod2, 2)]), + set(self.importer.get_name_locations('myvar'))) + + def test_handling_builtin_modules(self): + self.importer.update_module('sys') + self.assertTrue('sys' in self.importer.get_modules('exit')) + + def test_submodules(self): + self.assertEquals(set([self.mod1]), + autoimport.submodules(self.mod1)) + self.assertEquals(set([self.mod2, self.pkg]), + autoimport.submodules(self.pkg)) + +class AutoImportObservingTest(unittest.TestCase): + + def setUp(self): + super(AutoImportObservingTest, self).setUp() + self.project = testutils.sample_project() + self.mod1 = testutils.create_module(self.project, 'mod1') + self.pkg = testutils.create_package(self.project, 'pkg') + self.mod2 = testutils.create_module(self.project, 'mod2', self.pkg) + self.importer = autoimport.AutoImport(self.project, observe=True) + + def tearDown(self): + testutils.remove_project(self.project) + super(AutoImportObservingTest, self).tearDown() + + def test_writing_files(self): + self.mod1.write('myvar = None\n') + self.assertEquals(['mod1'], self.importer.get_modules('myvar')) + + def test_moving_files(self): + self.mod1.write('myvar = None\n') + self.mod1.move('mod3.py') + self.assertEquals(['mod3'], self.importer.get_modules('myvar')) + + def test_removing_files(self): + self.mod1.write('myvar = None\n') + self.mod1.remove() + self.assertEquals([], self.importer.get_modules('myvar')) + + +def suite(): + result = unittest.TestSuite() + result.addTests(unittest.makeSuite(AutoImportTest)) + result.addTests(unittest.makeSuite(AutoImportObservingTest)) + return result + +if __name__ == '__main__': + unittest.main() diff -r e30544496575 -r 48cacfdc2ca6 vim/sadness/ropevim/src/rope/ropetest/contrib/changestacktest.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vim/sadness/ropevim/src/rope/ropetest/contrib/changestacktest.py Wed Oct 06 12:30:46 2010 -0400 @@ -0,0 +1,35 @@ +import unittest + +import rope.base.history +import rope.contrib.changestack +from rope.base.change import * +from ropetest import testutils + + +class ChangeStackTest(unittest.TestCase): + + def setUp(self): + super(ChangeStackTest, self).setUp() + self.project = testutils.sample_project() + + def tearDown(self): + testutils.remove_project(self.project) + super(ChangeStackTest, self).tearDown() + + def test_change_stack(self): + myfile = self.project.root.create_file('myfile.txt') + myfile.write('1') + stack = rope.contrib.changestack.ChangeStack(self.project) + stack.push(ChangeContents(myfile, '2')) + self.assertEquals('2', myfile.read()) + stack.push(ChangeContents(myfile, '3')) + self.assertEquals('3', myfile.read()) + stack.pop_all() + self.assertEquals('1', myfile.read()) + changes = stack.merged() + self.project.do(changes) + self.assertEquals('3', myfile.read()) + + +if __name__ == '__main__': + unittest.main() diff -r e30544496575 -r 48cacfdc2ca6 vim/sadness/ropevim/src/rope/ropetest/contrib/codeassisttest.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vim/sadness/ropevim/src/rope/ropetest/contrib/codeassisttest.py Wed Oct 06 12:30:46 2010 -0400 @@ -0,0 +1,1065 @@ +# coding: utf-8 +import unittest + +from rope.base import exceptions +from rope.contrib.codeassist import (get_definition_location, get_doc, + starting_expression, code_assist, + sorted_proposals, starting_offset, + get_calltip) +from ropetest import testutils + + +class CodeAssistTest(unittest.TestCase): + + def setUp(self): + super(CodeAssistTest, self).setUp() + self.project = testutils.sample_project() + + def tearDown(self): + testutils.remove_project(self.project) + super(CodeAssistTest, self).tearDown() + + def _assist(self, code, offset=None, **args): + if offset is None: + offset = len(code) + return code_assist(self.project, code, offset, **args) + + def test_simple_assist(self): + self._assist('', 0) + + def assert_completion_in_result(self, name, scope, result, type=None): + for proposal in result: + if proposal.name == name: + self.assertEqual(scope, proposal.scope, + "proposal <%s> has wrong scope, expected " \ + "%r, got %r" % (name, scope, proposal.scope)) + if type is not None: + self.assertEqual(type, proposal.type, + "proposal <%s> has wrong type, expected " \ + "%r, got %r" % (name, type, proposal.type)) + return + self.fail('completion <%s> not proposed' % name) + + def assert_completion_not_in_result(self, name, scope, result): + for proposal in result: + if proposal.name == name and proposal.scope == scope: + self.fail('completion <%s> was proposed' % name) + + def test_completing_global_variables(self): + code = 'my_global = 10\nt = my' + result = self._assist(code) + self.assert_completion_in_result('my_global', 'global', result) + + def test_not_proposing_unmatched_vars(self): + code = 'my_global = 10\nt = you' + result = self._assist(code) + self.assert_completion_not_in_result('my_global', 'global', result) + + def test_not_proposing_unmatched_vars_with_underlined_starting(self): + code = 'my_global = 10\nt = your_' + result = self._assist(code) + self.assert_completion_not_in_result('my_global', 'global', result) + + def test_not_proposing_local_assigns_as_global_completions(self): + code = 'def f(): my_global = 10\nt = my_' + result = self._assist(code) + self.assert_completion_not_in_result('my_global', 'global', result) + + def test_proposing_functions(self): + code = 'def my_func(): return 2\nt = my_' + result = self._assist(code) + self.assert_completion_in_result('my_func', 'global', result) + + def test_proposing_classes(self): + code = 'class Sample(object): pass\nt = Sam' + result = self._assist(code) + self.assert_completion_in_result('Sample', 'global', result) + + def test_proposing_each_name_at_most_once(self): + code = 'variable = 10\nvariable = 20\nt = vari' + result = self._assist(code) + count = len([x for x in result + if x.name == 'variable' and x.scope == 'global']) + self.assertEquals(1, count) + + @testutils.assert_raises(exceptions.ModuleSyntaxError) + def test_throwing_exception_in_case_of_syntax_errors(self): + code = 'sample (sdf+)\n' + self._assist(code, maxfixes=0) + + def test_fixing_errors_with_maxfixes(self): + code = 'def f():\n sldj sldj\ndef g():\n ran' + result = self._assist(code, maxfixes=2) + self.assertTrue(len(result) > 0) + + def test_ignoring_errors_in_current_line(self): + code = 'def my_func():\n return 2\nt = ' + result = self._assist(code) + self.assert_completion_in_result('my_func', 'global', result) + + def test_not_reporting_variables_in_current_line(self): + code = 'def my_func(): return 2\nt = my_' + result = self._assist(code) + self.assert_completion_not_in_result('my_', 'global', result) + + def test_completion_result(self): + code = 'my_global = 10\nt = my' + self.assertEquals(len(code) - 2, starting_offset(code, len(code))) + + def test_completing_imported_names(self): + code = 'import sys\na = sy' + result = self._assist(code) + self.assert_completion_in_result('sys', 'imported', result) + + def test_completing_imported_names_with_as(self): + code = 'import sys as mysys\na = mys' + result = self._assist(code) + self.assert_completion_in_result('mysys', 'imported', result) + + def test_not_completing_imported_names_with_as(self): + code = 'import sys as mysys\na = sy' + result = self._assist(code) + self.assert_completion_not_in_result('sys', 'global', result) + + def test_including_matching_builtins_types(self): + code = 'my_var = Excep' + result = self._assist(code) + self.assert_completion_in_result('Exception', 'builtin', result) + self.assert_completion_not_in_result('zip', 'builtin', result) + + def test_including_matching_builtins_functions(self): + code = 'my_var = zi' + result = self._assist(code) + self.assert_completion_in_result('zip', 'builtin', result) + + def test_builtin_instances(self): + # ``import_dynload_stdmods`` pref is disabled for test project. + # we need to have it enabled to make pycore._find_module() + # load ``sys`` module. + self.project.prefs['import_dynload_stdmods'] = True + code = 'from sys import stdout\nstdout.wr' + result = self._assist(code) + self.assert_completion_in_result('write', 'builtin', result) + self.assert_completion_in_result('writelines', 'builtin', result) + + def test_including_keywords(self): + code = 'fo' + result = self._assist(code) + self.assert_completion_in_result('for', 'keyword', result) + + def test_not_reporting_proposals_after_dot(self): + code = 'a_dict = {}\nkey = 3\na_dict.ke' + result = self._assist(code) + self.assert_completion_not_in_result('key', 'global', result) + + def test_proposing_local_variables_in_functions(self): + code = 'def f(self):\n my_var = 10\n my_' + result = self._assist(code) + self.assert_completion_in_result('my_var', 'local', result) + + def test_local_variables_override_global_ones(self): + code = 'my_var = 20\ndef f(self):\n my_var = 10\n my_' + result = self._assist(code) + self.assert_completion_in_result('my_var', 'local', result) + + def test_not_including_class_body_variables(self): + code = 'class C(object):\n my_var = 20\n' \ + ' def f(self):\n a = 20\n my_' + result = self._assist(code) + self.assert_completion_not_in_result('my_var', 'local', result) + + def test_nested_functions(self): + code = 'def my_func():\n func_var = 20\n ' \ + 'def inner_func():\n a = 20\n func' + result = self._assist(code) + self.assert_completion_in_result('func_var', 'local', result) + + def test_scope_endpoint_selection(self): + code = "def my_func():\n func_var = 20\n" + result = self._assist(code) + self.assert_completion_not_in_result('func_var', 'local', result) + + def test_scope_better_endpoint_selection(self): + code = "if True:\n def f():\n my_var = 10\n my_" + result = self._assist(code) + self.assert_completion_not_in_result('my_var', 'local', result) + + def test_imports_inside_function(self): + code = "def f():\n import sys\n sy" + result = self._assist(code) + self.assert_completion_in_result('sys', 'imported', result) + + def test_imports_inside_function_dont_mix_with_globals(self): + code = "def f():\n import sys\nsy" + result = self._assist(code) + self.assert_completion_not_in_result('sys', 'local', result) + + def test_nested_classes_local_names(self): + code = 'global_var = 10\n' \ + 'def my_func():\n' \ + ' func_var = 20\n' \ + ' class C(object):\n' \ + ' def another_func(self):\n' \ + ' local_var = 10\n' \ + ' func' + result = self._assist(code) + self.assert_completion_in_result('func_var', 'local', result) + + def test_nested_classes_global(self): + code = 'global_var = 10\n' \ + 'def my_func():\n' \ + ' func_var = 20\n' \ + ' class C(object):\n' \ + ' def another_func(self):\n' \ + ' local_var = 10\n' \ + ' globa' + result = self._assist(code) + self.assert_completion_in_result('global_var', 'global', result) + + def test_nested_classes_global_function(self): + code = 'global_var = 10\n' \ + 'def my_func():\n' \ + ' func_var = 20\n' \ + ' class C(object):\n' \ + ' def another_func(self):\n' \ + ' local_var = 10\n' \ + ' my_f' + result = self._assist(code) + self.assert_completion_in_result('my_func', 'global', result) + + def test_proposing_function_parameters_in_functions(self): + code = 'def my_func(my_param):\n my_var = 20\n my_' + result = self._assist(code) + self.assert_completion_in_result('my_param', 'local', result) + + def test_proposing_function_keyword_parameters_in_functions(self): + code = 'def my_func(my_param, *my_list, **my_kws):\n' \ + ' my_var = 20\n' \ + ' my_' + result = self._assist(code) + self.assert_completion_in_result('my_param', 'local', result) + self.assert_completion_in_result('my_list', 'local', result) + self.assert_completion_in_result('my_kws', 'local', result) + + def test_not_proposing_unmatching_function_parameters_in_functions(self): + code = "def my_func(my_param):\n my_var = 20\n you_" + result = self._assist(code) + self.assert_completion_not_in_result('my_param', 'local', result) + + def test_ignoring_current_statement(self): + code = "my_var = 10\nmy_tuple = (10, \n my_" + result = self._assist(code) + self.assert_completion_in_result('my_var', 'global', result) + + def test_ignoring_current_statement_brackets_continuation(self): + code = "my_var = 10\n'hello'[10:\n my_" + result = self._assist(code) + self.assert_completion_in_result('my_var', 'global', result) + + def test_ignoring_current_statement_explicit_continuation(self): + code = "my_var = 10\nmy_var2 = 2 + \\\n my_" + result = self._assist(code) + self.assert_completion_in_result('my_var', 'global', result) + + def test_ignoring_current_statement_while_the_first_statement_of_the_block(self): + code = "my_var = 10\ndef f():\n my_" + result = self._assist(code) + self.assert_completion_in_result('my_var', 'global', result) + + def test_ignoring_current_statement_while_current_line_ends_with_a_colon(self): + code = "my_var = 10\nif my_:\n pass" + result = self._assist(code, 18) + self.assert_completion_in_result('my_var', 'global', result) + + def test_ignoring_string_contents(self): + code = "my_var = '('\nmy_" + result = self._assist(code) + self.assert_completion_in_result('my_var', 'global', result) + + def test_ignoring_comment_contents(self): + code = "my_var = 10 #(\nmy_" + result = self._assist(code) + self.assert_completion_in_result('my_var', 'global', result) + + def test_ignoring_string_contents_backslash_plus_quotes(self): + code = "my_var = '\\''\nmy_" + result = self._assist(code) + self.assert_completion_in_result('my_var', 'global', result) + + def test_ignoring_string_contents_backslash_plus_backslash(self): + code = "my_var = '\\\\'\nmy_" + result = self._assist(code) + self.assert_completion_in_result('my_var', 'global', result) + + def test_not_proposing_later_defined_variables_in_current_block(self): + code = "my_\nmy_var = 10\n" + result = self._assist(code, 3, later_locals=False) + self.assert_completion_not_in_result('my_var', 'global', result) + + def test_not_proposing_later_defined_variables_in_current_function(self): + code = "def f():\n my_\n my_var = 10\n" + result = self._assist(code, 16, later_locals=False) + self.assert_completion_not_in_result('my_var', 'local', result) + + def test_ignoring_string_contents_with_triple_quotes(self): + code = "my_var = '''(\n'('''\nmy_" + result = self._assist(code) + self.assert_completion_in_result('my_var', 'global', result) + + def test_ignoring_string_contents_with_triple_quotes_and_backslash(self): + code = 'my_var = """\\"""("""\nmy_' + result = self._assist(code) + self.assert_completion_in_result('my_var', 'global', result) + + def test_ignoring_string_contents_with_triple_quotes_and_double_backslash(self): + code = 'my_var = """\\\\"""\nmy_' + result = self._assist(code) + self.assert_completion_in_result('my_var', 'global', result) + + def test_reporting_params_when_in_the_first_line_of_a_function(self): + code = 'def f(param):\n para' + result = self._assist(code) + self.assert_completion_in_result('param', 'local', result) + + def test_code_assist_when_having_a_two_line_function_header(self): + code = 'def f(param1,\n param2):\n para' + result = self._assist(code) + self.assert_completion_in_result('param1', 'local', result) + + def test_code_assist_with_function_with_two_line_return(self): + code = 'def f(param1, param2):\n return(param1,\n para' + result = self._assist(code) + self.assert_completion_in_result('param2', 'local', result) + + def test_get_definition_location(self): + code = 'def a_func():\n pass\na_func()' + result = get_definition_location(self.project, code, len(code) - 3) + self.assertEquals((None, 1), result) + + def test_get_definition_location_underlined_names(self): + code = 'def a_sample_func():\n pass\na_sample_func()' + result = get_definition_location(self.project, code, len(code) - 11) + self.assertEquals((None, 1), result) + + def test_get_definition_location_dotted_names(self): + code = 'class AClass(object):\n' \ + ' @staticmethod\n' \ + ' def a_method():\n' \ + ' pass\n' \ + 'AClass.a_method()' + result = get_definition_location(self.project, code, len(code) - 3) + self.assertEquals((None, 2), result) + + def test_get_definition_location_dotted_module_names(self): + module_resource = testutils.create_module(self.project, 'mod') + module_resource.write('def a_func():\n pass\n') + code = 'import mod\nmod.a_func()' + result = get_definition_location(self.project, code, len(code) - 3) + self.assertEquals((module_resource, 1), result) + + def test_get_definition_location_for_nested_packages(self): + pycore = self.project.pycore + mod1 = testutils.create_module(self.project, 'mod1') + pkg1 = testutils.create_package(self.project, 'pkg1') + pkg2 = testutils.create_package(self.project, 'pkg2', pkg1) + mod2 = testutils.create_module(self.project, 'mod2', pkg2) + mod1.write('import pkg1.pkg2.mod2') + + mod1_scope = pycore.resource_to_pyobject(mod1).get_scope() + init_dot_py = pkg2.get_child('__init__.py') + found_pyname = get_definition_location(self.project, mod1.read(), + mod1.read().index('pkg2') + 1) + self.assertEquals(init_dot_py, found_pyname[0]) + + def test_get_definition_location_unknown(self): + code = 'a_func()\n' + result = get_definition_location(self.project, code, len(code) - 3) + self.assertEquals((None, None), result) + + def test_get_definition_location_dot_spaces(self): + code = 'class AClass(object):\n ' \ + '@staticmethod\n def a_method():\n' \ + ' pass\nAClass.\\\n a_method()' + result = get_definition_location(self.project, code, len(code) - 3) + self.assertEquals((None, 2), result) + + def test_get_definition_location_dot_line_break_inside_parens(self): + code = 'class A(object):\n def a_method(self):\n pass\n' + \ + '(A.\na_method)' + result = get_definition_location(self.project, code, + code.rindex('a_method') + 1) + self.assertEquals((None, 2), result) + + def test_if_scopes_in_other_scopes_for_get_definition_location(self): + code = 'def f(a_var):\n pass\na_var = 10\nif True:\n print a_var\n' + result = get_definition_location(self.project, code, len(code) - 3) + self.assertEquals((None, 3), result) + + def test_code_assists_in_parens(self): + code = 'def a_func(a_var):\n pass\na_var = 10\na_func(a_' + result = self._assist(code) + self.assert_completion_in_result('a_var', 'global', result) + + def test_simple_type_inferencing(self): + code = 'class Sample(object):\n' \ + ' def __init__(self, a_param):\n' \ + ' pass\n' \ + ' def a_method(self):\n' \ + ' pass\n' \ + 'Sample("hey").a_' + result = self._assist(code) + self.assert_completion_in_result('a_method', 'attribute', result) + + def test_proposals_sorter(self): + code = 'def my_sample_function(self):\n' + \ + ' my_sample_var = 20\n' + \ + ' my_sample_' + proposals = sorted_proposals(self._assist(code)) + self.assertEquals('my_sample_var', proposals[0].name) + self.assertEquals('my_sample_function', proposals[1].name) + + def test_proposals_sorter_for_methods_and_attributes(self): + code = 'class A(object):\n' + \ + ' def __init__(self):\n' + \ + ' self.my_a_var = 10\n' + \ + ' def my_b_func(self):\n' + \ + ' pass\n' + \ + ' def my_c_func(self):\n' + \ + ' pass\n' + \ + 'a_var = A()\n' + \ + 'a_var.my_' + proposals = sorted_proposals(self._assist(code)) + self.assertEquals('my_b_func', proposals[0].name) + self.assertEquals('my_c_func', proposals[1].name) + self.assertEquals('my_a_var', proposals[2].name) + + def test_proposals_sorter_for_global_methods_and_funcs(self): + code = 'def my_b_func(self):\n' + \ + ' pass\n' + \ + 'my_a_var = 10\n' + \ + 'my_' + proposals = sorted_proposals(self._assist(code)) + self.assertEquals('my_b_func', proposals[0].name) + self.assertEquals('my_a_var', proposals[1].name) + + def test_proposals_sorter_underlined_methods(self): + code = 'class A(object):\n' + \ + ' def _my_func(self):\n' + \ + ' self.my_a_var = 10\n' + \ + ' def my_func(self):\n' + \ + ' pass\n' + \ + 'a_var = A()\n' + \ + 'a_var.' + proposals = sorted_proposals(self._assist(code)) + self.assertEquals('my_func', proposals[0].name) + self.assertEquals('_my_func', proposals[1].name) + + def test_proposals_sorter_and_scope_prefs(self): + code = 'my_global_var = 1\n' \ + 'def func(self):\n' \ + ' my_local_var = 2\n' \ + ' my_' + result = self._assist(code) + proposals = sorted_proposals(result, scopepref=['global', 'local']) + self.assertEquals('my_global_var', proposals[0].name) + self.assertEquals('my_local_var', proposals[1].name) + + def test_proposals_sorter_and_type_prefs(self): + code = 'my_global_var = 1\n' \ + 'def my_global_func(self):\n' \ + ' pass\n' \ + 'my_' + result = self._assist(code) + proposals = sorted_proposals(result, typepref=['instance', 'function']) + self.assertEquals('my_global_var', proposals[0].name) + self.assertEquals('my_global_func', proposals[1].name) + + def test_proposals_sorter_and_missing_type_in_typepref(self): + code = 'my_global_var = 1\n' \ + 'def my_global_func():\n' \ + ' pass\n' \ + 'my_' + result = self._assist(code) + proposals = sorted_proposals(result, typepref=['function']) + + def test_get_pydoc_unicode(self): + src = u'# coding: utf-8\ndef foo():\n u"юникод-объект"' + doc = get_doc(self.project, src, src.index('foo') + 1) + self.assertTrue(isinstance(doc, unicode)) + self.assertTrue(u'юникод-объект' in doc) + + def test_get_pydoc_utf8_bytestring(self): + src = u'# coding: utf-8\ndef foo():\n "байтстринг"' + doc = get_doc(self.project, src, src.index('foo') + 1) + self.assertTrue(isinstance(doc, unicode)) + self.assertTrue(u'байтстринг' in doc) + + def test_get_pydoc_for_functions(self): + src = 'def a_func():\n' \ + ' """a function"""\n' \ + ' a_var = 10\n' \ + 'a_func()' + self.assertTrue(get_doc(self.project, src, len(src) - 4). + endswith('a function')) + get_doc(self.project, src, len(src) - 4).index('a_func()') + + def test_get_pydoc_for_classes(self): + src = 'class AClass(object):\n pass\n' + get_doc(self.project, src, src.index('AClass') + 1).index('AClass') + + def test_get_pydoc_for_classes_with_init(self): + src = 'class AClass(object):\n def __init__(self):\n pass\n' + get_doc(self.project, src, src.index('AClass') + 1).index('AClass') + + def test_get_pydoc_for_modules(self): + pycore = self.project.pycore + mod = testutils.create_module(self.project, 'mod') + mod.write('"""a module"""\n') + src = 'import mod\nmod' + self.assertEquals('a module', get_doc(self.project, src, len(src) - 1)) + + def test_get_pydoc_for_builtins(self): + src = 'print(object)\n' + self.assertTrue(get_doc(self.project, src, + src.index('obj')) is not None) + + def test_get_pydoc_for_methods_should_include_class_name(self): + src = 'class AClass(object):\n' \ + ' def a_method(self):\n'\ + ' """hey"""\n' \ + ' pass\n' + doc = get_doc(self.project, src, src.index('a_method') + 1) + doc.index('AClass.a_method') + doc.index('hey') + + def test_get_pydoc_for_methods_should_include_methods_from_super_classes(self): + src = 'class A(object):\n' \ + ' def a_method(self):\n' \ + ' """hey1"""\n' \ + ' pass\n' \ + 'class B(A):\n' \ + ' def a_method(self):\n' \ + ' """hey2"""\n' \ + ' pass\n' + doc = get_doc(self.project, src, src.rindex('a_method') + 1) + doc.index('A.a_method') + doc.index('hey1') + doc.index('B.a_method') + doc.index('hey2') + + def test_get_pydoc_for_classes_should_name_super_classes(self): + src = 'class A(object):\n pass\n' \ + 'class B(A):\n pass\n' + doc = get_doc(self.project, src, src.rindex('B') + 1) + doc.index('B(A)') + + def test_get_pydoc_for_builtin_functions(self): + src = 's = "hey"\ns.replace\n' + doc = get_doc(self.project, src, src.rindex('replace') + 1) + self.assertTrue(doc is not None) + + def test_commenting_errors_before_offset(self): + src = 'lsjd lsjdf\ns = "hey"\ns.replace()\n' + doc = get_doc(self.project, src, src.rindex('replace') + 1) + + def test_proposing_variables_defined_till_the_end_of_scope(self): + code = 'if True:\n a_v\na_var = 10\n' + result = self._assist(code, code.index('a_v') + 3) + self.assert_completion_in_result('a_var', 'global', result) + + def test_completing_in_uncomplete_try_blocks(self): + code = 'try:\n a_var = 10\n a_' + result = self._assist(code) + self.assert_completion_in_result('a_var', 'global', result) + + def test_completing_in_uncomplete_try_blocks_in_functions(self): + code = 'def a_func():\n try:\n a_var = 10\n a_' + result = self._assist(code) + self.assert_completion_in_result('a_var', 'local', result) + + def test_already_complete_try_blocks_with_finally(self): + code = 'def a_func():\n try:\n a_var = 10\n a_' + result = self._assist(code) + self.assert_completion_in_result('a_var', 'local', result) + + def test_already_complete_try_blocks_with_finally2(self): + code = 'try:\n a_var = 10\n a_\nfinally:\n pass\n' + result = self._assist(code, code.rindex('a_') + 2) + self.assert_completion_in_result('a_var', 'global', result) + + def test_already_complete_try_blocks_with_except(self): + code = 'try:\n a_var = 10\n a_\nexcept Exception:\n pass\n' + result = self._assist(code, code.rindex('a_') + 2) + self.assert_completion_in_result('a_var', 'global', result) + + def test_already_complete_try_blocks_with_except2(self): + code = 'a_var = 10\ntry:\n another_var = a_\n another_var = 10\n' \ + 'except Exception:\n pass\n' + result = self._assist(code, code.rindex('a_') + 2) + self.assert_completion_in_result('a_var', 'global', result) + + def test_completing_ifs_in_uncomplete_try_blocks(self): + code = 'try:\n if True:\n a_var = 10\n a_' + result = self._assist(code) + self.assert_completion_in_result('a_var', 'global', result) + + def test_completing_ifs_in_uncomplete_try_blocks2(self): + code = 'try:\n if True:\n a_var = 10\n a_' + result = self._assist(code) + self.assert_completion_in_result('a_var', 'global', result) + + def test_completing_excepts_in_uncomplete_try_blocks(self): + code = 'try:\n pass\nexcept Exc' + result = self._assist(code) + self.assert_completion_in_result('Exception', 'builtin', result) + + def test_and_normal_complete_blocks_and_single_fixing(self): + code = 'try:\n range.\nexcept:\n pass\n' + result = self._assist(code, code.index('.'), maxfixes=1) + + def test_nested_blocks(self): + code = 'a_var = 10\ntry:\n try:\n a_v' + result = self._assist(code) + self.assert_completion_in_result('a_var', 'global', result) + + def test_proposing_function_keywords_when_calling(self): + code = 'def f(p):\n pass\nf(p' + result = self._assist(code) + self.assert_completion_in_result('p=', 'parameter_keyword', result) + + def test_proposing_function_keywords_when_calling_for_non_functions(self): + code = 'f = 1\nf(p' + result = self._assist(code) + + def test_proposing_function_keywords_when_calling_extra_spaces(self): + code = 'def f(p):\n pass\nf( p' + result = self._assist(code) + self.assert_completion_in_result('p=', 'parameter_keyword', result) + + def test_proposing_function_keywords_when_calling_on_second_argument(self): + code = 'def f(p1, p2):\n pass\nf(1, p' + result = self._assist(code) + self.assert_completion_in_result('p2=', 'parameter_keyword', result) + + def test_proposing_function_keywords_when_calling_not_proposing_args(self): + code = 'def f(p1, *args):\n pass\nf(1, a' + result = self._assist(code) + self.assert_completion_not_in_result('args=', 'parameter_keyword', result) + + def test_proposing_function_keywords_when_calling_with_no_nothing_after_parens(self): + code = 'def f(p):\n pass\nf(' + result = self._assist(code) + self.assert_completion_in_result('p=', 'parameter_keyword', result) + + def test_proposing_function_keywords_when_calling_with_no_nothing_after_parens2(self): + code = 'def f(p):\n pass\ndef g():\n h = f\n f(' + result = self._assist(code) + self.assert_completion_in_result('p=', 'parameter_keyword', result) + + def test_codeassists_before_opening_of_parens(self): + code = 'def f(p):\n pass\na_var = 1\nf(1)\n' + result = self._assist(code, code.rindex('f') + 1) + self.assert_completion_not_in_result('a_var', 'global', result) + + def test_codeassist_before_single_line_indents(self): + code = 'myvar = 1\nif True:\n (myv\nif True:\n pass\n' + result = self._assist(code, code.rindex('myv') + 3) + self.assert_completion_not_in_result('myvar', 'local', result) + + def test_codeassist_before_line_indents_in_a_blank_line(self): + code = 'myvar = 1\nif True:\n \nif True:\n pass\n' + result = self._assist(code, code.rindex(' ') + 4) + self.assert_completion_not_in_result('myvar', 'local', result) + + def test_simple_get_calltips(self): + src = 'def f():\n pass\nvar = f()\n' + doc = get_calltip(self.project, src, src.rindex('f')) + self.assertEquals('f()', doc) + + def test_get_calltips_for_classes(self): + src = 'class C(object):\n' \ + ' def __init__(self):\n pass\nC(' + doc = get_calltip(self.project, src, len(src) - 1) + self.assertEquals('C.__init__(self)', doc) + + def test_get_calltips_for_objects_with_call(self): + src = 'class C(object):\n' \ + ' def __call__(self, p):\n pass\n' \ + 'c = C()\nc(1,' + doc = get_calltip(self.project, src, src.rindex('c')) + self.assertEquals('C.__call__(self, p)', doc) + + def test_get_calltips_and_including_module_name(self): + src = 'class C(object):\n' \ + ' def __call__(self, p):\n pass\n' \ + 'c = C()\nc(1,' + mod = testutils.create_module(self.project, 'mod') + mod.write(src) + doc = get_calltip(self.project, src, src.rindex('c'), mod) + self.assertEquals('mod.C.__call__(self, p)', doc) + + def test_get_calltips_and_including_module_name(self): + src = 'range()\n' + doc = get_calltip(self.project, src, 1, ignore_unknown=True) + self.assertTrue(doc is None) + + def test_removing_self_parameter(self): + src = 'class C(object):\n' \ + ' def f(self):\n'\ + ' pass\n' \ + 'C().f()' + doc = get_calltip(self.project, src, src.rindex('f'), remove_self=True) + self.assertEquals('C.f()', doc) + + def test_removing_self_parameter_and_more_than_one_parameter(self): + src = 'class C(object):\n' \ + ' def f(self, p1):\n'\ + ' pass\n' \ + 'C().f()' + doc = get_calltip(self.project, src, src.rindex('f'), remove_self=True) + self.assertEquals('C.f(p1)', doc) + + def test_lambda_calltip(self): + src = 'foo = lambda x, y=1: None\n' \ + 'foo()' + doc = get_calltip(self.project, src, src.rindex('f')) + self.assertEqual(doc, 'lambda(x, y)') + + def test_keyword_before_parens(self): + code = 'if (1).:\n pass' + result = self._assist(code, offset=len('if (1).')) + self.assertTrue(result) + + # TESTING PROPOSAL'S KINDS AND TYPES. + # SEE RELATION MATRIX IN `CompletionProposal`'s DOCSTRING + + def test_local_variable_completion_proposal(self): + code = 'def foo():\n xvar = 5\n x' + result = self._assist(code) + self.assert_completion_in_result('xvar', 'local', result, 'instance') + + def test_global_variable_completion_proposal(self): + code = 'yvar = 5\ny' + result = self._assist(code) + self.assert_completion_in_result('yvar', 'global', result, 'instance') + + def test_builtin_variable_completion_proposal(self): + for varname in ('False', 'True'): + result = self._assist(varname[0]) + self.assert_completion_in_result(varname, 'builtin', result, + type='instance') + + def test_attribute_variable_completion_proposal(self): + code = 'class AClass(object):\n def foo(self):\n ' \ + 'self.bar = 1\n self.b' + result = self._assist(code) + self.assert_completion_in_result('bar', 'attribute', result, + type='instance') + + def test_local_class_completion_proposal(self): + code = 'def foo():\n class LocalClass(object): pass\n Lo' + result = self._assist(code) + self.assert_completion_in_result('LocalClass', 'local', result, + type='class') + + def test_global_class_completion_proposal(self): + code = 'class GlobalClass(object): pass\nGl' + result = self._assist(code) + self.assert_completion_in_result('GlobalClass', 'global', result, + type='class') + + def test_builtin_class_completion_proposal(self): + for varname in ('object', 'dict', 'file'): + result = self._assist(varname[0]) + self.assert_completion_in_result(varname, 'builtin', result, + type='class') + + def test_attribute_class_completion_proposal(self): + code = 'class Outer(object):\n class Inner(object): pass\nOuter.' + result = self._assist(code) + self.assert_completion_in_result('Inner', 'attribute', result, + type='class') + + def test_local_function_completion_proposal(self): + code = 'def outer():\n def inner(): pass\n in' + result = self._assist(code) + self.assert_completion_in_result('inner', 'local', result, + type='function') + + def test_global_function_completion_proposal(self): + code = 'def foo(): pass\nf' + result = self._assist(code) + self.assert_completion_in_result('foo', 'global', result, + type='function') + + def test_builtin_function_completion_proposal(self): + code = 'a' + result = self._assist(code) + for expected in ('all', 'any', 'abs'): + self.assert_completion_in_result(expected, 'builtin', result, + type='function') + + def test_attribute_function_completion_proposal(self): + code = 'class Some(object):\n def method(self):\n self.' + result = self._assist(code) + self.assert_completion_in_result('method', 'attribute', result, + type='function') + + def test_local_module_completion_proposal(self): + code = 'def foo():\n import types\n t' + result = self._assist(code) + self.assert_completion_in_result('types', 'imported', result, + type='module') + + def test_global_module_completion_proposal(self): + code = 'import operator\no' + result = self._assist(code) + self.assert_completion_in_result('operator', 'imported', result, + type='module') + + def test_attribute_module_completion_proposal(self): + code = 'class Some(object):\n import os\nSome.o' + result = self._assist(code) + self.assert_completion_in_result('os', 'imported', result, + type='module') + + def test_builtin_exception_completion_proposal(self): + code = 'def blah():\n Z' + result = self._assist(code) + self.assert_completion_in_result('ZeroDivisionError', 'builtin', + result, type='class') + + def test_keyword_completion_proposal(self): + code = 'f' + result = self._assist(code) + self.assert_completion_in_result('for', 'keyword', result, type=None) + self.assert_completion_in_result('from', 'keyword', result, type=None) + + def test_parameter_keyword_completion_proposal(self): + code = 'def func(abc, aloha, alpha, amigo): pass\nfunc(a' + result = self._assist(code) + for expected in ('abc=', 'aloha=', 'alpha=', 'amigo='): + self.assert_completion_in_result(expected, 'parameter_keyword', + result, type=None) + + +class CodeAssistInProjectsTest(unittest.TestCase): + + def setUp(self): + super(CodeAssistInProjectsTest, self).setUp() + self.project = testutils.sample_project() + self.pycore = self.project.pycore + samplemod = testutils.create_module(self.project, 'samplemod') + code = 'class SampleClass(object):\n' \ + ' def sample_method():\n pass\n\n' \ + 'def sample_func():\n pass\n' \ + 'sample_var = 10\n\n' \ + 'def _underlined_func():\n pass\n\n' + samplemod.write(code) + package = testutils.create_package(self.project, 'package') + nestedmod = testutils.create_module(self.project, 'nestedmod', package) + + def tearDown(self): + testutils.remove_project(self.project) + super(self.__class__, self).tearDown() + + def _assist(self, code, resource=None, **kwds): + return code_assist(self.project, code, len(code), resource, **kwds) + + def assert_completion_in_result(self, name, scope, result): + for proposal in result: + if proposal.name == name and proposal.scope == scope: + return + self.fail('completion <%s> not proposed' % name) + + def assert_completion_not_in_result(self, name, scope, result): + for proposal in result: + if proposal.name == name and proposal.scope == scope: + self.fail('completion <%s> was proposed' % name) + + def test_simple_import(self): + code = 'import samplemod\nsample' + result = self._assist(code) + self.assert_completion_in_result('samplemod', 'imported', result) + + def test_from_import_class(self): + code = 'from samplemod import SampleClass\nSample' + result = self._assist(code) + self.assert_completion_in_result('SampleClass', 'imported', result) + + def test_from_import_function(self): + code = 'from samplemod import sample_func\nsample' + result = self._assist(code) + self.assert_completion_in_result('sample_func', 'imported', result) + + def test_from_import_variable(self): + code = 'from samplemod import sample_var\nsample' + result = self._assist(code) + self.assert_completion_in_result('sample_var', 'imported', result) + + def test_from_imports_inside_functions(self): + code = 'def f():\n from samplemod import SampleClass\n Sample' + result = self._assist(code) + self.assert_completion_in_result('SampleClass', 'imported', result) + + def test_from_import_only_imports_imported(self): + code = 'from samplemod import sample_func\nSample' + result = self._assist(code) + self.assert_completion_not_in_result('SampleClass', 'global', result) + + def test_from_import_star(self): + code = 'from samplemod import *\nSample' + result = self._assist(code) + self.assert_completion_in_result('SampleClass', 'imported', result) + + def test_from_import_star2(self): + code = 'from samplemod import *\nsample' + result = self._assist(code) + self.assert_completion_in_result('sample_func', 'imported', result) + self.assert_completion_in_result('sample_var', 'imported', result) + + def test_from_import_star_not_imporing_underlined(self): + code = 'from samplemod import *\n_under' + result = self._assist(code) + self.assert_completion_not_in_result('_underlined_func', 'global', result) + + def test_from_package_import_mod(self): + code = 'from package import nestedmod\nnest' + result = self._assist(code) + self.assert_completion_in_result('nestedmod', 'imported', result) + + def test_completing_after_dot(self): + code = 'class SampleClass(object):\n' \ + ' def sample_method(self):\n' \ + ' pass\n' \ + 'SampleClass.sam' + result = self._assist(code) + self.assert_completion_in_result('sample_method', 'attribute', result) + + def test_completing_after_multiple_dots(self): + code = 'class Class1(object):\n' \ + ' class Class2(object):\n' \ + ' def sample_method(self):\n' \ + ' pass\n' \ + 'Class1.Class2.sam' + result = self._assist(code) + self.assert_completion_in_result('sample_method', 'attribute', result) + + def test_completing_after_self_dot(self): + code = 'class Sample(object):\n' \ + ' def method1(self):\n' \ + ' pass\n' \ + ' def method2(self):\n' \ + ' self.m' + result = self._assist(code) + self.assert_completion_in_result('method1', 'attribute', result) + + def test_result_start_offset_for_dotted_completions(self): + code = 'class Sample(object):\n' \ + ' def method1(self):\n' \ + ' pass\n' \ + 'Sample.me' + self.assertEquals(len(code) - 2, starting_offset(code, len(code))) + + def test_backslash_after_dots(self): + code = 'class Sample(object):\n' \ + ' def a_method(self):\n' \ + ' pass\n' \ + 'Sample.\\\n a_m' + result = self._assist(code) + self.assert_completion_in_result('a_method', 'attribute', result) + + def test_not_proposing_global_names_after_dot(self): + code = 'class Sample(object):\n' \ + ' def a_method(self):\n' \ + ' pass\n' \ + 'Sample.' + result = self._assist(code) + self.assert_completion_not_in_result('Sample', 'global', result) + + def test_assist_on_relative_imports(self): + pkg = testutils.create_package(self.project, 'pkg') + mod1 = testutils.create_module(self.project, 'mod1', pkg) + mod2 = testutils.create_module(self.project, 'mod2', pkg) + mod1.write('def a_func():\n pass\n') + code = 'import mod1\nmod1.' + result = self._assist(code, resource=mod2) + self.assert_completion_in_result('a_func', 'imported', result) + + def test_get_location_on_relative_imports(self): + pkg = testutils.create_package(self.project, 'pkg') + mod1 = testutils.create_module(self.project, 'mod1', pkg) + mod2 = testutils.create_module(self.project, 'mod2', pkg) + mod1.write('def a_func():\n pass\n') + code = 'import mod1\nmod1.a_func\n' + result = get_definition_location(self.project, code, + len(code) - 2, mod2) + self.assertEquals((mod1, 1), result) + + def test_get_definition_location_for_builtins(self): + code = 'import sys\n' + result = get_definition_location(self.project, code, + len(code) - 2) + self.assertEquals((None, None), result) + + def test_get_doc_on_relative_imports(self): + pkg = testutils.create_package(self.project, 'pkg') + mod1 = testutils.create_module(self.project, 'mod1', pkg) + mod2 = testutils.create_module(self.project, 'mod2', pkg) + mod1.write('def a_func():\n """hey"""\n pass\n') + code = 'import mod1\nmod1.a_func\n' + result = get_doc(self.project, code, len(code) - 2, mod2) + self.assertTrue(result.endswith('hey')) + + def test_get_doc_on_from_import_module(self): + mod1 = testutils.create_module(self.project, 'mod1') + mod1.write('"""mod1 docs"""\nvar = 1\n') + code = 'from mod1 import var\n' + result = get_doc(self.project, code, code.index('mod1')) + result.index('mod1 docs') + + def test_fixing_errors_with_maxfixes_in_resources(self): + mod = testutils.create_module(self.project, 'mod') + code = 'def f():\n sldj sldj\ndef g():\n ran' + mod.write(code) + result = self._assist(code, maxfixes=2, resource=mod) + self.assertTrue(len(result) > 0) + + def test_completing_names_after_from_import(self): + mod1 = testutils.create_module(self.project, 'mod1') + mod2 = testutils.create_module(self.project, 'mod2') + mod1.write('myvar = None\n') + result = self._assist('from mod1 import myva', resource=mod2) + self.assertTrue(len(result) > 0) + self.assert_completion_in_result('myvar', 'global', result) + + def test_completing_names_after_from_import_and_sorted_proposals(self): + mod1 = testutils.create_module(self.project, 'mod1') + mod2 = testutils.create_module(self.project, 'mod2') + mod1.write('myvar = None\n') + result = self._assist('from mod1 import myva', resource=mod2) + result = sorted_proposals(result) + self.assertTrue(len(result) > 0) + self.assert_completion_in_result('myvar', 'global', result) + + def test_completing_names_after_from_import2(self): + mod1 = testutils.create_module(self.project, 'mod1') + mod2 = testutils.create_module(self.project, 'mod2') + mod1.write('myvar = None\n') + result = self._assist('from mod1 import ', resource=mod2) + self.assertTrue(len(result) > 0) + self.assert_completion_in_result('myvar', 'global', result) + + def test_starting_expression(self): + code = 'l = list()\nl.app' + self.assertEquals('l.app', starting_expression(code, len(code))) + + +def suite(): + result = unittest.TestSuite() + result.addTests(unittest.makeSuite(CodeAssistTest)) + result.addTests(unittest.makeSuite(CodeAssistInProjectsTest)) + return result + +if __name__ == '__main__': + unittest.main() diff -r e30544496575 -r 48cacfdc2ca6 vim/sadness/ropevim/src/rope/ropetest/contrib/finderrorstest.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vim/sadness/ropevim/src/rope/ropetest/contrib/finderrorstest.py Wed Oct 06 12:30:46 2010 -0400 @@ -0,0 +1,52 @@ +import unittest + +from rope.contrib import finderrors +from ropetest import testutils + + +class FindErrorsTest(unittest.TestCase): + + def setUp(self): + super(FindErrorsTest, self).setUp() + self.project = testutils.sample_project() + self.mod = self.project.root.create_file('mod.py') + + def tearDown(self): + testutils.remove_project(self.project) + super(FindErrorsTest, self).tearDown() + + def test_unresolved_variables(self): + self.mod.write('print(var)\n') + result = finderrors.find_errors(self.project, self.mod) + self.assertEquals(1, len(result)) + self.assertEquals(1, result[0].lineno) + + def test_defined_later(self): + self.mod.write('print(var)\nvar = 1\n') + result = finderrors.find_errors(self.project, self.mod) + self.assertEquals(1, len(result)) + self.assertEquals(1, result[0].lineno) + + def test_ignoring_builtins(self): + self.mod.write('range(2)\n') + result = finderrors.find_errors(self.project, self.mod) + self.assertEquals(0, len(result)) + + def test_ignoring_none(self): + self.mod.write('var = None\n') + result = finderrors.find_errors(self.project, self.mod) + self.assertEquals(0, len(result)) + + def test_bad_attributes(self): + code = 'class C(object):\n' \ + ' pass\n' \ + 'c = C()\n' \ + 'print(c.var)\n' + self.mod.write(code) + result = finderrors.find_errors(self.project, self.mod) + self.assertEquals(1, len(result)) + self.assertEquals(4, result[0].lineno) + + +if __name__ == '__main__': + unittest.main() diff -r e30544496575 -r 48cacfdc2ca6 vim/sadness/ropevim/src/rope/ropetest/contrib/findittest.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vim/sadness/ropevim/src/rope/ropetest/contrib/findittest.py Wed Oct 06 12:30:46 2010 -0400 @@ -0,0 +1,120 @@ +from rope.base import exceptions +import unittest + +from rope.contrib.findit import (find_occurrences, find_implementations, + find_definition) +from ropetest import testutils + + +class FindItTest(unittest.TestCase): + + def setUp(self): + super(FindItTest, self).setUp() + self.project = testutils.sample_project() + + def tearDown(self): + testutils.remove_project(self.project) + super(FindItTest, self).tearDown() + + def test_finding_occurrences(self): + mod = testutils.create_module(self.project, 'mod') + mod.write('a_var = 1\n') + result = find_occurrences(self.project, mod, 1) + self.assertEquals(mod, result[0].resource) + self.assertEquals(0, result[0].offset) + self.assertEquals(False, result[0].unsure) + + def test_finding_occurrences_in_more_than_one_module(self): + mod1 = testutils.create_module(self.project, 'mod1') + mod2 = testutils.create_module(self.project, 'mod2') + mod1.write('a_var = 1\n') + mod2.write('import mod1\nmy_var = mod1.a_var') + result = find_occurrences(self.project, mod1, 1) + self.assertEquals(2, len(result)) + modules = (result[0].resource, result[1].resource) + self.assertTrue(mod1 in modules and mod2 in modules) + + def test_finding_occurrences_matching_when_unsure(self): + mod1 = testutils.create_module(self.project, 'mod1') + mod1.write('class C(object):\n def a_func(self):\n pass\n' + 'def f(arg):\n arg.a_func()\n') + result = find_occurrences( + self.project, mod1, mod1.read().index('a_func'), unsure=True) + self.assertEquals(2, len(result)) + + def test_find_occurrences_resources_parameter(self): + mod1 = testutils.create_module(self.project, 'mod1') + mod2 = testutils.create_module(self.project, 'mod2') + mod1.write('a_var = 1\n') + mod2.write('import mod1\nmy_var = mod1.a_var') + result = find_occurrences(self.project, mod1, 1, resources=[mod1]) + self.assertEquals(1, len(result)) + self.assertEquals((mod1, 0), (result[0].resource, result[0].offset)) + + def test_find_occurrences_and_class_hierarchies(self): + mod1 = testutils.create_module(self.project, 'mod1') + mod1.write('class A(object):\n def f():\n pass\n' + 'class B(A):\n def f():\n pass\n') + offset = mod1.read().rindex('f') + result1 = find_occurrences(self.project, mod1, offset) + result2 = find_occurrences(self.project, mod1, + offset, in_hierarchy=True) + self.assertEquals(1, len(result1)) + self.assertEquals(2, len(result2)) + + def test_trivial_find_implementations(self): + mod1 = testutils.create_module(self.project, 'mod1') + mod1.write('class A(object):\n def f(self):\n pass\n') + offset = mod1.read().rindex('f(') + result = find_implementations(self.project, mod1, offset) + self.assertEquals([], result) + + def test_find_implementations_and_not_returning_parents(self): + mod1 = testutils.create_module(self.project, 'mod1') + mod1.write('class A(object):\n def f(self):\n pass\n' + 'class B(A):\n def f(self):\n pass\n') + offset = mod1.read().rindex('f(') + result = find_implementations(self.project, mod1, offset) + self.assertEquals([], result) + + def test_find_implementations_real_implementation(self): + mod1 = testutils.create_module(self.project, 'mod1') + mod1.write('class A(object):\n def f(self):\n pass\n' + 'class B(A):\n def f(self):\n pass\n') + offset = mod1.read().index('f(') + result = find_implementations(self.project, mod1, offset) + self.assertEquals(1, len(result)) + self.assertEquals(mod1.read().rindex('f('), result[0].offset) + + @testutils.assert_raises(exceptions.BadIdentifierError) + def test_find_implementations_real_implementation(self): + mod1 = testutils.create_module(self.project, 'mod1') + mod1.write('class A(object):\n pass\n') + offset = mod1.read().index('A') + result = find_implementations(self.project, mod1, offset) + + def test_trivial_find_definition(self): + code = 'def a_func():\n pass\na_func()' + result = find_definition(self.project, code, code.rindex('a_func')) + start = code.index('a_func') + self.assertEquals(start, result.offset) + self.assertEquals(None, result.resource) + self.assertEquals(1, result.lineno) + self.assertEquals((start, start + len('a_func')), result.region) + + def test_find_definition_in_other_modules(self): + mod1 = testutils.create_module(self.project, 'mod1') + mod1.write('var = 1\n') + code = 'import mod1\nprint(mod1.var)\n' + result = find_definition(self.project, code, code.index('var')) + self.assertEquals(mod1, result.resource) + self.assertEquals(0, result.offset) + + +def suite(): + result = unittest.TestSuite() + result.addTests(unittest.makeSuite(FindItTest)) + return result + +if __name__ == '__main__': + unittest.main() diff -r e30544496575 -r 48cacfdc2ca6 vim/sadness/ropevim/src/rope/ropetest/contrib/fixmodnamestest.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vim/sadness/ropevim/src/rope/ropetest/contrib/fixmodnamestest.py Wed Oct 06 12:30:46 2010 -0400 @@ -0,0 +1,56 @@ +import unittest + +from ropetest import testutils +from rope.contrib.fixmodnames import FixModuleNames +from rope.contrib.generate import create_module, create_package + + +# HACK: for making this test work on case-insensitive file-systems, it +# uses a name.replace('x', '_') fixer. +class FixModuleNamesTest(unittest.TestCase): + + def setUp(self): + super(FixModuleNamesTest, self).setUp() + self.project = testutils.sample_project() + + def tearDown(self): + testutils.remove_project(self.project) + super(FixModuleNamesTest, self).tearDown() + + def test_simple_module_renaming(self): + mod = create_module(self.project, 'xod') + self.project.do(FixModuleNames(self.project).get_changes(_fixer)) + self.assertFalse(mod.exists()) + self.assertTrue(self.project.get_resource('_od.py').exists()) + + def test_packages_module_renaming(self): + pkg = create_package(self.project, 'xkg') + self.project.do(FixModuleNames(self.project).get_changes(_fixer)) + self.assertFalse(pkg.exists()) + self.assertTrue(self.project.get_resource('_kg/__init__.py').exists()) + + def test_fixing_contents(self): + mod1 = create_module(self.project, 'xod1') + mod2 = create_module(self.project, 'xod2') + mod1.write('import xod2\n') + mod2.write('import xod1\n') + self.project.do(FixModuleNames(self.project).get_changes(_fixer)) + newmod1 = self.project.get_resource('_od1.py') + newmod2 = self.project.get_resource('_od2.py') + self.assertEquals('import _od2\n', newmod1.read()) + self.assertEquals('import _od1\n', newmod2.read()) + + def test_handling_nested_modules(self): + pkg = create_package(self.project, 'xkg') + mod = create_module(self.project, 'xkg.xod') + self.project.do(FixModuleNames(self.project).get_changes(_fixer)) + self.assertFalse(pkg.exists()) + self.assertTrue(self.project.get_resource('_kg/__init__.py').exists()) + self.assertTrue(self.project.get_resource('_kg/_od.py').exists()) + + +def _fixer(name): + return name.replace('x', '_') + +if __name__ == '__main__': + unittest.main() diff -r e30544496575 -r 48cacfdc2ca6 vim/sadness/ropevim/src/rope/ropetest/contrib/generatetest.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vim/sadness/ropevim/src/rope/ropetest/contrib/generatetest.py Wed Oct 06 12:30:46 2010 -0400 @@ -0,0 +1,265 @@ +import unittest + +from rope.base import exceptions +from rope.contrib import generate +from ropetest import testutils + + +class GenerateTest(unittest.TestCase): + + def setUp(self): + super(GenerateTest, self).setUp() + self.project = testutils.sample_project() + self.pycore = self.project.pycore + self.mod = testutils.create_module(self.project, 'mod1') + self.mod2 = testutils.create_module(self.project, 'mod2') + self.pkg = testutils.create_package(self.project, 'pkg') + + def tearDown(self): + testutils.remove_project(self.project) + super(GenerateTest, self).tearDown() + + def _get_generate(self, offset): + return generate.GenerateVariable(self.project, self.mod, offset) + + def _get_generate_class(self, offset): + return generate.GenerateClass(self.project, self.mod, offset) + + def _get_generate_module(self, offset): + return generate.GenerateModule(self.project, self.mod, offset) + + def _get_generate_package(self, offset): + return generate.GeneratePackage(self.project, self.mod, offset) + + def _get_generate_function(self, offset): + return generate.GenerateFunction(self.project, self.mod, offset) + + def test_getting_location(self): + code = 'a_var = name\n' + self.mod.write(code) + generator = self._get_generate(code.index('name')) + self.assertEquals((self.mod, 1), generator.get_location()) + + def test_generating_variable(self): + code = 'a_var = name\n' + self.mod.write(code) + changes = self._get_generate(code.index('name')).get_changes() + self.project.do(changes) + self.assertEquals('name = None\n\n\na_var = name\n', self.mod.read()) + + def test_generating_variable_inserting_before_statement(self): + code = 'c = 1\nc = b\n' + self.mod.write(code) + changes = self._get_generate(code.index('b')).get_changes() + self.project.do(changes) + self.assertEquals('c = 1\nb = None\n\n\nc = b\n', self.mod.read()) + + def test_generating_variable_in_local_scopes(self): + code = 'def f():\n c = 1\n c = b\n' + self.mod.write(code) + changes = self._get_generate(code.index('b')).get_changes() + self.project.do(changes) + self.assertEquals('def f():\n c = 1\n b = None\n c = b\n', + self.mod.read()) + + def test_generating_variable_in_other_modules(self): + code = 'import mod2\nc = mod2.b\n' + self.mod.write(code) + generator = self._get_generate(code.index('b')) + self.project.do(generator.get_changes()) + self.assertEquals((self.mod2, 1), generator.get_location()) + self.assertEquals('b = None\n', self.mod2.read()) + + def test_generating_variable_in_classes(self): + code = 'class C(object):\n def f(self):\n pass\n' \ + 'c = C()\na_var = c.attr' + self.mod.write(code) + changes = self._get_generate(code.index('attr')).get_changes() + self.project.do(changes) + self.assertEquals( + 'class C(object):\n def f(self):\n pass\n\n attr = None\n' \ + 'c = C()\na_var = c.attr', self.mod.read()) + + def test_generating_variable_in_classes_removing_pass(self): + code = 'class C(object):\n pass\nc = C()\na_var = c.attr' + self.mod.write(code) + changes = self._get_generate(code.index('attr')).get_changes() + self.project.do(changes) + self.assertEquals('class C(object):\n\n attr = None\n' \ + 'c = C()\na_var = c.attr', self.mod.read()) + + def test_generating_variable_in_packages(self): + code = 'import pkg\na = pkg.a\n' + self.mod.write(code) + generator = self._get_generate(code.rindex('a')) + self.project.do(generator.get_changes()) + init = self.pkg.get_child('__init__.py') + self.assertEquals((init, 1), generator.get_location()) + self.assertEquals('a = None\n', init.read()) + + def test_generating_classes(self): + code = 'c = C()\n' + self.mod.write(code) + changes = self._get_generate_class(code.index('C')).get_changes() + self.project.do(changes) + self.assertEquals('class C(object):\n pass\n\n\nc = C()\n', + self.mod.read()) + + def test_generating_modules(self): + code = 'import pkg\npkg.mod\n' + self.mod.write(code) + generator = self._get_generate_module(code.rindex('mod')) + self.project.do(generator.get_changes()) + mod = self.pkg.get_child('mod.py') + self.assertEquals((mod, 1), generator.get_location()) + self.assertEquals('import pkg.mod\npkg.mod\n', self.mod.read()) + + def test_generating_packages(self): + code = 'import pkg\npkg.pkg2\n' + self.mod.write(code) + generator = self._get_generate_package(code.rindex('pkg2')) + self.project.do(generator.get_changes()) + pkg2 = self.pkg.get_child('pkg2') + init = pkg2.get_child('__init__.py') + self.assertEquals((init, 1), generator.get_location()) + self.assertEquals('import pkg.pkg2\npkg.pkg2\n', self.mod.read()) + + def test_generating_function(self): + code = 'a_func()\n' + self.mod.write(code) + changes = self._get_generate_function(code.index('a_func')).get_changes() + self.project.do(changes) + self.assertEquals('def a_func():\n pass\n\n\na_func()\n', + self.mod.read()) + + def test_generating_modules_with_empty_primary(self): + code = 'mod\n' + self.mod.write(code) + generator = self._get_generate_module(code.rindex('mod')) + self.project.do(generator.get_changes()) + mod = self.project.root.get_child('mod.py') + self.assertEquals((mod, 1), generator.get_location()) + self.assertEquals('import mod\nmod\n', self.mod.read()) + + @testutils.assert_raises(exceptions.RefactoringError) + def test_generating_variable_already_exists(self): + code = 'b = 1\nc = b\n' + self.mod.write(code) + changes = self._get_generate(code.index('b')).get_changes() + + @testutils.assert_raises(exceptions.RefactoringError) + def test_generating_variable_primary_cannot_be_determined(self): + code = 'c = can_not_be_found.b\n' + self.mod.write(code) + changes = self._get_generate(code.rindex('b')).get_changes() + + @testutils.assert_raises(exceptions.RefactoringError) + def test_generating_modules_when_already_exists(self): + code = 'mod2\n' + self.mod.write(code) + generator = self._get_generate_module(code.rindex('mod')) + self.project.do(generator.get_changes()) + + def test_generating_static_methods(self): + code = 'class C(object):\n pass\nC.a_func()\n' + self.mod.write(code) + changes = self._get_generate_function(code.index('a_func')).get_changes() + self.project.do(changes) + self.assertEquals( + 'class C(object):\n\n @staticmethod\n def a_func():\n pass\nC.a_func()\n', + self.mod.read()) + + def test_generating_methods(self): + code = 'class C(object):\n pass\nc = C()\nc.a_func()\n' + self.mod.write(code) + changes = self._get_generate_function(code.index('a_func')).get_changes() + self.project.do(changes) + self.assertEquals( + 'class C(object):\n\n def a_func(self):\n pass\n' + 'c = C()\nc.a_func()\n', + self.mod.read()) + + def test_generating_constructors(self): + code = 'class C(object):\n pass\nc = C()\n' + self.mod.write(code) + changes = self._get_generate_function(code.rindex('C')).get_changes() + self.project.do(changes) + self.assertEquals( + 'class C(object):\n\n def __init__(self):\n pass\n' + 'c = C()\n', + self.mod.read()) + + def test_generating_calls(self): + code = 'class C(object):\n pass\nc = C()\nc()\n' + self.mod.write(code) + changes = self._get_generate_function(code.rindex('c')).get_changes() + self.project.do(changes) + self.assertEquals( + 'class C(object):\n\n def __call__(self):\n pass\n' + 'c = C()\nc()\n', + self.mod.read()) + + def test_generating_calls_in_other_modules(self): + self.mod2.write('class C(object):\n pass\n') + code = 'import mod2\nc = mod2.C()\nc()\n' + self.mod.write(code) + changes = self._get_generate_function(code.rindex('c')).get_changes() + self.project.do(changes) + self.assertEquals( + 'class C(object):\n\n def __call__(self):\n pass\n', + self.mod2.read()) + + def test_generating_function_handling_arguments(self): + code = 'a_func(1)\n' + self.mod.write(code) + changes = self._get_generate_function(code.index('a_func')).get_changes() + self.project.do(changes) + self.assertEquals('def a_func(arg0):\n pass\n\n\na_func(1)\n', + self.mod.read()) + + def test_generating_function_handling_keyword_xarguments(self): + code = 'a_func(p=1)\n' + self.mod.write(code) + changes = self._get_generate_function(code.index('a_func')).get_changes() + self.project.do(changes) + self.assertEquals('def a_func(p):\n pass\n\n\na_func(p=1)\n', + self.mod.read()) + + def test_generating_function_handling_arguments_better_naming(self): + code = 'a_var = 1\na_func(a_var)\n' + self.mod.write(code) + changes = self._get_generate_function(code.index('a_func')).get_changes() + self.project.do(changes) + self.assertEquals('a_var = 1\ndef a_func(a_var):\n pass\n\n\na_func(a_var)\n', + self.mod.read()) + + def test_generating_variable_in_other_modules2(self): + self.mod2.write('\n\n\nprint(1)\n') + code = 'import mod2\nc = mod2.b\n' + self.mod.write(code) + generator = self._get_generate(code.index('b')) + self.project.do(generator.get_changes()) + self.assertEquals((self.mod2, 5), generator.get_location()) + self.assertEquals('\n\n\nprint(1)\n\n\nb = None\n', self.mod2.read()) + + def test_generating_function_in_a_suite(self): + code = 'if True:\n a_func()\n' + self.mod.write(code) + changes = self._get_generate_function(code.index('a_func')).get_changes() + self.project.do(changes) + self.assertEquals('def a_func():\n pass\n\n\nif True:\n a_func()\n', + self.mod.read()) + + def test_generating_function_in_a_suite_in_a_function(self): + code = 'def f():\n a = 1\n if 1:\n g()\n' + self.mod.write(code) + changes = self._get_generate_function(code.index('g()')).get_changes() + self.project.do(changes) + self.assertEquals( + 'def f():\n a = 1\n def g():\n pass\n' + ' if 1:\n g()\n', + self.mod.read()) + + +if __name__ == '__main__': + unittest.main() diff -r e30544496575 -r 48cacfdc2ca6 vim/sadness/ropevim/src/rope/ropetest/historytest.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vim/sadness/ropevim/src/rope/ropetest/historytest.py Wed Oct 06 12:30:46 2010 -0400 @@ -0,0 +1,409 @@ +import unittest + +import rope.base.history +from rope.base import exceptions +from rope.base.change import * +from ropetest import testutils + + +class HistoryTest(unittest.TestCase): + + def setUp(self): + super(HistoryTest, self).setUp() + self.project = testutils.sample_project() + self.history = self.project.history + + def tearDown(self): + testutils.remove_project(self.project) + super(HistoryTest, self).tearDown() + + def test_undoing_writes(self): + my_file = self.project.root.create_file('my_file.txt') + my_file.write('text1') + self.history.undo() + self.assertEquals('', my_file.read()) + + def test_moving_files(self): + my_file = self.project.root.create_file('my_file.txt') + my_file.move('new_file.txt') + self.history.undo() + self.assertEquals('', my_file.read()) + + def test_moving_files_to_folders(self): + my_file = self.project.root.create_file('my_file.txt') + my_folder = self.project.root.create_folder('my_folder') + my_file.move(my_folder.path) + self.history.undo() + self.assertEquals('', my_file.read()) + + def test_writing_files_that_does_not_change_contents(self): + my_file = self.project.root.create_file('my_file.txt') + my_file.write('') + self.project.history.undo() + self.assertFalse(my_file.exists()) + +class IsolatedHistoryTest(unittest.TestCase): + + def setUp(self): + super(IsolatedHistoryTest, self).setUp() + self.project = testutils.sample_project() + self.history = rope.base.history.History(self.project) + self.file1 = self.project.root.create_file('file1.txt') + self.file2 = self.project.root.create_file('file2.txt') + + def tearDown(self): + testutils.remove_project(self.project) + super(IsolatedHistoryTest, self).tearDown() + + def test_simple_undo(self): + change = ChangeContents(self.file1, '1') + self.history.do(change) + self.assertEquals('1', self.file1.read()) + self.history.undo() + self.assertEquals('', self.file1.read()) + + def test_tobe_undone(self): + change1 = ChangeContents(self.file1, '1') + self.assertEquals(None, self.history.tobe_undone) + self.history.do(change1) + self.assertEquals(change1, self.history.tobe_undone) + change2 = ChangeContents(self.file1, '2') + self.history.do(change2) + self.assertEquals(change2, self.history.tobe_undone) + self.history.undo() + self.assertEquals(change1, self.history.tobe_undone) + + def test_tobe_redone(self): + change = ChangeContents(self.file1, '1') + self.history.do(change) + self.assertEquals(None, self.history.tobe_redone) + self.history.undo() + self.assertEquals(change, self.history.tobe_redone) + + @testutils.assert_raises(exceptions.HistoryError) + def test_undo_limit(self): + history = rope.base.history.History(self.project, maxundos=1) + history.do(ChangeContents(self.file1, '1')) + history.do(ChangeContents(self.file1, '2')) + try: + history.undo() + history.undo() + finally: + self.assertEquals('1', self.file1.read()) + + def test_simple_redo(self): + change = ChangeContents(self.file1, '1') + self.history.do(change) + self.history.undo() + self.history.redo() + self.assertEquals('1', self.file1.read()) + + def test_simple_re_undo(self): + change = ChangeContents(self.file1, '1') + self.history.do(change) + self.history.undo() + self.history.redo() + self.history.undo() + self.assertEquals('', self.file1.read()) + + def test_multiple_undos(self): + change = ChangeContents(self.file1, '1') + self.history.do(change) + change = ChangeContents(self.file1, '2') + self.history.do(change) + self.history.undo() + self.assertEquals('1', self.file1.read()) + change = ChangeContents(self.file1, '3') + self.history.do(change) + self.history.undo() + self.assertEquals('1', self.file1.read()) + self.history.redo() + self.assertEquals('3', self.file1.read()) + + @testutils.assert_raises(exceptions.HistoryError) + def test_undo_list_underflow(self): + self.history.undo() + + @testutils.assert_raises(exceptions.HistoryError) + def test_redo_list_underflow(self): + self.history.redo() + + @testutils.assert_raises(exceptions.HistoryError) + def test_dropping_undone_changes(self): + self.file1.write('1') + self.history.undo(drop=True) + self.history.redo() + + def test_undoing_choosen_changes(self): + change = ChangeContents(self.file1, '1') + self.history.do(change) + self.history.undo(change) + self.assertEquals('', self.file1.read()) + self.assertFalse(self.history.undo_list) + + def test_undoing_choosen_changes2(self): + change1 = ChangeContents(self.file1, '1') + self.history.do(change1) + self.history.do(ChangeContents(self.file1, '2')) + self.history.undo(change1) + self.assertEquals('', self.file1.read()) + self.assertFalse(self.history.undo_list) + + def test_undoing_choosen_changes_not_undoing_others(self): + change1 = ChangeContents(self.file1, '1') + self.history.do(change1) + self.history.do(ChangeContents(self.file2, '2')) + self.history.undo(change1) + self.assertEquals('', self.file1.read()) + self.assertEquals('2', self.file2.read()) + + def test_undoing_writing_after_moving(self): + change1 = ChangeContents(self.file1, '1') + self.history.do(change1) + self.history.do(MoveResource(self.file1, 'file3.txt')) + file3 = self.project.get_resource('file3.txt') + self.history.undo(change1) + self.assertEquals('', self.file1.read()) + self.assertFalse(file3.exists()) + + def test_undoing_folder_movements_for_undoing_writes_inside_it(self): + folder = self.project.root.create_folder('folder') + file3 = folder.create_file('file3.txt') + change1 = ChangeContents(file3, '1') + self.history.do(change1) + self.history.do(MoveResource(folder, 'new_folder')) + new_folder = self.project.get_resource('new_folder') + self.history.undo(change1) + self.assertEquals('', file3.read()) + self.assertFalse(new_folder.exists()) + + def test_undoing_changes_that_depend_on_a_dependant_change(self): + change1 = ChangeContents(self.file1, '1') + self.history.do(change1) + changes = ChangeSet('2nd change') + changes.add_change(ChangeContents(self.file1, '2')) + changes.add_change(ChangeContents(self.file2, '2')) + self.history.do(changes) + self.history.do(MoveResource(self.file2, 'file3.txt')) + file3 = self.project.get_resource('file3.txt') + + self.history.undo(change1) + self.assertEquals('', self.file1.read()) + self.assertEquals('', self.file2.read()) + self.assertFalse(file3.exists()) + + def test_undoing_writes_for_undoing_folder_movements_containing_it(self): + folder = self.project.root.create_folder('folder') + old_file = folder.create_file('file3.txt') + change1 = MoveResource(folder, 'new_folder') + self.history.do(change1) + new_file = self.project.get_resource('new_folder/file3.txt') + self.history.do(ChangeContents(new_file, '1')) + self.history.undo(change1) + self.assertEquals('', old_file.read()) + self.assertFalse(new_file.exists()) + + @testutils.assert_raises(exceptions.HistoryError) + def test_undoing_not_available_change(self): + change = ChangeContents(self.file1, '1') + self.history.undo(change) + + def test_ignoring_ignored_resources(self): + self.project.set('ignored_resources', ['ignored*']) + ignored = self.project.get_file('ignored.txt') + change = CreateResource(ignored) + self.history.do(change) + self.assertTrue(ignored.exists()) + self.assertEquals(0, len(self.history.undo_list)) + + def test_get_file_undo_list_simple(self): + change = ChangeContents(self.file1, '1') + self.history.do(change) + self.assertEquals(set([change]), + set(self.history.get_file_undo_list(self.file1))) + + def test_get_file_undo_list_for_moves(self): + change = MoveResource(self.file1, 'file2.txt') + self.history.do(change) + self.assertEquals(set([change]), + set(self.history.get_file_undo_list(self.file1))) + + # XXX: What happens for moves before the file is created? + def xxx_test_get_file_undo_list_and_moving_its_contining_folder(self): + folder = self.project.root.create_folder('folder') + old_file = folder.create_file('file3.txt') + change1 = MoveResource(folder, 'new_folder') + self.history.do(change1) + self.assertEquals(set([change1]), + set(self.history.get_file_undo_list(old_file))) + + def test_clearing_redo_list_after_do(self): + change = ChangeContents(self.file1, '1') + self.history.do(change) + self.history.undo() + self.history.do(change) + self.assertEquals(0, len(self.history.redo_list)) + + @testutils.assert_raises(exceptions.HistoryError) + def test_undoing_a_not_yet_performed_change(self): + change = ChangeContents(self.file1, '1') + str(change) + change.undo() + + def test_clearing_up_the_history(self): + change1 = ChangeContents(self.file1, '1') + change2 = ChangeContents(self.file1, '2') + self.history.do(change1) + self.history.do(change2) + self.history.undo() + self.history.clear() + self.assertEquals(0, len(self.history.undo_list)) + self.assertEquals(0, len(self.history.redo_list)) + + def test_redoing_choosen_changes_not_undoing_others(self): + change1 = ChangeContents(self.file1, '1') + change2 = ChangeContents(self.file2, '2') + self.history.do(change1) + self.history.do(change2) + self.history.undo() + self.history.undo() + redone = self.history.redo(change2) + self.assertEquals([change2], redone) + self.assertEquals('', self.file1.read()) + self.assertEquals('2', self.file2.read()) + + +class SavingHistoryTest(unittest.TestCase): + + def setUp(self): + super(SavingHistoryTest, self).setUp() + self.project = testutils.sample_project() + self.history = rope.base.history.History(self.project) + self.to_data = ChangeToData() + self.to_change = DataToChange(self.project) + + def tearDown(self): + testutils.remove_project(self.project) + super(SavingHistoryTest, self).tearDown() + + def test_simple_set_saving(self): + data = self.to_data(ChangeSet('testing')) + change = self.to_change(data) + self.assertEquals('testing', str(change)) + + def test_simple_change_content_saving(self): + myfile = self.project.get_file('myfile.txt') + myfile.create() + myfile.write('1') + data = self.to_data(ChangeContents(myfile, '2')) + change = self.to_change(data) + self.history.do(change) + self.assertEquals('2', myfile.read()) + self.history.undo() + self.assertEquals('1', change.old_contents) + + def test_move_resource_saving(self): + myfile = self.project.root.create_file('myfile.txt') + myfolder = self.project.root.create_folder('myfolder') + data = self.to_data(MoveResource(myfile, 'myfolder')) + change = self.to_change(data) + self.history.do(change) + self.assertFalse(myfile.exists()) + self.assertTrue(myfolder.has_child('myfile.txt')) + self.history.undo() + self.assertTrue(myfile.exists()) + self.assertFalse(myfolder.has_child('myfile.txt')) + + def test_move_resource_saving_for_folders(self): + myfolder = self.project.root.create_folder('myfolder') + newfolder = self.project.get_folder('newfolder') + change = MoveResource(myfolder, 'newfolder') + self.history.do(change) + + data = self.to_data(change) + change = self.to_change(data) + change.undo() + self.assertTrue(myfolder.exists()) + self.assertFalse(newfolder.exists()) + + def test_create_file_saving(self): + myfile = self.project.get_file('myfile.txt') + data = self.to_data(CreateFile(self.project.root, 'myfile.txt')) + change = self.to_change(data) + self.history.do(change) + self.assertTrue(myfile.exists()) + self.history.undo() + self.assertFalse(myfile.exists()) + + def test_create_folder_saving(self): + myfolder = self.project.get_folder('myfolder') + data = self.to_data(CreateFolder(self.project.root, 'myfolder')) + change = self.to_change(data) + self.history.do(change) + self.assertTrue(myfolder.exists()) + self.history.undo() + self.assertFalse(myfolder.exists()) + + def test_create_resource_saving(self): + myfile = self.project.get_file('myfile.txt') + data = self.to_data(CreateResource(myfile)) + change = self.to_change(data) + self.history.do(change) + self.assertTrue(myfile.exists()) + self.history.undo() + self.assertFalse(myfile.exists()) + + def test_remove_resource_saving(self): + myfile = self.project.root.create_file('myfile.txt') + data = self.to_data(RemoveResource(myfile)) + change = self.to_change(data) + self.history.do(change) + self.assertFalse(myfile.exists()) + + def test_change_set_saving(self): + change = ChangeSet('testing') + myfile = self.project.get_file('myfile.txt') + change.add_change(CreateResource(myfile)) + change.add_change(ChangeContents(myfile, '1')) + + data = self.to_data(change) + change = self.to_change(data) + self.history.do(change) + self.assertEquals('1', myfile.read()) + self.history.undo() + self.assertFalse(myfile.exists()) + + def test_writing_and_reading_history(self): + history_file = self.project.get_file('history.pickle') + self.project.set('save_history', True) + history = rope.base.history.History(self.project) + myfile = self.project.get_file('myfile.txt') + history.do(CreateResource(myfile)) + history.write() + + history = rope.base.history.History(self.project) + history.undo() + self.assertFalse(myfile.exists()) + + def test_writing_and_reading_history2(self): + history_file = self.project.get_file('history.pickle') + self.project.set('save_history', True) + history = rope.base.history.History(self.project) + myfile = self.project.get_file('myfile.txt') + history.do(CreateResource(myfile)) + history.undo() + history.write() + + history = rope.base.history.History(self.project) + history.redo() + self.assertTrue(myfile.exists()) + +def suite(): + result = unittest.TestSuite() + result.addTests(unittest.makeSuite(HistoryTest)) + result.addTests(unittest.makeSuite(IsolatedHistoryTest)) + result.addTests(unittest.makeSuite(SavingHistoryTest)) + return result + +if __name__ == '__main__': + unittest.main() diff -r e30544496575 -r 48cacfdc2ca6 vim/sadness/ropevim/src/rope/ropetest/objectdbtest.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vim/sadness/ropevim/src/rope/ropetest/objectdbtest.py Wed Oct 06 12:30:46 2010 -0400 @@ -0,0 +1,160 @@ +import unittest + +from rope.base.oi import objectdb, memorydb +from ropetest import testutils + + +def _do_for_all_dbs(function): + def called(self): + for db in self.dbs: + function(self, db) + return called + + +class _MockValidation(object): + + def is_value_valid(self, value): + return value != -1 + + def is_more_valid(self, new, old): + return new != -1 + + def is_file_valid(self, path): + return path != 'invalid' + + def is_scope_valid(self, path, key): + return path != 'invalid' and key != 'invalid' + + +class _MockFileListObserver(object): + + log = '' + + def added(self, path): + self.log += 'added %s ' % path + + def removed(self, path): + self.log += 'removed %s ' % path + + +class ObjectDBTest(unittest.TestCase): + + def setUp(self): + super(ObjectDBTest, self).setUp() + self.project = testutils.sample_project() + validation = _MockValidation() + self.dbs = [ + objectdb.ObjectDB(memorydb.MemoryDB(self.project), validation)] + + def tearDown(self): + for db in self.dbs: + db.write() + testutils.remove_project(self.project) + super(ObjectDBTest, self).tearDown() + + @_do_for_all_dbs + def test_simple_per_name(self, db): + db.add_pername('file', 'key', 'name', 1) + self.assertEqual(1, db.get_pername('file', 'key', 'name')) + + @_do_for_all_dbs + def test_simple_per_name_does_not_exist(self, db): + self.assertEquals(None, db.get_pername('file', 'key', 'name')) + + @_do_for_all_dbs + def test_simple_per_name_after_syncing(self, db): + db.add_pername('file', 'key', 'name', 1) + db.write() + self.assertEquals(1, db.get_pername('file', 'key', 'name')) + + @_do_for_all_dbs + def test_getting_returned(self, db): + db.add_callinfo('file', 'key', (1, 2), 3) + self.assertEquals(3, db.get_returned('file', 'key', (1, 2))) + + @_do_for_all_dbs + def test_getting_returned_when_does_not_match(self, db): + db.add_callinfo('file', 'key', (1, 2), 3) + self.assertEquals(None, db.get_returned('file', 'key', (1, 1))) + + @_do_for_all_dbs + def test_getting_call_info(self, db): + db.add_callinfo('file', 'key', (1, 2), 3) + + call_infos = list(db.get_callinfos('file', 'key')) + self.assertEquals(1, len(call_infos)) + self.assertEquals((1, 2), call_infos[0].get_parameters()) + self.assertEquals(3, call_infos[0].get_returned()) + + @_do_for_all_dbs + def test_invalid_per_name(self, db): + db.add_pername('file', 'key', 'name', -1) + self.assertEquals(None, db.get_pername('file', 'key', 'name')) + + @_do_for_all_dbs + def test_overwriting_per_name(self, db): + db.add_pername('file', 'key', 'name', 1) + db.add_pername('file', 'key', 'name', 2) + self.assertEquals(2, db.get_pername('file', 'key', 'name')) + + @_do_for_all_dbs + def test_not_overwriting_with_invalid_per_name(self, db): + db.add_pername('file', 'key', 'name', 1) + db.add_pername('file', 'key', 'name', -1) + self.assertEquals(1, db.get_pername('file', 'key', 'name')) + + @_do_for_all_dbs + def test_getting_invalid_returned(self, db): + db.add_callinfo('file', 'key', (1, 2), -1) + self.assertEquals(None, db.get_returned('file', 'key', (1, 2))) + + @_do_for_all_dbs + def test_not_overwriting_with_invalid_returned(self, db): + db.add_callinfo('file', 'key', (1, 2), 3) + db.add_callinfo('file', 'key', (1, 2), -1) + self.assertEquals(3, db.get_returned('file', 'key', (1, 2))) + + @_do_for_all_dbs + def test_get_files(self, db): + db.add_callinfo('file1', 'key', (1, 2), 3) + db.add_callinfo('file2', 'key', (1, 2), 3) + self.assertEquals(set(['file1', 'file2']), set(db.get_files())) + + @_do_for_all_dbs + def test_validating_files(self, db): + db.add_callinfo('invalid', 'key', (1, 2), 3) + db.validate_files() + self.assertEquals(0, len(db.get_files())) + + @_do_for_all_dbs + def test_validating_file_for_scopes(self, db): + db.add_callinfo('file', 'invalid', (1, 2), 3) + db.validate_file('file') + self.assertEquals(1, len(db.get_files())) + self.assertEquals(0, len(list(db.get_callinfos('file', 'invalid')))) + + @_do_for_all_dbs + def test_validating_file_moved(self, db): + db.add_callinfo('file', 'key', (1, 2), 3) + + db.file_moved('file', 'newfile') + self.assertEquals(1, len(db.get_files())) + self.assertEquals(1, len(list(db.get_callinfos('newfile', 'key')))) + + @_do_for_all_dbs + def test_using_file_list_observer(self, db): + db.add_callinfo('invalid', 'key', (1, 2), 3) + observer = _MockFileListObserver() + db.add_file_list_observer(observer) + db.validate_files() + self.assertEquals('removed invalid ', observer.log) + + +def suite(): + result = unittest.TestSuite() + result.addTests(unittest.makeSuite(ObjectDBTest)) + return result + + +if __name__ == '__main__': + unittest.main() diff -r e30544496575 -r 48cacfdc2ca6 vim/sadness/ropevim/src/rope/ropetest/objectinfertest.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vim/sadness/ropevim/src/rope/ropetest/objectinfertest.py Wed Oct 06 12:30:46 2010 -0400 @@ -0,0 +1,329 @@ +import unittest + +import rope.base.project +import rope.base.builtins +from ropetest import testutils + + +class ObjectInferTest(unittest.TestCase): + + def setUp(self): + super(ObjectInferTest, self).setUp() + self.project = testutils.sample_project() + self.pycore = self.project.pycore + + def tearDown(self): + testutils.remove_project(self.project) + super(ObjectInferTest, self).tearDown() + + def test_simple_type_inferencing(self): + code = 'class Sample(object):\n pass\na_var = Sample()\n' + scope = self.pycore.get_string_scope(code) + sample_class = scope['Sample'].get_object() + a_var = scope['a_var'].get_object() + self.assertEquals(sample_class, a_var.get_type()) + + def test_simple_type_inferencing_classes_defined_in_holding_scope(self): + code = 'class Sample(object):\n pass\n' \ + 'def a_func():\n a_var = Sample()\n' + scope = self.pycore.get_string_scope(code) + sample_class = scope['Sample'].get_object() + a_var = scope['a_func'].get_object().\ + get_scope()['a_var'].get_object() + self.assertEquals(sample_class, a_var.get_type()) + + def test_simple_type_inferencing_classes_in_class_methods(self): + code = 'class Sample(object):\n pass\n' \ + 'class Another(object):\n' \ + ' def a_method():\n a_var = Sample()\n' + scope = self.pycore.get_string_scope(code) + sample_class = scope['Sample'].get_object() + another_class = scope['Another'].get_object() + a_var = another_class['a_method'].\ + get_object().get_scope()['a_var'].get_object() + self.assertEquals(sample_class, a_var.get_type()) + + def test_simple_type_inferencing_class_attributes(self): + code = 'class Sample(object):\n pass\n' \ + 'class Another(object):\n' \ + ' def __init__(self):\n self.a_var = Sample()\n' + scope = self.pycore.get_string_scope(code) + sample_class = scope['Sample'].get_object() + another_class = scope['Another'].get_object() + a_var = another_class['a_var'].get_object() + self.assertEquals(sample_class, a_var.get_type()) + + def test_simple_type_inferencing_for_in_class_assignments(self): + code = 'class Sample(object):\n pass\n' \ + 'class Another(object):\n an_attr = Sample()\n' + scope = self.pycore.get_string_scope(code) + sample_class = scope['Sample'].get_object() + another_class = scope['Another'].get_object() + an_attr = another_class['an_attr'].get_object() + self.assertEquals(sample_class, an_attr.get_type()) + + def test_simple_type_inferencing_for_chained_assignments(self): + mod = 'class Sample(object):\n pass\n' \ + 'copied_sample = Sample' + mod_scope = self.project.pycore.get_string_scope(mod) + sample_class = mod_scope['Sample'] + copied_sample = mod_scope['copied_sample'] + self.assertEquals(sample_class.get_object(), + copied_sample.get_object()) + + def test_following_chained_assignments_avoiding_circles(self): + mod = 'class Sample(object):\n pass\n' \ + 'sample_class = Sample\n' \ + 'sample_class = sample_class\n' + mod_scope = self.project.pycore.get_string_scope(mod) + sample_class = mod_scope['Sample'] + sample_class_var = mod_scope['sample_class'] + self.assertEquals(sample_class.get_object(), + sample_class_var.get_object()) + + def test_function_returned_object_static_type_inference1(self): + src = 'class Sample(object):\n pass\n' \ + 'def a_func():\n return Sample\n' \ + 'a_var = a_func()\n' + scope = self.project.pycore.get_string_scope(src) + sample_class = scope['Sample'] + a_var = scope['a_var'] + self.assertEquals(sample_class.get_object(), a_var.get_object()) + + def test_function_returned_object_static_type_inference2(self): + src = 'class Sample(object):\n pass\n' \ + 'def a_func():\n return Sample()\n' \ + 'a_var = a_func()\n' + scope = self.project.pycore.get_string_scope(src) + sample_class = scope['Sample'].get_object() + a_var = scope['a_var'].get_object() + self.assertEquals(sample_class, a_var.get_type()) + + def test_recursive_function_returned_object_static_type_inference(self): + src = 'class Sample(object):\n pass\n' \ + 'def a_func():\n' \ + ' if True:\n return Sample()\n' \ + ' else:\n return a_func()\n' \ + 'a_var = a_func()\n' + scope = self.project.pycore.get_string_scope(src) + sample_class = scope['Sample'].get_object() + a_var = scope['a_var'].get_object() + self.assertEquals(sample_class, a_var.get_type()) + + def test_function_returned_object_using_call_special_function_static_type_inference(self): + src = 'class Sample(object):\n' \ + ' def __call__(self):\n return Sample\n' \ + 'sample = Sample()\na_var = sample()' + scope = self.project.pycore.get_string_scope(src) + sample_class = scope['Sample'] + a_var = scope['a_var'] + self.assertEquals(sample_class.get_object(), a_var.get_object()) + + def test_list_type_inferencing(self): + src = 'class Sample(object):\n pass\na_var = [Sample()]\n' + scope = self.pycore.get_string_scope(src) + sample_class = scope['Sample'].get_object() + a_var = scope['a_var'].get_object() + self.assertNotEquals(sample_class, a_var.get_type()) + + def test_attributed_object_inference(self): + src = 'class Sample(object):\n' \ + ' def __init__(self):\n self.a_var = None\n' \ + ' def set(self):\n self.a_var = Sample()\n' + scope = self.pycore.get_string_scope(src) + sample_class = scope['Sample'].get_object() + a_var = sample_class['a_var'].get_object() + self.assertEquals(sample_class, a_var.get_type()) + + def test_getting_property_attributes(self): + src = 'class A(object):\n pass\n' \ + 'def f(*args):\n return A()\n' \ + 'class B(object):\n p = property(f)\n' \ + 'a_var = B().p\n' + pymod = self.pycore.get_string_module(src) + a_class = pymod['A'].get_object() + a_var = pymod['a_var'].get_object() + self.assertEquals(a_class, a_var.get_type()) + + def test_getting_property_attributes_with_method_getters(self): + src = 'class A(object):\n pass\n' \ + 'class B(object):\n def p_get(self):\n return A()\n' \ + ' p = property(p_get)\n' \ + 'a_var = B().p\n' + pymod = self.pycore.get_string_module(src) + a_class = pymod['A'].get_object() + a_var = pymod['a_var'].get_object() + self.assertEquals(a_class, a_var.get_type()) + + def test_lambda_functions(self): + code = 'class C(object):\n pass\n' \ + 'l = lambda: C()\na_var = l()' + mod = self.pycore.get_string_module(code) + c_class = mod['C'].get_object() + a_var = mod['a_var'].get_object() + self.assertEquals(c_class, a_var.get_type()) + + def test_mixing_subscript_with_tuple_assigns(self): + code = 'class C(object):\n attr = 0\n' \ + 'd = {}\nd[0], b = (0, C())\n' + mod = self.pycore.get_string_module(code) + c_class = mod['C'].get_object() + a_var = mod['b'].get_object() + self.assertEquals(c_class, a_var.get_type()) + + def test_mixing_ass_attr_with_tuple_assignment(self): + code = 'class C(object):\n attr = 0\n' \ + 'c = C()\nc.attr, b = (0, C())\n' + mod = self.pycore.get_string_module(code) + c_class = mod['C'].get_object() + a_var = mod['b'].get_object() + self.assertEquals(c_class, a_var.get_type()) + + def test_mixing_slice_with_tuple_assigns(self): + mod = self.pycore.get_string_module( + 'class C(object):\n attr = 0\n' + 'd = [None] * 3\nd[0:2], b = ((0,), C())\n') + c_class = mod['C'].get_object() + a_var = mod['b'].get_object() + self.assertEquals(c_class, a_var.get_type()) + + def test_nested_tuple_assignments(self): + mod = self.pycore.get_string_module( + 'class C1(object):\n pass\nclass C2(object):\n pass\n' + 'a, (b, c) = (C1(), (C2(), C1()))\n') + c1_class = mod['C1'].get_object() + c2_class = mod['C2'].get_object() + a_var = mod['a'].get_object() + b_var = mod['b'].get_object() + c_var = mod['c'].get_object() + self.assertEquals(c1_class, a_var.get_type()) + self.assertEquals(c2_class, b_var.get_type()) + self.assertEquals(c1_class, c_var.get_type()) + + def test_empty_tuples(self): + mod = self.pycore.get_string_module('t = ()\na, b = t\n') + a = mod['a'].get_object() + + def test_handling_generator_functions(self): + code = 'class C(object):\n pass\n' \ + 'def f():\n yield C()\n' \ + 'for c in f():\n a_var = c\n' + mod = self.pycore.get_string_module(code) + c_class = mod['C'].get_object() + a_var = mod['a_var'].get_object() + self.assertEquals(c_class, a_var.get_type()) + + def test_handling_generator_functions_for_strs(self): + mod = testutils.create_module(self.project, 'mod') + mod.write('def f():\n yield ""\n' + 'for s in f():\n a_var = s\n') + pymod = self.pycore.resource_to_pyobject(mod) + a_var = pymod['a_var'].get_object() + self.assertTrue(isinstance(a_var.get_type(), rope.base.builtins.Str)) + + def test_considering_nones_to_be_unknowns(self): + code = 'class C(object):\n pass\n' \ + 'a_var = None\na_var = C()\na_var = None\n' + mod = self.pycore.get_string_module(code) + c_class = mod['C'].get_object() + a_var = mod['a_var'].get_object() + self.assertEquals(c_class, a_var.get_type()) + + def test_basic_list_comprehensions(self): + code = 'class C(object):\n pass\n' \ + 'l = [C() for i in range(1)]\na_var = l[0]\n' + mod = self.pycore.get_string_module(code) + c_class = mod['C'].get_object() + a_var = mod['a_var'].get_object() + self.assertEquals(c_class, a_var.get_type()) + + def test_basic_generator_expressions(self): + code = 'class C(object):\n pass\n' \ + 'l = (C() for i in range(1))\na_var = list(l)[0]\n' + mod = self.pycore.get_string_module(code) + c_class = mod['C'].get_object() + a_var = mod['a_var'].get_object() + self.assertEquals(c_class, a_var.get_type()) + + def test_list_comprehensions_and_loop_var(self): + code = 'class C(object):\n pass\n' \ + 'c_objects = [C(), C()]\n' \ + 'l = [c for c in c_objects]\na_var = l[0]\n' + mod = self.pycore.get_string_module(code) + c_class = mod['C'].get_object() + a_var = mod['a_var'].get_object() + self.assertEquals(c_class, a_var.get_type()) + + def test_list_comprehensions_and_multiple_loop_var(self): + code = 'class C1(object):\n pass\n' \ + 'class C2(object):\n pass\n' \ + 'l = [(c1, c2) for c1 in [C1()] for c2 in [C2()]]\n' \ + 'a, b = l[0]\n' + mod = self.pycore.get_string_module(code) + c1_class = mod['C1'].get_object() + c2_class = mod['C2'].get_object() + a_var = mod['a'].get_object() + b_var = mod['b'].get_object() + self.assertEquals(c1_class, a_var.get_type()) + self.assertEquals(c2_class, b_var.get_type()) + + def test_list_comprehensions_and_multiple_iters(self): + mod = self.pycore.get_string_module( + 'class C1(object):\n pass\nclass C2(object):\n pass\n' + 'l = [(c1, c2) for c1, c2 in [(C1(), C2())]]\n' + 'a, b = l[0]\n') + c1_class = mod['C1'].get_object() + c2_class = mod['C2'].get_object() + a_var = mod['a'].get_object() + b_var = mod['b'].get_object() + self.assertEquals(c1_class, a_var.get_type()) + self.assertEquals(c2_class, b_var.get_type()) + + def test_we_know_the_type_of_catched_exceptions(self): + code = 'class MyError(Exception):\n pass\n' \ + 'try:\n raise MyError()\n' \ + 'except MyError, e:\n pass\n' + mod = self.pycore.get_string_module( + code) + my_error = mod['MyError'].get_object() + e_var = mod['e'].get_object() + self.assertEquals(my_error, e_var.get_type()) + + def test_we_know_the_type_of_catched_multiple_excepts(self): + code = 'class MyError(Exception):\n pass\n' \ + 'try:\n raise MyError()\n' \ + 'except (MyError, Exception), e:\n pass\n' + mod = self.pycore.get_string_module( + code) + my_error = mod['MyError'].get_object() + e_var = mod['e'].get_object() + self.assertEquals(my_error, e_var.get_type()) + + def test_using_property_as_decorators(self): + code = 'class A(object):\n pass\n' \ + 'class B(object):\n' \ + ' @property\n def f(self):\n return A()\n' \ + 'b = B()\nvar = b.f\n' + mod = self.pycore.get_string_module(code) + var = mod['var'].get_object() + a = mod['A'].get_object() + self.assertEquals(a, var.get_type()) + + def test_using_property_as_decorators_and_passing_parameter(self): + code = 'class B(object):\n' \ + ' @property\n def f(self):\n return self\n' \ + 'b = B()\nvar = b.f\n' + mod = self.pycore.get_string_module(code) + var = mod['var'].get_object() + a = mod['B'].get_object() + self.assertEquals(a, var.get_type()) + + +def suite(): + result = unittest.TestSuite() + result.addTests(unittest.makeSuite(ObjectInferTest)) + return result + + +if __name__ == '__main__': + unittest.main() diff -r e30544496575 -r 48cacfdc2ca6 vim/sadness/ropevim/src/rope/ropetest/projecttest.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vim/sadness/ropevim/src/rope/ropetest/projecttest.py Wed Oct 06 12:30:46 2010 -0400 @@ -0,0 +1,958 @@ +import os.path +import unittest + +from rope.base.exceptions import RopeError, ResourceNotFoundError +from rope.base.fscommands import FileSystemCommands +from rope.base.libutils import path_to_resource +from rope.base.project import Project, NoProject, _realpath +from ropetest import testutils +from rope.base.resourceobserver import ResourceObserver, FilteredResourceObserver + + + +class ProjectTest(unittest.TestCase): + + def setUp(self): + unittest.TestCase.setUp(self) + self.project = testutils.sample_project(foldername='sampleproject', + ropefolder=None) + self.project_root = self.project.address + self._make_sample_project() + self.no_project = NoProject() + + def _make_sample_project(self): + self.sample_file = 'sample_file.txt' + self.sample_path = os.path.join(self.project_root, 'sample_file.txt') + if not os.path.exists(self.project_root): + os.mkdir(self.project_root) + self.sample_folder = 'sample_folder' + os.mkdir(os.path.join(self.project_root, self.sample_folder)) + sample = open(self.sample_path, 'w') + sample.write('sample text\n') + sample.close() + + def tearDown(self): + testutils.remove_project(self.project) + unittest.TestCase.tearDown(self) + + def test_project_creation(self): + self.assertEquals(_realpath(self.project_root), + self.project.address) + + def test_getting_project_file(self): + project_file = self.project.get_resource(self.sample_file) + self.assertTrue(project_file is not None) + + def test_project_file_reading(self): + projectFile = self.project.get_resource(self.sample_file) + self.assertEquals('sample text\n', projectFile.read()) + + @testutils.assert_raises(ResourceNotFoundError) + def test_getting_not_existing_project_file(self): + projectFile = self.project.get_resource('DoesNotExistFile.txt') + self.fail('Should have failed') + + def test_writing_in_project_files(self): + project_file = self.project.get_resource(self.sample_file) + project_file.write('another text\n') + self.assertEquals('another text\n', project_file.read()) + + def test_creating_files(self): + project_file = 'newfile.txt' + self.project.root.create_file(project_file) + newFile = self.project.get_resource(project_file) + self.assertTrue(newFile is not None) + + @testutils.assert_raises(RopeError) + def test_creating_files_that_already_exist(self): + self.project.root.create_file(self.sample_file) + self.fail('Should have failed') + + def test_making_root_folder_if_it_does_not_exist(self): + project = Project('sampleproject2') + try: + self.assertTrue(os.path.exists('sampleproject2') and + os.path.isdir('sampleproject2')) + finally: + testutils.remove_project(project) + + @testutils.assert_raises(RopeError) + def test_failure_when_project_root_exists_and_is_a_file(self): + try: + project_root = 'sampleproject2' + open(project_root, 'w').close() + project = Project(project_root) + finally: + testutils.remove_recursively(project_root) + + def test_creating_folders(self): + folderName = 'SampleFolder' + self.project.root.create_folder(folderName) + folderPath = os.path.join(self.project.address, folderName) + self.assertTrue(os.path.exists(folderPath) and os.path.isdir(folderPath)) + + @testutils.assert_raises(RopeError) + def test_making_folder_that_already_exists(self): + folderName = 'SampleFolder' + self.project.root.create_folder(folderName) + self.project.root.create_folder(folderName) + + @testutils.assert_raises(RopeError) + def test_failing_if_creating_folder_while_file_already_exists(self): + folderName = 'SampleFolder' + self.project.root.create_file(folderName) + self.project.root.create_folder(folderName) + + def test_creating_file_inside_folder(self): + folder_name = 'sampleFolder' + file_name = 'sample2.txt' + file_path = folder_name + '/' + file_name + parent_folder = self.project.root.create_folder(folder_name) + parent_folder.create_file(file_name) + file = self.project.get_resource(file_path) + file.write('sample notes') + self.assertEquals(file_path, file.path) + self.assertEquals('sample notes', open(os.path.join(self.project.address, + file_path)).read()) + + @testutils.assert_raises(ResourceNotFoundError) + def test_failing_when_creating_file_inside_non_existent_folder(self): + self.project.root.create_file('NonexistentFolder/SomeFile.txt') + + def test_nested_directories(self): + folder_name = 'SampleFolder' + parent = self.project.root.create_folder(folder_name) + parent.create_folder(folder_name) + folder_path = os.path.join(self.project.address, folder_name, folder_name) + self.assertTrue(os.path.exists(folder_path) and os.path.isdir(folder_path)) + + def test_removing_files(self): + self.assertTrue(os.path.exists(self.sample_path)) + self.project.get_resource(self.sample_file).remove() + self.assertFalse(os.path.exists(self.sample_path)) + + def test_removing_files_invalidating_in_project_resource_pool(self): + root_folder = self.project.root + my_file = root_folder.create_file('my_file.txt') + my_file.remove() + self.assertFalse(root_folder.has_child('my_file.txt')) + + def test_removing_directories(self): + self.assertTrue(os.path.exists(os.path.join(self.project.address, + self.sample_folder))) + self.project.get_resource(self.sample_folder).remove() + self.assertFalse(os.path.exists(os.path.join(self.project.address, + self.sample_folder))) + + @testutils.assert_raises(ResourceNotFoundError) + def test_removing_non_existent_files(self): + self.project.get_resource('NonExistentFile.txt').remove() + + def test_removing_nested_files(self): + file_name = self.sample_folder + '/sample_file.txt' + self.project.root.create_file(file_name) + self.project.get_resource(file_name).remove() + self.assertTrue(os.path.exists(os.path.join(self.project.address, + self.sample_folder))) + self.assertTrue(not os.path.exists(os.path.join(self.project.address, + file_name))) + + def test_file_get_name(self): + file = self.project.get_resource(self.sample_file) + self.assertEquals(self.sample_file, file.name) + file_name = 'nestedFile.txt' + parent = self.project.get_resource(self.sample_folder) + filePath = self.sample_folder + '/' + file_name + parent.create_file(file_name) + nestedFile = self.project.get_resource(filePath) + self.assertEquals(file_name, nestedFile.name) + + def test_folder_get_name(self): + folder = self.project.get_resource(self.sample_folder) + self.assertEquals(self.sample_folder, folder.name) + + def test_file_get_path(self): + file = self.project.get_resource(self.sample_file) + self.assertEquals(self.sample_file, file.path) + fileName = 'nestedFile.txt' + parent = self.project.get_resource(self.sample_folder) + filePath = self.sample_folder + '/' + fileName + parent.create_file(fileName) + nestedFile = self.project.get_resource(filePath) + self.assertEquals(filePath, nestedFile.path) + + def test_folder_get_path(self): + folder = self.project.get_resource(self.sample_folder) + self.assertEquals(self.sample_folder, folder.path) + + def test_is_folder(self): + self.assertTrue(self.project.get_resource(self.sample_folder).is_folder()) + self.assertTrue(not self.project.get_resource(self.sample_file).is_folder()) + + def testget_children(self): + children = self.project.get_resource(self.sample_folder).get_children() + self.assertEquals([], children) + + def test_nonempty_get_children(self): + file_name = 'nestedfile.txt' + filePath = self.sample_folder + '/' + file_name + parent = self.project.get_resource(self.sample_folder) + parent.create_file(file_name) + children = parent.get_children() + self.assertEquals(1, len(children)) + self.assertEquals(filePath, children[0].path) + + def test_nonempty_get_children2(self): + file_name = 'nestedfile.txt' + folder_name = 'nestedfolder.txt' + filePath = self.sample_folder + '/' + file_name + folderPath = self.sample_folder + '/' + folder_name + parent = self.project.get_resource(self.sample_folder) + parent.create_file(file_name) + parent.create_folder(folder_name) + children = parent.get_children() + self.assertEquals(2, len(children)) + self.assertTrue(filePath == children[0].path or filePath == children[1].path) + self.assertTrue(folderPath == children[0].path or folderPath == children[1].path) + + def test_getting_files(self): + files = self.project.root.get_files() + self.assertEquals(1, len(files)) + self.assertTrue(self.project.get_resource(self.sample_file) in files) + + def test_getting_folders(self): + folders = self.project.root.get_folders() + self.assertEquals(1, len(folders)) + self.assertTrue(self.project.get_resource(self.sample_folder) in folders) + + def test_nested_folder_get_files(self): + parent = self.project.root.create_folder('top') + parent.create_file('file1.txt') + parent.create_file('file2.txt') + files = parent.get_files() + self.assertEquals(2, len(files)) + self.assertTrue(self.project.get_resource('top/file2.txt') in files) + self.assertEquals(0, len(parent.get_folders())) + + def test_nested_folder_get_folders(self): + parent = self.project.root.create_folder('top') + parent.create_folder('dir1') + parent.create_folder('dir2') + folders = parent.get_folders() + self.assertEquals(2, len(folders)) + self.assertTrue(self.project.get_resource('top/dir1') in folders) + self.assertEquals(0, len(parent.get_files())) + + def test_root_folder(self): + root_folder = self.project.root + self.assertEquals(2, len(root_folder.get_children())) + self.assertEquals('', root_folder.path) + self.assertEquals('', root_folder.name) + + def test_get_all_files(self): + files = tuple(self.project.get_files()) + self.assertEquals(1, len(files)) + self.assertEquals(self.sample_file, files[0].name) + + def test_get_all_files_after_changing(self): + self.assertEquals(1, len(self.project.get_files())) + myfile = self.project.root.create_file('myfile.txt') + self.assertEquals(2, len(self.project.get_files())) + myfile.move('newfile.txt') + self.assertEquals(2, len(self.project.get_files())) + self.project.get_file('newfile.txt').remove() + self.assertEquals(1, len(self.project.get_files())) + + def test_multifile_get_all_files(self): + fileName = 'nestedFile.txt' + parent = self.project.get_resource(self.sample_folder) + parent.create_file(fileName) + files = list(self.project.get_files()) + self.assertEquals(2, len(files)) + self.assertTrue(fileName == files[0].name or fileName == files[1].name) + + def test_ignoring_dot_pyc_files_in_get_files(self): + root = self.project.address + src_folder = os.path.join(root, 'src') + os.mkdir(src_folder) + test_pyc = os.path.join(src_folder, 'test.pyc') + file(test_pyc, 'w').close() + for x in self.project.get_files(): + self.assertNotEquals('src/test.pyc', x.path) + + def test_folder_creating_files(self): + projectFile = 'NewFile.txt' + self.project.root.create_file(projectFile) + new_file = self.project.get_resource(projectFile) + self.assertTrue(new_file is not None and not new_file.is_folder()) + + def test_folder_creating_nested_files(self): + project_file = 'NewFile.txt' + parent_folder = self.project.get_resource(self.sample_folder) + parent_folder.create_file(project_file) + new_file = self.project.get_resource(self.sample_folder + + '/' + project_file) + self.assertTrue(new_file is not None and not new_file.is_folder()) + + def test_folder_creating_files2(self): + projectFile = 'newfolder' + self.project.root.create_folder(projectFile) + new_folder = self.project.get_resource(projectFile) + self.assertTrue(new_folder is not None and new_folder.is_folder()) + + def test_folder_creating_nested_files2(self): + project_file = 'newfolder' + parent_folder = self.project.get_resource(self.sample_folder) + parent_folder.create_folder(project_file) + new_folder = self.project.get_resource(self.sample_folder + + '/' + project_file) + self.assertTrue(new_folder is not None and new_folder.is_folder()) + + def test_folder_get_child(self): + folder = self.project.root + folder.create_file('myfile.txt') + folder.create_folder('myfolder') + self.assertEquals(self.project.get_resource('myfile.txt'), + folder.get_child('myfile.txt')) + self.assertEquals(self.project.get_resource('myfolder'), + folder.get_child('myfolder')) + + def test_folder_get_child_nested(self): + root = self.project.root + folder = root.create_folder('myfolder') + folder.create_file('myfile.txt') + folder.create_folder('myfolder') + self.assertEquals(self.project.get_resource('myfolder/myfile.txt'), + folder.get_child('myfile.txt')) + self.assertEquals(self.project.get_resource('myfolder/myfolder'), + folder.get_child('myfolder')) + + def test_project_root_is_root_folder(self): + self.assertEquals('', self.project.root.path) + + def test_moving_files(self): + root_folder = self.project.root + my_file = root_folder.create_file('my_file.txt') + my_file.move('my_other_file.txt') + self.assertFalse(my_file.exists()) + root_folder.get_child('my_other_file.txt') + + def test_moving_folders(self): + root_folder = self.project.root + my_folder = root_folder.create_folder('my_folder') + my_file = my_folder.create_file('my_file.txt') + my_folder.move('new_folder') + self.assertFalse(root_folder.has_child('my_folder')) + self.assertFalse(my_file.exists()) + self.assertTrue(root_folder.get_child('new_folder') is not None) + + def test_moving_destination_folders(self): + root_folder = self.project.root + my_folder = root_folder.create_folder('my_folder') + my_file = root_folder.create_file('my_file.txt') + my_file.move('my_folder') + self.assertFalse(root_folder.has_child('my_file.txt')) + self.assertFalse(my_file.exists()) + my_folder.get_child('my_file.txt') + + def test_moving_files_and_resource_objects(self): + root_folder = self.project.root + my_file = root_folder.create_file('my_file.txt') + old_hash = hash(my_file) + my_file.move('my_other_file.txt') + self.assertEquals(old_hash, hash(my_file)) + + def test_file_encoding_reading(self): + sample_file = self.project.root.create_file('my_file.txt') + contents = u'# -*- coding: utf-8 -*-\n#\N{LATIN SMALL LETTER I WITH DIAERESIS}\n' + file = open(sample_file.real_path, 'w') + file.write(contents.encode('utf-8')) + file.close() + self.assertEquals(contents, sample_file.read()) + + def test_file_encoding_writing(self): + sample_file = self.project.root.create_file('my_file.txt') + contents = u'# -*- coding: utf-8 -*-\n\N{LATIN SMALL LETTER I WITH DIAERESIS}\n' + sample_file.write(contents) + self.assertEquals(contents, sample_file.read()) + + def test_using_utf8_when_writing_in_case_of_errors(self): + sample_file = self.project.root.create_file('my_file.txt') + contents = u'\n\N{LATIN SMALL LETTER I WITH DIAERESIS}\n' + sample_file.write(contents) + self.assertEquals(contents, sample_file.read()) + + def test_encoding_declaration_in_the_second_line(self): + sample_file = self.project.root.create_file('my_file.txt') + contents = '\n# -*- coding: latin-1 -*-\n\xa9\n' + file = open(sample_file.real_path, 'wb') + file.write(contents) + file.close() + self.assertEquals(contents, sample_file.read().encode('latin-1')) + + def test_read_bytes(self): + sample_file = self.project.root.create_file('my_file.txt') + contents = '\n# -*- coding: latin-1 -*-\n\xa9\n' + file = open(sample_file.real_path, 'wb') + file.write(contents) + file.close() + self.assertEquals(contents, sample_file.read_bytes()) + + # TODO: Detecting utf-16 encoding + def xxx_test_using_utf16(self): + sample_file = self.project.root.create_file('my_file.txt') + contents = '# -*- coding: utf-16 -*-\n# This is a sample file ...\n' + file = open(sample_file.real_path, 'w') + file.write(contents.encode('utf-16')) + file.close() + sample_file.write(contents) + self.assertEquals(contents, sample_file.read()) + + # XXX: supporting utf_8_sig + def xxx_test_file_encoding_reading_for_notepad_styles(self): + sample_file = self.project.root.create_file('my_file.txt') + contents = u'#\N{LATIN SMALL LETTER I WITH DIAERESIS}\n' + file = open(sample_file.real_path, 'w') + # file.write('\xef\xbb\xbf') + file.write(contents.encode('utf-8-sig')) + file.close() + self.assertEquals(contents, sample_file.read()) + + def test_using_project_get_file(self): + myfile = self.project.get_file(self.sample_file) + self.assertTrue(myfile.exists()) + + def test_using_file_create(self): + myfile = self.project.get_file('myfile.txt') + self.assertFalse(myfile.exists()) + myfile.create() + self.assertTrue(myfile.exists()) + self.assertFalse(myfile.is_folder()) + + def test_using_folder_create(self): + myfolder = self.project.get_folder('myfolder') + self.assertFalse(myfolder.exists()) + myfolder.create() + self.assertTrue(myfolder.exists()) + self.assertTrue(myfolder.is_folder()) + + @testutils.assert_raises(RopeError) + def test_exception_when_creating_twice(self): + myfile = self.project.get_file('myfile.txt') + myfile.create() + myfile.create() + + @testutils.assert_raises(ResourceNotFoundError) + def test_exception_when_parent_does_not_exist(self): + myfile = self.project.get_file('myfolder/myfile.txt') + myfile.create() + + def test_simple_path_to_resource(self): + myfile = self.project.root.create_file('myfile.txt') + self.assertEquals(myfile, path_to_resource(self.project, + myfile.real_path)) + self.assertEquals(myfile, path_to_resource( + self.project, myfile.real_path, type='file')) + myfolder = self.project.root.create_folder('myfolder') + self.assertEquals(myfolder, path_to_resource(self.project, + myfolder.real_path)) + self.assertEquals(myfolder, path_to_resource( + self.project, myfolder.real_path, type='folder')) + + @testutils.run_only_for_unix + def test_ignoring_symlinks_inside_project(self): + project2 = testutils.sample_project(folder_name='sampleproject2') + mod = project2.root.create_file('mod.py') + try: + path = os.path.join(self.project.address, 'linkedfile.txt') + os.symlink(mod.real_path, path) + files = self.project.root.get_files() + self.assertEquals(1, len(files)) + finally: + testutils.remove_project(project2) + + +class ResourceObserverTest(unittest.TestCase): + + def setUp(self): + super(ResourceObserverTest, self).setUp() + self.project = testutils.sample_project() + + def tearDown(self): + testutils.remove_project(self.project) + super(ResourceObserverTest, self).tearDown() + + def test_resource_change_observer(self): + sample_file = self.project.root.create_file('my_file.txt') + sample_file.write('a sample file version 1') + sample_observer = _SampleObserver() + self.project.add_observer(sample_observer) + sample_file.write('a sample file version 2') + self.assertEquals(1, sample_observer.change_count) + self.assertEquals(sample_file, sample_observer.last_changed) + + def test_resource_change_observer_after_removal(self): + sample_file = self.project.root.create_file('my_file.txt') + sample_file.write('text') + sample_observer = _SampleObserver() + self.project.add_observer(FilteredResourceObserver(sample_observer, + [sample_file])) + sample_file.remove() + self.assertEquals(1, sample_observer.change_count) + self.assertEquals(sample_file, sample_observer.last_removed) + + def test_resource_change_observer2(self): + sample_file = self.project.root.create_file('my_file.txt') + sample_observer = _SampleObserver() + self.project.add_observer(sample_observer) + self.project.remove_observer(sample_observer) + sample_file.write('a sample file version 2') + self.assertEquals(0, sample_observer.change_count) + + def test_resource_change_observer_for_folders(self): + root_folder = self.project.root + my_folder = root_folder.create_folder('my_folder') + my_folder_observer = _SampleObserver() + root_folder_observer = _SampleObserver() + self.project.add_observer(FilteredResourceObserver(my_folder_observer, + [my_folder])) + self.project.add_observer(FilteredResourceObserver(root_folder_observer, + [root_folder])) + my_file = my_folder.create_file('my_file.txt') + self.assertEquals(1, my_folder_observer.change_count) + my_file.move('another_file.txt') + self.assertEquals(2, my_folder_observer.change_count) + self.assertEquals(1, root_folder_observer.change_count) + self.project.get_resource('another_file.txt').remove() + self.assertEquals(2, my_folder_observer.change_count) + self.assertEquals(2, root_folder_observer.change_count) + + def test_resource_change_observer_after_moving(self): + sample_file = self.project.root.create_file('my_file.txt') + sample_observer = _SampleObserver() + self.project.add_observer(sample_observer) + sample_file.move('new_file.txt') + self.assertEquals(1, sample_observer.change_count) + self.assertEquals((sample_file, self.project.get_resource('new_file.txt')), + sample_observer.last_moved) + + def test_revalidating_files(self): + root = self.project.root + my_file = root.create_file('my_file.txt') + sample_observer = _SampleObserver() + self.project.add_observer(FilteredResourceObserver(sample_observer, + [my_file])) + os.remove(my_file.real_path) + self.project.validate(root) + self.assertEquals(my_file, sample_observer.last_removed) + self.assertEquals(1, sample_observer.change_count) + + def test_revalidating_files_and_no_changes2(self): + root = self.project.root + my_file = root.create_file('my_file.txt') + sample_observer = _SampleObserver() + self.project.add_observer(FilteredResourceObserver(sample_observer, + [my_file])) + self.project.validate(root) + self.assertEquals(None, sample_observer.last_moved) + self.assertEquals(0, sample_observer.change_count) + + def test_revalidating_folders(self): + root = self.project.root + my_folder = root.create_folder('myfolder') + my_file = my_folder.create_file('myfile.txt') + sample_observer = _SampleObserver() + self.project.add_observer(FilteredResourceObserver(sample_observer, + [my_folder])) + testutils.remove_recursively(my_folder.real_path) + self.project.validate(root) + self.assertEquals(my_folder, sample_observer.last_removed) + self.assertEquals(1, sample_observer.change_count) + + def test_removing_and_adding_resources_to_filtered_observer(self): + my_file = self.project.root.create_file('my_file.txt') + sample_observer = _SampleObserver() + filtered_observer = FilteredResourceObserver(sample_observer) + self.project.add_observer(filtered_observer) + my_file.write('1') + self.assertEquals(0, sample_observer.change_count) + filtered_observer.add_resource(my_file) + my_file.write('2') + self.assertEquals(1, sample_observer.change_count) + filtered_observer.remove_resource(my_file) + my_file.write('3') + self.assertEquals(1, sample_observer.change_count) + + def test_validation_and_changing_files(self): + my_file = self.project.root.create_file('my_file.txt') + sample_observer = _SampleObserver() + timekeeper = _MockChangeIndicator() + filtered_observer = FilteredResourceObserver(sample_observer, [my_file], + timekeeper=timekeeper) + self.project.add_observer(filtered_observer) + self._write_file(my_file.real_path) + timekeeper.set_indicator(my_file, 1) + self.project.validate(self.project.root) + self.assertEquals(1, sample_observer.change_count) + + def test_validation_and_changing_files2(self): + my_file = self.project.root.create_file('my_file.txt') + sample_observer = _SampleObserver() + timekeeper = _MockChangeIndicator() + self.project.add_observer(FilteredResourceObserver( + sample_observer, [my_file], + timekeeper=timekeeper)) + timekeeper.set_indicator(my_file, 1) + my_file.write('hey') + self.assertEquals(1, sample_observer.change_count) + self.project.validate(self.project.root) + self.assertEquals(1, sample_observer.change_count) + + def test_not_reporting_multiple_changes_to_folders(self): + root = self.project.root + file1 = root.create_file('file1.txt') + file2 = root.create_file('file2.txt') + sample_observer = _SampleObserver() + self.project.add_observer(FilteredResourceObserver( + sample_observer, [root, file1, file2])) + os.remove(file1.real_path) + os.remove(file2.real_path) + self.assertEquals(0, sample_observer.change_count) + self.project.validate(self.project.root) + self.assertEquals(3, sample_observer.change_count) + + def _write_file(self, path): + my_file = open(path, 'w') + my_file.write('\n') + my_file.close() + + def test_moving_and_being_interested_about_a_folder_and_a_child(self): + my_folder = self.project.root.create_folder('my_folder') + my_file = my_folder.create_file('my_file.txt') + sample_observer = _SampleObserver() + filtered_observer = FilteredResourceObserver( + sample_observer, [my_folder, my_file]) + self.project.add_observer(filtered_observer) + my_folder.move('new_folder') + self.assertEquals(2, sample_observer.change_count) + + def test_contains_for_folders(self): + folder1 = self.project.root.create_folder('folder') + folder2 = self.project.root.create_folder('folder2') + self.assertFalse(folder1.contains(folder2)) + + def test_validating_when_created(self): + root = self.project.root + my_file = self.project.get_file('my_file.txt') + sample_observer = _SampleObserver() + self.project.add_observer(FilteredResourceObserver(sample_observer, + [my_file])) + file(my_file.real_path, 'w').close() + self.project.validate(root) + self.assertEquals(my_file, sample_observer.last_created) + self.assertEquals(1, sample_observer.change_count) + + def test_validating_twice_when_created(self): + root = self.project.root + my_file = self.project.get_file('my_file.txt') + sample_observer = _SampleObserver() + self.project.add_observer(FilteredResourceObserver(sample_observer, + [my_file])) + file(my_file.real_path, 'w').close() + self.project.validate(root) + self.project.validate(root) + self.assertEquals(my_file, sample_observer.last_created) + self.assertEquals(1, sample_observer.change_count) + + def test_changes_and_adding_resources(self): + root = self.project.root + file1 = self.project.get_file('file1.txt') + file2 = self.project.get_file('file2.txt') + file1.create() + sample_observer = _SampleObserver() + self.project.add_observer(FilteredResourceObserver(sample_observer, + [file1, file2])) + file1.move(file2.path) + self.assertEquals(2, sample_observer.change_count) + self.assertEquals(file2, sample_observer.last_created) + self.assertEquals((file1, file2), sample_observer.last_moved) + + def test_validating_get_files_list(self): + root = self.project.root + self.assertEquals(0, len(self.project.get_files())) + file = open(os.path.join(self.project.address, 'myfile.txt'), 'w') + file.close() + self.project.validate() + self.assertEquals(1, len(self.project.get_files())) + + def test_clear_observered_resources_for_filtered_observers(self): + sample_file = self.project.root.create_file('myfile.txt') + sample_observer = _SampleObserver() + filtered = FilteredResourceObserver(sample_observer) + self.project.add_observer(filtered) + filtered.add_resource(sample_file) + filtered.clear_resources() + sample_file.write('1') + self.assertEquals(0, sample_observer.change_count) + + +class _MockChangeIndicator(object): + + def __init__(self): + self.times = {} + + def set_indicator(self, resource, time): + self.times[resource] = time + + def get_indicator(self, resource): + return self.times.get(resource, 0) + + +class _SampleObserver(object): + + def __init__(self): + self.change_count = 0 + self.last_changed = None + self.last_moved = None + self.last_created = None + self.last_removed = None + + def resource_changed(self, resource): + self.last_changed = resource + self.change_count += 1 + + def resource_moved(self, resource, new_resource): + self.last_moved = (resource, new_resource) + self.change_count += 1 + + def resource_created(self, resource): + self.last_created = resource + self.change_count += 1 + + def resource_removed(self, resource): + self.last_removed = resource + self.change_count += 1 + + +class OutOfProjectTest(unittest.TestCase): + + def setUp(self): + super(OutOfProjectTest, self).setUp() + self.test_directory = 'temp_test_directory' + testutils.remove_recursively(self.test_directory) + os.mkdir(self.test_directory) + self.project = testutils.sample_project() + self.no_project = NoProject() + + def tearDown(self): + testutils.remove_project(self.project) + testutils.remove_recursively(self.test_directory) + super(OutOfProjectTest, self).tearDown() + + def test_simple_out_of_project_file(self): + sample_file_path = os.path.join(self.test_directory, 'sample.txt') + sample_file = file(sample_file_path, 'w') + sample_file.write('sample content\n') + sample_file.close() + sample_resource = self.no_project.get_resource(sample_file_path) + self.assertEquals('sample content\n', sample_resource.read()) + + def test_simple_out_of_project_folder(self): + sample_folder_path = os.path.join(self.test_directory, 'sample_folder') + os.mkdir(sample_folder_path) + sample_folder = self.no_project.get_resource(sample_folder_path) + self.assertEquals([], sample_folder.get_children()) + + sample_file_path = os.path.join(sample_folder_path, 'sample.txt') + file(sample_file_path, 'w').close() + sample_resource = self.no_project.get_resource(sample_file_path) + self.assertEquals(sample_resource, sample_folder.get_children()[0]) + + def test_using_absolute_path(self): + sample_file_path = os.path.join(self.test_directory, 'sample.txt') + file(sample_file_path, 'w').close() + normal_sample_resource = self.no_project.get_resource(sample_file_path) + absolute_sample_resource = \ + self.no_project.get_resource(os.path.abspath(sample_file_path)) + self.assertEquals(normal_sample_resource, absolute_sample_resource) + + def test_folder_get_child(self): + sample_folder_path = os.path.join(self.test_directory, 'sample_folder') + os.mkdir(sample_folder_path) + sample_folder = self.no_project.get_resource(sample_folder_path) + self.assertEquals([], sample_folder.get_children()) + + sample_file_path = os.path.join(sample_folder_path, 'sample.txt') + file(sample_file_path, 'w').close() + sample_resource = self.no_project.get_resource(sample_file_path) + self.assertTrue(sample_folder.has_child('sample.txt')) + self.assertFalse(sample_folder.has_child('doesnothave.txt')) + self.assertEquals(sample_resource, sample_folder.get_child('sample.txt')) + + def test_out_of_project_files_and_path_to_resource(self): + sample_file_path = os.path.join(self.test_directory, 'sample.txt') + sample_file = file(sample_file_path, 'w') + sample_file.write('sample content\n') + sample_file.close() + sample_resource = self.no_project.get_resource(sample_file_path) + self.assertEquals(sample_resource, + path_to_resource(self.project, sample_file_path)) + + +class _MockFSCommands(object): + + def __init__(self): + self.log = '' + self.fscommands = FileSystemCommands() + + def create_file(self, path): + self.log += 'create_file ' + self.fscommands.create_file(path) + + def create_folder(self, path): + self.log += 'create_folder ' + self.fscommands.create_folder(path) + + def move(self, path, new_location): + self.log += 'move ' + self.fscommands.move(path, new_location) + + def remove(self, path): + self.log += 'remove ' + self.fscommands.remove(path) + + +class RopeFolderTest(unittest.TestCase): + + def setUp(self): + super(RopeFolderTest, self).setUp() + self.project = None + + def tearDown(self): + if self.project: + testutils.remove_project(self.project) + super(RopeFolderTest, self).tearDown() + + def test_none_project_rope_folder(self): + self.project = testutils.sample_project(ropefolder=None) + self.assertTrue(self.project.ropefolder is None) + + def test_getting_project_rope_folder(self): + self.project = testutils.sample_project(ropefolder='.ropeproject') + self.assertTrue(self.project.ropefolder.exists()) + self.assertTrue('.ropeproject', self.project.ropefolder.path) + + def test_setting_ignored_resources(self): + self.project = testutils.sample_project(ignored_resources=['myfile.txt']) + myfile = self.project.get_file('myfile.txt') + file2 = self.project.get_file('file2.txt') + self.assertTrue(self.project.is_ignored(myfile)) + self.assertFalse(self.project.is_ignored(file2)) + + def test_ignored_folders(self): + self.project = testutils.sample_project(ignored_resources=['myfolder']) + myfolder = self.project.root.create_folder('myfolder') + self.assertTrue(self.project.is_ignored(myfolder)) + myfile = myfolder.create_file('myfile.txt') + self.assertTrue(self.project.is_ignored(myfile)) + + def test_ignored_resources_and_get_files(self): + self.project = testutils.sample_project( + ignored_resources=['myfile.txt'], ropefolder=None) + myfile = self.project.get_file('myfile.txt') + self.assertEquals(0, len(self.project.get_files())) + myfile.create() + self.assertEquals(0, len(self.project.get_files())) + + def test_ignored_resources_and_get_files2(self): + self.project = testutils.sample_project( + ignored_resources=['myfile.txt'], ropefolder=None) + myfile = self.project.root.create_file('myfile.txt') + self.assertEquals(0, len(self.project.get_files())) + + def test_setting_ignored_resources_patterns(self): + self.project = testutils.sample_project(ignored_resources=['m?file.*']) + myfile = self.project.get_file('myfile.txt') + file2 = self.project.get_file('file2.txt') + self.assertTrue(self.project.is_ignored(myfile)) + self.assertFalse(self.project.is_ignored(file2)) + + def test_star_should_not_include_slashes(self): + self.project = testutils.sample_project(ignored_resources=['f*.txt']) + folder = self.project.root.create_folder('folder') + file1 = folder.create_file('myfile.txt') + file2 = folder.create_file('file2.txt') + self.assertFalse(self.project.is_ignored(file1)) + self.assertTrue(self.project.is_ignored(file2)) + + def test_normal_fscommands(self): + fscommands = _MockFSCommands() + self.project = testutils.sample_project(fscommands=fscommands) + myfile = self.project.get_file('myfile.txt') + myfile.create() + self.assertTrue('create_file ', fscommands.log) + + def test_fscommands_and_ignored_resources(self): + fscommands = _MockFSCommands() + self.project = testutils.sample_project( + fscommands=fscommands, ignored_resources=['myfile.txt'], ropefolder=None) + myfile = self.project.get_file('myfile.txt') + myfile.create() + self.assertEquals('', fscommands.log) + + def test_ignored_resources_and_prefixes(self): + self.project = testutils.sample_project( + ignored_resources=['.hg']) + myfile = self.project.root.create_file('.hgignore') + self.assertFalse(self.project.is_ignored(myfile)) + + def test_loading_config_dot_py(self): + self.project = testutils.sample_project(ropefolder='.ropeproject') + config = self.project.get_file('.ropeproject/config.py') + if not config.exists(): + config.create() + config.write('def set_prefs(prefs):\n' + ' prefs["ignored_resources"] = ["myfile.txt"]\n' + 'def project_opened(project):\n' + ' project.root.create_file("loaded")\n') + self.project.close() + self.project = Project(self.project.address, ropefolder='.ropeproject') + self.assertTrue(self.project.get_file('loaded').exists()) + myfile = self.project.get_file('myfile.txt') + self.assertTrue(self.project.is_ignored(myfile)) + + def test_ignoring_syntax_errors(self): + self.project = testutils.sample_project(ropefolder=None, + ignore_syntax_errors=True) + pycore = self.project.pycore + mod = testutils.create_module(self.project, 'mod') + mod.write('xyz print') + pymod = pycore.resource_to_pyobject(mod) + + def test_compressed_history(self): + self.project = testutils.sample_project(compress_history=True) + mod = testutils.create_module(self.project, 'mod') + mod.write('') + + def test_compressed_objectdb(self): + self.project = testutils.sample_project(compress_objectdb=True) + mod = testutils.create_module(self.project, 'mod') + self.project.pycore.analyze_module(mod) + + def test_nested_dot_ropeproject_folder(self): + self.project = testutils.sample_project(ropefolder='.f1/f2') + ropefolder = self.project.ropefolder + self.assertEquals('.f1/f2', ropefolder.path) + self.assertTrue(ropefolder.exists()) + + +def suite(): + result = unittest.TestSuite() + result.addTests(unittest.makeSuite(ProjectTest)) + result.addTests(unittest.makeSuite(ResourceObserverTest)) + result.addTests(unittest.makeSuite(OutOfProjectTest)) + result.addTests(unittest.makeSuite(RopeFolderTest)) + return result + +if __name__ == '__main__': + unittest.main() diff -r e30544496575 -r 48cacfdc2ca6 vim/sadness/ropevim/src/rope/ropetest/pycoretest.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vim/sadness/ropevim/src/rope/ropetest/pycoretest.py Wed Oct 06 12:30:46 2010 -0400 @@ -0,0 +1,1110 @@ +import sys +import unittest + +from rope.base import exceptions +from rope.base.pycore import _TextChangeDetector +from rope.base.pyobjects import get_base_type, AbstractFunction +from ropetest import testutils + + +class PyCoreTest(unittest.TestCase): + + def setUp(self): + super(PyCoreTest, self).setUp() + self.project = testutils.sample_project() + self.pycore = self.project.pycore + + def tearDown(self): + testutils.remove_project(self.project) + super(PyCoreTest, self).tearDown() + + def test_simple_module(self): + testutils.create_module(self.project, 'mod') + result = self.pycore.get_module('mod') + self.assertEquals(get_base_type('Module'), result.type) + self.assertEquals(0, len(result.get_attributes())) + + def test_nested_modules(self): + pkg = testutils.create_package(self.project, 'pkg') + mod = testutils.create_module(self.project, 'mod', pkg) + package = self.pycore.get_module('pkg') + self.assertEquals(get_base_type('Module'), package.get_type()) + self.assertEquals(1, len(package.get_attributes())) + module = package['mod'].get_object() + self.assertEquals(get_base_type('Module'), module.get_type()) + + def test_package(self): + pkg = testutils.create_package(self.project, 'pkg') + mod = testutils.create_module(self.project, 'mod', pkg) + result = self.pycore.get_module('pkg') + self.assertEquals(get_base_type('Module'), result.type) + + def test_simple_class(self): + mod = testutils.create_module(self.project, 'mod') + mod.write('class SampleClass(object):\n pass\n') + mod_element = self.pycore.get_module('mod') + result = mod_element['SampleClass'].get_object() + self.assertEquals(get_base_type('Type'), result.get_type()) + + def test_simple_function(self): + mod = testutils.create_module(self.project, 'mod') + mod.write('def sample_function():\n pass\n') + mod_element = self.pycore.get_module('mod') + result = mod_element['sample_function'].get_object() + self.assertEquals(get_base_type('Function'), result.get_type()) + + def test_class_methods(self): + mod = testutils.create_module(self.project, 'mod') + code = 'class SampleClass(object):\n' \ + ' def sample_method(self):\n' \ + ' pass\n' + mod.write(code) + mod_element = self.pycore.get_module('mod') + sample_class = mod_element['SampleClass'].get_object() + self.assertTrue('sample_method' in sample_class) + method = sample_class['sample_method'].get_object() + self.assertEquals(get_base_type('Function'), method.get_type()) + + def test_global_variables(self): + mod = testutils.create_module(self.project, 'mod') + mod.write('var = 10') + mod_element = self.pycore.get_module('mod') + result = mod_element['var'] + + def test_class_variables(self): + mod = testutils.create_module(self.project, 'mod') + mod.write('class SampleClass(object):\n var = 10\n') + mod_element = self.pycore.get_module('mod') + sample_class = mod_element['SampleClass'].get_object() + var = sample_class['var'] + + def test_class_attributes_set_in_init(self): + mod = testutils.create_module(self.project, 'mod') + mod.write('class C(object):\n' + ' def __init__(self):\n self.var = 20\n') + mod_element = self.pycore.get_module('mod') + sample_class = mod_element['C'].get_object() + var = sample_class['var'] + + def test_class_attributes_set_in_init_overwriting_a_defined(self): + mod = testutils.create_module(self.project, 'mod') + code = 'class C(object):\n' \ + ' def __init__(self):\n' \ + ' self.f = 20\n' \ + ' def f():\n' \ + ' pass\n' + mod.write(code) + mod_element = self.pycore.get_module('mod') + sample_class = mod_element['C'].get_object() + f = sample_class['f'].get_object() + self.assertTrue(isinstance(f, AbstractFunction)) + + def test_classes_inside_other_classes(self): + mod = testutils.create_module(self.project, 'mod') + code = 'class SampleClass(object):\n' \ + ' class InnerClass(object):\n' \ + ' pass\n\n' + mod.write(code) + mod_element = self.pycore.get_module('mod') + sample_class = mod_element['SampleClass'].get_object() + var = sample_class['InnerClass'].get_object() + self.assertEquals(get_base_type('Type'), var.get_type()) + + @testutils.assert_raises(exceptions.ModuleNotFoundError) + def test_non_existent_module(self): + self.pycore.get_module('doesnotexistmodule') + + def test_imported_names(self): + testutils.create_module(self.project, 'mod1') + mod = testutils.create_module(self.project, 'mod2') + mod.write('import mod1\n') + module = self.pycore.get_module('mod2') + imported_sys = module['mod1'].get_object() + self.assertEquals(get_base_type('Module'), imported_sys.get_type()) + + def test_imported_as_names(self): + testutils.create_module(self.project, 'mod1') + mod = testutils.create_module(self.project, 'mod2') + mod.write('import mod1 as my_import\n') + module = self.pycore.get_module('mod2') + imported_mod = module['my_import'].get_object() + self.assertEquals(get_base_type('Module'), imported_mod.get_type()) + + def test_get_string_module(self): + mod = self.pycore.get_string_module('class Sample(object):\n pass\n') + sample_class = mod['Sample'].get_object() + self.assertEquals(get_base_type('Type'), sample_class.get_type()) + + def test_get_string_module_with_extra_spaces(self): + mod = self.pycore.get_string_module('a = 10\n ') + + def test_parameter_info_for_functions(self): + code = 'def func(param1, param2=10, *param3, **param4):\n pass' + mod = self.pycore.get_string_module(code) + sample_function = mod['func'] + self.assertEquals(['param1', 'param2', 'param3', 'param4'], + sample_function.get_object().get_param_names()) + + # FIXME: Not found modules + def xxx_test_not_found_module_is_module(self): + mod = self.pycore.get_string_module('import doesnotexist\n') + self.assertEquals(get_base_type('Module'), + mod['doesnotexist']. + get_object().get_type()) + + def test_mixing_scopes_and_objects_hierarchy(self): + mod = self.pycore.get_string_module('var = 200\n') + scope = mod.get_scope() + self.assertTrue('var' in scope.get_names()) + + def test_inheriting_base_class_attributes(self): + code = 'class Base(object):\n' \ + ' def method(self):\n' \ + ' pass\n' \ + 'class Derived(Base):\n' \ + ' pass\n' + mod = self.pycore.get_string_module(code) + derived = mod['Derived'].get_object() + self.assertTrue('method' in derived) + self.assertEquals(get_base_type('Function'), + derived['method'].get_object().get_type()) + + def test_inheriting_multiple_base_class_attributes(self): + code = 'class Base1(object):\n def method1(self):\n pass\n' \ + 'class Base2(object):\n def method2(self):\n pass\n' \ + 'class Derived(Base1, Base2):\n pass\n' + mod = self.pycore.get_string_module(code) + derived = mod['Derived'].get_object() + self.assertTrue('method1' in derived) + self.assertTrue('method2' in derived) + + def test_inheriting_multiple_base_class_attributes_with_the_same_name(self): + code = 'class Base1(object):\n def method(self):\n pass\n' \ + 'class Base2(object):\n def method(self):\n pass\n' \ + 'class Derived(Base1, Base2):\n pass\n' + mod = self.pycore.get_string_module(code) + base1 = mod['Base1'].get_object() + derived = mod['Derived'].get_object() + self.assertEquals(base1['method'].get_object(), + derived['method'].get_object()) + + def test_inheriting_unknown_base_class(self): + code = 'class Derived(NotFound):\n' \ + ' def f(self):\n' \ + ' pass\n' + mod = self.pycore.get_string_module(code) + derived = mod['Derived'].get_object() + self.assertTrue('f' in derived) + + def test_module_creation(self): + new_module = testutils.create_module(self.project, 'module') + self.assertFalse(new_module.is_folder()) + self.assertEquals(self.project.get_resource('module.py'), new_module) + + def test_packaged_module_creation(self): + package = self.project.root.create_folder('package') + new_module = testutils.create_module(self.project, 'package.module') + self.assertEquals(self.project.get_resource('package/module.py'), new_module) + + def test_packaged_module_creation_with_nested_src(self): + src = self.project.root.create_folder('src') + package = src.create_folder('pkg') + new_module = testutils.create_module(self.project, 'pkg.mod', src) + self.assertEquals(self.project.get_resource('src/pkg/mod.py'), new_module) + + def test_package_creation(self): + new_package = testutils.create_package(self.project, 'pkg') + self.assertTrue(new_package.is_folder()) + self.assertEquals(self.project.get_resource('pkg'), new_package) + self.assertEquals(self.project.get_resource('pkg/__init__.py'), + new_package.get_child('__init__.py')); + + def test_nested_package_creation(self): + package = testutils.create_package(self.project, 'pkg1') + nested_package = testutils.create_package(self.project, 'pkg1.pkg2') + self.assertEquals(self.project.get_resource('pkg1/pkg2'), nested_package) + + def test_packaged_package_creation_with_nested_src(self): + src = self.project.root.create_folder('src') + package = testutils.create_package(self.project, 'pkg1', src) + nested_package = testutils.create_package(self.project, 'pkg1.pkg2', src) + self.assertEquals(self.project.get_resource('src/pkg1/pkg2'), nested_package) + + def test_find_module(self): + src = self.project.root.create_folder('src') + samplemod = testutils.create_module(self.project, 'samplemod', src) + found_module = self.pycore.find_module('samplemod') + self.assertEquals(samplemod, found_module) + + def test_find_nested_module(self): + src = self.project.root.create_folder('src') + samplepkg = testutils.create_package(self.project, 'samplepkg', src) + samplemod = testutils.create_module(self.project, 'samplemod', samplepkg) + found_module = self.pycore.find_module('samplepkg.samplemod') + self.assertEquals(samplemod, found_module) + + def test_find_multiple_module(self): + src = self.project.root.create_folder('src') + samplemod1 = testutils.create_module(self.project, 'samplemod', src) + samplemod2 = testutils.create_module(self.project, 'samplemod') + test = self.project.root.create_folder('test') + samplemod3 = testutils.create_module(self.project, 'samplemod', test) + found_module = self.pycore.find_module('samplemod') + self.assertTrue(samplemod1 == found_module or + samplemod2 == found_module or + samplemod3 == found_module) + + def test_find_module_packages(self): + src = self.project.root + samplepkg = testutils.create_package(self.project, 'samplepkg', src) + found_module = self.pycore.find_module('samplepkg') + self.assertEquals(samplepkg, found_module) + + def test_find_module_when_module_and_package_with_the_same_name(self): + src = self.project.root + samplemod = testutils.create_module(self.project, 'sample', src) + samplepkg = testutils.create_package(self.project, 'sample', src) + found_module = self.pycore.find_module('sample') + self.assertEquals(samplepkg, found_module) + + def test_source_folders_preference(self): + pkg1 = testutils.create_package(self.project, 'pkg1') + src2 = testutils.create_package(self.project, 'pkg1.src2') + lost = testutils.create_module(self.project, 'pkg1.src2.lost') + self.assertEqual(self.project.pycore.find_module('lost'), None) + self.project.close() + from rope.base.project import Project + self.project = Project(self.project.address, + source_folders=['pkg1/src2']) + self.assertEqual(self.project.pycore.find_module('lost'), lost) + + def test_getting_empty_source_folders(self): + self.assertEquals([], self.pycore.get_source_folders()) + + def test_root_source_folder(self): + self.project.root.create_file('sample.py') + source_folders = self.pycore.get_source_folders() + self.assertEquals(1, len(source_folders)) + self.assertTrue(self.project.root in source_folders) + + def test_root_source_folder2(self): + self.project.root.create_file('mod1.py') + self.project.root.create_file('mod2.py') + source_folders = self.pycore.get_source_folders() + self.assertEquals(1, len(source_folders)) + self.assertTrue(self.project.root in source_folders) + + def test_src_source_folder(self): + src = self.project.root.create_folder('src') + src.create_file('sample.py') + source_folders = self.pycore.get_source_folders() + self.assertEquals(1, len(source_folders)) + self.assertTrue(self.project.get_resource('src') in source_folders) + + def test_packages(self): + src = self.project.root.create_folder('src') + pkg = src.create_folder('package') + pkg.create_file('__init__.py') + source_folders = self.pycore.get_source_folders() + self.assertEquals(1, len(source_folders)) + self.assertTrue(src in source_folders) + + def test_multi_source_folders(self): + src = self.project.root.create_folder('src') + package = src.create_folder('package') + package.create_file('__init__.py') + test = self.project.root.create_folder('test') + test.create_file('alltests.py') + source_folders = self.pycore.get_source_folders() + self.assertEquals(2, len(source_folders)) + self.assertTrue(src in source_folders) + self.assertTrue(test in source_folders) + + def test_multi_source_folders2(self): + mod1 = testutils.create_module(self.project, 'mod1') + src = self.project.root.create_folder('src') + package = testutils.create_package(self.project, 'package', src) + mod2 = testutils.create_module(self.project, 'mod2', package) + source_folders = self.pycore.get_source_folders() + self.assertEquals(2, len(source_folders)) + self.assertTrue(self.project.root in source_folders and \ + src in source_folders) + + def test_get_pyname_definition_location(self): + mod = self.pycore.get_string_module('a_var = 20\n') + a_var = mod['a_var'] + self.assertEquals((mod, 1), a_var.get_definition_location()) + + def test_get_pyname_definition_location_functions(self): + mod = self.pycore.get_string_module('def a_func():\n pass\n') + a_func = mod['a_func'] + self.assertEquals((mod, 1), a_func.get_definition_location()) + + def test_get_pyname_definition_location_class(self): + code = 'class AClass(object):\n pass\n\n' + mod = self.pycore.get_string_module(code) + a_class = mod['AClass'] + self.assertEquals((mod, 1), a_class.get_definition_location()) + + def test_get_pyname_definition_location_local_variables(self): + mod = self.pycore.get_string_module('def a_func():\n a_var = 10\n') + a_func_scope = mod.get_scope().get_scopes()[0] + a_var = a_func_scope['a_var'] + self.assertEquals((mod, 2), a_var.get_definition_location()) + + def test_get_pyname_definition_location_reassigning(self): + mod = self.pycore.get_string_module('a_var = 20\na_var=30\n') + a_var = mod['a_var'] + self.assertEquals((mod, 1), a_var.get_definition_location()) + + def test_get_pyname_definition_location_importes(self): + module = testutils.create_module(self.project, 'mod') + mod = self.pycore.get_string_module('import mod\n') + imported_module = self.pycore.get_module('mod') + module_pyname = mod['mod'] + self.assertEquals((imported_module, 1), + module_pyname.get_definition_location()) + + def test_get_pyname_definition_location_imports(self): + module_resource = testutils.create_module(self.project, 'mod') + module_resource.write('\ndef a_func():\n pass\n') + imported_module = self.pycore.get_module('mod') + mod = self.pycore.get_string_module('from mod import a_func\n') + a_func = mod['a_func'] + self.assertEquals((imported_module, 2), a_func.get_definition_location()) + + def test_get_pyname_definition_location_parameters(self): + code = 'def a_func(param1, param2):\n a_var = param\n' + mod = self.pycore.get_string_module(code) + a_func_scope = mod.get_scope().get_scopes()[0] + param1 = a_func_scope['param1'] + self.assertEquals((mod, 1), param1.get_definition_location()) + param2 = a_func_scope['param2'] + self.assertEquals((mod, 1), param2.get_definition_location()) + + def test_module_get_resource(self): + module_resource = testutils.create_module(self.project, 'mod') + module = self.pycore.get_module('mod') + self.assertEquals(module_resource, module.get_resource()) + string_module = self.pycore.get_string_module('from mod import a_func\n') + self.assertEquals(None, string_module.get_resource()) + + def test_get_pyname_definition_location_class2(self): + code = 'class AClass(object):\n' \ + ' def __init__(self):\n' \ + ' self.an_attr = 10\n' + mod = self.pycore.get_string_module(code) + a_class = mod['AClass'].get_object() + an_attr = a_class['an_attr'] + self.assertEquals((mod, 3), an_attr.get_definition_location()) + + def test_import_not_found_module_get_definition_location(self): + mod = self.pycore.get_string_module('import doesnotexist\n') + does_not_exist = mod['doesnotexist'] + self.assertEquals((None, None), does_not_exist.get_definition_location()) + + def test_from_not_found_module_get_definition_location(self): + mod = self.pycore.get_string_module('from doesnotexist import Sample\n') + sample = mod['Sample'] + self.assertEquals((None, None), sample.get_definition_location()) + + def test_from_package_import_module_get_definition_location(self): + pkg = testutils.create_package(self.project, 'pkg') + testutils.create_module(self.project, 'mod', pkg) + pkg_mod = self.pycore.get_module('pkg.mod') + mod = self.pycore.get_string_module('from pkg import mod\n') + imported_mod = mod['mod'] + self.assertEquals((pkg_mod, 1), + imported_mod.get_definition_location()) + + def test_get_module_for_defined_pyobjects(self): + mod = self.pycore.get_string_module('class AClass(object):\n pass\n') + a_class = mod['AClass'].get_object() + self.assertEquals(mod, a_class.get_module()) + + def test_get_definition_location_for_packages(self): + pkg = testutils.create_package(self.project, 'pkg') + init_module = self.pycore.get_module('pkg.__init__') + mod = self.pycore.get_string_module('import pkg\n') + pkg_pyname = mod['pkg'] + self.assertEquals((init_module, 1), pkg_pyname.get_definition_location()) + + def test_get_definition_location_for_filtered_packages(self): + pkg = testutils.create_package(self.project, 'pkg') + testutils.create_module(self.project, 'mod', pkg) + init_module = self.pycore.get_module('pkg.__init__') + mod = self.pycore.get_string_module('import pkg.mod') + pkg_pyname = mod['pkg'] + self.assertEquals((init_module, 1), pkg_pyname.get_definition_location()) + + def test_out_of_project_modules(self): + scope = self.pycore.get_string_scope('import rope.base.project as project\n') + imported_module = scope['project'].get_object() + self.assertTrue('Project' in imported_module) + + def test_file_encoding_reading(self): + contents = u'# -*- coding: utf-8 -*-\n#\N{LATIN SMALL LETTER I WITH DIAERESIS}\n' + mod = testutils.create_module(self.project, 'mod') + mod.write(contents) + self.pycore.get_module('mod') + + def test_global_keyword(self): + contents = 'a_var = 1\ndef a_func():\n global a_var\n' + mod = self.pycore.get_string_module(contents) + global_var = mod['a_var'] + func_scope = mod['a_func'].get_object().get_scope() + local_var = func_scope['a_var'] + self.assertEquals(global_var, local_var) + + def test_not_leaking_for_vars_inside_parent_scope(self): + mod = testutils.create_module(self.project, 'mod') + code = 'class C(object):\n' \ + ' def f(self):\n' \ + ' for my_var1, my_var2 in []:\n' \ + ' pass\n' + mod.write(code) + pymod = self.pycore.resource_to_pyobject(mod) + c_class = pymod['C'].get_object() + self.assertFalse('my_var1' in c_class) + self.assertFalse('my_var2' in c_class) + + def test_not_leaking_for_vars_inside_parent_scope2(self): + mod = testutils.create_module(self.project, 'mod') + code = 'class C(object):\n' \ + ' def f(self):\n' \ + ' for my_var in []:\n' \ + ' pass\n' + mod.write(code) + pymod = self.pycore.resource_to_pyobject(mod) + c_class = pymod['C'].get_object() + self.assertFalse('my_var' in c_class) + + def test_variables_defined_in_excepts(self): + mod = testutils.create_module(self.project, 'mod') + code = 'try:\n' \ + ' myvar1 = 1\n' \ + 'except:\n' \ + ' myvar2 = 1\n' \ + 'finally:\n' \ + ' myvar3 = 1\n' + mod.write(code) + pymod = self.pycore.resource_to_pyobject(mod) + self.assertTrue('myvar1' in pymod) + self.assertTrue('myvar2' in pymod) + self.assertTrue('myvar3' in pymod) + + def test_not_leaking_tuple_assigned_names_inside_parent_scope(self): + mod = testutils.create_module(self.project, 'mod') + code = 'class C(object):\n' \ + ' def f(self):\n' \ + ' var1, var2 = range(2)\n' + mod.write(code) + pymod = self.pycore.resource_to_pyobject(mod) + c_class = pymod['C'].get_object() + self.assertFalse('var1' in c_class) + + @testutils.run_only_for_25 + def test_with_statement_variables(self): + code = 'import threading\nwith threading.lock() as var: pass\n' + if sys.version_info < (2, 6, 0): + code = 'from __future__ import with_statement\n' + code + pymod = self.pycore.get_string_module(code) + self.assertTrue('var' in pymod) + + @testutils.run_only_for_25 + def test_with_statement_variables_and_tuple_assignment(self): + code = 'class A(object):\n' \ + ' def __enter__(self):' \ + ' return (1, 2)\n' \ + ' def __exit__(self, type, value, tb):\n' \ + ' pass\n'\ + 'with A() as (a, b):\n' \ + ' pass\n' + if sys.version_info < (2, 6, 0): + code = 'from __future__ import with_statement\n' + code + pymod = self.pycore.get_string_module(code) + self.assertTrue('a' in pymod) + self.assertTrue('b' in pymod) + + @testutils.run_only_for_25 + def test_with_statement_variable_type(self): + code = 'class A(object):\n' \ + ' def __enter__(self):\n' \ + ' return self\n'\ + ' def __exit__(self, type, value, tb):\n' \ + ' pass\n' \ + 'with A() as var:\n' \ + ' pass\n' + if sys.version_info < (2, 6, 0): + code = 'from __future__ import with_statement\n' + code + pymod = self.pycore.get_string_module(code) + a_class = pymod['A'].get_object() + var = pymod['var'].get_object() + self.assertEquals(a_class, var.get_type()) + + @testutils.run_only_for_25 + def test_with_statement_with_no_vars(self): + code = 'with open("file"): pass\n' + if sys.version_info < (2, 6, 0): + code = 'from __future__ import with_statement\n' + code + pymod = self.pycore.get_string_module(code) + pymod.get_attributes() + + def test_check_for_else_block(self): + code = 'for i in range(10):\n' \ + ' pass\n' \ + 'else:\n' \ + ' myvar = 1\n' + mod = self.pycore.get_string_module(code) + a_var = mod['myvar'] + self.assertEquals((mod, 4), a_var.get_definition_location()) + + def test_check_names_defined_in_whiles(self): + mod = self.pycore.get_string_module('while False:\n myvar = 1\n') + a_var = mod['myvar'] + self.assertEquals((mod, 2), a_var.get_definition_location()) + + def test_get_definition_location_in_tuple_assnames(self): + mod = self.pycore.get_string_module( + 'def f(x):\n x.z, a = range(2)\n') + x = mod['f'].get_object().get_scope()['x'] + a = mod['f'].get_object().get_scope()['a'] + self.assertEquals((mod, 1), x.get_definition_location()) + self.assertEquals((mod, 2), a.get_definition_location()) + + @testutils.assert_raises(exceptions.ModuleSyntaxError) + def test_syntax_errors_in_code(self): + mod = self.pycore.get_string_module('xyx print\n') + + def test_holding_error_location_information(self): + try: + mod = self.pycore.get_string_module('xyx print\n') + except exceptions.ModuleSyntaxError, e: + self.assertEquals(1, e.lineno) + + def test_no_exceptions_on_module_encoding_problems(self): + mod = testutils.create_module(self.project, 'mod') + contents = '\nsdsdsd\n\xa9\n' + file = open(mod.real_path, 'wb') + file.write(contents) + file.close() + mod.read() + + @testutils.assert_raises(exceptions.ModuleSyntaxError) + def test_syntax_errors_when_cannot_decode_file2(self): + mod = testutils.create_module(self.project, 'mod') + contents = '\n\xa9\n' + file = open(mod.real_path, 'wb') + file.write(contents) + file.close() + self.pycore.resource_to_pyobject(mod) + + @testutils.assert_raises(exceptions.ModuleSyntaxError) + def test_syntax_errors_when_null_bytes(self): + mod = testutils.create_module(self.project, 'mod') + contents = '\n\x00\n' + file = open(mod.real_path, 'wb') + file.write(contents) + file.close() + self.pycore.resource_to_pyobject(mod) + + @testutils.assert_raises(exceptions.ModuleSyntaxError) + def test_syntax_errors_when_bad_strs(self): + mod = testutils.create_module(self.project, 'mod') + contents = '\n"\\x0"\n' + file = open(mod.real_path, 'wb') + file.write(contents) + file.close() + self.pycore.resource_to_pyobject(mod) + + def test_not_reaching_maximum_recursions_with_from_star_imports(self): + mod1 = testutils.create_module(self.project, 'mod1') + mod2 = testutils.create_module(self.project, 'mod2') + mod1.write('from mod2 import *\n') + mod2.write('from mod1 import *\n') + pymod1 = self.pycore.resource_to_pyobject(mod1) + pymod1.get_attributes() + + def test_not_reaching_maximum_recursions_when_importing_variables(self): + mod1 = testutils.create_module(self.project, 'mod1') + mod2 = testutils.create_module(self.project, 'mod2') + mod1.write('from mod2 import myvar\n') + mod2.write('from mod1 import myvar\n') + pymod1 = self.pycore.resource_to_pyobject(mod1) + pymod1['myvar'].get_object() + + def test_not_reaching_maximum_recursions_when_importing_variables2(self): + mod1 = testutils.create_module(self.project, 'mod1') + mod1.write('from mod1 import myvar\n') + pymod1 = self.pycore.resource_to_pyobject(mod1) + pymod1['myvar'].get_object() + + def test_pyobject_equality_should_compare_types(self): + mod1 = testutils.create_module(self.project, 'mod1') + mod1.write('var1 = ""\nvar2 = ""\n') + pymod1 = self.pycore.resource_to_pyobject(mod1) + self.assertEquals(pymod1['var1'].get_object(), + pymod1['var2'].get_object()) + + +class PyCoreInProjectsTest(unittest.TestCase): + + def setUp(self): + super(self.__class__, self).setUp() + self.project = testutils.sample_project() + self.pycore = self.project.pycore + samplemod = testutils.create_module(self.project, 'samplemod') + code = 'class SampleClass(object):\n' \ + ' def sample_method():\n' \ + ' pass\n\n' \ + 'def sample_func():\n' \ + ' pass\n' \ + 'sample_var = 10\n\n' \ + 'def _underlined_func():\n' \ + ' pass\n\n' + samplemod.write(code) + package = testutils.create_package(self.project, 'package') + nestedmod = testutils.create_module(self.project, 'nestedmod', package) + + def tearDown(self): + testutils.remove_project(self.project) + super(self.__class__, self).tearDown() + + def test_simple_import(self): + mod = self.pycore.get_string_module('import samplemod\n') + samplemod = mod['samplemod'].get_object() + self.assertEquals(get_base_type('Module'), samplemod.get_type()) + + def test_from_import_class(self): + mod = self.pycore.get_string_module('from samplemod import SampleClass\n') + result = mod['SampleClass'].get_object() + self.assertEquals(get_base_type('Type'), result.get_type()) + self.assertTrue('sample_func' not in mod.get_attributes()) + + def test_from_import_star(self): + mod = self.pycore.get_string_module('from samplemod import *\n') + self.assertEquals(get_base_type('Type'), + mod['SampleClass'].get_object().get_type()) + self.assertEquals(get_base_type('Function'), + mod['sample_func'].get_object().get_type()) + self.assertTrue(mod['sample_var'] is not None) + + def test_from_import_star_overwriting(self): + code = 'from samplemod import *\n' \ + 'class SampleClass(object):\n pass\n' + mod = self.pycore.get_string_module(code) + samplemod = self.pycore.get_module('samplemod') + sample_class = samplemod['SampleClass'].get_object() + self.assertNotEquals(sample_class, + mod.get_attributes()['SampleClass'].get_object()) + + def test_from_import_star_not_imporing_underlined(self): + mod = self.pycore.get_string_module('from samplemod import *') + self.assertTrue('_underlined_func' not in mod.get_attributes()) + + def test_from_import_star_imports_in_functions(self): + mod = self.pycore.get_string_module('def f():\n from os import *\n') + mod['f'].get_object().get_scope().get_names() + + def test_from_package_import_mod(self): + mod = self.pycore.get_string_module('from package import nestedmod\n') + self.assertEquals(get_base_type('Module'), + mod['nestedmod'].get_object().get_type()) + + # XXX: Deciding to import everything on import start from packages + def xxx_test_from_package_import_star(self): + mod = self.pycore.get_string_module('from package import *\n') + self.assertTrue('nestedmod' not in mod.get_attributes()) + + def test_unknown_when_module_cannot_be_found(self): + mod = self.pycore.get_string_module('from doesnotexist import nestedmod\n') + self.assertTrue('nestedmod' in mod) + + def test_from_import_function(self): + code = 'def f():\n from samplemod import SampleClass\n' + scope = self.pycore.get_string_scope(code) + self.assertEquals(get_base_type('Type'), + scope.get_scopes()[0]['SampleClass']. + get_object().get_type()) + + def test_circular_imports(self): + mod1 = testutils.create_module(self.project, 'mod1') + mod2 = testutils.create_module(self.project, 'mod2') + mod1.write('import mod2\n') + mod2.write('import mod1\n') + module1 = self.pycore.get_module('mod1') + + def test_circular_imports2(self): + mod1 = testutils.create_module(self.project, 'mod1') + mod2 = testutils.create_module(self.project, 'mod2') + mod1.write('from mod2 import Sample2\nclass Sample1(object):\n pass\n') + mod2.write('from mod1 import Sample1\nclass Sample2(object):\n pass\n') + module1 = self.pycore.get_module('mod1').get_attributes() + + def test_multi_dot_imports(self): + pkg = testutils.create_package(self.project, 'pkg') + pkg_mod = testutils.create_module(self.project, 'mod', pkg) + pkg_mod.write('def sample_func():\n pass\n') + mod = self.pycore.get_string_module('import pkg.mod\n') + self.assertTrue('pkg' in mod) + self.assertTrue('sample_func' in mod['pkg'].get_object()['mod']. + get_object()) + + def test_multi_dot_imports2(self): + pkg = testutils.create_package(self.project, 'pkg') + mod1 = testutils.create_module(self.project, 'mod1', pkg) + mod2 = testutils.create_module(self.project, 'mod2', pkg) + mod = self.pycore.get_string_module('import pkg.mod1\nimport pkg.mod2\n') + package = mod['pkg'].get_object() + self.assertEquals(2, len(package.get_attributes())) + self.assertTrue('mod1' in package and + 'mod2' in package) + + def test_multi_dot_imports3(self): + pkg1 = testutils.create_package(self.project, 'pkg1') + pkg2 = testutils.create_package(self.project, 'pkg2', pkg1) + mod1 = testutils.create_module(self.project, 'mod1', pkg2) + mod2 = testutils.create_module(self.project, 'mod2', pkg2) + code = 'import pkg1.pkg2.mod1\nimport pkg1.pkg2.mod2\n' + mod = self.pycore.get_string_module(code) + package1 = mod['pkg1'].get_object() + package2 = package1['pkg2'].get_object() + self.assertEquals(2, len(package2.get_attributes())) + self.assertTrue('mod1' in package2 and 'mod2' in package2) + + def test_multi_dot_imports_as(self): + pkg = testutils.create_package(self.project, 'pkg') + mod1 = testutils.create_module(self.project, 'mod1', pkg) + mod1.write('def f():\n pass\n') + mod = self.pycore.get_string_module('import pkg.mod1 as mod1\n') + module = mod['mod1'].get_object() + self.assertTrue('f' in module) + + # TODO: not showing unimported names as attributes of packages + def xxx_test_from_package_import_package(self): + pkg1 = testutils.create_package(self.project, 'pkg1') + pkg2 = testutils.create_package(self.project, 'pkg2', pkg1) + module = testutils.create_module(self.project, 'mod', pkg2) + mod = self.pycore.get_string_module('from pkg1 import pkg2\n') + package = mod['pkg2'] + self.assertEquals(0, len(package.get_attributes())) + + def test_invalidating_cache_after_resource_change(self): + module = testutils.create_module(self.project, 'mod') + module.write('import sys\n') + mod1 = self.pycore.get_module('mod') + self.assertTrue('var' not in mod1.get_attributes()) + module.write('var = 10\n') + mod2 = self.pycore.get_module('mod') + self.assertTrue('var' in mod2) + + def test_invalidating_cache_after_resource_change_for_init_dot_pys(self): + pkg = testutils.create_package(self.project, 'pkg') + mod = testutils.create_module(self.project, 'mod') + init_dot_py = pkg.get_child('__init__.py') + init_dot_py.write('a_var = 10\n') + mod.write('import pkg\n') + pymod = self.pycore.get_module('mod') + self.assertTrue('a_var' in pymod['pkg'].get_object()) + init_dot_py.write('new_var = 10\n') + self.assertTrue('a_var' not in pymod['pkg'].get_object().get_attributes()) + + def test_invalidating_cache_after_resource_change_for_nested_init_dot_pys(self): + pkg1 = testutils.create_package(self.project, 'pkg1') + pkg2 = testutils.create_package(self.project, 'pkg2', pkg1) + mod = testutils.create_module(self.project, 'mod') + init_dot_py = pkg2.get_child('__init__.py') + init_dot_py.write('a_var = 10\n') + mod.write('import pkg1\n') + pymod = self.pycore.get_module('mod') + self.assertTrue('a_var' in pymod['pkg1'].get_object()['pkg2'].get_object()) + init_dot_py.write('new_var = 10\n') + self.assertTrue('a_var' not in pymod['pkg1'].get_object()['pkg2'].get_object()) + + def test_from_import_nonexistent_module(self): + code = 'from doesnotexistmod import DoesNotExistClass\n' + mod = self.pycore.get_string_module(code) + self.assertTrue('DoesNotExistClass' in mod) + self.assertEquals(get_base_type('Unknown'), + mod['DoesNotExistClass']. + get_object().get_type()) + + def test_from_import_nonexistent_name(self): + code = 'from samplemod import DoesNotExistClass\n' + mod = self.pycore.get_string_module(code) + self.assertTrue('DoesNotExistClass' in mod) + self.assertEquals(get_base_type('Unknown'), + mod['DoesNotExistClass']. + get_object().get_type()) + + def test_not_considering_imported_names_as_sub_scopes(self): + code = 'from samplemod import SampleClass\n' + scope = self.pycore.get_string_scope(code) + self.assertEquals(0, len(scope.get_scopes())) + + def test_not_considering_imported_modules_as_sub_scopes(self): + scope = self.pycore.get_string_scope('import samplemod\n') + self.assertEquals(0, len(scope.get_scopes())) + + def test_inheriting_dotted_base_class(self): + code = 'import samplemod\n' \ + 'class Derived(samplemod.SampleClass):\n' \ + ' pass\n' + mod = self.pycore.get_string_module(code) + derived = mod['Derived'].get_object() + self.assertTrue('sample_method' in derived) + + def test_self_in_methods(self): + code = 'class Sample(object):\n' \ + ' def func(self):\n' \ + ' pass\n' + scope = self.pycore.get_string_scope(code) + sample_class = scope['Sample'].get_object() + func_scope = scope.get_scopes()[0].get_scopes()[0] + self.assertEquals(sample_class, + func_scope['self'].get_object().get_type()) + self.assertTrue('func' in func_scope['self']. + get_object()) + + def test_none_assignments_in_classes(self): + code = 'class C(object):\n' \ + ' var = ""\n' \ + ' def f(self):\n' \ + ' self.var += "".join([])\n' + scope = self.pycore.get_string_scope( + code) + c_class = scope['C'].get_object() + self.assertTrue('var' in c_class) + + def test_self_in_methods_with_decorators(self): + code = 'class Sample(object):\n' \ + ' @staticmethod\n' \ + ' def func(self):\n' \ + ' pass\n' + scope = self.pycore.get_string_scope(code) + sample_class = scope['Sample'].get_object() + func_scope = scope.get_scopes()[0].get_scopes()[0] + self.assertNotEquals(sample_class, + func_scope['self'].get_object().get_type()) + + def test_location_of_imports_when_importing(self): + mod = testutils.create_module(self.project, 'mod') + mod.write('from samplemod import SampleClass\n') + scope = self.pycore.get_string_scope('from mod import SampleClass\n') + sample_class = scope['SampleClass'] + samplemod = self.pycore.get_module('samplemod') + self.assertEquals((samplemod, 1), sample_class.get_definition_location()) + + def test_nested_modules(self): + pkg = testutils.create_package(self.project, 'pkg') + mod = testutils.create_module(self.project, 'mod', pkg) + imported_module = self.pycore.get_module('pkg.mod') + scope = self.pycore.get_string_scope('import pkg.mod\n') + mod_pyobject = scope['pkg'].get_object()['mod'] + self.assertEquals((imported_module, 1), + mod_pyobject.get_definition_location()) + + def test_reading_init_dot_py(self): + pkg = testutils.create_package(self.project, 'pkg') + init_dot_py = pkg.get_child('__init__.py') + init_dot_py.write('a_var = 1\n') + pkg_object = self.pycore.get_module('pkg') + self.assertTrue('a_var' in pkg_object) + + def test_relative_imports(self): + pkg = testutils.create_package(self.project, 'pkg') + mod1 = testutils.create_module(self.project, 'mod1', pkg) + mod2 = testutils.create_module(self.project, 'mod2', pkg) + mod2.write('import mod1\n') + mod1_object = self.pycore.resource_to_pyobject(mod1) + mod2_object = self.pycore.resource_to_pyobject(mod2) + self.assertEquals(mod1_object, mod2_object.get_attributes()['mod1'].get_object()) + + def test_relative_froms(self): + pkg = testutils.create_package(self.project, 'pkg') + mod1 = testutils.create_module(self.project, 'mod1', pkg) + mod2 = testutils.create_module(self.project, 'mod2', pkg) + mod1.write('def a_func():\n pass\n') + mod2.write('from mod1 import a_func\n') + mod1_object = self.pycore.resource_to_pyobject(mod1) + mod2_object = self.pycore.resource_to_pyobject(mod2) + self.assertEquals(mod1_object['a_func'].get_object(), + mod2_object['a_func'].get_object()) + + def test_relative_imports_for_string_modules(self): + pkg = testutils.create_package(self.project, 'pkg') + mod1 = testutils.create_module(self.project, 'mod1', pkg) + mod2 = testutils.create_module(self.project, 'mod2', pkg) + mod2.write('import mod1\n') + mod1_object = self.pycore.resource_to_pyobject(mod1) + mod2_object = self.pycore.get_string_module(mod2.read(), mod2) + self.assertEquals(mod1_object, mod2_object['mod1'].get_object()) + + def test_relative_imports_for_string_scopes(self): + pkg = testutils.create_package(self.project, 'pkg') + mod1 = testutils.create_module(self.project, 'mod1', pkg) + mod2 = testutils.create_module(self.project, 'mod2', pkg) + mod2.write('import mod1\n') + mod1_object = self.pycore.resource_to_pyobject(mod1) + mod2_scope = self.pycore.get_string_scope(mod2.read(), mod2) + self.assertEquals(mod1_object, mod2_scope['mod1'].get_object()) + + @testutils.run_only_for_25 + def test_new_style_relative_imports(self): + pkg = testutils.create_package(self.project, 'pkg') + mod1 = testutils.create_module(self.project, 'mod1', pkg) + mod2 = testutils.create_module(self.project, 'mod2', pkg) + mod2.write('from . import mod1\n') + mod1_object = self.pycore.resource_to_pyobject(mod1) + mod2_object = self.pycore.resource_to_pyobject(mod2) + self.assertEquals(mod1_object, mod2_object['mod1'].get_object()) + + @testutils.run_only_for_25 + def test_new_style_relative_imports2(self): + pkg = testutils.create_package(self.project, 'pkg') + mod1 = testutils.create_module(self.project, 'mod1') + mod2 = testutils.create_module(self.project, 'mod2', pkg) + mod1.write('def a_func():\n pass\n') + mod2.write('from ..mod1 import a_func\n') + mod1_object = self.pycore.resource_to_pyobject(mod1) + mod2_object = self.pycore.resource_to_pyobject(mod2) + self.assertEquals(mod1_object['a_func'].get_object(), + mod2_object['a_func'].get_object()) + + def test_invalidating_cache_for_from_imports_after_resource_change(self): + mod1 = testutils.create_module(self.project, 'mod1') + mod2 = testutils.create_module(self.project, 'mod2') + mod2.write('def a_func():\n print(1)\n') + mod1.write('from mod2 import a_func\na_func()\n') + + pymod1 = self.pycore.get_module('mod1') + pymod2 = self.pycore.get_module('mod2') + self.assertEquals(pymod1['a_func'].get_object(), + pymod2['a_func'].get_object()) + mod2.write(mod2.read() + '\n') + pymod2 = self.pycore.get_module('mod2') + self.assertEquals(pymod1['a_func'].get_object(), + pymod2['a_func'].get_object()) + + def test_invalidating_superclasses_after_change(self): + mod1 = testutils.create_module(self.project, 'mod1') + mod2 = testutils.create_module(self.project, 'mod2') + mod1.write('class A(object):\n def func1(self):\n pass\n') + mod2.write('import mod1\nclass B(mod1.A):\n pass\n') + + b_class = self.pycore.get_module('mod2')['B'].get_object() + self.assertTrue('func1' in b_class) + + mod1.write('class A(object):\n def func2(self):\n pass\n') + self.assertTrue('func2' in b_class) + + def test_caching_pymodule_with_syntax_errors(self): + self.project.prefs['ignore_syntax_errors'] = True + self.project.prefs['automatic_soa'] = True + self.project.pycore._init_automatic_soa() + source = 'import sys\nab cd' + mod = testutils.create_module(self.project, 'mod') + mod.write(source) + from rope.contrib import fixsyntax + fixer = fixsyntax.FixSyntax(self.project.pycore, source, mod, 10) + pymodule = fixer.get_pymodule() + self.assertTrue(pymodule.source_code.startswith('import sys\npass\n')) + + +class TextChangeDetectorTest(unittest.TestCase): + + def test_trivial_case(self): + detector = _TextChangeDetector('\n', '\n') + self.assertFalse(detector.is_changed(1, 1)) + + def test_one_line_change(self): + detector = _TextChangeDetector('1\n2\n', '1\n3\n') + self.assertFalse(detector.is_changed(1, 1)) + self.assertTrue(detector.is_changed(2, 2)) + + def test_line_expansion(self): + detector = _TextChangeDetector('1\n2\n', '1\n3\n4\n2\n') + self.assertFalse(detector.is_changed(1, 1)) + self.assertFalse(detector.is_changed(2, 2)) + + def test_line_removals(self): + detector = _TextChangeDetector('1\n3\n4\n2\n', '1\n2\n') + self.assertFalse(detector.is_changed(1, 1)) + self.assertTrue(detector.is_changed(2, 3)) + self.assertFalse(detector.is_changed(4, 4)) + + def test_multi_line_checks(self): + detector = _TextChangeDetector('1\n2\n', '1\n3\n') + self.assertTrue(detector.is_changed(1, 2)) + + def test_consume_change(self): + detector = _TextChangeDetector('1\n2\n', '1\n3\n') + self.assertTrue(detector.is_changed(1, 2)) + self.assertTrue(detector.consume_changes(1, 2)) + self.assertFalse(detector.is_changed(1, 2)) + + +class PyCoreProjectConfigsTest(unittest.TestCase): + + def setUp(self): + super(PyCoreProjectConfigsTest, self).setUp() + self.project = None + + def tearDown(self): + if self.project: + testutils.remove_project(self.project) + super(PyCoreProjectConfigsTest, self).tearDown() + + def test_python_files_config(self): + self.project = testutils.sample_project(python_files=['myscript']) + myscript = self.project.root.create_file('myscript') + self.assertTrue(self.project.pycore.is_python_file(myscript)) + + def test_ignore_bad_imports(self): + self.project = testutils.sample_project(ignore_bad_imports=True) + pymod = self.project.pycore.get_string_module( + 'import some_nonexistent_module\n') + self.assertFalse('some_nonexistent_module' in pymod) + + def test_ignore_bad_imports_for_froms(self): + self.project = testutils.sample_project(ignore_bad_imports=True) + pymod = self.project.pycore.get_string_module( + 'from some_nonexistent_module import var\n') + self.assertFalse('var' in pymod) + + @testutils.assert_raises(exceptions.ModuleSyntaxError) + def test_reporting_syntax_errors_with_force_errors(self): + self.project = testutils.sample_project(ignore_syntax_errors=True) + mod = testutils.create_module(self.project, 'mod') + mod.write('syntax error ...\n') + self.project.pycore.resource_to_pyobject(mod, force_errors=True) + + @testutils.assert_raises(exceptions.ModuleSyntaxError) + def test_reporting_syntax_errors_in_strings_with_force_errors(self): + self.project = testutils.sample_project(ignore_syntax_errors=True) + self.project.pycore.get_string_module('syntax error ...', + force_errors=True) + + def test_not_raising_errors_for_strings_with_ignore_errors(self): + self.project = testutils.sample_project(ignore_syntax_errors=True) + self.project.pycore.get_string_module('syntax error ...') + + @testutils.assert_raises(exceptions.ModuleSyntaxError) + def test_reporting_syntax_errors_with_force_errors_for_packages(self): + self.project = testutils.sample_project(ignore_syntax_errors=True) + pkg = testutils.create_package(self.project, 'pkg') + pkg.get_child('__init__.py').write('syntax error ...\n') + self.project.pycore.resource_to_pyobject(pkg, force_errors=True) + + +def suite(): + result = unittest.TestSuite() + result.addTests(unittest.makeSuite(PyCoreTest)) + result.addTests(unittest.makeSuite(PyCoreInProjectsTest)) + result.addTests(unittest.makeSuite(TextChangeDetectorTest)) + result.addTests(unittest.makeSuite(PyCoreProjectConfigsTest)) + return result + + +if __name__ == '__main__': + unittest.main() diff -r e30544496575 -r 48cacfdc2ca6 vim/sadness/ropevim/src/rope/ropetest/pyscopestest.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vim/sadness/ropevim/src/rope/ropetest/pyscopestest.py Wed Oct 06 12:30:46 2010 -0400 @@ -0,0 +1,235 @@ +import unittest + +from rope.base.pyobjects import get_base_type +from ropetest import testutils + + +class PyCoreScopesTest(unittest.TestCase): + + def setUp(self): + super(PyCoreScopesTest, self).setUp() + self.project = testutils.sample_project() + self.pycore = self.project.pycore + + def tearDown(self): + testutils.remove_project(self.project) + super(PyCoreScopesTest, self).tearDown() + + def test_simple_scope(self): + scope = self.pycore.get_string_scope('def sample_func():\n pass\n') + sample_func = scope['sample_func'].get_object() + self.assertEquals(get_base_type('Function'), sample_func.get_type()) + + def test_simple_function_scope(self): + scope = self.pycore.get_string_scope( + 'def sample_func():\n a = 10\n') + self.assertEquals(1, len(scope.get_scopes())) + sample_func_scope = scope.get_scopes()[0] + self.assertEquals(1, len(sample_func_scope.get_names())) + self.assertEquals(0, len(sample_func_scope.get_scopes())) + + def test_classes_inside_function_scopes(self): + scope = self.pycore.get_string_scope( + 'def sample_func():\n' + ' class SampleClass(object):\n pass\n') + self.assertEquals(1, len(scope.get_scopes())) + sample_func_scope = scope.get_scopes()[0] + self.assertEquals(get_base_type('Type'), + scope.get_scopes()[0]['SampleClass'].get_object().get_type()) + + def test_simple_class_scope(self): + scope = self.pycore.get_string_scope( + 'class SampleClass(object):\n' + ' def f(self):\n var = 10\n') + self.assertEquals(1, len(scope.get_scopes())) + sample_class_scope = scope.get_scopes()[0] + self.assertTrue('f' in sample_class_scope) + self.assertEquals(1, len(sample_class_scope.get_scopes())) + f_in_class = sample_class_scope.get_scopes()[0] + self.assertTrue('var' in f_in_class) + + def test_get_lineno(self): + scope = self.pycore.get_string_scope( + '\ndef sample_func():\n a = 10\n') + self.assertEquals(1, len(scope.get_scopes())) + sample_func_scope = scope.get_scopes()[0] + self.assertEquals(1, scope.get_start()) + self.assertEquals(2, sample_func_scope.get_start()) + + def test_scope_kind(self): + scope = self.pycore.get_string_scope( + 'class SampleClass(object):\n pass\n' + 'def sample_func():\n pass\n') + sample_class_scope = scope.get_scopes()[0] + sample_func_scope = scope.get_scopes()[1] + self.assertEquals('Module', scope.get_kind()) + self.assertEquals('Class', sample_class_scope.get_kind()) + self.assertEquals('Function', sample_func_scope.get_kind()) + + def test_function_parameters_in_scope_names(self): + scope = self.pycore.get_string_scope( + 'def sample_func(param):\n a = 10\n') + sample_func_scope = scope.get_scopes()[0] + self.assertTrue('param' in sample_func_scope) + + def test_get_names_contains_only_names_defined_in_a_scope(self): + scope = self.pycore.get_string_scope( + 'var1 = 10\ndef sample_func(param):\n var2 = 20\n') + sample_func_scope = scope.get_scopes()[0] + self.assertTrue('var1' not in sample_func_scope) + + def test_scope_lookup(self): + scope = self.pycore.get_string_scope( + 'var1 = 10\ndef sample_func(param):\n var2 = 20\n') + self.assertTrue(scope.lookup('var2') is None) + self.assertEquals(get_base_type('Function'), + scope.lookup('sample_func').get_object().get_type()) + sample_func_scope = scope.get_scopes()[0] + self.assertTrue(sample_func_scope.lookup('var1') is not None) + + def test_function_scopes(self): + scope = self.pycore.get_string_scope('def func():\n var = 10\n') + func_scope = scope.get_scopes()[0] + self.assertTrue('var' in func_scope) + + def test_function_scopes_classes(self): + scope = self.pycore.get_string_scope( + 'def func():\n class Sample(object):\n pass\n') + func_scope = scope.get_scopes()[0] + self.assertTrue('Sample' in func_scope) + + def test_function_getting_scope(self): + mod = self.pycore.get_string_module('def func(): var = 10\n') + func_scope = mod['func'].get_object().get_scope() + self.assertTrue('var' in func_scope) + + def test_scopes_in_function_scopes(self): + scope = self.pycore.get_string_scope( + 'def func():\n def inner():\n var = 10\n') + func_scope = scope.get_scopes()[0] + inner_scope = func_scope.get_scopes()[0] + self.assertTrue('var' in inner_scope) + + def test_for_variables_in_scopes(self): + scope = self.pycore.get_string_scope( + 'for a_var in range(10):\n pass\n') + self.assertTrue('a_var' in scope) + + def test_assists_inside_fors(self): + scope = self.pycore.get_string_scope( + 'for i in range(10):\n a_var = i\n') + self.assertTrue('a_var' in scope) + + def test_first_parameter_of_a_method(self): + code = 'class AClass(object):\n' \ + ' def a_func(self, param):\n pass\n' + a_class = self.pycore.get_string_module(code)['AClass']. get_object() + function_scope = a_class['a_func'].get_object().get_scope() + self.assertEquals(a_class, function_scope['self'].get_object().get_type()) + self.assertNotEquals(a_class, function_scope['param']. + get_object().get_type()) + + def test_first_parameter_of_static_methods(self): + code = 'class AClass(object):\n' \ + ' @staticmethod\n def a_func(param):\n pass\n' + a_class = self.pycore.get_string_module(code)['AClass']. get_object() + function_scope = a_class['a_func'].\ + get_object().get_scope() + self.assertNotEquals(a_class, function_scope['param'].get_object().get_type()) + + def test_first_parameter_of_class_methods(self): + code = 'class AClass(object):\n' \ + ' @classmethod\n def a_func(cls):\n pass\n' + a_class = self.pycore.get_string_module(code)['AClass']. get_object() + function_scope = a_class['a_func'].get_object().get_scope() + self.assertEquals(a_class, function_scope['cls'].get_object()) + + def test_first_parameter_with_self_as_name_and_unknown_decorator(self): + code = 'def my_decorator(func):\n return func\n'\ + 'class AClass(object):\n' \ + ' @my_decorator\n def a_func(self):\n pass\n' + a_class = self.pycore.get_string_module(code)['AClass']. get_object() + function_scope = a_class['a_func'].get_object().get_scope() + self.assertEquals(a_class, function_scope['self']. + get_object().get_type()) + + def test_inside_class_scope_attribute_lookup(self): + scope = self.pycore.get_string_scope( + 'class C(object):\n' + ' an_attr = 1\n' + ' def a_func(self):\n pass') + self.assertEquals(1, len(scope.get_scopes())) + c_scope = scope.get_scopes()[0] + self.assertTrue('an_attr'in c_scope.get_names()) + self.assertTrue(c_scope.lookup('an_attr') is not None) + f_in_c = c_scope.get_scopes()[0] + self.assertTrue(f_in_c.lookup('an_attr') is None) + + def test_inside_class_scope_attribute_lookup2(self): + scope = self.pycore.get_string_scope( + 'class C(object):\n' + ' def __init__(self):\n self.an_attr = 1\n' + ' def a_func(self):\n pass') + self.assertEquals(1, len(scope.get_scopes())) + c_scope = scope.get_scopes()[0] + f_in_c = c_scope.get_scopes()[0] + self.assertTrue(f_in_c.lookup('an_attr') is None) + + def test_get_inner_scope_for_staticmethods(self): + scope = self.pycore.get_string_scope( + 'class C(object):\n' + ' @staticmethod\n' + ' def a_func(self):\n pass\n') + c_scope = scope.get_scopes()[0] + f_in_c = c_scope.get_scopes()[0] + self.assertEquals(f_in_c, scope.get_inner_scope_for_line(4)) + + def test_getting_overwritten_scopes(self): + scope = self.pycore.get_string_scope( + 'def f():\n pass\ndef f():\n pass\n') + self.assertEquals(2, len(scope.get_scopes())) + f1_scope = scope.get_scopes()[0] + f2_scope = scope.get_scopes()[1] + self.assertNotEquals(f1_scope, f2_scope) + + def test_assigning_builtin_names(self): + mod = self.pycore.get_string_module('range = 1\n') + range = mod.get_scope().lookup('range') + self.assertEquals((mod, 1), range.get_definition_location()) + + def test_get_inner_scope_and_logical_lines(self): + scope = self.pycore.get_string_scope( + 'class C(object):\n' + ' def f():\n s = """\n1\n2\n"""\n a = 1\n') + c_scope = scope.get_scopes()[0] + f_in_c = c_scope.get_scopes()[0] + self.assertEquals(f_in_c, scope.get_inner_scope_for_line(7)) + + def test_getting_defined_names_for_classes(self): + scope = self.pycore.get_string_scope( + 'class A(object):\n def a(self):\n pass\n' + 'class B(A):\n def b(self):\n pass\n') + a_scope = scope['A'].get_object().get_scope() + b_scope = scope['B'].get_object().get_scope() + self.assertTrue('a' in b_scope.get_names()) + self.assertTrue('b' in b_scope.get_names()) + self.assertTrue('a' not in b_scope.get_defined_names()) + self.assertTrue('b' in b_scope.get_defined_names()) + + def test_getting_defined_names_for_modules(self): + scope = self.pycore.get_string_scope( + 'class A(object):\n pass\n') + self.assertTrue('open' in scope.get_names()) + self.assertTrue('A' in scope.get_names()) + self.assertTrue('open' not in scope.get_defined_names()) + self.assertTrue('A' in scope.get_defined_names()) + + +def suite(): + result = unittest.TestSuite() + result.addTests(unittest.makeSuite(PyCoreScopesTest)) + return result + + +if __name__ == '__main__': + unittest.main() diff -r e30544496575 -r 48cacfdc2ca6 vim/sadness/ropevim/src/rope/ropetest/refactor/__init__.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vim/sadness/ropevim/src/rope/ropetest/refactor/__init__.py Wed Oct 06 12:30:46 2010 -0400 @@ -0,0 +1,925 @@ +import unittest + +import rope.base.taskhandle +import rope.refactor.introduce_parameter +import ropetest.refactor.extracttest +import ropetest.refactor.importutilstest +import ropetest.refactor.inlinetest +import ropetest.refactor.movetest +import ropetest.refactor.multiprojecttest +import ropetest.refactor.patchedasttest +import ropetest.refactor.renametest +import ropetest.refactor.restructuretest +import ropetest.refactor.suitestest +import ropetest.refactor.usefunctiontest +from rope.base.exceptions import RefactoringError, InterruptedTaskError +from rope.refactor.encapsulate_field import EncapsulateField +from rope.refactor.introduce_factory import IntroduceFactory +from rope.refactor.localtofield import LocalToField +from rope.refactor.method_object import MethodObject +from ropetest import testutils +from ropetest.refactor import change_signature_test, similarfindertest + + +class MethodObjectTest(unittest.TestCase): + + def setUp(self): + super(MethodObjectTest, self).setUp() + self.project = testutils.sample_project() + self.pycore = self.project.pycore + self.mod = testutils.create_module(self.project, 'mod') + + def tearDown(self): + testutils.remove_project(self.project) + super(MethodObjectTest, self).tearDown() + + def test_empty_method(self): + code = 'def func():\n pass\n' + self.mod.write(code) + replacer = MethodObject(self.project, self.mod, code.index('func')) + self.assertEquals( + 'class _New(object):\n\n def __call__(self):\n pass\n', + replacer.get_new_class('_New')) + + def test_trivial_return(self): + code = 'def func():\n return 1\n' + self.mod.write(code) + replacer = MethodObject(self.project, self.mod, code.index('func')) + self.assertEquals( + 'class _New(object):\n\n def __call__(self):\n return 1\n', + replacer.get_new_class('_New')) + + def test_multi_line_header(self): + code = 'def func(\n ):\n return 1\n' + self.mod.write(code) + replacer = MethodObject(self.project, self.mod, code.index('func')) + self.assertEquals( + 'class _New(object):\n\n def __call__(self):\n return 1\n', + replacer.get_new_class('_New')) + + def test_a_single_parameter(self): + code = 'def func(param):\n return 1\n' + self.mod.write(code) + replacer = MethodObject(self.project, self.mod, code.index('func')) + self.assertEquals( + 'class _New(object):\n\n' + ' def __init__(self, param):\n self.param = param\n\n' + ' def __call__(self):\n return 1\n', + replacer.get_new_class('_New')) + + def test_self_parameter(self): + code = 'def func(self):\n return 1\n' + self.mod.write(code) + replacer = MethodObject(self.project, self.mod, code.index('func')) + self.assertEquals( + 'class _New(object):\n\n' + ' def __init__(self, host):\n self.self = host\n\n' + ' def __call__(self):\n return 1\n', + replacer.get_new_class('_New')) + + def test_simple_using_passed_parameters(self): + code = 'def func(param):\n return param\n' + self.mod.write(code) + replacer = MethodObject(self.project, self.mod, code.index('func')) + self.assertEquals( + 'class _New(object):\n\n' + ' def __init__(self, param):\n self.param = param\n\n' + ' def __call__(self):\n return self.param\n', + replacer.get_new_class('_New')) + + def test_self_keywords_and_args_parameters(self): + code = 'def func(arg, *args, **kwds):\n' \ + ' result = arg + args[0] + kwds[arg]\n' \ + ' return result\n' + self.mod.write(code) + replacer = MethodObject(self.project, self.mod, code.index('func')) + expected = 'class _New(object):\n\n' \ + ' def __init__(self, arg, args, kwds):\n' \ + ' self.arg = arg\n' \ + ' self.args = args\n' \ + ' self.kwds = kwds\n\n' \ + ' def __call__(self):\n' \ + ' result = self.arg + self.args[0] + self.kwds[self.arg]\n' \ + ' return result\n' + self.assertEquals(expected, replacer.get_new_class('_New')) + + @testutils.assert_raises(RefactoringError) + def test_performing_on_not_a_function(self): + code = 'my_var = 10\n' + self.mod.write(code) + replacer = MethodObject(self.project, self.mod, code.index('my_var')) + + def test_changing_the_module(self): + code = 'def func():\n return 1\n' + self.mod.write(code) + replacer = MethodObject(self.project, self.mod, code.index('func')) + self.project.do(replacer.get_changes('_New')) + expected = 'def func():\n' \ + ' return _New()()\n\n\n' \ + 'class _New(object):\n\n' \ + ' def __call__(self):\n' \ + ' return 1\n' + self.assertEquals(expected, self.mod.read()) + + def test_changing_the_module_and_class_methods(self): + code = 'class C(object):\n\n' \ + ' def a_func(self):\n' \ + ' return 1\n\n' \ + ' def another_func(self):\n' \ + ' pass\n' + self.mod.write(code) + replacer = MethodObject(self.project, self.mod, code.index('func')) + self.project.do(replacer.get_changes('_New')) + expected = 'class C(object):\n\n' \ + ' def a_func(self):\n' \ + ' return _New(self)()\n\n' \ + ' def another_func(self):\n' \ + ' pass\n\n\n' \ + 'class _New(object):\n\n' \ + ' def __init__(self, host):\n' \ + ' self.self = host\n\n' \ + ' def __call__(self):\n' \ + ' return 1\n' + self.assertEquals(expected, self.mod.read()) + + +class IntroduceFactoryTest(unittest.TestCase): + + def setUp(self): + super(IntroduceFactoryTest, self).setUp() + self.project = testutils.sample_project() + self.pycore = self.project.pycore + + def tearDown(self): + testutils.remove_project(self.project) + super(IntroduceFactoryTest, self).tearDown() + + def _introduce_factory(self, resource, offset, *args, **kwds): + factory_introducer = IntroduceFactory(self.project, + resource, offset) + changes = factory_introducer.get_changes(*args, **kwds) + self.project.do(changes) + + def test_adding_the_method(self): + code = 'class AClass(object):\n an_attr = 10\n' + mod = testutils.create_module(self.project, 'mod') + mod.write(code) + expected = 'class AClass(object):\n' \ + ' an_attr = 10\n\n' \ + ' @staticmethod\n' \ + ' def create(*args, **kwds):\n' \ + ' return AClass(*args, **kwds)\n' + self._introduce_factory(mod, mod.read().index('AClass') + 1, 'create') + self.assertEquals(expected, mod.read()) + + def test_changing_occurances_in_the_main_module(self): + code = 'class AClass(object):\n' \ + ' an_attr = 10\n' \ + 'a_var = AClass()' + mod = testutils.create_module(self.project, 'mod') + mod.write(code) + expected = 'class AClass(object):\n' \ + ' an_attr = 10\n\n' \ + ' @staticmethod\n' \ + ' def create(*args, **kwds):\n' \ + ' return AClass(*args, **kwds)\n'\ + 'a_var = AClass.create()' + self._introduce_factory(mod, mod.read().index('AClass') + 1, 'create') + self.assertEquals(expected, mod.read()) + + def test_changing_occurances_with_arguments(self): + code = 'class AClass(object):\n' \ + ' def __init__(self, arg):\n' \ + ' pass\n' \ + 'a_var = AClass(10)\n' + mod = testutils.create_module(self.project, 'mod') + mod.write(code) + expected = 'class AClass(object):\n' \ + ' def __init__(self, arg):\n' \ + ' pass\n\n' \ + ' @staticmethod\n' \ + ' def create(*args, **kwds):\n' \ + ' return AClass(*args, **kwds)\n' \ + 'a_var = AClass.create(10)\n' + self._introduce_factory(mod, mod.read().index('AClass') + 1, 'create') + self.assertEquals(expected, mod.read()) + + def test_changing_occurances_in_other_modules(self): + mod1 = testutils.create_module(self.project, 'mod1') + mod2 = testutils.create_module(self.project, 'mod2') + mod1.write('class AClass(object):\n an_attr = 10\n') + mod2.write('import mod1\na_var = mod1.AClass()\n') + self._introduce_factory(mod1, mod1.read().index('AClass') + 1, 'create') + expected1 = 'class AClass(object):\n' \ + ' an_attr = 10\n\n' \ + ' @staticmethod\n' \ + ' def create(*args, **kwds):\n' \ + ' return AClass(*args, **kwds)\n' + expected2 = 'import mod1\n' \ + 'a_var = mod1.AClass.create()\n' + self.assertEquals(expected1, mod1.read()) + self.assertEquals(expected2, mod2.read()) + + @testutils.assert_raises(RefactoringError) + def test_raising_exception_for_non_classes(self): + mod = testutils.create_module(self.project, 'mod') + mod.write('def a_func():\n pass\n') + self._introduce_factory(mod, mod.read().index('a_func') + 1, 'create') + + def test_undoing_introduce_factory(self): + mod1 = testutils.create_module(self.project, 'mod1') + mod2 = testutils.create_module(self.project, 'mod2') + code1 = 'class AClass(object):\n an_attr = 10\n' + mod1.write(code1) + code2 = 'from mod1 import AClass\na_var = AClass()\n' + mod2.write(code2) + self._introduce_factory(mod1, mod1.read().index('AClass') + 1, 'create') + self.project.history.undo() + self.assertEquals(code1, mod1.read()) + self.assertEquals(code2, mod2.read()) + + def test_using_on_an_occurance_outside_the_main_module(self): + mod1 = testutils.create_module(self.project, 'mod1') + mod2 = testutils.create_module(self.project, 'mod2') + mod1.write('class AClass(object):\n an_attr = 10\n') + mod2.write('import mod1\na_var = mod1.AClass()\n') + self._introduce_factory(mod2, mod2.read().index('AClass') + 1, 'create') + expected1 = 'class AClass(object):\n' \ + ' an_attr = 10\n\n' \ + ' @staticmethod\n' \ + ' def create(*args, **kwds):\n' \ + ' return AClass(*args, **kwds)\n' + expected2 = 'import mod1\n' \ + 'a_var = mod1.AClass.create()\n' + self.assertEquals(expected1, mod1.read()) + self.assertEquals(expected2, mod2.read()) + + def test_introduce_factory_in_nested_scopes(self): + code = 'def create_var():\n'\ + ' class AClass(object):\n'\ + ' an_attr = 10\n'\ + ' return AClass()\n' + mod = testutils.create_module(self.project, 'mod') + mod.write(code) + expected = 'def create_var():\n'\ + ' class AClass(object):\n'\ + ' an_attr = 10\n\n'\ + ' @staticmethod\n def create(*args, **kwds):\n'\ + ' return AClass(*args, **kwds)\n'\ + ' return AClass.create()\n' + self._introduce_factory(mod, mod.read().index('AClass') + 1, 'create') + self.assertEquals(expected, mod.read()) + + def test_adding_factory_for_global_factories(self): + code = 'class AClass(object):\n an_attr = 10\n' + mod = testutils.create_module(self.project, 'mod') + mod.write(code) + expected = 'class AClass(object):\n' \ + ' an_attr = 10\n\n' \ + 'def create(*args, **kwds):\n' \ + ' return AClass(*args, **kwds)\n' + self._introduce_factory(mod, mod.read().index('AClass') + 1, + 'create', global_factory=True) + self.assertEquals(expected, mod.read()) + + def test_get_name_for_factories(self): + code = 'class C(object):\n pass\n' + mod = testutils.create_module(self.project, 'mod') + mod.write(code) + factory = IntroduceFactory(self.project, mod, + mod.read().index('C') + 1) + self.assertEquals('C', factory.get_name()) + + @testutils.assert_raises(RefactoringError) + def test_raising_exception_for_global_factory_for_nested_classes(self): + code = 'def create_var():\n'\ + ' class AClass(object):\n'\ + ' an_attr = 10\n'\ + ' return AClass()\n' + mod = testutils.create_module(self.project, 'mod') + mod.write(code) + self._introduce_factory(mod, mod.read().index('AClass') + 1, + 'create', global_factory=True) + + def test_changing_occurances_in_the_main_module_for_global_factories(self): + code = 'class AClass(object):\n' \ + ' an_attr = 10\n' \ + 'a_var = AClass()' + mod = testutils.create_module(self.project, 'mod') + mod.write(code) + expected = 'class AClass(object):\n an_attr = 10\n\n' \ + 'def create(*args, **kwds):\n' \ + ' return AClass(*args, **kwds)\n'\ + 'a_var = create()' + self._introduce_factory(mod, mod.read().index('AClass') + 1, + 'create', global_factory=True) + self.assertEquals(expected, mod.read()) + + def test_changing_occurances_in_other_modules_for_global_factories(self): + mod1 = testutils.create_module(self.project, 'mod1') + mod2 = testutils.create_module(self.project, 'mod2') + mod1.write('class AClass(object):\n an_attr = 10\n') + mod2.write('import mod1\na_var = mod1.AClass()\n') + self._introduce_factory(mod1, mod1.read().index('AClass') + 1, + 'create', global_factory=True) + expected1 = 'class AClass(object):\n' \ + ' an_attr = 10\n\n' \ + 'def create(*args, **kwds):\n' \ + ' return AClass(*args, **kwds)\n' + expected2 = 'import mod1\n' \ + 'a_var = mod1.create()\n' + self.assertEquals(expected1, mod1.read()) + self.assertEquals(expected2, mod2.read()) + + def test_importing_if_necessary_in_other_modules_for_global_factories(self): + mod1 = testutils.create_module(self.project, 'mod1') + mod2 = testutils.create_module(self.project, 'mod2') + mod1.write('class AClass(object):\n an_attr = 10\n') + mod2.write('from mod1 import AClass\npair = AClass(), AClass\n') + self._introduce_factory(mod1, mod1.read().index('AClass') + 1, + 'create', global_factory=True) + expected1 = 'class AClass(object):\n' \ + ' an_attr = 10\n\n' \ + 'def create(*args, **kwds):\n' \ + ' return AClass(*args, **kwds)\n' + expected2 = 'from mod1 import AClass, create\n' \ + 'pair = create(), AClass\n' + self.assertEquals(expected1, mod1.read()) + self.assertEquals(expected2, mod2.read()) + + def test_changing_occurances_for_renamed_classes(self): + code = 'class AClass(object):\n an_attr = 10\na_class = AClass\na_var = a_class()' + mod = testutils.create_module(self.project, 'mod') + mod.write(code) + expected = 'class AClass(object):\n' \ + ' an_attr = 10\n\n' \ + ' @staticmethod\n' \ + ' def create(*args, **kwds):\n' \ + ' return AClass(*args, **kwds)\n' \ + 'a_class = AClass\n' \ + 'a_var = a_class()' + self._introduce_factory(mod, mod.read().index('a_class') + 1, 'create') + self.assertEquals(expected, mod.read()) + + def test_changing_occurrences_in_the_same_module_with_conflicting_ranges(self): + mod = testutils.create_module(self.project, 'mod') + code = 'class C(object):\n' \ + ' def create(self):\n' \ + ' return C()\n' + mod.write(code) + self._introduce_factory(mod, mod.read().index('C'), 'create_c', True) + expected = 'class C(object):\n' \ + ' def create(self):\n' \ + ' return create_c()\n' + self.assertTrue(mod.read().startswith(expected)) + + def _transform_module_to_package(self, resource): + self.project.do(rope.refactor.ModuleToPackage( + self.project, resource).get_changes()) + + def test_transform_module_to_package(self): + mod1 = testutils.create_module(self.project, 'mod1') + mod1.write('import mod2\nfrom mod2 import AClass\n') + mod2 = testutils.create_module(self.project, 'mod2') + mod2.write('class AClass(object):\n pass\n') + self._transform_module_to_package(mod2) + mod2 = self.project.get_resource('mod2') + root_folder = self.project.root + self.assertFalse(root_folder.has_child('mod2.py')) + self.assertEquals('class AClass(object):\n pass\n', + root_folder.get_child('mod2'). + get_child('__init__.py').read()) + + def test_transform_module_to_package_undoing(self): + pkg = testutils.create_package(self.project, 'pkg') + mod = testutils.create_module(self.project, 'mod', pkg) + self._transform_module_to_package(mod) + self.assertFalse(pkg.has_child('mod.py')) + self.assertTrue(pkg.get_child('mod').has_child('__init__.py')) + self.project.history.undo() + self.assertTrue(pkg.has_child('mod.py')) + self.assertFalse(pkg.has_child('mod')) + + def test_transform_module_to_package_with_relative_imports(self): + pkg = testutils.create_package(self.project, 'pkg') + mod1 = testutils.create_module(self.project, 'mod1', pkg) + mod1.write('import mod2\nfrom mod2 import AClass\n') + mod2 = testutils.create_module(self.project, 'mod2', pkg) + mod2.write('class AClass(object):\n pass\n') + self._transform_module_to_package(mod1) + new_init = self.project.get_resource('pkg/mod1/__init__.py') + self.assertEquals('import pkg.mod2\nfrom pkg.mod2 import AClass\n', + new_init.read()) + + def test_resources_parameter(self): + code = 'class A(object):\n an_attr = 10\n' + code1 = 'import mod\na = mod.A()\n' + mod = testutils.create_module(self.project, 'mod') + mod1 = testutils.create_module(self.project, 'mod1') + mod.write(code) + mod1.write(code1) + expected = 'class A(object):\n' \ + ' an_attr = 10\n\n' \ + ' @staticmethod\n' \ + ' def create(*args, **kwds):\n' \ + ' return A(*args, **kwds)\n' + self._introduce_factory(mod, mod.read().index('A') + 1, + 'create', resources=[mod]) + self.assertEquals(expected, mod.read()) + self.assertEquals(code1, mod1.read()) + + +class EncapsulateFieldTest(unittest.TestCase): + + def setUp(self): + super(EncapsulateFieldTest, self).setUp() + self.project = testutils.sample_project() + self.pycore = self.project.pycore + self.mod = testutils.create_module(self.project, 'mod') + self.mod1 = testutils.create_module(self.project, 'mod1') + self.a_class = 'class A(object):\n' \ + ' def __init__(self):\n' \ + ' self.attr = 1\n' + self.added_methods = '\n' \ + ' def get_attr(self):\n' \ + ' return self.attr\n\n' \ + ' def set_attr(self, value):\n' \ + ' self.attr = value\n' + self.encapsulated = self.a_class + self.added_methods + + def tearDown(self): + testutils.remove_project(self.project) + super(EncapsulateFieldTest, self).tearDown() + + def _encapsulate(self, resource, offset, **args): + changes = EncapsulateField(self.project, resource, offset).\ + get_changes(**args) + self.project.do(changes) + + def test_adding_getters_and_setters(self): + code = self.a_class + self.mod.write(code) + self._encapsulate(self.mod, code.index('attr') + 1) + self.assertEquals(self.encapsulated, self.mod.read()) + + def test_changing_getters_in_other_modules(self): + code = 'import mod\n' \ + 'a_var = mod.A()\n' \ + 'range(a_var.attr)\n' + self.mod1.write(code) + self.mod.write(self.a_class) + self._encapsulate(self.mod, self.mod.read().index('attr') + 1) + expected = 'import mod\n' \ + 'a_var = mod.A()\n' \ + 'range(a_var.get_attr())\n' + self.assertEquals(expected, self.mod1.read()) + + def test_changing_setters_in_other_modules(self): + code = 'import mod\n' \ + 'a_var = mod.A()\n' \ + 'a_var.attr = 1\n' + self.mod1.write(code) + self.mod.write(self.a_class) + self._encapsulate(self.mod, self.mod.read().index('attr') + 1) + expected = 'import mod\n' \ + 'a_var = mod.A()\n' \ + 'a_var.set_attr(1)\n' + self.assertEquals(expected, self.mod1.read()) + + def test_changing_getters_in_setters(self): + code = 'import mod\n' \ + 'a_var = mod.A()\n' \ + 'a_var.attr = 1 + a_var.attr\n' + self.mod1.write(code) + self.mod.write(self.a_class) + self._encapsulate(self.mod, self.mod.read().index('attr') + 1) + expected = 'import mod\n' \ + 'a_var = mod.A()\n' \ + 'a_var.set_attr(1 + a_var.get_attr())\n' + self.assertEquals(expected, self.mod1.read()) + + def test_appending_to_class_end(self): + self.mod1.write(self.a_class + 'a_var = A()\n') + self._encapsulate(self.mod1, self.mod1.read().index('attr') + 1) + self.assertEquals(self.encapsulated + 'a_var = A()\n', + self.mod1.read()) + + def test_performing_in_other_modules(self): + code = 'import mod\n' \ + 'a_var = mod.A()\n' \ + 'range(a_var.attr)\n' + self.mod1.write(code) + self.mod.write(self.a_class) + self._encapsulate(self.mod1, self.mod1.read().index('attr') + 1) + self.assertEquals(self.encapsulated, self.mod.read()) + expected = 'import mod\n' \ + 'a_var = mod.A()\n' \ + 'range(a_var.get_attr())\n' + self.assertEquals(expected, self.mod1.read()) + + def test_changing_main_module_occurances(self): + code = self.a_class + \ + 'a_var = A()\n' \ + 'a_var.attr = a_var.attr * 2\n' + self.mod1.write(code) + self._encapsulate(self.mod1, self.mod1.read().index('attr') + 1) + expected = self.encapsulated + \ + 'a_var = A()\n' \ + 'a_var.set_attr(a_var.get_attr() * 2)\n' + self.assertEquals(expected, self.mod1.read()) + + @testutils.assert_raises(RefactoringError) + def test_raising_exception_when_performed_on_non_attributes(self): + self.mod1.write('attr = 10') + self._encapsulate(self.mod1, self.mod1.read().index('attr') + 1) + + @testutils.assert_raises(RefactoringError) + def test_raising_exception_on_tuple_assignments(self): + self.mod.write(self.a_class) + code = 'import mod\n' \ + 'a_var = mod.A()\n' \ + 'a_var.attr = 1\n' \ + 'a_var.attr, b = 1, 2\n' + self.mod1.write(code) + self._encapsulate(self.mod1, self.mod1.read().index('attr') + 1) + + @testutils.assert_raises(RefactoringError) + def test_raising_exception_on_tuple_assignments2(self): + self.mod.write(self.a_class) + code = 'import mod\n' \ + 'a_var = mod.A()\n' \ + 'a_var.attr = 1\n' \ + 'b, a_var.attr = 1, 2\n' + self.mod1.write(code) + self._encapsulate(self.mod1, self.mod1.read().index('attr') + 1) + + def test_tuple_assignments_and_function_calls(self): + code = 'import mod\n' \ + 'def func(a1=0, a2=0):\n' \ + ' pass\n' \ + 'a_var = mod.A()\n' \ + 'func(a_var.attr, a2=2)\n' + self.mod1.write(code) + self.mod.write(self.a_class) + self._encapsulate(self.mod, self.mod.read().index('attr') + 1) + expected = 'import mod\n' \ + 'def func(a1=0, a2=0):\n' \ + ' pass\n' \ + 'a_var = mod.A()\n' \ + 'func(a_var.get_attr(), a2=2)\n' + self.assertEquals(expected, self.mod1.read()) + + def test_tuple_assignments(self): + code = 'import mod\n' \ + 'a_var = mod.A()\n' \ + 'a, b = a_var.attr, 1\n' + self.mod1.write(code) + self.mod.write(self.a_class) + self._encapsulate(self.mod, self.mod.read().index('attr') + 1) + expected = 'import mod\n' \ + 'a_var = mod.A()\n' \ + 'a, b = a_var.get_attr(), 1\n' + self.assertEquals(expected, self.mod1.read()) + + def test_changing_augmented_assignments(self): + code = 'import mod\n' \ + 'a_var = mod.A()\n' \ + 'a_var.attr += 1\n' + self.mod1.write(code) + self.mod.write(self.a_class) + self._encapsulate(self.mod, self.mod.read().index('attr') + 1) + expected = 'import mod\n' \ + 'a_var = mod.A()\n' \ + 'a_var.set_attr(a_var.get_attr() + 1)\n' + self.assertEquals(expected, self.mod1.read()) + + def test_changing_augmented_assignments2(self): + code = 'import mod\n' \ + 'a_var = mod.A()\n' \ + 'a_var.attr <<= 1\n' + self.mod1.write(code) + self.mod.write(self.a_class) + self._encapsulate(self.mod, self.mod.read().index('attr') + 1) + expected = 'import mod\n' \ + 'a_var = mod.A()\n' \ + 'a_var.set_attr(a_var.get_attr() << 1)\n' + self.assertEquals(expected, self.mod1.read()) + + def test_changing_occurrences_inside_the_class(self): + new_class = self.a_class + '\n' \ + ' def a_func(self):\n' \ + ' self.attr = 1\n' + self.mod.write(new_class) + self._encapsulate(self.mod, self.mod.read().index('attr') + 1) + expected = self.a_class + '\n' \ + ' def a_func(self):\n' \ + ' self.set_attr(1)\n' + \ + self.added_methods + self.assertEquals(expected, self.mod.read()) + + def test_getter_and_setter_parameters(self): + self.mod.write(self.a_class) + self._encapsulate(self.mod, self.mod.read().index('attr') + 1, + getter='getAttr', setter='setAttr') + new_methods = self.added_methods.replace('get_attr', 'getAttr').\ + replace('set_attr', 'setAttr') + expected = self.a_class + new_methods + self.assertEquals(expected, self.mod.read()) + + def test_using_resources_parameter(self): + self.mod1.write('import mod\na = mod.A()\nvar = a.attr\n') + self.mod.write(self.a_class) + self._encapsulate(self.mod, self.mod.read().index('attr') + 1, + resources=[self.mod]) + self.assertEquals('import mod\na = mod.A()\nvar = a.attr\n', + self.mod1.read()) + expected = self.a_class + self.added_methods + self.assertEquals(expected, self.mod.read()) + + +class LocalToFieldTest(unittest.TestCase): + + def setUp(self): + super(LocalToFieldTest, self).setUp() + self.project = testutils.sample_project() + self.pycore = self.project.pycore + self.mod = testutils.create_module(self.project, 'mod') + + def tearDown(self): + testutils.remove_project(self.project) + super(LocalToFieldTest, self).tearDown() + + def _perform_convert_local_variable_to_field(self, resource, offset): + changes = LocalToField( + self.project, resource, offset).get_changes() + self.project.do(changes) + + def test_simple_local_to_field(self): + code = 'class A(object):\n' \ + ' def a_func(self):\n' \ + ' var = 10\n' + self.mod.write(code) + self._perform_convert_local_variable_to_field(self.mod, + code.index('var') + 1) + expected = 'class A(object):\n' \ + ' def a_func(self):\n' \ + ' self.var = 10\n' + self.assertEquals(expected, self.mod.read()) + + @testutils.assert_raises(RefactoringError) + def test_raising_exception_when_performed_on_a_global_var(self): + self.mod.write('var = 10\n') + self._perform_convert_local_variable_to_field( + self.mod, self.mod.read().index('var') + 1) + + @testutils.assert_raises(RefactoringError) + def test_raising_exception_when_performed_on_field(self): + code = 'class A(object):\n' \ + ' def a_func(self):\n' \ + ' self.var = 10\n' + self.mod.write(code) + self._perform_convert_local_variable_to_field( + self.mod, self.mod.read().index('var') + 1) + + @testutils.assert_raises(RefactoringError) + def test_raising_exception_when_performed_on_a_parameter(self): + code = 'class A(object):\n' \ + ' def a_func(self, var):\n' \ + ' a = var\n' + self.mod.write(code) + self._perform_convert_local_variable_to_field( + self.mod, self.mod.read().index('var') + 1) + + # NOTE: This situation happens alot and is normally not an error + #@testutils.assert_raises(RefactoringError) + def test_not_raising_exception_when_there_is_a_field_with_the_same_name(self): + code = 'class A(object):\n' \ + ' def __init__(self):\n' \ + ' self.var = 1\n' \ + ' def a_func(self):\n var = 10\n' + self.mod.write(code) + self._perform_convert_local_variable_to_field( + self.mod, self.mod.read().rindex('var') + 1) + + def test_local_to_field_with_self_renamed(self): + code = 'class A(object):\n' \ + ' def a_func(myself):\n' \ + ' var = 10\n' + self.mod.write(code) + self._perform_convert_local_variable_to_field(self.mod, + code.index('var') + 1) + expected = 'class A(object):\n' \ + ' def a_func(myself):\n' \ + ' myself.var = 10\n' + self.assertEquals(expected, self.mod.read()) + + +class IntroduceParameterTest(unittest.TestCase): + + def setUp(self): + super(IntroduceParameterTest, self).setUp() + self.project = testutils.sample_project() + self.pycore = self.project.pycore + self.mod = testutils.create_module(self.project, 'mod') + + def tearDown(self): + testutils.remove_project(self.project) + super(IntroduceParameterTest, self).tearDown() + + def _introduce_parameter(self, offset, name): + rope.refactor.introduce_parameter.IntroduceParameter( + self.project, self.mod, offset).get_changes(name).do() + + def test_simple_case(self): + code = 'var = 1\n' \ + 'def f():\n' \ + ' b = var\n' + self.mod.write(code) + offset = self.mod.read().rindex('var') + self._introduce_parameter(offset, 'var') + expected = 'var = 1\n' \ + 'def f(var=var):\n' \ + ' b = var\n' + self.assertEquals(expected, self.mod.read()) + + def test_changing_function_body(self): + code = 'var = 1\n' \ + 'def f():\n' \ + ' b = var\n' + self.mod.write(code) + offset = self.mod.read().rindex('var') + self._introduce_parameter(offset, 'p1') + expected = 'var = 1\n' \ + 'def f(p1=var):\n' \ + ' b = p1\n' + self.assertEquals(expected, self.mod.read()) + + @testutils.assert_raises(RefactoringError) + def test_unknown_variables(self): + self.mod.write('def f():\n b = var + c\n') + offset = self.mod.read().rindex('var') + self._introduce_parameter(offset, 'p1') + self.assertEquals('def f(p1=var):\n b = p1 + c\n', + self.mod.read()) + + @testutils.assert_raises(RefactoringError) + def test_failing_when_not_inside(self): + self.mod.write('var = 10\nb = var\n') + offset = self.mod.read().rindex('var') + self._introduce_parameter(offset, 'p1') + + def test_attribute_accesses(self): + code = 'class C(object):\n' \ + ' a = 10\nc = C()\n' \ + 'def f():\n' \ + ' b = c.a\n' + self.mod.write(code) + offset = self.mod.read().rindex('a') + self._introduce_parameter(offset, 'p1') + expected = 'class C(object):\n' \ + ' a = 10\n' \ + 'c = C()\n' \ + 'def f(p1=c.a):\n' \ + ' b = p1\n' + self.assertEquals(expected, self.mod.read()) + + def test_introducing_parameters_for_methods(self): + code = 'var = 1\n' \ + 'class C(object):\n' \ + ' def f(self):\n' \ + ' b = var\n' + self.mod.write(code) + offset = self.mod.read().rindex('var') + self._introduce_parameter(offset, 'p1') + expected = 'var = 1\n' \ + 'class C(object):\n' \ + ' def f(self, p1=var):\n' \ + ' b = p1\n' + self.assertEquals(expected, self.mod.read()) + + +class _MockTaskObserver(object): + + def __init__(self): + self.called = 0 + + def __call__(self): + self.called += 1 + +class TaskHandleTest(unittest.TestCase): + + def test_trivial_case(self): + handle = rope.base.taskhandle.TaskHandle() + self.assertFalse(handle.is_stopped()) + + def test_stopping(self): + handle = rope.base.taskhandle.TaskHandle() + handle.stop() + self.assertTrue(handle.is_stopped()) + + def test_job_sets(self): + handle = rope.base.taskhandle.TaskHandle() + jobs = handle.create_jobset() + self.assertEquals([jobs], handle.get_jobsets()) + + def test_starting_and_finishing_jobs(self): + handle = rope.base.taskhandle.TaskHandle() + jobs = handle.create_jobset(name='test job set', count=1) + jobs.started_job('job1') + jobs.finished_job() + + @testutils.assert_raises(InterruptedTaskError) + def test_test_checking_status(self): + handle = rope.base.taskhandle.TaskHandle() + jobs = handle.create_jobset() + handle.stop() + jobs.check_status() + + @testutils.assert_raises(InterruptedTaskError) + def test_test_checking_status_when_starting(self): + handle = rope.base.taskhandle.TaskHandle() + jobs = handle.create_jobset() + handle.stop() + jobs.started_job('job1') + + def test_calling_the_observer_after_stopping(self): + handle = rope.base.taskhandle.TaskHandle() + observer = _MockTaskObserver() + handle.add_observer(observer) + handle.stop() + self.assertEquals(1, observer.called) + + def test_calling_the_observer_after_creating_job_sets(self): + handle = rope.base.taskhandle.TaskHandle() + observer = _MockTaskObserver() + handle.add_observer(observer) + jobs = handle.create_jobset() + self.assertEquals(1, observer.called) + + def test_calling_the_observer_when_starting_and_finishing_jobs(self): + handle = rope.base.taskhandle.TaskHandle() + observer = _MockTaskObserver() + handle.add_observer(observer) + jobs = handle.create_jobset(name='test job set', count=1) + jobs.started_job('job1') + jobs.finished_job() + self.assertEquals(3, observer.called) + + def test_job_set_get_percent_done(self): + handle = rope.base.taskhandle.TaskHandle() + jobs = handle.create_jobset(name='test job set', count=2) + self.assertEquals(0, jobs.get_percent_done()) + jobs.started_job('job1') + jobs.finished_job() + self.assertEquals(50, jobs.get_percent_done()) + jobs.started_job('job2') + jobs.finished_job() + self.assertEquals(100, jobs.get_percent_done()) + + def test_getting_job_name(self): + handle = rope.base.taskhandle.TaskHandle() + jobs = handle.create_jobset(name='test job set', count=1) + self.assertEquals('test job set', jobs.get_name()) + self.assertEquals(None, jobs.get_active_job_name()) + jobs.started_job('job1') + self.assertEquals('job1', jobs.get_active_job_name()) + + +def suite(): + result = unittest.TestSuite() + result.addTests(ropetest.refactor.renametest.suite()) + result.addTests(unittest.makeSuite( + ropetest.refactor.extracttest.ExtractMethodTest)) + result.addTests(unittest.makeSuite(IntroduceFactoryTest)) + result.addTests(unittest.makeSuite( + ropetest.refactor.movetest.MoveRefactoringTest)) + result.addTests(ropetest.refactor.inlinetest.suite()) + result.addTests(unittest.makeSuite( + ropetest.refactor.patchedasttest.PatchedASTTest)) + result.addTests(unittest.makeSuite(EncapsulateFieldTest)) + result.addTests(unittest.makeSuite(LocalToFieldTest)) + result.addTests(unittest.makeSuite( + change_signature_test.ChangeSignatureTest)) + result.addTests(unittest.makeSuite(IntroduceParameterTest)) + result.addTests(ropetest.refactor.importutilstest.suite()) + result.addTests(similarfindertest.suite()) + result.addTests(unittest.makeSuite(TaskHandleTest)) + result.addTests(unittest.makeSuite(ropetest.refactor. + restructuretest.RestructureTest)) + result.addTests(unittest.makeSuite(ropetest.refactor. + suitestest.SuiteTest)) + result.addTests(unittest.makeSuite(ropetest.refactor.multiprojecttest. + MultiProjectRefactoringTest)) + result.addTests(unittest.makeSuite(ropetest.refactor.usefunctiontest. + UseFunctionTest)) + return result + + +if __name__ == '__main__': + import sys + if len(sys.argv) > 1: + unittest.main() + else: + runner = unittest.TextTestRunner() + result = runner.run(suite()) + sys.exit(not result.wasSuccessful()) diff -r e30544496575 -r 48cacfdc2ca6 vim/sadness/ropevim/src/rope/ropetest/refactor/change_signature_test.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vim/sadness/ropevim/src/rope/ropetest/refactor/change_signature_test.py Wed Oct 06 12:30:46 2010 -0400 @@ -0,0 +1,413 @@ +import unittest + +import rope.base.exceptions +from rope.refactor import change_signature +from rope.refactor.change_signature import * +from ropetest import testutils + + +class ChangeSignatureTest(unittest.TestCase): + + def setUp(self): + super(ChangeSignatureTest, self).setUp() + self.project = testutils.sample_project() + self.pycore = self.project.pycore + self.mod = testutils.create_module(self.project, 'mod') + + def tearDown(self): + testutils.remove_project(self.project) + super(ChangeSignatureTest, self).tearDown() + + def test_normalizing_parameters_for_trivial_case(self): + code = 'def a_func():\n pass\na_func()' + self.mod.write(code) + signature = ChangeSignature(self.project, self.mod, + self.mod.read().index('a_func') + 1) + self.project.do(signature.get_changes([ArgumentNormalizer()])) + self.assertEquals(code, self.mod.read()) + + def test_normalizing_parameters_for_trivial_case2(self): + code = 'def a_func(param):\n pass\na_func(2)' + self.mod.write(code) + signature = ChangeSignature(self.project, self.mod, + self.mod.read().index('a_func') + 1) + self.project.do(signature.get_changes([ArgumentNormalizer()])) + self.assertEquals(code, self.mod.read()) + + def test_normalizing_parameters_for_unneeded_keyword(self): + self.mod.write('def a_func(param):\n pass\na_func(param=1)') + signature = ChangeSignature(self.project, self.mod, + self.mod.read().index('a_func') + 1) + self.project.do(signature.get_changes([ArgumentNormalizer()])) + self.assertEquals('def a_func(param):\n pass\na_func(1)', self.mod.read()) + + def test_normalizing_parameters_for_unneeded_keyword_for_methods(self): + code = 'class A(object):\n' \ + ' def a_func(self, param):\n' \ + ' pass\n' \ + 'a_var = A()\n' \ + 'a_var.a_func(param=1)\n' + self.mod.write(code) + signature = ChangeSignature(self.project, self.mod, + self.mod.read().index('a_func') + 1) + self.project.do(signature.get_changes([ArgumentNormalizer()])) + expected = 'class A(object):\n' \ + ' def a_func(self, param):\n' \ + ' pass\n' \ + 'a_var = A()\n' \ + 'a_var.a_func(1)\n' + self.assertEquals(expected, self.mod.read()) + + def test_normalizing_parameters_for_unsorted_keyword(self): + self.mod.write('def a_func(p1, p2):\n pass\na_func(p2=2, p1=1)') + signature = ChangeSignature(self.project, self.mod, + self.mod.read().index('a_func') + 1) + self.project.do(signature.get_changes([ArgumentNormalizer()])) + self.assertEquals('def a_func(p1, p2):\n pass\na_func(1, 2)', + self.mod.read()) + + @testutils.assert_raises(rope.base.exceptions.RefactoringError) + def test_raising_exceptions_for_non_functions(self): + self.mod.write('a_var = 10') + signature = ChangeSignature(self.project, self.mod, + self.mod.read().index('a_var') + 1) + + def test_normalizing_parameters_for_args_parameter(self): + self.mod.write('def a_func(*arg):\n pass\na_func(1, 2)\n') + signature = ChangeSignature(self.project, self.mod, + self.mod.read().index('a_func') + 1) + self.project.do(signature.get_changes([ArgumentNormalizer()])) + self.assertEquals('def a_func(*arg):\n pass\na_func(1, 2)\n', + self.mod.read()) + + def test_normalizing_parameters_for_args_parameter_and_keywords(self): + self.mod.write('def a_func(param, *args):\n pass\na_func(*[1, 2, 3])\n') + signature = ChangeSignature(self.project, self.mod, + self.mod.read().index('a_func') + 1) + self.project.do(signature.get_changes([ArgumentNormalizer()])) + self.assertEquals('def a_func(param, *args):\n pass\n' + 'a_func(*[1, 2, 3])\n', self.mod.read()) + + def test_normalizing_functions_from_other_modules(self): + mod1 = testutils.create_module(self.project, 'mod1') + mod1.write('def a_func(param):\n pass\n') + self.mod.write('import mod1\nmod1.a_func(param=1)\n') + signature = ChangeSignature(self.project, mod1, + mod1.read().index('a_func') + 1) + self.project.do(signature.get_changes([ArgumentNormalizer()])) + self.assertEquals('import mod1\nmod1.a_func(1)\n', self.mod.read()) + + def test_normalizing_parameters_for_keyword_parameters(self): + self.mod.write('def a_func(p1, **kwds):\n pass\n' + 'a_func(p2=2, p1=1)\n') + signature = ChangeSignature(self.project, self.mod, + self.mod.read().index('a_func') + 1) + self.project.do(signature.get_changes([ArgumentNormalizer()])) + self.assertEquals('def a_func(p1, **kwds):\n pass\n' + 'a_func(1, p2=2)\n', self.mod.read()) + + def test_removing_arguments(self): + self.mod.write('def a_func(p1):\n pass\na_func(1)\n') + signature = ChangeSignature(self.project, self.mod, + self.mod.read().index('a_func') + 1) + self.project.do(signature.get_changes([ArgumentRemover(0)])) + self.assertEquals('def a_func():\n pass\na_func()\n', + self.mod.read()) + + def test_removing_arguments_with_multiple_args(self): + self.mod.write('def a_func(p1, p2):\n pass\na_func(1, 2)\n') + signature = ChangeSignature(self.project, self.mod, + self.mod.read().index('a_func') + 1) + self.project.do(signature.get_changes([ArgumentRemover(0)])) + self.assertEquals('def a_func(p2):\n pass\na_func(2)\n', + self.mod.read()) + + def test_removing_arguments_passed_as_keywords(self): + self.mod.write('def a_func(p1):\n pass\na_func(p1=1)\n') + signature = ChangeSignature(self.project, self.mod, + self.mod.read().index('a_func') + 1) + self.project.do(signature.get_changes([ArgumentRemover(0)])) + self.assertEquals('def a_func():\n pass\na_func()\n', + self.mod.read()) + + def test_removing_arguments_with_defaults(self): + self.mod.write('def a_func(p1=1):\n pass\na_func(1)\n') + signature = ChangeSignature(self.project, self.mod, + self.mod.read().index('a_func') + 1) + self.project.do(signature.get_changes([ArgumentRemover(0)])) + self.assertEquals('def a_func():\n pass\na_func()\n', + self.mod.read()) + + def test_removing_arguments_star_args(self): + self.mod.write('def a_func(p1, *args):\n pass\na_func(1)\n') + signature = ChangeSignature(self.project, self.mod, + self.mod.read().index('a_func') + 1) + self.project.do(signature.get_changes([ArgumentRemover(1)])) + self.assertEquals('def a_func(p1):\n pass\na_func(1)\n', + self.mod.read()) + + def test_removing_keyword_arg(self): + self.mod.write('def a_func(p1, **kwds):\n pass\na_func(1)\n') + signature = ChangeSignature(self.project, self.mod, + self.mod.read().index('a_func') + 1) + self.project.do(signature.get_changes([ArgumentRemover(1)])) + self.assertEquals('def a_func(p1):\n pass\na_func(1)\n', + self.mod.read()) + + def test_removing_keyword_arg2(self): + self.mod.write('def a_func(p1, *args, **kwds):\n pass\na_func(1)\n') + signature = ChangeSignature(self.project, self.mod, + self.mod.read().index('a_func') + 1) + self.project.do(signature.get_changes([ArgumentRemover(2)])) + self.assertEquals('def a_func(p1, *args):\n pass\na_func(1)\n', + self.mod.read()) + + # XXX: What to do here for star args? + def xxx_test_removing_arguments_star_args2(self): + self.mod.write('def a_func(p1, *args):\n pass\n' + 'a_func(2, 3, p1=1)\n') + signature = ChangeSignature(self.project, self.mod, + self.mod.read().index('a_func') + 1) + self.project.do(signature.get_changes([ArgumentRemover(1)])) + self.assertEquals('def a_func(p1):\n pass\na_func(p1=1)\n', + self.mod.read()) + + # XXX: What to do here for star args? + def xxx_test_removing_arguments_star_args3(self): + self.mod.write('def a_func(p1, *args):\n pass\n' + 'a_func(*[1, 2, 3])\n') + signature = ChangeSignature(self.project, self.mod, + self.mod.read().index('a_func') + 1) + self.project.do(signature.get_changes([ArgumentRemover(1)])) + self.assertEquals('def a_func(p1):\n pass\na_func(*[1, 2, 3])\n', + self.mod.read()) + + def test_adding_arguments_for_normal_args_changing_definition(self): + self.mod.write('def a_func():\n pass\n') + signature = ChangeSignature(self.project, self.mod, + self.mod.read().index('a_func') + 1) + self.project.do(signature.get_changes([ArgumentAdder(0, 'p1')])) + self.assertEquals('def a_func(p1):\n pass\n', self.mod.read()) + + def test_adding_arguments_for_normal_args_with_defaults(self): + self.mod.write('def a_func():\n pass\na_func()\n') + signature = ChangeSignature(self.project, self.mod, + self.mod.read().index('a_func') + 1) + adder = ArgumentAdder(0, 'p1', 'None') + self.project.do(signature.get_changes([adder])) + self.assertEquals('def a_func(p1=None):\n pass\na_func()\n', + self.mod.read()) + + def test_adding_arguments_for_normal_args_changing_calls(self): + self.mod.write('def a_func():\n pass\na_func()\n') + signature = ChangeSignature(self.project, self.mod, + self.mod.read().index('a_func') + 1) + adder = ArgumentAdder(0, 'p1', 'None', '1') + self.project.do(signature.get_changes([adder])) + self.assertEquals('def a_func(p1=None):\n pass\na_func(1)\n', + self.mod.read()) + + def test_adding_arguments_for_normal_args_changing_calls_with_keywords(self): + self.mod.write('def a_func(p1=0):\n pass\na_func()\n') + signature = ChangeSignature(self.project, self.mod, + self.mod.read().index('a_func') + 1) + adder = ArgumentAdder(1, 'p2', '0', '1') + self.project.do(signature.get_changes([adder])) + self.assertEquals('def a_func(p1=0, p2=0):\n pass\na_func(p2=1)\n', + self.mod.read()) + + def test_adding_arguments_for_normal_args_changing_calls_with_no_value(self): + self.mod.write('def a_func(p2=0):\n pass\na_func(1)\n') + signature = ChangeSignature(self.project, self.mod, + self.mod.read().index('a_func') + 1) + adder = ArgumentAdder(0, 'p1', '0', None) + self.project.do(signature.get_changes([adder])) + self.assertEquals('def a_func(p1=0, p2=0):\n pass\na_func(p2=1)\n', + self.mod.read()) + + @testutils.assert_raises(rope.base.exceptions.RefactoringError) + def test_adding_duplicate_parameter_and_raising_exceptions(self): + self.mod.write('def a_func(p1):\n pass\n') + signature = ChangeSignature(self.project, self.mod, + self.mod.read().index('a_func') + 1) + self.project.do(signature.get_changes([ArgumentAdder(1, 'p1')])) + + def test_inlining_default_arguments(self): + self.mod.write('def a_func(p1=0):\n pass\na_func()\n') + signature = ChangeSignature(self.project, self.mod, + self.mod.read().index('a_func') + 1) + self.project.do(signature.get_changes([ArgumentDefaultInliner(0)])) + self.assertEquals('def a_func(p1=0):\n pass\n' + 'a_func(0)\n', self.mod.read()) + + def test_inlining_default_arguments2(self): + self.mod.write('def a_func(p1=0):\n pass\na_func(1)\n') + signature = ChangeSignature(self.project, self.mod, + self.mod.read().index('a_func') + 1) + self.project.do(signature.get_changes([ArgumentDefaultInliner(0)])) + self.assertEquals('def a_func(p1=0):\n pass\n' + 'a_func(1)\n', self.mod.read()) + + def test_preserving_args_and_keywords_order(self): + self.mod.write('def a_func(*args, **kwds):\n pass\n' + 'a_func(3, 1, 2, a=1, c=3, b=2)\n') + signature = ChangeSignature(self.project, self.mod, + self.mod.read().index('a_func') + 1) + self.project.do(signature.get_changes([ArgumentNormalizer()])) + self.assertEquals('def a_func(*args, **kwds):\n pass\n' + 'a_func(3, 1, 2, a=1, c=3, b=2)\n', self.mod.read()) + + def test_change_order_for_only_one_parameter(self): + self.mod.write('def a_func(p1):\n pass\na_func(1)\n') + signature = ChangeSignature(self.project, self.mod, + self.mod.read().index('a_func') + 1) + self.project.do(signature.get_changes([ArgumentReorderer([0])])) + self.assertEquals('def a_func(p1):\n pass\na_func(1)\n', + self.mod.read()) + + def test_change_order_for_two_parameter(self): + self.mod.write('def a_func(p1, p2):\n pass\na_func(1, 2)\n') + signature = ChangeSignature(self.project, self.mod, + self.mod.read().index('a_func') + 1) + self.project.do(signature.get_changes([ArgumentReorderer([1, 0])])) + self.assertEquals('def a_func(p2, p1):\n pass\na_func(2, 1)\n', + self.mod.read()) + + def test_reordering_multi_line_function_headers(self): + self.mod.write('def a_func(p1,\n p2):\n pass\na_func(1, 2)\n') + signature = ChangeSignature(self.project, self.mod, + self.mod.read().index('a_func') + 1) + self.project.do(signature.get_changes([ArgumentReorderer([1, 0])])) + self.assertEquals('def a_func(p2, p1):\n pass\na_func(2, 1)\n', + self.mod.read()) + + def test_changing_order_with_static_params(self): + self.mod.write('def a_func(p1, p2=0, p3=0):\n pass\na_func(1, 2)\n') + signature = ChangeSignature(self.project, self.mod, + self.mod.read().index('a_func') + 1) + self.project.do(signature.get_changes([ArgumentReorderer([0, 2, 1])])) + self.assertEquals('def a_func(p1, p3=0, p2=0):\n pass\n' + 'a_func(1, p2=2)\n', self.mod.read()) + + def test_doing_multiple_changes(self): + changers = [] + self.mod.write('def a_func(p1):\n pass\na_func(1)\n') + changers.append(change_signature.ArgumentRemover(0)) + changers.append(change_signature.ArgumentAdder(0, 'p2', None, None)) + signature = ChangeSignature(self.project, self.mod, + self.mod.read().index('a_func') + 1) + signature.get_changes(changers).do() + self.assertEquals('def a_func(p2):\n pass\na_func()\n', + self.mod.read()) + + def test_doing_multiple_changes2(self): + changers = [] + self.mod.write('def a_func(p1, p2):\n pass\na_func(p2=2)\n') + changers.append(change_signature.ArgumentAdder(2, 'p3', None, '3')) + changers.append(change_signature.ArgumentReorderer([1, 0, 2])) + changers.append(change_signature.ArgumentRemover(1)) + signature = ChangeSignature(self.project, self.mod, + self.mod.read().index('a_func') + 1) + signature.get_changes(changers).do() + self.assertEquals('def a_func(p2, p3):\n pass\na_func(2, 3)\n', + self.mod.read()) + + def test_changing_signature_in_subclasses(self): + self.mod.write( + 'class A(object):\n def a_method(self):\n pass\n' + 'class B(A):\n def a_method(self):\n pass\n') + signature = ChangeSignature(self.project, self.mod, + self.mod.read().index('a_method') + 1) + signature.get_changes([change_signature.ArgumentAdder(1, 'p1')], + in_hierarchy=True).do() + self.assertEquals( + 'class A(object):\n def a_method(self, p1):\n pass\n' + 'class B(A):\n def a_method(self, p1):\n pass\n', + self.mod.read()) + + def test_differentiating_class_accesses_from_instance_accesses(self): + self.mod.write( + 'class A(object):\n def a_func(self, param):\n pass\n' + 'a_var = A()\nA.a_func(a_var, param=1)') + signature = ChangeSignature(self.project, self.mod, + self.mod.read().index('a_func') + 1) + self.project.do(signature.get_changes([ArgumentRemover(1)])) + self.assertEquals( + 'class A(object):\n def a_func(self):\n pass\n' + 'a_var = A()\nA.a_func(a_var)', self.mod.read()) + + def test_changing_signature_for_constructors(self): + self.mod.write( + 'class C(object):\n def __init__(self, p):\n pass\n' + 'c = C(1)\n') + signature = ChangeSignature(self.project, self.mod, + self.mod.read().index('C') + 1) + signature.get_changes([change_signature.ArgumentRemover(1)]).do() + self.assertEquals( + 'class C(object):\n def __init__(self):\n pass\n' + 'c = C()\n', + self.mod.read()) + + def test_changing_signature_for_constructors2(self): + self.mod.write( + 'class C(object):\n def __init__(self, p):\n pass\n' + 'c = C(1)\n') + signature = ChangeSignature(self.project, self.mod, + self.mod.read().index('__init__') + 1) + signature.get_changes([change_signature.ArgumentRemover(1)]).do() + self.assertEquals( + 'class C(object):\n def __init__(self):\n pass\n' + 'c = C()\n', + self.mod.read()) + + def test_changing_signature_for_constructors_when_using_super(self): + self.mod.write( + 'class A(object):\n def __init__(self, p):\n pass\n' + 'class B(A):\n ' + 'def __init__(self, p):\n super(B, self).__init__(p)\n') + signature = ChangeSignature(self.project, self.mod, + self.mod.read().index('__init__') + 1) + signature.get_changes([change_signature.ArgumentRemover(1)]).do() + self.assertEquals( + 'class A(object):\n def __init__(self):\n pass\n' + 'class B(A):\n ' + 'def __init__(self, p):\n super(B, self).__init__()\n', + self.mod.read()) + + def test_redordering_arguments_reported_by_mft(self): + self.mod.write('def f(a, b, c):\n pass\nf(1, 2, 3)\n') + signature = ChangeSignature(self.project, self.mod, + self.mod.read().rindex('f')) + signature.get_changes( + [change_signature.ArgumentReorderer([1, 2, 0])]).do() + self.assertEquals('def f(b, c, a):\n pass\nf(2, 3, 1)\n', + self.mod.read()) + + def test_resources_parameter(self): + mod1 = testutils.create_module(self.project, 'mod1') + mod1.write('def a_func(param):\n pass\n') + self.mod.write('import mod1\nmod1.a_func(1)\n') + signature = ChangeSignature(self.project, mod1, + mod1.read().index('a_func') + 1) + signature.get_changes([change_signature.ArgumentRemover(0)], + resources=[mod1]).do() + self.assertEquals('import mod1\nmod1.a_func(1)\n', self.mod.read()) + self.assertEquals('def a_func():\n pass\n', mod1.read()) + + def test_reordering_and_automatic_defaults(self): + code = 'def f(p1, p2=2):\n' \ + ' pass\n' \ + 'f(1, 2)\n' + self.mod.write(code) + signature = ChangeSignature(self.project, self.mod, + code.index('f(')) + reorder = change_signature.ArgumentReorderer([1, 0], autodef='1') + signature.get_changes([reorder]).do() + expected = 'def f(p2=2, p1=1):\n' \ + ' pass\n' \ + 'f(2, 1)\n' + self.assertEquals(expected, self.mod.read()) + + +if __name__ == '__main__': + unittest.main() diff -r e30544496575 -r 48cacfdc2ca6 vim/sadness/ropevim/src/rope/ropetest/refactor/extracttest.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vim/sadness/ropevim/src/rope/ropetest/refactor/extracttest.py Wed Oct 06 12:30:46 2010 -0400 @@ -0,0 +1,877 @@ +import unittest + +import rope.base.codeanalyze +import rope.base.exceptions +import ropetest.testutils as testutils +from rope.refactor import extract +from ropetest import testutils + + +class ExtractMethodTest(unittest.TestCase): + + def setUp(self): + super(ExtractMethodTest, self).setUp() + self.project = testutils.sample_project() + self.pycore = self.project.pycore + + def tearDown(self): + testutils.remove_project(self.project) + super(ExtractMethodTest, self).tearDown() + + def do_extract_method(self, source_code, start, end, extracted, **kwds): + testmod = testutils.create_module(self.project, 'testmod') + testmod.write(source_code) + extractor = extract.ExtractMethod( + self.project, testmod, start, end) + self.project.do(extractor.get_changes(extracted, **kwds)) + return testmod.read() + + def do_extract_variable(self, source_code, start, end, extracted, **kwds): + testmod = testutils.create_module(self.project, 'testmod') + testmod.write(source_code) + extractor = extract.ExtractVariable( self.project, testmod, start, end) + self.project.do(extractor.get_changes(extracted, **kwds)) + return testmod.read() + + def _convert_line_range_to_offset(self, code, start, end): + lines = rope.base.codeanalyze.SourceLinesAdapter(code) + return lines.get_line_start(start), lines.get_line_end(end) + + def test_simple_extract_function(self): + code = "def a_func():\n print('one')\n print('two')\n" + start, end = self._convert_line_range_to_offset(code, 2, 2) + refactored = self.do_extract_method(code, start, end, 'extracted') + expected = "def a_func():\n extracted()\n print('two')\n\n" \ + "def extracted():\n print('one')\n" + self.assertEquals(expected, refactored) + + def test_extract_function_at_the_end_of_file(self): + code = "def a_func():\n print('one')" + start, end = self._convert_line_range_to_offset(code, 2, 2) + refactored = self.do_extract_method(code, start, end, 'extracted') + expected = "def a_func():\n extracted()\n" \ + "def extracted():\n print('one')\n" + self.assertEquals(expected, refactored) + + def test_extract_function_after_scope(self): + code = "def a_func():\n print('one')\n print('two')\n\nprint('hey')\n" + start, end = self._convert_line_range_to_offset(code, 2, 2) + refactored = self.do_extract_method(code, start, end, 'extracted') + expected = "def a_func():\n extracted()\n print('two')\n\n" \ + "def extracted():\n print('one')\n\nprint('hey')\n" + self.assertEquals(expected, refactored) + + def test_simple_extract_function_with_parameter(self): + code = "def a_func():\n a_var = 10\n print(a_var)\n" + start, end = self._convert_line_range_to_offset(code, 3, 3) + refactored = self.do_extract_method(code, start, end, 'new_func') + expected = "def a_func():\n a_var = 10\n new_func(a_var)\n\n" \ + "def new_func(a_var):\n print(a_var)\n" + self.assertEquals(expected, refactored) + + def test_not_unread_variables_as_parameter(self): + code = "def a_func():\n a_var = 10\n print('hey')\n" + start, end = self._convert_line_range_to_offset(code, 3, 3) + refactored = self.do_extract_method(code, start, end, 'new_func') + expected = "def a_func():\n a_var = 10\n new_func()\n\n" \ + "def new_func():\n print('hey')\n" + self.assertEquals(expected, refactored) + + def test_simple_extract_function_with_two_parameter(self): + code = 'def a_func():\n a_var = 10\n another_var = 20\n' \ + ' third_var = a_var + another_var\n' + start, end = self._convert_line_range_to_offset(code, 4, 4) + refactored = self.do_extract_method(code, start, end, 'new_func') + expected = 'def a_func():\n a_var = 10\n another_var = 20\n' \ + ' new_func(a_var, another_var)\n\n' \ + 'def new_func(a_var, another_var):\n' \ + ' third_var = a_var + another_var\n' + self.assertEquals(expected, refactored) + + def test_simple_extract_function_with_return_value(self): + code = 'def a_func():\n a_var = 10\n print(a_var)\n' + start, end = self._convert_line_range_to_offset(code, 2, 2) + refactored = self.do_extract_method(code, start, end, 'new_func') + expected = 'def a_func():\n a_var = new_func()\n print(a_var)\n\n' \ + 'def new_func():\n a_var = 10\n return a_var\n' + self.assertEquals(expected, refactored) + + def test_extract_function_with_multiple_return_values(self): + code = 'def a_func():\n a_var = 10\n another_var = 20\n' \ + ' third_var = a_var + another_var\n' + start, end = self._convert_line_range_to_offset(code, 2, 3) + refactored = self.do_extract_method(code, start, end, 'new_func') + expected = 'def a_func():\n a_var, another_var = new_func()\n' \ + ' third_var = a_var + another_var\n\n' \ + 'def new_func():\n a_var = 10\n another_var = 20\n' \ + ' return a_var, another_var\n' + self.assertEquals(expected, refactored) + + def test_simple_extract_method(self): + code = 'class AClass(object):\n\n' \ + ' def a_func(self):\n print(1)\n print(2)\n' + start, end = self._convert_line_range_to_offset(code, 4, 4) + refactored = self.do_extract_method(code, start, end, 'new_func') + expected = 'class AClass(object):\n\n' \ + ' def a_func(self):\n' \ + ' self.new_func()\n' \ + ' print(2)\n\n' \ + ' def new_func(self):\n print(1)\n' + self.assertEquals(expected, refactored) + + def test_extract_method_with_args_and_returns(self): + code = 'class AClass(object):\n' \ + ' def a_func(self):\n' \ + ' a_var = 10\n' \ + ' another_var = a_var * 3\n' \ + ' third_var = a_var + another_var\n' + start, end = self._convert_line_range_to_offset(code, 4, 4) + refactored = self.do_extract_method(code, start, end, 'new_func') + expected = 'class AClass(object):\n' \ + ' def a_func(self):\n' \ + ' a_var = 10\n' \ + ' another_var = self.new_func(a_var)\n' \ + ' third_var = a_var + another_var\n\n' \ + ' def new_func(self, a_var):\n' \ + ' another_var = a_var * 3\n' \ + ' return another_var\n' + self.assertEquals(expected, refactored) + + def test_extract_method_with_self_as_argument(self): + code = 'class AClass(object):\n' \ + ' def a_func(self):\n' \ + ' print(self)\n' + start, end = self._convert_line_range_to_offset(code, 3, 3) + refactored = self.do_extract_method(code, start, end, 'new_func') + expected = 'class AClass(object):\n' \ + ' def a_func(self):\n' \ + ' self.new_func()\n\n' \ + ' def new_func(self):\n' \ + ' print(self)\n' + self.assertEquals(expected, refactored) + + @testutils.assert_raises(rope.base.exceptions.RefactoringError) + def test_extract_method_with_no_self_as_argument(self): + code = 'class AClass(object):\n' \ + ' def a_func():\n' \ + ' print(1)\n' + start, end = self._convert_line_range_to_offset(code, 3, 3) + refactored = self.do_extract_method(code, start, end, 'new_func') + + def test_extract_method_with_multiple_methods(self): + code = 'class AClass(object):\n' \ + ' def a_func(self):\n' \ + ' print(self)\n\n' \ + ' def another_func(self):\n' \ + ' pass\n' + start, end = self._convert_line_range_to_offset(code, 3, 3) + refactored = self.do_extract_method(code, start, end, 'new_func') + expected = 'class AClass(object):\n' \ + ' def a_func(self):\n' \ + ' self.new_func()\n\n' \ + ' def new_func(self):\n' \ + ' print(self)\n\n' \ + ' def another_func(self):\n' \ + ' pass\n' + self.assertEquals(expected, refactored) + + def test_extract_function_with_function_returns(self): + code = 'def a_func():\n def inner_func():\n pass\n' \ + ' inner_func()\n' + start, end = self._convert_line_range_to_offset(code, 2, 3) + refactored = self.do_extract_method(code, start, end, 'new_func') + expected = 'def a_func():\n' \ + ' inner_func = new_func()\n inner_func()\n\n' \ + 'def new_func():\n' \ + ' def inner_func():\n pass\n' \ + ' return inner_func\n' + self.assertEquals(expected, refactored) + + def test_simple_extract_global_function(self): + code = "print('one')\nprint('two')\nprint('three')\n" + start, end = self._convert_line_range_to_offset(code, 2, 2) + refactored = self.do_extract_method(code, start, end, 'new_func') + expected = "print('one')\n\ndef new_func():\n print('two')\n" \ + "\nnew_func()\nprint('three')\n" + self.assertEquals(expected, refactored) + + def test_extract_global_function_inside_ifs(self): + code = 'if True:\n a = 10\n' + start, end = self._convert_line_range_to_offset(code, 2, 2) + refactored = self.do_extract_method(code, start, end, 'new_func') + expected = '\ndef new_func():\n a = 10\n\nif True:\n' \ + ' new_func()\n' + self.assertEquals(expected, refactored) + + def test_extract_function_while_inner_function_reads(self): + code = 'def a_func():\n a_var = 10\n' \ + ' def inner_func():\n print(a_var)\n' \ + ' return inner_func\n' + start, end = self._convert_line_range_to_offset(code, 3, 4) + refactored = self.do_extract_method(code, start, end, 'new_func') + expected = 'def a_func():\n a_var = 10\n' \ + ' inner_func = new_func(a_var)\n return inner_func\n\n' \ + 'def new_func(a_var):\n' \ + ' def inner_func():\n print(a_var)\n' \ + ' return inner_func\n' + self.assertEquals(expected, refactored) + + @testutils.assert_raises(rope.base.exceptions.RefactoringError) + def test_extract_method_bad_range(self): + code = "def a_func():\n pass\na_var = 10\n" + start, end = self._convert_line_range_to_offset(code, 2, 3) + self.do_extract_method(code, start, end, 'new_func') + + @testutils.assert_raises(rope.base.exceptions.RefactoringError) + def test_extract_method_bad_range2(self): + code = "class AClass(object):\n pass\n" + start, end = self._convert_line_range_to_offset(code, 1, 1) + self.do_extract_method(code, start, end, 'new_func') + + @testutils.assert_raises(rope.base.exceptions.RefactoringError) + def test_extract_method_containing_return(self): + code = 'def a_func(arg):\n if arg:\n return arg * 2\n return 1' + start, end = self._convert_line_range_to_offset(code, 2, 4) + self.do_extract_method(code, start, end, 'new_func') + + @testutils.assert_raises(rope.base.exceptions.RefactoringError) + def test_extract_method_containing_yield(self): + code = "def a_func(arg):\n yield arg * 2\n" + start, end = self._convert_line_range_to_offset(code, 2, 2) + self.do_extract_method(code, start, end, 'new_func') + + @testutils.assert_raises(rope.base.exceptions.RefactoringError) + def test_extract_method_containing_uncomplete_lines(self): + code = 'a_var = 20\nanother_var = 30\n' + start = code.index('20') + end = code.index('30') + 2 + self.do_extract_method(code, start, end, 'new_func') + + @testutils.assert_raises(rope.base.exceptions.RefactoringError) + def test_extract_method_containing_uncomplete_lines2(self): + code = 'a_var = 20\nanother_var = 30\n' + start = code.index('20') + end = code.index('another') + 5 + self.do_extract_method(code, start, end, 'new_func') + + def test_extract_function_and_argument_as_paramenter(self): + code = 'def a_func(arg):\n print(arg)\n' + start, end = self._convert_line_range_to_offset(code, 2, 2) + refactored = self.do_extract_method(code, start, end, 'new_func') + expected = 'def a_func(arg):\n new_func(arg)\n\n' \ + 'def new_func(arg):\n print(arg)\n' + self.assertEquals(expected, refactored) + + def test_extract_function_and_end_as_the_start_of_a_line(self): + code = 'print("hey")\nif True:\n pass\n' + start = 0 + end = code.index('\n') + 1 + refactored = self.do_extract_method(code, start, end, 'new_func') + expected = '\ndef new_func():\n print("hey")\n\n' \ + 'new_func()\nif True:\n pass\n' + self.assertEquals(expected, refactored) + + def test_extract_function_and_indented_blocks(self): + code = 'def a_func(arg):\n if True:\n' \ + ' if True:\n print(arg)\n' + start, end = self._convert_line_range_to_offset(code, 3, 4) + refactored = self.do_extract_method(code, start, end, 'new_func') + expected = 'def a_func(arg):\n if True:\n new_func(arg)\n\n' \ + 'def new_func(arg):\n if True:\n print(arg)\n' + self.assertEquals(expected, refactored) + + def test_extract_method_and_multi_line_headers(self): + code = 'def a_func(\n arg):\n print(arg)\n' + start, end = self._convert_line_range_to_offset(code, 3, 3) + refactored = self.do_extract_method(code, start, end, 'new_func') + expected = 'def a_func(\n arg):\n new_func(arg)\n\n' \ + 'def new_func(arg):\n print(arg)\n' + self.assertEquals(expected, refactored) + + def test_single_line_extract_function(self): + code = 'a_var = 10 + 20\n' + start = code.index('10') + end = code.index('20') + 2 + refactored = self.do_extract_method(code, start, end, 'new_func') + expected = "\ndef new_func():\n return 10 + 20\n\na_var = new_func()\n" + self.assertEquals(expected, refactored) + + def test_single_line_extract_function2(self): + code = 'def a_func():\n a = 10\n b = a * 20\n' + start = code.rindex('a') + end = code.index('20') + 2 + refactored = self.do_extract_method(code, start, end, 'new_func') + expected = 'def a_func():\n a = 10\n b = new_func(a)\n' \ + '\ndef new_func(a):\n return a * 20\n' + self.assertEquals(expected, refactored) + + def test_single_line_extract_method_and_logical_lines(self): + code = 'a_var = 10 +\\\n 20\n' + start = code.index('10') + end = code.index('20') + 2 + refactored = self.do_extract_method(code, start, end, 'new_func') + expected = '\ndef new_func():\n return 10 + 20\n\na_var = new_func()\n' + self.assertEquals(expected, refactored) + + def test_single_line_extract_method_and_logical_lines2(self): + code = 'a_var = (10,\\\n 20)\n' + start = code.index('10') - 1 + end = code.index('20') + 3 + refactored = self.do_extract_method(code, start, end, 'new_func') + expected = '\ndef new_func():\n' \ + ' return (10, 20)\n\na_var = new_func()\n' + self.assertEquals(expected, refactored) + + def test_single_line_extract_method(self): + code = "class AClass(object):\n\n" \ + " def a_func(self):\n a = 10\n b = a * a\n" + start = code.rindex('=') + 2 + end = code.rindex('a') + 1 + refactored = self.do_extract_method(code, start, end, 'new_func') + expected = 'class AClass(object):\n\n' \ + ' def a_func(self):\n' \ + ' a = 10\n b = self.new_func(a)\n\n' \ + ' def new_func(self, a):\n return a * a\n' + self.assertEquals(expected, refactored) + + def test_single_line_extract_function_if_condition(self): + code = 'if True:\n pass\n' + start = code.index('True') + end = code.index('True') + 4 + refactored = self.do_extract_method(code, start, end, 'new_func') + expected = "\ndef new_func():\n return True\n\nif new_func():\n pass\n" + self.assertEquals(expected, refactored) + + def test_unneeded_params(self): + code = 'class A(object):\n ' \ + 'def a_func(self):\n a_var = 10\n a_var += 2\n' + start = code.rindex('2') + end = code.rindex('2') + 1 + refactored = self.do_extract_method(code, start, end, 'new_func') + expected = 'class A(object):\n' \ + ' def a_func(self):\n a_var = 10\n' \ + ' a_var += self.new_func()\n\n' \ + ' def new_func(self):\n return 2\n' + self.assertEquals(expected, refactored) + + def test_breaks_and_continues_inside_loops(self): + code = 'def a_func():\n for i in range(10):\n continue\n' + start = code.index('for') + end = len(code) - 1 + refactored = self.do_extract_method(code, start, end, 'new_func') + expected = 'def a_func():\n new_func()\n\n' \ + 'def new_func():\n' \ + ' for i in range(10):\n continue\n' + self.assertEquals(expected, refactored) + + @testutils.assert_raises(rope.base.exceptions.RefactoringError) + def test_breaks_and_continues_outside_loops(self): + code = 'def a_func():\n' \ + ' for i in range(10):\n a = i\n continue\n' + start = code.index('a = i') + end = len(code) - 1 + refactored = self.do_extract_method(code, start, end, 'new_func') + + def test_variable_writes_followed_by_variable_reads_after_extraction(self): + code = 'def a_func():\n a = 1\n a = 2\n b = a\n' + start = code.index('a = 1') + end = code.index('a = 2') - 1 + refactored = self.do_extract_method(code, start, end, 'new_func') + expected = 'def a_func():\n new_func()\n a = 2\n b = a\n\n' \ + 'def new_func():\n a = 1\n' + self.assertEquals(expected, refactored) + + def test_variable_writes_followed_by_variable_reads_inside_extraction(self): + code = 'def a_func():\n a = 1\n a = 2\n b = a\n' + start = code.index('a = 2') + end = len(code) - 1 + refactored = self.do_extract_method(code, start, end, 'new_func') + expected = 'def a_func():\n a = 1\n new_func()\n\n' \ + 'def new_func():\n a = 2\n b = a\n' + self.assertEquals(expected, refactored) + + def test_extract_variable(self): + code = 'a_var = 10 + 20\n' + start = code.index('10') + end = code.index('20') + 2 + refactored = self.do_extract_variable(code, start, end, 'new_var') + expected = 'new_var = 10 + 20\na_var = new_var\n' + self.assertEquals(expected, refactored) + + def test_extract_variable_multiple_lines(self): + code = 'a = 1\nb = 2\n' + start = code.index('1') + end = code.index('1') + 1 + refactored = self.do_extract_variable(code, start, end, 'c') + expected = 'c = 1\na = c\nb = 2\n' + self.assertEquals(expected, refactored) + + def test_extract_variable_in_the_middle_of_statements(self): + code = 'a = 1 + 2\n' + start = code.index('1') + end = code.index('1') + 1 + refactored = self.do_extract_variable(code, start, end, 'c') + expected = 'c = 1\na = c + 2\n' + self.assertEquals(expected, refactored) + + def test_extract_variable_for_a_tuple(self): + code = 'a = 1, 2\n' + start = code.index('1') + end = code.index('2') + 1 + refactored = self.do_extract_variable(code, start, end, 'c') + expected = 'c = 1, 2\na = c\n' + self.assertEquals(expected, refactored) + + def test_extract_variable_for_a_string(self): + code = 'def a_func():\n a = "hey!"\n' + start = code.index('"') + end = code.rindex('"') + 1 + refactored = self.do_extract_variable(code, start, end, 'c') + expected = 'def a_func():\n c = "hey!"\n a = c\n' + self.assertEquals(expected, refactored) + + def test_extract_variable_inside_ifs(self): + code = 'if True:\n a = 1 + 2\n' + start = code.index('1') + end = code.rindex('2') + 1 + refactored = self.do_extract_variable(code, start, end, 'b') + expected = 'if True:\n b = 1 + 2\n a = b\n' + self.assertEquals(expected, refactored) + + def test_extract_variable_inside_ifs_and_logical_lines(self): + code = 'if True:\n a = (3 + \n(1 + 2))\n' + start = code.index('1') + end = code.index('2') + 1 + refactored = self.do_extract_variable(code, start, end, 'b') + expected = 'if True:\n b = 1 + 2\n a = (3 + \n(b))\n' + self.assertEquals(expected, refactored) + + # TODO: Handle when extracting a subexpression + def xxx_test_extract_variable_for_a_subexpression(self): + code = 'a = 3 + 1 + 2\n' + start = code.index('1') + end = code.index('2') + 1 + refactored = self.do_extract_variable(code, start, end, 'b') + expected = 'b = 1 + 2\na = 3 + b\n' + self.assertEquals(expected, refactored) + + def test_extract_variable_starting_from_the_start_of_the_line(self): + code = 'a_dict = {1: 1}\na_dict.values().count(1)\n' + start = code.rindex('a_dict') + end = code.index('count') - 1 + refactored = self.do_extract_variable(code, start, end, 'values') + expected = 'a_dict = {1: 1}\nvalues = a_dict.values()\nvalues.count(1)\n' + self.assertEquals(expected, refactored) + + def test_extract_variable_on_the_last_line_of_a_function(self): + code = 'def f():\n a_var = {}\n a_var.keys()\n' + start = code.rindex('a_var') + end = code.index('.keys') + refactored = self.do_extract_variable(code, start, end, 'new_var') + expected = 'def f():\n a_var = {}\n new_var = a_var\n new_var.keys()\n' + self.assertEquals(expected, refactored) + + def test_extract_variable_on_the_indented_function_statement(self): + code = 'def f():\n if True:\n a_var = 1 + 2\n' + start = code.index('1') + end = code.index('2') + 1 + refactored = self.do_extract_variable(code, start, end, 'new_var') + expected = 'def f():\n if True:\n' \ + ' new_var = 1 + 2\n a_var = new_var\n' + self.assertEquals(expected, refactored) + + def test_extract_method_on_the_last_line_of_a_function(self): + code = 'def f():\n a_var = {}\n a_var.keys()\n' + start = code.rindex('a_var') + end = code.index('.keys') + refactored = self.do_extract_method(code, start, end, 'new_f') + expected = 'def f():\n a_var = {}\n new_f(a_var).keys()\n\n' \ + 'def new_f(a_var):\n return a_var\n' + self.assertEquals(expected, refactored) + + @testutils.assert_raises(rope.base.exceptions.RefactoringError) + def test_raising_exception_when_on_incomplete_variables(self): + code = 'a_var = 10 + 20\n' + start = code.index('10') + 1 + end = code.index('20') + 2 + refactored = self.do_extract_method(code, start, end, 'new_func') + + @testutils.assert_raises(rope.base.exceptions.RefactoringError) + def test_raising_exception_when_on_incomplete_variables_on_end(self): + code = 'a_var = 10 + 20\n' + start = code.index('10') + end = code.index('20') + 1 + refactored = self.do_extract_method(code, start, end, 'new_func') + + @testutils.assert_raises(rope.base.exceptions.RefactoringError) + def test_raising_exception_on_bad_parens(self): + code = 'a_var = (10 + 20) + 30\n' + start = code.index('20') + end = code.index('30') + 2 + refactored = self.do_extract_method(code, start, end, 'new_func') + + @testutils.assert_raises(rope.base.exceptions.RefactoringError) + def test_raising_exception_on_bad_operators(self): + code = 'a_var = 10 + 20 + 30\n' + start = code.index('10') + end = code.rindex('+') + 1 + refactored = self.do_extract_method(code, start, end, 'new_func') + + # FIXME: Extract method should be more intelligent about bad ranges + @testutils.assert_raises(rope.base.exceptions.RefactoringError) + def xxx_test_raising_exception_on_function_parens(self): + code = 'a = range(10)' + start = code.index('(') + end = code.rindex(')') + 1 + refactored = self.do_extract_method(code, start, end, 'new_func') + + def test_extract_method_and_extra_blank_lines(self): + code = '\nprint(1)\n' + refactored = self.do_extract_method(code, 0, len(code), 'new_f') + expected = '\n\ndef new_f():\n print(1)\n\nnew_f()\n' + self.assertEquals(expected, refactored) + + def test_variable_writes_in_the_same_line_as_variable_read(self): + code = 'a = 1\na = 1 + a\n' + start = code.index('\n') + 1 + end = len(code) + refactored = self.do_extract_method(code, start, end, 'new_f', + global_=True) + expected = 'a = 1\n\ndef new_f(a):\n a = 1 + a\n\nnew_f(a)\n' + self.assertEquals(expected, refactored) + + def test_variable_writes_in_the_same_line_as_variable_read2(self): + code = 'a = 1\na += 1\n' + start = code.index('\n') + 1 + end = len(code) + refactored = self.do_extract_method(code, start, end, 'new_f', + global_=True) + expected = 'a = 1\n\ndef new_f():\n a += 1\n\nnew_f()\n' + self.assertEquals(expected, refactored) + + def test_variable_and_similar_expressions(self): + code = 'a = 1\nb = 1\n' + start = code.index('1') + end = start + 1 + refactored = self.do_extract_variable(code, start, end, + 'one', similar=True) + expected = 'one = 1\na = one\nb = one\n' + self.assertEquals(expected, refactored) + + def test_definition_should_appear_before_the_first_use(self): + code = 'a = 1\nb = 1\n' + start = code.rindex('1') + end = start + 1 + refactored = self.do_extract_variable(code, start, end, + 'one', similar=True) + expected = 'one = 1\na = one\nb = one\n' + self.assertEquals(expected, refactored) + + def test_extract_method_and_similar_expressions(self): + code = 'a = 1\nb = 1\n' + start = code.index('1') + end = start + 1 + refactored = self.do_extract_method(code, start, end, + 'one', similar=True) + expected = '\ndef one():\n return 1\n\na = one()\nb = one()\n' + self.assertEquals(expected, refactored) + + def test_simple_extract_method_and_similar_statements(self): + code = 'class AClass(object):\n\n' \ + ' def func1(self):\n a = 1 + 2\n b = a\n' \ + ' def func2(self):\n a = 1 + 2\n b = a\n' + start, end = self._convert_line_range_to_offset(code, 4, 4) + refactored = self.do_extract_method(code, start, end, + 'new_func', similar=True) + expected = 'class AClass(object):\n\n' \ + ' def func1(self):\n' \ + ' a = self.new_func()\n b = a\n\n' \ + ' def new_func(self):\n' \ + ' a = 1 + 2\n return a\n' \ + ' def func2(self):\n' \ + ' a = self.new_func()\n b = a\n' + self.assertEquals(expected, refactored) + + def test_extract_method_and_similar_statements2(self): + code = 'class AClass(object):\n\n' \ + ' def func1(self, p1):\n a = p1 + 2\n' \ + ' def func2(self, p2):\n a = p2 + 2\n' + start = code.rindex('p1') + end = code.index('2\n') + 1 + refactored = self.do_extract_method(code, start, end, + 'new_func', similar=True) + expected = 'class AClass(object):\n\n' \ + ' def func1(self, p1):\n a = self.new_func(p1)\n\n' \ + ' def new_func(self, p1):\n return p1 + 2\n' \ + ' def func2(self, p2):\n a = self.new_func(p2)\n' + self.assertEquals(expected, refactored) + + def test_extract_method_and_similar_statements_where_return_is_different(self): + code = 'class AClass(object):\n\n' \ + ' def func1(self, p1):\n a = p1 + 2\n' \ + ' def func2(self, p2):\n self.attr = p2 + 2\n' + start = code.rindex('p1') + end = code.index('2\n') + 1 + refactored = self.do_extract_method(code, start, end, + 'new_func', similar=True) + expected = 'class AClass(object):\n\n' \ + ' def func1(self, p1):\n a = self.new_func(p1)\n\n' \ + ' def new_func(self, p1):\n return p1 + 2\n' \ + ' def func2(self, p2):\n self.attr = self.new_func(p2)\n' + self.assertEquals(expected, refactored) + + def test_definition_should_appear_where_it_is_visible(self): + code = 'if True:\n a = 1\nelse:\n b = 1\n' + start = code.rindex('1') + end = start + 1 + refactored = self.do_extract_variable(code, start, end, + 'one', similar=True) + expected = 'one = 1\nif True:\n a = one\nelse:\n b = one\n' + self.assertEquals(expected, refactored) + + def test_extract_variable_and_similar_statements_in_classes(self): + code = 'class AClass(object):\n\n' \ + ' def func1(self):\n a = 1\n' \ + ' def func2(self):\n b = 1\n' + start = code.index(' 1') + 1 + refactored = self.do_extract_variable(code, start, start + 1, + 'one', similar=True) + expected = 'class AClass(object):\n\n' \ + ' def func1(self):\n one = 1\n a = one\n' \ + ' def func2(self):\n b = 1\n' + self.assertEquals(expected, refactored) + + def test_extract_method_in_staticmethods(self): + code = 'class AClass(object):\n\n' \ + ' @staticmethod\n def func2():\n b = 1\n' + start = code.index(' 1') + 1 + refactored = self.do_extract_method(code, start, start + 1, + 'one', similar=True) + expected = 'class AClass(object):\n\n' \ + ' @staticmethod\n def func2():\n' \ + ' b = AClass.one()\n\n' \ + ' @staticmethod\n def one():\n' \ + ' return 1\n' + self.assertEquals(expected, refactored) + + def test_extract_normal_method_with_staticmethods(self): + code = 'class AClass(object):\n\n' \ + ' @staticmethod\n def func1():\n b = 1\n' \ + ' def func2(self):\n b = 1\n' + start = code.rindex(' 1') + 1 + refactored = self.do_extract_method(code, start, start + 1, + 'one', similar=True) + expected = 'class AClass(object):\n\n' \ + ' @staticmethod\n def func1():\n b = 1\n' \ + ' def func2(self):\n b = self.one()\n\n' \ + ' def one(self):\n return 1\n' + self.assertEquals(expected, refactored) + + def test_extract_variable_with_no_new_lines_at_the_end(self): + code = 'a_var = 10' + start = code.index('10') + end = start + 2 + refactored = self.do_extract_variable(code, start, end, 'new_var') + expected = 'new_var = 10\na_var = new_var' + self.assertEquals(expected, refactored) + + def test_extract_method_containing_return_in_functions(self): + code = 'def f(arg):\n return arg\nprint(f(1))\n' + start, end = self._convert_line_range_to_offset(code, 1, 3) + refactored = self.do_extract_method(code, start, end, 'a_func') + expected = '\ndef a_func():\n def f(arg):\n return arg\n' \ + ' print(f(1))\n\na_func()\n' + self.assertEquals(expected, refactored) + + def test_extract_method_and_varying_first_parameter(self): + code = 'class C(object):\n' \ + ' def f1(self):\n print(str(self))\n' \ + ' def f2(self):\n print(str(1))\n' + start = code.index('print(') + 6 + end = code.index('))\n') + 1 + refactored = self.do_extract_method(code, start, end, + 'to_str', similar=True) + expected = 'class C(object):\n' \ + ' def f1(self):\n print(self.to_str())\n\n' \ + ' def to_str(self):\n return str(self)\n' \ + ' def f2(self):\n print(str(1))\n' + self.assertEquals(expected, refactored) + + def test_extract_method_when_an_attribute_exists_in_function_scope(self): + code = 'class A(object):\n def func(self):\n pass\n' \ + 'a = A()\n' \ + 'def f():\n' \ + ' func = a.func()\n' \ + ' print func\n' + + start, end = self._convert_line_range_to_offset(code, 6, 6) + refactored = self.do_extract_method(code, start, end, 'g') + refactored = refactored[refactored.index('A()') + 4:] + expected = 'def f():\n func = g()\n print func\n\n' \ + 'def g():\n func = a.func()\n return func\n' + self.assertEquals(expected, refactored) + + def test_global_option_for_extract_method(self): + code = 'def a_func():\n print(1)\n' + start, end = self._convert_line_range_to_offset(code, 2, 2) + refactored = self.do_extract_method(code, start, end, + 'extracted', global_=True) + expected = 'def a_func():\n extracted()\n\n' \ + 'def extracted():\n print(1)\n' + self.assertEquals(expected, refactored) + + def test_global_extract_method(self): + code = 'class AClass(object):\n\n' \ + ' def a_func(self):\n print(1)\n' + start, end = self._convert_line_range_to_offset(code, 4, 4) + refactored = self.do_extract_method(code, start, end, + 'new_func', global_=True) + expected = 'class AClass(object):\n\n' \ + ' def a_func(self):\n new_func()\n\n' \ + 'def new_func():\n print(1)\n' + self.assertEquals(expected, refactored) + + def test_extract_method_with_multiple_methods(self): + code = 'class AClass(object):\n' \ + ' def a_func(self):\n' \ + ' print(1)\n\n' \ + ' def another_func(self):\n' \ + ' pass\n' + start, end = self._convert_line_range_to_offset(code, 3, 3) + refactored = self.do_extract_method(code, start, end, + 'new_func', global_=True) + expected = 'class AClass(object):\n' \ + ' def a_func(self):\n' \ + ' new_func()\n\n' \ + ' def another_func(self):\n' \ + ' pass\n\n' \ + 'def new_func():\n' \ + ' print(1)\n' + self.assertEquals(expected, refactored) + + def test_where_to_seach_when_extracting_global_names(self): + code = 'def a():\n return 1\ndef b():\n return 1\nb = 1\n' + start = code.index('1') + end = start + 1 + refactored = self.do_extract_variable(code, start, end, 'one', + similar=True, global_=True) + expected = 'def a():\n return one\none = 1\n' \ + 'def b():\n return one\nb = one\n' + self.assertEquals(expected, refactored) + + def test_extracting_pieces_with_distinct_temp_names(self): + code = 'a = 1\nprint a\nb = 1\nprint b\n' + start = code.index('a') + end = code.index('\nb') + refactored = self.do_extract_method(code, start, end, 'f', + similar=True, global_=True) + expected = '\ndef f():\n a = 1\n print a\n\nf()\nf()\n' + self.assertEquals(expected, refactored) + + def test_extracting_methods_in_global_functions_should_be_global(self): + code = 'def f():\n a = 1\ndef g():\n b = 1\n' + start = code.rindex('1') + refactored = self.do_extract_method(code, start, start + 1, 'one', + similar=True, global_=False) + expected = 'def f():\n a = one()\ndef g():\n b = one()\n\n' \ + 'def one():\n return 1\n' + self.assertEquals(expected, refactored) + + def test_extracting_methods_in_global_functions_should_be_global(self): + code = 'if 1:\n var = 2\n' + start = code.rindex('2') + refactored = self.do_extract_method(code, start, start + 1, 'two', + similar=True, global_=False) + expected = '\ndef two():\n return 2\n\nif 1:\n var = two()\n' + self.assertEquals(expected, refactored) + + def test_extract_method_and_try_blocks(self): + code = 'def f():\n try:\n pass\n' \ + ' except Exception:\n pass\n' + start, end = self._convert_line_range_to_offset(code, 2, 5) + refactored = self.do_extract_method(code, start, end, 'g') + expected = 'def f():\n g()\n\ndef g():\n try:\n pass\n' \ + ' except Exception:\n pass\n' + self.assertEquals(expected, refactored) + + def test_extract_and_not_passing_global_functions(self): + code = 'def next(p):\n return p + 1\nvar = next(1)\n' + start = code.rindex('next') + refactored = self.do_extract_method(code, start, len(code) - 1, 'two') + expected = 'def next(p):\n return p + 1\n' \ + '\ndef two():\n return next(1)\n\nvar = two()\n' + self.assertEquals(expected, refactored) + + def test_extracting_with_only_one_return(self): + code = 'def f():\n var = 1\n return var\n' + start, end = self._convert_line_range_to_offset(code, 2, 3) + refactored = self.do_extract_method(code, start, end, 'g') + expected = 'def f():\n return g()\n\n' \ + 'def g():\n var = 1\n return var\n' + self.assertEquals(expected, refactored) + + def test_extracting_variable_and_implicit_continuations(self): + code = 's = ("1"\n "2")\n' + start = code.index('"') + end = code.rindex('"') + 1 + refactored = self.do_extract_variable(code, start, end, 's2') + expected = 's2 = "1" "2"\ns = (s2)\n' + self.assertEquals(expected, refactored) + + def test_extracting_method_and_implicit_continuations(self): + code = 's = ("1"\n "2")\n' + start = code.index('"') + end = code.rindex('"') + 1 + refactored = self.do_extract_method(code, start, end, 'f') + expected = '\ndef f():\n return "1" "2"\n\ns = (f())\n' + self.assertEquals(expected, refactored) + + def test_passing_conditional_updated_vars_in_extracted(self): + code = 'def f(a):\n' \ + ' if 0:\n' \ + ' a = 1\n' \ + ' print(a)\n' + start, end = self._convert_line_range_to_offset(code, 2, 4) + refactored = self.do_extract_method(code, start, end, 'g') + expected = 'def f(a):\n' \ + ' g(a)\n\n' \ + 'def g(a):\n' \ + ' if 0:\n' \ + ' a = 1\n' \ + ' print(a)\n' + self.assertEquals(expected, refactored) + + def test_returning_conditional_updated_vars_in_extracted(self): + code = 'def f(a):\n' \ + ' if 0:\n' \ + ' a = 1\n' \ + ' print(a)\n' + start, end = self._convert_line_range_to_offset(code, 2, 3) + refactored = self.do_extract_method(code, start, end, 'g') + expected = 'def f(a):\n' \ + ' a = g(a)\n' \ + ' print(a)\n\n' \ + 'def g(a):\n' \ + ' if 0:\n' \ + ' a = 1\n' \ + ' return a\n' + self.assertEquals(expected, refactored) + + def test_extract_method_with_variables_possibly_written_to(self): + code = "def a_func(b):\n" \ + " if b > 0:\n" \ + " a = 2\n" \ + " print a\n" + start, end = self._convert_line_range_to_offset(code, 2, 3) + refactored = self.do_extract_method(code, start, end, 'extracted') + expected = "def a_func(b):\n" \ + " a = extracted(b)\n" \ + " print a\n\n" \ + "def extracted(b):\n" \ + " if b > 0:\n" \ + " a = 2\n" \ + " return a\n" + self.assertEquals(expected, refactored) + +if __name__ == '__main__': + unittest.main() diff -r e30544496575 -r 48cacfdc2ca6 vim/sadness/ropevim/src/rope/ropetest/refactor/importutilstest.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vim/sadness/ropevim/src/rope/ropetest/refactor/importutilstest.py Wed Oct 06 12:30:46 2010 -0400 @@ -0,0 +1,990 @@ +import unittest + +from rope.refactor.importutils import ImportTools, importinfo, add_import +from ropetest import testutils + + +class ImportUtilsTest(unittest.TestCase): + + def setUp(self): + super(ImportUtilsTest, self).setUp() + self.project = testutils.sample_project() + self.pycore = self.project.pycore + self.import_tools = ImportTools(self.pycore) + + self.mod = testutils.create_module(self.project, 'mod') + self.pkg1 = testutils.create_package(self.project, 'pkg1') + self.mod1 = testutils.create_module(self.project, 'mod1', self.pkg1) + self.pkg2 = testutils.create_package(self.project, 'pkg2') + self.mod2 = testutils.create_module(self.project, 'mod2', self.pkg2) + self.mod3 = testutils.create_module(self.project, 'mod3', self.pkg2) + p1 = testutils.create_package(self.project, 'p1') + p2 = testutils.create_package(self.project, 'p2', p1) + p3 = testutils.create_package(self.project, 'p3', p2) + m1 = testutils.create_module(self.project, 'm1', p3) + l = testutils.create_module(self.project, 'l', p3) + + def tearDown(self): + testutils.remove_project(self.project) + super(ImportUtilsTest, self).tearDown() + + def test_get_import_for_module(self): + mod = self.pycore.find_module('mod') + import_statement = self.import_tools.get_import(mod) + self.assertEquals('import mod', import_statement.get_import_statement()) + + def test_get_import_for_module_in_nested_modules(self): + mod = self.pycore.find_module('pkg1.mod1') + import_statement = self.import_tools.get_import(mod) + self.assertEquals('import pkg1.mod1', import_statement.get_import_statement()) + + def test_get_import_for_module_in_init_dot_py(self): + init_dot_py = self.pkg1.get_child('__init__.py') + import_statement = self.import_tools.get_import(init_dot_py) + self.assertEquals('import pkg1', import_statement.get_import_statement()) + + + def test_get_from_import_for_module(self): + mod = self.pycore.find_module('mod') + import_statement = self.import_tools.get_from_import(mod, 'a_func') + self.assertEquals('from mod import a_func', + import_statement.get_import_statement()) + + def test_get_from_import_for_module_in_nested_modules(self): + mod = self.pycore.find_module('pkg1.mod1') + import_statement = self.import_tools.get_from_import(mod, 'a_func') + self.assertEquals('from pkg1.mod1 import a_func', + import_statement.get_import_statement()) + + def test_get_from_import_for_module_in_init_dot_py(self): + init_dot_py = self.pkg1.get_child('__init__.py') + import_statement = self.import_tools.\ + get_from_import(init_dot_py, 'a_func') + self.assertEquals('from pkg1 import a_func', + import_statement.get_import_statement()) + + + def test_get_import_statements(self): + self.mod.write('import pkg1\n') + pymod = self.pycore.get_module('mod') + module_with_imports = self.import_tools.module_imports(pymod) + imports = module_with_imports.imports + self.assertEquals('import pkg1', + imports[0].import_info.get_import_statement()) + + def test_get_import_statements_with_alias(self): + self.mod.write('import pkg1.mod1 as mod1\n') + pymod = self.pycore.get_module('mod') + module_with_imports = self.import_tools.module_imports(pymod) + imports = module_with_imports.imports + self.assertEquals('import pkg1.mod1 as mod1', + imports[0].import_info.get_import_statement()) + + def test_get_import_statements_for_froms(self): + self.mod.write('from pkg1 import mod1\n') + pymod = self.pycore.get_module('mod') + module_with_imports = self.import_tools.module_imports(pymod) + imports = module_with_imports.imports + self.assertEquals('from pkg1 import mod1', + imports[0].import_info.get_import_statement()) + + def test_get_multi_line_import_statements_for_froms(self): + self.mod.write('from pkg1 \\\n import mod1\n') + pymod = self.pycore.get_module('mod') + module_with_imports = self.import_tools.module_imports(pymod) + imports = module_with_imports.imports + self.assertEquals('from pkg1 import mod1', + imports[0].import_info.get_import_statement()) + + def test_get_import_statements_for_from_star(self): + self.mod.write('from pkg1 import *\n') + pymod = self.pycore.get_module('mod') + module_with_imports = self.import_tools.module_imports(pymod) + imports = module_with_imports.imports + self.assertEquals('from pkg1 import *', + imports[0].import_info.get_import_statement()) + + @testutils.run_only_for_25 + def test_get_import_statements_for_new_relatives(self): + self.mod2.write('from .mod3 import x\n') + pymod = self.pycore.get_module('pkg2.mod2') + module_with_imports = self.import_tools.module_imports(pymod) + imports = module_with_imports.imports + self.assertEquals('from .mod3 import x', + imports[0].import_info.get_import_statement()) + + def test_ignoring_indented_imports(self): + self.mod.write('if True:\n import pkg1\n') + pymod = self.pycore.get_module('mod') + module_with_imports = self.import_tools.module_imports(pymod) + imports = module_with_imports.imports + self.assertEquals(0, len(imports)) + + def test_import_get_names(self): + self.mod.write('import pkg1 as pkg\n') + pymod = self.pycore.get_module('mod') + module_with_imports = self.import_tools.module_imports(pymod) + imports = module_with_imports.imports + context = importinfo.ImportContext(self.pycore, self.project.root) + self.assertEquals(['pkg'], + imports[0].import_info.get_imported_names(context)) + + def test_import_get_names_with_alias(self): + self.mod.write('import pkg1.mod1\n') + pymod = self.pycore.get_module('mod') + module_with_imports = self.import_tools.module_imports(pymod) + imports = module_with_imports.imports + context = importinfo.ImportContext(self.pycore, self.project.root) + self.assertEquals(['pkg1'], + imports[0].import_info.get_imported_names(context)) + + def test_import_get_names_with_alias2(self): + self.mod1.write('def a_func():\n pass\n') + self.mod.write('from pkg1.mod1 import *\n') + pymod = self.pycore.get_module('mod') + module_with_imports = self.import_tools.module_imports(pymod) + imports = module_with_imports.imports + context = importinfo.ImportContext(self.pycore, self.project.root) + self.assertEquals(['a_func'], + imports[0].import_info.get_imported_names(context)) + + def test_empty_getting_used_imports(self): + self.mod.write('') + pymod = self.pycore.get_module('mod') + module_with_imports = self.import_tools.module_imports(pymod) + imports = module_with_imports.get_used_imports(pymod) + self.assertEquals(0, len(imports)) + + def test_empty_getting_used_imports2(self): + self.mod.write('import pkg\n') + pymod = self.pycore.get_module('mod') + module_with_imports = self.import_tools.module_imports(pymod) + imports = module_with_imports.get_used_imports(pymod) + self.assertEquals(0, len(imports)) + + def test_simple_getting_used_imports(self): + self.mod.write('import pkg\nprint(pkg)\n') + pymod = self.pycore.get_module('mod') + module_with_imports = self.import_tools.module_imports(pymod) + imports = module_with_imports.get_used_imports(pymod) + self.assertEquals(1, len(imports)) + self.assertEquals('import pkg', imports[0].get_import_statement()) + + def test_simple_getting_used_imports2(self): + self.mod.write('import pkg\ndef a_func():\n print(pkg)\n') + pymod = self.pycore.get_module('mod') + module_with_imports = self.import_tools.module_imports(pymod) + imports = module_with_imports.get_used_imports(pymod) + self.assertEquals(1, len(imports)) + self.assertEquals('import pkg', imports[0].get_import_statement()) + + def test_getting_used_imports_for_nested_scopes(self): + self.mod.write('import pkg1\nprint(pkg1)\ndef a_func():\n pass\nprint(pkg1)\n') + pymod = self.pycore.get_module('mod') + module_with_imports = self.import_tools.module_imports(pymod) + imports = module_with_imports.get_used_imports( + pymod['a_func'].get_object()) + self.assertEquals(0, len(imports)) + + def test_getting_used_imports_for_nested_scopes2(self): + self.mod.write('from pkg1 import mod1\ndef a_func():\n print(mod1)\n') + pymod = self.pycore.get_module('mod') + module_with_imports = self.import_tools.module_imports(pymod) + imports = module_with_imports.get_used_imports( + pymod['a_func'].get_object()) + self.assertEquals(1, len(imports)) + self.assertEquals('from pkg1 import mod1', imports[0].get_import_statement()) + + def test_empty_removing_unused_imports(self): + self.mod.write('import pkg1\nprint(pkg1)\n') + pymod = self.pycore.get_module('mod') + module_with_imports = self.import_tools.module_imports(pymod) + module_with_imports.remove_unused_imports() + self.assertEquals('import pkg1\nprint(pkg1)\n', + module_with_imports.get_changed_source()) + + def test_simple_removing_unused_imports(self): + self.mod.write('import pkg1\n\n') + pymod = self.pycore.get_module('mod') + module_with_imports = self.import_tools.module_imports(pymod) + module_with_imports.remove_unused_imports() + self.assertEquals('', module_with_imports.get_changed_source()) + + def test_simple_removing_unused_imports_for_froms(self): + self.mod1.write('def a_func():\n pass\ndef another_func():\n pass\n') + self.mod.write('from pkg1.mod1 import a_func, another_func\n\na_func()\n') + pymod = self.pycore.get_module('mod') + module_with_imports = self.import_tools.module_imports(pymod) + module_with_imports.remove_unused_imports() + self.assertEquals('from pkg1.mod1 import a_func\n\na_func()\n', + module_with_imports.get_changed_source()) + + def test_simple_removing_unused_imports_for_from_stars(self): + self.mod.write('from pkg1.mod1 import *\n\n') + pymod = self.pycore.get_module('mod') + module_with_imports = self.import_tools.module_imports(pymod) + module_with_imports.remove_unused_imports() + self.assertEquals('', module_with_imports.get_changed_source()) + + def test_simple_removing_unused_imports_for_nested_modules(self): + self.mod1.write('def a_func():\n pass\n') + self.mod.write('import pkg1.mod1\npkg1.mod1.a_func()') + pymod = self.pycore.get_module('mod') + module_with_imports = self.import_tools.module_imports(pymod) + module_with_imports.remove_unused_imports() + self.assertEquals('import pkg1.mod1\npkg1.mod1.a_func()', + module_with_imports.get_changed_source()) + + def test_removing_unused_imports_and_functions_of_the_same_name(self): + self.mod.write('def a_func():\n pass\ndef a_func():\n pass\n') + pymod = self.pycore.get_module('mod') + module_with_imports = self.import_tools.module_imports(pymod) + module_with_imports.remove_unused_imports() + self.assertEquals('def a_func():\n pass\ndef a_func():\n pass\n', + module_with_imports.get_changed_source()) + + def test_removing_unused_imports_for_from_import_with_as(self): + self.mod.write('a_var = 1\n') + self.mod1.write('from mod import a_var as myvar\na_var = myvar\n') + pymod = self.pycore.resource_to_pyobject(self.mod1) + module_with_imports = self.import_tools.module_imports(pymod) + module_with_imports.remove_unused_imports() + self.assertEquals('from mod import a_var as myvar\na_var = myvar\n', + module_with_imports.get_changed_source()) + + def test_not_removing_imports_that_conflict_with_class_names(self): + code = 'import pkg1\nclass A(object):\n pkg1 = 0\n' \ + ' def f(self):\n a_var = pkg1\n' + self.mod.write(code) + pymod = self.pycore.get_module('mod') + module_with_imports = self.import_tools.module_imports(pymod) + module_with_imports.remove_unused_imports() + self.assertEquals(code, module_with_imports.get_changed_source()) + + def test_adding_imports(self): + self.mod.write('\n') + pymod = self.pycore.get_module('mod') + module_with_imports = self.import_tools.module_imports(pymod) + new_import = self.import_tools.get_import(self.mod1) + module_with_imports.add_import(new_import) + self.assertEquals('import pkg1.mod1\n', + module_with_imports.get_changed_source()) + + def test_adding_from_imports(self): + self.mod1.write('def a_func():\n pass\ndef another_func():\n pass\n') + self.mod.write('from pkg1.mod1 import a_func\n') + pymod = self.pycore.get_module('mod') + module_with_imports = self.import_tools.module_imports(pymod) + new_import = self.import_tools.get_from_import( + self.mod1, 'another_func') + module_with_imports.add_import(new_import) + self.assertEquals('from pkg1.mod1 import a_func, another_func\n', + module_with_imports.get_changed_source()) + + def test_adding_to_star_imports(self): + self.mod1.write('def a_func():\n pass\ndef another_func():\n pass\n') + self.mod.write('from pkg1.mod1 import *\n') + pymod = self.pycore.get_module('mod') + module_with_imports = self.import_tools.module_imports(pymod) + new_import = self.import_tools.get_from_import( + self.mod1, 'another_func') + module_with_imports.add_import(new_import) + self.assertEquals('from pkg1.mod1 import *\n', + module_with_imports.get_changed_source()) + + def test_adding_star_imports(self): + self.mod1.write('def a_func():\n pass\ndef another_func():\n pass\n') + self.mod.write('from pkg1.mod1 import a_func\n') + pymod = self.pycore.get_module('mod') + module_with_imports = self.import_tools.module_imports(pymod) + new_import = self.import_tools.get_from_import(self.mod1, + '*') + module_with_imports.add_import(new_import) + self.assertEquals('from pkg1.mod1 import *\n', + module_with_imports.get_changed_source()) + + def test_adding_imports_and_preserving_spaces_after_imports(self): + self.mod.write('import pkg1\n\n\nprint(pkg1)\n') + pymod = self.pycore.get_module('mod') + module_with_imports = self.import_tools.module_imports(pymod) + new_import = self.import_tools.get_import(self.pkg2) + module_with_imports.add_import(new_import) + self.assertEquals('import pkg1\nimport pkg2\n\n\nprint(pkg1)\n', + module_with_imports.get_changed_source()) + + def test_not_changing_the_format_of_unchanged_imports(self): + self.mod1.write('def a_func():\n pass\ndef another_func():\n pass\n') + self.mod.write('from pkg1.mod1 import (a_func,\n another_func)\n') + pymod = self.pycore.get_module('mod') + module_with_imports = self.import_tools.module_imports(pymod) + self.assertEquals( + 'from pkg1.mod1 import (a_func,\n another_func)\n', + module_with_imports.get_changed_source()) + + def test_not_changing_the_format_of_unchanged_imports2(self): + self.mod1.write('def a_func():\n pass\ndef another_func():\n pass\n') + self.mod.write('from pkg1.mod1 import (a_func)\na_func()\n') + pymod = self.pycore.get_module('mod') + module_with_imports = self.import_tools.module_imports(pymod) + module_with_imports.remove_unused_imports() + self.assertEquals('from pkg1.mod1 import (a_func)\na_func()\n', + module_with_imports.get_changed_source()) + + def test_removing_unused_imports_and_reoccuring_names(self): + self.mod1.write('def a_func():\n pass\n' + 'def another_func():\n pass\n') + self.mod.write('from pkg1.mod1 import *\n' + 'from pkg1.mod1 import a_func\na_func()\n') + pymod = self.pycore.get_module('mod') + module_with_imports = self.import_tools.module_imports(pymod) + module_with_imports.remove_unused_imports() + self.assertEquals('from pkg1.mod1 import *\na_func()\n', + module_with_imports.get_changed_source()) + + def test_removing_unused_imports_and_reoccuring_names2(self): + self.mod.write('import pkg2.mod2\nimport pkg2.mod3\n' + 'print(pkg2.mod2, pkg2.mod3)') + pymod = self.pycore.get_module('mod') + module_with_imports = self.import_tools.module_imports(pymod) + module_with_imports.remove_unused_imports() + self.assertEquals( + 'import pkg2.mod2\nimport pkg2.mod3\nprint(pkg2.mod2, pkg2.mod3)', + module_with_imports.get_changed_source()) + + def test_removing_unused_imports_and_common_packages(self): + self.mod.write('import pkg1.mod1\nimport pkg1\nprint(pkg1, pkg1.mod1)\n') + pymod = self.pycore.get_module('mod') + module_with_imports = self.import_tools.module_imports(pymod) + module_with_imports.remove_unused_imports() + self.assertEquals('import pkg1.mod1\nprint(pkg1, pkg1.mod1)\n', + module_with_imports.get_changed_source()) + + def test_removing_unused_imports_and_common_packages_reversed(self): + self.mod.write('import pkg1\nimport pkg1.mod1\nprint(pkg1, pkg1.mod1)\n') + pymod = self.pycore.get_module('mod') + module_with_imports = self.import_tools.module_imports(pymod) + module_with_imports.remove_duplicates() + self.assertEquals('import pkg1.mod1\nprint(pkg1, pkg1.mod1)\n', + module_with_imports.get_changed_source()) + + def test_removing_unused_imports_and_common_packages2(self): + self.mod.write('import pkg1.mod1\nimport pkg1.mod2\nprint(pkg1)\n') + pymod = self.pycore.get_module('mod') + module_with_imports = self.import_tools.module_imports(pymod) + module_with_imports.remove_unused_imports() + self.assertEquals('import pkg1.mod1\nprint(pkg1)\n', + module_with_imports.get_changed_source()) + + def test_removing_unused_imports_and_froms(self): + self.mod1.write('def func1():\n pass\n') + self.mod.write('from pkg1.mod1 import func1\n') + pymod = self.pycore.get_module('mod') + module_with_imports = self.import_tools.module_imports(pymod) + module_with_imports.remove_unused_imports() + self.assertEquals('', module_with_imports.get_changed_source()) + + def test_removing_unused_imports_and_froms2(self): + self.mod1.write('def func1():\n pass\n') + self.mod.write('from pkg1.mod1 import func1\nfunc1()') + pymod = self.pycore.get_module('mod') + module_with_imports = self.import_tools.module_imports(pymod) + module_with_imports.remove_unused_imports() + self.assertEquals('from pkg1.mod1 import func1\nfunc1()', + module_with_imports.get_changed_source()) + + def test_removing_unused_imports_and_froms3(self): + self.mod1.write('def func1():\n pass\n') + self.mod.write('from pkg1.mod1 import func1\n' + 'def a_func():\n func1()\n') + pymod = self.pycore.get_module('mod') + module_with_imports = self.import_tools.module_imports(pymod) + module_with_imports.remove_unused_imports() + self.assertEquals( + 'from pkg1.mod1 import func1\ndef a_func():\n func1()\n', + module_with_imports.get_changed_source()) + + def test_removing_unused_imports_and_froms4(self): + self.mod1.write('def func1():\n pass\n') + self.mod.write('from pkg1.mod1 import func1\nclass A(object):\n' + ' def a_func(self):\n func1()\n') + pymod = self.pycore.get_module('mod') + module_with_imports = self.import_tools.module_imports(pymod) + module_with_imports.remove_unused_imports() + self.assertEquals('from pkg1.mod1 import func1\nclass A(object):\n' + ' def a_func(self):\n func1()\n', + module_with_imports.get_changed_source()) + + def test_removing_unused_imports_and_getting_attributes(self): + self.mod1.write('class A(object):\n def f(self):\n pass\n') + self.mod.write('from pkg1.mod1 import A\nvar = A().f()') + pymod = self.pycore.get_module('mod') + module_with_imports = self.import_tools.module_imports(pymod) + module_with_imports.remove_unused_imports() + self.assertEquals('from pkg1.mod1 import A\nvar = A().f()', + module_with_imports.get_changed_source()) + + def test_removing_unused_imports_function_parameters(self): + self.mod1.write('def func1():\n pass\n') + self.mod.write('import pkg1\ndef a_func(pkg1):\n my_var = pkg1\n') + pymod = self.pycore.get_module('mod') + module_with_imports = self.import_tools.module_imports(pymod) + module_with_imports.remove_unused_imports() + self.assertEquals('def a_func(pkg1):\n my_var = pkg1\n', + module_with_imports.get_changed_source()) + + def test_trivial_expanding_star_imports(self): + self.mod1.write('def a_func():\n pass\ndef another_func():\n pass\n') + self.mod.write('from pkg1.mod1 import *\n') + pymod = self.pycore.get_module('mod') + module_with_imports = self.import_tools.module_imports(pymod) + module_with_imports.expand_stars() + self.assertEquals('', module_with_imports.get_changed_source()) + + def test_expanding_star_imports(self): + self.mod1.write('def a_func():\n pass\ndef another_func():\n pass\n') + self.mod.write('from pkg1.mod1 import *\na_func()\n') + pymod = self.pycore.get_module('mod') + module_with_imports = self.import_tools.module_imports(pymod) + module_with_imports.expand_stars() + self.assertEquals('from pkg1.mod1 import a_func\na_func()\n', + module_with_imports.get_changed_source()) + + def test_removing_duplicate_imports(self): + self.mod.write('import pkg1\nimport pkg1\n') + pymod = self.pycore.get_module('mod') + module_with_imports = self.import_tools.module_imports(pymod) + module_with_imports.remove_duplicates() + self.assertEquals('import pkg1\n', + module_with_imports.get_changed_source()) + + def test_removing_duplicates_and_reoccuring_names(self): + self.mod.write('import pkg2.mod2\nimport pkg2.mod3\n') + pymod = self.pycore.get_module('mod') + module_with_imports = self.import_tools.module_imports(pymod) + module_with_imports.remove_duplicates() + self.assertEquals('import pkg2.mod2\nimport pkg2.mod3\n', + module_with_imports.get_changed_source()) + + def test_removing_duplicate_imports_for_froms(self): + self.mod1.write( + 'def a_func():\n pass\ndef another_func():\n pass\n') + self.mod.write('from pkg1 import a_func\n' + 'from pkg1 import a_func, another_func\n') + pymod = self.pycore.get_module('mod') + module_with_imports = self.import_tools.module_imports(pymod) + module_with_imports.remove_duplicates() + self.assertEquals('from pkg1 import a_func, another_func\n', + module_with_imports.get_changed_source()) + + def test_transforming_froms_to_normal_changing_imports(self): + self.mod1.write('def a_func():\n pass\n') + self.mod.write('from pkg1.mod1 import a_func\nprint(a_func)\n') + pymod = self.pycore.get_module('mod') + changed_module = self.import_tools.froms_to_imports(pymod) + self.assertEquals('import pkg1.mod1\nprint(pkg1.mod1.a_func)\n', + changed_module) + + def test_transforming_froms_to_normal_changing_occurances(self): + self.mod1.write('def a_func():\n pass\n') + self.mod.write('from pkg1.mod1 import a_func\na_func()') + pymod = self.pycore.get_module('mod') + changed_module = self.import_tools.froms_to_imports(pymod) + self.assertEquals('import pkg1.mod1\npkg1.mod1.a_func()', + changed_module) + + def test_transforming_froms_to_normal_for_multi_imports(self): + self.mod1.write('def a_func():\n pass\ndef another_func():\n pass\n') + self.mod.write('from pkg1.mod1 import *\na_func()\nanother_func()\n') + pymod = self.pycore.get_module('mod') + changed_module = self.import_tools.froms_to_imports(pymod) + self.assertEquals( + 'import pkg1.mod1\npkg1.mod1.a_func()\npkg1.mod1.another_func()\n', + changed_module) + + def test_transforming_froms_to_normal_for_multi_imports_inside_parens(self): + self.mod1.write('def a_func():\n pass\ndef another_func():\n pass\n') + self.mod.write('from pkg1.mod1 import (a_func, \n another_func)' \ + '\na_func()\nanother_func()\n') + pymod = self.pycore.get_module('mod') + changed_module = self.import_tools.froms_to_imports(pymod) + self.assertEquals( + 'import pkg1.mod1\npkg1.mod1.a_func()\npkg1.mod1.another_func()\n', + changed_module) + + def test_transforming_froms_to_normal_from_stars(self): + self.mod1.write('def a_func():\n pass\n') + self.mod.write('from pkg1.mod1 import *\na_func()\n') + pymod = self.pycore.get_module('mod') + changed_module = self.import_tools.froms_to_imports(pymod) + self.assertEquals('import pkg1.mod1\npkg1.mod1.a_func()\n', changed_module) + + def test_transforming_froms_to_normal_from_stars2(self): + self.mod1.write('a_var = 10') + self.mod.write('import pkg1.mod1\nfrom pkg1.mod1 import a_var\n' \ + 'def a_func():\n print(pkg1.mod1, a_var)\n') + pymod = self.pycore.get_module('mod') + changed_module = self.import_tools.froms_to_imports(pymod) + self.assertEquals('import pkg1.mod1\n' \ + 'def a_func():\n print(pkg1.mod1, pkg1.mod1.a_var)\n', + changed_module) + + def test_transforming_froms_to_normal_from_with_alias(self): + self.mod1.write('def a_func():\n pass\n') + self.mod.write( + 'from pkg1.mod1 import a_func as another_func\nanother_func()\n') + pymod = self.pycore.get_module('mod') + changed_module = self.import_tools.froms_to_imports(pymod) + self.assertEquals('import pkg1.mod1\npkg1.mod1.a_func()\n', + changed_module) + + def test_transforming_froms_to_normal_for_relatives(self): + self.mod2.write('def a_func():\n pass\n') + self.mod3.write('from mod2 import *\na_func()\n') + pymod = self.pycore.resource_to_pyobject(self.mod3) + changed_module = self.import_tools.froms_to_imports(pymod) + self.assertEquals('import pkg2.mod2\npkg2.mod2.a_func()\n', + changed_module) + + def test_transforming_froms_to_normal_for_os_path(self): + self.mod.write('from os import path\npath.exists(\'.\')\n') + pymod = self.pycore.resource_to_pyobject(self.mod) + changed_module = self.import_tools.froms_to_imports(pymod) + self.assertEquals('import os\nos.path.exists(\'.\')\n', changed_module) + + def test_transform_relatives_imports_to_absolute_imports_doing_nothing(self): + self.mod2.write('from pkg1 import mod1\nimport mod1\n') + pymod = self.pycore.resource_to_pyobject(self.mod2) + self.assertEquals('from pkg1 import mod1\nimport mod1\n', + self.import_tools.relatives_to_absolutes(pymod)) + + def test_transform_relatives_to_absolute_imports_for_normal_imports(self): + self.mod2.write('import mod3\n') + pymod = self.pycore.resource_to_pyobject(self.mod2) + self.assertEquals('import pkg2.mod3\n', + self.import_tools.relatives_to_absolutes(pymod)) + + def test_transform_relatives_imports_to_absolute_imports_for_froms(self): + self.mod3.write('def a_func():\n pass\n') + self.mod2.write('from mod3 import a_func\n') + pymod = self.pycore.resource_to_pyobject(self.mod2) + self.assertEquals('from pkg2.mod3 import a_func\n', + self.import_tools.relatives_to_absolutes(pymod)) + + @testutils.run_only_for_25 + def test_transform_relatives_imports_to_absolute_imports_for_new_relatives(self): + self.mod3.write('def a_func():\n pass\n') + self.mod2.write('from .mod3 import a_func\n') + pymod = self.pycore.resource_to_pyobject(self.mod2) + self.assertEquals('from pkg2.mod3 import a_func\n', + self.import_tools.relatives_to_absolutes(pymod)) + + def test_transform_relatives_to_absolute_imports_for_normal_imports2(self): + self.mod2.write('import mod3\nprint(mod3)') + pymod = self.pycore.resource_to_pyobject(self.mod2) + self.assertEquals('import pkg2.mod3\nprint(pkg2.mod3)', + self.import_tools.relatives_to_absolutes(pymod)) + + def test_transform_relatives_to_absolute_imports_for_aliases(self): + self.mod2.write('import mod3 as mod3\nprint(mod3)') + pymod = self.pycore.resource_to_pyobject(self.mod2) + self.assertEquals('import pkg2.mod3 as mod3\nprint(mod3)', + self.import_tools.relatives_to_absolutes(pymod)) + + def test_organizing_imports(self): + self.mod1.write('import mod1\n') + pymod = self.pycore.resource_to_pyobject(self.mod1) + self.assertEquals('', self.import_tools.organize_imports(pymod)) + + def test_removing_self_imports(self): + self.mod.write('import mod\nmod.a_var = 1\nprint(mod.a_var)\n') + pymod = self.pycore.resource_to_pyobject(self.mod) + self.assertEquals('a_var = 1\nprint(a_var)\n', + self.import_tools.organize_imports(pymod)) + + def test_removing_self_imports2(self): + self.mod1.write('import pkg1.mod1\npkg1.mod1.a_var = 1\n' + 'print(pkg1.mod1.a_var)\n') + pymod = self.pycore.resource_to_pyobject(self.mod1) + self.assertEquals('a_var = 1\nprint(a_var)\n', + self.import_tools.organize_imports(pymod)) + + def test_removing_self_imports_with_as(self): + self.mod.write('import mod as mymod\n' + 'mymod.a_var = 1\nprint(mymod.a_var)\n') + pymod = self.pycore.resource_to_pyobject(self.mod) + self.assertEquals('a_var = 1\nprint(a_var)\n', + self.import_tools.organize_imports(pymod)) + + def test_removing_self_imports_for_froms(self): + self.mod1.write('from pkg1 import mod1\n' + 'mod1.a_var = 1\nprint(mod1.a_var)\n') + pymod = self.pycore.resource_to_pyobject(self.mod1) + self.assertEquals('a_var = 1\nprint(a_var)\n', + self.import_tools.organize_imports(pymod)) + + def test_removing_self_imports_for_froms_with_as(self): + self.mod1.write('from pkg1 import mod1 as mymod\n' + 'mymod.a_var = 1\nprint(mymod.a_var)\n') + pymod = self.pycore.resource_to_pyobject(self.mod1) + self.assertEquals('a_var = 1\nprint(a_var)\n', + self.import_tools.organize_imports(pymod)) + + def test_removing_self_imports_for_froms2(self): + self.mod.write('from mod import a_var\na_var = 1\nprint(a_var)\n') + pymod = self.pycore.resource_to_pyobject(self.mod) + self.assertEquals('a_var = 1\nprint(a_var)\n', + self.import_tools.organize_imports(pymod)) + + def test_removing_self_imports_for_froms3(self): + self.mod.write('from mod import a_var\na_var = 1\nprint(a_var)\n') + pymod = self.pycore.resource_to_pyobject(self.mod) + self.assertEquals('a_var = 1\nprint(a_var)\n', + self.import_tools.organize_imports(pymod)) + + def test_removing_self_imports_for_froms4(self): + self.mod.write('from mod import a_var as myvar\n' + 'a_var = 1\nprint(myvar)\n') + pymod = self.pycore.resource_to_pyobject(self.mod) + self.assertEquals('a_var = 1\nprint(a_var)\n', + self.import_tools.organize_imports(pymod)) + + def test_removing_self_imports_with_no_dot_after_mod(self): + self.mod.write('import mod\nprint(mod)\n') + pymod = self.pycore.resource_to_pyobject(self.mod) + self.assertEquals('import mod\n\n\nprint(mod)\n', + self.import_tools.organize_imports(pymod)) + + def test_removing_self_imports_with_no_dot_after_mod2(self): + self.mod.write('import mod\na_var = 1\n' + 'print(mod\\\n \\\n .var)\n\n') + pymod = self.pycore.resource_to_pyobject(self.mod) + self.assertEquals('a_var = 1\nprint(var)\n\n', + self.import_tools.organize_imports(pymod)) + + def test_removing_self_imports_for_from_import_star(self): + self.mod.write('from mod import *\na_var = 1\nprint(myvar)\n') + pymod = self.pycore.resource_to_pyobject(self.mod) + self.assertEquals('a_var = 1\nprint(myvar)\n', + self.import_tools.organize_imports(pymod)) + + def test_not_removing_future_imports(self): + self.mod.write('from __future__ import division\n') + pymod = self.pycore.resource_to_pyobject(self.mod) + self.assertEquals('from __future__ import division\n', + self.import_tools.organize_imports(pymod)) + + def test_sorting_empty_imports(self): + self.mod.write('') + pymod = self.pycore.resource_to_pyobject(self.mod) + self.assertEquals('', self.import_tools.sort_imports(pymod)) + + def test_sorting_one_import(self): + self.mod.write('import pkg1.mod1\n') + pymod = self.pycore.resource_to_pyobject(self.mod) + self.assertEquals('import pkg1.mod1\n', + self.import_tools.sort_imports(pymod)) + + def test_sorting_imports_alphabetically(self): + self.mod.write('import pkg2.mod2\nimport pkg1.mod1\n') + pymod = self.pycore.resource_to_pyobject(self.mod) + self.assertEquals('import pkg1.mod1\nimport pkg2.mod2\n', + self.import_tools.sort_imports(pymod)) + + def test_sorting_imports_and_froms(self): + self.mod.write('import pkg2.mod2\nfrom pkg1 import mod1\n') + pymod = self.pycore.resource_to_pyobject(self.mod) + self.assertEquals('import pkg2.mod2\nfrom pkg1 import mod1\n', + self.import_tools.sort_imports(pymod)) + + def test_sorting_imports_and_standard_modules(self): + self.mod.write('import pkg1\nimport sys\n') + pymod = self.pycore.resource_to_pyobject(self.mod) + self.assertEquals('import sys\n\nimport pkg1\n', + self.import_tools.sort_imports(pymod)) + + def test_sorting_imports_and_standard_modules2(self): + self.mod.write('import sys\n\nimport time\n') + pymod = self.pycore.resource_to_pyobject(self.mod) + self.assertEquals('import sys\nimport time\n', + self.import_tools.sort_imports(pymod)) + + def test_sorting_only_standard_modules(self): + self.mod.write('import sys\n') + pymod = self.pycore.resource_to_pyobject(self.mod) + self.assertEquals('import sys\n', + self.import_tools.sort_imports(pymod)) + + def test_sorting_third_party(self): + self.mod.write('import pkg1\nimport a_third_party\n') + pymod = self.pycore.resource_to_pyobject(self.mod) + self.assertEquals('import a_third_party\n\nimport pkg1\n', + self.import_tools.sort_imports(pymod)) + + def test_sorting_only_third_parties(self): + self.mod.write('import a_third_party\na_var = 1\n') + pymod = self.pycore.resource_to_pyobject(self.mod) + self.assertEquals('import a_third_party\n\n\na_var = 1\n', + self.import_tools.sort_imports(pymod)) + + def test_simple_handling_long_imports(self): + self.mod.write('import pkg1.mod1\n\n\nm = pkg1.mod1\n') + pymod = self.pycore.resource_to_pyobject(self.mod) + self.assertEquals( + 'import pkg1.mod1\n\n\nm = pkg1.mod1\n', + self.import_tools.handle_long_imports(pymod, maxdots=2)) + + def test_handling_long_imports_for_many_dots(self): + self.mod.write('import p1.p2.p3.m1\n\n\nm = p1.p2.p3.m1\n') + pymod = self.pycore.resource_to_pyobject(self.mod) + self.assertEquals( + 'from p1.p2.p3 import m1\n\n\nm = m1\n', + self.import_tools.handle_long_imports(pymod, maxdots=2)) + + def test_handling_long_imports_for_their_length(self): + self.mod.write('import p1.p2.p3.m1\n\n\nm = p1.p2.p3.m1\n') + pymod = self.pycore.resource_to_pyobject(self.mod) + self.assertEquals( + 'import p1.p2.p3.m1\n\n\nm = p1.p2.p3.m1\n', + self.import_tools.handle_long_imports(pymod, maxdots=3, + maxlength=20)) + + def test_handling_long_imports_for_many_dots2(self): + self.mod.write('import p1.p2.p3.m1\n\n\nm = p1.p2.p3.m1\n') + pymod = self.pycore.resource_to_pyobject(self.mod) + self.assertEquals( + 'from p1.p2.p3 import m1\n\n\nm = m1\n', + self.import_tools.handle_long_imports(pymod, maxdots=3, + maxlength=10)) + + def test_handling_long_imports_with_one_letter_last(self): + self.mod.write('import p1.p2.p3.l\n\n\nm = p1.p2.p3.l\n') + pymod = self.pycore.resource_to_pyobject(self.mod) + self.assertEquals( + 'from p1.p2.p3 import l\n\n\nm = l\n', + self.import_tools.handle_long_imports(pymod, maxdots=2)) + + def test_empty_removing_unused_imports_and_eating_blank_lines(self): + self.mod.write('import pkg1\nimport pkg2\n\n\nprint(pkg1)\n') + pymod = self.pycore.get_module('mod') + module_with_imports = self.import_tools.module_imports(pymod) + module_with_imports.remove_unused_imports() + self.assertEquals('import pkg1\n\n\nprint(pkg1)\n', + module_with_imports.get_changed_source()) + + def test_sorting_imports_moving_to_top(self): + self.mod.write('import mod\ndef f():\n print(mod, pkg1, pkg2)\n' + 'import pkg1\nimport pkg2\n') + pymod = self.pycore.get_module('mod') + self.assertEquals('import mod\nimport pkg1\nimport pkg2\n\n\n' + 'def f():\n print(mod, pkg1, pkg2)\n', + self.import_tools.sort_imports(pymod)) + + def test_sorting_imports_moving_to_top2(self): + self.mod.write('def f():\n print(mod)\nimport mod\n') + pymod = self.pycore.get_module('mod') + self.assertEquals('import mod\n\n\ndef f():\n print(mod)\n', + self.import_tools.sort_imports(pymod)) + + def test_sorting_imports_moving_to_top_and_module_docs(self): + self.mod.write('"""\ndocs\n"""\ndef f():\n print(mod)\nimport mod\n') + pymod = self.pycore.get_module('mod') + self.assertEquals( + '"""\ndocs\n"""\nimport mod\n\n\ndef f():\n print(mod)\n', + self.import_tools.sort_imports(pymod)) + + def test_sorting_future_imports(self): + self.mod.write('import os\nfrom __future__ import devision\n') + pymod = self.pycore.get_module('mod') + self.assertEquals( + 'from __future__ import devision\n\nimport os\n', + self.import_tools.sort_imports(pymod)) + + def test_customized_import_organization(self): + self.mod.write('import sys\nimport sys\n') + pymod = self.pycore.resource_to_pyobject(self.mod) + self.assertEquals( + 'import sys\n', + self.import_tools.organize_imports(pymod, unused=False)) + + def test_customized_import_organization2(self): + self.mod.write('import sys\n') + pymod = self.pycore.resource_to_pyobject(self.mod) + self.assertEquals( + 'import sys\n', + self.import_tools.organize_imports(pymod, unused=False)) + + def test_customized_import_organization3(self): + self.mod.write('import sys\nimport mod\n\n\nvar = 1\nprint(mod.var)\n') + pymod = self.pycore.resource_to_pyobject(self.mod) + self.assertEquals( + 'import sys\n\n\nvar = 1\nprint(var)\n', + self.import_tools.organize_imports(pymod, unused=False)) + + def test_trivial_filtered_expand_stars(self): + self.pkg1.get_child('__init__.py').write('var1 = 1\n') + self.pkg2.get_child('__init__.py').write('var2 = 1\n') + self.mod.write('from pkg1 import *\nfrom pkg2 import *\n\n' + 'print(var1, var2)\n') + pymod = self.pycore.resource_to_pyobject(self.mod) + self.assertEquals( + 'from pkg1 import *\nfrom pkg2 import *\n\nprint(var1, var2)\n', + self.import_tools.expand_stars(pymod, lambda stmt: False)) + + def _line_filter(self, lineno): + def import_filter(import_stmt): + return import_stmt.start_line <= lineno < import_stmt.end_line + return import_filter + + def test_filtered_expand_stars(self): + self.pkg1.get_child('__init__.py').write('var1 = 1\n') + self.pkg2.get_child('__init__.py').write('var2 = 1\n') + self.mod.write('from pkg1 import *\nfrom pkg2 import *\n\n' + 'print(var1, var2)\n') + pymod = self.pycore.resource_to_pyobject(self.mod) + self.assertEquals( + 'from pkg1 import *\nfrom pkg2 import var2\n\nprint(var1, var2)\n', + self.import_tools.expand_stars(pymod, self._line_filter(2))) + + def test_filtered_relative_to_absolute(self): + self.mod3.write('var = 1') + self.mod2.write('import mod3\n\nprint(mod3.var)\n') + pymod = self.pycore.resource_to_pyobject(self.mod2) + self.assertEquals( + 'import mod3\n\nprint(mod3.var)\n', + self.import_tools.relatives_to_absolutes( + pymod, lambda stmt: False)) + self.assertEquals( + 'import pkg2.mod3\n\nprint(pkg2.mod3.var)\n', + self.import_tools.relatives_to_absolutes( + pymod, self._line_filter(1))) + + def test_filtered_froms_to_normals(self): + self.pkg1.get_child('__init__.py').write('var1 = 1\n') + self.pkg2.get_child('__init__.py').write('var2 = 1\n') + self.mod.write('from pkg1 import var1\nfrom pkg2 import var2\n\n' + 'print(var1, var2)\n') + pymod = self.pycore.resource_to_pyobject(self.mod) + self.assertEquals( + 'from pkg1 import var1\nfrom pkg2 import var2\n\nprint(var1, var2)\n', + self.import_tools.expand_stars(pymod, lambda stmt: False)) + self.assertEquals( + 'from pkg1 import var1\nimport pkg2\n\nprint(var1, pkg2.var2)\n', + self.import_tools.froms_to_imports(pymod, self._line_filter(2))) + + def test_filtered_froms_to_normals2(self): + self.pkg1.get_child('__init__.py').write('var1 = 1\n') + self.pkg2.get_child('__init__.py').write('var2 = 1\n') + self.mod.write('from pkg1 import *\nfrom pkg2 import *\n\n' + 'print(var1, var2)\n') + pymod = self.pycore.resource_to_pyobject(self.mod) + self.assertEquals( + 'from pkg1 import *\nimport pkg2\n\nprint(var1, pkg2.var2)\n', + self.import_tools.froms_to_imports(pymod, self._line_filter(2))) + + def test_filtered_handle_long_imports(self): + self.mod.write('import p1.p2.p3.m1\nimport pkg1.mod1\n\n\n' + 'm = p1.p2.p3.m1, pkg1.mod1\n') + pymod = self.pycore.resource_to_pyobject(self.mod) + self.assertEquals( + 'import p1.p2.p3.m1\nfrom pkg1 import mod1\n\n\n' + 'm = p1.p2.p3.m1, mod1\n', + self.import_tools.handle_long_imports( + pymod, maxlength=5, + import_filter=self._line_filter(2))) + + def test_filtering_and_import_actions_with_more_than_one_phase(self): + self.pkg1.get_child('__init__.py').write('var1 = 1\n') + self.pkg2.get_child('__init__.py').write('var2 = 1\n') + self.mod.write('from pkg1 import *\nfrom pkg2 import *\n\n' + 'print(var2)\n') + pymod = self.pycore.resource_to_pyobject(self.mod) + self.assertEquals( + 'from pkg2 import *\n\nprint(var2)\n', + self.import_tools.expand_stars(pymod, self._line_filter(1))) + + def test_non_existent_module_and_used_imports(self): + self.mod.write( + 'from does_not_exist import func\n\nfunc()\n') + pymod = self.pycore.get_module('mod') + + module_with_imports = self.import_tools.module_imports(pymod) + imports = module_with_imports.get_used_imports(pymod) + self.assertEquals(1, len(imports)) + + +class AddImportTest(unittest.TestCase): + + def setUp(self): + super(AddImportTest, self).setUp() + self.project = testutils.sample_project() + self.pycore = self.project.pycore + + self.mod1 = testutils.create_module(self.project, 'mod1') + self.mod2 = testutils.create_module(self.project, 'mod2') + self.pkg = testutils.create_package(self.project, 'pkg') + self.mod3 = testutils.create_module(self.project, 'mod3', self.pkg) + + def tearDown(self): + testutils.remove_project(self.project) + super(AddImportTest, self).tearDown() + + def test_normal_imports(self): + self.mod2.write('myvar = None\n') + self.mod1.write('\n') + pymod = self.pycore.get_module('mod1') + result, name = add_import(self.pycore, pymod, 'mod2', 'myvar') + self.assertEquals('import mod2\n', result) + self.assertEquals('mod2.myvar', name) + + def test_not_reimporting_a_name(self): + self.mod2.write('myvar = None\n') + self.mod1.write('from mod2 import myvar\n') + pymod = self.pycore.get_module('mod1') + result, name = add_import(self.pycore, pymod, 'mod2', 'myvar') + self.assertEquals('from mod2 import myvar\n', result) + self.assertEquals('myvar', name) + + def test_adding_import_when_siblings_are_imported(self): + self.mod2.write('var1 = None\nvar2 = None\n') + self.mod1.write('from mod2 import var1\n') + pymod = self.pycore.get_module('mod1') + result, name = add_import(self.pycore, pymod, 'mod2', 'var2') + self.assertEquals('from mod2 import var1, var2\n', result) + self.assertEquals('var2', name) + + def test_adding_import_when_the_package_is_imported(self): + self.pkg.get_child('__init__.py').write('var1 = None\n') + self.mod3.write('var2 = None\n') + self.mod1.write('from pkg import var1\n') + pymod = self.pycore.get_module('mod1') + result, name = add_import(self.pycore, pymod, 'pkg.mod3', 'var2') + self.assertEquals('from pkg import var1, mod3\n', result) + self.assertEquals('mod3.var2', name) + + def test_adding_import_for_modules_instead_of_names(self): + self.pkg.get_child('__init__.py').write('var1 = None\n') + self.mod3.write('\n') + self.mod1.write('from pkg import var1\n') + pymod = self.pycore.get_module('mod1') + result, name = add_import(self.pycore, pymod, 'pkg.mod3', None) + self.assertEquals('from pkg import var1, mod3\n', result) + self.assertEquals('mod3', name) + + def test_adding_import_for_modules_with_normal_duplicate_imports(self): + self.pkg.get_child('__init__.py').write('var1 = None\n') + self.mod3.write('\n') + self.mod1.write('import pkg.mod3\n') + pymod = self.pycore.get_module('mod1') + result, name = add_import(self.pycore, pymod, 'pkg.mod3', None) + self.assertEquals('import pkg.mod3\n', result) + self.assertEquals('pkg.mod3', name) + + +def suite(): + result = unittest.TestSuite() + result.addTests(unittest.makeSuite(ImportUtilsTest)) + result.addTests(unittest.makeSuite(AddImportTest)) + return result + +if __name__ == '__main__': + unittest.main() diff -r e30544496575 -r 48cacfdc2ca6 vim/sadness/ropevim/src/rope/ropetest/refactor/inlinetest.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vim/sadness/ropevim/src/rope/ropetest/refactor/inlinetest.py Wed Oct 06 12:30:46 2010 -0400 @@ -0,0 +1,616 @@ +from ropetest.testutils import only_for +import unittest + +import rope.base.exceptions +from rope.refactor import inline +from ropetest import testutils + + +class InlineTest(unittest.TestCase): + + def setUp(self): + super(InlineTest, self).setUp() + self.project = testutils.sample_project() + self.pycore = self.project.pycore + self.mod = testutils.create_module(self.project, 'mod') + self.mod2 = testutils.create_module(self.project, 'mod2') + + def tearDown(self): + testutils.remove_project(self.project) + super(InlineTest, self).tearDown() + + def _inline(self, code, offset, **kwds): + self.mod.write(code) + self._inline2(self.mod, offset, **kwds) + return self.mod.read() + + def _inline2(self, resource, offset, **kwds): + inliner = inline.create_inline(self.project, resource, offset) + changes = inliner.get_changes(**kwds) + self.project.do(changes) + return self.mod.read() + + def test_simple_case(self): + code = 'a_var = 10\nanother_var = a_var\n' + refactored = self._inline(code, code.index('a_var') + 1) + self.assertEquals('another_var = 10\n', refactored) + + def test_empty_case(self): + code = 'a_var = 10\n' + refactored = self._inline(code, code.index('a_var') + 1) + self.assertEquals('', refactored) + + def test_long_definition(self): + code = 'a_var = 10 + (10 + 10)\nanother_var = a_var\n' + refactored = self._inline(code, code.index('a_var') + 1) + self.assertEquals('another_var = 10 + (10 + 10)\n', refactored) + + def test_explicit_continuation(self): + code = 'a_var = (10 +\n 10)\nanother_var = a_var\n' + refactored = self._inline(code, code.index('a_var') + 1) + self.assertEquals('another_var = (10 + 10)\n', refactored) + + def test_implicit_continuation(self): + code = 'a_var = 10 +\\\n 10\nanother_var = a_var\n' + refactored = self._inline(code, code.index('a_var') + 1) + self.assertEquals('another_var = 10 + 10\n', refactored) + + def test_inlining_at_the_end_of_input(self): + code = 'a = 1\nb = a' + refactored = self._inline(code, code.index('a') + 1) + self.assertEquals('b = 1', refactored) + + @testutils.assert_raises(rope.base.exceptions.RefactoringError) + def test_on_classes(self): + code = 'class AClass(object):\n pass\n' + refactored = self._inline(code, code.index('AClass') + 1) + + @testutils.assert_raises(rope.base.exceptions.RefactoringError) + def test_multiple_assignments(self): + code = 'a_var = 10\na_var = 20\n' + refactored = self._inline(code, code.index('a_var') + 1) + + @testutils.assert_raises(rope.base.exceptions.RefactoringError) + def test_tuple_assignments(self): + code = 'a_var, another_var = (20, 30)\n' + refactored = self._inline(code, code.index('a_var') + 1) + + @testutils.assert_raises(rope.base.exceptions.RefactoringError) + def test_on_unknown_vars(self): + code = 'a_var = another_var\n' + refactored = self._inline(code, code.index('another_var') + 1) + + def test_attribute_inlining(self): + code = 'class A(object):\n def __init__(self):\n' \ + ' self.an_attr = 3\n range(self.an_attr)\n' + refactored = self._inline(code, code.index('an_attr') + 1) + expected = 'class A(object):\n def __init__(self):\n' \ + ' range(3)\n' + self.assertEquals(expected, refactored) + + def test_attribute_inlining2(self): + code = 'class A(object):\n def __init__(self):\n' \ + ' self.an_attr = 3\n range(self.an_attr)\n' \ + 'a = A()\nrange(a.an_attr)' + refactored = self._inline(code, code.index('an_attr') + 1) + expected = 'class A(object):\n def __init__(self):\n' \ + ' range(3)\n' \ + 'a = A()\nrange(3)' + self.assertEquals(expected, refactored) + + + def test_a_function_with_no_occurance(self): + self.mod.write('def a_func():\n pass\n') + self._inline2(self.mod, self.mod.read().index('a_func') + 1) + self.assertEquals('', self.mod.read()) + + def test_a_function_with_no_occurance2(self): + self.mod.write('a_var = 10\ndef a_func():\n pass\nprint(a_var)\n') + self._inline2(self.mod, self.mod.read().index('a_func') + 1) + self.assertEquals('a_var = 10\nprint(a_var)\n', self.mod.read()) + + def test_replacing_calls_with_function_definition_in_other_modules(self): + self.mod.write('def a_func():\n print(1)\n') + mod1 = testutils.create_module(self.project, 'mod1') + mod1.write('import mod\nmod.a_func()\n') + self._inline2(self.mod, self.mod.read().index('a_func') + 1) + self.assertEquals('import mod\nprint(1)\n', mod1.read()) + + def test_replacing_calls_with_function_definition_in_other_modules2(self): + self.mod.write('def a_func():\n print(1)\n') + mod1 = testutils.create_module(self.project, 'mod1') + mod1.write('import mod\nif True:\n mod.a_func()\n') + self._inline2(self.mod, self.mod.read().index('a_func') + 1) + self.assertEquals('import mod\nif True:\n print(1)\n', mod1.read()) + + def test_replacing_calls_with_method_definition_in_other_modules(self): + self.mod.write('class A(object):\n var = 10\n' + ' def a_func(self):\n print(1)\n') + mod1 = testutils.create_module(self.project, 'mod1') + mod1.write('import mod\nmod.A().a_func()\n') + self._inline2(self.mod, self.mod.read().index('a_func') + 1) + self.assertEquals('import mod\nprint(1)\n', mod1.read()) + self.assertEquals('class A(object):\n var = 10\n', self.mod.read()) + + def test_replacing_calls_with_function_definition_in_defining_module(self): + self.mod.write('def a_func():\n print(1)\na_func()\n') + self._inline2(self.mod, self.mod.read().index('a_func') + 1) + self.assertEquals('print(1)\n', self.mod.read()) + + def test_replacing_calls_with_function_definition_in_defining_module2(self): + self.mod.write('def a_func():\n for i in range(10):\n print(1)\na_func()\n') + self._inline2(self.mod, self.mod.read().index('a_func') + 1) + self.assertEquals('for i in range(10):\n print(1)\n', self.mod.read()) + + def test_replacing_calls_with_method_definition_in_defining_modules(self): + self.mod.write('class A(object):\n var = 10\n' + ' def a_func(self):\n print(1)\nA().a_func()') + self._inline2(self.mod, self.mod.read().index('a_func') + 1) + self.assertEquals('class A(object):\n var = 10\nprint(1)\n', self.mod.read()) + + def test_parameters_with_the_same_name_as_passed(self): + self.mod.write('def a_func(var):\n print(var)\nvar = 1\na_func(var)\n') + self._inline2(self.mod, self.mod.read().index('a_func') + 1) + self.assertEquals('var = 1\nprint(var)\n', self.mod.read()) + + def test_parameters_with_the_same_name_as_passed2(self): + self.mod.write('def a_func(var):\n print(var)\nvar = 1\na_func(var=var)\n') + self._inline2(self.mod, self.mod.read().index('a_func') + 1) + self.assertEquals('var = 1\nprint(var)\n', self.mod.read()) + + def test_simple_parameters_renaming(self): + self.mod.write('def a_func(param):\n print(param)\nvar = 1\na_func(var)\n') + self._inline2(self.mod, self.mod.read().index('a_func') + 1) + self.assertEquals('var = 1\nprint(var)\n', self.mod.read()) + + def test_simple_parameters_renaming_for_multiple_params(self): + self.mod.write('def a_func(param1, param2):\n p = param1 + param2\n' + 'var1 = 1\nvar2 = 1\na_func(var1, var2)\n') + self._inline2(self.mod, self.mod.read().index('a_func') + 1) + self.assertEquals('var1 = 1\nvar2 = 1\np = var1 + var2\n', self.mod.read()) + + def test_parameters_renaming_for_passed_constants(self): + self.mod.write('def a_func(param):\n print(param)\na_func(1)\n') + self._inline2(self.mod, self.mod.read().index('a_func') + 1) + self.assertEquals('print(1)\n', self.mod.read()) + + def test_parameters_renaming_for_passed_statements(self): + self.mod.write('def a_func(param):\n print(param)\na_func((1 + 2) / 3)\n') + self._inline2(self.mod, self.mod.read().index('a_func') + 1) + self.assertEquals('print((1 + 2) / 3)\n', self.mod.read()) + + def test_simple_parameters_renaming_for_multiple_params_using_keywords(self): + self.mod.write('def a_func(param1, param2):\n p = param1 + param2\n' + 'var1 = 1\nvar2 = 1\na_func(param2=var1, param1=var2)\n') + self._inline2(self.mod, self.mod.read().index('a_func') + 1) + self.assertEquals('var1 = 1\nvar2 = 1\np = var2 + var1\n', self.mod.read()) + + def test_simple_parameters_renaming_for_multiple_params_using_mixed_keywords(self): + self.mod.write('def a_func(param1, param2):\n p = param1 + param2\n' + 'var1 = 1\nvar2 = 1\na_func(var2, param2=var1)\n') + self._inline2(self.mod, self.mod.read().index('a_func') + 1) + self.assertEquals('var1 = 1\nvar2 = 1\np = var2 + var1\n', self.mod.read()) + + def test_simple_putting_in_default_arguments(self): + self.mod.write('def a_func(param=None):\n print(param)\n' + 'a_func()\n') + self._inline2(self.mod, self.mod.read().index('a_func') + 1) + self.assertEquals('print(None)\n', self.mod.read()) + + def test_overriding_default_arguments(self): + self.mod.write('def a_func(param1=1, param2=2):\n print(param1, param2)\n' + 'a_func(param2=3)\n') + self._inline2(self.mod, self.mod.read().index('a_func') + 1) + self.assertEquals('print(1, 3)\n', self.mod.read()) + + def test_badly_formatted_text(self): + self.mod.write('def a_func ( param1 = 1 ,param2 = 2 ) :\n print(param1, param2)\n' + 'a_func ( param2 \n = 3 ) \n') + self._inline2(self.mod, self.mod.read().index('a_func') + 1) + self.assertEquals('print(1, 3)\n', self.mod.read()) + + def test_passing_first_arguments_for_methods(self): + a_class = 'class A(object):\n' \ + ' def __init__(self):\n' \ + ' self.var = 1\n' \ + ' self.a_func(self.var)\n' \ + ' def a_func(self, param):\n' \ + ' print(param)\n' + self.mod.write(a_class) + self._inline2(self.mod, self.mod.read().index('a_func') + 1) + expected = 'class A(object):\n' \ + ' def __init__(self):\n' \ + ' self.var = 1\n' \ + ' print(self.var)\n' + self.assertEquals(expected, self.mod.read()) + + def test_passing_first_arguments_for_methods2(self): + a_class = 'class A(object):\n' \ + ' def __init__(self):\n' \ + ' self.var = 1\n' \ + ' def a_func(self, param):\n' \ + ' print(param, self.var)\n' \ + 'an_a = A()\n' \ + 'an_a.a_func(1)\n' + self.mod.write(a_class) + self._inline2(self.mod, self.mod.read().index('a_func') + 1) + expected = 'class A(object):\n' \ + ' def __init__(self):\n' \ + ' self.var = 1\n' \ + 'an_a = A()\n' \ + 'print(1, an_a.var)\n' + self.assertEquals(expected, self.mod.read()) + + def test_passing_first_arguments_for_methods3(self): + a_class = 'class A(object):\n' \ + ' def __init__(self):\n' \ + ' self.var = 1\n' \ + ' def a_func(self, param):\n' \ + ' print(param, self.var)\n' \ + 'an_a = A()\n' \ + 'A.a_func(an_a, 1)\n' + self.mod.write(a_class) + self._inline2(self.mod, self.mod.read().index('a_func') + 1) + expected = 'class A(object):\n' \ + ' def __init__(self):\n' \ + ' self.var = 1\n' \ + 'an_a = A()\n' \ + 'print(1, an_a.var)\n' + self.assertEquals(expected, self.mod.read()) + + def test_inlining_staticmethods(self): + a_class = 'class A(object):\n' \ + ' @staticmethod\n' \ + ' def a_func(param):\n' \ + ' print(param)\n' \ + 'A.a_func(1)\n' + self.mod.write(a_class) + self._inline2(self.mod, self.mod.read().index('a_func') + 1) + expected = 'class A(object):\n' \ + ' pass\n' \ + 'print(1)\n' + self.assertEquals(expected, self.mod.read()) + + def test_static_methods2(self): + a_class = 'class A(object):\n' \ + ' var = 10\n' \ + ' @staticmethod\n' \ + ' def a_func(param):\n' \ + ' print(param)\n' \ + 'an_a = A()\n' \ + 'an_a.a_func(1)\n' \ + 'A.a_func(2)\n' + self.mod.write(a_class) + self._inline2(self.mod, self.mod.read().index('a_func') + 1) + expected = 'class A(object):\n' \ + ' var = 10\n' \ + 'an_a = A()\n' \ + 'print(1)\n' \ + 'print(2)\n' + self.assertEquals(expected, self.mod.read()) + + def test_inlining_classmethods(self): + a_class = 'class A(object):\n' \ + ' @classmethod\n' \ + ' def a_func(cls, param):\n' \ + ' print(param)\n' \ + 'A.a_func(1)\n' + self.mod.write(a_class) + self._inline2(self.mod, self.mod.read().index('a_func') + 1) + expected = 'class A(object):\n' \ + ' pass\n' \ + 'print(1)\n' + self.assertEquals(expected, self.mod.read()) + + def test_inlining_classmethods2(self): + a_class = 'class A(object):\n' \ + ' @classmethod\n' \ + ' def a_func(cls, param):\n' \ + ' return cls\n' \ + 'print(A.a_func(1))\n' + self.mod.write(a_class) + self._inline2(self.mod, self.mod.read().index('a_func') + 1) + expected = 'class A(object):\n' \ + ' pass\n' \ + 'print(A)\n' + self.assertEquals(expected, self.mod.read()) + + def test_simple_return_values_and_inlining_functions(self): + self.mod.write('def a_func():\n return 1\na = a_func()\n') + self._inline2(self.mod, self.mod.read().index('a_func') + 1) + self.assertEquals('a = 1\n', + self.mod.read()) + + def test_simple_return_values_and_inlining_lonely_functions(self): + self.mod.write('def a_func():\n return 1\na_func()\n') + self._inline2(self.mod, self.mod.read().index('a_func') + 1) + self.assertEquals('1\n', self.mod.read()) + + def test_empty_returns_and_inlining_lonely_functions(self): + self.mod.write('def a_func():\n if True:\n return\na_func()\n') + self._inline2(self.mod, self.mod.read().index('a_func') + 1) + self.assertEquals('if True:\n pass\n', self.mod.read()) + + @testutils.assert_raises(rope.base.exceptions.RefactoringError) + def test_multiple_returns(self): + self.mod.write('def less_than_five(var):\n if var < 5:\n' + ' return True\n return False\n' + 'a = less_than_five(2)\n') + self._inline2(self.mod, self.mod.read().index('less') + 1) + + def test_multiple_returns_and_not_using_the_value(self): + self.mod.write('def less_than_five(var):\n if var < 5:\n' + ' return True\n return False\nless_than_five(2)\n') + self._inline2(self.mod, self.mod.read().index('less') + 1) + self.assertEquals('if 2 < 5:\n True\nFalse\n', self.mod.read()) + + @testutils.assert_raises(rope.base.exceptions.RefactoringError) + def test_raising_exception_for_list_arguments(self): + self.mod.write('def a_func(*args):\n print(args)\na_func(1)\n') + self._inline2(self.mod, self.mod.read().index('a_func') + 1) + + @testutils.assert_raises(rope.base.exceptions.RefactoringError) + def test_raising_exception_for_list_keywods(self): + self.mod.write('def a_func(**kwds):\n print(kwds)\na_func(n=1)\n') + self._inline2(self.mod, self.mod.read().index('a_func') + 1) + + def test_function_parameters_and_returns_in_other_functions(self): + code = 'def a_func(param1, param2):\n' \ + ' return param1 + param2\n' \ + 'range(a_func(20, param2=abs(10)))\n' + self.mod.write(code) + self._inline2(self.mod, self.mod.read().index('a_func') + 1) + self.assertEquals('range(20 + abs(10))\n', self.mod.read()) + + @testutils.assert_raises(rope.base.exceptions.RefactoringError) + def test_function_references_other_than_call(self): + self.mod.write('def a_func(param):\n print(param)\nf = a_func\n') + self._inline2(self.mod, self.mod.read().index('a_func') + 1) + + @testutils.assert_raises(rope.base.exceptions.RefactoringError) + def test_function_referencing_itself(self): + self.mod.write('def a_func(var):\n func = a_func\n') + self._inline2(self.mod, self.mod.read().index('a_func') + 1) + + @testutils.assert_raises(rope.base.exceptions.RefactoringError) + def test_recursive_functions(self): + self.mod.write('def a_func(var):\n a_func(var)\n') + self._inline2(self.mod, self.mod.read().index('a_func') + 1) + + # TODO: inlining on function parameters + def xxx_test_inlining_function_default_parameters(self): + self.mod.write('def a_func(p1=1):\n pass\na_func()\n') + self._inline2(self.mod, self.mod.read().index('p1') + 1) + self.assertEquals('def a_func(p1=1):\n pass\na_func()\n', self.mod.read()) + + def test_simple_inlining_after_extra_indented_lines(self): + self.mod.write('def a_func():\n for i in range(10):\n pass\n' + 'if True:\n pass\na_func()\n') + self._inline2(self.mod, self.mod.read().index('a_func') + 1) + self.assertEquals('if True:\n pass\nfor i in range(10):\n pass\n', + self.mod.read()) + + def test_inlining_a_function_with_pydoc(self): + self.mod.write('def a_func():\n """docs"""\n a = 1\na_func()') + self._inline2(self.mod, self.mod.read().index('a_func') + 1) + self.assertEquals('a = 1\n', self.mod.read()) + + def test_inlining_methods(self): + self.mod.write("class A(object):\n name = 'hey'\n" + " def get_name(self):\n return self.name\n" + "a = A()\nname = a.get_name()\n") + self._inline2(self.mod, self.mod.read().rindex('get_name') + 1) + self.assertEquals("class A(object):\n name = 'hey'\n" + "a = A()\nname = a.name\n", self.mod.read()) + + def test_simple_returns_with_backslashes(self): + self.mod.write('def a_func():\n return 1\\\n + 2\na = a_func()\n') + self._inline2(self.mod, self.mod.read().index('a_func') + 1) + self.assertEquals('a = 1 + 2\n', self.mod.read()) + + def test_a_function_with_pass_body(self): + self.mod.write('def a_func():\n print(1)\na = a_func()\n') + self._inline2(self.mod, self.mod.read().index('a_func') + 1) + self.assertEquals('print(1)\na = None\n', self.mod.read()) + + def test_inlining_the_last_method_of_a_class(self): + self.mod.write('class A(object):\n' + ' def a_func(self):\n pass\n') + self._inline2(self.mod, self.mod.read().rindex('a_func') + 1) + self.assertEquals('class A(object):\n pass\n', + self.mod.read()) + + def test_adding_needed_imports_in_the_dest_module(self): + self.mod.write('import sys\n\ndef ver():\n print(sys.version)\n') + self.mod2.write('import mod\n\nmod.ver()') + self._inline2(self.mod, self.mod.read().index('ver') + 1) + self.assertEquals('import mod\nimport sys\n\nprint(sys.version)\n', + self.mod2.read()) + + def test_adding_needed_imports_in_the_dest_module_removing_selfs(self): + self.mod.write('import mod2\n\ndef f():\n print(mod2.var)\n') + self.mod2.write('import mod\n\nvar = 1\nmod.f()\n') + self._inline2(self.mod, self.mod.read().index('f(') + 1) + self.assertEquals('import mod\n\nvar = 1\nprint(var)\n', + self.mod2.read()) + + def test_handling_relative_imports_when_inlining(self): + pkg = testutils.create_package(self.project, 'pkg') + mod3 = testutils.create_module(self.project, 'mod3', pkg) + mod4 = testutils.create_module(self.project, 'mod4', pkg) + mod4.write('var = 1\n') + mod3.write('from . import mod4\n\ndef f():\n print(mod4.var)\n') + self.mod.write('import pkg.mod3\n\npkg.mod3.f()\n') + self._inline2(self.mod, self.mod.read().index('f(') + 1) + # Cannot determine the exact import + self.assertTrue('\n\nprint(mod4.var)\n' in self.mod.read()) + + def test_adding_needed_imports_for_elements_in_source(self): + self.mod.write('def f1():\n return f2()\ndef f2():\n return 1\n') + self.mod2.write('import mod\n\nprint(mod.f1())\n') + self._inline2(self.mod, self.mod.read().index('f1') + 1) + self.assertEquals('import mod\nfrom mod import f2\n\nprint(f2())\n', + self.mod2.read()) + + def test_relative_imports_and_changing_inlining_body(self): + pkg = testutils.create_package(self.project, 'pkg') + mod3 = testutils.create_module(self.project, 'mod3', pkg) + mod4 = testutils.create_module(self.project, 'mod4', pkg) + mod4.write('var = 1\n') + mod3.write('import mod4\n\ndef f():\n print(mod4.var)\n') + self.mod.write('import pkg.mod3\n\npkg.mod3.f()\n') + self._inline2(self.mod, self.mod.read().index('f(') + 1) + self.assertEquals( + 'import pkg.mod3\nimport pkg.mod4\n\nprint(pkg.mod4.var)\n', + self.mod.read()) + + def test_inlining_with_different_returns(self): + self.mod.write('def f(p):\n return p\n' + 'print(f(1))\nprint(f(2))\nprint(f(1))\n') + self._inline2(self.mod, self.mod.read().index('f(') + 1) + self.assertEquals('print(1)\nprint(2)\nprint(1)\n', + self.mod.read()) + + def test_not_removing_definition_for_variables(self): + code = 'a_var = 10\nanother_var = a_var\n' + refactored = self._inline(code, code.index('a_var') + 1, + remove=False) + self.assertEquals('a_var = 10\nanother_var = 10\n', refactored) + + def test_not_removing_definition_for_methods(self): + code = 'def func():\n print(1)\n\nfunc()\n' + refactored = self._inline(code, code.index('func') + 1, + remove=False) + self.assertEquals('def func():\n print(1)\n\nprint(1)\n', + refactored) + + def test_only_current_for_methods(self): + code = 'def func():\n print(1)\n\nfunc()\nfunc()\n' + refactored = self._inline(code, code.rindex('func') + 1, + remove=False, only_current=True) + self.assertEquals('def func():\n print(1)\n\nfunc()\nprint(1)\n', + refactored) + + def test_only_current_for_variables(self): + code = 'one = 1\n\na = one\nb = one\n' + refactored = self._inline(code, code.rindex('one') + 1, + remove=False, only_current=True) + self.assertEquals('one = 1\n\na = one\nb = 1\n', refactored) + + def test_inlining_one_line_functions(self): + code = 'def f(): return 1\nvar = f()\n' + refactored = self._inline(code, code.rindex('f')) + self.assertEquals('var = 1\n', refactored) + + def test_inlining_one_line_functions_with_breaks(self): + code = 'def f(\np): return p\nvar = f(1)\n' + refactored = self._inline(code, code.rindex('f')) + self.assertEquals('var = 1\n', refactored) + + def test_inlining_one_line_functions_with_breaks2(self): + code = 'def f(\n): return 1\nvar = f()\n' + refactored = self._inline(code, code.rindex('f')) + self.assertEquals('var = 1\n', refactored) + + def test_resources_parameter(self): + self.mod.write('def a_func():\n print(1)\n') + mod1 = testutils.create_module(self.project, 'mod1') + mod1.write('import mod\nmod.a_func()\n') + self._inline2(self.mod, self.mod.read().index('a_func'), + resources=[self.mod]) + self.assertEquals('', self.mod.read()) + self.assertEquals('import mod\nmod.a_func()\n', mod1.read()) + + def test_inlining_parameters(self): + code = 'def f(p=1):\n pass\nf()\n' + result = self._inline(code, code.index('p')) + self.assertEquals('def f(p=1):\n pass\nf(1)\n', result) + + def test_inlining_function_with_line_breaks_in_args(self): + code = 'def f(p): return p\nvar = f(1 +\n1)\n' + refactored = self._inline(code, code.rindex('f')) + self.assertEquals('var = 1 + 1\n', refactored) + + def test_inlining_variables_before_comparison(self): + code = 'start = 1\nprint(start <= 2)\n' + refactored = self._inline(code, code.index('start')) + self.assertEquals('print(1 <= 2)\n', refactored) + + def test_inlining_variables_in_other_modules(self): + self.mod.write('myvar = 1\n') + self.mod2.write('import mod\nprint(mod.myvar)\n') + self._inline2(self.mod, 2) + self.assertEquals('import mod\nprint(1)\n', self.mod2.read()) + + def test_inlining_variables_and_back_importing(self): + self.mod.write('mainvar = 1\nmyvar = mainvar\n') + self.mod2.write('import mod\nprint(mod.myvar)\n') + self._inline2(self.mod, self.mod.read().index('myvar')) + expected = 'import mod\n' \ + 'from mod import mainvar\n' \ + 'print(mainvar)\n' + self.assertEquals(expected, self.mod2.read()) + + def test_inlining_variables_and_importing_used_imports(self): + self.mod.write('import sys\nmyvar = sys.argv\n') + self.mod2.write('import mod\nprint(mod.myvar)\n') + self._inline2(self.mod, self.mod.read().index('myvar')) + expected = 'import mod\n' \ + 'import sys\n' \ + 'print(sys.argv)\n' + self.assertEquals(expected, self.mod2.read()) + + def test_inlining_variables_and_removing_old_froms(self): + self.mod.write('var = 1\n') + self.mod2.write('from mod import var\nprint(var)\n') + self._inline2(self.mod2, self.mod2.read().rindex('var')) + self.assertEquals('print(1)\n', self.mod2.read()) + + def test_inlining_method_and_removing_old_froms(self): + self.mod.write('def f(): return 1\n') + self.mod2.write('from mod import f\nprint(f())\n') + self._inline2(self.mod2, self.mod2.read().rindex('f')) + self.assertEquals('print(1)\n', self.mod2.read()) + + def test_inlining_functions_in_other_modules_and_only_current(self): + code1 = 'def f():\n' \ + ' return 1\n' \ + 'print(f())\n' + code2 = 'import mod\n' \ + 'print(mod.f())\n' \ + 'print(mod.f())\n' + self.mod.write(code1) + self.mod2.write(code2) + self._inline2(self.mod2, self.mod2.read().rindex('f'), + remove=False, only_current=True) + expected2 = 'import mod\n' \ + 'print(mod.f())\n' \ + 'print(1)\n' + self.assertEquals(code1, self.mod.read()) + self.assertEquals(expected2, self.mod2.read()) + + def test_inlining_variables_in_other_modules_and_only_current(self): + code1 = 'var = 1\n' \ + 'print(var)\n' + code2 = 'import mod\n' \ + 'print(mod.var)\n' \ + 'print(mod.var)\n' + self.mod.write(code1) + self.mod2.write(code2) + self._inline2(self.mod2, self.mod2.read().rindex('var'), + remove=False, only_current=True) + expected2 = 'import mod\n' \ + 'print(mod.var)\n' \ + 'print(1)\n' + self.assertEquals(code1, self.mod.read()) + self.assertEquals(expected2, self.mod2.read()) + + +def suite(): + result = unittest.TestSuite() + result.addTests(unittest.makeSuite(InlineTest)) + return result + + +if __name__ == '__main__': + unittest.main() diff -r e30544496575 -r 48cacfdc2ca6 vim/sadness/ropevim/src/rope/ropetest/refactor/movetest.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vim/sadness/ropevim/src/rope/ropetest/refactor/movetest.py Wed Oct 06 12:30:46 2010 -0400 @@ -0,0 +1,507 @@ +import unittest + +from rope.base import exceptions +from rope.refactor import move +from ropetest import testutils + + +class MoveRefactoringTest(unittest.TestCase): + + def setUp(self): + super(MoveRefactoringTest, self).setUp() + self.project = testutils.sample_project() + self.pycore = self.project.pycore + self.mod1 = testutils.create_module(self.project, 'mod1') + self.mod2 = testutils.create_module(self.project, 'mod2') + self.mod3 = testutils.create_module(self.project, 'mod3') + self.pkg = testutils.create_package(self.project, 'pkg') + self.mod4 = testutils.create_module(self.project, 'mod4', self.pkg) + self.mod5 = testutils.create_module(self.project, 'mod5', self.pkg) + + def tearDown(self): + testutils.remove_project(self.project) + super(MoveRefactoringTest, self).tearDown() + + def _move(self, resource, offset, dest_resource): + changes = move.create_move(self.project, resource, offset).\ + get_changes(dest_resource) + self.project.do(changes) + + def test_simple_moving(self): + self.mod1.write('class AClass(object):\n pass\n') + self._move(self.mod1, self.mod1.read().index('AClass') + 1, + self.mod2) + self.assertEquals('', self.mod1.read()) + self.assertEquals('class AClass(object):\n pass\n', + self.mod2.read()) + + def test_changing_other_modules_adding_normal_imports(self): + self.mod1.write('class AClass(object):\n pass\n') + self.mod3.write('import mod1\na_var = mod1.AClass()\n') + self._move(self.mod1, self.mod1.read().index('AClass') + 1, + self.mod2) + self.assertEquals('import mod1\nimport mod2\na_var = mod2.AClass()\n', + self.mod3.read()) + + def test_changing_other_modules_removing_from_imports(self): + self.mod1.write('class AClass(object):\n pass\n') + self.mod3.write('from mod1 import AClass\na_var = AClass()\n') + self._move(self.mod1, self.mod1.read().index('AClass') + 1, + self.mod2) + self.assertEquals('import mod2\na_var = mod2.AClass()\n', + self.mod3.read()) + + def test_changing_source_module(self): + self.mod1.write('class AClass(object):\n pass\na_var = AClass()\n') + self._move(self.mod1, self.mod1.read().index('AClass') + 1, + self.mod2) + self.assertEquals('import mod2\na_var = mod2.AClass()\n', + self.mod1.read()) + + def test_changing_destination_module(self): + self.mod1.write('class AClass(object):\n pass\n') + self.mod2.write('from mod1 import AClass\na_var = AClass()\n') + self._move(self.mod1, self.mod1.read().index('AClass') + 1, + self.mod2) + self.assertEquals('class AClass(object):\n pass\na_var = AClass()\n', + self.mod2.read()) + + @testutils.assert_raises(exceptions.RefactoringError) + def test_folder_destination(self): + folder = self.project.root.create_folder('folder') + self.mod1.write('class AClass(object):\n pass\n') + self._move(self.mod1, self.mod1.read().index('AClass') + 1, folder) + + @testutils.assert_raises(exceptions.RefactoringError) + def test_raising_exception_for_moving_non_global_elements(self): + self.mod1.write('def a_func():\n class AClass(object):\n pass\n') + self._move(self.mod1, self.mod1.read().index('AClass') + 1, + self.mod2) + + @testutils.assert_raises(exceptions.RefactoringError) + def test_raising_exception_for_moving_global_elements_to_the_same_module(self): + self.mod1.write('def a_func():\n pass\n') + self._move(self.mod1, self.mod1.read().index('a_func'), self.mod1) + + def test_moving_used_imports_to_destination_module(self): + self.mod3.write('a_var = 10') + code = 'import mod3\n' \ + 'from mod3 import a_var\n' \ + 'def a_func():\n' \ + ' print(mod3, a_var)\n' + self.mod1.write(code) + self._move(self.mod1, code.index('a_func') + 1, self.mod2) + expected = 'import mod3\n' \ + 'from mod3 import a_var\n\n\n' \ + 'def a_func():\n print(mod3, a_var)\n' + self.assertEquals(expected, self.mod2.read()) + + def test_moving_used_names_to_destination_module2(self): + code = 'a_var = 10\n' \ + 'def a_func():\n' \ + ' print(a_var)\n' + self.mod1.write(code) + self._move(self.mod1, code.index('a_func') + 1, self.mod2) + self.assertEquals('a_var = 10\n', self.mod1.read()) + expected = 'from mod1 import a_var\n\n\n' \ + 'def a_func():\n' \ + ' print(a_var)\n' + self.assertEquals(expected, self.mod2.read()) + + def test_moving_used_underlined_names_to_destination_module(self): + code = '_var = 10\n' \ + 'def a_func():\n' \ + ' print(_var)\n' + self.mod1.write(code) + self._move(self.mod1, code.index('a_func') + 1, self.mod2) + expected = 'from mod1 import _var\n\n\n' \ + 'def a_func():\n' \ + ' print(_var)\n' + self.assertEquals(expected, self.mod2.read()) + + def test_moving_and_used_relative_imports(self): + code = 'import mod5\n' \ + 'def a_func():\n' \ + ' print(mod5)\n' + self.mod4.write(code) + self._move(self.mod4, code.index('a_func') + 1, self.mod1) + expected = 'import pkg.mod5\n\n\n' \ + 'def a_func():\n' \ + ' print(pkg.mod5)\n' + self.assertEquals(expected, self.mod1.read()) + + def test_moving_modules(self): + code = 'import mod1\nprint(mod1)' + self.mod2.write(code) + self._move(self.mod2, code.index('mod1') + 1, self.pkg) + expected = 'import pkg.mod1\nprint(pkg.mod1)' + self.assertEquals(expected, self.mod2.read()) + self.assertTrue(not self.mod1.exists() and + self.pycore.find_module('pkg.mod1') is not None) + + def test_moving_modules_and_removing_out_of_date_imports(self): + code = 'import pkg.mod4\nprint(pkg.mod4)' + self.mod2.write(code) + self._move(self.mod2, code.index('mod4') + 1, self.project.root) + expected = 'import mod4\nprint(mod4)' + self.assertEquals(expected, self.mod2.read()) + self.assertTrue(self.pycore.find_module('mod4') is not None) + + def test_moving_modules_and_removing_out_of_date_froms(self): + code = 'from pkg import mod4\nprint(mod4)' + self.mod2.write(code) + self._move(self.mod2, code.index('mod4') + 1, self.project.root) + self.assertEquals('import mod4\nprint(mod4)', self.mod2.read()) + + def test_moving_modules_and_removing_out_of_date_froms2(self): + self.mod4.write('a_var = 10') + code = 'from pkg.mod4 import a_var\nprint(a_var)\n' + self.mod2.write(code) + self._move(self.mod2, code.index('mod4') + 1, self.project.root) + expected = 'from mod4 import a_var\nprint(a_var)\n' + self.assertEquals(expected, self.mod2.read()) + + def test_moving_modules_and_relative_import(self): + self.mod4.write('import mod5\nprint(mod5)\n') + code = 'import pkg.mod4\nprint(pkg.mod4)' + self.mod2.write(code) + self._move(self.mod2, code.index('mod4') + 1, self.project.root) + moved = self.pycore.find_module('mod4') + expected = 'import pkg.mod5\nprint(pkg.mod5)\n' + self.assertEquals(expected, moved.read()) + + def test_moving_packages(self): + pkg2 = testutils.create_package(self.project, 'pkg2') + code = 'import pkg.mod4\nprint(pkg.mod4)' + self.mod1.write(code) + self._move(self.mod1, code.index('pkg') + 1, pkg2) + self.assertFalse(self.pkg.exists()) + self.assertTrue(self.pycore.find_module('pkg2.pkg.mod4') is not None) + self.assertTrue(self.pycore.find_module('pkg2.pkg.mod4') is not None) + self.assertTrue(self.pycore.find_module('pkg2.pkg.mod5') is not None) + expected = 'import pkg2.pkg.mod4\nprint(pkg2.pkg.mod4)' + self.assertEquals(expected, self.mod1.read()) + + def test_moving_modules_with_self_imports(self): + self.mod1.write('import mod1\nprint(mod1)\n') + self.mod2.write('import mod1\n') + self._move(self.mod2, self.mod2.read().index('mod1') + 1, self.pkg) + moved = self.pycore.find_module('pkg.mod1') + self.assertEquals('import pkg.mod1\nprint(pkg.mod1)\n', moved.read()) + + def test_moving_funtions_to_imported_module(self): + code = 'import mod1\n' \ + 'def a_func():\n' \ + ' var = mod1.a_var\n' + self.mod1.write('a_var = 1\n') + self.mod2.write(code) + self._move(self.mod2, code.index('a_func') + 1, self.mod1) + expected = 'def a_func():\n' \ + ' var = a_var\n' \ + 'a_var = 1\n' + self.assertEquals(expected, self.mod1.read()) + + def test_moving_resources_using_move_module_refactoring(self): + self.mod1.write('a_var = 1') + self.mod2.write('import mod1\nmy_var = mod1.a_var\n') + mover = move.create_move(self.project, self.mod1) + mover.get_changes(self.pkg).do() + expected = 'import pkg.mod1\nmy_var = pkg.mod1.a_var\n' + self.assertEquals(expected, self.mod2.read()) + self.assertTrue(self.pkg.get_child('mod1.py') is not None) + + def test_moving_resources_using_move_module_for_packages(self): + self.mod1.write('import pkg\nmy_pkg = pkg') + pkg2 = testutils.create_package(self.project, 'pkg2') + mover = move.create_move(self.project, self.pkg) + mover.get_changes(pkg2).do() + expected = 'import pkg2.pkg\nmy_pkg = pkg2.pkg' + self.assertEquals(expected, self.mod1.read()) + self.assertTrue(pkg2.get_child('pkg') is not None) + + def test_moving_resources_using_move_module_for_init_dot_py(self): + self.mod1.write('import pkg\nmy_pkg = pkg') + pkg2 = testutils.create_package(self.project, 'pkg2') + init = self.pkg.get_child('__init__.py') + mover = move.create_move(self.project, init) + mover.get_changes(pkg2).do() + self.assertEquals('import pkg2.pkg\nmy_pkg = pkg2.pkg', + self.mod1.read()) + self.assertTrue(pkg2.get_child('pkg') is not None) + + def test_moving_module_and_star_imports(self): + self.mod1.write('a_var = 1') + self.mod2.write('from mod1 import *\na = a_var\n') + mover = move.create_move(self.project, self.mod1) + mover.get_changes(self.pkg).do() + self.assertEquals('from pkg.mod1 import *\na = a_var\n', + self.mod2.read()) + + def test_moving_module_and_not_removing_blanks_after_imports(self): + self.mod4.write('a_var = 1') + self.mod2.write('from pkg import mod4\n' + 'import os\n\n\nprint(mod4.a_var)\n') + mover = move.create_move(self.project, self.mod4) + mover.get_changes(self.project.root).do() + self.assertEquals('import os\nimport mod4\n\n\n' + 'print(mod4.a_var)\n', self.mod2.read()) + + @testutils.assert_raises(exceptions.RefactoringError) + def test_moving_module_refactoring_and_nonexistent_destinations(self): + self.mod4.write('a_var = 1') + self.mod2.write('from pkg import mod4\n' + 'import os\n\n\nprint(mod4.a_var)\n') + mover = move.create_move(self.project, self.mod4) + mover.get_changes(None).do() + + def test_moving_methods_choosing_the_correct_class(self): + code = 'class A(object):\n def a_method(self):\n pass\n' + self.mod1.write(code) + mover = move.create_move(self.project, self.mod1, code.index('a_method')) + self.assertTrue(isinstance(mover, move.MoveMethod)) + + def test_moving_methods_getting_new_method_for_empty_methods(self): + code = 'class A(object):\n def a_method(self):\n pass\n' + self.mod1.write(code) + mover = move.create_move(self.project, self.mod1, + code.index('a_method')) + self.assertEquals('def new_method(self):\n pass\n', + mover.get_new_method('new_method')) + + def test_moving_methods_getting_new_method_for_constant_methods(self): + code = 'class A(object):\n def a_method(self):\n return 1\n' + self.mod1.write(code) + mover = move.create_move(self.project, self.mod1, + code.index('a_method')) + self.assertEquals('def new_method(self):\n return 1\n', + mover.get_new_method('new_method')) + + def test_moving_methods_getting_new_method_passing_simple_paremters(self): + code = 'class A(object):\n' \ + ' def a_method(self, p):\n return p\n' + self.mod1.write(code) + mover = move.create_move(self.project, self.mod1, + code.index('a_method')) + self.assertEquals('def new_method(self, p):\n return p\n', + mover.get_new_method('new_method')) + + def test_moving_methods_getting_new_method_using_main_object(self): + code = 'class A(object):\n attr = 1\n' \ + ' def a_method(host):\n return host.attr\n' + self.mod1.write(code) + mover = move.create_move(self.project, self.mod1, + code.index('a_method')) + self.assertEquals('def new_method(self, host):\n return host.attr\n', + mover.get_new_method('new_method')) + + def test_moving_methods_getting_new_method_renaming_main_object(self): + code = 'class A(object):\n attr = 1\n' \ + ' def a_method(self):\n return self.attr\n' + self.mod1.write(code) + mover = move.create_move(self.project, self.mod1, + code.index('a_method')) + self.assertEquals('def new_method(self, host):\n return host.attr\n', + mover.get_new_method('new_method')) + + def test_moving_methods_gettin_new_method_with_keyword_arguments(self): + code = 'class A(object):\n attr = 1\n' \ + ' def a_method(self, p=None):\n return p\n' + self.mod1.write(code) + mover = move.create_move(self.project, self.mod1, + code.index('a_method')) + self.assertEquals('def new_method(self, p=None):\n return p\n', + mover.get_new_method('new_method')) + + def test_moving_methods_gettin_new_method_with_many_kinds_arguments(self): + code = 'class A(object):\n attr = 1\n' \ + ' def a_method(self, p1, *args, **kwds):\n' \ + ' return self.attr\n' + self.mod1.write(code) + mover = move.create_move(self.project, self.mod1, + code.index('a_method')) + expected = 'def new_method(self, host, p1, *args, **kwds):\n' \ + ' return host.attr\n' + self.assertEquals(expected, mover.get_new_method('new_method')) + + def test_moving_methods_getting_new_method_for_multi_line_methods(self): + code = 'class A(object):\n' \ + ' def a_method(self):\n' \ + ' a = 2\n' \ + ' return a\n' + self.mod1.write(code) + mover = move.create_move(self.project, self.mod1, + code.index('a_method')) + self.assertEquals( + 'def new_method(self):\n a = 2\n return a\n', + mover.get_new_method('new_method')) + + def test_moving_methods_getting_old_method_for_constant_methods(self): + self.mod2.write('class B(object):\n pass\n') + code = 'import mod2\n\n' \ + 'class A(object):\n' \ + ' attr = mod2.B()\n' \ + ' def a_method(self):\n' \ + ' return 1\n' + self.mod1.write(code) + mover = move.create_move(self.project, self.mod1, + code.index('a_method')) + mover.get_changes('attr', 'new_method').do() + expected = 'import mod2\n\n' \ + 'class A(object):\n' \ + ' attr = mod2.B()\n' \ + ' def a_method(self):\n' \ + ' return self.attr.new_method()\n' + self.assertEquals(expected, self.mod1.read()) + + def test_moving_methods_getting_getting_changes_for_goal_class(self): + self.mod2.write('class B(object):\n var = 1\n') + code = 'import mod2\n\n' \ + 'class A(object):\n' \ + ' attr = mod2.B()\n' \ + ' def a_method(self):\n' \ + ' return 1\n' + self.mod1.write(code) + mover = move.create_move(self.project, self.mod1, + code.index('a_method')) + mover.get_changes('attr', 'new_method').do() + expected = 'class B(object):\n' \ + ' var = 1\n\n\n' \ + ' def new_method(self):\n' \ + ' return 1\n' + self.assertEquals(expected, self.mod2.read()) + + def test_moving_methods_getting_getting_changes_for_goal_class2(self): + code = 'class B(object):\n var = 1\n\n' \ + 'class A(object):\n attr = B()\n' \ + ' def a_method(self):\n return 1\n' + self.mod1.write(code) + mover = move.create_move(self.project, self.mod1, + code.index('a_method')) + mover.get_changes('attr', 'new_method').do() + self.assertEquals( + 'class B(object):\n var = 1\n\n\n' + ' def new_method(self):\n' + ' return 1\n\n' + 'class A(object):\n attr = B()\n' + ' def a_method(self):\n' + ' return self.attr.new_method()\n', + self.mod1.read()) + + @testutils.assert_raises(exceptions.RefactoringError) + def test_moving_methods_and_nonexistent_attributes(self): + code = 'class A(object):\n' \ + ' def a_method(self):\n return 1\n' + self.mod1.write(code) + mover = move.create_move(self.project, self.mod1, + code.index('a_method')) + mover.get_changes('x', 'new_method') + + @testutils.assert_raises(exceptions.RefactoringError) + def test_unknown_attribute_type(self): + code = 'class A(object):\n attr = 1\n' \ + ' def a_method(self):\n return 1\n' + self.mod1.write(code) + mover = move.create_move(self.project, self.mod1, + code.index('a_method')) + mover.get_changes('attr', 'new_method') + + def test_moving_methods_and_moving_used_imports(self): + self.mod2.write('class B(object):\n var = 1\n') + code = 'import sys\nimport mod2\n\n' \ + 'class A(object):\n' \ + ' attr = mod2.B()\n' \ + ' def a_method(self):\n' \ + ' return sys.version\n' + self.mod1.write(code) + mover = move.create_move(self.project, self.mod1, + code.index('a_method')) + mover.get_changes('attr', 'new_method').do() + code = 'import sys\n' \ + 'class B(object):\n' \ + ' var = 1\n\n\n' \ + ' def new_method(self):\n' \ + ' return sys.version\n' + self.assertEquals(code, self.mod2.read()) + + def test_moving_methods_getting_getting_changes_for_goal_class3(self): + self.mod2.write('class B(object):\n pass\n') + code = 'import mod2\n\n' \ + 'class A(object):\n' \ + ' attr = mod2.B()\n' \ + ' def a_method(self):\n' \ + ' return 1\n' + self.mod1.write(code) + mover = move.create_move(self.project, self.mod1, + code.index('a_method')) + mover.get_changes('attr', 'new_method').do() + expected = 'class B(object):\n\n' \ + ' def new_method(self):\n' \ + ' return 1\n' + self.assertEquals(expected, self.mod2.read()) + + def test_moving_methods_and_source_class_with_parameters(self): + self.mod2.write('class B(object):\n pass\n') + code = 'import mod2\n\n' \ + 'class A(object):\n' \ + ' attr = mod2.B()\n' \ + ' def a_method(self, p):\n return p\n' + self.mod1.write(code) + mover = move.create_move(self.project, self.mod1, + code.index('a_method')) + mover.get_changes('attr', 'new_method').do() + expected1 = 'import mod2\n\n' \ + 'class A(object):\n' \ + ' attr = mod2.B()\n' \ + ' def a_method(self, p):\n' \ + ' return self.attr.new_method(p)\n' + self.assertEquals(expected1, self.mod1.read()) + expected2 = 'class B(object):\n\n' \ + ' def new_method(self, p):\n' \ + ' return p\n' + self.assertEquals(expected2, self.mod2.read()) + + def test_moving_globals_to_a_module_with_only_docstrings(self): + self.mod1.write('import sys\n\n\ndef f():\n print(sys.version)\n') + self.mod2.write('"""doc\n\nMore docs ...\n\n"""\n') + mover = move.create_move(self.project, self.mod1, + self.mod1.read().index('f()') + 1) + self.project.do(mover.get_changes(self.mod2)) + self.assertEquals( + '"""doc\n\nMore docs ...\n\n"""\n' + 'import sys\n\n\ndef f():\n print(sys.version)\n', + self.mod2.read()) + + def test_moving_globals_to_a_module_with_only_docstrings2(self): + code = 'import os\n' \ + 'import sys\n\n\n' \ + 'def f():\n' \ + ' print(sys.version, os.path)\n' + self.mod1.write(code) + self.mod2.write('"""doc\n\nMore docs ...\n\n"""\n') + mover = move.create_move(self.project, self.mod1, + self.mod1.read().index('f()') + 1) + self.project.do(mover.get_changes(self.mod2)) + expected = '"""doc\n\nMore docs ...\n\n"""\n' \ + 'import os\n' \ + 'import sys\n\n\n' \ + 'def f():\n' \ + ' print(sys.version, os.path)\n' + self.assertEquals(expected, self.mod2.read()) + + def test_moving_a_global_when_it_is_used_after_a_multiline_str(self): + code = 'def f():\n pass\ns = """\\\n"""\nr = f()\n' + self.mod1.write(code) + mover = move.create_move(self.project, self.mod1, + code.index('f()') + 1) + self.project.do(mover.get_changes(self.mod2)) + expected = 'import mod2\ns = """\\\n"""\nr = mod2.f()\n' + self.assertEquals(expected, self.mod1.read()) + + @testutils.assert_raises(exceptions.RefactoringError) + def test_raising_an_exception_when_moving_non_package_folders(self): + dir = self.project.root.create_folder('dir') + mover = move.create_move(self.project, dir) + + +if __name__ == '__main__': + unittest.main() diff -r e30544496575 -r 48cacfdc2ca6 vim/sadness/ropevim/src/rope/ropetest/refactor/multiprojecttest.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vim/sadness/ropevim/src/rope/ropetest/refactor/multiprojecttest.py Wed Oct 06 12:30:46 2010 -0400 @@ -0,0 +1,72 @@ +import unittest + +import rope.base.codeanalyze +import rope.refactor.occurrences +from rope.refactor import multiproject, rename, move +from ropetest import testutils + + +class MultiProjectRefactoringTest(unittest.TestCase): + + def setUp(self): + super(MultiProjectRefactoringTest, self).setUp() + self.project1 = testutils.sample_project(foldername='testproject1') + self.project2 = testutils.sample_project(foldername='testproject2') + self.mod1 = self.project1.root.create_file('mod1.py') + self.other = self.project1.root.create_file('other.py') + self.mod2 = self.project2.root.create_file('mod2.py') + + def tearDown(self): + testutils.remove_project(self.project1) + testutils.remove_project(self.project2) + super(MultiProjectRefactoringTest, self).tearDown() + + def test_trivial_rename(self): + self.mod1.write('var = 1\n') + refactoring = multiproject.MultiProjectRefactoring( + rename.Rename, []) + renamer = refactoring(self.project1, self.mod1, 1) + multiproject.perform(renamer.get_all_changes('newvar')) + self.assertEquals('newvar = 1\n', self.mod1.read()) + + def test_rename(self): + self.mod1.write('var = 1\n') + self.mod2.write('import mod1\nmyvar = mod1.var\n') + refactoring = multiproject.MultiProjectRefactoring( + rename.Rename, [self.project2]) + renamer = refactoring(self.project1, self.mod1, 1) + multiproject.perform(renamer.get_all_changes('newvar')) + self.assertEquals('newvar = 1\n', self.mod1.read()) + self.assertEquals('import mod1\nmyvar = mod1.newvar\n', + self.mod2.read()) + + def test_move(self): + self.mod1.write('def a_func():\n pass\n') + self.mod2.write('import mod1\nmyvar = mod1.a_func()\n') + refactoring = multiproject.MultiProjectRefactoring( + move.create_move, [self.project2]) + renamer = refactoring(self.project1, self.mod1, + self.mod1.read().index('_func')) + multiproject.perform(renamer.get_all_changes(self.other)) + self.assertEquals('', self.mod1.read()) + self.assertEquals('def a_func():\n pass\n', self.other.read()) + self.assertEquals( + 'import mod1\nimport other\nmyvar = other.a_func()\n', + self.mod2.read()) + + def test_rename_from_the_project_not_containing_the_change(self): + self.project2.get_prefs().add('python_path', self.project1.address) + self.mod1.write('var = 1\n') + self.mod2.write('import mod1\nmyvar = mod1.var\n') + refactoring = multiproject.MultiProjectRefactoring( + rename.Rename, [self.project1]) + renamer = refactoring(self.project2, self.mod2, + self.mod2.read().rindex('var')) + multiproject.perform(renamer.get_all_changes('newvar')) + self.assertEquals('newvar = 1\n', self.mod1.read()) + self.assertEquals('import mod1\nmyvar = mod1.newvar\n', + self.mod2.read()) + + +if __name__ == '__main__': + unittest.main() diff -r e30544496575 -r 48cacfdc2ca6 vim/sadness/ropevim/src/rope/ropetest/refactor/patchedasttest.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vim/sadness/ropevim/src/rope/ropetest/refactor/patchedasttest.py Wed Oct 06 12:30:46 2010 -0400 @@ -0,0 +1,832 @@ +import unittest + +from rope.base import ast +from rope.refactor import patchedast +from ropetest import testutils + + +class PatchedASTTest(unittest.TestCase): + + def setUp(self): + super(PatchedASTTest, self).setUp() + + def tearDown(self): + super(PatchedASTTest, self).tearDown() + + def test_integer_literals_and_region(self): + source = 'a = 10\n' + ast = patchedast.get_patched_ast(source, True) + checker = _ResultChecker(self, ast) + start = source.index('10') + checker.check_region('Num', start, start + 2) + + def test_integer_literals_and_sorted_children(self): + source = 'a = 10\n' + ast = patchedast.get_patched_ast(source, True) + checker = _ResultChecker(self, ast) + start = source.index('10') + checker.check_children('Num', ['10']) + + def test_ass_name_node(self): + source = 'a = 10\n' + ast = patchedast.get_patched_ast(source, True) + checker = _ResultChecker(self, ast) + start = source.index('a') + checker.check_region('Name', start, start + 1) + checker.check_children('Name', ['a']) + + def test_assign_node(self): + source = 'a = 10\n' + ast = patchedast.get_patched_ast(source, True) + checker = _ResultChecker(self, ast) + start = source.index('a') + checker.check_region('Assign', 0, len(source) - 1) + checker.check_children( + 'Assign', ['Name', ' ', '=', ' ', 'Num']) + + def test_add_node(self): + source = '1 + 2\n' + ast = patchedast.get_patched_ast(source, True) + checker = _ResultChecker(self, ast) + checker.check_region('BinOp', 0, len(source) - 1) + checker.check_children( + 'BinOp', ['Num', ' ', '+', ' ', 'Num']) + + def test_lshift_node(self): + source = '1 << 2\n' + ast = patchedast.get_patched_ast(source, True) + checker = _ResultChecker(self, ast) + checker.check_region('BinOp', 0, len(source) - 1) + checker.check_children( + 'BinOp', ['Num', ' ', '<<', ' ', 'Num']) + + def test_and_node(self): + source = 'True and True\n' + ast = patchedast.get_patched_ast(source, True) + checker = _ResultChecker(self, ast) + checker.check_region('BoolOp', 0, len(source) - 1) + checker.check_children( + 'BoolOp', ['Name', ' ', 'and', ' ', 'Name']) + + def test_basic_closing_parens(self): + source = '1 + (2)\n' + ast = patchedast.get_patched_ast(source, True) + checker = _ResultChecker(self, ast) + checker.check_region('BinOp', 0, len(source) - 1) + checker.check_children( + 'BinOp', ['Num', ' ', '+', ' (', 'Num', ')']) + + def test_basic_opening_parens(self): + source = '(1) + 2\n' + ast = patchedast.get_patched_ast(source, True) + checker = _ResultChecker(self, ast) + checker.check_region('BinOp', 0, len(source) - 1) + checker.check_children( + 'BinOp', ['(', 'Num', ') ', '+', ' ', 'Num']) + + def test_basic_opening_biway(self): + source = '(1) + (2)\n' + ast = patchedast.get_patched_ast(source, True) + checker = _ResultChecker(self, ast) + checker.check_region('BinOp', 0, len(source) - 1) + checker.check_children( + 'BinOp', ['(', 'Num', ') ', '+', ' (', 'Num', ')']) + + def test_basic_opening_double(self): + source = '1 + ((2))\n' + ast = patchedast.get_patched_ast(source, True) + checker = _ResultChecker(self, ast) + checker.check_region('BinOp', 0, len(source) - 1) + checker.check_children( + 'BinOp', ['Num', ' ', '+', ' ((', 'Num', '))']) + + def test_handling_comments(self): + source = '(1 + #(\n2)\n' + ast = patchedast.get_patched_ast(source, True) + checker = _ResultChecker(self, ast) + checker.check_children( + 'BinOp', ['Num', ' ', '+', ' #(\n', 'Num']) + + def test_handling_parens_with_spaces(self): + source = '1 + (2\n )\n' + ast = patchedast.get_patched_ast(source, True) + checker = _ResultChecker(self, ast) + checker.check_children( + 'BinOp', ['Num', ' ', '+', ' (', 'Num', '\n )']) + + def test_handling_strings(self): + source = '1 + "("\n' + ast = patchedast.get_patched_ast(source, True) + checker = _ResultChecker(self, ast) + checker.check_children( + 'BinOp', ['Num', ' ', '+', ' ', 'Str']) + + def test_handling_implicit_string_concatenation(self): + source = "a = '1''2'" + ast = patchedast.get_patched_ast(source, True) + checker = _ResultChecker(self, ast) + checker.check_children( + 'Assign', ['Name' , ' ', '=', ' ', 'Str']) + checker.check_children('Str', ["'1''2'"]) + + def test_handling_implicit_string_concatenation_line_breaks(self): + source = "a = '1' \\\n'2'" + ast = patchedast.get_patched_ast(source, True) + checker = _ResultChecker(self, ast) + checker.check_children( + 'Assign', ['Name' , ' ', '=', ' ', 'Str']) + checker.check_children('Str', ["'1' \\\n'2'"]) + + def test_handling_explicit_string_concatenation_line_breaks(self): + source = "a = ('1' \n'2')" + ast = patchedast.get_patched_ast(source, True) + checker = _ResultChecker(self, ast) + checker.check_children( + 'Assign', ['Name' , ' ', '=', ' (', 'Str', ')']) + checker.check_children('Str', ["'1' \n'2'"]) + + def test_not_concatenating_strings_on_separate_lines(self): + source = "'1'\n'2'\n" + ast = patchedast.get_patched_ast(source, True) + checker = _ResultChecker(self, ast) + checker.check_children('Module', ['', 'Expr', '\n', 'Expr', '\n']) + + def test_long_integer_literals(self): + source = "0x1L + a" + ast = patchedast.get_patched_ast(source, True) + checker = _ResultChecker(self, ast) + checker.check_children( + 'BinOp', ['Num' , ' ', '+', ' ', 'Name']) + checker.check_children('Num', ['0x1L']) + + def test_complex_number_literals(self): + source = "1.0e2j + a" + ast = patchedast.get_patched_ast(source, True) + checker = _ResultChecker(self, ast) + checker.check_children( + 'BinOp', ['Num' , ' ', '+', ' ', 'Name']) + checker.check_children('Num', ['1.0e2j']) + + def test_ass_attr_node(self): + source = 'a.b = 1\n' + ast = patchedast.get_patched_ast(source, True) + checker = _ResultChecker(self, ast) + checker.check_region('Attribute', 0, source.index('=') - 1) + checker.check_children('Attribute', ['Name', '', '.', '', 'b']) + + def test_ass_list_node(self): + source = '[a, b] = 1, 2\n' + ast = patchedast.get_patched_ast(source, True) + checker = _ResultChecker(self, ast) + checker.check_region('List', 0, source.index(']') + 1) + checker.check_children('List', ['[', '', 'Name', '', ',', + ' ', 'Name', '', ']']) + + def test_ass_tuple(self): + source = 'a, b = range(2)\n' + ast = patchedast.get_patched_ast(source, True) + checker = _ResultChecker(self, ast) + checker.check_region('Tuple', 0, source.index('=') - 1) + checker.check_children( + 'Tuple', ['Name', '', ',', ' ', 'Name']) + + def test_ass_tuple2(self): + source = '(a, b) = range(2)\n' + ast = patchedast.get_patched_ast(source, True) + checker = _ResultChecker(self, ast) + checker.check_region('Tuple', 0, source.index('=') - 1) + checker.check_children( + 'Tuple', ['(', '', 'Name', '', ',', ' ', 'Name', '', ')']) + + def test_assert(self): + source = 'assert True\n' + ast = patchedast.get_patched_ast(source, True) + checker = _ResultChecker(self, ast) + checker.check_region('Assert', 0, len(source) - 1) + checker.check_children( + 'Assert', ['assert', ' ', 'Name']) + + def test_assert2(self): + source = 'assert True, "error"\n' + ast = patchedast.get_patched_ast(source, True) + checker = _ResultChecker(self, ast) + checker.check_region('Assert', 0, len(source) - 1) + checker.check_children( + 'Assert', ['assert', ' ', 'Name', '', ',', ' ', 'Str']) + + def test_aug_assign_node(self): + source = 'a += 1\n' + ast = patchedast.get_patched_ast(source, True) + checker = _ResultChecker(self, ast) + start = source.index('a') + checker.check_region('AugAssign', 0, len(source) - 1) + checker.check_children( + 'AugAssign', ['Name', ' ', '+', '', '=', ' ', 'Num']) + + def test_back_quotenode(self): + source = '`1`\n' + ast = patchedast.get_patched_ast(source, True) + checker = _ResultChecker(self, ast) + checker.check_region('Repr', 0, len(source) - 1) + checker.check_children( + 'Repr', ['`', '', 'Num', '', '`']) + + def test_bitand(self): + source = '1 & 2\n' + ast = patchedast.get_patched_ast(source, True) + checker = _ResultChecker(self, ast) + checker.check_region('BinOp', 0, len(source) - 1) + checker.check_children( + 'BinOp', ['Num', ' ', '&', ' ', 'Num']) + + def test_bitor(self): + source = '1 | 2\n' + ast = patchedast.get_patched_ast(source, True) + checker = _ResultChecker(self, ast) + checker.check_children( + 'BinOp', ['Num', ' ', '|', ' ', 'Num']) + + def test_call_func(self): + source = 'f(1, 2)\n' + ast = patchedast.get_patched_ast(source, True) + checker = _ResultChecker(self, ast) + checker.check_region('Call', 0, len(source) - 1) + checker.check_children( + 'Call', ['Name', '', '(', '', 'Num', '', ',', + ' ', 'Num', '', ')']) + + def test_call_func_and_keywords(self): + source = 'f(1, p=2)\n' + ast = patchedast.get_patched_ast(source, True) + checker = _ResultChecker(self, ast) + checker.check_children( + 'Call', ['Name', '', '(', '', 'Num', '', ',', + ' ', 'keyword', '', ')']) + + def test_call_func_and_start_args(self): + source = 'f(1, *args)\n' + ast = patchedast.get_patched_ast(source, True) + checker = _ResultChecker(self, ast) + checker.check_children( + 'Call', ['Name', '', '(', '', 'Num', '', ',', + ' ', '*', '', 'Name', '', ')']) + + def test_call_func_and_only_dstart_args(self): + source = 'f(**kwds)\n' + ast = patchedast.get_patched_ast(source, True) + checker = _ResultChecker(self, ast) + checker.check_children( + 'Call', ['Name', '', '(', '', '**', '', 'Name', '', ')']) + + def test_call_func_and_both_varargs_and_kwargs(self): + source = 'f(*args, **kwds)\n' + ast = patchedast.get_patched_ast(source, True) + checker = _ResultChecker(self, ast) + checker.check_children( + 'Call', ['Name', '', '(', '', '*', '', 'Name', '', ',', + ' ', '**', '', 'Name', '', ')']) + + def test_class_node(self): + source = 'class A(object):\n """class docs"""\n pass\n' + ast = patchedast.get_patched_ast(source, True) + checker = _ResultChecker(self, ast) + checker.check_region('Class', 0, len(source) - 1) + checker.check_children( + 'Class', ['class', ' ', 'A', '', '(', '', 'Name', '', ')', + '', ':', '\n ', 'Expr', '\n ', 'Pass']) + + def test_class_with_no_bases(self): + source = 'class A:\n pass\n' + ast = patchedast.get_patched_ast(source, True) + checker = _ResultChecker(self, ast) + checker.check_region('Class', 0, len(source) - 1) + checker.check_children( + 'Class', ['class', ' ', 'A', '', ':', '\n ', 'Pass']) + + def test_simple_compare(self): + source = '1 < 2\n' + ast = patchedast.get_patched_ast(source, True) + checker = _ResultChecker(self, ast) + checker.check_region('Compare', 0, len(source) - 1) + checker.check_children( + 'Compare', ['Num', ' ', '<', ' ', 'Num']) + + def test_multiple_compare(self): + source = '1 < 2 <= 3\n' + ast = patchedast.get_patched_ast(source, True) + checker = _ResultChecker(self, ast) + checker.check_region('Compare', 0, len(source) - 1) + checker.check_children( + 'Compare', ['Num', ' ', '<', ' ', 'Num', ' ', + '<=', ' ', 'Num']) + + def test_decorators_node(self): + source = '@d\ndef f():\n pass\n' + ast = patchedast.get_patched_ast(source, True) + checker = _ResultChecker(self, ast) + checker.check_region('FunctionDef', 0, len(source) - 1) + checker.check_children( + 'FunctionDef', + ['@', '', 'Name', '\n', 'def', ' ', 'f', '', '(', '', 'arguments', + '', ')', '', ':', '\n ', 'Pass']) + + @testutils.only_for('2.6') + def test_decorators_for_classes(self): + source = '@d\nclass C(object):\n pass\n' + ast = patchedast.get_patched_ast(source, True) + checker = _ResultChecker(self, ast) + checker.check_region('ClassDef', 0, len(source) - 1) + checker.check_children( + 'ClassDef', + ['@', '', 'Name', '\n', 'class', ' ', 'C', '', '(', '', 'Name', + '', ')', '', ':', '\n ', 'Pass']) + + def test_both_varargs_and_kwargs(self): + source = 'def f(*args, **kwds):\n pass\n' + ast = patchedast.get_patched_ast(source, True) + checker = _ResultChecker(self, ast) + checker.check_children( + 'arguments', ['*', '', 'args' , '', ',' , ' ', '**', '', 'kwds']) + + def test_function_node(self): + source = 'def f():\n pass\n' + ast = patchedast.get_patched_ast(source, True) + checker = _ResultChecker(self, ast) + checker.check_region('Function', 0, len(source) - 1) + checker.check_children('Function', ['def', ' ', 'f', '', '(', '', 'arguments', '', + ')', '', ':', '\n ', 'Pass']) + + def test_function_node2(self): + source = 'def f(p1, **p2):\n """docs"""\n pass\n' + ast = patchedast.get_patched_ast(source, True) + checker = _ResultChecker(self, ast) + checker.check_region('Function', 0, len(source) - 1) + checker.check_children( + 'Function', ['def', ' ', 'f', '', '(', '', 'arguments', + '', ')' , '', ':', '\n ', 'Expr', '\n ', 'Pass']) + checker.check_children( + 'arguments', ['Name', '', ',', + ' ', '**', '', 'p2']) + + def test_function_node_and_tuple_parameters(self): + source = 'def f(a, (b, c)):\n pass\n' + ast = patchedast.get_patched_ast(source, True) + checker = _ResultChecker(self, ast) + checker.check_region('Function', 0, len(source) - 1) + checker.check_children( + 'Function', ['def', ' ', 'f', '', '(', '', 'arguments', + '', ')' , '', ':', '\n ', 'Pass']) + checker.check_children( + 'arguments', ['Name', '', ',', ' ', 'Tuple']) + + def test_dict_node(self): + source = '{1: 2, 3: 4}\n' + ast = patchedast.get_patched_ast(source, True) + checker = _ResultChecker(self, ast) + checker.check_region('Dict', 0, len(source) - 1) + checker.check_children( + 'Dict', ['{', '', 'Num', '', ':', ' ', 'Num', '', ',', + ' ', 'Num', '', ':', ' ', 'Num', '', '}']) + + def test_div_node(self): + source = '1 / 2\n' + ast = patchedast.get_patched_ast(source, True) + checker = _ResultChecker(self, ast) + checker.check_region('BinOp', 0, len(source) - 1) + checker.check_children('BinOp', ['Num', ' ', '/', ' ', 'Num']) + + def test_simple_exec_node(self): + source = 'exec ""\n' + ast = patchedast.get_patched_ast(source, True) + checker = _ResultChecker(self, ast) + checker.check_region('Exec', 0, len(source) - 1) + checker.check_children('Exec', ['exec', ' ', 'Str']) + + def test_exec_node(self): + source = 'exec "" in locals(), globals()\n' + ast = patchedast.get_patched_ast(source, True) + checker = _ResultChecker(self, ast) + checker.check_region('Exec', 0, len(source) - 1) + checker.check_children( + 'Exec', ['exec', ' ', 'Str', ' ', 'in', + ' ', 'Call', '', ',', ' ', 'Call']) + + def test_for_node(self): + source = 'for i in range(1):\n pass\nelse:\n pass\n' + ast = patchedast.get_patched_ast(source, True) + checker = _ResultChecker(self, ast) + checker.check_region('For', 0, len(source) - 1) + checker.check_children( + 'For', ['for', ' ', 'Name', ' ', 'in', ' ', 'Call', '', + ':', '\n ', 'Pass', '\n', + 'else', '', ':', '\n ', 'Pass']) + + def test_normal_from_node(self): + source = 'from x import y\n' + ast = patchedast.get_patched_ast(source, True) + checker = _ResultChecker(self, ast) + checker.check_region('ImportFrom', 0, len(source) - 1) + checker.check_children( + 'ImportFrom', ['from', ' ', 'x', ' ', 'import', ' ', 'alias']) + checker.check_children('alias', ['y']) + + @testutils.run_only_for_25 + def test_from_node(self): + source = 'from ..x import y as z\n' + ast = patchedast.get_patched_ast(source, True) + checker = _ResultChecker(self, ast) + checker.check_region('ImportFrom', 0, len(source) - 1) + checker.check_children( + 'ImportFrom', ['from', ' ', '..', '', 'x', ' ', + 'import', ' ', 'alias']) + checker.check_children('alias', ['y', ' ', 'as', ' ', 'z']) + + def test_simple_gen_expr_node(self): + source = 'zip(i for i in x)\n' + ast = patchedast.get_patched_ast(source, True) + checker = _ResultChecker(self, ast) + checker.check_region('GeneratorExp', 4, len(source) - 2) + checker.check_children( + 'GeneratorExp', ['Name', ' ', 'comprehension']) + checker.check_children( + 'comprehension', ['for', ' ', 'Name', ' ', 'in', ' ', 'Name']) + + def test_gen_expr_node_handling_surrounding_parens(self): + source = '(i for i in x)\n' + ast = patchedast.get_patched_ast(source, True) + checker = _ResultChecker(self, ast) + checker.check_region('GeneratorExp', 0, len(source) - 1) + checker.check_children( + 'GeneratorExp', ['(', '', 'Name', ' ', 'comprehension', '', ')']) + + def test_gen_expr_node2(self): + source = 'zip(i for i in range(1) if i == 1)\n' + ast = patchedast.get_patched_ast(source, True) + checker = _ResultChecker(self, ast) + checker.check_children( + 'comprehension', ['for', ' ', 'Name', ' ', 'in', ' ', 'Call', + ' ', 'if', ' ', 'Compare']) + + def test_get_attr_node(self): + source = 'a.b\n' + ast = patchedast.get_patched_ast(source, True) + checker = _ResultChecker(self, ast) + checker.check_region('Attribute', 0, len(source) - 1) + checker.check_children('Attribute', ['Name', '', '.', '', 'b']) + + def test_global_node(self): + source = 'global a, b\n' + ast = patchedast.get_patched_ast(source, True) + checker = _ResultChecker(self, ast) + checker.check_region('Global', 0, len(source) - 1) + checker.check_children('Global', ['global', ' ', 'a', '', ',', ' ', 'b']) + + def test_if_node(self): + source = 'if True:\n pass\nelse:\n pass\n' + ast = patchedast.get_patched_ast(source, True) + checker = _ResultChecker(self, ast) + checker.check_region('If', 0, len(source) - 1) + checker.check_children( + 'If', ['if', ' ', 'Name', '', ':', '\n ', 'Pass', '\n', + 'else', '', ':', '\n ', 'Pass']) + + def test_if_node2(self): + source = 'if True:\n pass\nelif False:\n pass\n' + ast = patchedast.get_patched_ast(source, True) + checker = _ResultChecker(self, ast) + checker.check_region('If', 0, len(source) - 1) + checker.check_children( + 'If', ['if', ' ', 'Name', '', ':', '\n ', 'Pass', '\n', + 'If']) + + def test_if_node3(self): + source = 'if True:\n pass\nelse:\n' \ + ' if True:\n pass\n' + ast = patchedast.get_patched_ast(source, True) + checker = _ResultChecker(self, ast) + checker.check_region('If', 0, len(source) - 1) + checker.check_children( + 'If', ['if', ' ', 'Name', '', ':', '\n ', 'Pass', '\n', + 'else', '', ':', '\n ', 'If']) + + def test_import_node(self): + source = 'import a, b as c\n' + ast = patchedast.get_patched_ast(source, True) + checker = _ResultChecker(self, ast) + checker.check_region('Import', 0, len(source) - 1) + checker.check_children( + 'Import', ['import', ' ', 'alias', '', ',', ' ', 'alias']) + + def test_lambda_node(self): + source = 'lambda a, b=1, *z: None\n' + ast = patchedast.get_patched_ast(source, True) + checker = _ResultChecker(self, ast) + checker.check_region('Lambda', 0, len(source) - 1) + checker.check_children( + 'Lambda', ['lambda', ' ', 'arguments', '', ':', ' ', 'Name']) + checker.check_children( + 'arguments', ['Name', '', ',', ' ', 'Name', '', '=', '', + 'Num', '', ',', ' ', '*', '', 'z']) + + def test_list_node(self): + source = '[1, 2]\n' + ast = patchedast.get_patched_ast(source, True) + checker = _ResultChecker(self, ast) + checker.check_region('List', 0, len(source) - 1) + checker.check_children( + 'List', ['[', '', 'Num', '', ',', ' ', 'Num', '', ']']) + + def test_list_comp_node(self): + source = '[i for i in range(1) if True]\n' + ast = patchedast.get_patched_ast(source, True) + checker = _ResultChecker(self, ast) + checker.check_region('ListComp', 0, len(source) - 1) + checker.check_children( + 'ListComp', ['[', '', 'Name', ' ', 'comprehension', '', ']']) + checker.check_children( + 'comprehension', ['for', ' ', 'Name', ' ', 'in', ' ', + 'Call', ' ', 'if', ' ', 'Name']) + + def test_list_comp_node_with_multiple_comprehensions(self): + source = '[i for i in range(1) for j in range(1) if True]\n' + ast = patchedast.get_patched_ast(source, True) + checker = _ResultChecker(self, ast) + checker.check_region('ListComp', 0, len(source) - 1) + checker.check_children( + 'ListComp', ['[', '', 'Name', ' ', 'comprehension', + ' ', 'comprehension', '', ']']) + checker.check_children( + 'comprehension', ['for', ' ', 'Name', ' ', 'in', ' ', + 'Call', ' ', 'if', ' ', 'Name']) + + def test_ext_slice_node(self): + source = 'x = xs[0,:]\n' + ast = patchedast.get_patched_ast(source, True) + checker = _ResultChecker(self, ast) + checker.check_region('ExtSlice', 7, len(source) - 2) + checker.check_children('ExtSlice', ['Index', '', ',', '', 'Slice']) + + def test_simple_module_node(self): + source = 'pass\n' + ast = patchedast.get_patched_ast(source, True) + checker = _ResultChecker(self, ast) + checker.check_region('Module', 0, len(source)) + checker.check_children('Module', ['', 'Pass', '\n']) + + def test_module_node(self): + source = '"""docs"""\npass\n' + ast = patchedast.get_patched_ast(source, True) + checker = _ResultChecker(self, ast) + checker.check_region('Module', 0, len(source)) + checker.check_children('Module', ['', 'Expr', '\n', 'Pass', '\n']) + checker.check_children('Str', ['"""docs"""']) + + def test_not_and_or_nodes(self): + source = 'not True or False\n' + ast = patchedast.get_patched_ast(source, True) + checker = _ResultChecker(self, ast) + checker.check_children('Expr', ['BoolOp']) + checker.check_children('BoolOp', ['UnaryOp', ' ', 'or', ' ', 'Name']) + + def test_print_node(self): + source = 'print >>out, 1,\n' + ast = patchedast.get_patched_ast(source, True) + checker = _ResultChecker(self, ast) + checker.check_region('Print', 0, len(source) - 1) + checker.check_children('Print', ['print', ' ', '>>', '', 'Name', '', + ',', ' ', 'Num', '', ',']) + + def test_printnl_node(self): + source = 'print 1\n' + ast = patchedast.get_patched_ast(source, True) + checker = _ResultChecker(self, ast) + checker.check_region('Print', 0, len(source) - 1) + checker.check_children('Print', ['print', ' ', 'Num']) + + def test_raise_node(self): + source = 'raise x, y, z\n' + ast = patchedast.get_patched_ast(source, True) + checker = _ResultChecker(self, ast) + checker.check_region('Raise', 0, len(source) - 1) + checker.check_children( + 'Raise', ['raise', ' ', 'Name', '', ',', ' ', 'Name', '', ',', + ' ', 'Name']) + + def test_return_node(self): + source = 'def f():\n return None\n' + ast = patchedast.get_patched_ast(source, True) + checker = _ResultChecker(self, ast) + checker.check_children('Return', ['return', ' ', 'Name']) + + def test_empty_return_node(self): + source = 'def f():\n return\n' + ast = patchedast.get_patched_ast(source, True) + checker = _ResultChecker(self, ast) + checker.check_children('Return', ['return']) + + def test_simple_slice_node(self): + source = 'a[1:2]\n' + ast = patchedast.get_patched_ast(source, True) + checker = _ResultChecker(self, ast) + checker.check_children( + 'Subscript', ['Name', '', '[', '', 'Slice', '', ']']) + checker.check_children( + 'Slice', ['Num', '', ':', '', 'Num']) + + def test_slice_node2(self): + source = 'a[:]\n' + ast = patchedast.get_patched_ast(source, True) + checker = _ResultChecker(self, ast) + checker.check_children('Subscript', ['Name', '', '[', '', 'Slice', '', ']']) + checker.check_children('Slice', [':']) + + def test_simple_subscript(self): + source = 'a[1]\n' + ast = patchedast.get_patched_ast(source, True) + checker = _ResultChecker(self, ast) + checker.check_children( + 'Subscript', ['Name', '', '[', '', 'Index', '', ']']) + checker.check_children('Index', ['Num']) + + def test_tuple_node(self): + source = '(1, 2)\n' + ast = patchedast.get_patched_ast(source, True) + checker = _ResultChecker(self, ast) + checker.check_children( + 'Tuple', ['(', '', 'Num', '', ',', ' ', 'Num', '', ')']) + + def test_tuple_node2(self): + source = '#(\n1, 2\n' + ast = patchedast.get_patched_ast(source, True) + checker = _ResultChecker(self, ast) + checker.check_children('Tuple', ['Num', '', ',', ' ', 'Num']) + + def test_one_item_tuple_node(self): + source = '(1,)\n' + ast = patchedast.get_patched_ast(source, True) + checker = _ResultChecker(self, ast) + checker.check_children('Tuple', ['(', '', 'Num', ',', ')']) + + def test_empty_tuple_node(self): + source = '()\n' + ast = patchedast.get_patched_ast(source, True) + checker = _ResultChecker(self, ast) + checker.check_children('Tuple', ['(', '', ')']) + + def test_yield_node(self): + source = 'def f():\n yield None\n' + ast = patchedast.get_patched_ast(source, True) + checker = _ResultChecker(self, ast) + checker.check_children('Yield', ['yield', ' ', 'Name']) + + def test_while_node(self): + source = 'while True:\n pass\nelse:\n pass\n' + ast = patchedast.get_patched_ast(source, True) + checker = _ResultChecker(self, ast) + checker.check_children( + 'While', ['while', ' ', 'Name', '', ':', '\n ', 'Pass', '\n', + 'else', '', ':', '\n ', 'Pass']) + + @testutils.run_only_for_25 + def test_with_node(self): + source = 'from __future__ import with_statement\nwith a as b:\n pass\n' + ast = patchedast.get_patched_ast(source, True) + checker = _ResultChecker(self, ast) + checker.check_children( + 'With', ['with', ' ', 'Name', ' ', 'as', ' ', 'Name', '', ':', + '\n ', 'Pass']) + + def test_try_finally_node(self): + source = 'try:\n pass\nfinally:\n pass\n' + ast = patchedast.get_patched_ast(source, True) + checker = _ResultChecker(self, ast) + checker.check_children( + 'TryFinally', ['try', '', ':', '\n ', 'Pass', '\n', 'finally', + '', ':', '\n ', 'Pass']) + + def test_try_except_node(self): + source = 'try:\n pass\nexcept Exception, e:\n pass\n' + ast = patchedast.get_patched_ast(source, True) + checker = _ResultChecker(self, ast) + checker.check_children( + 'TryExcept', ['try', '', ':', '\n ', 'Pass', '\n', + ('excepthandler', 'ExceptHandler')]) + checker.check_children( + ('excepthandler', 'ExceptHandler'), + ['except', ' ', 'Name', '', ',', ' ', 'Name', '', ':', + '\n ', 'Pass']) + + @testutils.run_only_for_25 + def test_try_except_and_finally_node(self): + source = 'try:\n pass\nexcept:\n pass\nfinally:\n pass\n' + ast = patchedast.get_patched_ast(source, True) + checker = _ResultChecker(self, ast) + checker.check_children( + 'TryFinally', ['TryExcept', '\n', 'finally', + '', ':', '\n ', 'Pass']) + + def test_ignoring_comments(self): + source = '#1\n1\n' + ast = patchedast.get_patched_ast(source, True) + checker = _ResultChecker(self, ast) + start = source.rindex('1') + checker.check_region('Num', start, start + 1) + + def test_simple_sliceobj(self): + source = 'a[1::3]\n' + ast = patchedast.get_patched_ast(source, True) + checker = _ResultChecker(self, ast) + checker.check_children( + 'Slice', ['Num', '', ':', '', ':', '', 'Num']) + + def test_ignoring_strings_that_start_with_a_char(self): + source = 'r"""("""\n1\n' + ast = patchedast.get_patched_ast(source, True) + checker = _ResultChecker(self, ast) + checker.check_children( + 'Module', ['', 'Expr', '\n', 'Expr', '\n']) + + def test_how_to_handle_old_not_equals(self): + source = '1 <> 2\n' + ast = patchedast.get_patched_ast(source, True) + checker = _ResultChecker(self, ast) + checker.check_children( + 'Compare', ['Num', ' ', '<>', ' ', 'Num']) + + def test_semicolon(self): + source = '1;\n' + ast = patchedast.get_patched_ast(source, True) + + @testutils.run_only_for_25 + def test_if_exp_node(self): + source = '1 if True else 2\n' + ast = patchedast.get_patched_ast(source, True) + checker = _ResultChecker(self, ast) + checker.check_children( + 'IfExp', ['Num', ' ', 'if', ' ', 'Name', ' ', 'else', + ' ', 'Num']) + + def test_delete_node(self): + source = 'del a, b\n' + ast = patchedast.get_patched_ast(source, True) + checker = _ResultChecker(self, ast) + checker.check_children( + 'Delete', ['del', ' ', 'Name', '', ',', ' ', 'Name']) + + +class _ResultChecker(object): + + def __init__(self, test_case, ast): + self.test_case = test_case + self.ast = ast + + def check_region(self, text, start, end): + node = self._find_node(text) + if node is None: + self.test_case.fail('Node <%s> cannot be found' % text) + self.test_case.assertEquals((start, end), node.region) + + def _find_node(self, text): + goal = text + if not isinstance(text, (tuple, list)): + goal = [text] + class Search(object): + result = None + def __call__(self, node): + for text in goal: + if str(node).startswith(text): + self.result = node + break + if node.__class__.__name__.startswith(text): + self.result = node + break + return self.result is not None + search = Search() + ast.call_for_nodes(self.ast, search, recursive=True) + return search.result + + def check_children(self, text, children): + node = self._find_node(text) + if node is None: + self.test_case.fail('Node <%s> cannot be found' % text) + result = list(node.sorted_children) + self.test_case.assertEquals(len(children), len(result)) + for expected, child in zip(children, result): + goals = expected + if not isinstance(expected, (tuple, list)): + goals = [expected] + for goal in goals: + if goal == '' or isinstance(child, basestring): + self.test_case.assertEquals(goal, child) + break + else: + self.test_case.assertNotEquals( + '', text, 'probably ignoring some node') + self.test_case.assertTrue( + child.__class__.__name__.startswith(expected), + msg='Expected <%s> but was <%s>' % + (expected, child.__class__.__name__)) + + +if __name__ == '__main__': + unittest.main() diff -r e30544496575 -r 48cacfdc2ca6 vim/sadness/ropevim/src/rope/ropetest/refactor/renametest.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vim/sadness/ropevim/src/rope/ropetest/refactor/renametest.py Wed Oct 06 12:30:46 2010 -0400 @@ -0,0 +1,676 @@ +import sys +import unittest + +import rope.base.codeanalyze +import rope.refactor.occurrences +from rope.refactor import rename +from rope.refactor.rename import Rename +from ropetest import testutils + + +class RenameRefactoringTest(unittest.TestCase): + + def setUp(self): + super(RenameRefactoringTest, self).setUp() + self.project = testutils.sample_project() + self.pycore = self.project.pycore + + def tearDown(self): + testutils.remove_project(self.project) + super(RenameRefactoringTest, self).tearDown() + + def _local_rename(self, source_code, offset, new_name): + testmod = testutils.create_module(self.project, 'testmod') + testmod.write(source_code) + changes = Rename(self.project, testmod, offset).\ + get_changes(new_name, resources=[testmod]) + self.project.do(changes) + return testmod.read() + + def _rename(self, resource, offset, new_name, **kwds): + changes = Rename(self.project, resource, offset).\ + get_changes(new_name, **kwds) + self.project.do(changes) + + def test_simple_global_variable_renaming(self): + refactored = self._local_rename('a_var = 20\n', 2, 'new_var') + self.assertEquals('new_var = 20\n', refactored) + + def test_variable_renaming_only_in_its_scope(self): + refactored = self._local_rename( + 'a_var = 20\ndef a_func():\n a_var = 10\n', 32, 'new_var') + self.assertEquals('a_var = 20\ndef a_func():\n new_var = 10\n', + refactored) + + def test_not_renaming_dot_name(self): + refactored = self._local_rename( + "replace = True\n'aaa'.replace('a', 'b')\n", 1, 'new_var') + self.assertEquals("new_var = True\n'aaa'.replace('a', 'b')\n", + refactored) + + def test_renaming_multiple_names_in_the_same_line(self): + refactored = self._local_rename( + 'a_var = 10\na_var = 10 + a_var / 2\n', 2, 'new_var') + self.assertEquals('new_var = 10\nnew_var = 10 + new_var / 2\n', + refactored) + + def test_renaming_names_when_getting_some_attribute(self): + refactored = self._local_rename( + "a_var = 'a b c'\na_var.split('\\n')\n", 2, 'new_var') + self.assertEquals("new_var = 'a b c'\nnew_var.split('\\n')\n", + refactored) + + def test_renaming_names_when_getting_some_attribute2(self): + refactored = self._local_rename( + "a_var = 'a b c'\na_var.split('\\n')\n", 20, 'new_var') + self.assertEquals("new_var = 'a b c'\nnew_var.split('\\n')\n", + refactored) + + def test_renaming_function_parameters1(self): + refactored = self._local_rename( + "def f(a_param):\n print(a_param)\n", 8, 'new_param') + self.assertEquals("def f(new_param):\n print(new_param)\n", + refactored) + + def test_renaming_function_parameters2(self): + refactored = self._local_rename( + "def f(a_param):\n print(a_param)\n", 30, 'new_param') + self.assertEquals("def f(new_param):\n print(new_param)\n", + refactored) + + def test_renaming_occurrences_inside_functions(self): + code = 'def a_func(p1):\n a = p1\na_func(1)\n' + refactored = self._local_rename(code, code.index('p1') + 1, 'new_param') + self.assertEquals( + 'def a_func(new_param):\n a = new_param\na_func(1)\n', + refactored) + + def test_renaming_arguments_for_normal_args_changing_calls(self): + code = 'def a_func(p1=None, p2=None):\n pass\na_func(p2=1)\n' + refactored = self._local_rename(code, code.index('p2') + 1, 'p3') + self.assertEquals( + 'def a_func(p1=None, p3=None):\n pass\na_func(p3=1)\n', + refactored) + + def test_renaming_function_parameters_of_class_init(self): + code = 'class A(object):\n def __init__(self, a_param):\n pass\n' \ + 'a_var = A(a_param=1)\n' + refactored = self._local_rename(code, code.index('a_param') + 1, 'new_param') + expected = 'class A(object):\n def __init__(self, new_param):\n pass\n' \ + 'a_var = A(new_param=1)\n' + self.assertEquals(expected, refactored) + + def test_renaming_functions_parameters_and_occurances_in_other_modules(self): + mod1 = testutils.create_module(self.project, 'mod1') + mod2 = testutils.create_module(self.project, 'mod2') + mod1.write('def a_func(a_param):\n print(a_param)\n') + mod2.write('from mod1 import a_func\na_func(a_param=10)\n') + self._rename(mod1, mod1.read().index('a_param') + 1, 'new_param') + self.assertEquals('def a_func(new_param):\n print(new_param)\n', + mod1.read()) + self.assertEquals('from mod1 import a_func\na_func(new_param=10)\n', + mod2.read()) + + def test_renaming_with_backslash_continued_names(self): + refactored = self._local_rename( + "replace = True\n'ali'.\\\nreplace\n", 2, 'is_replace') + self.assertEquals("is_replace = True\n'ali'.\\\nreplace\n", + refactored) + + def test_not_renaming_string_contents(self): + refactored = self._local_rename("a_var = 20\na_string='a_var'\n", + 2, 'new_var') + self.assertEquals("new_var = 20\na_string='a_var'\n", + refactored) + + def test_not_renaming_comment_contents(self): + refactored = self._local_rename("a_var = 20\n# a_var\n", + 2, 'new_var') + self.assertEquals("new_var = 20\n# a_var\n", refactored) + + def test_renaming_all_occurances_in_containing_scope(self): + code = 'if True:\n a_var = 1\nelse:\n a_var = 20\n' + refactored = self._local_rename(code, 16, 'new_var') + self.assertEquals( + 'if True:\n new_var = 1\nelse:\n new_var = 20\n', refactored) + + def test_renaming_a_variable_with_arguement_name(self): + code = 'a_var = 10\ndef a_func(a_var):\n print(a_var)\n' + refactored = self._local_rename(code, 1, 'new_var') + self.assertEquals( + 'new_var = 10\ndef a_func(a_var):\n print(a_var)\n', refactored) + + def test_renaming_an_arguement_with_variable_name(self): + code = 'a_var = 10\ndef a_func(a_var):\n print(a_var)\n' + refactored = self._local_rename(code, len(code) - 3, 'new_var') + self.assertEquals( + 'a_var = 10\ndef a_func(new_var):\n print(new_var)\n', + refactored) + + def test_renaming_function_with_local_variable_name(self): + code = 'def a_func():\n a_func=20\na_func()' + refactored = self._local_rename(code, len(code) - 3, 'new_func') + self.assertEquals('def new_func():\n a_func=20\nnew_func()', + refactored) + + def test_renaming_functions(self): + code = 'def a_func():\n pass\na_func()\n' + refactored = self._local_rename(code, len(code) - 5, 'new_func') + self.assertEquals('def new_func():\n pass\nnew_func()\n', + refactored) + + def test_renaming_functions_across_modules(self): + mod1 = testutils.create_module(self.project, 'mod1') + mod1.write('def a_func():\n pass\na_func()\n') + mod2 = testutils.create_module(self.project, 'mod2') + mod2.write('import mod1\nmod1.a_func()\n') + self._rename(mod1, len(mod1.read()) - 5, 'new_func') + self.assertEquals('def new_func():\n pass\nnew_func()\n', + mod1.read()) + self.assertEquals('import mod1\nmod1.new_func()\n', mod2.read()) + + def test_renaming_functions_across_modules_from_import(self): + mod1 = testutils.create_module(self.project, 'mod1') + mod1.write('def a_func():\n pass\na_func()\n') + mod2 = testutils.create_module(self.project, 'mod2') + mod2.write('from mod1 import a_func\na_func()\n') + self._rename(mod1, len(mod1.read()) - 5, 'new_func') + self.assertEquals('def new_func():\n pass\nnew_func()\n', + mod1.read()) + self.assertEquals('from mod1 import new_func\nnew_func()\n', + mod2.read()) + + def test_renaming_functions_from_another_module(self): + mod1 = testutils.create_module(self.project, 'mod1') + mod1.write('def a_func():\n pass\na_func()\n') + mod2 = testutils.create_module(self.project, 'mod2') + mod2.write('import mod1\nmod1.a_func()\n') + self._rename(mod2, len(mod2.read()) - 5, 'new_func') + self.assertEquals('def new_func():\n pass\nnew_func()\n', + mod1.read()) + self.assertEquals('import mod1\nmod1.new_func()\n', mod2.read()) + + def test_applying_all_changes_together(self): + mod1 = testutils.create_module(self.project, 'mod1') + mod1.write('import mod2\nmod2.a_func()\n') + mod2 = testutils.create_module(self.project, 'mod2') + mod2.write('def a_func():\n pass\na_func()\n') + self._rename(mod2, len(mod2.read()) - 5, 'new_func') + self.assertEquals('import mod2\nmod2.new_func()\n', mod1.read()) + self.assertEquals('def new_func():\n pass\nnew_func()\n', + mod2.read()) + + def test_renaming_modules(self): + mod1 = testutils.create_module(self.project, 'mod1') + mod1.write('def a_func():\n pass\n') + mod2 = testutils.create_module(self.project, 'mod2') + mod2.write('from mod1 import a_func\n') + self._rename(mod2, mod2.read().index('mod1') + 1, 'newmod') + self.assertTrue(not mod1.exists() and + self.pycore.find_module('newmod') is not None) + self.assertEquals('from newmod import a_func\n', mod2.read()) + + def test_renaming_packages(self): + pkg = testutils.create_package(self.project, 'pkg') + mod1 = testutils.create_module(self.project, 'mod1', pkg) + mod1.write('def a_func():\n pass\n') + mod2 = testutils.create_module(self.project, 'mod2', pkg) + mod2.write('from pkg.mod1 import a_func\n') + self._rename(mod2, 6, 'newpkg') + self.assertTrue(self.pycore.find_module('newpkg.mod1') is not None) + new_mod2 = self.pycore.find_module('newpkg.mod2') + self.assertEquals('from newpkg.mod1 import a_func\n', new_mod2.read()) + + def test_module_dependencies(self): + mod1 = testutils.create_module(self.project, 'mod1') + mod1.write('class AClass(object):\n pass\n') + mod2 = testutils.create_module(self.project, 'mod2') + mod2.write('import mod1\na_var = mod1.AClass()\n') + self.pycore.resource_to_pyobject(mod2).get_attributes()['mod1'] + mod1.write('def AClass():\n return 0\n') + + self._rename(mod2, len(mod2.read()) - 3, 'a_func') + self.assertEquals('def a_func():\n return 0\n', mod1.read()) + self.assertEquals('import mod1\na_var = mod1.a_func()\n', mod2.read()) + + def test_renaming_class_attributes(self): + mod1 = testutils.create_module(self.project, 'mod1') + mod1.write('class AClass(object):\n def __init__(self):\n' + ' self.an_attr = 10\n') + mod2 = testutils.create_module(self.project, 'mod2') + mod2.write('import mod1\na_var = mod1.AClass()\n' + 'another_var = a_var.an_attr') + + self._rename(mod1, mod1.read().index('an_attr'), 'attr') + self.assertEquals('class AClass(object):\n def __init__(self):\n' + ' self.attr = 10\n', mod1.read()) + self.assertEquals( + 'import mod1\na_var = mod1.AClass()\nanother_var = a_var.attr', + mod2.read()) + + def test_renaming_class_attributes2(self): + mod1 = testutils.create_module(self.project, 'mod1') + mod1.write('class AClass(object):\n def __init__(self):\n' + ' an_attr = 10\n self.an_attr = 10\n') + mod2 = testutils.create_module(self.project, 'mod2') + mod2.write('import mod1\na_var = mod1.AClass()\n' + 'another_var = a_var.an_attr') + + self._rename(mod1, mod1.read().rindex('an_attr'), 'attr') + self.assertEquals( + 'class AClass(object):\n def __init__(self):\n' + ' an_attr = 10\n self.attr = 10\n', mod1.read()) + self.assertEquals( + 'import mod1\na_var = mod1.AClass()\nanother_var = a_var.attr', + mod2.read()) + + def test_renaming_methods_in_subclasses(self): + mod = testutils.create_module(self.project, 'mod1') + mod.write('class A(object):\n def a_method(self):\n pass\n' + 'class B(A):\n def a_method(self):\n pass\n') + + self._rename(mod, mod.read().rindex('a_method') + 1, 'new_method', + in_hierarchy=True) + self.assertEquals( + 'class A(object):\n def new_method(self):\n pass\n' + 'class B(A):\n def new_method(self):\n pass\n', mod.read()) + + def test_renaming_methods_in_sibling_classes(self): + mod = testutils.create_module(self.project, 'mod1') + mod.write('class A(object):\n def a_method(self):\n pass\n' + 'class B(A):\n def a_method(self):\n pass\n' + 'class C(A):\n def a_method(self):\n pass\n') + + self._rename(mod, mod.read().rindex('a_method') + 1, 'new_method', + in_hierarchy=True) + self.assertEquals( + 'class A(object):\n def new_method(self):\n pass\n' + 'class B(A):\n def new_method(self):\n pass\n' + 'class C(A):\n def new_method(self):\n pass\n', mod.read()) + + def test_not_renaming_methods_in_hierarchies(self): + mod = testutils.create_module(self.project, 'mod1') + mod.write('class A(object):\n def a_method(self):\n pass\n' + 'class B(A):\n def a_method(self):\n pass\n') + + self._rename(mod, mod.read().rindex('a_method') + 1, 'new_method', + in_hierarchy=False) + self.assertEquals( + 'class A(object):\n def a_method(self):\n pass\n' + 'class B(A):\n def new_method(self):\n pass\n', mod.read()) + + def test_undoing_refactorings(self): + mod1 = testutils.create_module(self.project, 'mod1') + mod1.write('def a_func():\n pass\na_func()\n') + self._rename(mod1, len(mod1.read()) - 5, 'new_func') + self.project.history.undo() + self.assertEquals('def a_func():\n pass\na_func()\n', mod1.read()) + + def test_undoing_renaming_modules(self): + mod1 = testutils.create_module(self.project, 'mod1') + mod1.write('def a_func():\n pass\n') + mod2 = testutils.create_module(self.project, 'mod2') + mod2.write('from mod1 import a_func\n') + self._rename(mod2, 6, 'newmod') + self.project.history.undo() + self.assertEquals('mod1.py', mod1.path) + self.assertEquals('from mod1 import a_func\n', mod2.read()) + + def test_rename_in_module_renaming_one_letter_names_for_expressions(self): + mod1 = testutils.create_module(self.project, 'mod1') + mod1.write('a = 10\nprint(1+a)\n') + pymod = self.pycore.get_module('mod1') + old_pyname = pymod['a'] + finder = rope.refactor.occurrences.create_finder( + self.pycore, 'a', old_pyname) + refactored = rename.rename_in_module( + finder, 'new_var', pymodule=pymod, replace_primary=True) + self.assertEquals('new_var = 10\nprint(1+new_var)\n', refactored) + + def test_renaming_for_loop_variable(self): + code = 'for var in range(10):\n print(var)\n' + refactored = self._local_rename(code, code.find('var') + 1, 'new_var') + self.assertEquals('for new_var in range(10):\n print(new_var)\n', + refactored) + + def test_renaming_parameters(self): + code = 'def a_func(param):\n print(param)\na_func(param=hey)\n' + refactored = self._local_rename(code, code.find('param') + 1, + 'new_param') + self.assertEquals('def a_func(new_param):\n print(new_param)\n' + 'a_func(new_param=hey)\n', refactored) + + def test_renaming_assigned_parameters(self): + code = 'def f(p):\n p = p + 1\n return p\nf(p=1)\n' + refactored = self._local_rename(code, code.find('p'), 'arg') + self.assertEquals('def f(arg):\n arg = arg + 1\n' + ' return arg\nf(arg=1)\n', refactored) + + def test_renaming_parameters_not_renaming_others(self): + code = 'def a_func(param):\n print(param)\nparam=10\na_func(param)\n' + refactored = self._local_rename(code, code.find('param') + 1, 'new_param') + self.assertEquals('def a_func(new_param):\n print(new_param)\n' + 'param=10\na_func(param)\n', refactored) + + def test_renaming_parameters_not_renaming_others2(self): + code = 'def a_func(param):\n print(param)\nparam=10\na_func(param=param)' + refactored = self._local_rename(code, code.find('param') + 1, 'new_param') + self.assertEquals('def a_func(new_param):\n print(new_param)\n' + 'param=10\na_func(new_param=param)', refactored) + + def test_renaming_parameters_with_multiple_params(self): + code = 'def a_func(param1, param2):\n print(param1)\n'\ + 'a_func(param1=1, param2=2)\n' + refactored = self._local_rename(code, code.find('param1') + 1, 'new_param') + self.assertEquals( + 'def a_func(new_param, param2):\n print(new_param)\n' + 'a_func(new_param=1, param2=2)\n', refactored) + + def test_renaming_parameters_with_multiple_params2(self): + code = 'def a_func(param1, param2):\n print(param1)\n' \ + 'a_func(param1=1, param2=2)\n' + refactored = self._local_rename(code, code.rfind('param2') + 1, + 'new_param') + self.assertEquals('def a_func(param1, new_param):\n print(param1)\n' + 'a_func(param1=1, new_param=2)\n', refactored) + + def test_renaming_parameters_on_calls(self): + code = 'def a_func(param):\n print(param)\na_func(param = hey)\n' + refactored = self._local_rename(code, code.rfind('param') + 1, + 'new_param') + self.assertEquals('def a_func(new_param):\n print(new_param)\n' + 'a_func(new_param = hey)\n', refactored) + + def test_renaming_parameters_spaces_before_call(self): + code = 'def a_func(param):\n print(param)\na_func (param=hey)\n' + refactored = self._local_rename(code, code.rfind('param') + 1, + 'new_param') + self.assertEquals('def a_func(new_param):\n print(new_param)\n' + 'a_func (new_param=hey)\n', refactored) + + def test_renaming_parameter_like_objects_after_keywords(self): + code = 'def a_func(param):\n print(param)\ndict(param=hey)\n' + refactored = self._local_rename(code, code.find('param') + 1, 'new_param') + self.assertEquals('def a_func(new_param):\n print(new_param)\n' + 'dict(param=hey)\n', refactored) + + def test_renaming_variables_in_init_dot_pys(self): + pkg = testutils.create_package(self.project, 'pkg') + init_dot_py = pkg.get_child('__init__.py') + init_dot_py.write('a_var = 10\n') + mod = testutils.create_module(self.project, 'mod') + mod.write('import pkg\nprint(pkg.a_var)\n') + self._rename(mod, mod.read().index('a_var') + 1, 'new_var') + self.assertEquals('new_var = 10\n', init_dot_py.read()) + self.assertEquals('import pkg\nprint(pkg.new_var)\n', mod.read()) + + def test_renaming_variables_in_init_dot_pys2(self): + pkg = testutils.create_package(self.project, 'pkg') + init_dot_py = pkg.get_child('__init__.py') + init_dot_py.write('a_var = 10\n') + mod = testutils.create_module(self.project, 'mod') + mod.write('import pkg\nprint(pkg.a_var)\n') + self._rename(init_dot_py, + init_dot_py.read().index('a_var') + 1, 'new_var') + self.assertEquals('new_var = 10\n', init_dot_py.read()) + self.assertEquals('import pkg\nprint(pkg.new_var)\n', mod.read()) + + def test_renaming_variables_in_init_dot_pys3(self): + pkg = testutils.create_package(self.project, 'pkg') + init_dot_py = pkg.get_child('__init__.py') + init_dot_py.write('a_var = 10\n') + mod = testutils.create_module(self.project, 'mod') + mod.write('import pkg\nprint(pkg.a_var)\n') + self._rename(mod, mod.read().index('a_var') + 1, 'new_var') + self.assertEquals('new_var = 10\n', init_dot_py.read()) + self.assertEquals('import pkg\nprint(pkg.new_var)\n', mod.read()) + + def test_renaming_resources_using_rename_module_refactoring(self): + mod1 = testutils.create_module(self.project, 'mod1') + mod2 = testutils.create_module(self.project, 'mod2') + mod1.write('a_var = 1') + mod2.write('import mod1\nmy_var = mod1.a_var\n') + renamer = rename.Rename(self.project, mod1) + renamer.get_changes('newmod').do() + self.assertEquals('import newmod\nmy_var = newmod.a_var\n', mod2.read()) + + def test_renaming_resources_using_rename_module_refactoring_for_packages(self): + mod1 = testutils.create_module(self.project, 'mod1') + pkg = testutils.create_package(self.project, 'pkg') + mod1.write('import pkg\nmy_pkg = pkg') + renamer = rename.Rename(self.project, pkg) + renamer.get_changes('newpkg').do() + self.assertEquals('import newpkg\nmy_pkg = newpkg', mod1.read()) + + def test_renaming_resources_using_rename_module_refactoring_for_init_dot_py(self): + mod1 = testutils.create_module(self.project, 'mod1') + pkg = testutils.create_package(self.project, 'pkg') + mod1.write('import pkg\nmy_pkg = pkg') + renamer = rename.Rename(self.project, pkg.get_child('__init__.py')) + renamer.get_changes('newpkg').do() + self.assertEquals('import newpkg\nmy_pkg = newpkg', mod1.read()) + + def test_renaming_global_variables(self): + code = 'a_var = 1\ndef a_func():\n global a_var\n var = a_var\n' + refactored = self._local_rename(code, code.index('a_var'), 'new_var') + self.assertEquals( + 'new_var = 1\ndef a_func():\n global new_var\n var = new_var\n', + refactored) + + def test_renaming_global_variables2(self): + code = 'a_var = 1\ndef a_func():\n global a_var\n var = a_var\n' + refactored = self._local_rename(code, code.rindex('a_var'), 'new_var') + self.assertEquals( + 'new_var = 1\ndef a_func():\n global new_var\n var = new_var\n', + refactored) + + def test_renaming_when_unsure(self): + code = 'class C(object):\n def a_func(self):\n pass\n' \ + 'def f(arg):\n arg.a_func()\n' + mod1 = testutils.create_module(self.project, 'mod1') + mod1.write(code) + self._rename(mod1, code.index('a_func'), + 'new_func', unsure=self._true) + self.assertEquals( + 'class C(object):\n def new_func(self):\n pass\n' \ + 'def f(arg):\n arg.new_func()\n', + mod1.read()) + + def _true(self, *args): + return True + + def test_renaming_when_unsure_with_confirmation(self): + def confirm(occurrence): + return False + code = 'class C(object):\n def a_func(self):\n pass\n' \ + 'def f(arg):\n arg.a_func()\n' + mod1 = testutils.create_module(self.project, 'mod1') + mod1.write(code) + self._rename(mod1, code.index('a_func'), 'new_func', unsure=confirm) + self.assertEquals( + 'class C(object):\n def new_func(self):\n pass\n' \ + 'def f(arg):\n arg.a_func()\n', mod1.read()) + + def test_renaming_when_unsure_not_renaming_knowns(self): + code = 'class C1(object):\n def a_func(self):\n pass\n' \ + 'class C2(object):\n def a_func(self):\n pass\n' \ + 'c1 = C1()\nc1.a_func()\nc2 = C2()\nc2.a_func()\n' + mod1 = testutils.create_module(self.project, 'mod1') + mod1.write(code) + self._rename(mod1, code.index('a_func'), 'new_func', unsure=self._true) + self.assertEquals( + 'class C1(object):\n def new_func(self):\n pass\n' \ + 'class C2(object):\n def a_func(self):\n pass\n' \ + 'c1 = C1()\nc1.new_func()\nc2 = C2()\nc2.a_func()\n', + mod1.read()) + + def test_renaming_in_strings_and_comments(self): + code = 'a_var = 1\n# a_var\n' + mod1 = testutils.create_module(self.project, 'mod1') + mod1.write(code) + self._rename(mod1, code.index('a_var'), 'new_var', docs=True) + self.assertEquals('new_var = 1\n# new_var\n', mod1.read()) + + def test_not_renaming_in_strings_and_comments_where_not_visible(self): + code = 'def f():\n a_var = 1\n# a_var\n' + mod1 = testutils.create_module(self.project, 'mod1') + mod1.write(code) + self._rename(mod1, code.index('a_var'), 'new_var', docs=True) + self.assertEquals('def f():\n new_var = 1\n# a_var\n', mod1.read()) + + def test_not_renaming_all_text_occurrences_in_strings_and_comments(self): + code = 'a_var = 1\n# a_vard _a_var\n' + mod1 = testutils.create_module(self.project, 'mod1') + mod1.write(code) + self._rename(mod1, code.index('a_var'), 'new_var', docs=True) + self.assertEquals('new_var = 1\n# a_vard _a_var\n', mod1.read()) + + def test_renaming_occurrences_in_overwritten_scopes(self): + refactored = self._local_rename( + 'a_var = 20\ndef f():\n print(a_var)\n' + 'def f():\n print(a_var)\n', 2, 'new_var') + self.assertEquals('new_var = 20\ndef f():\n print(new_var)\n' + 'def f():\n print(new_var)\n', refactored) + + def test_renaming_occurrences_in_overwritten_scopes2(self): + code = 'def f():\n a_var = 1\n print(a_var)\n' \ + 'def f():\n a_var = 1\n print(a_var)\n' + refactored = self._local_rename(code, code.index('a_var') + 1, 'new_var') + self.assertEquals(code.replace('a_var', 'new_var', 2), refactored) + + def test_dos_line_ending_and_renaming(self): + code = '\r\na = 1\r\n\r\nprint(2 + a + 2)\r\n' + offset = code.replace('\r\n', '\n').rindex('a') + refactored = self._local_rename(code, offset, 'b') + self.assertEquals('\nb = 1\n\nprint(2 + b + 2)\n', + refactored.replace('\r\n', '\n')) + + def test_multi_byte_strs_and_renaming(self): + s = u'{LATIN SMALL LETTER I WITH DIAERESIS}' * 4 + code = u'# -*- coding: utf-8 -*-\n# ' + s + \ + '\na = 1\nprint(2 + a + 2)\n' + refactored = self._local_rename(code, code.rindex('a'), 'b') + self.assertEquals(u'# -*- coding: utf-8 -*-\n# ' + s + + '\nb = 1\nprint(2 + b + 2)\n', refactored) + + def test_resources_parameter(self): + mod1 = testutils.create_module(self.project, 'mod1') + mod2 = testutils.create_module(self.project, 'mod2') + mod1.write('def f():\n pass\n') + mod2.write('import mod1\nmod1.f()\n') + self._rename(mod1, mod1.read().rindex('f'), 'g', + resources=[mod1]) + self.assertEquals('def g():\n pass\n', mod1.read()) + self.assertEquals('import mod1\nmod1.f()\n', mod2.read()) + + def test_resources_parameter_not_changing_defining_module(self): + mod1 = testutils.create_module(self.project, 'mod1') + mod2 = testutils.create_module(self.project, 'mod2') + mod1.write('def f():\n pass\n') + mod2.write('import mod1\nmod1.f()\n') + self._rename(mod1, mod1.read().rindex('f'), 'g', + resources=[mod2]) + self.assertEquals('def f():\n pass\n', mod1.read()) + self.assertEquals('import mod1\nmod1.g()\n', mod2.read()) + + # XXX: with variables should not leak + @testutils.only_for('2.5') + def xxx_test_with_statement_variables_should_not_leak(self): + code = 'f = 1\nwith open("1.txt") as f:\n print(f)\n' + if sys.version_info < (2, 6, 0): + code = 'from __future__ import with_statement\n' + code + mod1 = testutils.create_module(self.project, 'mod1') + mod1.write(code) + self._rename(mod1, code.rindex('f'), 'file') + expected = 'f = 1\nwith open("1.txt") as file:\n print(file)\n' + self.assertEquals(expected, mod1.read()) + + +class ChangeOccurrencesTest(unittest.TestCase): + + def setUp(self): + self.project = testutils.sample_project() + self.mod = testutils.create_module(self.project, 'mod') + + def tearDown(self): + testutils.remove_project(self.project) + super(ChangeOccurrencesTest, self).tearDown() + + def test_simple_case(self): + self.mod.write('a_var = 1\nprint(a_var)\n') + changer = rename.ChangeOccurrences(self.project, self.mod, + self.mod.read().index('a_var')) + changer.get_changes('new_var').do() + self.assertEquals('new_var = 1\nprint(new_var)\n', self.mod.read()) + + def test_only_performing_inside_scopes(self): + self.mod.write('a_var = 1\nnew_var = 2\ndef f():\n print(a_var)\n') + changer = rename.ChangeOccurrences(self.project, self.mod, + self.mod.read().rindex('a_var')) + changer.get_changes('new_var').do() + self.assertEquals( + 'a_var = 1\nnew_var = 2\ndef f():\n print(new_var)\n', + self.mod.read()) + + def test_only_performing_on_calls(self): + self.mod.write('def f1():\n pass\ndef f2():\n pass\n' + 'g = f1\na = f1()\n') + changer = rename.ChangeOccurrences(self.project, self.mod, + self.mod.read().rindex('f1')) + changer.get_changes('f2', only_calls=True).do() + self.assertEquals( + 'def f1():\n pass\ndef f2():\n pass\ng = f1\na = f2()\n', + self.mod.read()) + + def test_only_performing_on_reads(self): + self.mod.write('a = 1\nb = 2\nprint(a)\n') + changer = rename.ChangeOccurrences(self.project, self.mod, + self.mod.read().rindex('a')) + changer.get_changes('b', writes=False).do() + self.assertEquals('a = 1\nb = 2\nprint(b)\n', self.mod.read()) + + +class ImplicitInterfacesTest(unittest.TestCase): + + def setUp(self): + super(ImplicitInterfacesTest, self).setUp() + self.project = testutils.sample_project(validate_objectdb=True) + self.pycore = self.project.pycore + self.mod1 = testutils.create_module(self.project, 'mod1') + self.mod2 = testutils.create_module(self.project, 'mod2') + + def tearDown(self): + testutils.remove_project(self.project) + super(ImplicitInterfacesTest, self).tearDown() + + def _rename(self, resource, offset, new_name, **kwds): + changes = Rename(self.project, resource, offset).\ + get_changes(new_name, **kwds) + self.project.do(changes) + + def test_performing_rename_on_parameters(self): + self.mod1.write('def f(arg):\n arg.run()\n') + self.mod2.write('import mod1\n\n\n' + 'class A(object):\n def run(self):\n pass\n' + 'class B(object):\n def run(self):\n pass\n' + 'mod1.f(A())\nmod1.f(B())\n') + self.pycore.analyze_module(self.mod2) + self._rename(self.mod1, self.mod1.read().index('run'), 'newrun') + self.assertEquals('def f(arg):\n arg.newrun()\n', self.mod1.read()) + self.assertEquals( + 'import mod1\n\n\n' + 'class A(object):\n def newrun(self):\n pass\n' + 'class B(object):\n def newrun(self):\n pass\n' + 'mod1.f(A())\nmod1.f(B())\n', self.mod2.read()) + + +def suite(): + result = unittest.TestSuite() + result.addTests(unittest.makeSuite(RenameRefactoringTest)) + result.addTests(unittest.makeSuite(ChangeOccurrencesTest)) + result.addTests(unittest.makeSuite(ImplicitInterfacesTest)) + return result + + +if __name__ == '__main__': + unittest.main() diff -r e30544496575 -r 48cacfdc2ca6 vim/sadness/ropevim/src/rope/ropetest/refactor/restructuretest.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vim/sadness/ropevim/src/rope/ropetest/refactor/restructuretest.py Wed Oct 06 12:30:46 2010 -0400 @@ -0,0 +1,180 @@ +from rope.refactor import restructure +from ropetest import testutils + +import unittest + + +class RestructureTest(unittest.TestCase): + + def setUp(self): + super(RestructureTest, self).setUp() + self.project = testutils.sample_project() + self.pycore = self.project.pycore + self.mod = testutils.create_module(self.project, 'mod') + + def tearDown(self): + testutils.remove_project(self.project) + super(RestructureTest, self).tearDown() + + def test_trivial_case(self): + refactoring = restructure.Restructure(self.project, + 'a = 1', 'a = 0') + self.mod.write('b = 1\n') + self.project.do(refactoring.get_changes()) + self.assertEquals('b = 1\n', self.mod.read()) + + def test_replacing_simple_patterns(self): + refactoring = restructure.Restructure(self.project, + 'a = 1', 'a = int(1)') + self.mod.write('a = 1\nb = 1\n') + self.project.do(refactoring.get_changes()) + self.assertEquals('a = int(1)\nb = 1\n', self.mod.read()) + + def test_replacing_patterns_with_normal_names(self): + refactoring = restructure.Restructure( + self.project, '${a} = 1', '${a} = int(1)', args={'a': 'exact'}) + self.mod.write('a = 1\nb = 1\n') + self.project.do(refactoring.get_changes()) + self.assertEquals('a = int(1)\nb = 1\n', self.mod.read()) + + def test_replacing_patterns_with_any_names(self): + refactoring = restructure.Restructure(self.project, + '${a} = 1', '${a} = int(1)') + self.mod.write('a = 1\nb = 1\n') + self.project.do(refactoring.get_changes()) + self.assertEquals('a = int(1)\nb = int(1)\n', self.mod.read()) + + def test_replacing_patterns_with_any_names2(self): + refactoring = restructure.Restructure( + self.project, '${x} + ${x}', '${x} * 2') + self.mod.write('a = 1 + 1\n') + self.project.do(refactoring.get_changes()) + self.assertEquals('a = 1 * 2\n', self.mod.read()) + + def test_replacing_patterns_with_checks(self): + self.mod.write('def f(p=1):\n return p\ng = f\ng()\n') + refactoring = restructure.Restructure( + self.project, '${f}()', '${f}(2)', args={'f': 'object=mod.f'}) + self.project.do(refactoring.get_changes()) + self.assertEquals('def f(p=1):\n return p\ng = f\ng(2)\n', + self.mod.read()) + + def test_replacing_assignments_with_sets(self): + refactoring = restructure.Restructure( + self.project, '${a} = ${b}', '${a}.set(${b})') + self.mod.write('a = 1\nb = 1\n') + self.project.do(refactoring.get_changes()) + self.assertEquals('a.set(1)\nb.set(1)\n', self.mod.read()) + + def test_replacing_sets_with_assignments(self): + refactoring = restructure.Restructure( + self.project, '${a}.set(${b})', '${a} = ${b}') + self.mod.write('a.set(1)\nb.set(1)\n') + self.project.do(refactoring.get_changes()) + self.assertEquals('a = 1\nb = 1\n', self.mod.read()) + + def test_using_make_checks(self): + self.mod.write('def f(p=1):\n return p\ng = f\ng()\n') + refactoring = restructure.Restructure( + self.project, '${f}()', '${f}(2)', args={'f': 'object=mod.f'}) + self.project.do(refactoring.get_changes()) + self.assertEquals('def f(p=1):\n return p\ng = f\ng(2)\n', + self.mod.read()) + + def test_using_make_checking_builtin_types(self): + self.mod.write('a = 1 + 1\n') + refactoring = restructure.Restructure( + self.project, '${i} + ${i}', '${i} * 2', + args={'i': 'type=__builtin__.int'}) + self.project.do(refactoring.get_changes()) + self.assertEquals('a = 1 * 2\n', self.mod.read()) + + def test_auto_indentation_when_no_indentation(self): + self.mod.write('a = 2\n') + refactoring = restructure.Restructure( + self.project, '${a} = 2', '${a} = 1\n${a} += 1') + self.project.do(refactoring.get_changes()) + self.assertEquals('a = 1\na += 1\n', self.mod.read()) + + def test_auto_indentation(self): + self.mod.write('def f():\n a = 2\n') + refactoring = restructure.Restructure( + self.project, '${a} = 2', '${a} = 1\n${a} += 1') + self.project.do(refactoring.get_changes()) + self.assertEquals('def f():\n a = 1\n a += 1\n', self.mod.read()) + + def test_auto_indentation_and_not_indenting_blanks(self): + self.mod.write('def f():\n a = 2\n') + refactoring = restructure.Restructure( + self.project, '${a} = 2', '${a} = 1\n\n${a} += 1') + self.project.do(refactoring.get_changes()) + self.assertEquals('def f():\n a = 1\n\n a += 1\n', + self.mod.read()) + + def test_importing_names(self): + self.mod.write('a = 2\n') + refactoring = restructure.Restructure( + self.project, '${a} = 2', '${a} = myconsts.two', + imports=['import myconsts']) + self.project.do(refactoring.get_changes()) + self.assertEquals('import myconsts\na = myconsts.two\n', + self.mod.read()) + + def test_not_importing_names_when_there_are_no_changes(self): + self.mod.write('a = True\n') + refactoring = restructure.Restructure( + self.project, '${a} = 2', '${a} = myconsts.two', + imports=['import myconsts']) + self.project.do(refactoring.get_changes()) + self.assertEquals('a = True\n', self.mod.read()) + + def test_handling_containing_matches(self): + self.mod.write('a = 1 / 2 / 3\n') + refactoring = restructure.Restructure( + self.project, '${a} / ${b}', '${a} // ${b}') + self.project.do(refactoring.get_changes()) + self.assertEquals('a = 1 // 2 // 3\n', self.mod.read()) + + def test_handling_overlapping_matches(self): + self.mod.write('a = 1\na = 1\na = 1\n') + refactoring = restructure.Restructure( + self.project, 'a = 1\na = 1\n', 'b = 1') + self.project.do(refactoring.get_changes()) + self.assertEquals('b = 1\na = 1\n', self.mod.read()) + + def test_preventing_stack_overflow_when_matching(self): + self.mod.write('1\n') + refactoring = restructure.Restructure(self.project, '${a}', '${a}') + self.project.do(refactoring.get_changes()) + self.assertEquals('1\n', self.mod.read()) + + def test_performing_a_restructuring_to_all_modules(self): + mod2 = testutils.create_module(self.project, 'mod2') + self.mod.write('a = 1\n') + mod2.write('b = 1\n') + refactoring = restructure.Restructure(self.project, '1', '2 / 1') + self.project.do(refactoring.get_changes()) + self.assertEquals('a = 2 / 1\n', self.mod.read()) + self.assertEquals('b = 2 / 1\n', mod2.read()) + + def test_performing_a_restructuring_to_selected_modules(self): + mod2 = testutils.create_module(self.project, 'mod2') + self.mod.write('a = 1\n') + mod2.write('b = 1\n') + refactoring = restructure.Restructure(self.project, '1', '2 / 1') + self.project.do(refactoring.get_changes(resources=[mod2])) + self.assertEquals('a = 1\n', self.mod.read()) + self.assertEquals('b = 2 / 1\n', mod2.read()) + + def test_unsure_argument_of_default_wildcard(self): + self.mod.write('def f(p):\n return p * 2\nx = "" * 2\ni = 1 * 2\n') + refactoring = restructure.Restructure( + self.project, '${s} * 2', 'dup(${s})', + args={'s': {'type': '__builtins__.str','unsure': True}}) + self.project.do(refactoring.get_changes()) + self.assertEquals('def f(p):\n return dup(p)\nx = dup("")\n' + 'i = 1 * 2\n', self.mod.read()) + + +if __name__ == '__main__': + unittest.main() diff -r e30544496575 -r 48cacfdc2ca6 vim/sadness/ropevim/src/rope/ropetest/refactor/similarfindertest.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vim/sadness/ropevim/src/rope/ropetest/refactor/similarfindertest.py Wed Oct 06 12:30:46 2010 -0400 @@ -0,0 +1,284 @@ +import unittest + +from rope.refactor import similarfinder +from ropetest import testutils + + +class SimilarFinderTest(unittest.TestCase): + + def setUp(self): + super(SimilarFinderTest, self).setUp() + self.project = testutils.sample_project() + self.mod = testutils.create_module(self.project, 'mod') + + def tearDown(self): + testutils.remove_project(self.project) + super(SimilarFinderTest, self).tearDown() + + def _create_finder(self, source, **kwds): + self.mod.write(source) + pymodule = self.project.pycore.resource_to_pyobject(self.mod) + return similarfinder.SimilarFinder(pymodule, **kwds) + + def test_trivial_case(self): + finder = self._create_finder('') + self.assertEquals([], list(finder.get_match_regions('10'))) + + def test_constant_integer(self): + source = 'a = 10\n' + finder = self._create_finder(source) + result = [(source.index('10'), source.index('10') + 2)] + self.assertEquals(result, list(finder.get_match_regions('10'))) + + def test_simple_addition(self): + source = 'a = 1 + 2\n' + finder = self._create_finder(source) + result = [(source.index('1'), source.index('2') + 1)] + self.assertEquals(result, list(finder.get_match_regions('1 + 2'))) + + def test_simple_addition2(self): + source = 'a = 1 +2\n' + finder = self._create_finder(source) + result = [(source.index('1'), source.index('2') + 1)] + self.assertEquals(result, list(finder.get_match_regions('1 + 2'))) + + def test_simple_assign_statements(self): + source = 'a = 1 + 2\n' + finder = self._create_finder(source) + self.assertEquals([(0, len(source) - 1)], + list(finder.get_match_regions('a = 1 + 2'))) + + def test_simple_multiline_statements(self): + source = 'a = 1\nb = 2\n' + finder = self._create_finder(source) + self.assertEquals([(0, len(source) - 1)], + list(finder.get_match_regions('a = 1\nb = 2'))) + + def test_multiple_matches(self): + source = 'a = 1 + 1\n' + finder = self._create_finder(source) + result = list(finder.get_match_regions('1')) + self.assertEquals(2, len(result)) + start1 = source.index('1') + self.assertEquals((start1, start1 + 1) , result[0]) + start2 = source.rindex('1') + self.assertEquals((start2, start2 + 1) , result[1]) + + def test_multiple_matches2(self): + source = 'a = 1\nb = 2\n\na = 1\nb = 2\n' + finder = self._create_finder(source) + self.assertEquals( + 2, len(list(finder.get_match_regions('a = 1\nb = 2')))) + + def test_restricting_the_region_to_search(self): + source = '1\n\n1\n' + finder = self._create_finder(source) + result = list(finder.get_match_regions('1', start=2)) + start = source.rfind('1') + self.assertEquals([(start, start + 1)], result) + + def test_matching_basic_patterns(self): + source = 'b = a\n' + finder = self._create_finder(source) + result = list(finder.get_match_regions('${a}', args={'a': 'exact'})) + start = source.rfind('a') + self.assertEquals([(start, start + 1)], result) + + def test_match_get_ast(self): + source = 'b = a\n' + finder = self._create_finder(source) + result = list(finder.get_matches('${a}', args={'a': 'exact'})) + self.assertEquals('a', result[0].get_ast('a').id) + + def test_match_get_ast_for_statements(self): + source = 'b = a\n' + finder = self._create_finder(source) + result = list(finder.get_matches('b = ${a}')) + self.assertEquals('a', result[0].get_ast('a').id) + + def test_matching_multiple_patterns(self): + source = 'c = a + b\n' + finder = self._create_finder(source) + result = list(finder.get_matches('${a} + ${b}')) + self.assertEquals('a', result[0].get_ast('a').id) + self.assertEquals('b', result[0].get_ast('b').id) + + def test_matching_any_patterns(self): + source = 'b = a\n' + finder = self._create_finder(source) + result = list(finder.get_matches('b = ${x}')) + self.assertEquals('a', result[0].get_ast('x').id) + + def test_matching_any_patterns_repeating(self): + source = 'b = 1 + 1\n' + finder = self._create_finder(source) + result = list(finder.get_matches('b = ${x} + ${x}')) + self.assertEquals(1, result[0].get_ast('x').n) + + def test_matching_any_patterns_not_matching_different_nodes(self): + source = 'b = 1 + 2\n' + finder = self._create_finder(source) + result = list(finder.get_matches('b = ${x} + ${x}')) + self.assertEquals(0, len(result)) + + def test_matching_normal_names_and_assname(self): + source = 'a = 1\n' + finder = self._create_finder(source) + result = list(finder.get_matches('${a} = 1')) + self.assertEquals('a', result[0].get_ast('a').id) + + def test_matching_normal_names_and_assname2(self): + source = 'a = 1\n' + finder = self._create_finder(source) + result = list(finder.get_matches('${a}', args={'a': 'exact'})) + self.assertEquals(1, len(result)) + + def test_matching_normal_names_and_attributes(self): + source = 'x.a = 1\n' + finder = self._create_finder(source) + result = list(finder.get_matches('${a} = 1', args={'a': 'exact'})) + self.assertEquals(0, len(result)) + + def test_functions_not_matching_when_only_first_parameters(self): + source = 'f(1, 2)\n' + finder = self._create_finder(source) + self.assertEquals(0, len(list(finder.get_matches('f(1)')))) + + def test_matching_nested_try_finally(self): + source = 'if 1:\n try:\n pass\n except:\n pass\n' + pattern = 'try:\n pass\nexcept:\n pass\n' + finder = self._create_finder(source) + self.assertEquals(1, len(list(finder.get_matches(pattern)))) + + def test_matching_dicts_inside_functions(self): + source = 'def f(p):\n d = {1: p.x}\n' + pattern = '{1: ${a}.x}' + finder = self._create_finder(source) + self.assertEquals(1, len(list(finder.get_matches(pattern)))) + + +class CheckingFinderTest(unittest.TestCase): + + def setUp(self): + super(CheckingFinderTest, self).setUp() + self.project = testutils.sample_project() + self.pycore = self.project.pycore + self.mod1 = testutils.create_module(self.project, 'mod1') + + def tearDown(self): + testutils.remove_project(self.project) + super(CheckingFinderTest, self).tearDown() + + def test_trivial_case(self): + self.mod1.write('') + pymodule = self.pycore.resource_to_pyobject(self.mod1) + finder = similarfinder.SimilarFinder(pymodule) + self.assertEquals([], list(finder.get_matches('10', {}))) + + def test_simple_finding(self): + self.mod1.write('class A(object):\n pass\na = A()\n') + pymodule = self.pycore.resource_to_pyobject(self.mod1) + finder = similarfinder.SimilarFinder(pymodule) + result = list(finder.get_matches('${anything} = ${A}()', {})) + self.assertEquals(1, len(result)) + + def test_not_matching_when_the_name_does_not_match(self): + self.mod1.write('class A(object):\n pass\na = list()\n') + pymodule = self.pycore.resource_to_pyobject(self.mod1) + finder = similarfinder.SimilarFinder(pymodule) + result = list(finder.get_matches('${anything} = ${C}()', + {'C': 'name=mod1.A'})) + self.assertEquals(0, len(result)) + + def test_not_matching_unknowns_finding(self): + self.mod1.write('class A(object):\n pass\na = unknown()\n') + pymodule = self.pycore.resource_to_pyobject(self.mod1) + finder = similarfinder.SimilarFinder(pymodule) + result = list(finder.get_matches('${anything} = ${C}()', + {'C': 'name=mod1.A'})) + self.assertEquals(0, len(result)) + + def test_finding_and_matching_pyobjects(self): + source = 'class A(object):\n pass\nNewA = A\na = NewA()\n' + self.mod1.write(source) + pymodule = self.pycore.resource_to_pyobject(self.mod1) + finder = similarfinder.SimilarFinder(pymodule) + result = list(finder.get_matches('${anything} = ${A}()', + {'A': 'object=mod1.A'})) + self.assertEquals(1, len(result)) + start = source.rindex('a =') + self.assertEquals((start, len(source) - 1), result[0].get_region()) + + def test_finding_and_matching_types(self): + source = 'class A(object):\n def f(self):\n pass\n' \ + 'a = A()\nb = a.f()\n' + self.mod1.write(source) + pymodule = self.pycore.resource_to_pyobject(self.mod1) + finder = similarfinder.SimilarFinder(pymodule) + result = list(finder.get_matches('${anything} = ${inst}.f()', + {'inst': 'type=mod1.A'})) + self.assertEquals(1, len(result)) + start = source.rindex('b') + self.assertEquals((start, len(source) - 1), result[0].get_region()) + + def test_checking_the_type_of_an_ass_name_node(self): + self.mod1.write('class A(object):\n pass\nan_a = A()\n') + pymodule = self.pycore.resource_to_pyobject(self.mod1) + finder = similarfinder.SimilarFinder(pymodule) + result = list(finder.get_matches('${a} = ${assigned}', + {'a': 'type=mod1.A'})) + self.assertEquals(1, len(result)) + + def test_checking_instance_of_an_ass_name_node(self): + self.mod1.write('class A(object):\n pass\n' + 'class B(A):\n pass\nb = B()\n') + pymodule = self.pycore.resource_to_pyobject(self.mod1) + finder = similarfinder.SimilarFinder(pymodule) + result = list(finder.get_matches('${a} = ${assigned}', + {'a': 'instance=mod1.A'})) + self.assertEquals(1, len(result)) + + def test_checking_equality_of_imported_pynames(self): + mod2 = testutils.create_module(self.project, 'mod2') + mod2.write('class A(object):\n pass\n') + self.mod1.write('from mod2 import A\nan_a = A()\n') + pymod2 = self.pycore.resource_to_pyobject(mod2) + pymod1 = self.pycore.resource_to_pyobject(self.mod1) + finder = similarfinder.SimilarFinder(pymod1) + result = list(finder.get_matches('${a_class}()', + {'a_class': 'name=mod2.A'})) + self.assertEquals(1, len(result)) + + +class TemplateTest(unittest.TestCase): + + def test_simple_templates(self): + template = similarfinder.CodeTemplate('${a}\n') + self.assertEquals(set(['a']), set(template.get_names())) + + def test_ignoring_matches_in_comments(self): + template = similarfinder.CodeTemplate('#${a}\n') + self.assertEquals([], template.get_names()) + + def test_ignoring_matches_in_strings(self): + template = similarfinder.CodeTemplate("'${a}'\n") + self.assertEquals([], template.get_names()) + + def test_simple_substitution(self): + template = similarfinder.CodeTemplate('${a}\n') + self.assertEquals('b\n', template.substitute({'a': 'b'})) + + def test_substituting_multiple_names(self): + template = similarfinder.CodeTemplate('${a}, ${b}\n') + self.assertEquals('1, 2\n', template.substitute({'a': '1', 'b': '2'})) + + +def suite(): + result = unittest.TestSuite() + result.addTests(unittest.makeSuite(SimilarFinderTest)) + result.addTests(unittest.makeSuite(CheckingFinderTest)) + result.addTests(unittest.makeSuite(TemplateTest)) + return result + +if __name__ == '__main__': + unittest.main() diff -r e30544496575 -r 48cacfdc2ca6 vim/sadness/ropevim/src/rope/ropetest/refactor/suitestest.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vim/sadness/ropevim/src/rope/ropetest/refactor/suitestest.py Wed Oct 06 12:30:46 2010 -0400 @@ -0,0 +1,139 @@ +import unittest + +from rope.base import ast +from rope.refactor import suites + + +class SuiteTest(unittest.TestCase): + + def setUp(self): + super(SuiteTest, self).setUp() + + def tearDown(self): + super(SuiteTest, self).tearDown() + + def test_trivial_case(self): + root = source_suite_tree('') + self.assertEquals(1, root.get_start()) + self.assertEquals(0, len(root.get_children())) + + def test_simple_ifs(self): + root = source_suite_tree('if True:\n pass') + self.assertEquals(1, len(root.get_children())) + + def test_simple_else(self): + root = source_suite_tree( + 'if True:\n pass\nelse:\n pass\n') + self.assertEquals(2, len(root.get_children())) + self.assertEquals(1, root.get_children()[1].get_start()) + + def test_for(self): + root = source_suite_tree( + '\nfor i in range(10):\n pass\nelse:\n pass\n') + self.assertEquals(2, len(root.get_children())) + self.assertEquals(2, root.get_children()[1].get_start()) + + def test_while(self): + root = source_suite_tree( + 'while True:\n pass\n') + self.assertEquals(1, len(root.get_children())) + self.assertEquals(1, root.get_children()[0].get_start()) + + def test_with(self): + root = source_suite_tree( + 'from __future__ import with_statement\nwith file(x): pass\n') + self.assertEquals(1, len(root.get_children())) + self.assertEquals(2, root.get_children()[0].get_start()) + + def test_try_finally(self): + root = source_suite_tree( + 'try:\n pass\nfinally:\n pass\n') + self.assertEquals(2, len(root.get_children())) + self.assertEquals(1, root.get_children()[0].get_start()) + + def test_try_except(self): + root = source_suite_tree( + 'try:\n pass\nexcept:\n pass\nelse:\n pass\n') + self.assertEquals(3, len(root.get_children())) + self.assertEquals(1, root.get_children()[2].get_start()) + + def test_try_except_finally(self): + root = source_suite_tree( + 'try:\n pass\nexcept:\n pass\nfinally:\n pass\n') + self.assertEquals(3, len(root.get_children())) + self.assertEquals(1, root.get_children()[2].get_start()) + + def test_local_start_and_end(self): + root = source_suite_tree('if True:\n pass\nelse:\n pass\n') + self.assertEquals(1, root.local_start()) + self.assertEquals(4, root.local_end()) + if_suite = root.get_children()[0] + self.assertEquals(2, if_suite.local_start()) + self.assertEquals(2, if_suite.local_end()) + else_suite = root.get_children()[1] + self.assertEquals(4, else_suite.local_start()) + self.assertEquals(4, else_suite.local_end()) + + def test_find_suite(self): + root = source_suite_tree('\n') + self.assertEquals(root, root.find_suite(1)) + + def test_find_suite_for_ifs(self): + root = source_suite_tree('if True:\n pass\n') + if_suite = root.get_children()[0] + self.assertEquals(if_suite, root.find_suite(2)) + + def test_find_suite_for_between_suites(self): + root = source_suite_tree( + 'if True:\n pass\nprint(1)\nif True:\n pass\n') + if_suite1 = root.get_children()[0] + if_suite2 = root.get_children()[1] + self.assertEquals(if_suite1, root.find_suite(2)) + self.assertEquals(if_suite2, root.find_suite(5)) + self.assertEquals(root, root.find_suite(3)) + + def test_simple_find_visible(self): + root = source_suite_tree('a = 1\n') + self.assertEquals(1, suites.find_visible_for_suite(root, [1])) + + def test_simple_find_visible_ifs(self): + root = source_suite_tree('\nif True:\n a = 1\n b = 2\n') + self.assertEquals(root.find_suite(3), root.find_suite(4)) + self.assertEquals(3, suites.find_visible_for_suite(root, [3, 4])) + + def test_simple_find_visible_for_else(self): + root = source_suite_tree('\nif True:\n pass\nelse: pass\n') + self.assertEquals(2, suites.find_visible_for_suite(root, [2, 4])) + + def test_simple_find_visible_for_different_suites(self): + root = source_suite_tree('if True:\n pass\na = 1\n' + 'if False:\n pass\n') + self.assertEquals(1, suites.find_visible_for_suite(root, [2, 3])) + self.assertEquals(5, suites.find_visible_for_suite(root, [5])) + self.assertEquals(1, suites.find_visible_for_suite(root, [2, 5])) + + def test_not_always_selecting_scope_start(self): + root = source_suite_tree( + 'if True:\n a = 1\n if True:\n pass\n' + ' else:\n pass\n') + self.assertEquals(3, suites.find_visible_for_suite(root, [4, 6])) + self.assertEquals(3, suites.find_visible_for_suite(root, [3, 5])) + self.assertEquals(3, suites.find_visible_for_suite(root, [4, 5])) + + def test_ignoring_functions(self): + root = source_suite_tree( + 'def f():\n pass\na = 1\n') + self.assertEquals(3, suites.find_visible_for_suite(root, [2, 3])) + + def test_ignoring_classes(self): + root = source_suite_tree( + 'a = 1\nclass C():\n pass\n') + self.assertEquals(1, suites.find_visible_for_suite(root, [1, 3])) + + +def source_suite_tree(source): + return suites.ast_suite_tree(ast.parse(source)) + + +if __name__ == '__main__': + unittest.main() diff -r e30544496575 -r 48cacfdc2ca6 vim/sadness/ropevim/src/rope/ropetest/refactor/usefunctiontest.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vim/sadness/ropevim/src/rope/ropetest/refactor/usefunctiontest.py Wed Oct 06 12:30:46 2010 -0400 @@ -0,0 +1,122 @@ +import unittest + +from rope.base import exceptions +from ropetest import testutils +from rope.refactor.usefunction import UseFunction + + +class UseFunctionTest(unittest.TestCase): + + def setUp(self): + super(UseFunctionTest, self).setUp() + self.project = testutils.sample_project() + self.mod1 = testutils.create_module(self.project, 'mod1') + self.mod2 = testutils.create_module(self.project, 'mod2') + + def tearDown(self): + testutils.remove_project(self.project) + super(UseFunctionTest, self).tearDown() + + def test_simple_case(self): + code = 'def f():\n pass\n' + self.mod1.write(code) + user = UseFunction(self.project, self.mod1, code.rindex('f')) + self.project.do(user.get_changes()) + self.assertEquals(code, self.mod1.read()) + + def test_simple_function(self): + code = 'def f(p):\n print(p)\nprint(1)\n' + self.mod1.write(code) + user = UseFunction(self.project, self.mod1, code.rindex('f')) + self.project.do(user.get_changes()) + self.assertEquals('def f(p):\n print(p)\nf(1)\n', + self.mod1.read()) + + def test_simple_function2(self): + code = 'def f(p):\n print(p + 1)\nprint(1 + 1)\n' + self.mod1.write(code) + user = UseFunction(self.project, self.mod1, code.rindex('f')) + self.project.do(user.get_changes()) + self.assertEquals('def f(p):\n print(p + 1)\nf(1)\n', + self.mod1.read()) + + def test_functions_with_multiple_statements(self): + code = 'def f(p):\n r = p + 1\n print(r)\nr = 2 + 1\nprint(r)\n' + self.mod1.write(code) + user = UseFunction(self.project, self.mod1, code.rindex('f')) + self.project.do(user.get_changes()) + self.assertEquals('def f(p):\n r = p + 1\n print(r)\nf(2)\n', + self.mod1.read()) + + def test_returning(self): + code = 'def f(p):\n return p + 1\nr = 2 + 1\nprint(r)\n' + self.mod1.write(code) + user = UseFunction(self.project, self.mod1, code.rindex('f')) + self.project.do(user.get_changes()) + self.assertEquals( + 'def f(p):\n return p + 1\nr = f(2)\nprint(r)\n', + self.mod1.read()) + + def test_returning_a_single_expression(self): + code = 'def f(p):\n return p + 1\nprint(2 + 1)\n' + self.mod1.write(code) + user = UseFunction(self.project, self.mod1, code.rindex('f')) + self.project.do(user.get_changes()) + self.assertEquals( + 'def f(p):\n return p + 1\nprint(f(2))\n', + self.mod1.read()) + + def test_occurrences_in_other_modules(self): + code = 'def f(p):\n return p + 1\n' + self.mod1.write(code) + user = UseFunction(self.project, self.mod1, code.rindex('f')) + self.mod2.write('print(2 + 1)\n') + self.project.do(user.get_changes()) + self.assertEquals('import mod1\nprint(mod1.f(2))\n', + self.mod2.read()) + + @testutils.assert_raises(exceptions.RefactoringError) + def test_when_performing_on_non_functions(self): + code = 'var = 1\n' + self.mod1.write(code) + user = UseFunction(self.project, self.mod1, code.rindex('var')) + + def test_differing_in_the_inner_temp_names(self): + code = 'def f(p):\n a = p + 1\n print(a)\nb = 2 + 1\nprint(b)\n' + self.mod1.write(code) + user = UseFunction(self.project, self.mod1, code.rindex('f')) + self.project.do(user.get_changes()) + self.assertEquals('def f(p):\n a = p + 1\n print(a)\nf(2)\n', + self.mod1.read()) + + # TODO: probably new options should be added to restructure + def xxx_test_being_a_bit_more_intelligent_when_returning_assigneds(self): + code = 'def f(p):\n a = p + 1\n return a\n'\ + 'var = 2 + 1\nprint(var)\n' + self.mod1.write(code) + user = UseFunction(self.project, self.mod1, code.rindex('f')) + self.project.do(user.get_changes()) + self.assertEquals('def f(p):\n a = p + 1\n return a\n' + 'var = f(p)\nprint(var)\n', self.mod1.read()) + + @testutils.assert_raises(exceptions.RefactoringError) + def test_exception_when_performing_a_function_with_yield(self): + code = 'def func():\n yield 1\n' + self.mod1.write(code) + user = UseFunction(self.project, self.mod1, code.index('func')) + + @testutils.assert_raises(exceptions.RefactoringError) + def test_exception_when_performing_a_function_two_returns(self): + code = 'def func():\n return 1\n return 2\n' + self.mod1.write(code) + user = UseFunction(self.project, self.mod1, code.index('func')) + + @testutils.assert_raises(exceptions.RefactoringError) + def test_exception_when_returns_is_not_the_last_statement(self): + code = 'def func():\n return 2\n a = 1\n' + self.mod1.write(code) + user = UseFunction(self.project, self.mod1, code.index('func')) + + +if __name__ == '__main__': + unittest.main() diff -r e30544496575 -r 48cacfdc2ca6 vim/sadness/ropevim/src/rope/ropetest/runmodtest.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vim/sadness/ropevim/src/rope/ropetest/runmodtest.py Wed Oct 06 12:30:46 2010 -0400 @@ -0,0 +1,152 @@ +import os +import unittest + +from rope.base import exceptions +from ropetest import testutils + + +class PythonFileRunnerTest(unittest.TestCase): + + def setUp(self): + super(PythonFileRunnerTest, self).setUp() + self.project = testutils.sample_project() + self.pycore = self.project.pycore + + def tearDown(self): + testutils.remove_project(self.project) + super(PythonFileRunnerTest, self).tearDown() + + def make_sample_python_file(self, file_path, get_text_function_source=None): + self.project.root.create_file(file_path) + file = self.project.get_resource(file_path) + if not get_text_function_source: + get_text_function_source = "def get_text():\n return 'run'\n\n" + file_content = get_text_function_source + \ + "output = open('output.txt', 'w')\n" \ + "output.write(get_text())\noutput.close()\n" + file.write(file_content) + + def get_output_file_content(self, file_path): + try: + output_path = '' + last_slash = file_path.rfind('/') + if last_slash != -1: + output_path = file_path[0:last_slash + 1] + file = self.project.get_resource(output_path + 'output.txt') + return file.read() + except exceptions.ResourceNotFoundError: + return '' + + def test_making_runner(self): + file_path = 'sample.py' + self.make_sample_python_file(file_path) + file_resource = self.project.get_resource(file_path) + runner = self.pycore.run_module(file_resource) + runner.wait_process() + self.assertEquals('run', self.get_output_file_content(file_path)) + + def test_passing_arguments(self): + file_path = 'sample.py' + function_source = 'import sys\ndef get_text():\n return str(sys.argv[1:])\n' + self.make_sample_python_file(file_path, function_source) + file_resource = self.project.get_resource(file_path) + runner = self.pycore.run_module(file_resource, args=['hello', 'world']) + runner.wait_process() + self.assertTrue(self.get_output_file_content(file_path).endswith("['hello', 'world']")) + + def test_passing_arguments_with_spaces(self): + file_path = 'sample.py' + function_source = 'import sys\ndef get_text():\n return str(sys.argv[1:])\n' + self.make_sample_python_file(file_path, function_source) + file_resource = self.project.get_resource(file_path) + runner = self.pycore.run_module(file_resource, args=['hello world']) + runner.wait_process() + self.assertTrue(self.get_output_file_content(file_path).endswith("['hello world']")) + + def test_killing_runner(self): + file_path = 'sample.py' + self.make_sample_python_file(file_path, + "def get_text():" + + "\n import time\n time.sleep(1)\n return 'run'\n") + file_resource = self.project.get_resource(file_path) + runner = self.pycore.run_module(file_resource) + runner.kill_process() + self.assertEquals('', self.get_output_file_content(file_path)) + + def test_running_nested_files(self): + self.project.root.create_folder('src') + file_path = 'src/sample.py' + self.make_sample_python_file(file_path) + file_resource = self.project.get_resource(file_path) + runner = self.pycore.run_module(file_resource) + runner.wait_process() + self.assertEquals('run', self.get_output_file_content(file_path)) + + def test_setting_process_input(self): + file_path = 'sample.py' + self.make_sample_python_file(file_path, + "def get_text():" + + "\n import sys\n return sys.stdin.readline()\n") + temp_file_name = 'processtest.tmp' + try: + temp_file = open(temp_file_name, 'w') + temp_file.write('input text\n') + temp_file.close() + file_resource = self.project.get_resource(file_path) + stdin = open(temp_file_name) + runner = self.pycore.run_module(file_resource, stdin=stdin) + runner.wait_process() + stdin.close() + self.assertEquals('input text\n', self.get_output_file_content(file_path)) + finally: + os.remove(temp_file_name) + + def test_setting_process_output(self): + file_path = 'sample.py' + self.make_sample_python_file(file_path, + "def get_text():" + + "\n print 'output text'\n return 'run'\n") + temp_file_name = 'processtest.tmp' + try: + file_resource = self.project.get_resource(file_path) + stdout = open(temp_file_name, 'w') + runner = self.pycore.run_module(file_resource, stdout=stdout) + runner.wait_process() + stdout.close() + temp_file = open(temp_file_name, 'r') + self.assertEquals('output text\n', temp_file.read()) + temp_file.close() + finally: + os.remove(temp_file_name) + + def test_setting_pythonpath(self): + src = self.project.root.create_folder('src') + src.create_file('sample.py') + src.get_child('sample.py').write('def f():\n pass\n') + self.project.root.create_folder('test') + file_path = 'test/test.py' + self.make_sample_python_file(file_path, + "def get_text():\n" + " import sample\n sample.f()\n return'run'\n") + file_resource = self.project.get_resource(file_path) + runner = self.pycore.run_module(file_resource) + runner.wait_process() + self.assertEquals('run', self.get_output_file_content(file_path)) + + def test_making_runner_when_doi_is_disabled(self): + self.project.set('enable_doi', False) + file_path = 'sample.py' + self.make_sample_python_file(file_path) + file_resource = self.project.get_resource(file_path) + runner = self.pycore.run_module(file_resource) + runner.wait_process() + self.assertEquals('run', self.get_output_file_content(file_path)) + + +def suite(): + result = unittest.TestSuite() + result.addTests(unittest.makeSuite(PythonFileRunnerTest)) + return result + +if __name__ == '__main__': + unittest.main() diff -r e30544496575 -r 48cacfdc2ca6 vim/sadness/ropevim/src/rope/ropetest/simplifytest.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vim/sadness/ropevim/src/rope/ropetest/simplifytest.py Wed Oct 06 12:30:46 2010 -0400 @@ -0,0 +1,68 @@ +import unittest + +from rope.base import simplify + + +class SimplifyTest(unittest.TestCase): + + def setUp(self): + super(SimplifyTest, self).setUp() + + def tearDown(self): + super(SimplifyTest, self).tearDown() + + def test_trivial_case(self): + self.assertEquals('', simplify.real_code('')) + + def test_empty_strs(self): + code = 's = ""\n' + self.assertEquals(code, simplify.real_code(code)) + + def test_blanking_strs(self): + code = 's = "..."\n' + self.assertEquals('s = " "\n', simplify.real_code(code)) + + def test_changing_to_double_quotes(self): + code = 's = \'\'\n' + self.assertEquals('s = ""\n', simplify.real_code(code)) + + def test_changing_to_double_quotes2(self): + code = 's = """\n"""\n' + self.assertEquals('s = " "\n', simplify.real_code(code)) + + def test_removing_comments(self): + code = '# c\n' + self.assertEquals(' \n', simplify.real_code(code)) + + def test_removing_comments_that_contain_strings(self): + code = '# "c"\n' + self.assertEquals(' \n', simplify.real_code(code)) + + def test_removing_strings_containing_comments(self): + code = '"#c"\n' + self.assertEquals('" "\n', simplify.real_code(code)) + + def test_joining_implicit_continuations(self): + code = '(\n)\n' + self.assertEquals('( )\n', simplify.real_code(code)) + + def test_joining_explicit_continuations(self): + code = '1 + \\\n 2\n' + self.assertEquals('1 + 2\n', simplify.real_code(code)) + + def test_replacing_tabs(self): + code = '1\t+\t2\n' + self.assertEquals('1 + 2\n', simplify.real_code(code)) + + def test_replacing_semicolons(self): + code = 'a = 1;b = 2\n' + self.assertEquals('a = 1\nb = 2\n', simplify.real_code(code)) + + +def suite(): + result = unittest.TestSuite() + result.addTests(unittest.makeSuite(SimplifyTest)) + return result + +if __name__ == '__main__': + unittest.main() diff -r e30544496575 -r 48cacfdc2ca6 vim/sadness/ropevim/src/rope/ropetest/testutils.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vim/sadness/ropevim/src/rope/ropetest/testutils.py Wed Oct 06 12:30:46 2010 -0400 @@ -0,0 +1,98 @@ +import os.path +import shutil +import sys + +import rope.base.project +from rope.contrib import generate + + +def sample_project(root=None, foldername=None, **kwds): + if root is None: + root = 'sample_project' + if foldername: + root = foldername + # HACK: Using ``/dev/shm/`` for faster tests + if os.name == 'posix' and os.path.isdir('/dev/shm'): + root = '/dev/shm/' + root + # Using these prefs for faster tests + prefs = {'save_objectdb': False, 'save_history': False, + 'validate_objectdb': False, 'automatic_soa': False, + 'ignored_resources': ['.ropeproject', '*.pyc'], + 'import_dynload_stdmods': False} + prefs.update(kwds) + remove_recursively(root) + project = rope.base.project.Project(root, **prefs) + return project + +create_module = generate.create_module +create_package = generate.create_package + +def remove_project(project): + project.close() + remove_recursively(project.address) + + +def remove_recursively(path): + import time + # windows sometimes raises exceptions instead of removing files + if os.name == 'nt' or sys.platform == 'cygwin': + for i in range(12): + try: + _remove_recursively(path) + except OSError, e: + if e.errno not in (13, 16, 32): + raise + time.sleep(0.3) + else: + break + else: + _remove_recursively(path) + +def _remove_recursively(path): + if not os.path.exists(path): + return + if os.path.isfile(path): + os.remove(path) + else: + shutil.rmtree(path) + + +def run_only_for_25(func): + """Should be used as a decorator for a unittest.TestCase test method""" + if sys.version_info >= (2, 5, 0): + return func + else: + def do_nothing(self): + pass + return do_nothing + + +def only_for(version): + """Should be used as a decorator for a unittest.TestCase test method""" + def decorator(func): + if sys.version >= version: + return func + else: + def do_nothing(self): + pass + return do_nothing + return decorator + + +def run_only_for_unix(func): + """Should be used as a decorator for a unittest.TestCase test method""" + if os.name == 'posix': + return func + else: + def do_nothing(self): + pass + return do_nothing + + +def assert_raises(exception_class): + """Should be used as a decorator for a unittest.TestCase test method""" + def _assert_raises(func): + def call_func(self, *args, **kws): + self.assertRaises(exception_class, func, self, *args, **kws) + return call_func + return _assert_raises diff -r e30544496575 -r 48cacfdc2ca6 vim/sadness/ropevim/src/rope/setup.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vim/sadness/ropevim/src/rope/setup.py Wed Oct 06 12:30:46 2010 -0400 @@ -0,0 +1,45 @@ +import glob +import os +import shutil + +extra_kwargs = {} +try: + # we don't want to depend on setuptools + # please don't use any setuptools specific API + from setuptools import setup + extra_kwargs['test_suite'] = 'ropetest' +except ImportError: + from distutils.core import setup + +import rope + + +classifiers=[ + 'Development Status :: 4 - Beta', + 'Operating System :: OS Independent', + 'Environment :: X11 Applications', + 'Environment :: Win32 (MS Windows)', + 'Environment :: MacOS X', + 'Intended Audience :: Developers', + 'License :: OSI Approved :: GNU General Public License (GPL)', + 'Natural Language :: English', + 'Programming Language :: Python', + 'Topic :: Software Development'] + +def get_long_description(): + lines = open('README.txt').read().splitlines(False) + end = lines.index('Getting Started') + return '\n' + '\n'.join(lines[:end]) + '\n' + +setup(name='rope', + version=rope.VERSION, + description='a python refactoring library...', + long_description=get_long_description(), + author='Ali Gholami Rudi', + author_email='aligrudi@users.sourceforge.net', + url='http://rope.sf.net/', + packages=['rope', 'rope.base', 'rope.base.oi', 'rope.refactor', + 'rope.refactor.importutils', 'rope.contrib'], + license='GNU GPL', + classifiers=classifiers, + **extra_kwargs) diff -r e30544496575 -r 48cacfdc2ca6 vim/sadness/ropevim/src/ropemode/.hgignore --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vim/sadness/ropevim/src/ropemode/.hgignore Wed Oct 06 12:30:46 2010 -0400 @@ -0,0 +1,9 @@ +syntax:glob + +*.pyc +*.*~ +*.*.orig +*.egg-info +doc/build +build +dist diff -r e30544496575 -r 48cacfdc2ca6 vim/sadness/ropevim/src/ropemode/.hgtags --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vim/sadness/ropevim/src/ropemode/.hgtags Wed Oct 06 12:30:46 2010 -0400 @@ -0,0 +1,1 @@ +e75b75d70ac93804e9e4f90ddab8c294df8088b5 0.1-rc diff -r e30544496575 -r 48cacfdc2ca6 vim/sadness/ropevim/src/ropemode/ropemode/__init__.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vim/sadness/ropevim/src/ropemode/ropemode/__init__.py Wed Oct 06 12:30:46 2010 -0400 @@ -0,0 +1,16 @@ +"""ropemode, a helper for using rope refactoring library in IDEs""" + +INFO = __doc__ +VERSION = '0.1-rc2' +COPYRIGHT = """\ +Copyright (C) 2007-2008 Ali Gholami Rudi + +This program is free software; you can redistribute it and/or modify it +under the terms of GNU General Public License as published by the +Free Software Foundation; either version 2 of the license, or (at your +opinion) 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.""" diff -r e30544496575 -r 48cacfdc2ca6 vim/sadness/ropevim/src/ropemode/ropemode/decorators.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vim/sadness/ropevim/src/ropemode/ropemode/decorators.py Wed Oct 06 12:30:46 2010 -0400 @@ -0,0 +1,98 @@ +import traceback + +from rope.base import exceptions + + +class Logger(object): + + message = None + only_short = False + + def __call__(self, message, short=None): + if short is None or not self.only_short: + self._show(message) + if short is not None: + self._show(short) + + def _show(self, message): + if message is None: + print message + else: + self.message(message) + +logger = Logger() + + +def lisphook(func): + def newfunc(*args, **kwds): + try: + func(*args, **kwds) + except Exception, e: + trace = str(traceback.format_exc()) + short = 'Ignored an exception in ropemode hook: %s' % \ + _exception_message(e) + logger(trace, short) + newfunc.lisp = None + newfunc.__name__ = func.__name__ + newfunc.__doc__ = func.__doc__ + return newfunc + + +def lispfunction(func): + func.lisp = None + return func + + +input_exceptions = (exceptions.RefactoringError, + exceptions.ModuleSyntaxError, + exceptions.BadIdentifierError) + +def _exception_handler(func): + def newfunc(*args, **kwds): + try: + return func(*args, **kwds) + except exceptions.RopeError, e: + short = None + if isinstance(e, input_exceptions): + short = _exception_message(e) + logger(str(traceback.format_exc()), short) + newfunc.__name__ = func.__name__ + newfunc.__doc__ = func.__doc__ + return newfunc + +def _exception_message(e): + return '%s: %s' % (e.__class__.__name__, str(e)) + +def rope_hook(hook): + def decorator(func): + func = lisphook(func) + func.name = func.__name__ + func.kind = 'hook' + func.hook = hook + return func + return decorator + + +def local_command(key=None, prefix=False, shortcut=None, name=None): + def decorator(func, name=name): + func = _exception_handler(func) + func.kind = 'local' + func.prefix = prefix + func.local_key = key + func.shortcut_key = shortcut + if name is None: + name = func.__name__ + func.name = name + return func + return decorator + + +def global_command(key=None, prefix=False): + def decorator(func): + func = _exception_handler(func) + func.kind = 'global' + func.prefix = prefix + func.global_key = key + func.name = func.__name__ + return func + return decorator diff -r e30544496575 -r 48cacfdc2ca6 vim/sadness/ropevim/src/ropemode/ropemode/dialog.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vim/sadness/ropevim/src/ropemode/ropemode/dialog.py Wed Oct 06 12:30:46 2010 -0400 @@ -0,0 +1,97 @@ +class Data(object): + + def __init__(self, prompt=None, default=None, values=None, + kind=None, decode=None): + self.prompt = prompt + self.default = default + self.values = values + self.kind = kind + self._decode = decode + + def decode(self, value): + if self._decode: + return self._decode(value) + return value + + +class Boolean(Data): + + def __init__(self, prompt=None, default=False): + Data.__init__(self, prompt, self._encode(default), + [self._encode(True), self._encode(False)]) + + def _encode(self, value): + if value: + return 'yes' + return 'no' + + def decode(self, value): + if value.lower() in ('yes', '1', 'true'): + return True + return False + + +def show_dialog(askdata, actions, confs={}, optionals={}, initial_asking=True): + result = {} + if initial_asking: + for name, conf in confs.items(): + result[name] = askdata(conf) + actions.append('batchset') + names = list(actions) + names.extend(optionals.keys()) + names.extend(confs.keys()) + base_question = Data('Choose what to do: ', + default=actions[0], values=names) + batchset_question = Data('Batch sets: ') + while True: + response = askdata(base_question) + if response == '': + response = base_question.default + elif response == 'batchset': + sets = askdata(batchset_question) + for key, value in _parse_batchset(sets).items(): + if key.endswith(':'): + key = key[:-1] + if key in names: + conf = confs.get(key, optionals.get(key)) + result[key] = value + elif response in actions: + break + else: + if response in confs: + conf = confs[response] + else: + conf = optionals[response] + oldvalue = result.get(response, None) + result[response] = askdata(conf, starting=oldvalue) + decoded = {} + all_confs = dict(confs) + all_confs.update(optionals) + for key in all_confs: + conf = all_confs.get(key) + if key in result: + decoded[key] = conf.decode(result[key]) + else: + decoded[key] = conf.decode(conf.default) + return response, decoded + + +def _parse_batchset(sets): + result = [] + multiline = False + for line in sets.splitlines(True): + if line[0].isspace(): + if multiline: + result[-1][1] += line[1:] + else: + if not line.strip(): + continue + multiline= False + tokens = line.split(None, 1) + value = '' + if len(tokens) > 1: + result.append([tokens[0], tokens[1].rstrip('\r\n')]) + else: + multiline = True + result.append([tokens[0], '']) + return dict(result) diff -r e30544496575 -r 48cacfdc2ca6 vim/sadness/ropevim/src/ropemode/ropemode/environment.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vim/sadness/ropevim/src/ropemode/ropemode/environment.py Wed Oct 06 12:30:46 2010 -0400 @@ -0,0 +1,101 @@ +class Environment(object): + + def ask(self, prompt, default=None, starting=None): + pass + + def ask_values(self, prompt, values, default=None, starting=None): + pass + + def ask_directory(self, prompt, default=None, starting=None): + pass + + def ask_completion(self, prompt, values, starting=None): + pass + + def message(self, message): + pass + + def yes_or_no(self, prompt): + pass + + def y_or_n(self, prompt): + pass + + def get(self, name, default=None): + pass + + def get_offset(self): + pass + + def get_text(self): + pass + + def get_region(self): + pass + + def filename(self): + pass + + def is_modified(self): + pass + + def goto_line(self, lineno): + pass + + def insert_line(self, line, lineno): + pass + + def insert(self, text): + pass + + def delete(self, start, end): + pass + + def filenames(self): + pass + + def save_files(self, filenames): + pass + + def reload_files(self, filenames, moves={}): + pass + + def find_file(self, filename, readonly=False, other=False): + pass + + def create_progress(self, name): + pass + + def current_word(self): + pass + + def push_mark(self): + pass + + def prefix_value(self, prefix): + pass + + def show_occurrences(self, locations): + pass + + def show_doc(self, docs, altview=False): + pass + + def preview_changes(self, diffs): + pass + + def local_command(self, name, callback, key=None, prefix=False): + pass + + def global_command(self, name, callback, key=None, prefix=False): + pass + + def add_hook(self, name, callback, hook): + pass + + def _completion_text(self, proposal): + return proposal.name + + def _completion_data(self, proposal): + return self._completion_text(proposal) + diff -r e30544496575 -r 48cacfdc2ca6 vim/sadness/ropevim/src/ropemode/ropemode/filter.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vim/sadness/ropevim/src/ropemode/ropemode/filter.py Wed Oct 06 12:30:46 2010 -0400 @@ -0,0 +1,39 @@ +from rope.base import exceptions + + +def resources(project, rules): + """Find python files in the `project` matching `rules` + + `rules` is a multi-line `str`; each line starts with either a '+' + or '-'. Each '+' means include the file (or its children if it's + a folder) that comes after it. '-' has the same meaning for + exclusion. + + """ + all = set(project.pycore.get_python_files()) + files = None + for line in rules.splitlines(): + if not line.strip(): + continue + first, path = (line[0], line[1:]) + if first not in '+-': + continue + try: + resource = project.get_resource(path.strip()) + except exceptions.ResourceNotFoundError: + continue + if resource.is_folder(): + matches = set(filter(lambda item: resource.contains(item), all)) + else: + matches = set([resource]) + if first == '+': + if files is None: + files = set() + files.update(matches) + if first == '-': + if files is None: + files = set(all) + files -= matches + if files is None: + return all + return files diff -r e30544496575 -r 48cacfdc2ca6 vim/sadness/ropevim/src/ropemode/ropemode/interface.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vim/sadness/ropevim/src/ropemode/ropemode/interface.py Wed Oct 06 12:30:46 2010 -0400 @@ -0,0 +1,677 @@ +import os + +import rope.base.change +from rope.base import libutils, utils, exceptions +from rope.contrib import codeassist, generate, autoimport, findit + +from ropemode import refactor, decorators, dialog + + +class RopeMode(object): + + def __init__(self, env): + self.project = None + self.old_content = None + self.env = env + + self._prepare_refactorings() + self.autoimport = None + self._init_mode() + + def init(self): + """Initialize rope mode""" + + def _init_mode(self): + for attrname in dir(self): + attr = getattr(self, attrname) + if not callable(attr): + continue + kind = getattr(attr, 'kind', None) + if kind == 'local': + key = getattr(attr, 'local_key', None) + prefix = getattr(attr, 'prefix', None) + self.env.local_command(attrname, attr, key, prefix) + if kind == 'global': + key = getattr(attr, 'global_key', None) + prefix = getattr(attr, 'prefix', None) + self.env.global_command(attrname, attr, key, prefix) + if kind == 'hook': + hook = getattr(attr, 'hook', None) + self.env.add_hook(attrname, attr, hook) + + def _prepare_refactorings(self): + for name in dir(refactor): + if not name.startswith('_') and name != 'Refactoring': + attr = getattr(refactor, name) + if isinstance(attr, type) and \ + issubclass(attr, refactor.Refactoring): + refname = self._refactoring_name(attr) + @decorators.local_command(attr.key, 'P', None, refname) + def do_refactor(prefix, self=self, refactoring=attr): + initial_asking = prefix is None + refactoring(self, self.env).show(initial_asking=initial_asking) + setattr(self, refname, do_refactor) + + def _refactoring_name(self, refactoring): + return refactor.refactoring_name(refactoring) + + @decorators.rope_hook('before_save') + def before_save_actions(self): + if self.project is not None: + if not self._is_python_file(self.env.filename()): + return + resource = self._get_resource() + if resource.exists(): + self.old_content = resource.read() + else: + self.old_content = '' + + @decorators.rope_hook('after_save') + def after_save_actions(self): + if self.project is not None and self.old_content is not None: + libutils.report_change(self.project, self.env.filename(), + self.old_content) + self.old_content = None + + @decorators.rope_hook('exit') + def exiting_actions(self): + if self.project is not None: + self.close_project() + + @decorators.global_command('o') + def open_project(self, root=None): + if not root: + root = self.env.ask_directory('Rope project root folder: ') + if self.project is not None: + self.close_project() + address = rope.base.project._realpath(os.path.join(root, + '.ropeproject')) + if not os.path.exists(address): + if not self.env.y_or_n('Project not exists in %s, ' \ + 'create one?' % root): + self.env.message("Project creation aborted") + return + progress = self.env.create_progress('Opening [%s] project' % root) + self.project = rope.base.project.Project(root) + if self.env.get('enable_autoimport'): + underlined = self.env.get('autoimport_underlineds') + self.autoimport = autoimport.AutoImport(self.project, + underlined=underlined) + progress.done() + + @decorators.global_command('k') + def close_project(self): + if self.project is not None: + progress = self.env.create_progress('Closing [%s] project' % + self.project.address) + self.project.close() + self.project = None + progress.done() + + @decorators.global_command() + def write_project(self): + if self.project is not None: + progress = self.env.create_progress( + 'Writing [%s] project data to disk' % self.project.address) + self.project.sync() + progress.done() + + @decorators.global_command('u') + def undo(self): + self._check_project() + change = self.project.history.tobe_undone + if change is None: + self.env.message('Nothing to undo!') + return + if self.env.y_or_n('Undo [%s]? ' % str(change)): + def undo(handle): + for changes in self.project.history.undo(task_handle=handle): + self._reload_buffers(changes, undo=True) + refactor.runtask(self.env, undo, 'Undo refactoring', + interrupts=False) + + @decorators.global_command('r') + def redo(self): + self._check_project() + change = self.project.history.tobe_redone + if change is None: + self.env.message('Nothing to redo!') + return + if self.env.y_or_n('Redo [%s]? ' % str(change)): + def redo(handle): + for changes in self.project.history.redo(task_handle=handle): + self._reload_buffers(changes) + refactor.runtask(self.env, redo, 'Redo refactoring', + interrupts=False) + + @decorators.local_command('a g', shortcut='C-c g') + def goto_definition(self): + definition = self._base_definition_location() + if definition: + self.env.push_mark() + self._goto_location(definition[0], definition[1]) + else: + self.env.message('Cannot find the definition!') + + @decorators.local_command() + def definition_location(self): + definition = self._base_definition_location() + if definition: + return str(definition[0].real_path), definition[1] + return None + + def _base_definition_location(self): + self._check_project() + resource, offset = self._get_location() + maxfixes = self.env.get('codeassist_maxfixes') + try: + definition = codeassist.get_definition_location( + self.project, self._get_text(), offset, resource, maxfixes) + except exceptions.BadIdentifierError: + return None + if tuple(definition) != (None, None): + return definition + return None + + @decorators.local_command('a d', 'P', 'C-c d') + def show_doc(self, prefix): + self._check_project() + self._base_show_doc(prefix, codeassist.get_doc) + + @decorators.local_command('a c', 'P') + def show_calltip(self, prefix): + self._check_project() + def _get_doc(project, text, offset, *args, **kwds): + try: + offset = text.rindex('(', 0, offset) - 1 + except ValueError: + return None + return codeassist.get_calltip(project, text, offset, *args, **kwds) + self._base_show_doc(prefix, _get_doc) + + def _base_show_doc(self, prefix, get_doc): + docs = self._base_get_doc(get_doc) + if docs: + self.env.show_doc(docs, prefix) + else: + self.env.message('No docs available!') + + @decorators.local_command() + def get_doc(self): + self._check_project() + return self._base_get_doc(codeassist.get_doc) + + def _base_get_doc(self, get_doc): + maxfixes = self.env.get('codeassist_maxfixes') + text = self._get_text() + offset = self.env.get_offset() + try: + return get_doc(self.project, text, offset, + self.resource, maxfixes) + except exceptions.BadIdentifierError: + return None + + def _get_text(self): + resource = self.resource + if not self.env.is_modified() and resource is not None: + return resource.read() + return self.env.get_text() + + def _base_findit(self, do_find, optionals, get_kwds): + self._check_project() + self._save_buffers() + resource, offset = self._get_location() + + action, values = dialog.show_dialog( + self._askdata, ['search', 'cancel'], optionals=optionals) + if action == 'search': + kwds = get_kwds(values) + def calculate(handle): + resources = refactor._resources(self.project, + values.get('resources')) + return do_find(self.project, resource, offset, + resources=resources, task_handle=handle, **kwds) + result = refactor.runtask(self.env, calculate, 'Find Occurrences') + locations = [Location(location) for location in result] + self.env.show_occurrences(locations) + + @decorators.local_command('a f', shortcut='C-c f') + def find_occurrences(self): + optionals = { + 'unsure': dialog.Data('Find uncertain occurrences: ', + default='no', values=['yes', 'no']), + 'resources': dialog.Data('Files to search: '), + 'in_hierarchy': dialog.Data( + 'Rename methods in class hierarchy: ', + default='no', values=['yes', 'no'])} + def get_kwds(values): + return {'unsure': values.get('unsure') == 'yes', + 'in_hierarchy': values.get('in_hierarchy') == 'yes'} + self._base_findit(findit.find_occurrences, optionals, get_kwds) + + @decorators.local_command('a i') + def find_implementations(self): + optionals = {'resources': dialog.Data('Files to search: ')} + def get_kwds(values): + return {} + self._base_findit(findit.find_implementations, optionals, get_kwds) + + @decorators.local_command('a /', 'P', 'M-/') + def code_assist(self, prefix): + _CodeAssist(self, self.env).code_assist(prefix) + + @decorators.local_command('a ?', 'P', 'M-?') + def lucky_assist(self, prefix): + _CodeAssist(self, self.env).lucky_assist(prefix) + + @decorators.local_command() + def auto_import(self): + _CodeAssist(self, self.env).auto_import() + + @decorators.local_command() + def completions(self): + return _CodeAssist(self, self.env).completions() + + @decorators.local_command() + def extended_completions(self): + return _CodeAssist(self, self.env).extended_completions() + + def _check_autoimport(self): + self._check_project() + if self.autoimport is None: + self.env.message('autoimport is disabled; ' + 'see `enable_autoimport\' variable') + return False + return True + + @decorators.global_command() + def generate_autoimport_cache(self): + if not self._check_autoimport(): + return + modules = self.env.get('autoimport_modules') + modnames = [] + if modules: + for i in range(len(modules)): + modname = modules[i] + if not isinstance(modname, basestring): + modname = modname.value() + modnames.append(modname) + else: + modules = [] + def generate(handle): + self.autoimport.generate_cache(task_handle=handle) + self.autoimport.generate_modules_cache(modules, task_handle=handle) + refactor.runtask(self.env, generate, 'Generate autoimport cache') + + @decorators.global_command('f', 'P') + def find_file(self, prefix): + file = self._base_find_file(prefix) + if file is not None: + self.env.find_file(file.real_path) + + @decorators.global_command('4 f', 'P') + def find_file_other_window(self, prefix): + file = self._base_find_file(prefix) + if file is not None: + self.env.find_file(file.real_path, other=True) + + def _base_find_file(self, prefix): + self._check_project() + if prefix: + files = self.project.pycore.get_python_files() + else: + files = self.project.get_files() + return self._ask_file(files) + + def _ask_file(self, files): + names = [] + for file in files: + names.append('<'.join(reversed(file.path.split('/')))) + result = self.env.ask_values('Rope Find File: ', names) + if result is not None: + path = '/'.join(reversed(result.split('<'))) + file = self.project.get_file(path) + return file + self.env.message('No file selected') + + @decorators.local_command('a j') + def jump_to_global(self): + if not self._check_autoimport(): + return + all_names = list(self.autoimport.get_all_names()) + name = self.env.ask_values('Global name: ', all_names) + result = dict(self.autoimport.get_name_locations(name)) + if len(result) == 1: + resource = list(result.keys())[0] + else: + resource = self._ask_file(result.keys()) + if resource: + self._goto_location(resource, result[resource]) + + @decorators.global_command('c') + def project_config(self): + self._check_project() + if self.project.ropefolder is not None: + config = self.project.ropefolder.get_child('config.py') + self.env.find_file(config.real_path) + else: + self.env.message('No rope project folder found') + + @decorators.global_command('n m') + def create_module(self): + def callback(sourcefolder, name): + return generate.create_module(self.project, name, sourcefolder) + self._create('module', callback) + + @decorators.global_command('n p') + def create_package(self): + def callback(sourcefolder, name): + folder = generate.create_package(self.project, name, sourcefolder) + return folder.get_child('__init__.py') + self._create('package', callback) + + @decorators.global_command('n f') + def create_file(self): + def callback(parent, name): + return parent.create_file(name) + self._create('file', callback, 'parent') + + @decorators.global_command('n d') + def create_directory(self): + def callback(parent, name): + parent.create_folder(name) + self._create('directory', callback, 'parent') + + @decorators.local_command() + def analyze_module(self): + """Perform static object analysis on this module""" + self._check_project() + self.project.pycore.analyze_module(self.resource) + + @decorators.global_command() + def analyze_modules(self): + """Perform static object analysis on all project modules""" + self._check_project() + def _analyze_modules(handle): + libutils.analyze_modules(self.project, task_handle=handle) + refactor.runtask(self.env, _analyze_modules, 'Analyze project modules') + + @decorators.local_command() + def run_module(self): + """Run and perform dynamic object analysis on this module""" + self._check_project() + process = self.project.pycore.run_module(self.resource) + try: + process.wait_process() + finally: + process.kill_process() + + def _create(self, name, callback, parentname='source'): + self._check_project() + confs = {'name': dialog.Data(name.title() + ' name: ')} + parentname = parentname + 'folder' + optionals = {parentname: dialog.Data( + parentname.title() + ' Folder: ', + default=self.project.address, kind='directory')} + action, values = dialog.show_dialog( + self._askdata, ['perform', 'cancel'], confs, optionals) + if action == 'perform': + parent = libutils.path_to_resource( + self.project, values.get(parentname, self.project.address)) + resource = callback(parent, values['name']) + if resource: + self.env.find_file(resource.real_path) + + def _goto_location(self, resource, lineno): + if resource: + self.env.find_file(str(resource.real_path), + other=self.env.get('goto_def_newwin')) + if lineno: + self.env.goto_line(lineno) + + def _get_location(self): + offset = self.env.get_offset() + return self.resource, offset + + def _get_resource(self, filename=None): + if filename is None: + filename = self.env.filename() + if filename is None or self.project is None: + return + resource = libutils.path_to_resource(self.project, filename, 'file') + return resource + + @property + def resource(self): + """the current resource + + Returns `None` when file does not exist. + """ + resource = self._get_resource() + if resource and resource.exists(): + return resource + + def _check_project(self): + if self.project is None: + if self.env.get('guess_project'): + self.open_project(self._guess_project()) + else: + self.open_project() + else: + self.project.validate(self.project.root) + + def _guess_project(self): + cwd = self.env.filename() + if cwd is not None: + while True: + ropefolder = os.path.join(cwd, '.ropeproject') + if os.path.exists(ropefolder) and os.path.isdir(ropefolder): + return cwd + newcwd = os.path.dirname(cwd) + if newcwd == cwd: + break + cwd = newcwd + + def _reload_buffers(self, changes, undo=False): + self._reload_buffers_for_changes( + changes.get_changed_resources(), + self._get_moved_resources(changes, undo)) + + def _reload_buffers_for_changes(self, changed, moved={}): + filenames = [resource.real_path for resource in changed] + moved = dict([(resource.real_path, moved[resource].real_path) + for resource in moved]) + self.env.reload_files(filenames, moved) + + def _get_moved_resources(self, changes, undo=False): + result = {} + if isinstance(changes, rope.base.change.ChangeSet): + for change in changes.changes: + result.update(self._get_moved_resources(change)) + if isinstance(changes, rope.base.change.MoveResource): + result[changes.resource] = changes.new_resource + if undo: + return dict([(value, key) for key, value in result.items()]) + return result + + def _save_buffers(self, only_current=False): + if only_current: + filenames = [self.env.filename()] + else: + filenames = self.env.filenames() + pythons = [] + for filename in filenames: + if self._is_python_file(filename): + pythons.append(filename) + self.env.save_files(pythons) + + def _is_python_file(self, path): + resource = self._get_resource(path) + return (resource is not None and + resource.project == self.project and + self.project.pycore.is_python_file(resource)) + + def _askdata(self, data, starting=None): + ask_func = self.env.ask + ask_args = {'prompt': data.prompt, 'starting': starting, + 'default': data.default} + if data.values: + ask_func = self.env.ask_values + ask_args['values'] = data.values + elif data.kind == 'directory': + ask_func = self.env.ask_directory + return ask_func(**ask_args) + + +class Location(object): + def __init__(self, location): + self.location = location + self.filename = location.resource.real_path + self.offset = location.offset + self.note = '' + if location.unsure: + self.note = '?' + + @property + def lineno(self): + if hasattr(self.location, 'lineno'): + return self.location.lineno + return self.location.resource.read().count('\n', 0, self.offset) + 1 + + +class _CodeAssist(object): + + def __init__(self, interface, env): + self.interface = interface + self.env = env + + def code_assist(self, prefix): + proposals = self._calculate_proposals() + if prefix is not None: + arg = self.env.prefix_value(prefix) + if arg == 0: + arg = len(proposals) + common_start = self._calculate_prefix(proposals[:arg]) + self.env.insert(common_start[self.offset - self.starting_offset:]) + self._starting = common_start + self._offset = self.starting_offset + len(common_start) + prompt = 'Completion for %s: ' % self.expression + proposals = map(self.env._completion_data, proposals) + result = self.env.ask_completion(prompt, proposals, self.starting) + if result is not None: + self._apply_assist(result) + + def lucky_assist(self, prefix): + proposals = self._calculate_proposals() + selected = 0 + if prefix is not None: + selected = self.env.prefix_value(prefix) + if 0 <= selected < len(proposals): + result = self.env._completion_text(proposals[selected]) + else: + self.env.message('Not enough proposals!') + return + self._apply_assist(result) + + def auto_import(self): + if not self.interface._check_autoimport(): + return + name = self.env.current_word() + modules = self.autoimport.get_modules(name) + if modules: + if len(modules) == 1: + module = modules[0] + else: + module = self.env.ask_values( + 'Which module to import: ', modules) + self._insert_import(name, module) + else: + self.env.message('Global name %s not found!' % name) + + def completions(self): + proposals = self._calculate_proposals() + prefix = self.offset - self.starting_offset + return [self.env._completion_text(proposal)[prefix:] + for proposal in proposals] + + def extended_completions(self): + proposals = self._calculate_proposals() + prefix = self.offset - self.starting_offset + return [[proposal.name[prefix:], proposal.get_doc(), + proposal.type] for proposal in proposals] + + def _apply_assist(self, assist): + if ' : ' in assist: + name, module = assist.rsplit(' : ', 1) + self.env.delete(self.starting_offset + 1, self.offset + 1) + self.env.insert(name) + self._insert_import(name, module) + else: + self.env.delete(self.starting_offset + 1, self.offset + 1) + self.env.insert(assist) + + def _calculate_proposals(self): + self.interface._check_project() + resource = self.interface.resource + maxfixes = self.env.get('codeassist_maxfixes') + proposals = codeassist.code_assist( + self.interface.project, self.source, self.offset, + resource, maxfixes=maxfixes) + if self.env.get('sorted_completions', True): + proposals = codeassist.sorted_proposals(proposals) + if self.autoimport is not None: + if self.starting.strip() and '.' not in self.expression: + import_assists = self.autoimport.import_assist(self.starting) + for assist in import_assists: + p = codeassist.CompletionProposal(' : '.join(assist), + 'autoimport') + proposals.append(p) + return proposals + + def _insert_import(self, name, module): + lineno = self.autoimport.find_insertion_line(self.source) + line = 'from %s import %s' % (module, name) + self.env.insert_line(line, lineno) + + def _calculate_prefix(self, proposals): + if not proposals: + return '' + prefix = self.env._completion_text(proposals[0]) + for proposal in proposals: + common = 0 + name = self.env._completion_text(proposal) + for c1, c2 in zip(prefix, name): + if c1 != c2 or ' ' in (c1, c2): + break + common += 1 + prefix = prefix[:common] + return prefix + + @property + @utils.cacheit + def offset(self): + return self.env.get_offset() + + @property + @utils.cacheit + def source(self): + return self.interface._get_text() + + @property + @utils.cacheit + def starting_offset(self): + return codeassist.starting_offset(self.source, self.offset) + + @property + @utils.cacheit + def starting(self): + return self.source[self.starting_offset:self.offset] + + @property + @utils.cacheit + def expression(self): + return codeassist.starting_expression(self.source, self.offset) + + @property + def autoimport(self): + return self.interface.autoimport diff -r e30544496575 -r 48cacfdc2ca6 vim/sadness/ropevim/src/ropemode/ropemode/refactor.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vim/sadness/ropevim/src/ropemode/ropemode/refactor.py Wed Oct 06 12:30:46 2010 -0400 @@ -0,0 +1,491 @@ +import re + +import rope.base.change +import rope.contrib.generate +import rope.refactor.change_signature +import rope.refactor.extract +import rope.refactor.inline +import rope.refactor.introduce_factory +import rope.refactor.method_object +import rope.refactor.move +import rope.refactor.rename +import rope.refactor.restructure +import rope.refactor.usefunction +from rope.base import taskhandle + +from ropemode import dialog, filter + + +class Refactoring(object): + key = None + confs = {} + optionals = {} + saveall = True + + def __init__(self, interface, env): + self.interface = interface + self.env = env + + def show(self, initial_asking=True): + self.interface._check_project() + self.interface._save_buffers(only_current=not self.saveall) + self._create_refactoring() + action, result = dialog.show_dialog( + self.interface._askdata, ['perform', 'preview', 'cancel'], + self._get_confs(), self._get_optionals(), + initial_asking=initial_asking) + if action == 'cancel': + self.env.message('Cancelled!') + return + def calculate(handle): + return self._calculate_changes(result, handle) + name = 'Calculating %s changes' % self.name + changes = runtask(self.env, calculate, name=name) + if action == 'perform': + self._perform(changes) + if action == 'preview': + if changes is not None: + diffs = changes.get_description() + if self.env.preview_changes(diffs): + self._perform(changes) + else: + self.env.message('Thrown away!') + else: + self.env.message('No changes!') + + @property + def project(self): + return self.interface.project + + @property + def resource(self): + return self.interface._get_resource() + + @property + def offset(self): + return self.env.get_offset() + + @property + def region(self): + return self.env.get_region() + + @property + def name(self): + return refactoring_name(self.__class__) + + def _calculate_changes(self, option_values, task_handle): + pass + + def _create_refactoring(self): + pass + + def _done(self): + pass + + def _perform(self, changes): + if changes is None: + self.env.message('No changes!') + return + def perform(handle, self=self, changes=changes): + self.project.do(changes, task_handle=handle) + self.interface._reload_buffers(changes) + self._done() + runtask(self.env, perform, 'Making %s changes' % self.name, + interrupts=False) + self.env.message(str(changes.description) + ' finished') + + def _get_confs(self): + return self.confs + + def _get_optionals(self): + return self.optionals + + @property + def resources_option(self): + return dialog.Data('Files to apply this refactoring on: ', + decode=self._decode_resources) + + def _decode_resources(self, value): + return _resources(self.project, value) + + +class Rename(Refactoring): + key = 'r' + + saveall = True + + def _create_refactoring(self): + self.renamer = rope.refactor.rename.Rename( + self.project, self.resource, self.offset) + + def _calculate_changes(self, values, task_handle): + return self.renamer.get_changes(task_handle=task_handle, **values) + + def _get_optionals(self): + opts = {} + opts['docs'] = dialog.Boolean('Search comments and docs: ', True) + if self.renamer.is_method(): + opts['in_hierarchy'] = dialog.Boolean('Rename methods in ' + 'class hierarchy: ') + opts['resources'] = self.resources_option + opts['unsure'] = dialog.Data('Unsure occurrences: ', + decode=self._decode_unsure, + values=['ignore', 'match'], + default='ignore') + return opts + + def _get_confs(self): + oldname = str(self.renamer.get_old_name()) + return {'new_name': dialog.Data('New name: ', default=oldname)} + + def _decode_unsure(self, value): + unsure = value == 'match' + return lambda occurrence: unsure + + +class RenameCurrentModule(Rename): + key = '1 r' + offset = None + + +class Restructure(Refactoring): + key = 'x' + confs = {'pattern': dialog.Data('Restructuring pattern: '), + 'goal': dialog.Data('Restructuring goal: ')} + + def _calculate_changes(self, values, task_handle): + restructuring = rope.refactor.restructure.Restructure( + self.project, values['pattern'], values['goal'], + args=values['args'], imports=values['imports']) + return restructuring.get_changes(resources=values['resources'], + task_handle=task_handle) + + def _get_optionals(self): + return { + 'args': dialog.Data('Arguments: ', decode=self._decode_args), + 'imports': dialog.Data('Imports: ', decode=self._decode_imports), + 'resources': self.resources_option} + + def _decode_args(self, value): + if value: + args = {} + for raw_check in value.split('\n'): + if raw_check: + key, value = raw_check.split(':', 1) + args[key.strip()] = value.strip() + return args + + def _decode_imports(self, value): + if value: + return [line.strip() for line in value.split('\n')] + + +class UseFunction(Refactoring): + key = 'u' + + def _create_refactoring(self): + self.user = rope.refactor.usefunction.UseFunction( + self.project, self.resource, self.offset) + + def _calculate_changes(self, values, task_handle): + return self.user.get_changes(task_handle=task_handle, **values) + + def _get_optionals(self): + return {'resources': self.resources_option} + + +class Move(Refactoring): + key = 'v' + + def _create_refactoring(self): + self.mover = rope.refactor.move.create_move(self.project, + self.resource, + self.offset) + + def _calculate_changes(self, values, task_handle): + destination = values['destination'] + resources = values.get('resources', None) + if isinstance(self.mover, rope.refactor.move.MoveGlobal): + return self._move_global(destination, resources, task_handle) + if isinstance(self.mover, rope.refactor.move.MoveModule): + return self._move_module(destination, resources, task_handle) + if isinstance(self.mover, rope.refactor.move.MoveMethod): + return self._move_method(destination, resources, task_handle) + + def _move_global(self, dest, resources, handle): + destination = self.project.pycore.find_module(dest) + return self.mover.get_changes( + destination, resources=resources, task_handle=handle) + + def _move_method(self, dest, resources, handle): + return self.mover.get_changes( + dest, self.mover.get_method_name(), + resources=resources, task_handle=handle) + + def _move_module(self, dest, resources, handle): + destination = self.project.pycore.find_module(dest) + return self.mover.get_changes( + destination, resources=resources, task_handle=handle) + + def _get_confs(self): + if isinstance(self.mover, rope.refactor.move.MoveGlobal): + prompt = 'Destination module: ' + if isinstance(self.mover, rope.refactor.move.MoveModule): + prompt = 'Destination package: ' + if isinstance(self.mover, rope.refactor.move.MoveMethod): + prompt = 'Destination attribute: ' + return {'destination': dialog.Data(prompt)} + + def _get_optionals(self): + return {'resources': self.resources_option} + + +class MoveCurrentModule(Move): + key = '1 v' + offset = None + + +class ModuleToPackage(Refactoring): + key = '1 p' + saveall = False + + def _create_refactoring(self): + self.packager = rope.refactor.ModuleToPackage( + self.project, self.resource) + + def _calculate_changes(self, values, task_handle): + return self.packager.get_changes() + + +class Inline(Refactoring): + key = 'i' + + def _create_refactoring(self): + self.inliner = rope.refactor.inline.create_inline( + self.project, self.resource, self.offset) + + def _calculate_changes(self, values, task_handle): + return self.inliner.get_changes(task_handle=task_handle, **values) + + def _get_optionals(self): + opts = {'resources': self.resources_option} + if self.inliner.get_kind() == 'parameter': + opts['in_hierarchy'] = dialog.Boolean( + 'Apply on all matching methods in class hierarchy: ', False) + else: + opts['remove'] = dialog.Boolean('Remove the definition: ', True) + opts['only_current'] = dialog.Boolean('Inline this ' + 'occurrence only: ') + return opts + + +class _Extract(Refactoring): + saveall = False + optionals = {'similar': dialog.Boolean('Extract similar pieces: ', True), + 'global_': dialog.Boolean('Make global: ')} + kind = None + constructor = None + + def _create_refactoring(self): + start, end = self.region + self.extractor = self.constructor(self.project, + self.resource, start, end) + + def _calculate_changes(self, values, task_handle): + similar = values.get('similar') + global_ = values.get('global_') + return self.extractor.get_changes(values['name'], similar=similar, + global_=global_) + + def _get_confs(self): + return {'name': dialog.Data('Extracted %s name: ' % self.kind)} + + +class ExtractVariable(_Extract): + key = 'l' + kind = 'variable' + constructor = rope.refactor.extract.ExtractVariable + + +class ExtractMethod(_Extract): + key = 'm' + kind = 'method' + constructor = rope.refactor.extract.ExtractMethod + + +class OrganizeImports(Refactoring): + key = 'o' + saveall = False + + def _create_refactoring(self): + self.organizer = rope.refactor.ImportOrganizer(self.project) + + def _calculate_changes(self, values, task_handle): + return self.organizer.organize_imports(self.resource) + + +class MethodObject(Refactoring): + saveall = False + confs = {'classname': dialog.Data('New class name: ', + default='_ExtractedClass')} + + def _create_refactoring(self): + self.objecter = rope.refactor.method_object.MethodObject( + self.project, self.resource, self.offset) + + def _calculate_changes(self, values, task_handle): + classname = values.get('classname') + return self.objecter.get_changes(classname) + + +class IntroduceFactory(Refactoring): + saveall = True + key = 'f' + + def _create_refactoring(self): + self.factory = rope.refactor.introduce_factory.IntroduceFactory( + self.project, self.resource, self.offset) + + def _calculate_changes(self, values, task_handle): + return self.factory.get_changes(task_handle=task_handle, **values) + + def _get_confs(self): + default = 'create_%s' % self.factory.old_name.lower() + return {'factory_name': dialog.Data('Factory name: ', default)} + + def _get_optionals(self): + return {'global_factory': dialog.Boolean('Make global: ', True), + 'resources': self.resources_option} + + +class ChangeSignature(Refactoring): + saveall = True + key = 's' + + def _create_refactoring(self): + self.changer = rope.refactor.change_signature.ChangeSignature( + self.project, self.resource, self.offset) + + def _calculate_changes(self, values, task_handle): + signature = values.get('signature') + args = re.sub(r'[\s\(\)]+', '', signature).split(',') + olds = [arg[0] for arg in self._get_args()] + + changers = [] + for arg in list(olds): + if arg in args: + continue + changers.append(rope.refactor.change_signature. + ArgumentRemover(olds.index(arg))) + olds.remove(arg) + + order = [] + for index, arg in enumerate(args): + if arg not in olds: + changers.append(rope.refactor.change_signature. + ArgumentAdder(index, arg)) + olds.insert(index, arg) + order.append(olds.index(arg)) + changers.append(rope.refactor.change_signature. + ArgumentReorderer(order, autodef='None')) + + del values['signature'] + return self.changer.get_changes(changers, task_handle=task_handle, + **values) + + def _get_args(self): + if hasattr(self.changer, 'get_args'): + return self.changer.get_args() + return self.changer.get_definition_info().args_with_defaults + + def _get_confs(self): + args = [] + for arg, default in self._get_args(): + args.append(arg) + signature = '(' + ', '.join(args) + ')' + return {'signature': dialog.Data('Change the signature: ', + default=signature)} + + def _get_optionals(self): + opts = {'resources': self.resources_option} + if self.changer.is_method(): + opts['in_hierarchy'] = dialog.Boolean('Rename methods in ' + 'class hierarchy: ') + return opts + + +class _GenerateElement(Refactoring): + + def _create_refactoring(self): + kind = self.name.split('_')[-1] + self.generator = rope.contrib.generate.create_generate( + kind, self.project, self.resource, self.offset) + + def _calculate_changes(self, values, task_handle): + return self.generator.get_changes() + + def _done(self): + resource, lineno = self.generator.get_location() + self.interface._goto_location(resource, lineno) + + +class GenerateVariable(_GenerateElement): + key = 'n v' + + +class GenerateFunction(_GenerateElement): + key = 'n f' + + +class GenerateClass(_GenerateElement): + key = 'n c' + + +class GenerateModule(_GenerateElement): + key = 'n m' + + +class GeneratePackage(_GenerateElement): + key = 'n p' + + +def refactoring_name(refactoring): + classname = refactoring.__name__ + result = [] + for c in classname: + if result and c.isupper(): + result.append('_') + result.append(c.lower()) + name = ''.join(result) + return name + +def _resources(project, text): + if text is None or text.strip() == '': + return None + return filter.resources(project, text) + + +def runtask(env, command, name, interrupts=True): + return RunTask(env, command, name, interrupts)() + +class RunTask(object): + + def __init__(self, env, task, name, interrupts=True): + self.env = env + self.task = task + self.name = name + self.interrupts = interrupts + + def __call__(self): + handle = taskhandle.TaskHandle(name=self.name) + progress = self.env.create_progress(self.name) + def update_progress(): + jobset = handle.current_jobset() + if jobset: + percent = jobset.get_percent_done() + if percent is not None: + progress.update(percent) + handle.add_observer(update_progress) + result = self.task(handle) + progress.done() + return result diff -r e30544496575 -r 48cacfdc2ca6 vim/sadness/ropevim/src/ropemode/ropemodetest.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vim/sadness/ropevim/src/ropemode/ropemodetest.py Wed Oct 06 12:30:46 2010 -0400 @@ -0,0 +1,122 @@ +import unittest + +from ropemode import dialog + + +class ConfigTest(unittest.TestCase): + + def setUp(self): + super(ConfigTest, self).setUp() + + def tearDown(self): + super(ConfigTest, self).tearDown() + + def test_trivial_case(self): + action, confs = dialog.show_dialog(_MockAskConfig(['done']), ['done']) + self.assertEquals('done', action) + self.assertEquals({}, confs) + + def test_asking_normal_configs(self): + confs = {'name': dialog.Data()} + minibuffer = _MockAskConfig(['value', 'done']) + action, result = dialog.show_dialog(minibuffer, + ['done', 'cancel'], confs) + self.assertEquals({'name': 'value'}, result) + self.assertEquals('done', action) + + def test_optional_confs(self): + optionals = {'name': dialog.Data()} + minibuffer = _MockAskConfig(['done']) + action, result = dialog.show_dialog(minibuffer, ['done', 'cancel'], + optionals=optionals) + self.assertEquals(None, result.get('name', None)) + self.assertEquals('done', action) + + def test_optional_confs2(self): + optionals = {'name': dialog.Data()} + minibuffer = _MockAskConfig(['name', 'value', 'done']) + action, result = dialog.show_dialog(minibuffer, ['done', 'cancel'], + optionals=optionals) + self.assertEquals({'name': 'value'}, result) + self.assertEquals('done', action) + + def test_trivial_batchset(self): + optionals = {'name': dialog.Data()} + minibuffer = _MockAskConfig(['batchset', 'name value', 'done']) + action, result = dialog.show_dialog(minibuffer, ['done', 'cancel'], + optionals=optionals) + self.assertEquals({'name': 'value'}, result) + self.assertEquals('done', action) + + def test_batchset_multiple_sets(self): + optionals = {'name1': dialog.Data(), 'name2': dialog.Data()} + minibuffer = _MockAskConfig(['batchset', + 'name1 value1\nname2 value2', 'done']) + action, result = dialog.show_dialog(minibuffer, ['done', 'cancel'], + optionals=optionals) + self.assertEquals({'name1': 'value1', 'name2': 'value2'}, result) + self.assertEquals('done', action) + + def test_multiline_sets(self): + optionals = {'name': dialog.Data()} + minibuffer = _MockAskConfig( + ['batchset', 'name\n line1\n line2\n', 'done']) + action, result = dialog.show_dialog(minibuffer, ['done', 'cancel'], + optionals=optionals) + self.assertEquals({'name': 'line1\n line2\n'}, result) + self.assertEquals('done', action) + + def test_complex_batchset(self): + optionals = {'name1': dialog.Data(), 'name2': dialog.Data(), + 'name3': dialog.Data()} + minibuffer = _MockAskConfig( + ['batchset', 'name3\n value3\nname1\n line1\n ' + 'line2\n\nname2 value2\n', 'done']) + action, result = dialog.show_dialog(minibuffer, ['done', 'cancel'], + optionals=optionals) + self.assertEquals( + {'name1': 'line1\n line2\n', 'name2': 'value2', + 'name3': 'value3\n'}, result) + self.assertEquals('done', action) + + def test_skipping_blanks(self): + optionals = {'name1': dialog.Data(), 'name2': dialog.Data()} + minibuffer = _MockAskConfig( + ['batchset', '\nname1\n value1\n\nname2 value2\n\n', 'done']) + action, result = dialog.show_dialog(minibuffer, ['done', 'cancel'], + optionals=optionals) + self.assertEquals({'name1': 'value1\n', 'name2': 'value2'}, result) + self.assertEquals('done', action) + + def test_skip_initial_asking(self): + confs = {'name': dialog.Data()} + minibuffer = _MockAskConfig( + ['name', 'value', 'done']) + action, result = dialog.show_dialog(minibuffer, ['done', 'cancel'], + confs=confs, initial_asking=False) + self.assertEquals({'name': 'value'}, result) + self.assertEquals('done', action) + + def test_ignoring_trailing_colon_in_config_names(self): + optionals = {'name1': dialog.Data()} + minibuffer = _MockAskConfig( + ['batchset', 'name1: value1\n', 'done']) + action, result = dialog.show_dialog(minibuffer, ['done', 'cancel'], + optionals=optionals) + self.assertEquals({'name1': 'value1'}, result) + self.assertEquals('done', action) + + +class _MockAskConfig(object): + + def __init__(self, responses=[]): + self.responses = responses + self.asked = [] + + def __call__(self, config, starting=None): + self.asked.append(config) + return self.responses[len(self.asked) - 1] + + +if __name__ == '__main__': + unittest.main() diff -r e30544496575 -r 48cacfdc2ca6 vim/sadness/ropevim/src/ropemode/setup.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vim/sadness/ropevim/src/ropemode/setup.py Wed Oct 06 12:30:46 2010 -0400 @@ -0,0 +1,35 @@ +extra_kwargs = {} +try: + from setuptools import setup + extra_kwargs['install_requires'] = ['rope >= 0.9.2'] +except ImportError: + from distutils.core import setup + +import ropemode + + +classifiers=[ + 'Development Status :: 4 - Beta', + 'Operating System :: OS Independent', + 'Environment :: X11 Applications', + 'Environment :: Win32 (MS Windows)', + 'Environment :: MacOS X', + 'Intended Audience :: Developers', + 'License :: OSI Approved :: GNU General Public License (GPL)', + 'Natural Language :: English', + 'Programming Language :: Python', + 'Topic :: Software Development'] + +setup(name='ropemode', + version=ropemode.VERSION, + description=ropemode.INFO, + author='Ali Gholami Rudi', + author_email='aligrudi@users.sourceforge.net', + url='http://rope.sf.net/', + packages=['ropemode'], + license='GNU GPL', + classifiers=classifiers, + requires=['rope (>= 0.9.2)'], + **extra_kwargs +) + diff -r e30544496575 -r 48cacfdc2ca6 vim/sadness/ropevim/src/ropevim/.hgtags --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vim/sadness/ropevim/src/ropevim/.hgtags Wed Oct 06 12:30:46 2010 -0400 @@ -0,0 +1,4 @@ +dd2506d135c323e95f1033c488817ade2d1fbbc1 0.1 +43dcf217265c3beba85c7fe0b139df9d8b167ced 0.2c1 +f548c711e86af8cc62c0fc9df186516c416a4f22 0.2 +511c3b16f57c785b0e9fdc8d095e6325684e7415 0.3-rc diff -r e30544496575 -r 48cacfdc2ca6 vim/sadness/ropevim/src/ropevim/CONTRIBUTORS --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vim/sadness/ropevim/src/ropevim/CONTRIBUTORS Wed Oct 06 12:30:46 2010 -0400 @@ -0,0 +1,9 @@ +====================== + Ropevim Contributors +====================== + +* Alon Levy +* Matthieu Tanguay-Carel +* Jesse Zhang +* Ben Davis +* Anton Gritsay diff -r e30544496575 -r 48cacfdc2ca6 vim/sadness/ropevim/src/ropevim/COPYING --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vim/sadness/ropevim/src/ropevim/COPYING Wed Oct 06 12:30:46 2010 -0400 @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + 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 of the License, 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., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. diff -r e30544496575 -r 48cacfdc2ca6 vim/sadness/ropevim/src/ropevim/MANIFEST.in --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vim/sadness/ropevim/src/ropevim/MANIFEST.in Wed Oct 06 12:30:46 2010 -0400 @@ -0,0 +1,4 @@ +include README.txt COPYING setup.py MANIFEST.in +include ropevim.py ropevim.vim +recursive-include ropemode *.py +recursive-include docs *.txt diff -r e30544496575 -r 48cacfdc2ca6 vim/sadness/ropevim/src/ropevim/README.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vim/sadness/ropevim/src/ropevim/README.txt Wed Oct 06 12:30:46 2010 -0400 @@ -0,0 +1,337 @@ +====================== + ropevim, rope in vim +====================== + +Ropevim is a vim mode that uses rope_ library to provide features like +python refactorings and code-assists. You should install rope_ +library before using ropevim. + +.. _rope: http://rope.sf.net/ + + +New Features +============ + +* improved support of multibyte sources +* implemented `extended complete` feature (disabled by default) +* ropemode is not the part of distribution now + + +Setting Up +========== + +First add ropevim folder to the ``PYTHONPATH`` (or install it using +``python setup.py install``). + +Then load ``ropevim.vim`` in vim. That can be done either by adding +``source path/to/ropevim.vim`` to your ``~/.vimrc`` or copying it to +``~/.vim/plugin/`` folder. + +If you don't want to install rope and ropevim you can add something +like this to your ``~/.vimrc``:: + + let $PYTHONPATH .= ":/path/to/rope:/path/to/ropevim" + source /path/to/ropevim.vim + +For using the repository version of rope, see ``docs/ropevim.txt``. + + +Getting Started +=============== + +Refactoring Dialog +------------------ + +Ropevim refactorings use a special kind of dialog. Depending on the +refactoring, you'll be asked about the essential information a +refactoring needs to know (like the new name in rename refactoring). + +Next you'll see the base prompt of a refactoring dialog that shows +something like "Choose what to do". By entering the name of a +refactoring option you can set its value. After setting each option +you'll be returned back to the base prompt. Finally, you can ask rope +to perform, preview or cancel the refactoring. + +See keybinding_ section and try the refactorings yourself. + + +Finding Files +------------- + +By using ``RopeFindFile`` (``C-x p f`` by default), you can search for +files in your project. When you complete the minibuffer you'll see +all files in the project; files are shown as their reversed paths. +For instance ``projectroot/docs/todo.txt`` is shown like +``todo.txt" if it is not. + +Note that you'll need rope r1558:0d76aa9d0614 or later and ropemode +r35:bd77ca42b04d or later for extended complete feature to work. + + +Enabling Autoimport +------------------- + +Rope can propose and automatically import global names in other +modules. Rope maintains a cache of global names for each project. It +updates the cache only when modules are changed; if you want to cache +all your modules at once, use ``RopeGenerateAutoimportCache``. It +will cache all of the modules inside the project plus those whose +names are listed in ``ropevim_autoimport_modules`` list:: + + # add the name of modules you want to autoimport + let g:ropevim_autoimport_modules = ["os", "shutil"] + +Now if you are in a buffer that contains:: + + rmtree + +and you execute ``RopevimAutoImport`` you'll end up with:: + + from shutil import rmtree + rmtree + +Also ``RopeCodeAssist`` and ``RopeLuckyAssist`` propose auto-imported +names by using ``name : module`` style. Selecting them will import +the module automatically. + + +Filtering Resources +------------------- + +Some refactorings, restructuring and find occurrences take an option +called resources. This option can be used to limit the resources on +which a refactoring should be applied. + +It uses a simple format: each line starts with either '+' or '-'. +Each '+' means include the file (or its children if it's a folder) +that comes after it. '-' has the same meaning for exclusion. So +using:: + + +rope + +ropetest + -rope/contrib + +means include all python files inside ``rope`` and ``ropetest`` +folders and their subfolder, but those that are in ``rope/contrib``. +Or:: + + -ropetest + -setup.py + +means include all python files inside the project but ``setup.py`` and +those under ``ropetest`` folder. + + +Finding Occurrences +------------------- + +The find occurrences command (``C-c f`` by default) can be used to +find the occurrences of a python name. If ``unsure`` option is +``yes``, it will also show unsure occurrences; unsure occurrences are +indicated with a ``?`` mark in the end. Note that ropevim uses the +quickfix feature of vim for marking occurrence locations. + + +Dialog ``batchset`` Command +--------------------------- + +When you use ropevim dialogs there is a command called ``batchset``. +It can set many options at the same time. After selecting this +command from dialog base prompt, you are asked to enter a string. + +``batchset`` strings can set the value of configs in two ways. The +single line form is like this:: + + name1 value1 + name2 value2 + +That is the name of config is followed its value. For multi-line +values you can use:: + + name1 + line1 + line2 + + name2 + line3 + +Each line of the definition should start with a space or a tab. Note +that blank lines before the name of config definitions are ignored. + +``batchset`` command is useful when performing refactorings with long +configs, like restructurings:: + + pattern ${pycore}.create_module(${project}.root, ${name}) + + goal generate.create_module(${project}, ${name}) + + imports + from rope.contrib import generate + + args + pycore: type=rope.base.pycore.PyCore + project: type=rope.base.project.Project + +.. ignore the two-space indents + +This is a valid ``batchset`` string for restructurings. + +Just for the sake of completeness, the reverse of the above +restructuring can be:: + + pattern ${create_module}(${project}, ${name}) + + goal ${project}.pycore.create_module(${project}.root, ${name}) + + args + create_module: name=rope.contrib.generate.create_module + project: type=rope.base.project.Project + + +Variables +========= + +* ``ropevim_codeassist_maxfixes``: The maximum number of syntax errors + to fix for code assists. The default value is ``1``. +* ``ropevim_local_prefix``: The prefix for ropevim refactorings. + Defaults to ``C-c r``. +* ``ropevim_global_prefix``: The prefix for ropevim project commands + Defaults to ``C-x p``. +* ``ropevim_enable_shortcuts``: Shows whether to bind ropevim + shortcuts keys. Defaults to ``1``. +* ``ropevim_guess_project``: If non-zero, ropevim tries to guess and + open the project that contains the file on which a ropevim command + is performed when no project is already open. + +* ``ropevim_enable_autoimport``: Shows whether to enable autoimport. +* ``ropevim_autoimport_modules``: The name of modules whose global + names should be cached. `RopeGenerateAutoimportCache' reads this + list and fills its cache. +* ``ropevim_autoimport_underlineds``: If set, autoimport will cache + names starting with underlines, too. + +* ``ropevim_goto_def_newwin``: If set, ropevim will open a new buffer + for "go to definition" result if the definition found is located + in another file. By default the file is open in the same buffer. + + +Keybinding +========== + +Uses almost the same keybinding as ropemacs. Note that global +commands have a ``C-x p`` prefix and local commands have a ``C-c r`` +prefix. You can change that (see variables_ section). + +================ ============================ +Key Command +================ ============================ +C-x p o RopeOpenProject +C-x p k RopeCloseProject +C-x p f RopeFindFile +C-x p 4 f RopeFindFileOtherWindow +C-x p u RopeUndo +C-x p r RopeRedo +C-x p c RopeProjectConfig +C-x p n [mpfd] RopeCreate(Module|Package|File|Directory) + RopeWriteProject + +C-c r r RopeRename +C-c r l RopeExtractVariable +C-c r m RopeExtractMethod +C-c r i RopeInline +C-c r v RopeMove +C-c r x RopeRestructure +C-c r u RopeUseFunction +C-c r f RopeIntroduceFactory +C-c r s RopeChangeSignature +C-c r 1 r RopeRenameCurrentModule +C-c r 1 v RopeMoveCurrentModule +C-c r 1 p RopeModuleToPackage + +C-c r o RopeOrganizeImports +C-c r n [vfcmp] RopeGenerate(Variable|Function|Class|Module|Package) + +C-c r a / RopeCodeAssist +C-c r a g RopeGotoDefinition +C-c r a d RopeShowDoc +C-c r a f RopeFindOccurrences +C-c r a ? RopeLuckyAssist +C-c r a j RopeJumpToGlobal +C-c r a c RopeShowCalltip + RopeAnalyzeModule + + RopeAutoImport + RopeGenerateAutoimportCache +=============== ============================ + + +Shortcuts +--------- + +Some commands are used very frequently; specially the commands in +code-assist group. You can define your own shortcuts like this:: + + :map g :call RopeGotoDefinition() + +Ropevim itself comes with a few shortcuts. These shortcuts will be +used only when ``ropevim_enable_shortcuts`` is set. + +================ ============================ +Key Command +================ ============================ +M-/ RopeCodeAssist +M-? RopeLuckyAssist +C-c g RopeGotoDefinition +C-c d RopeShowDoc +C-c f RopeFindOccurrences +================ ============================ + + +Contributing +============ + +Send your bug reports, feature requests and patches to `rope-dev (at) +googlegroups.com`_. + +.. _`rope-dev (at) googlegroups.com`: http://groups.google.com/group/rope-dev + + +License +======= + +This program is under the terms of GPL (GNU General Public License). +Have a look at ``COPYING`` file for more information. diff -r e30544496575 -r 48cacfdc2ca6 vim/sadness/ropevim/src/ropevim/docs/done.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vim/sadness/ropevim/src/ropevim/docs/done.txt Wed Oct 06 12:30:46 2010 -0400 @@ -0,0 +1,28 @@ +====== + Done +====== + +> Public Release 0.3 : Febrary 5, 2010 + +* ropemode is not the part of distribution : Febrary 5, 2010 +* implemented `extended complete` feature : January 26, 2010 +* improved support of multibyte sources : June 24, 2009 + +> Public Release 0.2 : October 3, 2008 + +* fixed quickfix error format : August 18, 2008 +* ropevim_guess_project variable : June 18, 2008 + +> Public Release 0.2c1 : June 12, 2008 + +* not showing python traceback for bad inputs : May 23, 2008 +* interrupting refactorings : May 22, 2008 + +> Public Release 0.1 : May 22, 2008 + +* ropvim menu : May 21, 2008 +* code-assist in insert mode : May 21, 2008 +* using vim quickfix for showing occurrences : May 20, 2008 +* better dialogs : May 19, 2008 +* implementing basic ropemode commands : May 15, 2008 +* project started! : May 12, 2008 diff -r e30544496575 -r 48cacfdc2ca6 vim/sadness/ropevim/src/ropevim/docs/ropevim.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vim/sadness/ropevim/src/ropevim/docs/ropevim.txt Wed Oct 06 12:30:46 2010 -0400 @@ -0,0 +1,77 @@ +====================== + ropevim, rope in vim +====================== + +Ropevim is a plugin for performing python refactorings in vim. It +uses rope_ library. + +You should install `rope`_ library before using ropevim. You can +download ropevim from `project download page`_. + +.. _rope: http://rope.sf.net/ + + +Features +======== + +* Supports many of the refactorings that are supported by rope_ + library: + + * Rename + * Extract method/local variable + * Move class/function/module/package/method + * Inline method/local variable/parameter + * Restructuring + * Change signature + * ... + +* Other refactoring-related features + + * Previewing refactorings + * Undo/redo refactorings + * Showing refactoring progress + +* Code-assists + + * Code-completion + * Goto definition + * Show pydoc + * Find occurrences + * Organize imports (remove unused and duplicate imports and sort them) + * Generating python elements + + +Source Repository +================= + +The repository version needs ropemode (which was once part of +ropemacs); in order to use the repository version of ropevim you need +to put ropemode in your ``PYTHONPATH``. Note that ropemode is +included in released packages. + +Ropevim: + +* repo url: http://bitbucket.org/agr/ropevim +* snapshot: http://bitbucket.org/agr/ropevim/get/tip.gz + +Ropemode: + +* repo url: http://bitbucket.org/agr/ropemode +* snapshot: http://bitbucket.org/agr/ropemode/get/tip.gz + + +Feedback +======== + +Send your bug reports, feature requests and patches to `rope-dev (at) +googlegroups.com`_. + + +License +======= + +Ropevim is under the terms of GNU GPL (GNU General Public License). + +.. _project download page: http://sf.net/projects/rope/files +.. _`rope-dev (at) googlegroups.com`: http://groups.google.com/group/rope-dev +.. _Mercurial: http://selenic.com/mercurial diff -r e30544496575 -r 48cacfdc2ca6 vim/sadness/ropevim/src/ropevim/docs/todo.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vim/sadness/ropevim/src/ropevim/docs/todo.txt Wed Oct 06 12:30:46 2010 -0400 @@ -0,0 +1,8 @@ +============== + Ropevim TODO +============== + +* preventing changed file warnings +* interrupting refactorings +* better progress bar +* prefixing functions diff -r e30544496575 -r 48cacfdc2ca6 vim/sadness/ropevim/src/ropevim/ropevim.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vim/sadness/ropevim/src/ropevim/ropevim.py Wed Oct 06 12:30:46 2010 -0400 @@ -0,0 +1,459 @@ +"""ropevim, a vim mode for using rope refactoring library""" +import os +import tempfile +import re + +import ropemode.decorators +import ropemode.environment +import ropemode.interface + +import vim + + +class VimUtils(ropemode.environment.Environment): + + def ask(self, prompt, default=None, starting=None): + if starting is None: + starting = '' + if default is not None: + prompt = prompt + ('[%s] ' % default) + result = call('input("%s", "%s")' % (prompt, starting)) + if default is not None and result == '': + return default + return result + + def ask_values(self, prompt, values, default=None, + starting=None, show_values=None): + if show_values or (show_values is None and len(values) < 14): + self._print_values(values) + if default is not None: + prompt = prompt + ('[%s] ' % default) + starting = starting or '' + _completer.values = values + answer = call('input("%s", "%s", "customlist,RopeValueCompleter")' % + (prompt, starting)) + if answer is None: + if 'cancel' in values: + return 'cancel' + return + if default is not None and not answer: + return default + if answer.isdigit() and 0 <= int(answer) < len(values): + return values[int(answer)] + return answer + + def _print_values(self, values): + numbered = [] + for index, value in enumerate(values): + numbered.append('%s. %s' % (index, str(value))) + echo('\n'.join(numbered) + '\n') + + def ask_directory(self, prompt, default=None, starting=None): + return call('input("%s", ".", "dir")' % prompt) + + def ask_completion(self, prompt, values, starting=None): + if self.get('vim_completion') and 'i' in call('mode()'): + if not self.get('extended_complete', False): + proposals = u','.join(u"'%s'" % self._completion_text(proposal) + for proposal in values) + else: + proposals = u','.join(self._extended_completion(proposal) + for proposal in values) + + col = int(call('col(".")')) + if starting: + col -= len(starting) + command = u'call complete(%s, [%s])' % (col, proposals) + vim.command(command.encode(self._get_encoding())) + return None + return self.ask_values(prompt, values, starting=starting, + show_values=False) + + def message(self, message): + echo(message) + + def yes_or_no(self, prompt): + return self.ask_values(prompt, ['yes', 'no']) == 'yes' + + def y_or_n(self, prompt): + return self.yes_or_no(prompt) + + def get(self, name, default=None): + vimname = 'g:ropevim_%s' % name + if str(vim.eval('exists("%s")' % vimname)) == '0': + return default + result = vim.eval(vimname) + if isinstance(result, str) and result.isdigit(): + return int(result) + return result + + def get_offset(self): + result = self._position_to_offset(*self.cursor) + return result + + def _get_encoding(self): + return vim.eval('&encoding') + def _encode_line(self, line): + return line.encode(self._get_encoding()) + def _decode_line(self, line): + return line.decode(self._get_encoding()) + + def _position_to_offset(self, lineno, colno): + result = min(colno, len(self.buffer[lineno -1]) + 1) + for line in self.buffer[:lineno-1]: + line = self._decode_line(line) + result += len(line) + 1 + return result + + def get_text(self): + return self._decode_line('\n'.join(self.buffer)) + u'\n' + + def get_region(self): + start = self._position_to_offset(*self.buffer.mark('<')) + end = self._position_to_offset(*self.buffer.mark('>')) + return start, end + + @property + def buffer(self): + return vim.current.buffer + + def _get_cursor(self): + lineno, col = vim.current.window.cursor + line = self._decode_line(vim.current.line[:col]) + col = len(line) + return (lineno, col) + + def _set_cursor(self, cursor): + lineno, col = cursor + line = self._decode_line(vim.current.line) + line = self._encode_line(line[:col]) + col = len(line) + vim.current.window.cursor = (lineno, col) + + cursor = property(_get_cursor, _set_cursor) + + def filename(self): + return self.buffer.name + + def is_modified(self): + return vim.eval('&modified') + + def goto_line(self, lineno): + self.cursor = (lineno, 0) + + def insert_line(self, line, lineno): + self.buffer[lineno - 1:lineno - 1] = [line] + + def insert(self, text): + lineno, colno = self.cursor + line = self.buffer[lineno - 1] + self.buffer[lineno - 1] = line[:colno] + text + line[colno:] + self.cursor = (lineno, colno + len(text)) + + def delete(self, start, end): + lineno1, colno1 = self._offset_to_position(start - 1) + lineno2, colno2 = self._offset_to_position(end - 1) + lineno, colno = self.cursor + if lineno1 == lineno2: + line = self.buffer[lineno1 - 1] + self.buffer[lineno1 - 1] = line[:colno1] + line[colno2:] + if lineno == lineno1 and colno >= colno1: + diff = colno2 - colno1 + self.cursor = (lineno, max(0, colno - diff)) + + def _offset_to_position(self, offset): + text = self.get_text() + lineno = text.count('\n', 0, offset) + 1 + try: + colno = offset - text.rindex('\n', 0, offset) - 1 + except ValueError: + colno = offset + return lineno, colno + + def filenames(self): + result = [] + for buffer in vim.buffers: + if buffer.name: + result.append(buffer.name) + return result + + def save_files(self, filenames): + vim.command('wall') + + def reload_files(self, filenames, moves={}): + initial = self.filename() + for filename in filenames: + self.find_file(moves.get(filename, filename), force=True) + if initial: + self.find_file(initial) + + def find_file(self, filename, readonly=False, other=False, force=False): + if filename != self.filename() or force: + if other: + vim.command('new') + vim.command('e %s' % filename) + if readonly: + vim.command('set nomodifiable') + + def create_progress(self, name): + return VimProgress(name) + + def current_word(self): + return vim.eval('expand("")') + + def push_mark(self): + vim.command('mark `') + + def prefix_value(self, prefix): + return prefix + + def show_occurrences(self, locations): + self._quickfixdefs(locations) + + def _quickfixdefs(self, locations): + filename = os.path.join(tempfile.gettempdir(), tempfile.mktemp()) + try: + self._writedefs(locations, filename) + vim.command('let old_errorfile = &errorfile') + vim.command('let old_errorformat = &errorformat') + vim.command('set errorformat=%f:%l:\ %m') + vim.command('cfile ' + filename) + vim.command('let &errorformat = old_errorformat') + vim.command('let &errorfile = old_errorfile') + finally: + os.remove(filename) + + def _writedefs(self, locations, filename): + tofile = open(filename, 'w') + try: + for location in locations: + err = '%s:%d: - %s\n' % (location.filename, + location.lineno, location.note) + echo(err) + tofile.write(err) + finally: + tofile.close() + + def show_doc(self, docs, altview=False): + if docs: + echo(docs) + + def preview_changes(self, diffs): + echo(diffs) + return self.y_or_n('Do the changes? ') + + def local_command(self, name, callback, key=None, prefix=False): + self._add_command(name, callback, key, prefix, + prekey=self.get('local_prefix')) + + def global_command(self, name, callback, key=None, prefix=False): + self._add_command(name, callback, key, prefix, + prekey=self.get('global_prefix')) + + def add_hook(self, name, callback, hook): + mapping = {'before_save': 'FileWritePre,BufWritePre', + 'after_save': 'FileWritePost,BufWritePost', + 'exit': 'VimLeave'} + self._add_function(name, callback) + vim.command('autocmd %s *.py call %s()' % + (mapping[hook], _vim_name(name))) + + def _add_command(self, name, callback, key, prefix, prekey): + self._add_function(name, callback, prefix) + vim.command('command! -range %s call %s()' % + (_vim_name(name), _vim_name(name))) + if key is not None: + key = prekey + key.replace(' ', '') + vim.command('map %s :call %s()' % (key, _vim_name(name))) + + def _add_function(self, name, callback, prefix=False): + globals()[name] = callback + arg = 'None' if prefix else '' + vim.command('function! %s()\n' % _vim_name(name) + + 'python ropevim.%s(%s)\n' % (name, arg) + + 'endfunction\n') + + def _completion_data(self, proposal): + return proposal + + _docstring_re = re.compile('^[\s\t\n]*([^\n]*)') + def _extended_completion(self, proposal): + # we are using extended complete and return dicts instead of strings. + # `ci` means "completion item". see `:help complete-items` + ci = {'word': proposal.name} + + scope = proposal.scope[0].upper() + type_ = proposal.type + info = None + + if proposal.scope == 'parameter_keyword': + scope = ' ' + type_ = 'param' + if not hasattr(proposal, 'get_default'): + # old version of rope + pass + else: + default = proposal.get_default() + if default is None: + info = '*' + else: + info = '= %s' % default + + elif proposal.scope == 'keyword': + scope = ' ' + type_ = 'keywd' + + elif proposal.scope == 'attribute': + scope = 'M' + if proposal.type == 'function': + type_ = 'meth' + elif proposal.type == 'instance': + type_ = 'prop' + + elif proposal.type == 'function': + type_ = 'func' + + elif proposal.type == 'instance': + type_ = 'inst' + + elif proposal.type == 'module': + type_ = 'mod' + + if info is None: + obj_doc = proposal.get_doc() + if obj_doc: + info = self._docstring_re.match(obj_doc).group(1) + else: + info = '' + + if type_ is None: + type_ = ' ' + else: + type_ = type_.ljust(5)[:5] + ci['menu'] = ' '.join((scope, type_, info)) + ret = u'{%s}' % \ + u','.join(u'"%s":"%s"' % \ + (key, value.replace('"', '\\"')) \ + for (key, value) in ci.iteritems()) + return ret + + +def _vim_name(name): + tokens = name.split('_') + newtokens = ['Rope'] + [token.title() for token in tokens] + return ''.join(newtokens) + + +class VimProgress(object): + + def __init__(self, name): + self.name = name + self.last = 0 + echo('%s ... ' % self.name) + + def update(self, percent): + try: + vim.eval('getchar(0)') + except vim.error: + raise KeyboardInterrupt('Task %s was interrupted!' % self.name) + if percent > self.last + 4: + echo('%s ... %s%%%%' % (self.name, percent)) + self.last = percent + + def done(self): + echo('%s ... done' % self.name) + + +def echo(message): + if isinstance(message, unicode): + message = message.encode(vim.eval('&encoding')) + print message + +def call(command): + return vim.eval(command) + + +class _ValueCompleter(object): + + def __init__(self): + self.values = [] + vim.command('python import vim') + vim.command('function! RopeValueCompleter(A, L, P)\n' + 'python args = [vim.eval("a:" + p) for p in "ALP"]\n' + 'python ropevim._completer(*args)\n' + 'return s:completions\n' + 'endfunction\n') + + def __call__(self, arg_lead, cmd_line, cursor_pos): + result = [proposal.name for proposal in self.values \ + if proposal.name.startswith(arg_lead)] + vim.command('let s:completions = %s' % result) + + +variables = {'ropevim_enable_autoimport': 1, + 'ropevim_autoimport_underlineds': 0, + 'ropevim_codeassist_maxfixes' : 1, + 'ropevim_enable_shortcuts' : 1, + 'ropevim_autoimport_modules': '[]', + 'ropevim_confirm_saving': 0, + 'ropevim_local_prefix': '"r"', + 'ropevim_global_prefix': '"p"', + 'ropevim_vim_completion': 0, + 'ropevim_guess_project': 0} + +shortcuts = {'code_assist': '', + 'lucky_assist': '', + 'goto_definition': 'g', + 'show_doc': 'd', + 'find_occurrences': 'f'} + +insert_shortcuts = {'code_assist': '', + 'lucky_assist': ''} + +def _init_variables(): + for variable, default in variables.items(): + vim.command('if !exists("g:%s")\n' % variable + + ' let g:%s = %s\n' % (variable, default)) + +def _enable_shortcuts(env): + if env.get('enable_shortcuts'): + for command, shortcut in shortcuts.items(): + vim.command('map %s :call %s()' % + (shortcut, _vim_name(command))) + for command, shortcut in insert_shortcuts.items(): + command_name = _vim_name(command) + 'InsertMode' + vim.command('func! %s()\n' % command_name + + 'call %s()\n' % _vim_name(command) + + 'return ""\n' + 'endfunc') + vim.command('imap %s =%s()' % (shortcut, command_name)) + +def _add_menu(env): + project = ['open_project', 'close_project', 'find_file', 'undo', 'redo'] + refactor = ['rename', 'extract_variable', 'extract_method', 'inline', + 'move', 'restructure', 'use_function', 'introduce_factory', + 'change_signature', 'rename_current_module', + 'move_current_module', 'module_to_package'] + assists = ['code_assist', 'goto_definition', 'show_doc', 'find_occurrences', + 'lucky_assist', 'jump_to_global', 'show_calltip'] + vim.command('silent! aunmenu Ropevim') + for index, items in enumerate([project, assists, refactor]): + if index != 0: + vim.command('amenu &Ropevim.-SEP%s- :' % index) + for name in items: + item = '\ '.join(token.title() for token in name.split('_')) + for command in ['amenu', 'vmenu']: + vim.command('%s &Ropevim.%s :call %s()' % + (command, item, _vim_name(name))) + + +ropemode.decorators.logger.message = echo +ropemode.decorators.logger.only_short = True +_completer = _ValueCompleter() + +_init_variables() +_env = VimUtils() +_interface = ropemode.interface.RopeMode(env=_env) +_interface.init() +_enable_shortcuts(_env) +_add_menu(_env) diff -r e30544496575 -r 48cacfdc2ca6 vim/sadness/ropevim/src/ropevim/ropevim.vim --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vim/sadness/ropevim/src/ropevim/ropevim.vim Wed Oct 06 12:30:46 2010 -0400 @@ -0,0 +1,7 @@ +function! LoadRope() +python << EOF +import ropevim +EOF +endfunction + +call LoadRope() diff -r e30544496575 -r 48cacfdc2ca6 vim/sadness/ropevim/src/ropevim/setup.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vim/sadness/ropevim/src/ropevim/setup.py Wed Oct 06 12:30:46 2010 -0400 @@ -0,0 +1,41 @@ +extra_kwargs = {} +try: + from setuptools import setup + extra_kwargs['install_requires'] = ['rope >= 0.9.3', 'ropemode'] + extra_kwargs['zip_safe'] = False +except ImportError: + from distutils.core import setup + + +classifiers=[ + 'Development Status :: 4 - Beta', + 'Operating System :: OS Independent', + 'Environment :: X11 Applications', + 'Environment :: Win32 (MS Windows)', + # Have not been tested on MacOS + # 'Environment :: MacOS X', + 'Intended Audience :: Developers', + 'License :: OSI Approved :: GNU General Public License (GPL)', + 'Natural Language :: English', + 'Programming Language :: Python', + 'Topic :: Software Development'] + +def get_long_description(): + lines = open('README.txt').read().splitlines(False) + end = lines.index('Setting Up') + return '\n' + '\n'.join(lines[:end]) + '\n' + +setup(name='ropevim', + version='0.3-rc', + description='A vim plugin for using rope python refactoring library', + long_description=get_long_description(), + py_modules=['ropevim'], + author='Ali Gholami Rudi', + author_email='aligrudi@users.sourceforge.net', + url='http://rope.sf.net/ropevim.html', + license='GNU GPL', + classifiers=classifiers, + requires=['ropemode'], + data_files=[('share/vim/plugin', ['ropevim.vim'])], + **extra_kwargs +)