@Override
  @Nullable
  public Spacing getSpacing(@Nullable Block child1, @NotNull Block child2) {
    final CommonCodeStyleSettings settings = myContext.getSettings();
    final PyCodeStyleSettings pySettings = myContext.getPySettings();
    if (child1 instanceof ASTBlock && child2 instanceof ASTBlock) {
      final ASTNode node1 = ((ASTBlock)child1).getNode();
      ASTNode node2 = ((ASTBlock)child2).getNode();
      final IElementType childType1 = node1.getElementType();
      final PsiElement psi1 = node1.getPsi();

      PsiElement psi2 = node2.getPsi();

      if (psi2 instanceof PyAstStatementList) {
        // Quite odd getSpacing() doesn't get called with child1=null for the first statement
        // in the statement list of a class, yet it does get called for the preceding colon and
        // the statement list itself. Hence we have to handle blank lines around methods here in
        // addition to SpacingBuilder.
        if (myNode.getElementType() == PyElementTypes.CLASS_DECLARATION) {
          final PyAstStatement[] statements = ((PyAstStatementList)psi2).getStatements();
          if (statements.length > 0 && statements[0] instanceof PyAstFunction) {
            return getBlankLinesForOption(pySettings.BLANK_LINES_BEFORE_FIRST_METHOD);
          }
        }
        if (childType1 == PyTokenTypes.COLON && (needLineBreakInStatement())) {
          return Spacing.createSpacing(0, 0, 1, true, settings.KEEP_BLANK_LINES_IN_CODE);
        }
      }

      // pycodestyle.py enforces at most 2 blank lines only between comments directly
      // at the top-level of a file, not inside if, try/except, etc.
      if (psi1 instanceof PsiComment && myNode.getPsi() instanceof PsiFile) {
        return Spacing.createSpacing(0, 0, 1, true, 2);
      }

      // skip not inline comments to handles blank lines between various declarations
      if (psi2 instanceof PsiComment && hasLineBreaksBeforeInSameParent(node2, 1)) {
        final PsiElement nonCommentAfter = PyPsiUtilsCore.getNextNonCommentSibling(psi2, true);
        if (nonCommentAfter != null) {
          psi2 = nonCommentAfter;
        }
      }
      node2 = psi2.getNode();
      final IElementType childType2 = psi2.getNode().getElementType();
      child2 = getSubBlockByNode(node2);

      if (isInsideFStringFragmentWithEqualsSign(myNode)) {
        return Spacing.getReadOnlySpacing();
      }
      if (childType1 == PyTokenTypes.FSTRING_FRAGMENT_START) {
        final LeafElement firstLeaf = TreeUtil.findFirstLeaf(node2);
        if (firstLeaf != null && firstLeaf.getElementType() == PyTokenTypes.LBRACE) {
          return Spacing.createSpacing(1, 1, 0, false, 0);
        }
      }

      if (childType2 == PyTokenTypes.FSTRING_FRAGMENT_END) {
        final ASTNode lastLeaf = TreeUtil.findLastLeaf(node1);
        if (lastLeaf != null && lastLeaf.getElementType() == PyTokenTypes.RBRACE) {
          return Spacing.createSpacing(1, 1, 0, false, 0);
        }
      }

      if ((childType1 == PyTokenTypes.EQ || childType2 == PyTokenTypes.EQ)) {
        final PyAstNamedParameter namedParameter = ObjectUtils.tryCast(myNode.getPsi(), PyAstNamedParameter.class);
        if (namedParameter != null && namedParameter.getAnnotation() != null) {
          return Spacing.createSpacing(1, 1, 0, settings.KEEP_LINE_BREAKS, settings.KEEP_BLANK_LINES_IN_CODE);
        }
      }

      if (psi1 instanceof PyAstImportStatementBase) {
        if (psi2 instanceof PyAstImportStatementBase) {
          final Boolean leftImportIsGroupStart = psi1.getCopyableUserData(PythonCodeStyleService.IMPORT_GROUP_BEGIN);
          final Boolean rightImportIsGroupStart = psi2.getCopyableUserData(PythonCodeStyleService.IMPORT_GROUP_BEGIN);
          // Cleanup user data, it's no longer needed
          psi1.putCopyableUserData(PythonCodeStyleService.IMPORT_GROUP_BEGIN, null);
          // Don't remove IMPORT_GROUP_BEGIN from the element psi2 yet, because spacing is constructed pairwise:
          // it might be needed on the next iteration.
          //psi2.putCopyableUserData(IMPORT_GROUP_BEGIN, null);
          if (rightImportIsGroupStart != null) {
            return Spacing.createSpacing(0, 0, 2, true, 1);
          }
          else if (leftImportIsGroupStart != null) {
            // It's a trick to keep spacing consistent when new import statement is inserted
            // at the beginning of an import group, i.e. if there is a blank line before the next
            // import we want to save it, but remove line *after* inserted import.
            return Spacing.createSpacing(0, 0, 1, false, 0);
          }
        }
        if (psi2 instanceof PyAstStatement && !(psi2 instanceof PyAstImportStatementBase)) {
          if (PyUtilCore.isTopLevel(psi1)) {
            // If there is any function or class after a top-level import, it should be top-level as well
            if (PyElementTypes.CLASS_OR_FUNCTION.contains(childType2)) {
              return getBlankLinesForOption(Math.max(settings.BLANK_LINES_AFTER_IMPORTS,
                                                     pySettings.BLANK_LINES_AROUND_TOP_LEVEL_CLASSES_FUNCTIONS));
            }
            return getBlankLinesForOption(settings.BLANK_LINES_AFTER_IMPORTS);
          }
          else {
            return getBlankLinesForOption(pySettings.BLANK_LINES_AFTER_LOCAL_IMPORTS);
          }
        }
      }

      if (psi2 instanceof PyAstImportStatementBase && PyUtilCore.isAssignmentToModuleLevelDunderName(psi1)) {
        // blank line between module-level dunder name and import statement
        return Spacing.createSpacing(0, 0, 2, settings.KEEP_LINE_BREAKS, settings.KEEP_BLANK_LINES_IN_DECLARATIONS);
      }

      if ((PyElementTypes.CLASS_OR_FUNCTION.contains(childType1) && STATEMENT_OR_DECLARATION.contains(childType2)) ||
          STATEMENT_OR_DECLARATION.contains(childType1) && PyElementTypes.CLASS_OR_FUNCTION.contains(childType2)) {
        if (PyUtilCore.isTopLevel(psi1)) {
          return getBlankLinesForOption(pySettings.BLANK_LINES_AROUND_TOP_LEVEL_CLASSES_FUNCTIONS);
        }
      }
    }
    return myContext.getSpacingBuilder().getSpacing(this, child1, child2);
  }
@Override
  @Nullable
  public Spacing getSpacing(@Nullable Block child1, @NotNull Block child2)