@Override
  protected void doFillCompletionVariants(@NotNull CompletionParameters parameters, @NotNull CompletionResultSet result) {
    boolean isExtendedCompletion = parameters.isExtendedCompletion();
    if (!PyCodeInsightSettings.getInstance().INCLUDE_IMPORTABLE_NAMES_IN_BASIC_COMPLETION && !isExtendedCompletion) {
      return;
    }
    PsiFile originalFile = parameters.getOriginalFile();
    PsiElement position = parameters.getPosition();
    PyReferenceExpression refExpr = as(position.getParent(), PyReferenceExpression.class);
    PyTargetExpression targetExpr = as(position.getParent(), PyTargetExpression.class);
    boolean insideUnqualifiedReference = refExpr != null && !refExpr.isQualified();
    boolean insidePattern = targetExpr != null && position.getParent().getParent() instanceof PyCapturePattern;
    boolean insideStringLiteralInExtendedCompletion = position instanceof PyStringElement && isExtendedCompletion;
    if (!(insideUnqualifiedReference || insidePattern || insideStringLiteralInExtendedCompletion)) {
      return;
    }

    // Directly inside the class body scope, it's rarely needed to have expression statements
    // TODO apply the same logic for completion of importable module and package names
    if (refExpr != null &&
        (isDirectlyInsideClassBody(refExpr) || isInsideErrorElement(refExpr))) {
      return;
    }
    // TODO Use another method to collect already visible names
    // Candidates: PyExtractMethodValidator, IntroduceValidator.isDefinedInScope
    PsiReference refUnderCaret = refExpr != null ? refExpr.getReference() :
                                 targetExpr != null ? targetExpr.getReference() :
                                 null;
    Set<String> namesInScope = refUnderCaret == null ? Collections.emptySet() : StreamEx.of(refUnderCaret.getVariants())
      .select(LookupElement.class)
      .map(LookupElement::getLookupString)
      .toSet();
    Project project = originalFile.getProject();
    TypeEvalContext typeEvalContext = TypeEvalContext.codeCompletion(project, originalFile);
    int maxVariants = Registry.intValue("ide.completion.variant.limit");
    Counters counters = new Counters();
    StubIndex stubIndex = StubIndex.getInstance();
    TimeoutUtil.run(() -> {
      GlobalSearchScope scope = createScope(originalFile);
      Set<QualifiedName> alreadySuggested = new HashSet<>();
      StubIndex.getInstance().processAllKeys(PyExportedModuleAttributeIndex.KEY, elementName -> {
        ProgressManager.checkCanceled();
        counters.scannedNames++;
        if (elementName.length() < NAME_TOO_SHORT_FOR_BASIC_COMPLETION_THRESHOLD && !isExtendedCompletion) {
          counters.tooShortNames++;
          return true;
        }
        if (!result.getPrefixMatcher().isStartMatch(elementName)) return true;
        return stubIndex.processElements(PyExportedModuleAttributeIndex.KEY, elementName, project, scope, PyElement.class, exported -> {
          ProgressManager.checkCanceled();
          String name = exported.getName();
          if (name == null || namesInScope.contains(name)) return true;
          QualifiedName fqn = getFullyQualifiedName(exported);
          if (!isApplicableInInsertionContext(exported, fqn, position, typeEvalContext)) {
            counters.notApplicableInContextNames++;
            return true;
          }
          if (alreadySuggested.add(fqn)) {
            if (isPrivateDefinition(fqn, exported, originalFile)) {
              counters.privateNames++;
              return true;
            }
            LookupElementBuilder lookupElement = LookupElementBuilder
              .createWithSmartPointer(name, exported)
              .withIcon(exported.getIcon(0))
              .withExpensiveRenderer(new LookupElementRenderer<>() {
                @Override
                public void renderElement(LookupElement element, LookupElementPresentation presentation) {
                  presentation.setItemText(element.getLookupString());
                  presentation.setIcon(exported.getIcon(0));
                  QualifiedName importPath = QualifiedNameFinder.findCanonicalImportPath(exported, originalFile);
                  if (importPath == null) return;
                  presentation.setTypeText(importPath.toString());
                }
              })
              .withInsertHandler(getInsertHandler(exported, position, typeEvalContext));
            result.addElement(PrioritizedLookupElement.withPriority(lookupElement, PythonCompletionWeigher.NOT_IMPORTED_MODULE_WEIGHT));
            counters.totalVariants++;
            if (counters.totalVariants >= maxVariants) return false;
          }
          return true;
        });
      }, scope);
    }, duration -> {
      LOG.debug(counters + " computed for prefix '" + result.getPrefixMatcher().getPrefix() + "' in " + duration + " ms");
      if (TRACING_WITH_SPUTNIK_ENABLED) {
        //noinspection UseOfSystemOutOrSystemErr
        System.out.printf("\1h('Importable names completion','%d')%n", (duration / 10) * 10);
      }
    });
  }
@Override
  protected void doFillCompletionVariants(@NotNull CompletionParameters parameters, @NotNull CompletionResultSet result)