--- 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 <F4> :TlistToggle<cr>
map <leader>T :!/usr/local/bin/ctags -R .<CR>
+" Rope
+source $HOME/.vim/sadness/ropevim/rope.vim
+
if has('gui_running')
set guifont=Menlo:h12
colorscheme molokai
--- /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
--- /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
--- /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
--- /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
--- /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
--- /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
--- /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
--- /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 <piranha@piranha.org.ua>
+* Sebastjan Trepca <trepca@gmail.com>
+* MATSUI Tetsushi <mft@users.sf.net>
+* Kevin Turner <keturn@keturn.net>
+* Darren Syzling <dsyzling@gmail.com>
+* Orestis Markou <orestis@gmail.com>
+* Ronny Pfannschmidt <ronny.pfannschmidt@gmail.com>
+* Anton Gritsay <general@angri.ru>
--- /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.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ 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.
+
+ <signature of Ty Coon>, 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.
--- /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
--- /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
--- /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
--- /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.
--- /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
--- /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.
--- /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)
--- /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
--- /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
--- /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."""
--- /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']
--- /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
--- /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='<string>'):
+ # 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
--- /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)
--- /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)
--- /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])
--- /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]*'
--- /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!
--- /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
--- /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))
--- /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
--- /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
--- /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()
--- /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.
+
+"""
--- /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)
--- /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
--- /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
--- /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)
--- /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 ['?', '<module>']:
+ # 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()
--- /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))
--- /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]
--- /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)
--- /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)
--- /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)))
--- /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
--- /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
--- /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
--- /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
--- /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
--- /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'
--- /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)
--- /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
--- /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]')
--- /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
--- /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
--- /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
--- /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]
+
--- /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.
+
+"""
--- /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
--- /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
--- /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)
--- /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)
--- /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
--- /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
--- /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)
--- /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])
--- /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']
--- /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())
--- /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)
--- /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)
--- /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]
--- /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
--- /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__'
--- /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
--- /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
--- /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(?P<return>return)\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 <file: %s, offset: %d>' % (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()
--- /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
--- /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)
--- /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'
--- /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()
--- /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
--- /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)
--- /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)
--- /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
--- /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)
--- /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]
--- /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<name>\$\{[^\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)
--- /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)
--- /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))
--- /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)
--- /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)
--- /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
--- /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())
--- /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()
--- /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()
--- /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()
--- /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())
--- /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()
--- /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()
--- /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()
--- /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()
--- /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()
--- /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()
--- /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()
--- /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()
--- /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()
--- /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()
--- /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()
--- /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()
--- /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()
--- /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())
--- /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()
--- /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()
--- /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()
--- /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()
--- /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()
--- /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()
--- /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()
--- /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()
--- /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()
--- /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()
--- /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()
--- /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()
--- /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()
--- /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()
--- /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
--- /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)
--- /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
--- /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
--- /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."""
--- /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
--- /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)
--- /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)
+
--- /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
--- /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
--- /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
--- /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()
--- /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
+)
+
--- /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
--- /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 <alonlevy1@gmail.com>
+* Matthieu Tanguay-Carel <matthieutc@gmail.com>
+* Jesse Zhang <sbjesse@gmail.com>
+* Ben Davis <bendavis78@gmail.com>
+* Anton Gritsay <general@angri.ru>
--- /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.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ 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.
+
+ <signature of Ty Coon>, 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.
--- /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
--- /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<docs``. This way you can find files faster in your
+project. ``RopeFindFileOtherWindow`` (``C-x p 4 f``) opens the
+file in the other window.
+
+
+Code-Assist
+-----------
+
+``RopeCodeAssist`` command (``M-/``) will let you select from a list
+of completions. ``RopeLuckyAssist`` command (``M-?``) does not ask
+anything; instead, it inserts the first proposal.
+
+You can tell ropevim to use vim's complete function in insert mode;
+Add::
+
+ let ropevim_vim_completion=1
+
+to your ``~/.vimrc`` file.
+
+Note that when this variable is set, autoimport completions no longer
+work since they need to insert an import to the top of the module, too.
+
+By default autocomplete feature will use plain list of proposed completion
+items. You can enable showing extended information about completion
+proposals by setting ::
+
+ let ropevim_extended_complete=1
+
+Completion menu list will show the proposed name itself, one letter which
+shows where this proposal came from (it can be "L" for locals, "G" for
+globals, "B" for builtins, or empty string if such scope definition is not
+applicable), a short object type description (such as "func", "param",
+"meth" and so forth) and a first line of proposed object's docstring (if it
+has one). For function's keyword parameters the last field shows "*" symbol
+if this param is required or "= <default value>" 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 <C-c>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.
--- /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
--- /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
--- /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
--- /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("<cword>")')
+
+ 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()<cr>' % (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': '"<C-c>r"',
+ 'ropevim_global_prefix': '"<C-x>p"',
+ 'ropevim_vim_completion': 0,
+ 'ropevim_guess_project': 0}
+
+shortcuts = {'code_assist': '<M-/>',
+ 'lucky_assist': '<M-?>',
+ 'goto_definition': '<C-c>g',
+ 'show_doc': '<C-c>d',
+ 'find_occurrences': '<C-c>f'}
+
+insert_shortcuts = {'code_assist': '<M-/>',
+ 'lucky_assist': '<M-?>'}
+
+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()<cr>' %
+ (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 <C-R>=%s()<cr>' % (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 <silent> &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 <silent> &Ropevim.%s :call %s()<cr>' %
+ (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)
--- /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()
--- /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
+)