rope-0.9.2/0000755000175000017500000000000011147312731010563 5ustar alialirope-0.9.2/PKG-INFO0000644000175000017500000000423411147312731011663 0ustar alialiMetadata-Version: 1.0 Name: rope Version: 0.9.2 Summary: a python refactoring library... Home-page: http://rope.sf.net/ Author: Ali Gholami Rudi Author-email: aligrudi@users.sourceforge.net License: GNU GPL Description: ======================================== rope, a python refactoring library ... ======================================== Overview ======== `Rope`_ is a python refactoring library. .. _`rope`: http://rope.sf.net/ New Features ============ * caching all sub-modules of a module in `rope.contrib.autoimport` * fix recursion when creating modules * added basic support for setuptools * extract method handles conditional variable updates * added `rope.contrib.codeassist.CompletionProposal.parameters` The `rope.contrib.autoimport.AutoImport.generate_module_cache()` has been changed to handle module names that end with ``.*``. Now one can use ``rope.*`` to mean `rope` and all of its sub-modules. Extract method now handles variable updates better. For instance in:: def f(a): if 0: a = 1 print(a) When extracting the first two lines of `f()`, `a` should be passed to `g()`. Although these lines don't read `a`, if the conditional write (like in ``if`` or ``while`` blocks) does not happen, it results in an error. So the outcome will be:: def f(a): a = g(a) print(a) def g(a): if 0: a = 1 return a Platform: UNKNOWN Classifier: Development Status :: 4 - Beta Classifier: Operating System :: OS Independent Classifier: Environment :: X11 Applications Classifier: Environment :: Win32 (MS Windows) Classifier: Environment :: MacOS X Classifier: Intended Audience :: Developers Classifier: License :: OSI Approved :: GNU General Public License (GPL) Classifier: Natural Language :: English Classifier: Programming Language :: Python Classifier: Topic :: Software Development rope-0.9.2/setup.py0000644000175000017500000000336411147312726012307 0ustar alialiimport 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 def make_temps(): if not os.path.exists('rope/docs'): os.mkdir('rope/docs') for name in glob.glob('docs/*.txt'): shutil.copy(name, 'rope/docs/') def remove_temps(): if os.path.exists('rope/docs'): shutil.rmtree('rope/docs') 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' make_temps() try: 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'], package_data={'rope': ['docs/*.txt']}, license='GNU GPL', classifiers=classifiers, **extra_kwargs) finally: remove_temps() rope-0.9.2/README.txt0000644000175000017500000000406011147312725012264 0ustar aliali======================================== rope, a python refactoring library ... ======================================== Overview ======== `Rope`_ is a python refactoring library. .. _`rope`: http://rope.sf.net/ New Features ============ * caching all sub-modules of a module in `rope.contrib.autoimport` * fix recursion when creating modules * added basic support for setuptools * extract method handles conditional variable updates * added `rope.contrib.codeassist.CompletionProposal.parameters` The `rope.contrib.autoimport.AutoImport.generate_module_cache()` has been changed to handle module names that end with ``.*``. Now one can use ``rope.*`` to mean `rope` and all of its sub-modules. Extract method now handles variable updates better. For instance in:: def f(a): if 0: a = 1 print(a) When extracting the first two lines of `f()`, `a` should be passed to `g()`. Although these lines don't read `a`, if the conditional write (like in ``if`` or ``while`` blocks) does not happen, it results in an error. So the outcome will be:: def f(a): a = g(a) print(a) def g(a): if 0: a = 1 return a 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 rope-0.9.2/MANIFEST.in0000644000175000017500000000021111147312725012316 0ustar alialiinclude README.txt COPYING setup.py MANIFEST.in recursive-include rope *.py recursive-include docs *.txt recursive-include ropetest *.py rope-0.9.2/COPYING0000644000175000017500000004310311147312725011622 0ustar aliali GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Lesser General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. rope-0.9.2/ropetest/0000755000175000017500000000000011147312731012430 5ustar alialirope-0.9.2/ropetest/testutils.py0000644000175000017500000000525611147312726015056 0ustar alialiimport 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 rope-0.9.2/ropetest/simplifytest.py0000644000175000017500000000370011147312726015542 0ustar alialiimport 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() rope-0.9.2/ropetest/runmodtest.py0000644000175000017500000001444011147312726015215 0ustar alialiimport 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() rope-0.9.2/ropetest/pyscopestest.py0000644000175000017500000002411711147312726015560 0ustar alialiimport 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() rope-0.9.2/ropetest/pycoretest.py0000644000175000017500000014044311147312726015215 0ustar alialiimport 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_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) @testutils.assert_raises(exceptions.ModuleDecodeError) def test_not_syntax_errors_when_cannot_decode_file(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) 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() rope-0.9.2/ropetest/projecttest.py0000644000175000017500000012065211147312726015362 0ustar alialiimport 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() rope-0.9.2/ropetest/objectinfertest.py0000644000175000017500000003364611147312726016214 0ustar alialiimport 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() rope-0.9.2/ropetest/objectdbtest.py0000644000175000017500000001167611147312726015475 0ustar alialiimport 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() rope-0.9.2/ropetest/historytest.py0000644000175000017500000003602311147312726015413 0ustar alialiimport 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() rope-0.9.2/ropetest/codeanalyzetest.py0000644000175000017500000006245111147312726016214 0ustar alialiimport 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_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() rope-0.9.2/ropetest/builtinstest.py0000644000175000017500000004732711147312726015554 0ustar alialiimport 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_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()) 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() rope-0.9.2/ropetest/advanced_oi_test.py0000644000175000017500000010163011147312726016302 0ustar alialiimport 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() rope-0.9.2/ropetest/__init__.py0000644000175000017500000000205011147312726014542 0ustar alialiimport 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() runner.run(suite()) rope-0.9.2/ropetest/refactor/0000755000175000017500000000000011147312731014235 5ustar alialirope-0.9.2/ropetest/refactor/usefunctiontest.py0000644000175000017500000001174111147312726020061 0ustar alialiimport 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() rope-0.9.2/ropetest/refactor/suitestest.py0000644000175000017500000001251311147312726017031 0ustar alialiimport 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() rope-0.9.2/ropetest/refactor/similarfindertest.py0000644000175000017500000002677611147312726020365 0ustar alialiimport 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() rope-0.9.2/ropetest/refactor/restructuretest.py0000644000175000017500000001736611147312726020117 0ustar alialifrom 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() rope-0.9.2/ropetest/refactor/renametest.py0000644000175000017500000010014411147312726016762 0ustar alialiimport 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() rope-0.9.2/ropetest/refactor/patchedasttest.py0000644000175000017500000010151711147312726017640 0ustar alialiimport 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_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() rope-0.9.2/ropetest/refactor/multiprojecttest.py0000644000175000017500000000605011147312726020235 0ustar alialiimport 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() rope-0.9.2/ropetest/refactor/movetest.py0000644000175000017500000005604311147312726016471 0ustar alialiimport 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() rope-0.9.2/ropetest/refactor/inlinetest.py0000644000175000017500000007053311147312726017001 0ustar alialifrom 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() rope-0.9.2/ropetest/refactor/importutilstest.py0000644000175000017500000014023111147312726020107 0ustar alialiimport 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() rope-0.9.2/ropetest/refactor/extracttest.py0000644000175000017500000012154011147312726017170 0ustar alialiimport 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) if __name__ == '__main__': unittest.main() rope-0.9.2/ropetest/refactor/change_signature_test.py0000644000175000017500000005155511147312726021173 0ustar alialiimport 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() rope-0.9.2/ropetest/refactor/__init__.py0000644000175000017500000011516211147312726016360 0ustar alialiimport 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() runner.run(suite()) rope-0.9.2/ropetest/contrib/0000755000175000017500000000000011147312731014070 5ustar alialirope-0.9.2/ropetest/contrib/generatetest.py0000644000175000017500000002555311147312726017152 0ustar alialiimport 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() rope-0.9.2/ropetest/contrib/fixmodnamestest.py0000644000175000017500000000415511147312726017665 0ustar alialiimport 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() rope-0.9.2/ropetest/contrib/findittest.py0000644000175000017500000001220011147312726016616 0ustar alialifrom 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() rope-0.9.2/ropetest/contrib/finderrorstest.py0000644000175000017500000000316111147312726017524 0ustar alialiimport 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() rope-0.9.2/ropetest/contrib/codeassisttest.py0000644000175000017500000011506311147312726017515 0ustar alialiimport 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, kind, result): for proposal in result: if proposal.name == name and proposal.kind == kind: return self.fail('completion <%s> not proposed' % name) def assert_completion_not_in_result(self, name, kind, result): for proposal in result: if proposal.name == name and proposal.kind == kind: 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.kind == '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', 'global', 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', 'global', 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', 'global', result) self.assert_completion_not_in_result('zip', 'global', result) def test_including_matching_builtins_functions(self): code = 'my_var = zi' result = self._assist(code) self.assert_completion_in_result('zip', 'global', 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', 'local', 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_kind_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, kindpref=['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=['variable', '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_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', 'global', 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) 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, kind, result): for proposal in result: if proposal.name == name and proposal.kind == kind: return self.fail('completion <%s> not proposed' % name) def assert_completion_not_in_result(self, name, kind, result): for proposal in result: if proposal.name == name and proposal.kind == kind: 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', 'global', result) def test_from_import_class(self): code = 'from samplemod import SampleClass\nSample' result = self._assist(code) self.assert_completion_in_result('SampleClass', 'global', 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', 'global', 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', 'global', 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', 'local', 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', 'global', result) def test_from_import_star2(self): code = 'from samplemod import *\nsample' result = self._assist(code) self.assert_completion_in_result('sample_func', 'global', result) self.assert_completion_in_result('sample_var', 'global', 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', 'global', 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', 'attribute', 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() rope-0.9.2/ropetest/contrib/changestacktest.py0000644000175000017500000000200011147312726017611 0ustar alialiimport 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() rope-0.9.2/ropetest/contrib/autoimporttest.py0000644000175000017500000001457111147312726017561 0ustar alialiimport 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() rope-0.9.2/ropetest/contrib/__init__.py0000644000175000017500000000216311147312726016207 0ustar alialiimport 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() runner.run(suite()) rope-0.9.2/rope/0000755000175000017500000000000011147312731011530 5ustar alialirope-0.9.2/rope/__init__.py0000644000175000017500000000114111147312725013641 0ustar aliali"""rope, a python refactoring library""" INFO = __doc__ VERSION = '0.9.2' COPYRIGHT = """\ Copyright (C) 2006-2009 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.""" rope-0.9.2/rope/refactor/0000755000175000017500000000000011147312731013335 5ustar alialirope-0.9.2/rope/refactor/wildcards.py0000644000175000017500000001331411147312726015671 0ustar alialifrom 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 rope-0.9.2/rope/refactor/usefunction.py0000644000175000017500000001426111147312726016261 0ustar alialifrom 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) rope-0.9.2/rope/refactor/topackage.py0000644000175000017500000000243211147312726015652 0ustar alialiimport 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) rope-0.9.2/rope/refactor/suites.py0000644000175000017500000001043011147312726015225 0ustar alialifrom 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)) rope-0.9.2/rope/refactor/sourceutils.py0000644000175000017500000000563411147312726016304 0ustar alialifrom 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) rope-0.9.2/rope/refactor/similarfinder.py0000644000175000017500000003012211147312726016541 0ustar aliali"""This module can be used for finding similar code""" import re import rope.refactor.wildcards from rope.base import codeanalyze, evaluate, exceptions, ast, builtins from rope.refactor import (patchedast, sourceutils, occurrences, wildcards, importutils) class BadNameInCheckError(exceptions.RefactoringError): pass class SimilarFinder(object): """`SimilarFinder` can be used to find similar pieces of code See the notes in the `rope.refactor.restructure` module for more info. """ def __init__(self, pymodule, wildcards=None): """Construct a SimilarFinder""" self.source = pymodule.source_code self.raw_finder = RawSimilarFinder( pymodule.source_code, pymodule.get_ast(), self._does_match) self.pymodule = pymodule if wildcards is None: self.wildcards = {} for wildcard in [rope.refactor.wildcards. DefaultWildcard(pymodule.pycore.project)]: self.wildcards[wildcard.get_name()] = wildcard else: self.wildcards = wildcards def get_matches(self, code, args={}, start=0, end=None): self.args = args if end is None: end = len(self.source) skip_region = None if 'skip' in args.get('', {}): resource, region = args['']['skip'] if resource == self.pymodule.get_resource(): skip_region = region return self.raw_finder.get_matches(code, start=start, end=end, skip=skip_region) def get_match_regions(self, *args, **kwds): for match in self.get_matches(*args, **kwds): yield match.get_region() def _does_match(self, node, name): arg = self.args.get(name, '') kind = 'default' if isinstance(arg, (tuple, list)): kind = arg[0] arg = arg[1] suspect = wildcards.Suspect(self.pymodule, node, name) return self.wildcards[kind].matches(suspect, arg) class RawSimilarFinder(object): """A class for finding similar expressions and statements""" def __init__(self, source, node=None, does_match=None): if node is None: node = ast.parse(source) if does_match is None: self.does_match = self._simple_does_match else: self.does_match = does_match self._init_using_ast(node, source) def _simple_does_match(self, node, name): return isinstance(node, (ast.expr, ast.Name)) def _init_using_ast(self, node, source): self.source = source self._matched_asts = {} if not hasattr(node, 'region'): patchedast.patch_ast(node, source) self.ast = node def get_matches(self, code, start=0, end=None, skip=None): """Search for `code` in source and return a list of `Match`\es `code` can contain wildcards. ``${name}`` matches normal names and ``${?name} can match any expression. You can use `Match.get_ast()` for getting the node that has matched a given pattern. """ if end is None: end = len(self.source) for match in self._get_matched_asts(code): match_start, match_end = match.get_region() if start <= match_start and match_end <= end: if skip is not None and (skip[0] < match_end and skip[1] > match_start): continue yield match def _get_matched_asts(self, code): if code not in self._matched_asts: wanted = self._create_pattern(code) matches = _ASTMatcher(self.ast, wanted, self.does_match).find_matches() self._matched_asts[code] = matches return self._matched_asts[code] def _create_pattern(self, expression): expression = self._replace_wildcards(expression) node = ast.parse(expression) # Getting Module.Stmt.nodes nodes = node.body if len(nodes) == 1 and isinstance(nodes[0], ast.Expr): # Getting Discard.expr wanted = nodes[0].value else: wanted = nodes return wanted def _replace_wildcards(self, expression): ropevar = _RopeVariable() template = CodeTemplate(expression) mapping = {} for name in template.get_names(): mapping[name] = ropevar.get_var(name) return template.substitute(mapping) class _ASTMatcher(object): def __init__(self, body, pattern, does_match): """Searches the given pattern in the body AST. body is an AST node and pattern can be either an AST node or a list of ASTs nodes """ self.body = body self.pattern = pattern self.matches = None self.ropevar = _RopeVariable() self.matches_callback = does_match def find_matches(self): if self.matches is None: self.matches = [] ast.call_for_nodes(self.body, self._check_node, recursive=True) return self.matches def _check_node(self, node): if isinstance(self.pattern, list): self._check_statements(node) else: self._check_expression(node) def _check_expression(self, node): mapping = {} if self._match_nodes(self.pattern, node, mapping): self.matches.append(ExpressionMatch(node, mapping)) def _check_statements(self, node): for child in ast.get_children(node): if isinstance(child, (list, tuple)): self.__check_stmt_list(child) def __check_stmt_list(self, nodes): for index in range(len(nodes)): if len(nodes) - index >= len(self.pattern): current_stmts = nodes[index:index + len(self.pattern)] mapping = {} if self._match_stmts(current_stmts, mapping): self.matches.append(StatementMatch(current_stmts, mapping)) def _match_nodes(self, expected, node, mapping): if isinstance(expected, ast.Name): if self.ropevar.is_var(expected.id): return self._match_wildcard(expected, node, mapping) if not isinstance(expected, ast.AST): return expected == node if expected.__class__ != node.__class__: return False children1 = self._get_children(expected) children2 = self._get_children(node) if len(children1) != len(children2): return False for child1, child2 in zip(children1, children2): if isinstance(child1, ast.AST): if not self._match_nodes(child1, child2, mapping): return False elif isinstance(child1, (list, tuple)): if not isinstance(child2, (list, tuple)) or \ len(child1) != len(child2): return False for c1, c2 in zip(child1, child2): if not self._match_nodes(c1, c2, mapping): return False else: if child1 != child2: return False return True def _get_children(self, node): """Return not `ast.expr_context` children of `node`""" children = ast.get_children(node) return [child for child in children if not isinstance(child, ast.expr_context)] def _match_stmts(self, current_stmts, mapping): if len(current_stmts) != len(self.pattern): return False for stmt, expected in zip(current_stmts, self.pattern): if not self._match_nodes(expected, stmt, mapping): return False return True def _match_wildcard(self, node1, node2, mapping): name = self.ropevar.get_base(node1.id) if name not in mapping: if self.matches_callback(node2, name): mapping[name] = node2 return True return False else: return self._match_nodes(mapping[name], node2, {}) class Match(object): def __init__(self, mapping): self.mapping = mapping def get_region(self): """Returns match region""" def get_ast(self, name): """Return the ast node that has matched rope variables""" return self.mapping.get(name, None) class ExpressionMatch(Match): def __init__(self, ast, mapping): super(ExpressionMatch, self).__init__(mapping) self.ast = ast def get_region(self): return self.ast.region class StatementMatch(Match): def __init__(self, ast_list, mapping): super(StatementMatch, self).__init__(mapping) self.ast_list = ast_list def get_region(self): return self.ast_list[0].region[0], self.ast_list[-1].region[1] class CodeTemplate(object): def __init__(self, template): self.template = template self._find_names() def _find_names(self): self.names = {} for match in CodeTemplate._get_pattern().finditer(self.template): if 'name' in match.groupdict() and \ match.group('name') is not None: start, end = match.span('name') name = self.template[start + 2:end - 1] if name not in self.names: self.names[name] = [] self.names[name].append((start, end)) def get_names(self): return self.names.keys() def substitute(self, mapping): collector = codeanalyze.ChangeCollector(self.template) for name, occurrences in self.names.items(): for region in occurrences: collector.add_change(region[0], region[1], mapping[name]) result = collector.get_changed() if result is None: return self.template return result _match_pattern = None @classmethod def _get_pattern(cls): if cls._match_pattern is None: pattern = codeanalyze.get_comment_pattern() + '|' + \ codeanalyze.get_string_pattern() + '|' + \ r'(?P\$\{[^\s\$\}]*\})' cls._match_pattern = re.compile(pattern) return cls._match_pattern class _RopeVariable(object): """Transform and identify rope inserted wildcards""" _normal_prefix = '__rope__variable_normal_' _any_prefix = '__rope__variable_any_' def get_var(self, name): if name.startswith('?'): return self._get_any(name) else: return self._get_normal(name) def is_var(self, name): return self._is_normal(name) or self._is_var(name) def get_base(self, name): if self._is_normal(name): return name[len(self._normal_prefix):] if self._is_var(name): return '?' + name[len(self._any_prefix):] def _get_normal(self, name): return self._normal_prefix + name def _get_any(self, name): return self._any_prefix + name[1:] def _is_normal(self, name): return name.startswith(self._normal_prefix) def _is_var(self, name): return name.startswith(self._any_prefix) def make_pattern(code, variables): variables = set(variables) collector = codeanalyze.ChangeCollector(code) def does_match(node, name): return isinstance(node, ast.Name) and node.id == name finder = RawSimilarFinder(code, does_match=does_match) for variable in variables: for match in finder.get_matches('${%s}' % variable): start, end = match.get_region() collector.add_change(start, end, '${%s}' % variable) result = collector.get_changed() return result if result is not None else code def _pydefined_to_str(pydefined): address = [] if isinstance(pydefined, (builtins.BuiltinClass, builtins.BuiltinFunction)): return '__builtins__.' + pydefined.get_name() else: while pydefined.parent is not None: address.insert(0, pydefined.get_name()) pydefined = pydefined.parent module_name = pydefined.pycore.modname(pydefined.resource) return '.'.join(module_name.split('.') + address) rope-0.9.2/rope/refactor/restructure.py0000644000175000017500000002655411147312726016316 0ustar alialiimport 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] rope-0.9.2/rope/refactor/rename.py0000644000175000017500000002221711147312726015166 0ustar alialiimport 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) rope-0.9.2/rope/refactor/patchedast.py0000644000175000017500000005761311147312726016047 0ustar alialiimport 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 _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 rope-0.9.2/rope/refactor/occurrences.py0000644000175000017500000002472011147312726016233 0ustar alialiimport 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) rope-0.9.2/rope/refactor/multiproject.py0000644000175000017500000000511711147312726016440 0ustar aliali"""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) rope-0.9.2/rope/refactor/move.py0000644000175000017500000006344511147312726014675 0ustar aliali"""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 rope-0.9.2/rope/refactor/method_object.py0000644000175000017500000000743411147312726016531 0ustar alialiimport 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() rope-0.9.2/rope/refactor/localtofield.py0000644000175000017500000000407711147312726016364 0ustar alialifrom 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' rope-0.9.2/rope/refactor/introduce_parameter.py0000644000175000017500000000745411147312726017761 0ustar alialiimport 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) rope-0.9.2/rope/refactor/introduce_factory.py0000644000175000017500000001406611147312726017445 0ustar alialiimport 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 rope-0.9.2/rope/refactor/inline.py0000644000175000017500000005501011147312726015172 0ustar alialiimport 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 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): 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, returns=False): # caching already calculated definitions key = (call, returns) if key not in self._calculated_definitions: self._calculated_definitions[key] = self._calculate_definition( primary, pyname, call, returns) return self._calculated_definitions[key] def _calculate_definition(self, primary, pyname, call, returns): 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 = [] 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) source = header + self.body for name in to_be_inlined: pymodule = self.pycore.get_string_module(source, self.resource) pyname = pymodule[name] source = _inline_variable(self.pycore, pymodule, pyname, name) return self._replace_returns_with(source, returns) def _replace_returns_with(self, source, returns): result = [] returned = None last_changed = 0 for match in _DefinitionGenerator._get_return_pattern().finditer(source): for key, value in match.groupdict().items(): if value and key == 'return': result.append(source[last_changed:match.start('return')]) if returns: self._check_nothing_after_return(source, match.end('return')) returned = _join_lines( source[match.end('return'): len(source)].splitlines()) last_changed = len(source) else: current = match.end('return') while current < len(source) and source[current] in ' \t': current += 1 last_changed = current if current == len(source) or source[current] == '\n': result.append('pass') result.append(source[last_changed:]) return ''.join(result), returned def _check_nothing_after_return(self, source, offset): lines = codeanalyze.SourceLinesAdapter(source) lineno = lines.get_line_number(offset) logical_lines = codeanalyze.LogicalLineFinder(lines) lineno = logical_lines.logical_line_in(lineno)[1] if source[lines.get_line_end(lineno):len(source)].strip() != '': raise rope.base.exceptions.RefactoringError( 'Cannot inline functions with statements after return statement.') @classmethod def _get_return_pattern(cls): if not hasattr(cls, '_return_pattern'): def named_pattern(name, list_): return "(?P<%s>" % name + "|".join(list_) + ")" comment_pattern = named_pattern('comment', [r'#[^\n]*']) string_pattern = named_pattern('string', [codeanalyze.get_string_pattern()]) return_pattern = r'\b(?Preturn)\b' cls._return_pattern = re.compile(comment_pattern + "|" + string_pattern + "|" + return_pattern) return cls._return_pattern class _InlineFunctionCallsForModuleHandle(object): def __init__(self, pycore, resource, definition_generator, aim_offset=None): """Inlines occurrences If `aim` is not `None` only the occurrences that intersect `aim` offset will be inlined. """ self.pycore = pycore self.generator = definition_generator self.resource = resource self.aim = aim_offset def occurred_inside_skip(self, change_collector, occurrence): if not occurrence.is_defined(): raise rope.base.exceptions.RefactoringError( 'Cannot inline functions that reference themselves') def occurred_outside_skip(self, change_collector, occurrence): start, end = occurrence.get_primary_range() # we remove out of date imports later if occurrence.is_in_import_statement(): return # the function is referenced outside an import statement if not occurrence.is_called(): raise rope.base.exceptions.RefactoringError( 'Reference to inlining function other than function call' ' in ' % (self.resource.path, start)) if self.aim is not None and (self.aim < start or self.aim > end): return end_parens = self._find_end_parens(self.source, end - 1) lineno = self.lines.get_line_number(start) start_line, end_line = self.pymodule.logical_lines.\ logical_line_in(lineno) line_start = self.lines.get_line_start(start_line) line_end = self.lines.get_line_end(end_line) returns = self.source[line_start:start].strip() != '' or \ self.source[end_parens:line_end].strip() != '' indents = sourceutils.get_indents(self.lines, start_line) primary, pyname = occurrence.get_primary_and_pyname() definition, returned = self.generator.get_definition( primary, pyname, self.source[start:end_parens], 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() rope-0.9.2/rope/refactor/functionutils.py0000644000175000017500000001774511147312726016637 0ustar alialiimport rope.base.exceptions import rope.base.pyobjects 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() is_method = pyfunction.get_kind() == 'method' info = _FunctionParser(code, is_method) 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) 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): self.call = call self.implicit_arg = implicit_arg self.word_finder = worder.Worder(self.call) 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] rope-0.9.2/rope/refactor/extract.py0000644000175000017500000006676311147312726015407 0ustar alialiimport 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.maybe_written & self.info_collector.postread) 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) rope-0.9.2/rope/refactor/encapsulate_field.py0000644000175000017500000002072111147312726017364 0ustar alialifrom 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) rope-0.9.2/rope/refactor/change_signature.py0000644000175000017500000003174011147312726017226 0ustar alialiimport 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()) rope-0.9.2/rope/refactor/__init__.py0000644000175000017500000000404111147312726015451 0ustar aliali"""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'] rope-0.9.2/rope/refactor/importutils/0000755000175000017500000000000011147312731015730 5ustar alialirope-0.9.2/rope/refactor/importutils/module_imports.py0000644000175000017500000004022111147312726021347 0ustar alialiimport 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 rope-0.9.2/rope/refactor/importutils/importinfo.py0000644000175000017500000001317611147312726020504 0ustar alialiclass 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 rope-0.9.2/rope/refactor/importutils/actions.py0000644000175000017500000003325611147312726017757 0ustar alialiimport 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__' rope-0.9.2/rope/refactor/importutils/__init__.py0000644000175000017500000003071411147312726020052 0ustar aliali"""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 rope-0.9.2/rope/contrib/0000755000175000017500000000000011147312731013170 5ustar alialirope-0.9.2/rope/contrib/generate.py0000644000175000017500000003170111147312726015342 0ustar alialiimport 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]) rope-0.9.2/rope/contrib/fixsyntax.py0000644000175000017500000001574711147312726015621 0ustar alialiimport 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) rope-0.9.2/rope/contrib/fixmodnames.py0000644000175000017500000000432011147312726016057 0ustar aliali"""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 rope-0.9.2/rope/contrib/findit.py0000644000175000017500000001062711147312726015031 0ustar alialiimport 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 rope-0.9.2/rope/contrib/finderrors.py0000644000175000017500000000560411147312726015730 0ustar aliali"""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) rope-0.9.2/rope/contrib/codeassist.py0000644000175000017500000005447111147312726015722 0ustar alialiimport keyword import sys import warnings import rope.base.codeanalyze import rope.base.evaluate from rope.base import pyobjects, 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 CodeAssistProposal(object): """The base class for proposals reported by `code_assist` The `kind` instance variable shows the kind of the proposal and can be 'global', 'local', 'builtin', 'attribute', 'keyword', 'parameter_keyword'. """ def __init__(self, name, kind): self.name = name self.kind = kind class CompletionProposal(CodeAssistProposal): """A completion proposal The `type` instance variable shows the type of the proposal and can be 'variable', 'class', 'function', 'imported' , 'paramter' and `None`. """ def __init__(self, name, kind, type=None, pyname=None): super(CompletionProposal, self).__init__(name, kind) self.type = type self.pyname = pyname def __str__(self): return '%s (%s, %s)' % (self.name, self.kind, 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, pyobject.AbstractFunction): return pyobject.get_param_names() def sorted_proposals(proposals, kindpref=None, typepref=None): """Sort a list of proposals Return a sorted list of the given `CodeAssistProposal`\s. `kindpref` can be a list of proposal kinds. Defaults to ``['local', 'parameter_keyword', 'global', 'attribute', 'keyword']``. `typepref` can be a list of proposal types. Defaults to ``['class', 'function', 'variable', 'parameter', 'imported', 'builtin', None]``. (`None` stands for completions with no type like keywords.) """ sorter = _ProposalSorter(proposals, kindpref, 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() for name, pyname in element.get_attributes().items(): if name.startswith(self.starting): result[name] = CompletionProposal( name, 'attribute', self._get_pyname_type(pyname), 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): kind = 'local' if scope.get_kind() == 'Module': kind = 'global' if lineno is None or self.later_locals or \ not self._is_defined_after(scope, pyname, lineno): result[name] = CompletionProposal( name, kind, self._get_pyname_type(pyname), 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, kind='global', type='imported', 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 _get_pyname_type(self, pyname): if isinstance(pyname, builtins.BuiltinName): return 'builtin' if isinstance(pyname, pynames.ImportedName) or \ isinstance(pyname, pynames.ImportedModule): return 'imported' if isinstance(pyname, pynames.ParameterName): return 'parameter' if isinstance(pyname, builtins.BuiltinName) or \ isinstance(pyname, pynames.DefinedName): pyobject = pyname.get_object() if isinstance(pyobject, pyobjects.AbstractFunction): return 'function' if isinstance(pyobject, pyobjects.AbstractClass): return 'class' return 'variable' 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 + '='] = CompletionProposal( name + '=', 'parameter_keyword') return result return {} class _ProposalSorter(object): """Sort a list of code assist proposals""" def __init__(self, code_assist_proposals, kindpref=None, typepref=None): self.proposals = code_assist_proposals if kindpref is None: kindpref = ['local', 'parameter_keyword', 'global', 'attribute', 'keyword'] self.kindpref = kindpref if typepref is None: typepref = ['class', 'function', 'variable', 'parameter', 'imported', 'builtin', 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.kind, []).append(proposal) result = [] for kind in self.kindpref: kind_proposals = proposals.get(kind, []) kind_proposals = [proposal for proposal in kind_proposals if proposal.type in self.typerank] kind_proposals.sort(self._proposal_cmp) result.extend(kind_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) rope-0.9.2/rope/contrib/changestack.py0000644000175000017500000000256011147312726016024 0ustar aliali"""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 rope-0.9.2/rope/contrib/autoimport.py0000644000175000017500000001764711147312726015770 0ustar alialiimport 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 rope-0.9.2/rope/contrib/__init__.py0000644000175000017500000000025111147312726015303 0ustar aliali"""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. """ rope-0.9.2/rope/base/0000755000175000017500000000000011147312731012442 5ustar alialirope-0.9.2/rope/base/worder.py0000644000175000017500000004553111147312726014332 0ustar alialiimport bisect 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 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)): return self._find_atom_start(offset) 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): end = self._find_word_end(offset) start_parens = self.code.index('(', end) index = start_parens open_count = 0 while index < len(self.code): if self.code[index] == '(': open_count += 1 if self.code[index] == ')': 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): while True: offset = self.code.index('def ', 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_) rope-0.9.2/rope/base/utils.py0000644000175000017500000000430311147312726014160 0ustar alialiimport 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 rope-0.9.2/rope/base/taskhandle.py0000644000175000017500000000551311147312726015142 0ustar alialiimport 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.handle._inform_observers() self.job_name = None self.done += 1 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 rope-0.9.2/rope/base/stdmods.py0000644000175000017500000000216511147312726014501 0ustar alialiimport 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 rope-0.9.2/rope/base/simplify.py0000644000175000017500000000323411147312726014656 0ustar aliali"""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]') rope-0.9.2/rope/base/resources.py0000644000175000017500000001405711147312726015041 0ustar alialiimport 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 rope-0.9.2/rope/base/resourceobserver.py0000644000175000017500000002403211147312726016420 0ustar alialiimport 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) rope-0.9.2/rope/base/pyscopes.py0000644000175000017500000002301711147312726014670 0ustar alialiimport 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' rope-0.9.2/rope/base/pyobjectsdef.py0000644000175000017500000004456111147312726015513 0ustar alialiimport 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 try: source, node = self._init_source(pycore, source, resource) except exceptions.ModuleSyntaxError: if syntax_errors: raise else: source = '\n' node = ast.parse('\n') self.source_code = source self.star_imports = [] self.visitor_class = _GlobalVisitor 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 rope-0.9.2/rope/base/pyobjects.py0000644000175000017500000002101611147312726015022 0ustar alialifrom 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): return expr.value.s 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 rope-0.9.2/rope/base/pynamesdef.py0000644000175000017500000000326711147312726015163 0ustar alialiimport 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 rope-0.9.2/rope/base/pynames.py0000644000175000017500000001342611147312726014502 0ustar alialiimport 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 rope-0.9.2/rope/base/pycore.py0000644000175000017500000003601011147312726014321 0ustar alialiimport 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', []): self._custom_source_folders.append(path) 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) 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 rope-0.9.2/rope/base/project.py0000644000175000017500000003265011147312725014473 0ustar alialiimport 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.needs_gc = True self.files = set() self.folders = set() def get_files(self): if self.needs_gc: # forcing the creation of the observer self.observer for file in list(self.files): if not file.exists(): self.files.remove(file) for folder in list(self.folders): if not folder.exists(): self.folders.remove(folder) self.observer.remove_resource(folder) self.needs_gc = False return self.files def _updated_resources(self, folder): if not folder.exists(): return set(), set() files = set() folders = set([folder]) files.update(folder.get_files()) for child in folder.get_folders(): if child not in self.folders: newfiles, newfolders = self._updated_resources(child) files.update(newfiles) folders.update(newfolders) return files, folders def _update_folder(self, folder): files, folders = self._updated_resources(folder) self.files.update(files) for child in folders - self.folders: self.folders.add(child) self.observer.add_resource(child) self.needs_gc = True @property @utils.saveit def observer(self): rawobserver = ResourceObserver( self._changed, self._moved, self._created, self._removed, self._validate) observer = FilteredResourceObserver(rawobserver) self.project.add_observer(observer) self._update_folder(self.project.root) return observer def _changed(self, resource): if resource.is_folder(): self._update_folder(resource) def _moved(self, resource, new_resource): if resource.is_folder(): self._update_folder(resource) self._update_folder(new_resource) else: self._removed(resource) self._created(new_resource) def _created(self, resource): if resource.is_folder(): self._update_folder(resource) else: if not self.project.is_ignored(resource): self.files.add(resource) def _removed(self, resource): if resource.is_folder(): self._update_folder(resource) else: if resource in self.files: self.files.remove(resource) def _validate(self, resource): pass 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))) rope-0.9.2/rope/base/prefs.py0000644000175000017500000000211611147312725014136 0ustar alialiclass 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) rope-0.9.2/rope/base/libutils.py0000644000175000017500000000433011147312725014646 0ustar aliali"""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() rope-0.9.2/rope/base/history.py0000644000175000017500000002071611147312725014526 0ustar alialifrom 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 rope-0.9.2/rope/base/fscommands.py0000644000175000017500000001515711147312725015162 0ustar aliali"""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() self.ui = self.hg.ui.ui( verbose=False, debug=False, quiet=True, interactive=False, traceback=False, report_untrusted=False) 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 encoding is None: encoding = read_str_coding(data) try: if encoding is not None: return unicode(data, encoding) return unicode(data) except (UnicodeDecodeError, LookupError): # Using ``utf-8`` if guessed encoding fails return unicode(data, 'utf-8') 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 rope-0.9.2/rope/base/exceptions.py0000644000175000017500000000264611147312725015210 0ustar alialiclass 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)) rope-0.9.2/rope/base/evaluate.py0000644000175000017500000002754311147312725014640 0ustar alialiimport 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): self.result = rope.base.pynames.UnboundName( self._get_object_for_node(node.values[0])) 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: call_function = pyobject[function_name].get_object() args = [node] if other_args: args += other_args arguments_ = arguments.Arguments(args, self.scope) self.result = rope.base.pynames.UnboundName( pyobject=call_function.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 rope-0.9.2/rope/base/default_config.py0000644000175000017500000000660511147312725015777 0ustar aliali# 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! rope-0.9.2/rope/base/codeanalyze.py0000644000175000017500000002563011147312725015323 0ustar alialiimport 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]*' rope-0.9.2/rope/base/change.py0000644000175000017500000003236611147312725014256 0ustar alialiimport 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]) rope-0.9.2/rope/base/builtins.py0000644000175000017500000005532311147312725014660 0ustar aliali"""This module trys to support builtin types and functions.""" import inspect import rope.base.evaluate from rope.base import pynames, pyobjects, arguments, utils 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 self.builtin.__doc__ def get_name(self): if self.builtin: return self.builtin.__name__ @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 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 = pyobjects.get_unknown() 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.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_pattributes(self): return {} 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: iter = seq['__iter__'].get_object().\ 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) rope-0.9.2/rope/base/astutils.py0000644000175000017500000000304311147312725014667 0ustar alialifrom 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) rope-0.9.2/rope/base/ast.py0000644000175000017500000000367511147312725013621 0ustar alialiimport _ast from _ast import * from rope.base import fscommands def parse(source, filename=''): # NOTE: the raw string should be given to `compile` function if isinstance(source, unicode): source = fscommands.unicode_to_file_data(source) if '\r' in source: source = source.replace('\r\n', '\n').replace('\r', '\n') if not source.endswith('\n'): source += '\n' try: return compile(source, filename, 'exec', _ast.PyCF_ONLY_AST) except (TypeError, ValueError), e: error = SyntaxError() error.lineno = 1 error.filename = filename error.msg = str(e) raise error def walk(node, walker): """Walk the syntax tree""" method_name = '_' + node.__class__.__name__ method = getattr(walker, method_name, None) if method is not None: return method(node) for child in get_child_nodes(node): walk(child, walker) def get_child_nodes(node): if isinstance(node, _ast.Module): return node.body result = [] if node._fields is not None: for name in node._fields: child = getattr(node, name) if isinstance(child, list): for entry in child: if isinstance(entry, _ast.AST): result.append(entry) if isinstance(child, _ast.AST): result.append(child) return result def call_for_nodes(node, callback, recursive=False): """If callback returns `True` the child nodes are skipped""" result = callback(node) if recursive and not result: for child in get_child_nodes(node): call_for_nodes(child, callback, recursive) def get_children(node): result = [] if node._fields is not None: for name in node._fields: if name in ['lineno', 'col_offset']: continue child = getattr(node, name) result.append(child) return result rope-0.9.2/rope/base/arguments.py0000644000175000017500000000634011147312725015027 0ustar alialiimport 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 rope-0.9.2/rope/base/__init__.py0000644000175000017500000000024111147312725014553 0ustar aliali"""Base rope package This package contains rope core modules that are used by other modules and packages. """ __all__ = ['project', 'libutils', 'exceptions'] rope-0.9.2/rope/base/oi/0000755000175000017500000000000011147312731013051 5ustar alialirope-0.9.2/rope/base/oi/transform.py0000644000175000017500000002320211147312725015440 0ustar aliali"""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) rope-0.9.2/rope/base/oi/soi.py0000644000175000017500000001520311147312725014221 0ustar aliali"""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] rope-0.9.2/rope/base/oi/soa.py0000644000175000017500000001276211147312725014220 0ustar alialiimport 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)) rope-0.9.2/rope/base/oi/runmod.py0000644000175000017500000001666011147312725014743 0ustar aliali def __rope_start_everything(): import os import sys import socket import cPickle as pickle import marshal import inspect import types import threading class _MessageSender(object): def send_data(self, data): pass class _SocketSender(_MessageSender): def __init__(self, port): s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect(('127.0.0.1', port)) self.my_file = s.makefile('w') def send_data(self, data): if not self.my_file.closed: pickle.dump(data, self.my_file) def close(self): self.my_file.close() class _FileSender(_MessageSender): def __init__(self, file_name): self.my_file = open(file_name, 'wb') def send_data(self, data): if not self.my_file.closed: marshal.dump(data, self.my_file) def close(self): self.my_file.close() def _cached(func): cache = {} def newfunc(self, arg): if arg in cache: return cache[arg] result = func(self, arg) cache[arg] = result return result return newfunc class _FunctionCallDataSender(object): def __init__(self, send_info, project_root): self.project_root = project_root if send_info.isdigit(): self.sender = _SocketSender(int(send_info)) else: self.sender = _FileSender(send_info) def global_trace(frame, event, arg): # HACK: Ignoring out->in calls # This might lose some information if self._is_an_interesting_call(frame): return self.on_function_call sys.settrace(global_trace) threading.settrace(global_trace) def on_function_call(self, frame, event, arg): if event != 'return': return args = [] returned = ('unknown',) code = frame.f_code for argname in code.co_varnames[:code.co_argcount]: try: args.append(self._object_to_persisted_form(frame.f_locals[argname])) except (TypeError, AttributeError): args.append(('unknown',)) try: returned = self._object_to_persisted_form(arg) except (TypeError, AttributeError): pass try: data = (self._object_to_persisted_form(frame.f_code), tuple(args), returned) self.sender.send_data(data) except (TypeError): pass return self.on_function_call def _is_an_interesting_call(self, frame): #if frame.f_code.co_name in ['?', '']: # return False #return not frame.f_back or not self._is_code_inside_project(frame.f_back.f_code) if not self._is_code_inside_project(frame.f_code) and \ (not frame.f_back or not self._is_code_inside_project(frame.f_back.f_code)): return False return True def _is_code_inside_project(self, code): source = self._path(code.co_filename) return source is not None and os.path.exists(source) and \ _realpath(source).startswith(self.project_root) @_cached def _get_persisted_code(self, object_): source = self._path(object_.co_filename) if not os.path.exists(source): raise TypeError('no source') return ('defined', _realpath(source), str(object_.co_firstlineno)) @_cached def _get_persisted_class(self, object_): try: return ('defined', _realpath(inspect.getsourcefile(object_)), object_.__name__) except (TypeError, AttributeError): return ('unknown',) def _get_persisted_builtin(self, object_): if isinstance(object_, (str, unicode)): return ('builtin', 'str') if isinstance(object_, list): holding = None if len(object_) > 0: holding = object_[0] return ('builtin', 'list', self._object_to_persisted_form(holding)) if isinstance(object_, dict): keys = None values = None if len(object_) > 0: keys = object_.keys()[0] values = object_[keys] return ('builtin', 'dict', self._object_to_persisted_form(keys), self._object_to_persisted_form(values)) if isinstance(object_, tuple): objects = [] if len(object_) < 3: for holding in object_: objects.append(self._object_to_persisted_form(holding)) else: objects.append(self._object_to_persisted_form(object_[0])) return tuple(['builtin', 'tuple'] + objects) if isinstance(object_, set): holding = None if len(object_) > 0: for o in object_: holding = o break return ('builtin', 'set', self._object_to_persisted_form(holding)) return ('unknown',) def _object_to_persisted_form(self, object_): if object_ is None: return ('none',) if isinstance(object_, types.CodeType): return self._get_persisted_code(object_) if isinstance(object_, types.FunctionType): return self._get_persisted_code(object_.func_code) if isinstance(object_, types.MethodType): return self._get_persisted_code(object_.im_func.func_code) if isinstance(object_, types.ModuleType): return self._get_persisted_module(object_) if isinstance(object_, (str, unicode, list, dict, tuple, set)): return self._get_persisted_builtin(object_) if isinstance(object_, (types.TypeType, types.ClassType)): return self._get_persisted_class(object_) return ('instance', self._get_persisted_class(type(object_))) @_cached def _get_persisted_module(self, object_): path = self._path(object_.__file__) if path and os.path.exists(path): return ('defined', _realpath(path)) return ('unknown',) def _path(self, path): if path.endswith('.pyc'): path = path[:-1] if path.endswith('.py'): return path def close(self): self.sender.close() def _realpath(path): return os.path.realpath(os.path.abspath(os.path.expanduser(path))) send_info = sys.argv[1] project_root = sys.argv[2] file_to_run = sys.argv[3] run_globals = globals() run_globals.update({'__name__': '__main__', '__builtins__': __builtins__, '__file__': file_to_run}) if send_info != '-': data_sender = _FunctionCallDataSender(send_info, project_root) del sys.argv[1:4] execfile(file_to_run, run_globals) if send_info != '-': data_sender.close() if __name__ == '__main__': __rope_start_everything() rope-0.9.2/rope/base/oi/objectinfo.py0000644000175000017500000002107711147312725015557 0ustar alialiimport 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) rope-0.9.2/rope/base/oi/objectdb.py0000644000175000017500000001101111147312725015174 0ustar alialiimport 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 rope-0.9.2/rope/base/oi/memorydb.py0000644000175000017500000000522311147312725015246 0ustar alialifrom 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 rope-0.9.2/rope/base/oi/doa.py0000644000175000017500000001165511147312725014201 0ustar alialiimport 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) rope-0.9.2/rope/base/oi/__init__.py0000644000175000017500000000322411147312725015166 0ustar aliali"""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. """ rope-0.9.2/docs/0000755000175000017500000000000011147312731011513 5ustar alialirope-0.9.2/docs/rope.txt0000644000175000017500000000261411147312725013227 0ustar alialiFeatures ======== 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 rope-0.9.2/docs/overview.txt0000644000175000017500000006004211147312725014127 0ustar aliali=============== 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 rope-0.9.2/docs/library.txt0000644000175000017500000005471311147312725013735 0ustar aliali========================= 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) rope-0.9.2/docs/done.txt0000644000175000017500000004716411147312725013220 0ustar aliali=========== Done List =========== > 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. rope-0.9.2/docs/contributing.txt0000644000175000017500000000455511147312725014777 0ustar aliali====================== 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 rope-0.9.2/docs/dev/0000755000175000017500000000000011147312731012271 5ustar alialirope-0.9.2/docs/dev/todo.txt0000644000175000017500000000016111147312725014000 0ustar aliali====== TODO ====== See the `unresolved issues` section of ``issues.txt`` file for more. > Public Release 1.0 rope-0.9.2/docs/dev/issues.txt0000644000175000017500000001052011147312725014346 0ustar aliali============= 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.