Make `else` its own scope and standardize behaviour of `block_range`
diff --git a/ChangeLog b/ChangeLog
index ec13d64..c9af822 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -7,6 +7,11 @@
 ============================
 Release date: TBA
 
+* Changed `block_range` to consider `else` its own block, allowing `pylint` to apply
+  disables to just the block.
+
+  References pylint-dev/pylint#872
+
 
 What's New in astroid 4.1.2?
 ============================
diff --git a/astroid/nodes/_base_nodes.py b/astroid/nodes/_base_nodes.py
index df452cb..a3cf912 100644
--- a/astroid/nodes/_base_nodes.py
+++ b/astroid/nodes/_base_nodes.py
@@ -237,22 +237,51 @@
 class MultiLineWithElseBlockNode(MultiLineBlockNode):
     """Base node for multi-line blocks that can have else statements."""
 
+    body: list[NodeNG]
+    """The contents of the block."""
+
+    orelse: list[NodeNG]
+    """The contents of the ``else`` block."""
+
     @cached_property
     def blockstart_tolineno(self):
         return self.lineno
 
+    def block_range(self, lineno: int) -> tuple[int, int]:
+        """Get a range from the given line number to where this node ends.
+
+        :param lineno: The line number to start the range at.
+
+        :returns: The range of line numbers that this node belongs to,
+            starting at the given line number.
+        """
+        if lineno < self.fromlineno:
+            return lineno, self.tolineno
+        if lineno == self.body[0].fromlineno:
+            return lineno, lineno
+        if lineno <= self.body[-1].tolineno:
+            return lineno, self.body[-1].tolineno
+        return self._elsed_block_range(lineno, self.orelse, self.body[0].fromlineno - 1)
+
     def _elsed_block_range(
         self, lineno: int, orelse: list[nodes.NodeNG], last: int | None = None
     ) -> tuple[int, int]:
         """Handle block line numbers range for try/finally, for, if and while
         statements.
         """
-        if lineno == self.fromlineno:
+        # If at the end of the node, return same line
+        if lineno == self.tolineno:
             return lineno, lineno
         if orelse:
-            if lineno >= orelse[0].fromlineno:
+            # If the lineno is beyond the body of the node we check the orelse
+            if lineno >= self.body[-1].tolineno + 1:
+                # If the orelse has a scope of its own we determine the block range there
+                if isinstance(orelse[0], MultiLineWithElseBlockNode):
+                    return orelse[0]._elsed_block_range(lineno, orelse[0].orelse)
+                # Return last line of orelse
                 return lineno, orelse[-1].tolineno
-            return lineno, orelse[0].fromlineno - 1
+            # If the lineno is within the body we take the last line of the body
+            return lineno, self.body[-1].tolineno
         return lineno, last or self.tolineno
 
 
