Couple<List<String>> (@NotNull ParametersInfo origInfo, @NotNull ParametersInfo superInfo, boolean addSelfToCall) { final List<String> newFunctionParams = new ArrayList<>(); final List<String> superCallArgs = new ArrayList<>(); final PyParameter selfParameter = origInfo.getSelfParameter(); if (selfParameter != null && StringUtil.isNotEmpty(selfParameter.getName())) { newFunctionParams.add(selfParameter.getText()); } else { newFunctionParams.add(PyNames.CANONICAL_SELF); } if (addSelfToCall) { superCallArgs.add(getSelfParameterName(origInfo)); } // Required parameters (not-keyword) for (PyParameter param : origInfo.getRequiredParameters()) { newFunctionParams.add(param.getText()); } for (PyParameter param : superInfo.getRequiredParameters()) { // Special case as if base class has constructor __init__((a, b), c) and // subclass has constructor __init__(a, (b, c)) final PyTupleParameter tupleParam = param.getAsTuple(); if (tupleParam != null) { final List<String> uniqueNames = collectParameterNames(tupleParam); final boolean hasDuplicates = uniqueNames.removeAll(origInfo.getAllParameterNames()); if (hasDuplicates) { newFunctionParams.addAll(uniqueNames); } else { newFunctionParams.add(param.getText()); } // Retain original structure of tuple parameter. // Note that tuple parameters cannot have annotations or nested default values, so it's syntactically safe superCallArgs.add(param.getText()); } else { if (!origInfo.getAllParameterNames().contains(param.getName())) { newFunctionParams.add(param.getText()); } superCallArgs.add(param.getName()); } } // Optional parameters (not-keyword) for (PyParameter param : origInfo.getOptionalParameters()) { newFunctionParams.add(param.getText()); } // Pass parameters with default values to super class constructor, only if both functions contain them for (PyParameter param : superInfo.getOptionalParameters()) { final PyTupleParameter tupleParam = param.getAsTuple(); if (tupleParam != null) { if (origInfo.getAllParameterNames().containsAll(collectParameterNames(tupleParam))) { final String paramText = tupleParam.getText(); final PsiElement equalSign = PyPsiUtils.getFirstChildOfType(param, PyTokenTypes.EQ); if (equalSign != null) { superCallArgs.add(paramText.substring(0, equalSign.getStartOffsetInParent()).trim()); } } } else { if (origInfo.getAllParameterNames().contains(param.getName())) { superCallArgs.add(param.getName()); } } } // Positional vararg PyParameter starredParam = null; if (origInfo.getPositionalContainerParameter() != null) { starredParam = origInfo.getPositionalContainerParameter(); } else if (superInfo.getPositionalContainerParameter() != null) { starredParam = superInfo.getPositionalContainerParameter(); } else if (origInfo.getSingleStarParameter() != null) { starredParam = origInfo.getSingleStarParameter(); } else if (superInfo.getSingleStarParameter() != null) { starredParam = superInfo.getSingleStarParameter(); } if (starredParam != null) { newFunctionParams.add(starredParam.getText()); if (superInfo.getPositionalContainerParameter() != null) { superCallArgs.add("*" + starredParam.getName()); } } // Required keyword-only parameters boolean newSignatureContainsKeywordParams = false; for (PyParameter param : origInfo.getRequiredKeywordOnlyParameters()) { newFunctionParams.add(param.getText()); newSignatureContainsKeywordParams = true; } for (PyParameter param : superInfo.getRequiredKeywordOnlyParameters()) { if (!origInfo.getAllParameterNames().contains(param.getName())) { newFunctionParams.add(param.getText()); newSignatureContainsKeywordParams = true; } superCallArgs.add(param.getName() + "=" + param.getName()); } // Optional keyword-only parameters for (PyParameter param : origInfo.getOptionalKeywordOnlyParameters()) { newFunctionParams.add(param.getText()); newSignatureContainsKeywordParams = true; } // If '*' param is followed by nothing in result signature, remove it altogether if (starredParam instanceof PySingleStarParameter && !newSignatureContainsKeywordParams) { newFunctionParams.remove(newFunctionParams.size() - 1); } for (PyParameter param : superInfo.getOptionalKeywordOnlyParameters()) { if (origInfo.getAllParameterNames().contains(param.getName())) { superCallArgs.add(param.getName() + "=" + param.getName()); } } // Keyword vararg PyParameter doubleStarredParam = null; if (origInfo.getKeywordContainerParameter() != null) { doubleStarredParam = origInfo.getKeywordContainerParameter(); } else if (superInfo.getKeywordContainerParameter() != null) { doubleStarredParam = superInfo.getKeywordContainerParameter(); } if (doubleStarredParam != null) { newFunctionParams.add(doubleStarredParam.getText()); if (superInfo.getKeywordContainerParameter() != null) { superCallArgs.add("**" + doubleStarredParam.getName()); } } return Couple.of(newFunctionParams, superCallArgs); }