From 21d0b485c89f6aefb617dec09e31a36e578fe1f1 Mon Sep 17 00:00:00 2001 From: Dmitry Jemerov Date: Fri, 21 Jan 2011 16:51:01 +0100 Subject: [PATCH 1/8] offer to rename containing file when renaming Python class (PY-2372) --- python/src/META-INF/python-plugin-common.xml | 2 + .../codeInsight/PyCodeInsightSettings.java | 4 +- .../PyContainingFileRenamerFactory.java | 95 +++++++++++++++++++ 3 files changed, 100 insertions(+), 1 deletion(-) create mode 100644 python/src/com/jetbrains/python/refactoring/rename/PyContainingFileRenamerFactory.java diff --git a/python/src/META-INF/python-plugin-common.xml b/python/src/META-INF/python-plugin-common.xml index fcdf8892823d..55ec53660a16 100644 --- a/python/src/META-INF/python-plugin-common.xml +++ b/python/src/META-INF/python-plugin-common.xml @@ -217,6 +217,8 @@ + + diff --git a/python/src/com/jetbrains/python/codeInsight/PyCodeInsightSettings.java b/python/src/com/jetbrains/python/codeInsight/PyCodeInsightSettings.java index 6f2b23ec5021..bf884fab7bf8 100644 --- a/python/src/com/jetbrains/python/codeInsight/PyCodeInsightSettings.java +++ b/python/src/com/jetbrains/python/codeInsight/PyCodeInsightSettings.java @@ -33,7 +33,9 @@ public class PyCodeInsightSettings implements PersistentStateComponent usages) { + return new PyContainingFileRenamer((PyClass) element, newName); + } + + public static class PyContainingFileRenamer extends AutomaticRenamer { + private final PyClass myClass; + + public PyContainingFileRenamer(PyClass element, String newName) { + myClass = element; + myElements.add(element.getContainingFile()); + suggestAllNames(element.getName(), newName); + } + + @Override + public String getDialogTitle() { + return "Rename containing file"; + } + + @Override + public String getDialogDescription() { + return "Rename containing file with the following name to: "; + } + + @Override + public String entityName() { + return "Containing File"; + } + + @Override + protected String nameToCanonicalName(@NonNls String name, PsiNamedElement element) { + return FileUtil.getNameWithoutExtension(name); + } + + @Override + protected String canonicalNameToName(@NonNls String canonicalName, PsiNamedElement element) { + return canonicalName + "." + FileUtil.getExtension(myClass.getContainingFile().getName()); + } + + @Override + public boolean isSelectedByDefault() { + return true; + } + } +} From 59d1b07ad7a9d40350165cd03cc856ff02d1a9d4 Mon Sep 17 00:00:00 2001 From: Dmitry Jemerov Date: Fri, 21 Jan 2011 17:03:23 +0100 Subject: [PATCH 2/8] offer to rename inheritors when renaming Python class (PY-2373) --- python/src/META-INF/python-plugin-common.xml | 1 + .../codeInsight/PyCodeInsightSettings.java | 1 + .../PyContainingFileRenamerFactory.java | 2 +- .../rename/PyInheritorRenameFactory.java | 63 +++++++++++++++++++ 4 files changed, 66 insertions(+), 1 deletion(-) create mode 100644 python/src/com/jetbrains/python/refactoring/rename/PyInheritorRenameFactory.java diff --git a/python/src/META-INF/python-plugin-common.xml b/python/src/META-INF/python-plugin-common.xml index 55ec53660a16..7eebdd6aed89 100644 --- a/python/src/META-INF/python-plugin-common.xml +++ b/python/src/META-INF/python-plugin-common.xml @@ -218,6 +218,7 @@ + diff --git a/python/src/com/jetbrains/python/codeInsight/PyCodeInsightSettings.java b/python/src/com/jetbrains/python/codeInsight/PyCodeInsightSettings.java index bf884fab7bf8..072f15124bb8 100644 --- a/python/src/com/jetbrains/python/codeInsight/PyCodeInsightSettings.java +++ b/python/src/com/jetbrains/python/codeInsight/PyCodeInsightSettings.java @@ -36,6 +36,7 @@ public class PyCodeInsightSettings implements PersistentStateComponent usages) { + return new PyInheritorRenamer((PyClass) element, newName); + } + + public static class PyInheritorRenamer extends AutomaticRenamer { + public PyInheritorRenamer(PyClass element, String newName) { + myElements.addAll(PyClassInheritorsSearch.search(element, false).findAll()); + suggestAllNames(element.getName(), newName); + } + + @Override + public String getDialogTitle() { + return "Rename Inheritors"; + } + + @Override + public String getDialogDescription() { + return "Rename inheritor classes with the following names to:"; + } + + @Override + public String entityName() { + return "Inheritor Class"; + } + } +} From 3b8315f5e2302abe99665c5e53c23f05e67198d9 Mon Sep 17 00:00:00 2001 From: Dmitry Jemerov Date: Fri, 21 Jan 2011 17:33:01 +0100 Subject: [PATCH 3/8] option to rename parameters in hierarchy when renaming a method parameter (PY-2374) --- python/src/META-INF/python-plugin-common.xml | 1 + .../codeInsight/PyCodeInsightSettings.java | 1 + .../refactoring/RefactoringProvider.java | 17 ++-- .../rename/PyParametersRenameFactory.java | 91 +++++++++++++++++++ 4 files changed, 104 insertions(+), 6 deletions(-) create mode 100644 python/src/com/jetbrains/python/refactoring/rename/PyParametersRenameFactory.java diff --git a/python/src/META-INF/python-plugin-common.xml b/python/src/META-INF/python-plugin-common.xml index 7eebdd6aed89..73a52fe9d45e 100644 --- a/python/src/META-INF/python-plugin-common.xml +++ b/python/src/META-INF/python-plugin-common.xml @@ -219,6 +219,7 @@ + diff --git a/python/src/com/jetbrains/python/codeInsight/PyCodeInsightSettings.java b/python/src/com/jetbrains/python/codeInsight/PyCodeInsightSettings.java index 072f15124bb8..f13ae4b289f2 100644 --- a/python/src/com/jetbrains/python/codeInsight/PyCodeInsightSettings.java +++ b/python/src/com/jetbrains/python/codeInsight/PyCodeInsightSettings.java @@ -37,6 +37,7 @@ public class PyCodeInsightSettings implements PersistentStateComponent usages) { + return new PyParametersRenamer((PyParameter)element, newName); + } + + public static class PyParametersRenamer extends AutomaticRenamer { + + public PyParametersRenamer(final PyParameter element, String newName) { + PyFunction function = PsiTreeUtil.getParentOfType(element, PyFunction.class); + PyOverridingMethodsSearch.search(function, true).forEach(new Processor() { + @Override + public boolean process(PyFunction pyFunction) { + PyParameter[] parameters = pyFunction.getParameterList().getParameters(); + for (PyParameter parameter : parameters) { + PyNamedParameter named = parameter.getAsNamed(); + if (named != null && Comparing.equal(named.getName(), element.getName())) { + myElements.add(named); + } + } + return true; + } + }); + suggestAllNames(element.getName(), newName); + } + + @Override + public String getDialogTitle() { + return "Rename parameters"; + } + + @Override + public String getDialogDescription() { + return "Rename parameter in hierarchy to:"; + } + + @Override + public String entityName() { + return "Parameter"; + } + + @Override + public boolean isSelectedByDefault() { + return true; + } + } +} From fd23c777bcd21cf78a487549f8f9c7b41b06adc6 Mon Sep 17 00:00:00 2001 From: Ekaterina Tuzova Date: Mon, 24 Jan 2011 17:49:18 +0300 Subject: [PATCH 4/8] fixed failed test. --- python/testData/inspections/ReplaceNotEqOperator.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/testData/inspections/ReplaceNotEqOperator.py b/python/testData/inspections/ReplaceNotEqOperator.py index 59b313eb8773..3dc25820ba83 100644 --- a/python/testData/inspections/ReplaceNotEqOperator.py +++ b/python/testData/inspections/ReplaceNotEqOperator.py @@ -1 +1 @@ -print(a <> b) \ No newline at end of file +print(a <> b) \ No newline at end of file From 748b32b71887477139c3a38c8916a716afe3cc59 Mon Sep 17 00:00:00 2001 From: Ekaterina Tuzova Date: Mon, 24 Jan 2011 17:55:24 +0300 Subject: [PATCH 5/8] fixed failed django test. --- python/helpers/pycharm/django_test_manage.py | 40 +++++++++++++++++++- 1 file changed, 39 insertions(+), 1 deletion(-) diff --git a/python/helpers/pycharm/django_test_manage.py b/python/helpers/pycharm/django_test_manage.py index d15732efcbef..3a1bc8ad047c 100644 --- a/python/helpers/pycharm/django_test_manage.py +++ b/python/helpers/pycharm/django_test_manage.py @@ -3,6 +3,44 @@ from pycharm.fix_getpass import fixGetpass from pycharm import django_test_settings from django.core.management import execute_manager + +def setup_environ(settings_mod, original_settings_path=None): + if '__init__.py' in settings_mod.__file__: + p = os.path.dirname(settings_mod.__file__) + else: + p = settings_mod.__file__ + project_directory, settings_filename = os.path.split(p) + if project_directory == os.curdir or not project_directory: + project_directory = os.getcwd() + project_name = os.path.basename(project_directory) + + # Strip filename suffix to get the module name. + settings_name = os.path.splitext(settings_filename)[0] + + # Strip $py for Jython compiled files (like settings$py.class) + if settings_name.endswith("$py"): + settings_name = settings_name[:-3] + + # Set DJANGO_SETTINGS_MODULE appropriately. + if original_settings_path: + os.environ['DJANGO_SETTINGS_MODULE'] = original_settings_path + else: + os.environ['DJANGO_SETTINGS_MODULE'] = '%s.%s' % (project_name, settings_name) + + # Import the project module. We add the parent directory to PYTHONPATH to + # avoid some of the path errors new users can have. + sys.path.append(os.path.join(project_directory, os.pardir)) + project_module = import_module(project_name) + sys.path.pop() + + return project_directory + +def execute_manager(settings_mod): + setup_environ(settings_mod) + utility = ManagementUtility(argv) + utility.execute() + + if __name__ == "__main__": fixGetpass() - execute_manager(django_settings) + execute_manager(django_test_settings) From 2f007d256e27df07871807185608e8fa4641b0f2 Mon Sep 17 00:00:00 2001 From: Ekaterina Tuzova Date: Mon, 24 Jan 2011 19:01:37 +0300 Subject: [PATCH 6/8] fixed PY-2334 Buildout custom manage.py for unit tests. (All custom stuff should be defined outside main block) --- python/helpers/pycharm/django_test_manage.py | 46 +++----------------- 1 file changed, 7 insertions(+), 39 deletions(-) diff --git a/python/helpers/pycharm/django_test_manage.py b/python/helpers/pycharm/django_test_manage.py index 3a1bc8ad047c..c1c2dbbee629 100644 --- a/python/helpers/pycharm/django_test_manage.py +++ b/python/helpers/pycharm/django_test_manage.py @@ -1,46 +1,14 @@ #!/usr/bin/env python from pycharm.fix_getpass import fixGetpass -from pycharm import django_test_settings +from pycharm import django_settings from django.core.management import execute_manager - -def setup_environ(settings_mod, original_settings_path=None): - if '__init__.py' in settings_mod.__file__: - p = os.path.dirname(settings_mod.__file__) - else: - p = settings_mod.__file__ - project_directory, settings_filename = os.path.split(p) - if project_directory == os.curdir or not project_directory: - project_directory = os.getcwd() - project_name = os.path.basename(project_directory) - - # Strip filename suffix to get the module name. - settings_name = os.path.splitext(settings_filename)[0] - - # Strip $py for Jython compiled files (like settings$py.class) - if settings_name.endswith("$py"): - settings_name = settings_name[:-3] - - # Set DJANGO_SETTINGS_MODULE appropriately. - if original_settings_path: - os.environ['DJANGO_SETTINGS_MODULE'] = original_settings_path - else: - os.environ['DJANGO_SETTINGS_MODULE'] = '%s.%s' % (project_name, settings_name) - - # Import the project module. We add the parent directory to PYTHONPATH to - # avoid some of the path errors new users can have. - sys.path.append(os.path.join(project_directory, os.pardir)) - project_module = import_module(project_name) - sys.path.pop() - - return project_directory - -def execute_manager(settings_mod): - setup_environ(settings_mod) - utility = ManagementUtility(argv) - utility.execute() - +import os +manage_file = os.getenv('PYCHARM_DJANGO_MANAGE_MODULE') +if not manage_file: + manage_file = 'manage' if __name__ == "__main__": + __import__(manage_file) fixGetpass() - execute_manager(django_test_settings) + execute_manager(django_settings) From c76623946b176f2eedab57c8190e8f486e8512b5 Mon Sep 17 00:00:00 2001 From: Ekaterina Tuzova Date: Mon, 24 Jan 2011 19:02:20 +0300 Subject: [PATCH 7/8] Prepared fix for PY-1634 Provide link to diff for string assertEquals failures in Python unit tests --- python/helpers/pycharm/tcmessages.py | 6 +++++- python/helpers/pycharm/tcunittest.py | 29 +++++++++++++++++++++++++++- 2 files changed, 33 insertions(+), 2 deletions(-) diff --git a/python/helpers/pycharm/tcmessages.py b/python/helpers/pycharm/tcmessages.py index 3d8d5a7d8fbf..f54e235252f0 100644 --- a/python/helpers/pycharm/tcmessages.py +++ b/python/helpers/pycharm/tcmessages.py @@ -36,7 +36,11 @@ class TeamcityServiceMessages: def testIgnored(self, testName, message=''): self.message('testIgnored', name=testName, message=message) - def testFailed(self, testName, message='', details=''): + def testFailed(self, testName, message='', details='', expected='', actual=''): + if expected and actual: + self.message('testFailed', type='comparisonFailure', name=testName, message=message, + details=details, expected=expected, actual=actual) + else: self.message('testFailed', name=testName, message=message, details=details) def testError(self, testName, message='', details=''): diff --git a/python/helpers/pycharm/tcunittest.py b/python/helpers/pycharm/tcunittest.py index f6e35ee9ea55..055401764e38 100644 --- a/python/helpers/pycharm/tcunittest.py +++ b/python/helpers/pycharm/tcunittest.py @@ -17,6 +17,26 @@ class TeamcityTestResult(TestResult): self.messages = TeamcityServiceMessages(self.output, prepend_linebreak=True) self.current_suite = None + def find_first(self, val): + quot = val[0] + count = 1 + quote_ind = val[count:].find(quot) + while val[count+quote_ind-1] == "\\": + count = count + quote_ind + 1 + quote_ind = val[count:].find(quot) + + return val[0:quote_ind+count+1] + + def find_second(self, val): + quot = val[-1] + count = 1 + quote_ind = val[:len(val)-count-1].rfind(quot) + while val[quote_ind-1] == "\\": + quote_ind = val[:quote_ind-1].rfind(quot) + + return val[quote_ind:] + + def formatErr(self, err): exctype, value, tb = err return ''.join(traceback.format_exception(exctype, value, tb)) @@ -46,10 +66,17 @@ class TeamcityTestResult(TestResult): def addFailure(self, test, err): TestResult.addFailure(self, test, err) + error_value = err[1][0] + + if error_value.startswith("'") or error_value.startswith('"'): + first = self.find_first(err[1][0]) + second = self.find_second(err[1][0]) + else: + first = second = "" err = self.formatErr(err) self.messages.testFailed(self.getTestName(test), - message='Failure', details=err) + message='Failure', details=err, expected=first, actual=second) def addSkip(self, test, reason): self.messages.testIgnored(self.getTestName(test), message=reason) From 8519231a189b956940dce4ce9be78d15cd7ffb68 Mon Sep 17 00:00:00 2001 From: Dmitry Jemerov Date: Mon, 24 Jan 2011 18:13:40 +0100 Subject: [PATCH 8/8] branch number = 104 --- python/build/pycharm_build.gant | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/python/build/pycharm_build.gant b/python/build/pycharm_build.gant index 3c668288cd34..e61775a07613 100644 --- a/python/build/pycharm_build.gant +++ b/python/build/pycharm_build.gant @@ -1,11 +1,11 @@ +import org.jetbrains.jps.Jps import org.jetbrains.jps.Module import static org.jetbrains.jps.idea.IdeaProjectLoader.guessHome -import org.jetbrains.jps.Jps includeTargets << new File("${guessHome(this as Script)}/community/build/scripts/utils.gant") includeTool << Jps -requireProperty("buildNumber", requireProperty("build.number", "102.SNAPSHOT")) +requireProperty("buildNumber", requireProperty("build.number", "104.SNAPSHOT")) setProperty("ch", "$home/community") setProperty("dryRun", false)