diff --git a/astroid/nodes/node_classes.py b/astroid/nodes/node_classes.py
index af2131c..144f2f8 100644
--- a/astroid/nodes/node_classes.py
+++ b/astroid/nodes/node_classes.py
@@ -3061,20 +3061,6 @@
         """
         return self.test.tolineno
 
-    def block_range(self, lineno: int) -> tuple[int, int]:
-        """Get a range from the given line number to where this node ends.
-
-        :param lineno: The line number to start the range at.
-
-        :returns: The range of line numbers that this node belongs to,
-            starting at the given line number.
-        """
-        if lineno == self.body[0].fromlineno:
-            return lineno, lineno
-        if lineno <= self.body[-1].tolineno:
-            return lineno, self.body[-1].tolineno
-        return self._elsed_block_range(lineno, self.orelse, self.body[0].fromlineno - 1)
-
     def get_children(self):
         yield self.test
 
@@ -3915,27 +3901,20 @@
 
     def block_range(self, lineno: int) -> tuple[int, int]:
         """Get a range from a given line number to where this node ends."""
-        if lineno == self.fromlineno:
-            return lineno, lineno
-        if self.body and self.body[0].fromlineno <= lineno <= self.body[-1].tolineno:
-            # Inside try body - return from lineno till end of try body
-            return lineno, self.body[-1].tolineno
         for exhandler in self.handlers:
             if exhandler.type and lineno == exhandler.type.fromlineno:
-                return lineno, lineno
+                return lineno, exhandler.tolineno
             if exhandler.body[0].fromlineno <= lineno <= exhandler.body[-1].tolineno:
                 return lineno, exhandler.body[-1].tolineno
-        if self.orelse:
-            if self.orelse[0].fromlineno - 1 == lineno:
-                return lineno, lineno
-            if self.orelse[0].fromlineno <= lineno <= self.orelse[-1].tolineno:
-                return lineno, self.orelse[-1].tolineno
         if self.finalbody:
             if self.finalbody[0].fromlineno - 1 == lineno:
-                return lineno, lineno
+                return lineno, self.finalbody[0].tolineno
             if self.finalbody[0].fromlineno <= lineno <= self.finalbody[-1].tolineno:
                 return lineno, self.finalbody[-1].tolineno
-        return lineno, self.tolineno
+
+        # If not within any of the ExceptHandlers or `finally` body, fall back to regular
+        # handling of block_range for nodes with a potential `else` statement.
+        return super().block_range(lineno)
 
     def get_children(self):
         yield from self.body
@@ -4014,36 +3993,29 @@
     def _infer_name(self, frame, name):
         return name
 
-    def block_range(self, lineno: int) -> tuple[int, int]:
-        """Get a range from a given line number to where this node ends."""
-        if lineno == self.fromlineno:
-            return lineno, lineno
-        if self.body and self.body[0].fromlineno <= lineno <= self.body[-1].tolineno:
-            # Inside try body - return from lineno till end of try body
-            return lineno, self.body[-1].tolineno
-        for exhandler in self.handlers:
-            if exhandler.type and lineno == exhandler.type.fromlineno:
-                return lineno, lineno
-            if exhandler.body[0].fromlineno <= lineno <= exhandler.body[-1].tolineno:
-                return lineno, exhandler.body[-1].tolineno
-        if self.orelse:
-            if self.orelse[0].fromlineno - 1 == lineno:
-                return lineno, lineno
-            if self.orelse[0].fromlineno <= lineno <= self.orelse[-1].tolineno:
-                return lineno, self.orelse[-1].tolineno
-        if self.finalbody:
-            if self.finalbody[0].fromlineno - 1 == lineno:
-                return lineno, lineno
-            if self.finalbody[0].fromlineno <= lineno <= self.finalbody[-1].tolineno:
-                return lineno, self.finalbody[-1].tolineno
-        return lineno, self.tolineno
-
     def get_children(self):
         yield from self.body
         yield from self.handlers
         yield from self.orelse
         yield from self.finalbody
 
+    def block_range(self, lineno: int) -> tuple[int, int]:
+        """Get a range from a given line number to where this node ends."""
+        for exhandler in self.handlers:
+            if exhandler.type and lineno == exhandler.type.fromlineno:
+                return lineno, exhandler.tolineno
+            if exhandler.body[0].fromlineno <= lineno <= exhandler.body[-1].tolineno:
+                return lineno, exhandler.body[-1].tolineno
+        if self.finalbody:
+            if self.finalbody[0].fromlineno - 1 == lineno:
+                return lineno, self.finalbody[0].tolineno
+            if self.finalbody[0].fromlineno <= lineno <= self.finalbody[-1].tolineno:
+                return lineno, self.finalbody[-1].tolineno
+
+        # If not within any of the ExceptHandlers or `finally` body, fall back to regular
+        # handling of block_range for nodes with a potential `else` statement.
+        return super().block_range(lineno)
+
 
 class Tuple(BaseContainer):
     """Class representing an :class:`ast.Tuple` node.
@@ -4472,16 +4444,6 @@
         """
         return self.test.tolineno
 
-    def block_range(self, lineno: int) -> tuple[int, int]:
-        """Get a range from the given line number to where this node ends.
-
-        :param lineno: The line number to start the range at.
-
-        :returns: The range of line numbers that this node belongs to,
-            starting at the given line number.
-        """
-        return self._elsed_block_range(lineno, self.orelse)
-
     def get_children(self):
         yield self.test
 
diff --git a/tests/test_group_exceptions.py b/tests/test_group_exceptions.py
index 9680664..2ced9ae 100644
--- a/tests/test_group_exceptions.py
+++ b/tests/test_group_exceptions.py
@@ -41,7 +41,7 @@
     assert isinstance(node, nodes.Try)
     handler = node.handlers[0]
     assert node.block_range(lineno=1) == (1, 9)
-    assert node.block_range(lineno=2) == (2, 2)
+    assert node.block_range(lineno=2) == (2, 3)
     assert node.block_range(lineno=5) == (5, 9)
     assert isinstance(handler, nodes.ExceptHandler)
     assert handler.type.name == "ExceptionGroup"
@@ -72,15 +72,15 @@
     assert node.as_string() == code.replace('"', "'").strip()
     assert isinstance(node.body[0], nodes.Raise)
     assert node.block_range(1) == (1, 11)
-    assert node.block_range(2) == (2, 2)
+    assert node.block_range(2) == (2, 3)
     assert node.block_range(3) == (3, 3)
-    assert node.block_range(4) == (4, 4)
+    assert node.block_range(4) == (4, 5)
     assert node.block_range(5) == (5, 5)
-    assert node.block_range(6) == (6, 6)
+    assert node.block_range(6) == (6, 7)
     assert node.block_range(7) == (7, 7)
-    assert node.block_range(8) == (8, 8)
+    assert node.block_range(8) == (8, 9)
     assert node.block_range(9) == (9, 9)
-    assert node.block_range(10) == (10, 10)
+    assert node.block_range(10) == (10, 11)
     assert node.block_range(11) == (11, 11)
     assert node.handlers
     handler = node.handlers[0]
diff --git a/tests/test_nodes.py b/tests/test_nodes.py
index 4bba86b..ff2ecea 100644
--- a/tests/test_nodes.py
+++ b/tests/test_nodes.py
@@ -427,11 +427,22 @@
             pass
         else:
             raise
+
+        if 1:
+            print()
+        elif (
+            2
+            and 3
+        ):
+            print()
+        else:
+            # This is using else in a comment
+            raise
     """
 
     def test_if_elif_else_node(self) -> None:
         """Test transformation for If node."""
