from typing import Any


def _get_ending_line(expr: Any) -> int:
    """Get the ending line number of a Python expression

    This method gets the final line number of a
    (possibly-multiline) Python expression.

    Args:
        expr (ast.AST): a Python expression object

    Returns:
        int: the line number on which the given expression ends
    """
    final_stmt = expr
    highest_line_no = -1
    not_at_end = True
    while not_at_end:
        if hasattr(final_stmt, 'lineno'):
            highest_line_no = final_stmt.lineno

        body_is_valid = hasattr(final_stmt, 'body') and final_stmt.body
        if hasattr(final_stmt, 'orelse') and final_stmt.orelse:
            # 'orelse' should take priority over 'body'
            # (as it always has a lower ending line)
            final_stmt = final_stmt.orelse
            if isinstance(final_stmt, list):
                # .orelse may or may not be a list
                final_stmt = final_stmt[-1]
        elif body_is_valid and isinstance(final_stmt.body, list):
            final_stmt = final_stmt.body[-1]
        elif body_is_valid:
            final_stmt = final_stmt.body
        elif hasattr(final_stmt, 'exc'):
            final_stmt = final_stmt.exc
        elif hasattr(final_stmt, 'args') and final_stmt.args:
            final_stmt = final_stmt.args[-1]
        elif hasattr(final_stmt, 'elts') and final_stmt.elts:
            final_stmt = final_stmt.elts[-1]
        elif hasattr(final_stmt, 'generators') and final_stmt.generators:
            final_stmt = final_stmt.generators[-1]
        elif hasattr(final_stmt, 'iter'):
            final_stmt = final_stmt.iter
        elif hasattr(final_stmt, 'values') and final_stmt.values:
            final_stmt = final_stmt.values[-1]
        elif hasattr(final_stmt, 'value'):
            # some (but not all) value attributes have
            # child elements - we handle both kinds here
            final_stmt = final_stmt.value
        else:
            not_at_end = False

    return highest_line_no