diff --git a/python/src/META-INF/python-plugin-common.xml b/python/src/META-INF/python-plugin-common.xml
index 73f6d6f394cc..6c1bea107187 100644
--- a/python/src/META-INF/python-plugin-common.xml
+++ b/python/src/META-INF/python-plugin-common.xml
@@ -389,6 +389,7 @@
+
diff --git a/python/src/com/jetbrains/python/PyParameterInfoHandler.java b/python/src/com/jetbrains/python/PyParameterInfoHandler.java
index 07b004da2c68..d1a5bd5afb5c 100644
--- a/python/src/com/jetbrains/python/PyParameterInfoHandler.java
+++ b/python/src/com/jetbrains/python/PyParameterInfoHandler.java
@@ -39,7 +39,9 @@ public class PyParameterInfoHandler implements ParameterInfoHandler types = node.getSuperClassTypes(myTypeEvalContext);
+ for (PyClassLikeType type : types) {
+ if (type == null) return;
+ final String qName = type.getClassQName();
+ if (qName != null && qName.contains(PyNames.TEST_CASE)) return;
+ if (!(type instanceof PyClassType)) return;
}
+
final PyFunction init = node.findInitOrNew(true);
if (init == null) {
registerProblem(node.getNameIdentifier(), PyBundle.message("INSP.class.has.no.init"),
diff --git a/python/src/com/jetbrains/python/inspections/PyOldStyleClassesInspection.java b/python/src/com/jetbrains/python/inspections/PyOldStyleClassesInspection.java
index c8ddf0034715..5aa05194ea4b 100644
--- a/python/src/com/jetbrains/python/inspections/PyOldStyleClassesInspection.java
+++ b/python/src/com/jetbrains/python/inspections/PyOldStyleClassesInspection.java
@@ -62,6 +62,7 @@ public class PyOldStyleClassesInspection extends PyInspection {
if (klass != null && !klass.isNewStyleClass()) {
final List types = klass.getSuperClassTypes(myTypeEvalContext);
for (PyClassLikeType type : types) {
+ if (type == null) return;
final String qName = type.getClassQName();
if (qName != null && qName.contains("PyQt")) return;
if (!(type instanceof PyClassType)) return;
diff --git a/python/src/com/jetbrains/python/psi/impl/CallArgumentsMappingImpl.java b/python/src/com/jetbrains/python/psi/impl/CallArgumentsMappingImpl.java
index 7122f4c93bc2..4f71bd786f70 100644
--- a/python/src/com/jetbrains/python/psi/impl/CallArgumentsMappingImpl.java
+++ b/python/src/com/jetbrains/python/psi/impl/CallArgumentsMappingImpl.java
@@ -79,12 +79,12 @@ public class CallArgumentsMappingImpl implements CallArgumentsMapping {
PyNamedParameter kwd_par = null; // **param
PyNamedParameter tuple_par = null; // *param
Set mapped_args = new HashSet();
- final int implicit_offset = resolved_callee.getImplicitOffset();
+ final int implicitOffset = resolved_callee.getImplicitOffset();
int positional_index = 0; // up to this index parameters are positional
// check positional arguments, fill slots
int i = 0;
for (PyParameter par : parameters) {
- if (tuple_par == null && kwd_par == null && positional_index < implicit_offset) {
+ if (tuple_par == null && kwd_par == null && positional_index < implicitOffset) {
positional_index += 1;
continue;
}
@@ -107,14 +107,14 @@ public class CallArgumentsMappingImpl implements CallArgumentsMapping {
i += 1;
}
// rule out 'self' or other implicit params
- for (i=0; i < implicit_offset && i < parameters.size(); i+=1) {
+ for (i=0; i < implicitOffset && i < parameters.size(); i+=1) {
slots.remove(parameters.get(i).getAsNamed());
positional_index += 1;
}
// now params to the left of positional_index are positional.
// map positional args to positional params.
// we assume that implicitly skipped parameters are never nested tuples. no idea when they could ever be.
- int cnt = implicit_offset;
+ int cnt = implicitOffset;
int positional_bound = arguments.length; // to the right of this pos args are verboten
ListIterator unmatched_arg_iter = unmatched_args.listIterator();
while (unmatched_arg_iter.hasNext()) {
@@ -290,10 +290,12 @@ public class CallArgumentsMappingImpl implements CallArgumentsMapping {
}
// map unmapped named params to **kwarg
if (myKwdArg != null) {
- for (PyParameter par : parameters) {
- PyNamedParameter n_par = par.getAsNamed();
- if (n_par != null && !n_par.isKeywordContainer() && !n_par.isPositionalContainer() && slots.get(n_par) == null) {
- slots.put(n_par, myKwdArg);
+ for (int j = implicitOffset; j != parameters.size(); ++j) {
+ final PyParameter par = parameters.get(j);
+ final PyNamedParameter namedParameter = par.getAsNamed();
+ if (namedParameter != null && !namedParameter.isKeywordContainer()
+ && !namedParameter.isPositionalContainer() && slots.get(namedParameter) == null) {
+ slots.put(namedParameter, myKwdArg);
}
}
}
diff --git a/python/testData/paramInfo/KwdArgInClass.py b/python/testData/paramInfo/KwdArgInClass.py
new file mode 100644
index 000000000000..8bfc48529a42
--- /dev/null
+++ b/python/testData/paramInfo/KwdArgInClass.py
@@ -0,0 +1,9 @@
+class A:
+ def foo(self, e):
+ self.kw = {}
+ self.add_comm(**self.kw)
+
+
+ def add_comm(self, **kw):
+ self.kw = []
+
diff --git a/python/testSrc/com/jetbrains/python/PyParameterInfoTest.java b/python/testSrc/com/jetbrains/python/PyParameterInfoTest.java
index d4f40cf21e94..1c931314f20c 100644
--- a/python/testSrc/com/jetbrains/python/PyParameterInfoTest.java
+++ b/python/testSrc/com/jetbrains/python/PyParameterInfoTest.java
@@ -132,6 +132,11 @@ public class PyParameterInfoTest extends LightMarkedTestCase {
feignCtrlP(marks.get("").getTextOffset()).check("a, b, c", new String[]{"b, ","c"});
}
+ public void testKwdArgInClass() {
+ Map marks = loadTest(1);
+ feignCtrlP(marks.get("").getTextOffset()).check("self, **kw", new String[]{"**kw"}, new String[]{"self, "});
+ }
+
public void testKwdArgOutOfOrder() {
Map marks = loadTest(3);