-        self.assertEqual(len(self.astroid.body), 4)
+        self.assertEqual(len(self.astroid.body), 5)
         for stmt in self.astroid.body:
             self.assertIsInstance(stmt, nodes.If)
         self.assertFalse(self.astroid.body[0].orelse)  # simple If
@@ -440,13 +451,50 @@
         self.assertIsInstance(self.astroid.body[3].orelse[0].orelse[0], nodes.If)
 
     def test_block_range(self) -> None:
-        # XXX ensure expected values
-        self.assertEqual(self.astroid.block_range(1), (0, 22))
-        self.assertEqual(self.astroid.block_range(10), (0, 22))  # XXX (10, 22) ?
+        """Test block_range of various scope constructs"""
+        # Module
+        self.assertEqual(self.astroid.block_range(1), (0, 33))
+        # NOTE: Module does not consider the lineno argument. It would be more consistent to make
+        # this return (10, 33) but without a use case it seems better to not change behaviour.
+        self.assertEqual(self.astroid.block_range(10), (0, 33))
+
+        # if
+        self.assertEqual(self.astroid.body[0].block_range(2), (2, 3))
+        self.assertEqual(self.astroid.body[0].block_range(3), (3, 3))
+
+        # if ... else
         self.assertEqual(self.astroid.body[1].block_range(5), (5, 6))
         self.assertEqual(self.astroid.body[1].block_range(6), (6, 6))
-        self.assertEqual(self.astroid.body[1].orelse[0].block_range(7), (7, 8))
-        self.assertEqual(self.astroid.body[1].orelse[0].block_range(8), (8, 8))
+        self.assertEqual(self.astroid.body[1].block_range(7), (7, 8))
+        self.assertEqual(self.astroid.body[1].block_range(8), (8, 8))
+
+        # if ... elif
+        self.assertEqual(self.astroid.body[2].block_range(10), (10, 11))
+        self.assertEqual(self.astroid.body[2].block_range(11), (11, 11))
+        self.assertEqual(self.astroid.body[2].block_range(12), (12, 13))
+        self.assertEqual(self.astroid.body[2].block_range(13), (13, 13))
+
+        # if ... elif ... elif ... else
+        self.assertEqual(self.astroid.body[3].block_range(15), (15, 16))
+        self.assertEqual(self.astroid.body[3].block_range(16), (16, 16))
+        self.assertEqual(self.astroid.body[3].block_range(17), (17, 18))
+        self.assertEqual(self.astroid.body[3].block_range(18), (18, 18))
+        self.assertEqual(self.astroid.body[3].block_range(19), (19, 20))
+        self.assertEqual(self.astroid.body[3].block_range(20), (20, 20))
+        self.assertEqual(self.astroid.body[3].block_range(21), (21, 22))
+        self.assertEqual(self.astroid.body[3].block_range(22), (22, 22))
+
+        # if ... elif ... else
+        self.assertEqual(self.astroid.body[4].block_range(24), (24, 25))
+        self.assertEqual(self.astroid.body[4].block_range(25), (25, 25))
+        self.assertEqual(self.astroid.body[4].block_range(26), (26, 30))
+        self.assertEqual(self.astroid.body[4].block_range(27), (27, 30))
+        self.assertEqual(self.astroid.body[4].block_range(28), (28, 30))
+        self.assertEqual(self.astroid.body[4].block_range(29), (29, 30))
+        self.assertEqual(self.astroid.body[4].block_range(30), (30, 30))
+        self.assertEqual(self.astroid.body[4].block_range(31), (31, 33))
+        self.assertEqual(self.astroid.body[4].block_range(32), (32, 33))
+        self.assertEqual(self.astroid.body[4].block_range(33), (33, 33))
 
 
 class TryNodeTest(_NodeTest):
