diff --git a/python/helpers/tools/class_method_versions.xml b/python/helpers/tools/class_method_versions.xml
new file mode 100644
index 000000000000..9a403b984dd1
--- /dev/null
+++ b/python/helpers/tools/class_method_versions.xml
@@ -0,0 +1,155 @@
+
+ assertCountEqual
+ assertNotRegex
+ assertRaisesRegex
+ maxDiff
+ addTypeEqualityFunc
+ assertGreater
+ assertDictContainsSubset
+ assertLess
+ assertMultiLineEqual
+ assertIsNotNone
+ assertGreaterEqual
+ assertNotIn
+ assertRaisesRegexp
+ addCleanup
+ assertRegexpMatches
+ assertLessEqual
+ tearDownClass
+ doCleanups
+ assertRegex
+ assertSameElements
+ assertDictEqual
+ assertItemsEqual
+ assertIn
+ assertNotRegexpMatches
+ assertNotIsInstance
+ assertTupleEqual
+ assertIsNone
+ assertIs
+ assertIsInstance
+ assertWarnsRegex
+ setUpClass
+ assertListEqual
+ assertIsNot
+ assertSequenceEqual
+ longMessage
+ skipTest
+ assertWarns
+ assertSetEqual
+ assertCountEqual
+ assertNotRegex
+ assertRaisesRegex
+ maxDiff
+ addTypeEqualityFunc
+ assertGreater
+ assertDictContainsSubset
+ assertLess
+ assertMultiLineEqual
+ assertIsNotNone
+ assertGreaterEqual
+ assertNotIn
+ assertRaisesRegexp
+ addCleanup
+ assertRegexpMatches
+ assertLessEqual
+ tearDownClass
+ doCleanups
+ assertRegex
+ assertSameElements
+ assertDictEqual
+ assertItemsEqual
+ assertIn
+ assertNotRegexpMatches
+ assertNotIsInstance
+ assertTupleEqual
+ assertIsNone
+ assertIs
+ assertIsInstance
+ assertWarnsRegex
+ setUpClass
+ assertListEqual
+ assertIsNot
+ assertSequenceEqual
+ longMessage
+ skipTest
+ assertWarns
+ assertSetEqual
+ assertCountEqual
+ assertNotRegex
+ assertRaisesRegex
+ maxDiff
+ addTypeEqualityFunc
+ assertGreater
+ assertDictContainsSubset
+ assertLess
+ assertMultiLineEqual
+ assertIsNotNone
+ assertGreaterEqual
+ assertNotIn
+ assertRaisesRegexp
+ addCleanup
+ assertRegexpMatches
+ assertLessEqual
+ tearDownClass
+ doCleanups
+ assertRegex
+ assertSameElements
+ assertDictEqual
+ assertItemsEqual
+ assertIn
+ assertNotRegexpMatches
+ assertNotIsInstance
+ assertTupleEqual
+ assertIsNone
+ assertIs
+ assertIsInstance
+ assertWarnsRegex
+ setUpClass
+ assertListEqual
+ assertIsNot
+ assertSequenceEqual
+ longMessage
+ skipTest
+ assertWarns
+ assertSetEqual
+ assertCountEqual
+ assertNotRegex
+ assertWarnsRegex
+ assertRaisesRegex
+ assertRegex
+ assertSameElements
+ assertWarns
+ assertCountEqual
+ assertNotRegex
+ assertWarnsRegex
+ setUpClass
+ assertRaisesRegex
+ assertNotRegexpMatches
+ assertNotIsInstance
+ assertRegex
+ tearDownClass
+ assertItemsEqual
+ maxDiff
+ assertWarns
+ assertIsInstance
+ assertCountEqual
+ assertNotRegex
+ assertWarnsRegex
+ setUpClass
+ assertRaisesRegex
+ assertNotRegexpMatches
+ assertNotIsInstance
+ assertRegex
+ tearDownClass
+ assertItemsEqual
+ maxDiff
+ assertWarns
+ assertIsInstance
+ assertItemsEqual
+ assertNotRegexpMatches
+ assertSameElements
+ assertItemsEqual
+ assertNotRegexpMatches
+
+
diff --git a/python/src/com/jetbrains/python/inspections/PyCompatibilityInspection.java b/python/src/com/jetbrains/python/inspections/PyCompatibilityInspection.java
index 52d7d273078e..9dfa2c0d8e0c 100644
--- a/python/src/com/jetbrains/python/inspections/PyCompatibilityInspection.java
+++ b/python/src/com/jetbrains/python/inspections/PyCompatibilityInspection.java
@@ -161,14 +161,30 @@ public class PyCompatibilityInspection extends PyInspection {
StringBuilder message = new StringBuilder("Python version ");
final PyExpression callee = node.getCallee();
assert callee != null;
- for (int i = 0; i != myVersionsToProcess.size(); ++i) {
- LanguageLevel languageLevel = myVersionsToProcess.get(i);
- PsiReference reference = callee.getReference();
- if (reference != null) {
- PsiElement resolved = reference.resolve();
- ProjectFileIndex ind = ProjectRootManager.getInstance(callee.getProject()).getFileIndex();
- final String name = callee.getText();
- if (resolved != null) {
+ PsiReference reference = callee.getReference();
+ if (reference != null) {
+ PsiElement resolved = reference.resolve();
+ ProjectFileIndex ind = ProjectRootManager.getInstance(callee.getProject()).getFileIndex();
+ if (resolved instanceof PyFunction) {
+ String name = ((PyFunction)resolved).getName();
+ final PyClass containingClass = ((PyFunction)resolved).getContainingClass();
+ if (containingClass != null) {
+ if (PyNames.INIT.equals(name))
+ name = callee.getText();
+ else
+ message = new StringBuilder("Class " + containingClass.getName() + " in python version ");
+ for (int i = 0; i != myVersionsToProcess.size(); ++i) {
+ LanguageLevel languageLevel = myVersionsToProcess.get(i);
+ if (UnsupportedFeaturesUtil.CLASS_METHODS.containsKey(containingClass.getName())) {
+ final Map> map = UnsupportedFeaturesUtil.CLASS_METHODS.get(containingClass.getName());
+ final Set unsupportedMethods = map.get(languageLevel);
+ if (unsupportedMethods != null && unsupportedMethods.contains(name))
+ len = appendLanguageLevel(message, len, languageLevel);
+ }
+ }
+ }
+ for (int i = 0; i != myVersionsToProcess.size(); ++i) {
+ LanguageLevel languageLevel = myVersionsToProcess.get(i);
PsiFile file = resolved.getContainingFile();
VirtualFile virtualFile = file.getVirtualFile();
if (virtualFile != null && ind.isInLibraryClasses(virtualFile)) {
@@ -177,15 +193,9 @@ public class PyCompatibilityInspection extends PyInspection {
}
}
}
- //else {
- // if (!name.equals("print") && UnsupportedFeaturesUtil.BUILTINS.get(languageLevel).contains(name)) {
- // len = appendLanguageLevel(message, len, languageLevel);
- // }
- //}
+ commonRegisterProblem(message, " not have method " + name, len, node, null, false);
}
}
- commonRegisterProblem(message, " not have method " + callee.getText(),
- len, node, null, false);
}
@Override
diff --git a/python/src/com/jetbrains/python/validation/UnsupportedFeaturesUtil.java b/python/src/com/jetbrains/python/validation/UnsupportedFeaturesUtil.java
index 5b1e2b1182a5..c438583840bc 100644
--- a/python/src/com/jetbrains/python/validation/UnsupportedFeaturesUtil.java
+++ b/python/src/com/jetbrains/python/validation/UnsupportedFeaturesUtil.java
@@ -25,16 +25,39 @@ import java.util.*;
public class UnsupportedFeaturesUtil {
public static Map> BUILTINS = new HashMap>();
public static Map> MODULES = new HashMap>();
+ public static Map>> CLASS_METHODS = new HashMap>>();
public static Vector ALL_LANGUAGE_LEVELS;
static {
try {
fillMaps();
+ fillTestCaseMethods();
}
catch (IOException e) {
Logger log = Logger.getInstance(UnsupportedFeaturesUtil.class.getName());
log.error("Cannot find \"versions.xml\". " + e.getMessage());
}
+ fillAllLanguageLeves();
+ }
+
+ private static void fillTestCaseMethods() throws IOException {
+ final Logger log = Logger.getInstance(UnsupportedFeaturesUtil.class.getName());
+ final FileReader reader = new FileReader(PythonHelpersLocator.getHelperPath("/tools/class_method_versions.xml"));
+ try {
+ final XMLReader xr = XMLReaderFactory.createXMLReader();
+ final ClassMethodsParser parser = new ClassMethodsParser();
+ xr.setContentHandler(parser);
+ xr.parse(new InputSource(reader));
+ }
+ catch (SAXException e) {
+ log.error("Improperly formed \"class_method_versions.xml\". " + e.getMessage());
+ }
+ finally {
+ reader.close();
+ }
+ }
+
+ private static void fillAllLanguageLeves() {
ALL_LANGUAGE_LEVELS = new Vector();
ALL_LANGUAGE_LEVELS.add(LanguageLevel.PYTHON24.toString());
ALL_LANGUAGE_LEVELS.add(LanguageLevel.PYTHON25.toString());
@@ -160,5 +183,51 @@ public class UnsupportedFeaturesUtil {
myContent.write(ch, start, length);
}
}
+
+ static class ClassMethodsParser extends DefaultHandler {
+ private CharArrayWriter myContent = new CharArrayWriter();
+ private String myClassName = "";
+ private LanguageLevel myCurrentLevel;
+
+ public void startElement(String namespaceURI,
+ String localName,
+ String qName,
+ Attributes attr) throws SAXException {
+ myContent.reset();
+ if (localName.equals("class_name")) {
+ myClassName = attr.getValue("name");
+ if (!CLASS_METHODS.containsKey(myClassName)) {
+ CLASS_METHODS.put(myClassName, new HashMap>());
+
+ }
+ }
+ if (localName.equals("python")) {
+ myCurrentLevel = LanguageLevel.fromPythonVersion(attr.getValue("version"));
+ if (myClassName != null) {
+ final Map> map = CLASS_METHODS.get(myClassName);
+ if (map != null)
+ map.put(myCurrentLevel, new HashSet());
+ }
+ }
+ }
+
+ public void endElement(String namespaceURI,
+ String localName,
+ String qName) throws SAXException {
+ if (localName.equals("func")) {
+ Map> levelSetMap = CLASS_METHODS.get(myClassName);
+ if (levelSetMap != null) {
+ final Set set = levelSetMap.get(myCurrentLevel);
+ if (set != null)
+ set.add(myContent.toString());
+ }
+ }
+ }
+
+ public void characters(char[] ch, int start, int length)
+ throws SAXException {
+ myContent.write(ch, start, length);
+ }
+ }
}