added possibility to specify missing methods for (class, version) pair. Added updater for a new versions.

fixed PY-10497 Teach code compatibility inspection about differences in unittest implementations
This commit is contained in:
Ekaterina Tuzova
2013-08-07 19:53:22 +04:00
parent 341cae1324
commit b435ed1f4c
3 changed files with 249 additions and 15 deletions
@@ -0,0 +1,155 @@
<?xml version="1.0" ?><root><class_name name="TestCase">
<python version="2.4"><func>assertCountEqual</func>
<func>assertNotRegex</func>
<func>assertRaisesRegex</func>
<func>maxDiff</func>
<func>addTypeEqualityFunc</func>
<func>assertGreater</func>
<func>assertDictContainsSubset</func>
<func>assertLess</func>
<func>assertMultiLineEqual</func>
<func>assertIsNotNone</func>
<func>assertGreaterEqual</func>
<func>assertNotIn</func>
<func>assertRaisesRegexp</func>
<func>addCleanup</func>
<func>assertRegexpMatches</func>
<func>assertLessEqual</func>
<func>tearDownClass</func>
<func>doCleanups</func>
<func>assertRegex</func>
<func>assertSameElements</func>
<func>assertDictEqual</func>
<func>assertItemsEqual</func>
<func>assertIn</func>
<func>assertNotRegexpMatches</func>
<func>assertNotIsInstance</func>
<func>assertTupleEqual</func>
<func>assertIsNone</func>
<func>assertIs</func>
<func>assertIsInstance</func>
<func>assertWarnsRegex</func>
<func>setUpClass</func>
<func>assertListEqual</func>
<func>assertIsNot</func>
<func>assertSequenceEqual</func>
<func>longMessage</func>
<func>skipTest</func>
<func>assertWarns</func>
<func>assertSetEqual</func></python>
<python version="2.5"><func>assertCountEqual</func>
<func>assertNotRegex</func>
<func>assertRaisesRegex</func>
<func>maxDiff</func>
<func>addTypeEqualityFunc</func>
<func>assertGreater</func>
<func>assertDictContainsSubset</func>
<func>assertLess</func>
<func>assertMultiLineEqual</func>
<func>assertIsNotNone</func>
<func>assertGreaterEqual</func>
<func>assertNotIn</func>
<func>assertRaisesRegexp</func>
<func>addCleanup</func>
<func>assertRegexpMatches</func>
<func>assertLessEqual</func>
<func>tearDownClass</func>
<func>doCleanups</func>
<func>assertRegex</func>
<func>assertSameElements</func>
<func>assertDictEqual</func>
<func>assertItemsEqual</func>
<func>assertIn</func>
<func>assertNotRegexpMatches</func>
<func>assertNotIsInstance</func>
<func>assertTupleEqual</func>
<func>assertIsNone</func>
<func>assertIs</func>
<func>assertIsInstance</func>
<func>assertWarnsRegex</func>
<func>setUpClass</func>
<func>assertListEqual</func>
<func>assertIsNot</func>
<func>assertSequenceEqual</func>
<func>longMessage</func>
<func>skipTest</func>
<func>assertWarns</func>
<func>assertSetEqual</func></python>
<python version="2.6"><func>assertCountEqual</func>
<func>assertNotRegex</func>
<func>assertRaisesRegex</func>
<func>maxDiff</func>
<func>addTypeEqualityFunc</func>
<func>assertGreater</func>
<func>assertDictContainsSubset</func>
<func>assertLess</func>
<func>assertMultiLineEqual</func>
<func>assertIsNotNone</func>
<func>assertGreaterEqual</func>
<func>assertNotIn</func>
<func>assertRaisesRegexp</func>
<func>addCleanup</func>
<func>assertRegexpMatches</func>
<func>assertLessEqual</func>
<func>tearDownClass</func>
<func>doCleanups</func>
<func>assertRegex</func>
<func>assertSameElements</func>
<func>assertDictEqual</func>
<func>assertItemsEqual</func>
<func>assertIn</func>
<func>assertNotRegexpMatches</func>
<func>assertNotIsInstance</func>
<func>assertTupleEqual</func>
<func>assertIsNone</func>
<func>assertIs</func>
<func>assertIsInstance</func>
<func>assertWarnsRegex</func>
<func>setUpClass</func>
<func>assertListEqual</func>
<func>assertIsNot</func>
<func>assertSequenceEqual</func>
<func>longMessage</func>
<func>skipTest</func>
<func>assertWarns</func>
<func>assertSetEqual</func></python>
<python version="2.7"><func>assertCountEqual</func>
<func>assertNotRegex</func>
<func>assertWarnsRegex</func>
<func>assertRaisesRegex</func>
<func>assertRegex</func>
<func>assertSameElements</func>
<func>assertWarns</func></python>
<python version="3.0"><func>assertCountEqual</func>
<func>assertNotRegex</func>
<func>assertWarnsRegex</func>
<func>setUpClass</func>
<func>assertRaisesRegex</func>
<func>assertNotRegexpMatches</func>
<func>assertNotIsInstance</func>
<func>assertRegex</func>
<func>tearDownClass</func>
<func>assertItemsEqual</func>
<func>maxDiff</func>
<func>assertWarns</func>
<func>assertIsInstance</func></python>
<python version="3.1"><func>assertCountEqual</func>
<func>assertNotRegex</func>
<func>assertWarnsRegex</func>
<func>setUpClass</func>
<func>assertRaisesRegex</func>
<func>assertNotRegexpMatches</func>
<func>assertNotIsInstance</func>
<func>assertRegex</func>
<func>tearDownClass</func>
<func>assertItemsEqual</func>
<func>maxDiff</func>
<func>assertWarns</func>
<func>assertIsInstance</func></python>
<python version="3.2"><func>assertItemsEqual</func>
<func>assertNotRegexpMatches</func></python>
<python version="3.3"><func>assertSameElements</func>
<func>assertItemsEqual</func>
<func>assertNotRegexpMatches</func></python>
</class_name>
</root>
@@ -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<LanguageLevel, Set<String>> map = UnsupportedFeaturesUtil.CLASS_METHODS.get(containingClass.getName());
final Set<String> 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
@@ -25,16 +25,39 @@ import java.util.*;
public class UnsupportedFeaturesUtil {
public static Map<LanguageLevel, Set<String>> BUILTINS = new HashMap<LanguageLevel, Set<String>>();
public static Map<LanguageLevel, Set<String>> MODULES = new HashMap<LanguageLevel, Set<String>>();
public static Map<String, Map<LanguageLevel, Set<String>>> CLASS_METHODS = new HashMap<String, Map<LanguageLevel, Set<String>>>();
public static Vector<String> 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<String>();
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<LanguageLevel, Set<String>>());
}
}
if (localName.equals("python")) {
myCurrentLevel = LanguageLevel.fromPythonVersion(attr.getValue("version"));
if (myClassName != null) {
final Map<LanguageLevel, Set<String>> map = CLASS_METHODS.get(myClassName);
if (map != null)
map.put(myCurrentLevel, new HashSet<String>());
}
}
}
public void endElement(String namespaceURI,
String localName,
String qName) throws SAXException {
if (localName.equals("func")) {
Map<LanguageLevel, Set<String>> levelSetMap = CLASS_METHODS.get(myClassName);
if (levelSetMap != null) {
final Set<String> 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);
}
}
}