@@ -466,81 +514,18 @@
     def test_block_range(self) -> None:
         try_node = self.astroid.body[0]
         assert try_node.block_range(1) == (1, 11)
-        assert try_node.block_range(2) == (2, 2)
+        assert try_node.block_range(2) == (2, 3)
         assert try_node.block_range(3) == (3, 3)
-        assert try_node.block_range(4) == (4, 4)
+        assert try_node.block_range(4) == (4, 5)
         assert try_node.block_range(5) == (5, 5)
-        assert try_node.block_range(6) == (6, 6)
+        assert try_node.block_range(6) == (6, 7)
         assert try_node.block_range(7) == (7, 7)
-        assert try_node.block_range(8) == (8, 8)
+        assert try_node.block_range(8) == (8, 9)
         assert try_node.block_range(9) == (9, 9)
-        assert try_node.block_range(10) == (10, 10)
+        assert try_node.block_range(10) == (10, 11)
         assert try_node.block_range(11) == (11, 11)
 
 
-class TryExceptNodeTest(_NodeTest):
-    CODE = """
-        try:
-            print ('pouet')
-        except IOError:
-            pass
-        except UnicodeError:
-            print()
-        else:
-            print()
-    """
-
-    def test_block_range(self) -> None:
-        # XXX ensure expected values
-        self.assertEqual(self.astroid.body[0].block_range(1), (1, 9))
-        self.assertEqual(self.astroid.body[0].block_range(2), (2, 2))
-        self.assertEqual(self.astroid.body[0].block_range(3), (3, 3))
-        self.assertEqual(self.astroid.body[0].block_range(4), (4, 4))
-        self.assertEqual(self.astroid.body[0].block_range(5), (5, 5))
-        self.assertEqual(self.astroid.body[0].block_range(6), (6, 6))
-        self.assertEqual(self.astroid.body[0].block_range(7), (7, 7))
-        self.assertEqual(self.astroid.body[0].block_range(8), (8, 8))
-        self.assertEqual(self.astroid.body[0].block_range(9), (9, 9))
-
-
-class TryFinallyNodeTest(_NodeTest):
-    CODE = """
-        try:
-            print ('pouet')
-        finally:
-            print ('pouet')
-    """
-
-    def test_block_range(self) -> None:
-        # XXX ensure expected values
-        self.assertEqual(self.astroid.body[0].block_range(1), (1, 5))
-        self.assertEqual(self.astroid.body[0].block_range(2), (2, 2))
-        self.assertEqual(self.astroid.body[0].block_range(3), (3, 3))
-        self.assertEqual(self.astroid.body[0].block_range(4), (4, 4))
-        self.assertEqual(self.astroid.body[0].block_range(5), (5, 5))
-
-
-class TryExceptFinallyNodeTest(_NodeTest):
-    CODE = """
-        try:
-            print('pouet')
-        except Exception:
-            print ('oops')
-        finally:
-            print ('pouet')
-    """
-
-    def test_block_range(self) -> None:
-        # XXX ensure expected values
-        self.assertEqual(self.astroid.body[0].block_range(1), (1, 7))
-        self.assertEqual(self.astroid.body[0].block_range(2), (2, 2))
-        self.assertEqual(self.astroid.body[0].block_range(3), (3, 3))
-        self.assertEqual(self.astroid.body[0].block_range(4), (4, 4))
-        self.assertEqual(self.astroid.body[0].block_range(5), (5, 5))
-        self.assertEqual(self.astroid.body[0].block_range(6), (6, 6))
-        self.assertEqual(self.astroid.body[0].block_range(7), (7, 7))
-
-
 class ImportNodeTest(resources.SysPathSetup, unittest.TestCase):
     def setUp(self) -> None:
         super().setUp()
diff --git a/tests/test_nodes_lineno.py b/tests/test_nodes_lineno.py
index bbc1e8c..37db476 100644
--- a/tests/test_nodes_lineno.py
+++ b/tests/test_nodes_lineno.py
@@ -878,6 +878,10 @@
         assert (w1.body[0].end_lineno, w1.body[0].end_col_offset) == (2, 8)
         assert (w1.orelse[0].lineno, w1.orelse[0].col_offset) == (4, 4)
         assert (w1.orelse[0].end_lineno, w1.orelse[0].end_col_offset) == (4, 8)
+        assert w1.block_range(1) == (1, 2)
+        assert w1.block_range(2) == (2, 2)
+        assert w1.block_range(3) == (3, 4)
+        assert w1.block_range(4) == (4, 4)
 
     @staticmethod
     def test_end_lineno_string() -> None: