Merge branch 'main' into dependabot/pip/numpy-gte-1.17.0-and-lt-3
diff --git a/.coveragerc b/.coveragerc
index 55838fc..ca605f7 100644
--- a/.coveragerc
+++ b/.coveragerc
@@ -3,6 +3,7 @@
 
 [report]
 omit =
+    */astroid/__main__.py
     */tests/*
     */tmp*/*
 exclude_lines =
diff --git a/.github/workflows/backport.yml b/.github/workflows/backport.yml
index 9fbc070..d81e593 100644
--- a/.github/workflows/backport.yml
+++ b/.github/workflows/backport.yml
@@ -6,14 +6,14 @@
       - labeled
 
 permissions:
-  actions: write
-  contents: write
-  pull-requests: write
+  contents: read
 
 jobs:
   backport:
     name: Backport
     runs-on: ubuntu-latest
+    environment:
+      name: Backport
     # Only react to merged PRs for security reasons.
     # See https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#pull_request_target.
     if: >
@@ -25,6 +25,16 @@
         )
       )
     steps:
-      - uses: tibdex/backport@9565281eda0731b1d20c4025c43339fb0a23812e # v2.0.4
+      - uses: actions/create-github-app-token@29824e69f54612133e76f7eaac726eef6c875baf # v2.2.1
+        id: app-token
         with:
-          github_token: ${{ secrets.GITHUB_TOKEN }}
+          app-id: ${{ vars.BACKPORT_APP_ID }}
+          private-key: ${{ secrets.PRIVATE_KEY }}
+          permission-contents: write # push branch to Github
+          permission-pull-requests: write # create PR / add comment for manual backport
+          permission-workflows: write # modify files in .github/workflows
+      - uses: pylint-dev/backport@6accae9e09c5ad1bc3a0b56adf37c45357e7bcdc # v2.1.3
+        with:
+          github_token: ${{ steps.app-token.outputs.token }}
+          user_name: ${{ vars.BACKPORT_USER_NAME }}
+          user_email: ${{ vars.BACKPORT_USER_EMAIL }}
diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml
index 7c4e1b5..730254f 100644
--- a/.github/workflows/ci.yaml
+++ b/.github/workflows/ci.yaml
@@ -5,7 +5,8 @@
     branches:
       - main
       - 2.*
-  pull_request: ~
+  pull_request:
+  workflow_dispatch:
 
 env:
   CACHE_VERSION: 3
@@ -23,11 +24,13 @@
     runs-on: ubuntu-latest
     timeout-minutes: 20
     steps:
-      - name: Check out code from GitHub
-        uses: actions/checkout@v4.2.2
-      - name: Set up Python ${{ env.DEFAULT_PYTHON }}
+      - &checkout
+        name: Check out code from GitHub
+        uses: actions/checkout@v6.0.2
+      - &setup-python-default
+        name: Set up Python ${{ env.DEFAULT_PYTHON }}
         id: python
-        uses: actions/setup-python@v5.4.0
+        uses: actions/setup-python@v6.2.0
         with:
           python-version: ${{ env.DEFAULT_PYTHON }}
           check-latest: true
@@ -37,9 +40,10 @@
           echo "key=base-venv-${{ env.CACHE_VERSION }}-${{
             hashFiles('pyproject.toml', 'requirements_dev.txt',
           'requirements_full.txt', 'requirements_minimal.txt') }}" >> $GITHUB_OUTPUT
-      - name: Restore Python virtual environment
+      - &cache-python
+        name: Restore Python virtual environment
         id: cache-venv
-        uses: actions/cache@v4.2.2
+        uses: actions/cache@v5.0.3
         with:
           path: venv
           key: >-
@@ -50,7 +54,7 @@
         run: |
           python -m venv venv
           . venv/bin/activate
-          python -m pip install -U pip setuptools wheel
+          python -m pip install -U pip
           pip install -U -r requirements_full.txt
       - name: Generate pre-commit restore key
         id: generate-pre-commit-key
@@ -59,7 +63,7 @@
             hashFiles('.pre-commit-config.yaml') }}" >> $GITHUB_OUTPUT
       - name: Restore pre-commit environment
         id: cache-precommit
-        uses: actions/cache@v4.2.2
+        uses: actions/cache@v5.0.3
         with:
           path: ${{ env.PRE_COMMIT_CACHE }}
           key: >-
@@ -72,7 +76,7 @@
       - name: Run pre-commit checks
         run: |
           . venv/bin/activate
-          pre-commit run pylint --all-files
+          pre-commit run --hook-stage manual pylint-ci --all-files
 
   tests-linux:
     name: tests / run / ${{ matrix.python-version }} / Linux
@@ -81,17 +85,17 @@
     strategy:
       fail-fast: false
       matrix:
-        python-version: [3.9, "3.10", "3.11", "3.12", "3.13"]
+        python-version: &matrix-python-version ["3.10", "3.11", "3.12", "3.13", "3.14"]
     outputs:
       python-key: ${{ steps.generate-python-key.outputs.key }}
     steps:
-      - name: Check out code from GitHub
-        uses: actions/checkout@v4.2.2
+      - *checkout
       - name: Set up Python ${{ matrix.python-version }}
         id: python
-        uses: actions/setup-python@v5.4.0
+        uses: actions/setup-python@v6.2.0
         with:
           python-version: ${{ matrix.python-version }}
+          allow-prereleases: true
           check-latest: true
       - name: Install Qt
         if: ${{ matrix.python-version == '3.10' }}
@@ -104,14 +108,7 @@
           echo "key=${{ env.KEY_PREFIX }}-${{ env.CACHE_VERSION }}-${{
             hashFiles('pyproject.toml', 'requirements_dev.txt',
           'requirements_full.txt', 'requirements_minimal.txt') }}" >> $GITHUB_OUTPUT
-      - name: Restore Python virtual environment
-        id: cache-venv
-        uses: actions/cache@v4.2.2
-        with:
-          path: venv
-          key: >-
-            ${{ runner.os }}-${{ steps.python.outputs.python-version }}-${{
-            steps.generate-python-key.outputs.key }}
+      - *cache-python
       - name: Create Python virtual environment
         if: steps.cache-venv.outputs.cache-hit != 'true'
         run: |
@@ -125,7 +122,7 @@
           . venv/bin/activate
           pytest --cov
       - name: Upload coverage artifact
-        uses: actions/upload-artifact@v4.6.1
+        uses: &actions-upload-artifact actions/upload-artifact@v6.0.0
         with:
           name: coverage-linux-${{ matrix.python-version }}
           path: .coverage
@@ -135,44 +132,38 @@
     name: tests / run / ${{ matrix.python-version }} / Windows
     runs-on: windows-latest
     timeout-minutes: 20
-    needs: tests-linux
+    needs: [tests-linux]
     strategy:
       fail-fast: false
       matrix:
-        python-version: [3.9, "3.10", "3.11", "3.12", "3.13"]
+        python-version: ["3.10", "3.11", "3.12", "3.13", "3.14"]
     steps:
       - name: Set temp directory
         run: echo "TEMP=$env:USERPROFILE\AppData\Local\Temp" >> $env:GITHUB_ENV
         # Workaround to set correct temp directory on Windows
         # https://github.com/actions/virtual-environments/issues/712
-      - name: Check out code from GitHub
-        uses: actions/checkout@v4.2.2
-      - name: Set up Python ${{ matrix.python-version }}
+      - *checkout
+      - &setup-python-matrix
+        name: Set up Python ${{ matrix.python-version }}
         id: python
-        uses: actions/setup-python@v5.4.0
+        uses: actions/setup-python@v6.2.0
         with:
           python-version: ${{ matrix.python-version }}
+          allow-prereleases: true
           check-latest: true
       - name: Generate partial Python venv restore key
         id: generate-python-key
         run: >-
           echo "key=${{ env.KEY_PREFIX }}-${{ env.CACHE_VERSION }}-${{
             hashFiles('pyproject.toml', 'requirements_dev.txt',
-          'requirements_full.txt', 'requirements_minimal.txt') }}" >> $GITHUB_OUTPUT
-      - name: Restore Python virtual environment
-        id: cache-venv
-        uses: actions/cache@v4.2.2
-        with:
-          path: venv
-          key: >-
-            ${{ runner.os }}-${{ steps.python.outputs.python-version }}-${{
-            steps.generate-python-key.outputs.key }}
+          'requirements_full.txt', 'requirements_minimal.txt') }}" >> $env:GITHUB_OUTPUT
+      - *cache-python
       - name: Create Python virtual environment
         if: steps.cache-venv.outputs.cache-hit != 'true'
         run: |
           python -m venv venv
           . venv\\Scripts\\activate
-          python -m pip install -U pip setuptools wheel
+          python -m pip install -U pip
           pip install -U -r requirements_full.txt
           pip install -e .
       - name: Run pytest
@@ -180,7 +171,7 @@
           . venv\\Scripts\\activate
           pytest --cov
       - name: Upload coverage artifact
-        uses: actions/upload-artifact@v4.6.1
+        uses: *actions-upload-artifact
         with:
           name: coverage-windows-${{ matrix.python-version }}
           path: .coverage
@@ -194,36 +185,23 @@
       fail-fast: false
       matrix:
         # We only test on the lowest and highest supported PyPy versions
-        python-version: ["pypy3.9", "pypy3.10"]
+        python-version: ["pypy3.10"]
     steps:
-      - name: Check out code from GitHub
-        uses: actions/checkout@v4.2.2
-      - name: Set up Python ${{ matrix.python-version }}
-        id: python
-        uses: actions/setup-python@v5.4.0
-        with:
-          python-version: ${{ matrix.python-version }}
-          check-latest: true
+      - *checkout
+      - *setup-python-matrix
       - name: Generate partial Python venv restore key
         id: generate-python-key
         run: >-
           echo "key=${{ env.KEY_PREFIX }}-${{ env.CACHE_VERSION }}-${{
             hashFiles('pyproject.toml', 'requirements_minimal.txt')
           }}" >> $GITHUB_OUTPUT
-      - name: Restore Python virtual environment
-        id: cache-venv
-        uses: actions/cache@v4.2.2
-        with:
-          path: venv
-          key: >-
-            ${{ runner.os }}-${{ matrix.python-version }}-${{
-            steps.generate-python-key.outputs.key }}
+      - *cache-python
       - name: Create Python virtual environment
         if: steps.cache-venv.outputs.cache-hit != 'true'
         run: |
           python -m venv venv
           . venv/bin/activate
-          python -m pip install -U pip setuptools wheel
+          python -m pip install -U pip
           pip install -U -r requirements_minimal.txt
           pip install -e .
       - name: Run pytest
@@ -231,7 +209,7 @@
           . venv/bin/activate
           pytest --cov
       - name: Upload coverage artifact
-        uses: actions/upload-artifact@v4.6.1
+        uses: *actions-upload-artifact
         with:
           name: coverage-pypy-${{ matrix.python-version }}
           path: .coverage
@@ -243,23 +221,17 @@
     timeout-minutes: 10
     needs: ["tests-linux", "tests-windows", "tests-pypy"]
     steps:
-      - name: Check out code from GitHub
-        uses: actions/checkout@v4.2.2
-      - name: Set up Python 3.13
-        id: python
-        uses: actions/setup-python@v5.4.0
-        with:
-          python-version: "3.13"
-          check-latest: true
+      - *checkout
+      - *setup-python-default
       - name: Install dependencies
         run: pip install -U -r requirements_minimal.txt
       - name: Download all coverage artifacts
-        uses: actions/download-artifact@v4.1.9
+        uses: actions/download-artifact@v7.0.0
       - name: Combine Linux coverage results
         run: |
           coverage combine coverage-linux*/.coverage
           coverage xml -o coverage-linux.xml
-      - uses: codecov/codecov-action@v5
+      - uses: &actions-codecov codecov/codecov-action@v5
         with:
           token: ${{ secrets.CODECOV_TOKEN }}
           fail_ci_if_error: true
@@ -270,7 +242,7 @@
         run: |
           coverage combine coverage-windows*/.coverage
           coverage xml -o coverage-windows.xml
-      - uses: codecov/codecov-action@v5
+      - uses: *actions-codecov
         with:
           token: ${{ secrets.CODECOV_TOKEN }}
           fail_ci_if_error: true
@@ -281,7 +253,7 @@
         run: |
           coverage combine coverage-pypy*/.coverage
           coverage xml -o coverage-pypy.xml
-      - uses: codecov/codecov-action@v5
+      - uses: *actions-codecov
         with:
           token: ${{ secrets.CODECOV_TOKEN }}
           fail_ci_if_error: true
diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml
index 68acfd4..a569355 100644
--- a/.github/workflows/codeql-analysis.yml
+++ b/.github/workflows/codeql-analysis.yml
@@ -46,11 +46,11 @@
 
     steps:
       - name: Checkout repository
-        uses: actions/checkout@v4.2.2
+        uses: actions/checkout@v6.0.2
 
       # Initializes the CodeQL tools for scanning.
       - name: Initialize CodeQL
-        uses: github/codeql-action/init@v3
+        uses: github/codeql-action/init@v4
         with:
           languages: ${{ matrix.language }}
           # If you wish to specify custom queries, you can do so here or in a config file.
@@ -61,7 +61,7 @@
       # Autobuild attempts to build any compiled languages  (C/C++, C#, or Java).
       # If this step fails, then you should remove it and run the build manually (see below)
       - name: Autobuild
-        uses: github/codeql-action/autobuild@v3
+        uses: github/codeql-action/autobuild@v4
 
       # ℹ️ Command-line programs to run using the OS shell.
       # 📚 https://git.io/JvXDl
@@ -75,4 +75,4 @@
       #   make release
 
       - name: Perform CodeQL Analysis
-        uses: github/codeql-action/analyze@v3
+        uses: github/codeql-action/analyze@v4
diff --git a/.github/workflows/release-tests.yml b/.github/workflows/release-tests.yml
deleted file mode 100644
index 4aa24d6..0000000
--- a/.github/workflows/release-tests.yml
+++ /dev/null
@@ -1,38 +0,0 @@
-name: Release tests
-
-on: workflow_dispatch
-
-permissions:
-  contents: read
-
-jobs:
-  virtualenv-15-windows-test:
-    # Regression test added in https://github.com/pylint-dev/astroid/pull/1386
-    name: Regression test for virtualenv==15.1.0 on Windows
-    runs-on: windows-latest
-    timeout-minutes: 5
-    steps:
-      - name: Check out code from GitHub
-        uses: actions/checkout@v4.2.2
-      - name: Set up Python 3.9
-        id: python
-        uses: actions/setup-python@v5.4.0
-        with:
-          # virtualenv 15.1.0 cannot be installed on Python 3.10+
-          python-version: 3.9
-        env:
-          PIP_TRUSTED_HOST: "pypi.python.org pypi.org files.pythonhosted.org"
-      - name: Create Python virtual environment with virtualenv==15.1.0
-        env:
-          PIP_TRUSTED_HOST: "pypi.python.org pypi.org files.pythonhosted.org"
-        run: |
-          python -m pip install virtualenv==15.1.0
-          python -m virtualenv venv2
-          . venv2\scripts\activate
-          python -m pip install pylint
-          python -m pip install -e .
-      - name: Test no import-error from distutils.util
-        run: |
-          . venv2\scripts\activate
-          echo "import distutils.util  # pylint: disable=unused-import" > test.py
-          pylint test.py
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index eac1b86..d0ca1ba 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -18,10 +18,10 @@
     if: github.event_name == 'release'
     steps:
       - name: Check out code from Github
-        uses: actions/checkout@v4.2.2
+        uses: actions/checkout@v6.0.2
       - name: Set up Python ${{ env.DEFAULT_PYTHON }}
         id: python
-        uses: actions/setup-python@v5.4.0
+        uses: actions/setup-python@v6.2.0
         with:
           python-version: ${{ env.DEFAULT_PYTHON }}
           check-latest: true
@@ -34,7 +34,7 @@
         run: |
           python -m build
       - name: Upload release assets
-        uses: actions/upload-artifact@v4.6.1
+        uses: actions/upload-artifact@v6.0.0
         with:
           name: release-assets
           path: dist/
@@ -50,7 +50,7 @@
       id-token: write
     steps:
       - name: Download release assets
-        uses: actions/download-artifact@v4.1.9
+        uses: actions/download-artifact@v7.0.0
         with:
           name: release-assets
           path: dist/
@@ -67,13 +67,13 @@
       id-token: write
     steps:
       - name: Download release assets
-        uses: actions/download-artifact@v4.1.9
+        uses: actions/download-artifact@v7.0.0
         with:
           name: release-assets
           path: dist/
       - name: Sign the dists with Sigstore and upload assets to Github release
         if: github.event_name == 'release'
-        uses: sigstore/gh-action-sigstore-python@v3.0.0
+        uses: sigstore/gh-action-sigstore-python@v3.2.0
         with:
           inputs: |
             ./dist/*.tar.gz
diff --git a/.github/workflows/test-pylint.yml b/.github/workflows/test-pylint.yml
new file mode 100644
index 0000000..2b4b104
--- /dev/null
+++ b/.github/workflows/test-pylint.yml
@@ -0,0 +1,11 @@
+name: Test pylint
+
+on:
+  pull_request:
+
+jobs:
+  test-pylint-with-astroid-sha:
+    uses: pylint-dev/pylint/.github/workflows/tests.yaml@main
+    with:
+      repository: pylint-dev/pylint
+      astroid_sha: ${{ github.sha }}
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 1e8b2b5..c4cdf8a 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -3,16 +3,16 @@
 
 repos:
   - repo: https://github.com/pre-commit/pre-commit-hooks
-    rev: v5.0.0
+    rev: v6.0.0
     hooks:
       - id: trailing-whitespace
         exclude: .github/|tests/testdata
       - id: end-of-file-fixer
         exclude: tests/testdata
   - repo: https://github.com/astral-sh/ruff-pre-commit
-    rev: "v0.11.0"
+    rev: "v0.15.2"
     hooks:
-      - id: ruff
+      - id: ruff-check
         args: ["--fix"]
   - repo: https://github.com/Pierre-Sassoulas/copyright_notice_precommit
     rev: 0.1.2
@@ -22,18 +22,18 @@
         exclude: tests/testdata|setup.py
         types: [python]
   - repo: https://github.com/asottile/pyupgrade
-    rev: v3.19.1
+    rev: v3.21.2
     hooks:
       - id: pyupgrade
         exclude: tests/testdata
-        args: [--py39-plus]
+        args: [--py310-plus]
   - repo: https://github.com/Pierre-Sassoulas/black-disable-checker/
     rev: v1.1.3
     hooks:
       - id: black-disable-checker
         exclude: tests/test_nodes_lineno.py
-  - repo: https://github.com/psf/black
-    rev: 25.1.0
+  - repo: https://github.com/psf/black-pre-commit-mirror
+    rev: 26.1.0
     hooks:
       - id: black
         args: [--safe, --quiet]
@@ -49,11 +49,26 @@
             "-rn",
             "-sn",
             "--rcfile=pylintrc",
+            # "--load-plugins=pylint.extensions.docparams", We're not ready for that
+          ]
+      # We define an additional manual step to allow running pylint
+      # with the proper output for CI.
+      - id: pylint
+        alias: pylint-ci
+        name: pylint
+        entry: pylint
+        language: system
+        types: [python]
+        args: [
+            "-rn",
+            "-sn",
+            "--rcfile=pylintrc",
             "--output-format=github",
             # "--load-plugins=pylint.extensions.docparams", We're not ready for that
           ]
+        stages: [manual]
   - repo: https://github.com/pre-commit/mirrors-mypy
-    rev: v1.15.0
+    rev: v1.19.1
     hooks:
       - id: mypy
         language: python
@@ -61,11 +76,11 @@
         require_serial: true
         additional_dependencies: ["types-typed-ast"]
   - repo: https://github.com/rbubley/mirrors-prettier
-    rev: v3.5.3
+    rev: v3.8.1
     hooks:
       - id: prettier
         args: [--prose-wrap=always, --print-width=88]
   - repo: https://github.com/tox-dev/pyproject-fmt
-    rev: "v2.5.1"
+    rev: "v2.16.2"
     hooks:
       - id: pyproject-fmt
diff --git a/CONTRIBUTORS.txt b/CONTRIBUTORS.txt
index 83d4651..e9fd059 100644
--- a/CONTRIBUTORS.txt
+++ b/CONTRIBUTORS.txt
@@ -14,8 +14,8 @@
 Maintainers
 -----------
 - Pierre Sassoulas <pierre.sassoulas@gmail.com>
-- Daniël van Noord <13665637+DanielNoord@users.noreply.github.com>
 - Jacob Walls <jacobtylerwalls@gmail.com>
+- Daniël van Noord <13665637+DanielNoord@users.noreply.github.com>
 - Marc Mueller <30130371+cdce8p@users.noreply.github.com>
 - Hippo91 <guillaume.peillex@gmail.com>
 - Bryce Guinta <bryce.paul.guinta@gmail.com>
@@ -35,16 +35,19 @@
 - correctmost <134317971+correctmost@users.noreply.github.com>
 - Andrew Haigh <hello@nelf.in>
 - Julien Cristau <julien.cristau@logilab.fr>
-- David Liu <david@cs.toronto.edu>
 - Artem Yurchenko <44875844+temyurchenko@users.noreply.github.com>
+- David Liu <david@cs.toronto.edu>
 - Alexandre Fayolle <alexandre.fayolle@logilab.fr>
 - Eevee (Alex Munroe) <amunroe@yelp.com>
+- Emmanuel Ferdman <emmanuelferdman@gmail.com>
 - David Gilman <davidgilman1@gmail.com>
+- Zen Lee <53538590+zenlyj@users.noreply.github.com>
 - Tushar Sadhwani <tushar.sadhwani000@gmail.com>
+- Matus Valo <matusvalo@users.noreply.github.com>
 - Julien Jehannet <julien.jehannet@logilab.fr>
+- Hugo van Kemenade <hugovk@users.noreply.github.com>
 - Calen Pennington <calen.pennington@gmail.com>
 - Antonio <antonio@zoftko.com>
-- Hugo van Kemenade <hugovk@users.noreply.github.com>
 - Akhil Kamat <akhil.kamat@gmail.com>
 - Tim Martin <tim@asymptotic.co.uk>
 - Phil Schaf <flying-sheep@web.de>
@@ -59,6 +62,7 @@
 - Daniel Harding <dharding@gmail.com>
 - Christian Clauss <cclauss@me.com>
 - Ville Skyttä <ville.skytta@iki.fi>
+- Synrom <30272537+Synrom@users.noreply.github.com>
 - Rene Zhang <rz99@cornell.edu>
 - Philip Lorenz <philip@bithub.de>
 - Nicolas Chauvat <nicolas.chauvat@logilab.fr>
@@ -72,6 +76,7 @@
 - Dani Alcala <112832187+clavedeluna@users.noreply.github.com>
 - Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
 - tristanlatr <19967168+tristanlatr@users.noreply.github.com>
+- grayjk <grayjk@gmail.com>
 - emile@crater.logilab.fr <emile@crater.logilab.fr>
 - doranid <ddandd@gmail.com>
 - brendanator <brendan.maginnis@gmail.com>
@@ -81,16 +86,19 @@
 - Stefan Scherfke <stefan@sofa-rockers.org>
 - Sergei Lebedev <185856+superbobry@users.noreply.github.com>
 - Saugat Pachhai (सौगात) <suagatchhetri@outlook.com>
+- Robert Hofer <1058012+hofrob@users.noreply.github.com>
 - Ram Rachum <ram@rachum.com>
 - Pierre-Yves David <pierre-yves.david@logilab.fr>
 - Peter Pentchev <roam@ringlet.net>
 - Peter Kolbus <peter.kolbus@gmail.com>
 - Omer Katz <omer.drow@gmail.com>
 - Moises Lopez <moylop260@vauxoo.com>
+- Mitch Harding <mitchell.harding@hpe.com>
 - Michal Vasilek <michal@vasilek.cz>
 - Keichi Takahashi <keichi.t@me.com>
 - Kavins Singh <kavinsingh@hotmail.com>
 - Karthikeyan Singaravelan <tir.karthi@gmail.com>
+- Kai Mueller <15907922+kasium@users.noreply.github.com>
 - Joshua Cannon <joshdcannon@gmail.com>
 - John Vandenberg <jayvdb@gmail.com>
 - Jacob Bogdanov <jacob@bogdanov.dev>
@@ -102,26 +110,31 @@
 - Anthony Sottile <asottile@umich.edu>
 - Alexander Shadchin <alexandr.shadchin@gmail.com>
 - wgehalo <wgehalo@gmail.com>
+- tejaschauhan36912 <59693377+tejaschauhan36912@users.noreply.github.com>
 - rr- <rr-@sakuya.pl>
 - raylu <lurayl@gmail.com>
 - plucury <plucury@gmail.com>
+- pavan-msys <149513767+pavan-msys@users.noreply.github.com>
 - ostr00000 <ostr00000@gmail.com>
 - noah-weingarden <33741795+noah-weingarden@users.noreply.github.com>
 - nathannaveen <42319948+nathannaveen@users.noreply.github.com>
 - mathieui <mathieui@users.noreply.github.com>
 - markmcclain <markmcclain@users.noreply.github.com>
+- jkmnt <git@firewood.fastmail.com>
 - ioanatia <ioanatia@users.noreply.github.com>
-- grayjk <grayjk@gmail.com>
 - alm <alonme@users.noreply.github.com>
 - adam-grant-hendry <59346180+adam-grant-hendry@users.noreply.github.com>
+- aatle <168398276+aatle@users.noreply.github.com>
 - Zbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>
 - Zac Hatfield-Dodds <Zac-HD@users.noreply.github.com>
+- Youngwook Kim <youngwook.kim@gmail.com>
 - Vilnis Termanis <vilnis.termanis@iotics.com>
 - Valentin Valls <valentin.valls@esrf.fr>
 - Uilian Ries <uilianries@gmail.com>
 - Tomas Novak <ext.Tomas.Novak@skoda-auto.cz>
 - Thirumal Venkat <me@thirumal.in>
 - SupImDos <62866982+SupImDos@users.noreply.github.com>
+- Stéphane Brunner <stephane.brunner@camptocamp.com>
 - Stanislav Levin <slev@altlinux.org>
 - Simon Hewitt <si@sjhewitt.co.uk>
 - Serhiy Storchaka <storchaka@gmail.com>
@@ -133,6 +146,7 @@
 - Peter de Blanc <peter@standard.ai>
 - Peter Talley <peterctalley@gmail.com>
 - Ovidiu Sabou <ovidiu@sabou.org>
+- Oliver Reiche <oliver.reiche@gmail.com>
 - Oleh Prypin <oleh@pryp.in>
 - Nicolas Noirbent <nicolas@noirbent.fr>
 - Neil Girdhar <mistersheik@gmail.com>
@@ -141,16 +155,17 @@
 - Mateusz Bysiek <mb@mbdev.pl>
 - Matej Aleksandrov <matej.aleksandrov@gmail.com>
 - Marcelo Trylesinski <marcelotryle@gmail.com>
+- Low, Zhi Hao <lowzhao@gmail.com>
 - Leandro T. C. Melo <ltcmelo@gmail.com>
 - Konrad Weihmann <kweihmann@outlook.com>
 - Kian Meng, Ang <kianmeng.ang@gmail.com>
-- Kai Mueller <15907922+kasium@users.noreply.github.com>
 - Jörg Thalheim <Mic92@users.noreply.github.com>
 - Jérome Perrin <perrinjerome@gmail.com>
 - JulianJvn <128477611+JulianJvn@users.noreply.github.com>
 - Josef Kemetmüller <josef.kemetmueller@gmail.com>
 - Jonathan Striebel <jstriebel@users.noreply.github.com>
 - John Belmonte <john@neggie.net>
+- Joao Faria <joaovitorfaria.dev@gmail.com>
 - Jeff Widman <jeff@jeffwidman.com>
 - Jeff Quast <contact@jeffquast.com>
 - Jarrad Hope <me@jarradhope.com>
@@ -175,6 +190,7 @@
 - Denis Laxalde <denis.laxalde@logilab.fr>
 - Deepyaman Datta <deepyaman.datta@utexas.edu>
 - David Poirier <david-poirier-csn@users.noreply.github.com>
+- David Foster <david@dafoster.net>
 - Dave Hirschfeld <dave.hirschfeld@gmail.com>
 - Dave Baum <dbaum@google.com>
 - Daniel Martin <daniel.martin@crowdstrike.com>
@@ -185,6 +201,7 @@
 - Cole Robinson <crobinso@redhat.com>
 - Christoph Reiter <reiter.christoph@gmail.com>
 - Chris Philip <chrisp533@gmail.com>
+- Charlie Ringström <34444482+Chasarr@users.noreply.github.com>
 - BioGeek <jeroen.vangoey@gmail.com>
 - Bianca Power <30207144+biancapower@users.noreply.github.com>
 - Benjamin Elven <25181435+S3ntinelX@users.noreply.github.com>
diff --git a/ChangeLog b/ChangeLog
index d730e8e..a6d6335 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -3,10 +3,209 @@
 ===================
 
 
-What's New in astroid 4.0.0?
+What's New in astroid 4.2.0?
 ============================
 Release date: TBA
 
+
+What's New in astroid 4.1.2?
+============================
+Release date: TBA
+
+* Fix ``RecursionError`` in ``_compute_mro()`` when circular class hierarchies
+  are created through runtime name rebinding. Circular bases are now resolved
+  to the original class instead of recursing.
+
+  Closes #2967
+  Closes pylint-dev/pylint#10821
+
+* Fix ``DuplicateBasesError`` crash in dataclass transform when a class has
+  duplicate bases in its MRO (e.g., ``Protocol`` appearing both directly and
+  indirectly). Catch ``MroError`` at ``.mro()`` call sites in
+  ``brain_dataclasses.py``, consistent with the existing pattern elsewhere.
+
+  Closes #2628
+
+* Fix ``FunctionModel`` returning descriptor attributes for builtin functions.
+
+  Closes #2743
+
+* Catch ``MemoryError`` when inferring f-strings with extremely large format
+  widths (e.g. ``f'{0:11111111111}'``) so that inference yields ``Uninferable``
+  instead of crashing.
+
+  Closes #2762
+
+* Fix ``ValueError`` in ``__str__``/``repr`` and error messages when nodes have
+  extreme values (very long identifiers or large integers). Clamp pprint width
+  to a minimum of 1 and truncate oversized values in error messages.
+
+  Closes #2764
+
+
+What's New in astroid 4.1.1?
+============================
+Release date: 2026-02-22
+
+* Let `UnboundMethodModel` inherit from `FunctionModel` to improve inference of
+  dunder methods for unbound methods.
+
+  Refs #2741
+
+* Filter ``Unknown`` from ``UnboundMethod`` and ``Super`` special attribute
+  lookup to prevent placeholder nodes from leaking during inference.
+
+  Refs #2741
+
+
+What's New in astroid 4.1.0?
+============================
+Release date: 2026-02-08
+
+* Add support for equality constraints (``==``, ``!=``) in inference.
+  Closes pylint-dev/pylint#3632
+  Closes pylint-dev/pylint#3633
+
+* Ensure ``ast.JoinedStr`` nodes are ``Uninferable`` when the ``ast.FormattedValue`` is
+  ``Uninferable``. This prevents ``unexpected-keyword-arg`` messages in Pylint
+  where the ``Uninferable`` string appeared in function arguments that were
+  constructed dynamically.
+
+  Closes pylint-dev/pylint#10822
+
+* Add support for type constraints (`isinstance(x, y)`) in inference.
+
+  Closes pylint-dev/pylint#1162
+  Closes pylint-dev/pylint#4635
+  Closes pylint-dev/pylint#10469
+
+* Make `type.__new__()` raise clear errors instead of returning `None`
+
+* Move object dunder methods from ``FunctionModel`` to ``ObjectModel`` to make them
+  available on all object types, not just functions.
+
+  Closes #2742
+  Closes #2741
+  Closes pylint-dev/pylint#6094
+
+* ``lineno`` and ``end_lineno`` are now available on ``Arguments``.
+
+* Add helper to iterate over all annotations nodes of function arguments,
+  ``Arguments.get_annotations()``.
+
+  Refs #2860
+
+* Skip direct parent when determining the ``Decorator`` frame.
+
+  Refs pylint-dev/pylint#8425
+
+* Add simple command line interface for astroid to output generated AST.
+  Use with ``python -m astroid``.
+
+* Fix incorrect type inference for ``super().method()`` calls that return ``Self``.
+  Previously, astroid would infer the parent class type instead of the child class type,
+  causing pylint E1101 false positives in method chaining scenarios.
+
+  Closes #457
+
+* Add missing ``dtype`` and ``casting`` parameters to ``numpy.concatenate`` brain.
+
+  Closes #2870
+
+* Fix ability to detect .py modules inside PATH directories on Windows
+  described by a UNC path with a trailing backslash (`\`)
+    - Example: modutils.modpath_from_file(filename=r"\\Mac\Code\tests\test_resources.py", path=["\\mac\code\"]) == ['tests', 'test_resources']
+
+* Fix ``random.sample`` inference crash when sequence contains uninferable elements.
+
+  Closes #2518
+
+* Fix ``random.sample`` crash when cloning ``ClassDef`` or ``FunctionDef`` nodes.
+
+  Closes #2923
+
+
+What's New in astroid 4.0.4?
+============================
+Release date: 2026-02-07
+
+* Fix ``is_namespace()`` crash when search locations contain ``pathlib.Path`` objects.
+
+  Closes #2942
+
+What's New in astroid 4.0.3?
+============================
+Release date: 2026-01-03
+
+* Fix inference of ``IfExp`` (ternary expression) nodes to avoid prematurely narrowing
+  results in the face of inference ambiguity.
+
+  Closes #2899
+
+* Fix base class inference for dataclasses using the PEP 695 typing syntax.
+
+  Refs pylint-dev/pylint#10788
+
+
+What's New in astroid 4.0.2?
+============================
+Release date: 2025-11-09
+
+* Handle FunctionDef blockstart_tolineno edge cases correctly.
+
+  Refs #2880
+
+* Add ``HTTPMethod`` enum support to brain module for Python 3.11+.
+
+  Refs pylint-dev/pylint#10624
+  Closes #2877
+
+What's New in astroid 4.0.1?
+============================
+Release date: 2025-10-11
+
+* Suppress ``SyntaxWarning`` for invalid escape sequences and return in finally on
+  Python 3.14 when parsing modules.
+
+* Assign ``Import`` and ``ImportFrom`` nodes to module locals if used with ``global``.
+
+  Closes pylint-dev/pylint#10632
+
+
+What's New in astroid 4.0.0?
+============================
+Release date: 2025-10-05
+
+* Support constraints from ternary expressions in inference.
+
+  Closes pylint-dev/pylint#9729
+
+* Handle deprecated `bool(NotImplemented)` cast in const nodes.
+
+* Add support for boolean truthiness constraints (`x`, `not x`) in inference.
+
+  Closes pylint-dev/pylint#9515
+
+* Fix false positive `invalid-name` on `attrs` classes with `ClassVar` annotated variables.
+
+  Closes pylint-dev/pylint#10525
+
+* Prevent crash when parsing deeply nested parentheses causing MemoryError in python's built-in ast.
+
+  Closes #2643
+
+* Fix crash when inferring namedtuple with invalid field name looking like f-string formatting.
+
+  Closes #2519
+
+* Fix false positive no-member in except * handler.
+
+  Closes pylint-dev/pylint#9056
+
+* Fix crash when comparing invalid dict literal
+
+  Closes #2522
+
 * Removed internal functions ``infer_numpy_member``, ``name_looks_like_numpy_member``, and
   ``attribute_looks_like_numpy_member`` from ``astroid.brain.brain_numpy_utils``.
 
@@ -32,15 +231,71 @@
 
   Closes #2513
 
+* Remove support for Python 3.9 (and constant `PY310_PLUS`).
+
+* Include subclasses of standard property classes as `property` decorators
+
+  Closes #10377
+
+* Modify ``astroid.bases`` and ``tests.test_nodes`` to reflect that `enum.property` was added in Python 3.11, not 3.10
+
+* Fix incorrect result in `_get_relative_base_path` when the target directory name starts with the base path
+
+  Closes #2608
+
+* The brain for nose was dropped. nose has been deprecated for 10 years and the brain required some maintenance.
+
+  Refs #2765
+
+* Fix a crash when the root of a node is not a module but is unknown.
+
+  Closes #2672
+
+* Add basic support for ``ast.TemplateStr`` and ``ast.Interpolation`` added in Python 3.14.
+
+  Refs #2789
+
+* Add support for type parameter defaults added in Python 3.13.
+
+* Improve ``as_string()`` representation for ``TypeVar``, ``ParamSpec`` and ``TypeVarTuple`` nodes, as well as
+  type parameter in ``ClassDef``, ``FuncDef`` and ``TypeAlias`` nodes (PEP 695).
+
+* Astroid now correctly supports the ``exceptions`` attribute of ``ExceptionGroup``.
+
+  Closes pylint-dev/pylint#8985
+  Closes pylint-dev/pylint#10558
+
+* Deprecate importing node classes from ``astroid`` directly. This will be removed in v5.
+  It's recommended to import them from ``astroid.nodes`` instead.
+
+  Refs #2837
+
+
+What's New in astroid 3.3.11?
+=============================
+Release date: 2025-07-13
+
+* Fix a crash when parsing an empty arbitrary expression with ``extract_node`` (``extract_node("__()")``).
+
+  Closes #2734
+
+* Fix a crash when parsing a slice called in a decorator on a function that is also decorated with
+  a known ``six`` decorator.
+
+  Closes #2721
 
 What's New in astroid 3.3.10?
 =============================
-Release date: TBA
+Release date: 2025-05-10
 
 * Avoid importing submodules sharing names with standard library modules.
 
   Closes #2684
 
+* Fix bug where ``pylint code.custom_extension`` would analyze ``code.py`` or ``code.pyi`` instead if they existed.
+
+	Closes pylint-dev/pylint#3631
+
 
 What's New in astroid 3.3.9?
 ============================
@@ -539,11 +794,6 @@
   Closes #2305
   Closes pylint-dev/pylint#9069
 
-* Fix a regression in 2.15.7 for ``unsubscriptable-object``.
-
-  Closes #2305
-  Closes pylint-dev/pylint#9069
-
 
 What's New in astroid 2.15.7?
 =============================
diff --git a/README.rst b/README.rst
index 26d2231..0e479b1 100644
--- a/README.rst
+++ b/README.rst
@@ -1,7 +1,7 @@
 Astroid
 =======
 
-.. image:: https://codecov.io/gh/pylint-dev/astroid/branch/main/graph/badge.svg?token=Buxy4WptLb
+.. image:: https://codecov.io/gh/pylint-dev/astroid/branch/main/graph/badge.svg
     :target: https://codecov.io/gh/pylint-dev/astroid
     :alt: Coverage badge from codecov
 
diff --git a/astroid/__init__.py b/astroid/__init__.py
index f04b4df..abb45cf 100644
--- a/astroid/__init__.py
+++ b/astroid/__init__.py
@@ -30,9 +30,6 @@
 * builder contains the class responsible to build astroid trees
 """
 
-import functools
-import tokenize
-
 # isort: off
 # We have an isort: off on 'astroid.nodes' because of a circular import.
 from astroid.nodes import node_classes, scoped_nodes
@@ -44,7 +41,7 @@
 from astroid.bases import BaseInstance, BoundMethod, Instance, UnboundMethod
 from astroid.brain.helpers import register_module_extender
 from astroid.builder import extract_node, parse
-from astroid.const import PY310_PLUS, Context
+from astroid.const import Context
 from astroid.exceptions import (
     AstroidBuildingError,
     AstroidError,
@@ -83,89 +80,91 @@
 from astroid.astroid_manager import MANAGER
 from astroid.nodes import (
     CONST_CLS,
-    AnnAssign,
-    Arguments,
-    Assert,
-    Assign,
-    AssignAttr,
-    AssignName,
-    AsyncFor,
-    AsyncFunctionDef,
-    AsyncWith,
-    Attribute,
-    AugAssign,
-    Await,
-    BinOp,
-    BoolOp,
-    Break,
-    Call,
-    ClassDef,
-    Compare,
-    Comprehension,
-    ComprehensionScope,
-    Const,
-    Continue,
-    Decorators,
-    DelAttr,
-    Delete,
-    DelName,
-    Dict,
-    DictComp,
-    DictUnpack,
-    EmptyNode,
-    EvaluatedObject,
-    ExceptHandler,
-    Expr,
-    For,
-    FormattedValue,
-    FunctionDef,
-    GeneratorExp,
-    Global,
-    If,
-    IfExp,
-    Import,
-    ImportFrom,
-    JoinedStr,
-    Keyword,
-    Lambda,
-    List,
-    ListComp,
-    Match,
-    MatchAs,
-    MatchCase,
-    MatchClass,
-    MatchMapping,
-    MatchOr,
-    MatchSequence,
-    MatchSingleton,
-    MatchStar,
-    MatchValue,
-    Module,
-    Name,
-    NamedExpr,
-    NodeNG,
-    Nonlocal,
-    ParamSpec,
-    Pass,
-    Raise,
-    Return,
-    Set,
-    SetComp,
-    Slice,
-    Starred,
-    Subscript,
-    Try,
-    TryStar,
-    Tuple,
-    TypeAlias,
-    TypeVar,
-    TypeVarTuple,
-    UnaryOp,
-    Unknown,
-    While,
-    With,
-    Yield,
-    YieldFrom,
+    AnnAssign as _DEPRECATED_AnnAssign,
+    Arguments as _DEPRECATED_Arguments,
+    Assert as _DEPRECATED_Assert,
+    Assign as _DEPRECATED_Assign,
+    AssignAttr as _DEPRECATED_AssignAttr,
+    AssignName as _DEPRECATED_AssignName,
+    AsyncFor as _DEPRECATED_AsyncFor,
+    AsyncFunctionDef as _DEPRECATED_AsyncFunctionDef,
+    AsyncWith as _DEPRECATED_AsyncWith,
+    Attribute as _DEPRECATED_Attribute,
+    AugAssign as _DEPRECATED_AugAssign,
+    Await as _DEPRECATED_Await,
+    BinOp as _DEPRECATED_BinOp,
+    BoolOp as _DEPRECATED_BoolOp,
+    Break as _DEPRECATED_Break,
+    Call as _DEPRECATED_Call,
+    ClassDef as _DEPRECATED_ClassDef,
+    Compare as _DEPRECATED_Compare,
+    Comprehension as _DEPRECATED_Comprehension,
+    ComprehensionScope as _DEPRECATED_ComprehensionScope,
+    Const as _DEPRECATED_Const,
+    Continue as _DEPRECATED_Continue,
+    Decorators as _DEPRECATED_Decorators,
+    DelAttr as _DEPRECATED_DelAttr,
+    Delete as _DEPRECATED_Delete,
+    DelName as _DEPRECATED_DelName,
+    Dict as _DEPRECATED_Dict,
+    DictComp as _DEPRECATED_DictComp,
+    DictUnpack as _DEPRECATED_DictUnpack,
+    EmptyNode as _DEPRECATED_EmptyNode,
+    EvaluatedObject as _DEPRECATED_EvaluatedObject,
+    ExceptHandler as _DEPRECATED_ExceptHandler,
+    Expr as _DEPRECATED_Expr,
+    For as _DEPRECATED_For,
+    FormattedValue as _DEPRECATED_FormattedValue,
+    FunctionDef as _DEPRECATED_FunctionDef,
+    GeneratorExp as _DEPRECATED_GeneratorExp,
+    Global as _DEPRECATED_Global,
+    If as _DEPRECATED_If,
+    IfExp as _DEPRECATED_IfExp,
+    Import as _DEPRECATED_Import,
+    ImportFrom as _DEPRECATED_ImportFrom,
+    Interpolation as _DEPRECATED_Interpolation,
+    JoinedStr as _DEPRECATED_JoinedStr,
+    Keyword as _DEPRECATED_Keyword,
+    Lambda as _DEPRECATED_Lambda,
+    List as _DEPRECATED_List,
+    ListComp as _DEPRECATED_ListComp,
+    Match as _DEPRECATED_Match,
+    MatchAs as _DEPRECATED_MatchAs,
+    MatchCase as _DEPRECATED_MatchCase,
+    MatchClass as _DEPRECATED_MatchClass,
+    MatchMapping as _DEPRECATED_MatchMapping,
+    MatchOr as _DEPRECATED_MatchOr,
+    MatchSequence as _DEPRECATED_MatchSequence,
+    MatchSingleton as _DEPRECATED_MatchSingleton,
+    MatchStar as _DEPRECATED_MatchStar,
+    MatchValue as _DEPRECATED_MatchValue,
+    Module as _DEPRECATED_Module,
+    Name as _DEPRECATED_Name,
+    NamedExpr as _DEPRECATED_NamedExpr,
+    NodeNG as _DEPRECATED_NodeNG,
+    Nonlocal as _DEPRECATED_Nonlocal,
+    ParamSpec as _DEPRECATED_ParamSpec,
+    Pass as _DEPRECATED_Pass,
+    Raise as _DEPRECATED_Raise,
+    Return as _DEPRECATED_Return,
+    Set as _DEPRECATED_Set,
+    SetComp as _DEPRECATED_SetComp,
+    Slice as _DEPRECATED_Slice,
+    Starred as _DEPRECATED_Starred,
+    Subscript as _DEPRECATED_Subscript,
+    TemplateStr as _DEPRECATED_TemplateStr,
+    Try as _DEPRECATED_Try,
+    TryStar as _DEPRECATED_TryStar,
+    Tuple as _DEPRECATED_Tuple,
+    TypeAlias as _DEPRECATED_TypeAlias,
+    TypeVar as _DEPRECATED_TypeVar,
+    TypeVarTuple as _DEPRECATED_TypeVarTuple,
+    UnaryOp as _DEPRECATED_UnaryOp,
+    Unknown as _DEPRECATED_Unknown,
+    While as _DEPRECATED_While,
+    With as _DEPRECATED_With,
+    Yield as _DEPRECATED_Yield,
+    YieldFrom as _DEPRECATED_YieldFrom,
     are_exclusive,
     builtin_lookup,
     unpack_infer,
@@ -176,11 +175,68 @@
 
 from astroid.util import Uninferable
 
-# Performance hack for tokenize. See https://bugs.python.org/issue43014
-# Adapted from https://github.com/PyCQA/pycodestyle/pull/993
-if (
-    not PY310_PLUS
-    and callable(getattr(tokenize, "_compile", None))
-    and getattr(tokenize._compile, "__wrapped__", None) is None  # type: ignore[attr-defined]
-):
-    tokenize._compile = functools.lru_cache(tokenize._compile)  # type: ignore[attr-defined]
+__all__ = [
+    "CONST_CLS",
+    "MANAGER",
+    "AstroidBuildingError",
+    "AstroidError",
+    "AstroidImportError",
+    "AstroidIndexError",
+    "AstroidSyntaxError",
+    "AstroidTypeError",
+    "AstroidValueError",
+    "AttributeInferenceError",
+    "BaseInstance",
+    "BoundMethod",
+    "Context",
+    "DuplicateBasesError",
+    "ExceptionInstance",
+    "InconsistentMroError",
+    "InferenceError",
+    "InferenceOverwriteError",
+    "Instance",
+    "MroError",
+    "NameInferenceError",
+    "NoDefault",
+    "NotFoundError",
+    "ParentMissingError",
+    "ResolveError",
+    "StatementMissing",
+    "SuperArgumentTypeError",
+    "SuperError",
+    "TooManyLevelsError",
+    "UnboundMethod",
+    "Uninferable",
+    "UnresolvableName",
+    "UseInferenceDefault",
+    "__version__",
+    "_inference_tip_cached",
+    "are_exclusive",
+    "builtin_lookup",
+    "extract_node",
+    "function_to_method",
+    "inference_tip",
+    "node_classes",
+    "parse",
+    "raw_building",
+    "register_module_extender",
+    "scoped_nodes",
+    "unpack_infer",
+    "version",
+]
+
+
+def __getattr__(name: str):
+    if (val := globals().get(f"_DEPRECATED_{name}")) is None:
+        msg = f"module '{__name__}' has no attribute '{name}"
+        raise AttributeError(msg)
+
+    # pylint: disable-next=import-outside-toplevel
+    import warnings
+
+    msg = (
+        f"importing '{name}' from 'astroid' is deprecated and will be removed in v5, "
+        "import it from 'astroid.nodes' instead"
+    )
+    warnings.warn(msg, DeprecationWarning, stacklevel=2)
+    return val
diff --git a/astroid/__main__.py b/astroid/__main__.py
new file mode 100644
index 0000000..90a40d6
--- /dev/null
+++ b/astroid/__main__.py
@@ -0,0 +1,54 @@
+# Licensed under the LGPL: https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html
+# For details: https://github.com/pylint-dev/astroid/blob/main/LICENSE
+# Copyright (c) https://github.com/pylint-dev/astroid/blob/main/CONTRIBUTORS.txt
+
+"""Command line interface for astroid."""
+
+from __future__ import annotations
+
+import sys
+from argparse import ArgumentParser, Namespace
+from collections.abc import Callable, Sequence
+from pathlib import Path
+from typing import cast
+
+import astroid
+
+
+class Arguments(Namespace):
+    func: Callable[[Arguments], int]
+
+
+class ASTParserArguments(Arguments):
+    file: str
+
+
+def parse_ast(args: ASTParserArguments) -> int:
+    if not ((file := Path(args.file)).is_file() and file.suffix in {".py", ".pyi"}):
+        print(f"error: '{file}' does not exist or isn't a Python file")
+        return 1
+
+    tree = astroid.parse(file.read_text(encoding="utf8"))
+    print(tree.repr_tree())
+    return 0
+
+
+def main(argv: Sequence[str] | None = None) -> int:
+    argv = argv or sys.argv[1:]
+    parser = ArgumentParser(description="Command line interface for astroid")
+    subparsers = parser.add_subparsers()
+
+    ast_parser = subparsers.add_parser("ast", help="Print astroid AST")
+    ast_parser.set_defaults(func=parse_ast)
+    ast_parser.add_argument("file", metavar="FILE", help="File to parse")
+
+    args = cast(Arguments, parser.parse_args(argv))
+    if "func" not in args:
+        parser.print_help()
+        return 2
+
+    return args.func(args)
+
+
+if __name__ == "__main__":
+    sys.exit(main())
diff --git a/astroid/__pkginfo__.py b/astroid/__pkginfo__.py
index 8af981f..a3e9cb4 100644
--- a/astroid/__pkginfo__.py
+++ b/astroid/__pkginfo__.py
@@ -2,5 +2,5 @@
 # For details: https://github.com/pylint-dev/astroid/blob/main/LICENSE
 # Copyright (c) https://github.com/pylint-dev/astroid/blob/main/CONTRIBUTORS.txt
 
-__version__ = "4.0.0dev1"
+__version__ = "4.2.0-dev0"
 version = __version__
diff --git a/astroid/_backport_stdlib_names.py b/astroid/_backport_stdlib_names.py
deleted file mode 100644
index 901f90b..0000000
--- a/astroid/_backport_stdlib_names.py
+++ /dev/null
@@ -1,352 +0,0 @@
-# Licensed under the LGPL: https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html
-# For details: https://github.com/pylint-dev/astroid/blob/main/LICENSE
-# Copyright (c) https://github.com/pylint-dev/astroid/blob/main/CONTRIBUTORS.txt
-
-"""
-Shim to support Python versions < 3.10 that don't have sys.stdlib_module_names
-
-These values were created by cherry-picking the commits from
-https://bugs.python.org/issue42955 into each version, but may be updated
-manually if changes are needed.
-"""
-
-import sys
-
-# TODO: Remove this file when Python 3.9 is no longer supported
-
-PY_3_7 = frozenset(
-    {
-        "__future__",
-        "_abc",
-        "_ast",
-        "_asyncio",
-        "_bisect",
-        "_blake2",
-        "_bootlocale",
-        "_bz2",
-        "_codecs",
-        "_codecs_cn",
-        "_codecs_hk",
-        "_codecs_iso2022",
-        "_codecs_jp",
-        "_codecs_kr",
-        "_codecs_tw",
-        "_collections",
-        "_collections_abc",
-        "_compat_pickle",
-        "_compression",
-        "_contextvars",
-        "_crypt",
-        "_csv",
-        "_ctypes",
-        "_curses",
-        "_curses_panel",
-        "_datetime",
-        "_dbm",
-        "_decimal",
-        "_dummy_thread",
-        "_elementtree",
-        "_functools",
-        "_gdbm",
-        "_hashlib",
-        "_heapq",
-        "_imp",
-        "_io",
-        "_json",
-        "_locale",
-        "_lsprof",
-        "_lzma",
-        "_markupbase",
-        "_md5",
-        "_msi",
-        "_multibytecodec",
-        "_multiprocessing",
-        "_opcode",
-        "_operator",
-        "_osx_support",
-        "_pickle",
-        "_posixsubprocess",
-        "_py_abc",
-        "_pydecimal",
-        "_pyio",
-        "_queue",
-        "_random",
-        "_sha1",
-        "_sha256",
-        "_sha3",
-        "_sha512",
-        "_signal",
-        "_sitebuiltins",
-        "_socket",
-        "_sqlite3",
-        "_sre",
-        "_ssl",
-        "_stat",
-        "_string",
-        "_strptime",
-        "_struct",
-        "_symtable",
-        "_thread",
-        "_threading_local",
-        "_tkinter",
-        "_tracemalloc",
-        "_uuid",
-        "_warnings",
-        "_weakref",
-        "_weakrefset",
-        "_winapi",
-        "abc",
-        "aifc",
-        "antigravity",
-        "argparse",
-        "array",
-        "ast",
-        "asynchat",
-        "asyncio",
-        "asyncore",
-        "atexit",
-        "audioop",
-        "base64",
-        "bdb",
-        "binascii",
-        "binhex",
-        "bisect",
-        "builtins",
-        "bz2",
-        "cProfile",
-        "calendar",
-        "cgi",
-        "cgitb",
-        "chunk",
-        "cmath",
-        "cmd",
-        "code",
-        "codecs",
-        "codeop",
-        "collections",
-        "colorsys",
-        "compileall",
-        "concurrent",
-        "configparser",
-        "contextlib",
-        "contextvars",
-        "copy",
-        "copyreg",
-        "crypt",
-        "csv",
-        "ctypes",
-        "curses",
-        "dataclasses",
-        "datetime",
-        "dbm",
-        "decimal",
-        "difflib",
-        "dis",
-        "distutils",
-        "doctest",
-        "dummy_threading",
-        "email",
-        "encodings",
-        "ensurepip",
-        "enum",
-        "errno",
-        "faulthandler",
-        "fcntl",
-        "filecmp",
-        "fileinput",
-        "fnmatch",
-        "formatter",
-        "fractions",
-        "ftplib",
-        "functools",
-        "gc",
-        "genericpath",
-        "getopt",
-        "getpass",
-        "gettext",
-        "glob",
-        "grp",
-        "gzip",
-        "hashlib",
-        "heapq",
-        "hmac",
-        "html",
-        "http",
-        "idlelib",
-        "imaplib",
-        "imghdr",
-        "imp",
-        "importlib",
-        "inspect",
-        "io",
-        "ipaddress",
-        "itertools",
-        "json",
-        "keyword",
-        "lib2to3",
-        "linecache",
-        "locale",
-        "logging",
-        "lzma",
-        "macpath",
-        "mailbox",
-        "mailcap",
-        "marshal",
-        "math",
-        "mimetypes",
-        "mmap",
-        "modulefinder",
-        "msilib",
-        "msvcrt",
-        "multiprocessing",
-        "netrc",
-        "nis",
-        "nntplib",
-        "nt",
-        "ntpath",
-        "nturl2path",
-        "numbers",
-        "opcode",
-        "operator",
-        "optparse",
-        "os",
-        "ossaudiodev",
-        "parser",
-        "pathlib",
-        "pdb",
-        "pickle",
-        "pickletools",
-        "pipes",
-        "pkgutil",
-        "platform",
-        "plistlib",
-        "poplib",
-        "posix",
-        "posixpath",
-        "pprint",
-        "profile",
-        "pstats",
-        "pty",
-        "pwd",
-        "py_compile",
-        "pyclbr",
-        "pydoc",
-        "pydoc_data",
-        "pyexpat",
-        "queue",
-        "quopri",
-        "random",
-        "re",
-        "readline",
-        "reprlib",
-        "resource",
-        "rlcompleter",
-        "runpy",
-        "sched",
-        "secrets",
-        "select",
-        "selectors",
-        "shelve",
-        "shlex",
-        "shutil",
-        "signal",
-        "site",
-        "smtpd",
-        "smtplib",
-        "sndhdr",
-        "socket",
-        "socketserver",
-        "spwd",
-        "sqlite3",
-        "sre_compile",
-        "sre_constants",
-        "sre_parse",
-        "ssl",
-        "stat",
-        "statistics",
-        "string",
-        "stringprep",
-        "struct",
-        "subprocess",
-        "sunau",
-        "symbol",
-        "symtable",
-        "sys",
-        "sysconfig",
-        "syslog",
-        "tabnanny",
-        "tarfile",
-        "telnetlib",
-        "tempfile",
-        "termios",
-        "textwrap",
-        "this",
-        "threading",
-        "time",
-        "timeit",
-        "tkinter",
-        "token",
-        "tokenize",
-        "trace",
-        "traceback",
-        "tracemalloc",
-        "tty",
-        "turtle",
-        "turtledemo",
-        "types",
-        "typing",
-        "unicodedata",
-        "unittest",
-        "urllib",
-        "uu",
-        "uuid",
-        "venv",
-        "warnings",
-        "wave",
-        "weakref",
-        "webbrowser",
-        "winreg",
-        "winsound",
-        "wsgiref",
-        "xdrlib",
-        "xml",
-        "xmlrpc",
-        "zipapp",
-        "zipfile",
-        "zipimport",
-        "zlib",
-    }
-)
-
-PY_3_8 = frozenset(
-    PY_3_7
-    - {
-        "macpath",
-    }
-    | {
-        "_posixshmem",
-        "_statistics",
-        "_xxsubinterpreters",
-    }
-)
-
-PY_3_9 = frozenset(
-    PY_3_8
-    - {
-        "_dummy_thread",
-        "dummy_threading",
-    }
-    | {
-        "_aix_support",
-        "_bootsubprocess",
-        "_peg_parser",
-        "_zoneinfo",
-        "graphlib",
-        "zoneinfo",
-    }
-)
-
-if sys.version_info[:2] == (3, 9):
-    stdlib_module_names = PY_3_9
-else:
-    raise AssertionError("This module is only intended as a backport for Python <= 3.9")
diff --git a/astroid/bases.py b/astroid/bases.py
index d91a4c9..b7fd80c 100644
--- a/astroid/bases.py
+++ b/astroid/bases.py
@@ -5,6 +5,7 @@
 """This module contains base classes and functions for the nodes and some
 inference utils.
 """
+
 from __future__ import annotations
 
 import collections
@@ -13,7 +14,7 @@
 from typing import TYPE_CHECKING, Any, Literal
 
 from astroid import decorators, nodes
-from astroid.const import PY310_PLUS
+from astroid.const import PY311_PLUS
 from astroid.context import (
     CallContext,
     InferenceContext,
@@ -38,8 +39,9 @@
     from astroid.constraint import Constraint
 
 
-PROPERTIES = {"builtins.property", "abc.abstractproperty"}
-if PY310_PLUS:
+PROPERTIES = {"builtins.property", "abc.abstractproperty", "functools.cached_property"}
+# enum.property was added in Python 3.11
+if PY311_PLUS:
     PROPERTIES.add("enum.property")
 
 # List of possible property names. We use this list in order
@@ -79,24 +81,30 @@
     if any(name in stripped for name in POSSIBLE_PROPERTIES):
         return True
 
-    # Lookup for subclasses of *property*
     if not meth.decorators:
         return False
+    # Lookup for subclasses of *property*
     for decorator in meth.decorators.nodes or ():
         inferred = safe_infer(decorator, context=context)
         if inferred is None or isinstance(inferred, UninferableBase):
             continue
         if isinstance(inferred, nodes.ClassDef):
+            # Check for a class which inherits from a standard property type
+            if any(inferred.is_subtype_of(pclass) for pclass in PROPERTIES):
+                return True
             for base_class in inferred.bases:
-                if not isinstance(base_class, nodes.Name):
+                # Check for a class which inherits from functools.cached_property
+                # and includes a subscripted type annotation
+                if isinstance(base_class, nodes.Subscript):
+                    value = safe_infer(base_class.value, context=context)
+                    if not isinstance(value, nodes.ClassDef):
+                        continue
+                    if value.name != "cached_property":
+                        continue
+                    module, _ = value.lookup(value.name)
+                    if isinstance(module, nodes.Module) and module.name == "functools":
+                        return True
                     continue
-                module, _ = base_class.lookup(base_class.name)
-                if (
-                    isinstance(module, nodes.Module)
-                    and module.name == "builtins"
-                    and base_class.name == "property"
-                ):
-                    return True
 
     return False
 
@@ -243,7 +251,9 @@
             values = self._proxied.instance_attr(name, context)
         except AttributeInferenceError as exc:
             if self.special_attributes and name in self.special_attributes:
-                return [self.special_attributes.lookup(name)]
+                special_attr = self.special_attributes.lookup(name)
+                if not isinstance(special_attr, nodes.Unknown):
+                    return [special_attr]
 
             if lookupclass:
                 # Class attributes not available through the instance
@@ -452,14 +462,18 @@
 
     def getattr(self, name: str, context: InferenceContext | None = None):
         if name in self.special_attributes:
-            return [self.special_attributes.lookup(name)]
+            special_attr = self.special_attributes.lookup(name)
+            if not isinstance(special_attr, nodes.Unknown):
+                return [special_attr]
         return self._proxied.getattr(name, context)
 
     def igetattr(
         self, name: str, context: InferenceContext | None = None
     ) -> Iterator[InferenceResult]:
         if name in self.special_attributes:
-            return iter((self.special_attributes.lookup(name),))
+            special_attr = self.special_attributes.lookup(name)
+            if not isinstance(special_attr, nodes.Unknown):
+                return iter((special_attr,))
         return self._proxied.igetattr(name, context)
 
     def infer_call_result(
@@ -532,9 +546,13 @@
         self,
         proxy: nodes.FunctionDef | nodes.Lambda | UnboundMethod,
         bound: SuccessfulInferenceResult,
+        original_caller: SuccessfulInferenceResult | None = None,
     ) -> None:
         super().__init__(proxy)
         self.bound = bound
+        # For super() calls: the actual instance/class that called super()
+        # Used to correctly infer return type of methods returning Self
+        self.original_caller = original_caller
 
     def implicit_parameters(self) -> Literal[0, 1]:
         if self.name == "__new__":
@@ -564,10 +582,14 @@
             raise InferenceError(context=context) from e
         if not isinstance(mcs, nodes.ClassDef):
             # Not a valid first argument.
-            return None
+            raise InferenceError(
+                "type.__new__() requires a class for metaclass", context=context
+            )
         if not mcs.is_subtype_of("builtins.type"):
             # Not a valid metaclass.
-            return None
+            raise InferenceError(
+                "type.__new__() metaclass must be a subclass of type", context=context
+            )
 
         # Verify the name
         try:
@@ -576,10 +598,14 @@
             raise InferenceError(context=context) from e
         if not isinstance(name, nodes.Const):
             # Not a valid name, needs to be a const.
-            return None
+            raise InferenceError(
+                "type.__new__() requires a constant for name", context=context
+            )
         if not isinstance(name.value, str):
             # Needs to be a string.
-            return None
+            raise InferenceError(
+                "type.__new__() requires a string for name", context=context
+            )
 
         # Verify the bases
         try:
@@ -588,14 +614,18 @@
             raise InferenceError(context=context) from e
         if not isinstance(bases, nodes.Tuple):
             # Needs to be a tuple.
-            return None
+            raise InferenceError(
+                "type.__new__() requires a tuple for bases", context=context
+            )
         try:
             inferred_bases = [next(elt.infer(context=context)) for elt in bases.elts]
         except StopIteration as e:
             raise InferenceError(context=context) from e
         if any(not isinstance(base, nodes.ClassDef) for base in inferred_bases):
             # All the bases needs to be Classes
-            return None
+            raise InferenceError(
+                "type.__new__() requires classes for bases", context=context
+            )
 
         # Verify the attributes.
         try:
@@ -604,7 +634,9 @@
             raise InferenceError(context=context) from e
         if not isinstance(attrs, nodes.Dict):
             # Needs to be a dictionary.
-            return None
+            raise InferenceError(
+                "type.__new__() requires a dict for attrs", context=context
+            )
         cls_locals: dict[str, list[InferenceResult]] = collections.defaultdict(list)
         for key, value in attrs.items:
             try:
@@ -651,15 +683,21 @@
         caller: SuccessfulInferenceResult | None,
         context: InferenceContext | None = None,
     ) -> Iterator[InferenceResult]:
-        context = bind_context_to_node(context, self.bound)
+        # For super() calls, use original_caller to correctly infer Self return type
+        bound_node = self.original_caller if self.original_caller else self.bound
+        context = bind_context_to_node(context, bound_node)
         if (
             isinstance(self.bound, nodes.ClassDef)
             and self.bound.name == "type"
             and self.name == "__new__"
             and isinstance(caller, nodes.Call)
-            and len(caller.args) == 4
         ):
             # Check if we have a ``type.__new__(mcs, name, bases, attrs)`` call.
+            if len(caller.args) != 4:
+                raise InferenceError(
+                    f"type.__new__() requires 4 arguments, got {len(caller.args)}",
+                    context=context,
+                )
             new_cls = self._infer_type_new_call(caller, context)
             if new_cls:
                 return iter((new_cls,))
diff --git a/astroid/brain/brain_attrs.py b/astroid/brain/brain_attrs.py
index 23ec9f6..9d7e7b5 100644
--- a/astroid/brain/brain_attrs.py
+++ b/astroid/brain/brain_attrs.py
@@ -8,9 +8,10 @@
 Without this hook pylint reports unsupported-assignment-operation
 for attrs classes
 """
+
+from astroid import nodes
+from astroid.brain.helpers import is_class_var
 from astroid.manager import AstroidManager
-from astroid.nodes.node_classes import AnnAssign, Assign, AssignName, Call, Unknown
-from astroid.nodes.scoped_nodes import ClassDef
 from astroid.util import safe_infer
 
 ATTRIB_NAMES = frozenset(
@@ -50,7 +51,7 @@
     if not node.decorators:
         return False
     for decorator_attribute in node.decorators.nodes:
-        if isinstance(decorator_attribute, Call):  # decorator with arguments
+        if isinstance(decorator_attribute, nodes.Call):  # decorator with arguments
             decorator_attribute = decorator_attribute.func
         if decorator_attribute.as_string() in decorator_names:
             return True
@@ -61,35 +62,42 @@
     return False
 
 
-def attr_attributes_transform(node: ClassDef) -> None:
+def attr_attributes_transform(node: nodes.ClassDef) -> None:
     """Given that the ClassNode has an attr decorator,
     rewrite class attributes as instance attributes
     """
     # Astroid can't infer this attribute properly
     # Prevents https://github.com/pylint-dev/pylint/issues/1884
-    node.locals["__attrs_attrs__"] = [Unknown(parent=node)]
+    node.locals["__attrs_attrs__"] = [nodes.Unknown(parent=node)]
 
     use_bare_annotations = is_decorated_with_attrs(node, NEW_ATTRS_NAMES)
     for cdef_body_node in node.body:
-        if not isinstance(cdef_body_node, (Assign, AnnAssign)):
+        if not isinstance(cdef_body_node, (nodes.Assign, nodes.AnnAssign)):
             continue
-        if isinstance(cdef_body_node.value, Call):
+        if isinstance(cdef_body_node.value, nodes.Call):
             if cdef_body_node.value.func.as_string() not in ATTRIB_NAMES:
                 continue
         elif not use_bare_annotations:
             continue
+
+        # Skip attributes that are explicitly annotated as class variables
+        if isinstance(cdef_body_node, nodes.AnnAssign) and is_class_var(
+            cdef_body_node.annotation
+        ):
+            continue
+
         targets = (
             cdef_body_node.targets
             if hasattr(cdef_body_node, "targets")
             else [cdef_body_node.target]
         )
         for target in targets:
-            rhs_node = Unknown(
+            rhs_node = nodes.Unknown(
                 lineno=cdef_body_node.lineno,
                 col_offset=cdef_body_node.col_offset,
                 parent=cdef_body_node,
             )
-            if isinstance(target, AssignName):
+            if isinstance(target, nodes.AssignName):
                 # Could be a subscript if the code analysed is
                 # i = Optional[str] = ""
                 # See https://github.com/pylint-dev/pylint/issues/4439
@@ -99,5 +107,5 @@
 
 def register(manager: AstroidManager) -> None:
     manager.register_transform(
-        ClassDef, attr_attributes_transform, is_decorated_with_attrs
+        nodes.ClassDef, attr_attributes_transform, is_decorated_with_attrs
     )
diff --git a/astroid/brain/brain_builtin_inference.py b/astroid/brain/brain_builtin_inference.py
index a56b152..a2ca955 100644
--- a/astroid/brain/brain_builtin_inference.py
+++ b/astroid/brain/brain_builtin_inference.py
@@ -9,7 +9,7 @@
 import itertools
 from collections.abc import Callable, Iterable, Iterator
 from functools import partial
-from typing import TYPE_CHECKING, Any, NoReturn, Union, cast
+from typing import TYPE_CHECKING, Any, NoReturn, cast
 
 from astroid import arguments, helpers, nodes, objects, util
 from astroid.builder import AstroidBuilder
@@ -33,26 +33,13 @@
 if TYPE_CHECKING:
     from astroid.bases import Instance
 
-ContainerObjects = Union[
-    objects.FrozenSet,
-    objects.DictItems,
-    objects.DictKeys,
-    objects.DictValues,
-]
+ContainerObjects = (
+    objects.FrozenSet | objects.DictItems | objects.DictKeys | objects.DictValues
+)
 
-BuiltContainers = Union[
-    type[tuple],
-    type[list],
-    type[set],
-    type[frozenset],
-]
+BuiltContainers = type[tuple] | type[list] | type[set] | type[frozenset]
 
-CopyResult = Union[
-    nodes.Dict,
-    nodes.List,
-    nodes.Set,
-    objects.FrozenSet,
-]
+CopyResult = nodes.Dict | nodes.List | nodes.Set | objects.FrozenSet
 
 OBJECT_DUNDER_NEW = "object.__new__"
 
@@ -282,7 +269,7 @@
     if isinstance(arg, klass):
         return arg
     if isinstance(arg, iterables):
-        arg = cast(Union[nodes.BaseContainer, ContainerObjects], arg)
+        arg = cast((nodes.BaseContainer | ContainerObjects), arg)
         if all(isinstance(elt, nodes.Const) for elt in arg.elts):
             elts = [cast(nodes.Const, elt).value for elt in arg.elts]
         else:
@@ -769,12 +756,14 @@
     except (InferenceError, StopIteration) as exc:
         raise UseInferenceDefault from exc
     if not isinstance(obj_type, nodes.ClassDef):
-        raise UseInferenceDefault("TypeError: arg 1 must be class")
+        raise UseInferenceDefault(
+            f"TypeError: arg 1 must be class, not {type(obj_type)!r}"
+        )
 
     # The right hand argument is the class(es) that the given
     # object is to be checked against.
     try:
-        class_container = _class_or_tuple_to_container(
+        class_container = helpers.class_or_tuple_to_container(
             class_or_tuple_node, context=context
         )
     except InferenceError as exc:
@@ -809,7 +798,7 @@
     # The right hand argument is the class(es) that the given
     # obj is to be check is an instance of
     try:
-        class_container = _class_or_tuple_to_container(
+        class_container = helpers.class_or_tuple_to_container(
             class_or_tuple_node, context=context
         )
     except InferenceError as exc:
@@ -825,30 +814,6 @@
     return nodes.Const(isinstance_bool)
 
 
-def _class_or_tuple_to_container(
-    node: InferenceResult, context: InferenceContext | None = None
-) -> list[InferenceResult]:
-    # Move inferences results into container
-    # to simplify later logic
-    # raises InferenceError if any of the inferences fall through
-    try:
-        node_infer = next(node.infer(context=context))
-    except StopIteration as e:
-        raise InferenceError(node=node, context=context) from e
-    # arg2 MUST be a type or a TUPLE of types
-    # for isinstance
-    if isinstance(node_infer, nodes.Tuple):
-        try:
-            class_container = [
-                next(node.infer(context=context)) for node in node_infer.elts
-            ]
-        except StopIteration as e:
-            raise InferenceError(node=node, context=context) from e
-    else:
-        class_container = [node_infer]
-    return class_container
-
-
 def infer_len(node, context: InferenceContext | None = None) -> nodes.Const:
     """Infer length calls.
 
@@ -1009,7 +974,7 @@
 
 def _is_str_format_call(node: nodes.Call) -> bool:
     """Catch calls to str.format()."""
-    if not isinstance(node.func, nodes.Attribute) or not node.func.attrname == "format":
+    if not (isinstance(node.func, nodes.Attribute) and node.func.attrname == "format"):
         return False
 
     if isinstance(node.func.expr, nodes.Name):
@@ -1029,8 +994,9 @@
 
     value: nodes.Const
     if isinstance(node.func.expr, nodes.Name):
-        if not (inferred := util.safe_infer(node.func.expr)) or not isinstance(
-            inferred, nodes.Const
+        if not (
+            (inferred := util.safe_infer(node.func.expr))
+            and isinstance(inferred, nodes.Const)
         ):
             return iter([util.Uninferable])
         value = inferred
diff --git a/astroid/brain/brain_collections.py b/astroid/brain/brain_collections.py
index 94944e6..393bc60 100644
--- a/astroid/brain/brain_collections.py
+++ b/astroid/brain/brain_collections.py
@@ -19,17 +19,13 @@
 
 
 def _collections_transform():
-    return parse(
-        """
+    return parse("""
     class defaultdict(dict):
         default_factory = None
         def __missing__(self, key): pass
         def __getitem__(self, key): return default_factory
 
-    """
-        + _deque_mock()
-        + _ordered_dict_mock()
-    )
+    """ + _deque_mock() + _ordered_dict_mock())
 
 
 def _collections_abc_313_transform() -> nodes.Module:
diff --git a/astroid/brain/brain_crypt.py b/astroid/brain/brain_crypt.py
index 71f9dfc..92d30b9 100644
--- a/astroid/brain/brain_crypt.py
+++ b/astroid/brain/brain_crypt.py
@@ -9,8 +9,7 @@
 
 
 def _re_transform() -> nodes.Module:
-    return parse(
-        """
+    return parse("""
     from collections import namedtuple
     _Method = namedtuple('_Method', 'name ident salt_chars total_size')
 
@@ -19,8 +18,7 @@
     METHOD_BLOWFISH = _Method('BLOWFISH', 2, 'b', 22)
     METHOD_MD5 = _Method('MD5', '1', 8, 34)
     METHOD_CRYPT = _Method('CRYPT', None, 2, 13)
-    """
-    )
+    """)
 
 
 def register(manager: AstroidManager) -> None:
diff --git a/astroid/brain/brain_ctypes.py b/astroid/brain/brain_ctypes.py
index 8ae10bc..9d2e163 100644
--- a/astroid/brain/brain_ctypes.py
+++ b/astroid/brain/brain_ctypes.py
@@ -10,6 +10,7 @@
 Thus astroid doesn't know that the value member is a builtin type
 among float, int, bytes or str.
 """
+
 import sys
 
 from astroid import nodes
@@ -56,26 +57,22 @@
         ("c_wchar", "str", "u"),
     )
 
-    src = [
-        """
+    src = ["""
 from _ctypes import _SimpleCData
 
 class c_bool(_SimpleCData):
     def __init__(self, value):
         self.value = True
         self._type_ = '?'
-    """
-    ]
+    """]
 
     for c_type, builtin_type, type_code in c_class_to_type:
-        src.append(
-            f"""
+        src.append(f"""
 class {c_type}(_SimpleCData):
     def __init__(self, value):
         self.value = {builtin_type}(value)
         self._type_ = '{type_code}'
-        """
-        )
+        """)
 
     return parse("\n".join(src))
 
diff --git a/astroid/brain/brain_curses.py b/astroid/brain/brain_curses.py
index 5824fd7..5055ec4 100644
--- a/astroid/brain/brain_curses.py
+++ b/astroid/brain/brain_curses.py
@@ -9,8 +9,7 @@
 
 
 def _curses_transform() -> nodes.Module:
-    return parse(
-        """
+    return parse("""
     A_ALTCHARSET = 1
     A_BLINK = 1
     A_BOLD = 1
@@ -177,8 +176,7 @@
     COLOR_RED = 1
     COLOR_WHITE = 1
     COLOR_YELLOW = 1
-        """
-    )
+        """)
 
 
 def register(manager: AstroidManager) -> None:
diff --git a/astroid/brain/brain_dataclasses.py b/astroid/brain/brain_dataclasses.py
index 92d983e..b6b1956 100644
--- a/astroid/brain/brain_dataclasses.py
+++ b/astroid/brain/brain_dataclasses.py
@@ -15,22 +15,28 @@
 from __future__ import annotations
 
 from collections.abc import Iterator
-from typing import Literal, Union
+from typing import Literal
 
 from astroid import bases, context, nodes
+from astroid.brain.helpers import is_class_var
 from astroid.builder import parse
-from astroid.const import PY310_PLUS, PY313_PLUS
-from astroid.exceptions import AstroidSyntaxError, InferenceError, UseInferenceDefault
+from astroid.const import PY313_PLUS
+from astroid.exceptions import (
+    AstroidSyntaxError,
+    InferenceError,
+    MroError,
+    UseInferenceDefault,
+)
 from astroid.inference_tip import inference_tip
 from astroid.manager import AstroidManager
 from astroid.typing import InferenceResult
 from astroid.util import Uninferable, UninferableBase, safe_infer
 
-_FieldDefaultReturn = Union[
-    None,
-    tuple[Literal["default"], nodes.NodeNG],
-    tuple[Literal["default_factory"], nodes.Call],
-]
+_FieldDefaultReturn = (
+    None
+    | tuple[Literal["default"], nodes.NodeNG]
+    | tuple[Literal["default_factory"], nodes.Call]
+)
 
 DATACLASSES_DECORATORS = frozenset(("dataclass",))
 FIELD_NAME = "field"
@@ -44,7 +50,7 @@
     node: nodes.ClassDef, decorator_names: frozenset[str] = DATACLASSES_DECORATORS
 ) -> bool:
     """Return True if a decorated node has a `dataclass` decorator applied."""
-    if not isinstance(node, nodes.ClassDef) or not node.decorators:
+    if not (isinstance(node, nodes.ClassDef) and node.decorators):
         return False
 
     return any(
@@ -53,7 +59,7 @@
     )
 
 
-def dataclass_transform(node: nodes.ClassDef) -> None:
+def dataclass_transform(node: nodes.ClassDef) -> nodes.ClassDef | None:
     """Rewrite a dataclass to be easily understood by pylint."""
     node.is_dataclass = True
 
@@ -69,17 +75,17 @@
         node.instance_attrs[name] = [rhs_node]
 
     if not _check_generate_dataclass_init(node):
-        return
+        return None
 
     kw_only_decorated = False
-    if PY310_PLUS and node.decorators.nodes:
+    if node.decorators.nodes:
         for decorator in node.decorators.nodes:
             if not isinstance(decorator, nodes.Call):
                 kw_only_decorated = False
                 break
             for keyword in decorator.keywords:
                 if keyword.arg == "kw_only":
-                    kw_only_decorated = keyword.value.bool_value()
+                    kw_only_decorated = keyword.value.bool_value() is True
 
     init_str = _generate_dataclass_init(
         node,
@@ -101,6 +107,7 @@
             new_assign = parse(f"{DEFAULT_FACTORY} = object()").body[0]
             new_assign.parent = root
             root.locals[DEFAULT_FACTORY] = [new_assign.targets[0]]
+    return node
 
 
 def _get_dataclass_attributes(
@@ -111,13 +118,14 @@
     If init is True, also include InitVars.
     """
     for assign_node in node.body:
-        if not isinstance(assign_node, nodes.AnnAssign) or not isinstance(
-            assign_node.target, nodes.AssignName
+        if not (
+            isinstance(assign_node, nodes.AnnAssign)
+            and isinstance(assign_node.target, nodes.AssignName)
         ):
             continue
 
         # Annotation is never None
-        if _is_class_var(assign_node.annotation):  # type: ignore[arg-type]
+        if is_class_var(assign_node.annotation):  # type: ignore[arg-type]
             continue
 
         if _is_keyword_only_sentinel(assign_node.annotation):
@@ -155,7 +163,7 @@
     # Check for keyword arguments of the form init=False
     return not any(
         keyword.arg == "init"
-        and not keyword.value.bool_value()  # type: ignore[union-attr] # value is never None
+        and keyword.value.bool_value() is False  # type: ignore[union-attr] # value is never None
         for keyword in found.keywords
     )
 
@@ -171,7 +179,12 @@
     # See TODO down below
     # all_have_defaults = True
 
-    for base in reversed(node.mro()):
+    try:
+        mro = node.mro()
+    except MroError:
+        return pos_only_store, kw_only_store
+
+    for base in reversed(mro):
         if not base.is_dataclass:
             continue
         try:
@@ -221,7 +234,12 @@
 
 def _get_previous_field_default(node: nodes.ClassDef, name: str) -> nodes.NodeNG | None:
     """Get the default value of a previously defined field."""
-    for base in reversed(node.mro()):
+    try:
+        mro = node.mro()
+    except MroError:
+        return None
+
+    for base in reversed(mro):
         if not base.is_dataclass:
             continue
         if name in base.locals:
@@ -271,7 +289,7 @@
         if is_field:
             # Skip any fields that have `init=False`
             if any(
-                keyword.arg == "init" and not keyword.value.bool_value()
+                keyword.arg == "init" and (keyword.value.bool_value() is False)
                 for keyword in value.keywords  # type: ignore[union-attr] # value is never None
             ):
                 # Also remove the name from the previous arguments to be inserted later
@@ -341,7 +359,7 @@
         if is_field:
             kw_only = [k for k in value.keywords if k.arg == "kw_only"]  # type: ignore[union-attr]
             if kw_only:
-                if kw_only[0].value.bool_value():
+                if kw_only[0].value.bool_value() is True:
                     kw_only_params.append(param_str)
                 else:
                     params.append(param_str)
@@ -550,20 +568,8 @@
     return None
 
 
-def _is_class_var(node: nodes.NodeNG) -> bool:
-    """Return True if node is a ClassVar, with or without subscripting."""
-    try:
-        inferred = next(node.infer())
-    except (InferenceError, StopIteration):
-        return False
-
-    return getattr(inferred, "name", "") == "ClassVar"
-
-
 def _is_keyword_only_sentinel(node: nodes.NodeNG) -> bool:
     """Return True if node is the KW_ONLY sentinel."""
-    if not PY310_PLUS:
-        return False
     inferred = safe_infer(node)
     return (
         isinstance(inferred, bases.Instance)
diff --git a/astroid/brain/brain_dateutil.py b/astroid/brain/brain_dateutil.py
index c27343f..b6452d2 100644
--- a/astroid/brain/brain_dateutil.py
+++ b/astroid/brain/brain_dateutil.py
@@ -13,15 +13,11 @@
 
 
 def dateutil_transform() -> nodes.Module:
-    return AstroidBuilder(AstroidManager()).string_build(
-        textwrap.dedent(
-            """
+    return AstroidBuilder(AstroidManager()).string_build(textwrap.dedent("""
     import datetime
     def parse(timestr, parserinfo=None, **kwargs):
         return datetime.datetime()
-    """
-        )
-    )
+    """))
 
 
 def register(manager: AstroidManager) -> None:
diff --git a/astroid/brain/brain_functools.py b/astroid/brain/brain_functools.py
index c11b856..4af3d4f 100644
--- a/astroid/brain/brain_functools.py
+++ b/astroid/brain/brain_functools.py
@@ -17,8 +17,6 @@
 from astroid.inference_tip import inference_tip
 from astroid.interpreter import objectmodel
 from astroid.manager import AstroidManager
-from astroid.nodes.node_classes import AssignName, Attribute, Call, Name
-from astroid.nodes.scoped_nodes import FunctionDef
 from astroid.typing import InferenceResult, SuccessfulInferenceResult
 from astroid.util import UninferableBase, safe_infer
 
@@ -38,12 +36,10 @@
 
     @property
     def attr_cache_info(self):
-        cache_info = extract_node(
-            """
+        cache_info = extract_node("""
         from functools import _CacheInfo
         _CacheInfo(0, 0, 0, 0)
-        """
-        )
+        """)
 
         class CacheInfoBoundMethod(BoundMethod):
             def infer_call_result(
@@ -92,7 +88,7 @@
         raise UseInferenceDefault from exc
     if isinstance(inferred_wrapped_function, UninferableBase):
         raise UseInferenceDefault("Cannot infer the wrapped function")
-    if not isinstance(inferred_wrapped_function, FunctionDef):
+    if not isinstance(inferred_wrapped_function, nodes.FunctionDef):
         raise UseInferenceDefault("The wrapped function is not a function")
 
     # Determine if the passed keywords into the callsite are supported
@@ -106,7 +102,9 @@
             inferred_wrapped_function.args.kwonlyargs or (),
         )
     parameter_names = {
-        param.name for param in function_parameters if isinstance(param, AssignName)
+        param.name
+        for param in function_parameters
+        if isinstance(param, nodes.AssignName)
     }
     if set(call.keyword_arguments) - parameter_names:
         raise UseInferenceDefault("wrapped function received unknown parameters")
@@ -135,23 +133,25 @@
     if not node.decorators:
         return False
     for decorator in node.decorators.nodes:
-        if not isinstance(decorator, (Attribute, Call)):
+        if not isinstance(decorator, (nodes.Attribute, nodes.Call)):
             continue
         if _looks_like_functools_member(decorator, "lru_cache"):
             return True
     return False
 
 
-def _looks_like_functools_member(node: Attribute | Call, member: str) -> bool:
+def _looks_like_functools_member(
+    node: nodes.Attribute | nodes.Call, member: str
+) -> bool:
     """Check if the given Call node is the wanted member of functools."""
-    if isinstance(node, Attribute):
+    if isinstance(node, nodes.Attribute):
         return node.attrname == member
-    if isinstance(node.func, Name):
+    if isinstance(node.func, nodes.Name):
         return node.func.name == member
-    if isinstance(node.func, Attribute):
+    if isinstance(node.func, nodes.Attribute):
         return (
             node.func.attrname == member
-            and isinstance(node.func.expr, Name)
+            and isinstance(node.func.expr, nodes.Name)
             and node.func.expr.name == "functools"
         )
     return False
@@ -161,10 +161,12 @@
 
 
 def register(manager: AstroidManager) -> None:
-    manager.register_transform(FunctionDef, _transform_lru_cache, _looks_like_lru_cache)
+    manager.register_transform(
+        nodes.FunctionDef, _transform_lru_cache, _looks_like_lru_cache
+    )
 
     manager.register_transform(
-        Call,
+        nodes.Call,
         inference_tip(_functools_partial_inference),
         _looks_like_partial,
     )
diff --git a/astroid/brain/brain_gi.py b/astroid/brain/brain_gi.py
index fa60077..da2b0db 100644
--- a/astroid/brain/brain_gi.py
+++ b/astroid/brain/brain_gi.py
@@ -54,6 +54,35 @@
 )
 
 
+def _gi_supports_inspect_signature():
+    """
+    Indicates if pygobject supports inspect.signature().
+    """
+    import gi
+
+    try:
+        # inspect.signature() is supported since pygobject==3.51.0 (ee9558e4).
+        gi.check_version((3, 51, 0))
+        return True
+    except ValueError:
+        pass
+    return False
+
+
+def _gi_is_method_call(obj):
+    if _gi_supports_inspect_signature():
+        # Since inspect.signature() is supported, the workaround to use
+        # inspect.ismethoddescriptor() was disabled and cannot be used anymore
+        # to tell apart functions from methods.
+        # See https://github.com/pylint-dev/astroid/issues/2594
+        try:
+            sig = str(inspect.signature(obj))
+            return sig == "(self)" or sig.startswith("(self, ")
+        except Exception:  # pylint: disable=broad-except
+            return False
+    return inspect.ismethod(obj) or inspect.ismethoddescriptor(obj)
+
+
 def _gi_build_stub(parent):  # noqa: C901
     """
     Inspect the passed module recursively and build stubs for functions,
@@ -84,7 +113,7 @@
             classes[name] = obj
         elif inspect.isfunction(obj) or inspect.isbuiltin(obj):
             functions[name] = obj
-        elif inspect.ismethod(obj) or inspect.ismethoddescriptor(obj):
+        elif _gi_is_method_call(obj):
             methods[name] = obj
         elif (
             str(obj).startswith("<flags")
diff --git a/astroid/brain/brain_http.py b/astroid/brain/brain_http.py
index 3a8a858..da0d65f 100644
--- a/astroid/brain/brain_http.py
+++ b/astroid/brain/brain_http.py
@@ -3,6 +3,7 @@
 # Copyright (c) https://github.com/pylint-dev/astroid/blob/main/CONTRIBUTORS.txt
 
 """Astroid brain hints for some of the `http` module."""
+
 import textwrap
 
 from astroid import nodes
@@ -12,12 +13,22 @@
 
 
 def _http_transform() -> nodes.Module:
-    code = textwrap.dedent(
-        """
-    from enum import IntEnum
+    code = textwrap.dedent("""
+    from enum import IntEnum, StrEnum
     from collections import namedtuple
     _HTTPStatus = namedtuple('_HTTPStatus', 'value phrase description')
 
+    class HTTPMethod(StrEnum):
+        GET = "GET"
+        POST = "POST"
+        PUT = "PUT"
+        DELETE = "DELETE"
+        HEAD = "HEAD"
+        OPTIONS = "OPTIONS"
+        PATCH = "PATCH"
+        TRACE = "TRACE"
+        CONNECT = "CONNECT"
+
     class HTTPStatus(IntEnum):
 
         @property
@@ -35,6 +46,7 @@
         SWITCHING_PROTOCOLS = _HTTPStatus(101, 'Switching Protocols',
                 'Switching to new protocol; obey Upgrade header')
         PROCESSING = _HTTPStatus(102, 'Processing', '')
+        EARLY_HINTS = _HTTPStatus(103, 'Early Hints')
         OK = _HTTPStatus(200, 'OK', 'Request fulfilled, document follows')
         CREATED = _HTTPStatus(201, 'Created', 'Document created, URL follows')
         ACCEPTED = _HTTPStatus(202, 'Accepted',
@@ -87,22 +99,27 @@
             'Client must specify Content-Length')
         PRECONDITION_FAILED = _HTTPStatus(412, 'Precondition Failed',
             'Precondition in headers is false')
-        REQUEST_ENTITY_TOO_LARGE = _HTTPStatus(413, 'Request Entity Too Large',
-            'Entity is too large')
-        REQUEST_URI_TOO_LONG = _HTTPStatus(414, 'Request-URI Too Long',
-            'URI is too long')
+        CONTENT_TOO_LARGE = _HTTPStatus(413, 'Content Too Large',
+        'Content is too large')
+        REQUEST_ENTITY_TOO_LARGE = CONTENT_TOO_LARGE
+        URI_TOO_LONG = _HTTPStatus(414, 'URI Too Long', 'URI is too long')
+        REQUEST_URI_TOO_LONG = URI_TOO_LONG
         UNSUPPORTED_MEDIA_TYPE = _HTTPStatus(415, 'Unsupported Media Type',
             'Entity body in unsupported format')
-        REQUESTED_RANGE_NOT_SATISFIABLE = _HTTPStatus(416,
-            'Requested Range Not Satisfiable',
-            'Cannot satisfy request range')
+        RANGE_NOT_SATISFIABLE = (416, 'Range Not Satisfiable',
+        'Cannot satisfy request range')
+        REQUESTED_RANGE_NOT_SATISFIABLE = RANGE_NOT_SATISFIABLE
         EXPECTATION_FAILED = _HTTPStatus(417, 'Expectation Failed',
             'Expect condition could not be satisfied')
+        IM_A_TEAPOT = _HTTPStatus(418, 'I\\\'m a Teapot',
+            'Server refuses to brew coffee because it is a teapot.')
         MISDIRECTED_REQUEST = _HTTPStatus(421, 'Misdirected Request',
             'Server is not able to produce a response')
-        UNPROCESSABLE_ENTITY = _HTTPStatus(422, 'Unprocessable Entity')
+        UNPROCESSABLE_CONTENT = _HTTPStatus(422, 'Unprocessable Content')
+        UNPROCESSABLE_ENTITY = UNPROCESSABLE_CONTENT
         LOCKED = _HTTPStatus(423, 'Locked')
         FAILED_DEPENDENCY = _HTTPStatus(424, 'Failed Dependency')
+        TOO_EARLY = _HTTPStatus(425, 'Too Early')
         UPGRADE_REQUIRED = _HTTPStatus(426, 'Upgrade Required')
         PRECONDITION_REQUIRED = _HTTPStatus(428, 'Precondition Required',
             'The origin server requires the request to be conditional')
@@ -136,20 +153,18 @@
         NETWORK_AUTHENTICATION_REQUIRED = _HTTPStatus(511,
             'Network Authentication Required',
             'The client needs to authenticate to gain network access')
-    """
-    )
+    """)
     return AstroidBuilder(AstroidManager()).string_build(code)
 
 
 def _http_client_transform() -> nodes.Module:
-    return AstroidBuilder(AstroidManager()).string_build(
-        textwrap.dedent(
-            """
+    return AstroidBuilder(AstroidManager()).string_build(textwrap.dedent("""
     from http import HTTPStatus
 
     CONTINUE = HTTPStatus.CONTINUE
     SWITCHING_PROTOCOLS = HTTPStatus.SWITCHING_PROTOCOLS
     PROCESSING = HTTPStatus.PROCESSING
+    EARLY_HINTS = HTTPStatus.EARLY_HINTS
     OK = HTTPStatus.OK
     CREATED = HTTPStatus.CREATED
     ACCEPTED = HTTPStatus.ACCEPTED
@@ -181,14 +196,20 @@
     GONE = HTTPStatus.GONE
     LENGTH_REQUIRED = HTTPStatus.LENGTH_REQUIRED
     PRECONDITION_FAILED = HTTPStatus.PRECONDITION_FAILED
-    REQUEST_ENTITY_TOO_LARGE = HTTPStatus.REQUEST_ENTITY_TOO_LARGE
-    REQUEST_URI_TOO_LONG = HTTPStatus.REQUEST_URI_TOO_LONG
+    CONTENT_TOO_LARGE = HTTPStatus.CONTENT_TOO_LARGE
+    REQUEST_ENTITY_TOO_LARGE = HTTPStatus.CONTENT_TOO_LARGE
+    URI_TOO_LONG = HTTPStatus.URI_TOO_LONG
+    REQUEST_URI_TOO_LONG = HTTPStatus.URI_TOO_LONG
     UNSUPPORTED_MEDIA_TYPE = HTTPStatus.UNSUPPORTED_MEDIA_TYPE
-    REQUESTED_RANGE_NOT_SATISFIABLE = HTTPStatus.REQUESTED_RANGE_NOT_SATISFIABLE
+    RANGE_NOT_SATISFIABLE = HTTPStatus.RANGE_NOT_SATISFIABLE
+    REQUESTED_RANGE_NOT_SATISFIABLE = HTTPStatus.RANGE_NOT_SATISFIABLE
     EXPECTATION_FAILED = HTTPStatus.EXPECTATION_FAILED
-    UNPROCESSABLE_ENTITY = HTTPStatus.UNPROCESSABLE_ENTITY
+    IM_A_TEAPOT = HTTPStatus.IM_A_TEAPOT
+    UNPROCESSABLE_CONTENT = HTTPStatus.UNPROCESSABLE_CONTENT
+    UNPROCESSABLE_ENTITY = HTTPStatus.UNPROCESSABLE_CONTENT
     LOCKED = HTTPStatus.LOCKED
     FAILED_DEPENDENCY = HTTPStatus.FAILED_DEPENDENCY
+    TOO_EARLY = HTTPStatus.TOO_EARLY
     UPGRADE_REQUIRED = HTTPStatus.UPGRADE_REQUIRED
     PRECONDITION_REQUIRED = HTTPStatus.PRECONDITION_REQUIRED
     TOO_MANY_REQUESTS = HTTPStatus.TOO_MANY_REQUESTS
@@ -204,9 +225,7 @@
     LOOP_DETECTED = HTTPStatus.LOOP_DETECTED
     NOT_EXTENDED = HTTPStatus.NOT_EXTENDED
     NETWORK_AUTHENTICATION_REQUIRED = HTTPStatus.NETWORK_AUTHENTICATION_REQUIRED
-    """
-        )
-    )
+    """))
 
 
 def register(manager: AstroidManager) -> None:
diff --git a/astroid/brain/brain_hypothesis.py b/astroid/brain/brain_hypothesis.py
index ba20f06..e656bef 100644
--- a/astroid/brain/brain_hypothesis.py
+++ b/astroid/brain/brain_hypothesis.py
@@ -16,6 +16,7 @@
 
     a_strategy()
 """
+
 from astroid.manager import AstroidManager
 from astroid.nodes.scoped_nodes import FunctionDef
 
diff --git a/astroid/brain/brain_io.py b/astroid/brain/brain_io.py
index ab6e607..48fdfdf 100644
--- a/astroid/brain/brain_io.py
+++ b/astroid/brain/brain_io.py
@@ -3,6 +3,7 @@
 # Copyright (c) https://github.com/pylint-dev/astroid/blob/main/CONTRIBUTORS.txt
 
 """Astroid brain hints for some of the _io C objects."""
+
 from astroid.manager import AstroidManager
 from astroid.nodes import ClassDef
 
diff --git a/astroid/brain/brain_mechanize.py b/astroid/brain/brain_mechanize.py
index 62cc2d0..c483f25 100644
--- a/astroid/brain/brain_mechanize.py
+++ b/astroid/brain/brain_mechanize.py
@@ -9,8 +9,7 @@
 
 
 def mechanize_transform() -> nodes.Module:
-    return AstroidBuilder(AstroidManager()).string_build(
-        """class Browser(object):
+    return AstroidBuilder(AstroidManager()).string_build("""class Browser(object):
     def __getattr__(self, name):
         return None
 
@@ -117,8 +116,7 @@
 
     def visit_response(self, response, request=None):
         return None
-"""
-    )
+""")
 
 
 def register(manager: AstroidManager) -> None:
diff --git a/astroid/brain/brain_multiprocessing.py b/astroid/brain/brain_multiprocessing.py
index e6413b0..a553160 100644
--- a/astroid/brain/brain_multiprocessing.py
+++ b/astroid/brain/brain_multiprocessing.py
@@ -11,23 +11,19 @@
 
 
 def _multiprocessing_transform():
-    module = parse(
-        """
+    module = parse("""
     from multiprocessing.managers import SyncManager
     def Manager():
         return SyncManager()
-    """
-    )
+    """)
     # Multiprocessing uses a getattr lookup inside contexts,
     # in order to get the attributes they need. Since it's extremely
     # dynamic, we use this approach to fake it.
-    node = parse(
-        """
+    node = parse("""
     from multiprocessing.context import DefaultContext, BaseContext
     default = DefaultContext()
     base = BaseContext()
-    """
-    )
+    """)
     try:
         context = next(node["default"].infer())
         base = next(node["base"].infer())
@@ -49,8 +45,7 @@
 
 
 def _multiprocessing_managers_transform():
-    return parse(
-        """
+    return parse("""
     import array
     import threading
     import multiprocessing.pool as pool
@@ -95,8 +90,7 @@
             pass
         def shutdown(self):
             pass
-    """
-    )
+    """)
 
 
 def register(manager: AstroidManager) -> None:
diff --git a/astroid/brain/brain_namedtuple_enum.py b/astroid/brain/brain_namedtuple_enum.py
index 104bd97..ccefb19 100644
--- a/astroid/brain/brain_namedtuple_enum.py
+++ b/astroid/brain/brain_namedtuple_enum.py
@@ -12,7 +12,6 @@
 from textwrap import dedent
 from typing import Final
 
-import astroid
 from astroid import arguments, bases, nodes, util
 from astroid.builder import AstroidBuilder, _extract_single_node, extract_node
 from astroid.context import InferenceContext
@@ -204,9 +203,10 @@
     )
     assert isinstance(func, nodes.NodeNG)
     try:
-        rename = next(
+        rename_arg_bool_value = next(
             call_site.infer_argument(func, "rename", context or InferenceContext())
         ).bool_value()
+        rename = rename_arg_bool_value is True
     except (InferenceError, StopIteration):
         rename = False
 
@@ -226,8 +226,7 @@
         field_def.format(name=name, index=index)
         for index, name in enumerate(attributes)
     )
-    fake = AstroidBuilder(AstroidManager()).string_build(
-        f"""
+    fake = AstroidBuilder(AstroidManager()).string_build(f"""
 class {name}(tuple):
     __slots__ = ()
     _fields = {attributes!r}
@@ -241,8 +240,7 @@
     def __getnewargs__(self):
         return tuple(self)
 {field_defs}
-    """
-    )
+    """)
     class_node.locals["_asdict"] = fake.body[0].locals["_asdict"]
     class_node.locals["_make"] = fake.body[0].locals["_make"]
     class_node.locals["_replace"] = fake.body[0].locals["_replace"]
@@ -280,7 +278,9 @@
     # <snippet>
     for name in (typename, *attributes):
         if not isinstance(name, str):
-            raise AstroidTypeError("Type names and field names must be strings")
+            raise AstroidTypeError(
+                f"Type names and field names must be strings, not {type(name)!r}"
+            )
         if not name.isidentifier():
             raise AstroidValueError(
                 "Type names and field names must be valid" + f"identifiers: {name!r}"
@@ -320,8 +320,7 @@
     ):
         raise UseInferenceDefault
 
-    enum_meta = _extract_single_node(
-        """
+    enum_meta = _extract_single_node("""
     class EnumMeta(object):
         'docstring'
         def __call__(self, node):
@@ -352,8 +351,7 @@
 
             return Value()
         __members__ = ['']
-    """
-    )
+    """)
 
     # FIXME arguably, the base here shouldn't be the EnumMeta class definition
     # itself, but a reference (Name) to it. Otherwise, the invariant that all
@@ -515,8 +513,7 @@
         # For "value", we have no idea what that should be, but for "name", we at least
         # know that it should be a string, so infer that as a guess.
         if "name" not in target_names:
-            code = dedent(
-                '''
+            code = dedent('''
                 @property
                 def name(self):
                     """The name of the Enum member.
@@ -525,8 +522,7 @@
                     know 'name' should be a string, so this is astroid's best guess.
                     """
                     return ''
-                '''
-            )
+                ''')
             name_dynamicclassattr = AstroidBuilder(AstroidManager()).string_build(code)[
                 "name"
             ]
@@ -543,12 +539,10 @@
         for annassign in class_node.body
         if isinstance(annassign, nodes.AnnAssign)
     ]
-    code = dedent(
-        """
+    code = dedent("""
     from collections import namedtuple
     namedtuple({typename!r}, {fields!r})
-    """
-    ).format(typename=class_node.name, fields=",".join(annassigns_fields))
+    """).format(typename=class_node.name, fields=",".join(annassigns_fields))
     node = extract_node(code)
     try:
         generated_class_node = next(infer_named_tuple(node, context))
@@ -574,12 +568,10 @@
     The class NamedTuple is build dynamically through a call to `type` during
     initialization of the `_NamedTuple` variable.
     """
-    klass = extract_node(
-        """
+    klass = extract_node("""
         from typing import _NamedTuple
         _NamedTuple
-        """
-    )
+        """)
     return klass.infer(context)
 
 
@@ -648,7 +640,7 @@
     return field_names
 
 
-def _is_enum_subclass(cls: astroid.ClassDef) -> bool:
+def _is_enum_subclass(cls: nodes.ClassDef) -> bool:
     """Return whether cls is a subclass of an Enum."""
     return cls.is_subtype_of("enum.Enum")
 
diff --git a/astroid/brain/brain_nose.py b/astroid/brain/brain_nose.py
deleted file mode 100644
index b194414..0000000
--- a/astroid/brain/brain_nose.py
+++ /dev/null
@@ -1,79 +0,0 @@
-# Licensed under the LGPL: https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html
-# For details: https://github.com/pylint-dev/astroid/blob/main/LICENSE
-# Copyright (c) https://github.com/pylint-dev/astroid/blob/main/CONTRIBUTORS.txt
-
-"""Hooks for nose library."""
-
-import re
-import textwrap
-
-from astroid.bases import BoundMethod
-from astroid.brain.helpers import register_module_extender
-from astroid.builder import AstroidBuilder
-from astroid.exceptions import InferenceError
-from astroid.manager import AstroidManager
-from astroid.nodes import List, Module
-
-CAPITALS = re.compile("([A-Z])")
-
-
-def _pep8(name, caps=CAPITALS):
-    return caps.sub(lambda m: "_" + m.groups()[0].lower(), name)
-
-
-def _nose_tools_functions():
-    """Get an iterator of names and bound methods."""
-    module = AstroidBuilder(AstroidManager()).string_build(
-        textwrap.dedent(
-            """
-    import unittest
-
-    class Test(unittest.TestCase):
-        pass
-    a = Test()
-    """
-        )
-    )
-    try:
-        case = next(module["a"].infer())
-    except (InferenceError, StopIteration):
-        return
-    for method in case.methods():
-        if method.name.startswith("assert") and "_" not in method.name:
-            pep8_name = _pep8(method.name)
-            yield pep8_name, BoundMethod(method, case)
-        if method.name == "assertEqual":
-            # nose also exports assert_equals.
-            yield "assert_equals", BoundMethod(method, case)
-
-
-def _nose_tools_transform(node):
-    for method_name, method in _nose_tools_functions():
-        node.locals[method_name] = [method]
-
-
-def _nose_tools_trivial_transform():
-    """Custom transform for the nose.tools module."""
-    stub = AstroidBuilder(AstroidManager()).string_build("""__all__ = []""")
-    all_entries = ["ok_", "eq_"]
-
-    for pep8_name, method in _nose_tools_functions():
-        all_entries.append(pep8_name)
-        stub[pep8_name] = method
-
-    # Update the __all__ variable, since nose.tools
-    # does this manually with .append.
-    all_assign = stub["__all__"].parent
-    all_object = List(all_entries)
-    all_object.parent = all_assign
-    all_assign.value = all_object
-    return stub
-
-
-def register(manager: AstroidManager) -> None:
-    register_module_extender(
-        manager, "nose.tools.trivial", _nose_tools_trivial_transform
-    )
-    manager.register_transform(
-        Module, _nose_tools_transform, lambda n: n.name == "nose.tools"
-    )
diff --git a/astroid/brain/brain_numpy_core_einsumfunc.py b/astroid/brain/brain_numpy_core_einsumfunc.py
index b72369c..514ba83 100644
--- a/astroid/brain/brain_numpy_core_einsumfunc.py
+++ b/astroid/brain/brain_numpy_core_einsumfunc.py
@@ -14,12 +14,10 @@
 
 
 def numpy_core_einsumfunc_transform() -> nodes.Module:
-    return parse(
-        """
+    return parse("""
     def einsum(*operands, out=None, optimize=False, **kwargs):
         return numpy.ndarray([0, 0])
-    """
-    )
+    """)
 
 
 def register(manager: AstroidManager) -> None:
diff --git a/astroid/brain/brain_numpy_core_fromnumeric.py b/astroid/brain/brain_numpy_core_fromnumeric.py
index ce4173c..527700e 100644
--- a/astroid/brain/brain_numpy_core_fromnumeric.py
+++ b/astroid/brain/brain_numpy_core_fromnumeric.py
@@ -3,6 +3,7 @@
 # Copyright (c) https://github.com/pylint-dev/astroid/blob/main/CONTRIBUTORS.txt
 
 """Astroid hooks for numpy.core.fromnumeric module."""
+
 from astroid import nodes
 from astroid.brain.helpers import register_module_extender
 from astroid.builder import parse
@@ -10,12 +11,10 @@
 
 
 def numpy_core_fromnumeric_transform() -> nodes.Module:
-    return parse(
-        """
+    return parse("""
     def sum(a, axis=None, dtype=None, out=None, keepdims=None, initial=None):
         return numpy.ndarray([0, 0])
-    """
-    )
+    """)
 
 
 def register(manager: AstroidManager) -> None:
diff --git a/astroid/brain/brain_numpy_core_function_base.py b/astroid/brain/brain_numpy_core_function_base.py
index 2bfe970..b66ba5f 100644
--- a/astroid/brain/brain_numpy_core_function_base.py
+++ b/astroid/brain/brain_numpy_core_function_base.py
@@ -6,13 +6,13 @@
 
 import functools
 
+from astroid import nodes
 from astroid.brain.brain_numpy_utils import (
     attribute_name_looks_like_numpy_member,
     infer_numpy_attribute,
 )
 from astroid.inference_tip import inference_tip
 from astroid.manager import AstroidManager
-from astroid.nodes.node_classes import Attribute
 
 METHODS_TO_BE_INFERRED = {
     "linspace": """def linspace(start, stop, num=50, endpoint=True, retstep=False, dtype=None, axis=0):
@@ -26,7 +26,7 @@
 
 def register(manager: AstroidManager) -> None:
     manager.register_transform(
-        Attribute,
+        nodes.Attribute,
         inference_tip(functools.partial(infer_numpy_attribute, METHODS_TO_BE_INFERRED)),
         functools.partial(
             attribute_name_looks_like_numpy_member,
diff --git a/astroid/brain/brain_numpy_core_multiarray.py b/astroid/brain/brain_numpy_core_multiarray.py
index 95ef0a3..97af794 100644
--- a/astroid/brain/brain_numpy_core_multiarray.py
+++ b/astroid/brain/brain_numpy_core_multiarray.py
@@ -17,20 +17,17 @@
 from astroid.builder import parse
 from astroid.inference_tip import inference_tip
 from astroid.manager import AstroidManager
-from astroid.nodes.node_classes import Attribute, Name
 
 
 def numpy_core_multiarray_transform() -> nodes.Module:
-    return parse(
-        """
+    return parse("""
     # different functions defined in multiarray.py
     def inner(a, b):
         return numpy.ndarray([0, 0])
 
     def vdot(a, b):
         return numpy.ndarray([0, 0])
-        """
-    )
+        """)
 
 
 METHODS_TO_BE_INFERRED = {
@@ -40,7 +37,7 @@
             return numpy.ndarray([0, 0])""",
     "empty_like": """def empty_like(a, dtype=None, order='K', subok=True):
             return numpy.ndarray((0, 0))""",
-    "concatenate": """def concatenate(arrays, axis=None, out=None):
+    "concatenate": """def concatenate(arrays, axis=None, out=None, dtype=None, casting='same_kind'):
             return numpy.ndarray((0, 0))""",
     "where": """def where(condition, x=None, y=None):
             return numpy.ndarray([0, 0])""",
@@ -96,12 +93,12 @@
     method_names = frozenset(METHODS_TO_BE_INFERRED.keys())
 
     manager.register_transform(
-        Attribute,
+        nodes.Attribute,
         inference_tip(functools.partial(infer_numpy_attribute, METHODS_TO_BE_INFERRED)),
         functools.partial(attribute_name_looks_like_numpy_member, method_names),
     )
     manager.register_transform(
-        Name,
+        nodes.Name,
         inference_tip(functools.partial(infer_numpy_name, METHODS_TO_BE_INFERRED)),
         functools.partial(member_name_looks_like_numpy_member, method_names),
     )
diff --git a/astroid/brain/brain_numpy_core_numeric.py b/astroid/brain/brain_numpy_core_numeric.py
index 72d4cc9..10c4603 100644
--- a/astroid/brain/brain_numpy_core_numeric.py
+++ b/astroid/brain/brain_numpy_core_numeric.py
@@ -15,25 +15,20 @@
 from astroid.builder import parse
 from astroid.inference_tip import inference_tip
 from astroid.manager import AstroidManager
-from astroid.nodes.node_classes import Attribute
 
 
 def numpy_core_numeric_transform() -> nodes.Module:
-    return parse(
-        """
+    return parse("""
     # different functions defined in numeric.py
     import numpy
     def zeros_like(a, dtype=None, order='K', subok=True, shape=None): return numpy.ndarray((0, 0))
     def ones_like(a, dtype=None, order='K', subok=True, shape=None): return numpy.ndarray((0, 0))
     def full_like(a, fill_value, dtype=None, order='K', subok=True, shape=None): return numpy.ndarray((0, 0))
-        """
-    )
+        """)
 
 
-METHODS_TO_BE_INFERRED = {
-    "ones": """def ones(shape, dtype=None, order='C'):
-            return numpy.ndarray([0, 0])"""
-}
+METHODS_TO_BE_INFERRED = {"ones": """def ones(shape, dtype=None, order='C'):
+            return numpy.ndarray([0, 0])"""}
 
 
 def register(manager: AstroidManager) -> None:
@@ -42,7 +37,7 @@
     )
 
     manager.register_transform(
-        Attribute,
+        nodes.Attribute,
         inference_tip(functools.partial(infer_numpy_attribute, METHODS_TO_BE_INFERRED)),
         functools.partial(
             attribute_name_looks_like_numpy_member,
diff --git a/astroid/brain/brain_numpy_core_numerictypes.py b/astroid/brain/brain_numpy_core_numerictypes.py
index 7111c83..2ebfa42 100644
--- a/astroid/brain/brain_numpy_core_numerictypes.py
+++ b/astroid/brain/brain_numpy_core_numerictypes.py
@@ -5,6 +5,7 @@
 # TODO(hippo91) : correct the methods signature.
 
 """Astroid hooks for numpy.core.numerictypes module."""
+
 from astroid import nodes
 from astroid.brain.brain_numpy_utils import numpy_supports_type_hints
 from astroid.brain.helpers import register_module_extender
@@ -109,9 +110,7 @@
         def __class_getitem__(cls, value):
             return cls
         """
-    return parse(
-        generic_src
-        + """
+    return parse(generic_src + """
     class dtype(object):
         def __init__(self, obj, align=False, copy=False):
             self.alignment = None
@@ -255,8 +254,7 @@
     unicode_ = str_
     ushort = uint16
     void0 = void
-    """
-    )
+    """)
 
 
 def register(manager: AstroidManager) -> None:
diff --git a/astroid/brain/brain_numpy_core_umath.py b/astroid/brain/brain_numpy_core_umath.py
index a048a1c..d5701af 100644
--- a/astroid/brain/brain_numpy_core_umath.py
+++ b/astroid/brain/brain_numpy_core_umath.py
@@ -7,6 +7,7 @@
 # typecheck in `_emit_no_member` function)
 
 """Astroid hooks for numpy.core.umath module."""
+
 from astroid import nodes
 from astroid.brain.helpers import register_module_extender
 from astroid.builder import parse
@@ -18,8 +19,7 @@
         """out=None, where=True, casting='same_kind', order='K', """
         """dtype=None, subok=True"""
     )
-    return parse(
-        """
+    return parse("""
     class FakeUfunc:
         def __init__(self):
             self.__doc__ = str()
@@ -144,10 +144,7 @@
     right_shift = FakeUfuncTwoArgs()
     subtract = FakeUfuncTwoArgs()
     true_divide = FakeUfuncTwoArgs()
-    """.format(
-            opt_args=ufunc_optional_keyword_arguments
-        )
-    )
+    """.format(opt_args=ufunc_optional_keyword_arguments))
 
 
 def register(manager: AstroidManager) -> None:
diff --git a/astroid/brain/brain_numpy_ma.py b/astroid/brain/brain_numpy_ma.py
index e61acb5..24ab473 100644
--- a/astroid/brain/brain_numpy_ma.py
+++ b/astroid/brain/brain_numpy_ma.py
@@ -17,16 +17,14 @@
     :param node: node to infer
     :param context: inference context
     """
-    return parse(
-        """
+    return parse("""
     import numpy.ma
     def masked_where(condition, a, copy=True):
         return numpy.ma.masked_array(a, mask=[])
 
     def masked_invalid(a, copy=True):
         return numpy.ma.masked_array(a, mask=[])
-    """
-    )
+    """)
 
 
 def register(manager: AstroidManager) -> None:
diff --git a/astroid/brain/brain_numpy_ndarray.py b/astroid/brain/brain_numpy_ndarray.py
index 38db4e6..ad79111 100644
--- a/astroid/brain/brain_numpy_ndarray.py
+++ b/astroid/brain/brain_numpy_ndarray.py
@@ -3,14 +3,15 @@
 # Copyright (c) https://github.com/pylint-dev/astroid/blob/main/CONTRIBUTORS.txt
 
 """Astroid hooks for numpy ndarray class."""
+
 from __future__ import annotations
 
+from astroid import nodes
 from astroid.brain.brain_numpy_utils import numpy_supports_type_hints
 from astroid.builder import extract_node
 from astroid.context import InferenceContext
 from astroid.inference_tip import inference_tip
 from astroid.manager import AstroidManager
-from astroid.nodes.node_classes import Attribute
 
 
 def infer_numpy_ndarray(node, context: InferenceContext | None = None):
@@ -151,13 +152,13 @@
     return node.infer(context=context)
 
 
-def _looks_like_numpy_ndarray(node: Attribute) -> bool:
+def _looks_like_numpy_ndarray(node: nodes.Attribute) -> bool:
     return node.attrname == "ndarray"
 
 
 def register(manager: AstroidManager) -> None:
     manager.register_transform(
-        Attribute,
+        nodes.Attribute,
         inference_tip(infer_numpy_ndarray),
         _looks_like_numpy_ndarray,
     )
diff --git a/astroid/brain/brain_numpy_random_mtrand.py b/astroid/brain/brain_numpy_random_mtrand.py
index be1c957..7976f2f 100644
--- a/astroid/brain/brain_numpy_random_mtrand.py
+++ b/astroid/brain/brain_numpy_random_mtrand.py
@@ -4,6 +4,7 @@
 
 # TODO(hippo91) : correct the functions return types
 """Astroid hooks for numpy.random.mtrand module."""
+
 from astroid import nodes
 from astroid.brain.helpers import register_module_extender
 from astroid.builder import parse
@@ -11,8 +12,7 @@
 
 
 def numpy_random_mtrand_transform() -> nodes.Module:
-    return parse(
-        """
+    return parse("""
     def beta(a, b, size=None): return uninferable
     def binomial(n, p, size=None): return uninferable
     def bytes(length): return uninferable
@@ -63,8 +63,7 @@
     def wald(mean, scale, size=None): return uninferable
     def weibull(a, size=None): return uninferable
     def zipf(a, size=None): return uninferable
-    """
-    )
+    """)
 
 
 def register(manager: AstroidManager) -> None:
diff --git a/astroid/brain/brain_numpy_utils.py b/astroid/brain/brain_numpy_utils.py
index a3d4ed5..1a8f665 100644
--- a/astroid/brain/brain_numpy_utils.py
+++ b/astroid/brain/brain_numpy_utils.py
@@ -6,9 +6,9 @@
 
 from __future__ import annotations
 
+from astroid import nodes
 from astroid.builder import extract_node
 from astroid.context import InferenceContext
-from astroid.nodes.node_classes import Attribute, Import, Name
 
 # Class subscript is available in numpy starting with version 1.20.0
 NUMPY_VERSION_TYPE_HINTS_SUPPORT = ("1", "20", "0")
@@ -35,20 +35,22 @@
 
 
 def infer_numpy_name(
-    sources: dict[str, str], node: Name, context: InferenceContext | None = None
+    sources: dict[str, str], node: nodes.Name, context: InferenceContext | None = None
 ):
     extracted_node = extract_node(sources[node.name])
     return extracted_node.infer(context=context)
 
 
 def infer_numpy_attribute(
-    sources: dict[str, str], node: Attribute, context: InferenceContext | None = None
+    sources: dict[str, str],
+    node: nodes.Attribute,
+    context: InferenceContext | None = None,
 ):
     extracted_node = extract_node(sources[node.attrname])
     return extracted_node.infer(context=context)
 
 
-def _is_a_numpy_module(node: Name) -> bool:
+def _is_a_numpy_module(node: nodes.Name) -> bool:
     """
     Returns True if the node is a representation of a numpy module.
 
@@ -62,7 +64,7 @@
     """
     module_nickname = node.name
     potential_import_target = [
-        x for x in node.lookup(module_nickname)[1] if isinstance(x, Import)
+        x for x in node.lookup(module_nickname)[1] if isinstance(x, nodes.Import)
     ]
     return any(
         ("numpy", module_nickname) in target.names or ("numpy", None) in target.names
@@ -71,7 +73,7 @@
 
 
 def member_name_looks_like_numpy_member(
-    member_names: frozenset[str], node: Name
+    member_names: frozenset[str], node: nodes.Name
 ) -> bool:
     """
     Returns True if the Name node's name matches a member name from numpy
@@ -80,13 +82,13 @@
 
 
 def attribute_name_looks_like_numpy_member(
-    member_names: frozenset[str], node: Attribute
+    member_names: frozenset[str], node: nodes.Attribute
 ) -> bool:
     """
     Returns True if the Attribute node's name matches a member name from numpy
     """
     return (
         node.attrname in member_names
-        and isinstance(node.expr, Name)
+        and isinstance(node.expr, nodes.Name)
         and _is_a_numpy_module(node.expr)
     )
diff --git a/astroid/brain/brain_pathlib.py b/astroid/brain/brain_pathlib.py
index 62daaaf..d1d1bda 100644
--- a/astroid/brain/brain_pathlib.py
+++ b/astroid/brain/brain_pathlib.py
@@ -8,7 +8,7 @@
 
 from astroid import bases, context, nodes
 from astroid.builder import _extract_single_node
-from astroid.const import PY313_PLUS
+from astroid.const import PY313
 from astroid.exceptions import InferenceError, UseInferenceDefault
 from astroid.inference_tip import inference_tip
 from astroid.manager import AstroidManager
@@ -29,7 +29,7 @@
         value = next(node.value.infer())
     except (InferenceError, StopIteration):
         return False
-    parents = "builtins.tuple" if PY313_PLUS else "pathlib._PathParents"
+    parents = "builtins.tuple" if PY313 else "pathlib._PathParents"
     return (
         isinstance(value, bases.Instance)
         and isinstance(value._proxied, nodes.ClassDef)
diff --git a/astroid/brain/brain_pkg_resources.py b/astroid/brain/brain_pkg_resources.py
index e2bd669..d3b8562 100644
--- a/astroid/brain/brain_pkg_resources.py
+++ b/astroid/brain/brain_pkg_resources.py
@@ -9,8 +9,7 @@
 
 
 def pkg_resources_transform() -> nodes.Module:
-    return parse(
-        """
+    return parse("""
 def require(*requirements):
     return pkg_resources.working_set.require(*requirements)
 
@@ -64,8 +63,7 @@
     return Distribution(dist)
 
 _namespace_packages = {}
-"""
-    )
+""")
 
 
 def register(manager: AstroidManager) -> None:
diff --git a/astroid/brain/brain_pytest.py b/astroid/brain/brain_pytest.py
index 6d06267..827a24d 100644
--- a/astroid/brain/brain_pytest.py
+++ b/astroid/brain/brain_pytest.py
@@ -3,6 +3,7 @@
 # Copyright (c) https://github.com/pylint-dev/astroid/blob/main/CONTRIBUTORS.txt
 
 """Astroid hooks for pytest."""
+
 from astroid import nodes
 from astroid.brain.helpers import register_module_extender
 from astroid.builder import AstroidBuilder
@@ -10,8 +11,7 @@
 
 
 def pytest_transform() -> nodes.Module:
-    return AstroidBuilder(AstroidManager()).string_build(
-        """
+    return AstroidBuilder(AstroidManager()).string_build("""
 
 try:
     import _pytest.mark
@@ -76,8 +76,7 @@
         yield_fixture = _pytest.python.yield_fixture
     except ImportError:
         pass
-"""
-    )
+""")
 
 
 def register(manager: AstroidManager) -> None:
diff --git a/astroid/brain/brain_qt.py b/astroid/brain/brain_qt.py
index 30581e0..b384972 100644
--- a/astroid/brain/brain_qt.py
+++ b/astroid/brain/brain_qt.py
@@ -28,8 +28,7 @@
 
 
 def transform_pyqt_signal(node: nodes.FunctionDef) -> None:
-    module = parse(
-        """
+    module = parse("""
     _UNSET = object()
 
     class pyqtSignal(object):
@@ -39,8 +38,7 @@
             pass
         def emit(self, *args):
             pass
-    """
-    )
+    """)
     signal_cls: nodes.ClassDef = module["pyqtSignal"]
     node.instance_attrs["emit"] = [signal_cls["emit"]]
     node.instance_attrs["disconnect"] = [signal_cls["disconnect"]]
@@ -48,8 +46,7 @@
 
 
 def transform_pyside_signal(node: nodes.FunctionDef) -> None:
-    module = parse(
-        """
+    module = parse("""
     class NotPySideSignal(object):
         def connect(self, receiver, type=None):
             pass
@@ -57,8 +54,7 @@
             pass
         def emit(self, *args):
             pass
-    """
-    )
+    """)
     signal_cls: nodes.ClassDef = module["NotPySideSignal"]
     node.instance_attrs["connect"] = [signal_cls["connect"]]
     node.instance_attrs["disconnect"] = [signal_cls["disconnect"]]
@@ -66,15 +62,13 @@
 
 
 def pyqt4_qtcore_transform():
-    return AstroidBuilder(AstroidManager()).string_build(
-        """
+    return AstroidBuilder(AstroidManager()).string_build("""
 
 def SIGNAL(signal_name): pass
 
 class QObject(object):
     def emit(self, signal): pass
-"""
-    )
+""")
 
 
 def register(manager: AstroidManager) -> None:
diff --git a/astroid/brain/brain_random.py b/astroid/brain/brain_random.py
index 48cc121..849a9f4 100644
--- a/astroid/brain/brain_random.py
+++ b/astroid/brain/brain_random.py
@@ -4,29 +4,21 @@
 
 from __future__ import annotations
 
+import inspect
 import random
 
+from astroid import nodes
 from astroid.context import InferenceContext
 from astroid.exceptions import UseInferenceDefault
 from astroid.inference_tip import inference_tip
 from astroid.manager import AstroidManager
-from astroid.nodes.node_classes import (
-    Attribute,
-    Call,
-    Const,
-    EvaluatedObject,
-    List,
-    Name,
-    Set,
-    Tuple,
-)
-from astroid.util import safe_infer
+from astroid.util import UninferableBase, safe_infer
 
-ACCEPTED_ITERABLES_FOR_SAMPLE = (List, Set, Tuple)
+ACCEPTED_ITERABLES_FOR_SAMPLE = (nodes.List, nodes.Set, nodes.Tuple)
 
 
 def _clone_node_with_lineno(node, parent, lineno):
-    if isinstance(node, EvaluatedObject):
+    if isinstance(node, nodes.EvaluatedObject):
         node = node.original
     cls = node.__class__
     other_fields = node._other_fields
@@ -39,11 +31,19 @@
         "end_col_offset": node.end_col_offset,
     }
     postinit_params = {param: getattr(node, param) for param in _astroid_fields}
-    if other_fields:
-        init_params.update({param: getattr(node, param) for param in other_fields})
+
+    valid_init_params = set(inspect.signature(cls.__init__).parameters)
+    for param in other_fields:
+        if param in valid_init_params:
+            init_params[param] = getattr(node, param)
+
     new_node = cls(**init_params)
     if hasattr(node, "postinit") and _astroid_fields:
         new_node.postinit(**postinit_params)
+
+    for param in other_fields:
+        if param not in valid_init_params:
+            setattr(new_node, param, getattr(node, param))
     return new_node
 
 
@@ -52,7 +52,7 @@
         raise UseInferenceDefault
 
     inferred_length = safe_infer(node.args[1], context=context)
-    if not isinstance(inferred_length, Const):
+    if not isinstance(inferred_length, nodes.Const):
         raise UseInferenceDefault
     if not isinstance(inferred_length.value, int):
         raise UseInferenceDefault
@@ -68,12 +68,15 @@
         # In this case, this will raise a ValueError
         raise UseInferenceDefault
 
+    if any(isinstance(elt, UninferableBase) for elt in inferred_sequence.elts):
+        raise UseInferenceDefault
+
     try:
         elts = random.sample(inferred_sequence.elts, inferred_length.value)
     except ValueError as exc:
         raise UseInferenceDefault from exc
 
-    new_node = List(
+    new_node = nodes.List(
         lineno=node.lineno,
         col_offset=node.col_offset,
         parent=node.scope(),
@@ -90,14 +93,14 @@
 
 def _looks_like_random_sample(node) -> bool:
     func = node.func
-    if isinstance(func, Attribute):
+    if isinstance(func, nodes.Attribute):
         return func.attrname == "sample"
-    if isinstance(func, Name):
+    if isinstance(func, nodes.Name):
         return func.name == "sample"
     return False
 
 
 def register(manager: AstroidManager) -> None:
     manager.register_transform(
-        Call, inference_tip(infer_random_sample), _looks_like_random_sample
+        nodes.Call, inference_tip(infer_random_sample), _looks_like_random_sample
     )
diff --git a/astroid/brain/brain_re.py b/astroid/brain/brain_re.py
index 6464645..575434d 100644
--- a/astroid/brain/brain_re.py
+++ b/astroid/brain/brain_re.py
@@ -20,8 +20,7 @@
         import_compiler = "import re._compiler as _compiler"
     else:
         import_compiler = "import sre_compile as _compiler"
-    return parse(
-        f"""
+    return parse(f"""
     {import_compiler}
     NOFLAG = 0
     ASCII = _compiler.SRE_FLAG_ASCII
@@ -41,8 +40,7 @@
     S = DOTALL
     X = VERBOSE
     T = TEMPLATE
-    """
-    )
+    """)
 
 
 CLASS_GETITEM_TEMPLATE = """
diff --git a/astroid/brain/brain_regex.py b/astroid/brain/brain_regex.py
index 70fb946..9bc4b22 100644
--- a/astroid/brain/brain_regex.py
+++ b/astroid/brain/brain_regex.py
@@ -18,8 +18,7 @@
     # pylint: disable-next=line-too-long
     See https://github.com/mrabarnett/mrab-regex/blob/2022.10.31/regex_3/regex.py#L200
     """
-    return parse(
-        """
+    return parse("""
     A = ASCII = 0x80          # Assume ASCII locale.
     B = BESTMATCH = 0x1000    # Best fuzzy match.
     D = DEBUG = 0x200         # Print parsed pattern.
@@ -39,8 +38,7 @@
     W = WORD = 0x800          # Default Unicode word breaks.
     X = VERBOSE = 0x40        # Ignore whitespace and comments.
     T = TEMPLATE = 0x1        # Template (present because re module has it).
-    """
-    )
+    """)
 
 
 CLASS_GETITEM_TEMPLATE = """
diff --git a/astroid/brain/brain_responses.py b/astroid/brain/brain_responses.py
index f2e6069..aed58ee 100644
--- a/astroid/brain/brain_responses.py
+++ b/astroid/brain/brain_responses.py
@@ -10,6 +10,7 @@
 
 See: https://github.com/getsentry/responses/blob/master/responses.py
 """
+
 from astroid import nodes
 from astroid.brain.helpers import register_module_extender
 from astroid.builder import parse
@@ -17,8 +18,7 @@
 
 
 def responses_funcs() -> nodes.Module:
-    return parse(
-        """
+    return parse("""
         DELETE = "DELETE"
         GET = "GET"
         HEAD = "HEAD"
@@ -72,8 +72,7 @@
 
         def stop(allow_assert=True):
             return
-        """
-    )
+        """)
 
 
 def register(manager: AstroidManager) -> None:
diff --git a/astroid/brain/brain_scipy_signal.py b/astroid/brain/brain_scipy_signal.py
index a7a2576..bbbd187 100755
--- a/astroid/brain/brain_scipy_signal.py
+++ b/astroid/brain/brain_scipy_signal.py
@@ -3,6 +3,7 @@
 # Copyright (c) https://github.com/pylint-dev/astroid/blob/main/CONTRIBUTORS.txt
 
 """Astroid hooks for scipy.signal module."""
+
 from astroid import nodes
 from astroid.brain.helpers import register_module_extender
 from astroid.builder import parse
@@ -10,8 +11,7 @@
 
 
 def scipy_signal() -> nodes.Module:
-    return parse(
-        """
+    return parse("""
     # different functions defined in scipy.signals
 
     def barthann(M, sym=True):
@@ -82,8 +82,7 @@
 
     def tukey(M, alpha=0.5, sym=True):
         return numpy.ndarray([0])
-        """
-    )
+        """)
 
 
 def register(manager: AstroidManager) -> None:
diff --git a/astroid/brain/brain_signal.py b/astroid/brain/brain_signal.py
index 649e974..b725b1b 100644
--- a/astroid/brain/brain_signal.py
+++ b/astroid/brain/brain_signal.py
@@ -24,7 +24,6 @@
 actual standard signal numbers - which may vary depending on the system.
 """
 
-
 import sys
 
 from astroid.brain.helpers import register_module_extender
diff --git a/astroid/brain/brain_six.py b/astroid/brain/brain_six.py
index c222a42..e589848 100644
--- a/astroid/brain/brain_six.py
+++ b/astroid/brain/brain_six.py
@@ -107,13 +107,11 @@
 
 
 def six_moves_transform():
-    code = dedent(
-        """
+    code = dedent("""
     class Moves(object):
     {}
     moves = Moves()
-    """
-    ).format(_indent(_IMPORTS, "    "))
+    """).format(_indent(_IMPORTS, "    "))
     module = AstroidBuilder(AstroidManager()).string_build(code)
     module.name = "six.moves"
     return module
@@ -182,7 +180,11 @@
             func = next(decorator.func.infer())
         except (InferenceError, StopIteration):
             continue
-        if func.qname() == SIX_ADD_METACLASS and decorator.args:
+        if (
+            isinstance(func, (nodes.FunctionDef, nodes.ClassDef))
+            and func.qname() == SIX_ADD_METACLASS
+            and decorator.args
+        ):
             metaclass = decorator.args[0]
             node._metaclass = metaclass
             return node
diff --git a/astroid/brain/brain_sqlalchemy.py b/astroid/brain/brain_sqlalchemy.py
index 8410d9e..77cac2d 100644
--- a/astroid/brain/brain_sqlalchemy.py
+++ b/astroid/brain/brain_sqlalchemy.py
@@ -9,8 +9,7 @@
 
 
 def _session_transform() -> nodes.Module:
-    return parse(
-        """
+    return parse("""
     from sqlalchemy.orm.session import Session
 
     class sessionmaker:
@@ -33,8 +32,7 @@
             return
 
         return Session()
-    """
-    )
+    """)
 
 
 def register(manager: AstroidManager) -> None:
diff --git a/astroid/brain/brain_ssl.py b/astroid/brain/brain_ssl.py
index de932de..4cb89f8 100644
--- a/astroid/brain/brain_ssl.py
+++ b/astroid/brain/brain_ssl.py
@@ -7,7 +7,7 @@
 from astroid import nodes
 from astroid.brain.helpers import register_module_extender
 from astroid.builder import parse
-from astroid.const import PY310_PLUS, PY312_PLUS
+from astroid.const import PY312_PLUS
 from astroid.manager import AstroidManager
 
 
@@ -18,9 +18,7 @@
         VERIFY_CRL_CHECK_LEAF = 1
         VERIFY_CRL_CHECK_CHAIN = 2
         VERIFY_X509_STRICT = 3
-        VERIFY_X509_TRUSTED_FIRST = 4"""
-    if PY310_PLUS:
-        enum += """
+        VERIFY_X509_TRUSTED_FIRST = 4
         VERIFY_ALLOW_PROXY_CERTS = 5
         VERIFY_X509_PARTIAL_CHAIN = 6
         """
@@ -51,8 +49,7 @@
 
 
 def ssl_transform() -> nodes.Module:
-    return parse(
-        f"""
+    return parse(f"""
     # Import necessary for conversion of objects defined in C into enums
     from enum import IntEnum as _IntEnum, IntFlag as _IntFlag
 
@@ -155,10 +152,7 @@
         CERT_NONE = 0
         CERT_OPTIONAL = 1
         CERT_REQUIRED = 2
-    """
-        + _verifyflags_enum()
-        + _options_enum()
-    )
+    """ + _verifyflags_enum() + _options_enum())
 
 
 def register(manager: AstroidManager) -> None:
diff --git a/astroid/brain/brain_statistics.py b/astroid/brain/brain_statistics.py
new file mode 100644
index 0000000..5420ef9
--- /dev/null
+++ b/astroid/brain/brain_statistics.py
@@ -0,0 +1,73 @@
+# Licensed under the LGPL: https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html
+# For details: https://github.com/pylint-dev/astroid/blob/main/LICENSE
+# Copyright (c) https://github.com/pylint-dev/astroid/blob/main/CONTRIBUTORS.txt
+
+"""Astroid hooks for understanding statistics library module.
+
+Provides inference improvements for statistics module functions that have
+complex runtime behavior difficult to analyze statically.
+"""
+
+from __future__ import annotations
+
+from collections.abc import Iterator
+from typing import TYPE_CHECKING
+
+from astroid import nodes
+from astroid.context import InferenceContext
+from astroid.inference_tip import inference_tip
+from astroid.manager import AstroidManager
+from astroid.util import Uninferable
+
+if TYPE_CHECKING:
+    from astroid.typing import InferenceResult
+
+
+def _looks_like_statistics_quantiles(node: nodes.Call) -> bool:
+    """Check if this is a call to statistics.quantiles."""
+    match node.func:
+        case nodes.Attribute(expr=nodes.Name(name="statistics"), attrname="quantiles"):
+            # Case 1: statistics.quantiles(...)
+            return True
+        case nodes.Name(name="quantiles"):
+            # Case 2: from statistics import quantiles; quantiles(...)
+            # Check if quantiles was imported from statistics
+            try:
+                frame = node.frame()
+                if "quantiles" in frame.locals:
+                    # Look for import from statistics
+                    for stmt in frame.body:
+                        if (
+                            isinstance(stmt, nodes.ImportFrom)
+                            and stmt.modname == "statistics"
+                            and any(name[0] == "quantiles" for name in stmt.names or [])
+                        ):
+                            return True
+            except (AttributeError, TypeError):
+                # If we can't determine the import context, be conservative
+                pass
+    return False
+
+
+def infer_statistics_quantiles(
+    node: nodes.Call, context: InferenceContext | None = None
+) -> Iterator[InferenceResult]:
+    """Infer the result of statistics.quantiles() calls.
+
+    Returns Uninferable because quantiles() has complex runtime behavior
+    that cannot be statically analyzed, preventing false positives in
+    pylint's unbalanced-tuple-unpacking checker.
+
+    statistics.quantiles() returns a list with (n-1) elements, but static
+    analysis sees only the empty list initializations in the function body.
+    """
+    yield Uninferable
+
+
+def register(manager: AstroidManager) -> None:
+    """Register statistics-specific inference improvements."""
+    manager.register_transform(
+        nodes.Call,
+        inference_tip(infer_statistics_quantiles),
+        _looks_like_statistics_quantiles,
+    )
diff --git a/astroid/brain/brain_subprocess.py b/astroid/brain/brain_subprocess.py
index 96855c6..e18a0fe 100644
--- a/astroid/brain/brain_subprocess.py
+++ b/astroid/brain/brain_subprocess.py
@@ -7,7 +7,7 @@
 from astroid import nodes
 from astroid.brain.helpers import register_module_extender
 from astroid.builder import parse
-from astroid.const import PY310_PLUS, PY311_PLUS
+from astroid.const import PY311_PLUS
 from astroid.manager import AstroidManager
 
 
@@ -19,10 +19,7 @@
         preexec_fn=None, close_fds=True, shell=False, cwd=None, env=None,
         universal_newlines=None, startupinfo=None, creationflags=0, restore_signals=True,
         start_new_session=False, pass_fds=(), *, encoding=None, errors=None, text=None,
-        user=None, group=None, extra_groups=None, umask=-1"""
-
-    if PY310_PLUS:
-        args += ", pipesize=-1"
+        user=None, group=None, extra_groups=None, umask=-1, pipesize=-1"""
     if PY311_PLUS:
         args += ", process_group=None"
 
@@ -62,8 +59,7 @@
     ):
     """.strip()
 
-    code = textwrap.dedent(
-        f"""
+    code = textwrap.dedent(f"""
     def {check_output_signature}
         if universal_newlines:
             return ""
@@ -90,8 +86,7 @@
         @classmethod
         def __class_getitem__(cls, item):
             pass
-        """
-    )
+        """)
 
     init_lines = textwrap.dedent(init).splitlines()
     indented_init = "\n".join(" " * 4 + line for line in init_lines)
diff --git a/astroid/brain/brain_threading.py b/astroid/brain/brain_threading.py
index 95af2db..a4ea976 100644
--- a/astroid/brain/brain_threading.py
+++ b/astroid/brain/brain_threading.py
@@ -9,8 +9,7 @@
 
 
 def _thread_transform() -> nodes.Module:
-    return parse(
-        """
+    return parse("""
     class lock(object):
         def acquire(self, blocking=True, timeout=-1):
             return False
@@ -25,8 +24,7 @@
 
     def Lock(*args, **kwargs):
         return lock()
-    """
-    )
+    """)
 
 
 def register(manager: AstroidManager) -> None:
diff --git a/astroid/brain/brain_type.py b/astroid/brain/brain_type.py
index 2fb06be..8391e59 100644
--- a/astroid/brain/brain_type.py
+++ b/astroid/brain/brain_type.py
@@ -35,7 +35,7 @@
     Try to figure out if a Name node is used inside a type related subscript.
 
     :param node: node to check
-    :type node: astroid.nodes.node_classes.NodeNG
+    :type node: astroid.nodes.NodeNG
     :return: whether the node is a Name node inside a type related subscript
     """
     if isinstance(node.parent, nodes.Subscript):
@@ -48,12 +48,12 @@
     Infer a type[...] subscript.
 
     :param node: node to infer
-    :type node: astroid.nodes.node_classes.NodeNG
+    :type node: astroid.nodes.NodeNG
     :return: the inferred node
     :rtype: nodes.NodeNG
     """
     node_scope, _ = node.scope().lookup("type")
-    if not isinstance(node_scope, nodes.Module) or node_scope.qname() != "builtins":
+    if not (isinstance(node_scope, nodes.Module) and node_scope.qname() == "builtins"):
         raise UseInferenceDefault()
     class_src = """
     class type:
diff --git a/astroid/brain/brain_typing.py b/astroid/brain/brain_typing.py
index 57cb56e..e0eb15f 100644
--- a/astroid/brain/brain_typing.py
+++ b/astroid/brain/brain_typing.py
@@ -12,10 +12,10 @@
 from functools import partial
 from typing import Final
 
-from astroid import context
+from astroid import context, nodes
 from astroid.brain.helpers import register_module_extender
 from astroid.builder import AstroidBuilder, _extract_single_node, extract_node
-from astroid.const import PY312_PLUS, PY313_PLUS
+from astroid.const import PY312_PLUS, PY313_PLUS, PY314_PLUS
 from astroid.exceptions import (
     AstroidSyntaxError,
     AttributeInferenceError,
@@ -24,18 +24,6 @@
 )
 from astroid.inference_tip import inference_tip
 from astroid.manager import AstroidManager
-from astroid.nodes.node_classes import (
-    Assign,
-    AssignName,
-    Attribute,
-    Call,
-    Const,
-    JoinedStr,
-    Name,
-    NodeNG,
-    Subscript,
-)
-from astroid.nodes.scoped_nodes import ClassDef, FunctionDef
 
 TYPING_TYPEVARS = {"TypeVar", "NewType"}
 TYPING_TYPEVARS_QUALIFIED: Final = {
@@ -78,7 +66,7 @@
         "typing.MutableMapping",
         "typing.Sequence",
         "typing.MutableSequence",
-        "typing.ByteString",
+        "typing.ByteString",  # scheduled for removal in 3.17
         "typing.Tuple",
         "typing.List",
         "typing.Deque",
@@ -112,16 +100,16 @@
 
 def looks_like_typing_typevar_or_newtype(node) -> bool:
     func = node.func
-    if isinstance(func, Attribute):
+    if isinstance(func, nodes.Attribute):
         return func.attrname in TYPING_TYPEVARS
-    if isinstance(func, Name):
+    if isinstance(func, nodes.Name):
         return func.name in TYPING_TYPEVARS
     return False
 
 
 def infer_typing_typevar_or_newtype(
-    node: Call, context_itton: context.InferenceContext | None = None
-) -> Iterator[ClassDef]:
+    node: nodes.Call, context_itton: context.InferenceContext | None = None
+) -> Iterator[nodes.ClassDef]:
     """Infer a typing.TypeVar(...) or typing.NewType(...) call."""
     try:
         func = next(node.func.infer(context=context_itton))
@@ -133,7 +121,7 @@
     if not node.args:
         raise UseInferenceDefault
     # Cannot infer from a dynamic class name (f-string)
-    if isinstance(node.args[0], JoinedStr):
+    if isinstance(node.args[0], nodes.JoinedStr):
         raise UseInferenceDefault
 
     typename = node.args[0].as_string().strip("'")
@@ -146,18 +134,18 @@
 
 def _looks_like_typing_subscript(node) -> bool:
     """Try to figure out if a Subscript node *might* be a typing-related subscript."""
-    if isinstance(node, Name):
+    if isinstance(node, nodes.Name):
         return node.name in TYPING_MEMBERS
-    if isinstance(node, Attribute):
+    if isinstance(node, nodes.Attribute):
         return node.attrname in TYPING_MEMBERS
-    if isinstance(node, Subscript):
+    if isinstance(node, nodes.Subscript):
         return _looks_like_typing_subscript(node.value)
     return False
 
 
 def infer_typing_attr(
-    node: Subscript, ctx: context.InferenceContext | None = None
-) -> Iterator[ClassDef]:
+    node: nodes.Subscript, ctx: context.InferenceContext | None = None
+) -> Iterator[nodes.ClassDef]:
     """Infer a typing.X[...] subscript."""
     try:
         value = next(node.value.infer())  # type: ignore[union-attr] # value shouldn't be None for Subscript.
@@ -170,14 +158,14 @@
 
     if (
         PY313_PLUS
-        and isinstance(value, FunctionDef)
+        and isinstance(value, nodes.FunctionDef)
         and value.qname() == "typing.Annotated"
     ):
         # typing.Annotated is a FunctionDef on 3.13+
         node._explicit_inference = lambda node, context: iter([value])
         return iter([value])
 
-    if isinstance(value, ClassDef) and value.qname() in {
+    if isinstance(value, nodes.ClassDef) and value.qname() in {
         "typing.Generic",
         "typing.Annotated",
         "typing_extensions.Annotated",
@@ -188,7 +176,7 @@
         func_to_add = _extract_single_node(CLASS_GETITEM_TEMPLATE)
         value.locals["__class_getitem__"] = [func_to_add]
         if (
-            isinstance(node.parent, ClassDef)
+            isinstance(node.parent, nodes.ClassDef)
             and node in node.parent.bases
             and getattr(node.parent, "__cache", None)
         ):
@@ -205,14 +193,14 @@
     return node.infer(context=ctx)
 
 
-def _looks_like_generic_class_pep695(node: ClassDef) -> bool:
+def _looks_like_generic_class_pep695(node: nodes.ClassDef) -> bool:
     """Check if class is using type parameter. Python 3.12+."""
     return len(node.type_params) > 0
 
 
 def infer_typing_generic_class_pep695(
-    node: ClassDef, ctx: context.InferenceContext | None = None
-) -> Iterator[ClassDef]:
+    node: nodes.ClassDef, ctx: context.InferenceContext | None = None
+) -> Iterator[nodes.ClassDef]:
     """Add __class_getitem__ for generic classes. Python 3.12+."""
     func_to_add = _extract_single_node(CLASS_GETITEM_TEMPLATE)
     node.locals["__class_getitem__"] = [func_to_add]
@@ -220,17 +208,17 @@
 
 
 def _looks_like_typedDict(  # pylint: disable=invalid-name
-    node: FunctionDef | ClassDef,
+    node: nodes.FunctionDef | nodes.ClassDef,
 ) -> bool:
     """Check if node is TypedDict FunctionDef."""
     return node.qname() in TYPING_TYPEDDICT_QUALIFIED
 
 
 def infer_typedDict(  # pylint: disable=invalid-name
-    node: FunctionDef, ctx: context.InferenceContext | None = None
-) -> Iterator[ClassDef]:
+    node: nodes.FunctionDef, ctx: context.InferenceContext | None = None
+) -> Iterator[nodes.ClassDef]:
     """Replace TypedDict FunctionDef with ClassDef."""
-    class_def = ClassDef(
+    class_def = nodes.ClassDef(
         name="TypedDict",
         lineno=node.lineno,
         col_offset=node.col_offset,
@@ -244,7 +232,7 @@
     return iter([class_def])
 
 
-def _looks_like_typing_alias(node: Call) -> bool:
+def _looks_like_typing_alias(node: nodes.Call) -> bool:
     """
     Returns True if the node corresponds to a call to _alias function.
 
@@ -255,18 +243,18 @@
     :param node: call node
     """
     return (
-        isinstance(node.func, Name)
+        isinstance(node.func, nodes.Name)
         # TODO: remove _DeprecatedGenericAlias when Py3.14 min
         and node.func.name in {"_alias", "_DeprecatedGenericAlias"}
         and len(node.args) == 2
         and (
             # _alias function works also for builtins object such as list and dict
-            isinstance(node.args[0], (Attribute, Name))
+            isinstance(node.args[0], (nodes.Attribute, nodes.Name))
         )
     )
 
 
-def _forbid_class_getitem_access(node: ClassDef) -> None:
+def _forbid_class_getitem_access(node: nodes.ClassDef) -> None:
     """Disable the access to __class_getitem__ method for the node in parameters."""
 
     def full_raiser(origin_func, attr, *args, **kwargs):
@@ -291,8 +279,8 @@
 
 
 def infer_typing_alias(
-    node: Call, ctx: context.InferenceContext | None = None
-) -> Iterator[ClassDef]:
+    node: nodes.Call, ctx: context.InferenceContext | None = None
+) -> Iterator[nodes.ClassDef]:
     """
     Infers the call to _alias function
     Insert ClassDef, with same name as aliased class,
@@ -303,10 +291,10 @@
 
     # TODO: evaluate if still necessary when Py3.12 is minimum
     """
-    if (
-        not isinstance(node.parent, Assign)
-        or not len(node.parent.targets) == 1
-        or not isinstance(node.parent.targets[0], AssignName)
+    if not (
+        isinstance(node.parent, nodes.Assign)
+        and len(node.parent.targets) == 1
+        and isinstance(node.parent.targets[0], nodes.AssignName)
     ):
         raise UseInferenceDefault
     try:
@@ -316,7 +304,7 @@
 
     assign_name = node.parent.targets[0]
 
-    class_def = ClassDef(
+    class_def = nodes.ClassDef(
         name=assign_name.name,
         lineno=assign_name.lineno,
         col_offset=assign_name.col_offset,
@@ -324,13 +312,13 @@
         end_lineno=assign_name.end_lineno,
         end_col_offset=assign_name.end_col_offset,
     )
-    if isinstance(res, ClassDef):
+    if isinstance(res, nodes.ClassDef):
         # Only add `res` as base if it's a `ClassDef`
         # This isn't the case for `typing.Pattern` and `typing.Match`
         class_def.postinit(bases=[res], body=[], decorators=None)
 
     maybe_type_var = node.args[1]
-    if isinstance(maybe_type_var, Const) and maybe_type_var.value > 0:
+    if isinstance(maybe_type_var, nodes.Const) and maybe_type_var.value > 0:
         # If typing alias is subscriptable, add `__class_getitem__` to ClassDef
         func_to_add = _extract_single_node(CLASS_GETITEM_TEMPLATE)
         class_def.locals["__class_getitem__"] = [func_to_add]
@@ -345,7 +333,7 @@
     return iter([class_def])
 
 
-def _looks_like_special_alias(node: Call) -> bool:
+def _looks_like_special_alias(node: nodes.Call) -> bool:
     """Return True if call is for Tuple or Callable alias.
 
     In PY37 and PY38 the call is to '_VariadicGenericAlias' with 'tuple' as
@@ -357,28 +345,32 @@
     PY37: Callable = _VariadicGenericAlias(collections.abc.Callable, (), special=True)
     PY39: Callable = _CallableType(collections.abc.Callable, 2)
     """
-    return isinstance(node.func, Name) and (
-        (
-            node.func.name == "_TupleType"
-            and isinstance(node.args[0], Name)
-            and node.args[0].name == "tuple"
-        )
-        or (
-            node.func.name == "_CallableType"
-            and isinstance(node.args[0], Attribute)
-            and node.args[0].as_string() == "collections.abc.Callable"
+    return (
+        isinstance(node.func, nodes.Name)
+        and node.args
+        and (
+            (
+                node.func.name == "_TupleType"
+                and isinstance(node.args[0], nodes.Name)
+                and node.args[0].name == "tuple"
+            )
+            or (
+                node.func.name == "_CallableType"
+                and isinstance(node.args[0], nodes.Attribute)
+                and node.args[0].as_string() == "collections.abc.Callable"
+            )
         )
     )
 
 
 def infer_special_alias(
-    node: Call, ctx: context.InferenceContext | None = None
-) -> Iterator[ClassDef]:
+    node: nodes.Call, ctx: context.InferenceContext | None = None
+) -> Iterator[nodes.ClassDef]:
     """Infer call to tuple alias as new subscriptable class typing.Tuple."""
     if not (
-        isinstance(node.parent, Assign)
+        isinstance(node.parent, nodes.Assign)
         and len(node.parent.targets) == 1
-        and isinstance(node.parent.targets[0], AssignName)
+        and isinstance(node.parent.targets[0], nodes.AssignName)
     ):
         raise UseInferenceDefault
     try:
@@ -387,7 +379,7 @@
         raise InferenceError(node=node.args[0], context=ctx) from e
 
     assign_name = node.parent.targets[0]
-    class_def = ClassDef(
+    class_def = nodes.ClassDef(
         name=assign_name.name,
         parent=node.parent,
         lineno=assign_name.lineno,
@@ -403,27 +395,27 @@
     return iter([class_def])
 
 
-def _looks_like_typing_cast(node: Call) -> bool:
-    return (isinstance(node.func, Name) and node.func.name == "cast") or (
-        isinstance(node.func, Attribute) and node.func.attrname == "cast"
+def _looks_like_typing_cast(node: nodes.Call) -> bool:
+    return (isinstance(node.func, nodes.Name) and node.func.name == "cast") or (
+        isinstance(node.func, nodes.Attribute) and node.func.attrname == "cast"
     )
 
 
 def infer_typing_cast(
-    node: Call, ctx: context.InferenceContext | None = None
-) -> Iterator[NodeNG]:
+    node: nodes.Call, ctx: context.InferenceContext | None = None
+) -> Iterator[nodes.NodeNG]:
     """Infer call to cast() returning same type as casted-from var."""
-    if not isinstance(node.func, (Name, Attribute)):
+    if not isinstance(node.func, (nodes.Name, nodes.Attribute)):
         raise UseInferenceDefault
 
     try:
         func = next(node.func.infer(context=ctx))
     except (InferenceError, StopIteration) as exc:
         raise UseInferenceDefault from exc
-    if (
-        not isinstance(func, FunctionDef)
-        or func.qname() != "typing.cast"
-        or len(node.args) != 2
+    if not (
+        isinstance(func, nodes.FunctionDef)
+        and func.qname() == "typing.cast"
+        and len(node.args) == 2
     ):
         raise UseInferenceDefault
 
@@ -431,9 +423,7 @@
 
 
 def _typing_transform():
-    return AstroidBuilder(AstroidManager()).string_build(
-        textwrap.dedent(
-            """
+    code = textwrap.dedent("""
     class Generic:
         @classmethod
         def __class_getitem__(cls, item):  return cls
@@ -466,39 +456,45 @@
     class Match:
         @classmethod
         def __class_getitem__(cls, item):  return cls
-    """
-        )
-    )
+    """)
+    if PY314_PLUS:
+        code += textwrap.dedent("""
+    from annotationlib import ForwardRef
+    class Union:
+        @classmethod
+        def __class_getitem__(cls, item): return cls
+    """)
+    return AstroidBuilder(AstroidManager()).string_build(code)
 
 
 def register(manager: AstroidManager) -> None:
     manager.register_transform(
-        Call,
+        nodes.Call,
         inference_tip(infer_typing_typevar_or_newtype),
         looks_like_typing_typevar_or_newtype,
     )
     manager.register_transform(
-        Subscript, inference_tip(infer_typing_attr), _looks_like_typing_subscript
+        nodes.Subscript, inference_tip(infer_typing_attr), _looks_like_typing_subscript
     )
     manager.register_transform(
-        Call, inference_tip(infer_typing_cast), _looks_like_typing_cast
+        nodes.Call, inference_tip(infer_typing_cast), _looks_like_typing_cast
     )
 
     manager.register_transform(
-        FunctionDef, inference_tip(infer_typedDict), _looks_like_typedDict
+        nodes.FunctionDef, inference_tip(infer_typedDict), _looks_like_typedDict
     )
 
     manager.register_transform(
-        Call, inference_tip(infer_typing_alias), _looks_like_typing_alias
+        nodes.Call, inference_tip(infer_typing_alias), _looks_like_typing_alias
     )
     manager.register_transform(
-        Call, inference_tip(infer_special_alias), _looks_like_special_alias
+        nodes.Call, inference_tip(infer_special_alias), _looks_like_special_alias
     )
 
     if PY312_PLUS:
         register_module_extender(manager, "typing", _typing_transform)
         manager.register_transform(
-            ClassDef,
+            nodes.ClassDef,
             inference_tip(infer_typing_generic_class_pep695),
             _looks_like_generic_class_pep695,
         )
diff --git a/astroid/brain/brain_unittest.py b/astroid/brain/brain_unittest.py
index 4103ce0..64bd367 100644
--- a/astroid/brain/brain_unittest.py
+++ b/astroid/brain/brain_unittest.py
@@ -3,6 +3,7 @@
 # Copyright (c) https://github.com/pylint-dev/astroid/blob/main/CONTRIBUTORS.txt
 
 """Astroid hooks for unittest module."""
+
 from astroid import nodes
 from astroid.brain.helpers import register_module_extender
 from astroid.builder import parse
@@ -20,11 +21,9 @@
 
     (see https://github.com/pylint-dev/pylint/issues/4060)
     """
-    return parse(
-        """
+    return parse("""
     from .async_case import IsolatedAsyncioTestCase
-    """
-    )
+    """)
 
 
 def register(manager: AstroidManager) -> None:
diff --git a/astroid/brain/brain_uuid.py b/astroid/brain/brain_uuid.py
index 37800b8..b10bdea 100644
--- a/astroid/brain/brain_uuid.py
+++ b/astroid/brain/brain_uuid.py
@@ -3,17 +3,17 @@
 # Copyright (c) https://github.com/pylint-dev/astroid/blob/main/CONTRIBUTORS.txt
 
 """Astroid hooks for the UUID module."""
+
+from astroid import nodes
 from astroid.manager import AstroidManager
-from astroid.nodes.node_classes import Const
-from astroid.nodes.scoped_nodes import ClassDef
 
 
-def _patch_uuid_class(node: ClassDef) -> None:
+def _patch_uuid_class(node: nodes.ClassDef) -> None:
     # The .int member is patched using __dict__
-    node.locals["int"] = [Const(0, parent=node)]
+    node.locals["int"] = [nodes.Const(0, parent=node)]
 
 
 def register(manager: AstroidManager) -> None:
     manager.register_transform(
-        ClassDef, _patch_uuid_class, lambda node: node.qname() == "uuid.UUID"
+        nodes.ClassDef, _patch_uuid_class, lambda node: node.qname() == "uuid.UUID"
     )
diff --git a/astroid/brain/helpers.py b/astroid/brain/helpers.py
index 79d778b..0064a1f 100644
--- a/astroid/brain/helpers.py
+++ b/astroid/brain/helpers.py
@@ -5,10 +5,15 @@
 from __future__ import annotations
 
 from collections.abc import Callable
+from typing import TYPE_CHECKING
 
+from astroid.exceptions import InferenceError
 from astroid.manager import AstroidManager
 from astroid.nodes.scoped_nodes import Module
 
+if TYPE_CHECKING:
+    from astroid.nodes.node_ng import NodeNG
+
 
 def register_module_extender(
     manager: AstroidManager, module_name: str, get_extension_mod: Callable[[], Module]
@@ -47,7 +52,6 @@
         brain_mechanize,
         brain_multiprocessing,
         brain_namedtuple_enum,
-        brain_nose,
         brain_numpy_core_einsumfunc,
         brain_numpy_core_fromnumeric,
         brain_numpy_core_function_base,
@@ -71,6 +75,7 @@
         brain_six,
         brain_sqlalchemy,
         brain_ssl,
+        brain_statistics,
         brain_subprocess,
         brain_threading,
         brain_type,
@@ -99,7 +104,6 @@
     brain_mechanize.register(manager)
     brain_multiprocessing.register(manager)
     brain_namedtuple_enum.register(manager)
-    brain_nose.register(manager)
     brain_numpy_core_einsumfunc.register(manager)
     brain_numpy_core_fromnumeric.register(manager)
     brain_numpy_core_function_base.register(manager)
@@ -123,9 +127,20 @@
     brain_six.register(manager)
     brain_sqlalchemy.register(manager)
     brain_ssl.register(manager)
+    brain_statistics.register(manager)
     brain_subprocess.register(manager)
     brain_threading.register(manager)
     brain_type.register(manager)
     brain_typing.register(manager)
     brain_unittest.register(manager)
     brain_uuid.register(manager)
+
+
+def is_class_var(node: NodeNG) -> bool:
+    """Return True if node is a ClassVar, with or without subscripting."""
+    try:
+        inferred = next(node.infer())
+    except (InferenceError, StopIteration):
+        return False
+
+    return getattr(inferred, "name", "") == "ClassVar"
diff --git a/astroid/builder.py b/astroid/builder.py
index 6fa7be6..f166ab4 100644
--- a/astroid/builder.py
+++ b/astroid/builder.py
@@ -16,14 +16,14 @@
 import textwrap
 import types
 import warnings
-from collections.abc import Iterator, Sequence
+from collections.abc import Collection, Iterator, Sequence
 from io import TextIOWrapper
 from tokenize import detect_encoding
-from typing import TYPE_CHECKING
+from typing import TYPE_CHECKING, cast
 
 from astroid import bases, modutils, nodes, raw_building, rebuilder, util
 from astroid._ast import ParserModule, get_parser_module
-from astroid.const import PY312_PLUS
+from astroid.const import PY312_PLUS, PY314_PLUS
 from astroid.exceptions import AstroidBuildingError, AstroidSyntaxError, InferenceError
 
 if TYPE_CHECKING:
@@ -39,7 +39,11 @@
 _STATEMENT_SELECTOR = "#@"
 
 if PY312_PLUS:
-    warnings.filterwarnings("ignore", "invalid escape sequence", SyntaxWarning)
+    warnings.filterwarnings("ignore", ".*invalid escape sequence", SyntaxWarning)
+if PY314_PLUS:
+    warnings.filterwarnings(
+        "ignore", "'(return|continue|break)' in a 'finally'", SyntaxWarning
+    )
 
 
 def open_source_file(filename: str) -> tuple[TextIOWrapper, str, str]:
@@ -159,11 +163,11 @@
         module.file_encoding = encoding
         self._manager.cache_module(module)
         # post tree building steps after we stored the module in the cache:
-        for from_node in builder._import_from_nodes:
+        for from_node, global_names in builder._import_from_nodes:
             if from_node.modname == "__future__":
                 for symbol, _ in from_node.names:
                     module.future_imports.add(symbol)
-            self.add_from_names_to_locals(from_node)
+            self.add_from_names_to_locals(from_node, global_names)
         # handle delayed assattr nodes
         for delayed in builder._delayed_assattr:
             self.delayed_assattr(delayed)
@@ -181,7 +185,7 @@
             node, parser_module = _parse_string(
                 data, type_comments=True, modname=modname
             )
-        except (TypeError, ValueError, SyntaxError) as exc:
+        except (TypeError, ValueError, SyntaxError, MemoryError) as exc:
             raise AstroidSyntaxError(
                 "Parsing Python code failed:\n{error}",
                 source=data,
@@ -206,19 +210,23 @@
         module = builder.visit_module(node, modname, node_file, package)
         return module, builder
 
-    def add_from_names_to_locals(self, node: nodes.ImportFrom) -> None:
+    def add_from_names_to_locals(
+        self, node: nodes.ImportFrom, global_name: Collection[str]
+    ) -> None:
         """Store imported names to the locals.
 
         Resort the locals if coming from a delayed node
         """
 
-        def _key_func(node: nodes.NodeNG) -> int:
-            return node.fromlineno or 0
-
-        def sort_locals(my_list: list[nodes.NodeNG]) -> None:
-            my_list.sort(key=_key_func)
+        def add_local(parent_or_root: nodes.NodeNG, name: str) -> None:
+            parent_or_root.set_local(name, node)
+            my_list = parent_or_root.scope().locals[name]
+            if TYPE_CHECKING:
+                my_list = cast(list[nodes.NodeNG], my_list)
+            my_list.sort(key=lambda n: n.fromlineno or 0)
 
         assert node.parent  # It should always default to the module
+        module = node.root()
         for name, asname in node.names:
             if name == "*":
                 try:
@@ -226,11 +234,16 @@
                 except AstroidBuildingError:
                     continue
                 for name in imported.public_names():
-                    node.parent.set_local(name, node)
-                    sort_locals(node.parent.scope().locals[name])  # type: ignore[arg-type]
+                    if name in global_name:
+                        add_local(module, name)
+                    else:
+                        add_local(node.parent, name)
             else:
-                node.parent.set_local(asname or name, node)
-                sort_locals(node.parent.scope().locals[asname or name])  # type: ignore[arg-type]
+                name = asname or name
+                if name in global_name:
+                    add_local(module, name)
+                else:
+                    add_local(node.parent, name)
 
     def delayed_assattr(self, node: nodes.AssignAttr) -> None:
         """Visit an AssignAttr node.
@@ -317,6 +330,7 @@
         isinstance(node, nodes.Call)
         and isinstance(node.func, nodes.Name)
         and node.func.name == _TRANSIENT_FUNCTION
+        and node.args
     ):
         real_expr = node.args[0]
         assert node.parent
diff --git a/astroid/const.py b/astroid/const.py
index c010818..dcce074 100644
--- a/astroid/const.py
+++ b/astroid/const.py
@@ -5,10 +5,11 @@
 import enum
 import sys
 
-PY310_PLUS = sys.version_info >= (3, 10)
 PY311_PLUS = sys.version_info >= (3, 11)
 PY312_PLUS = sys.version_info >= (3, 12)
+PY313 = sys.version_info[:2] == (3, 13)
 PY313_PLUS = sys.version_info >= (3, 13)
+PY314_PLUS = sys.version_info >= (3, 14)
 
 WIN32 = sys.platform == "win32"
 
diff --git a/astroid/constraint.py b/astroid/constraint.py
index 08bb80e..0dfecc3 100644
--- a/astroid/constraint.py
+++ b/astroid/constraint.py
@@ -3,14 +3,16 @@
 # Copyright (c) https://github.com/pylint-dev/astroid/blob/main/CONTRIBUTORS.txt
 
 """Classes representing different types of constraints on inference values."""
+
 from __future__ import annotations
 
 import sys
 from abc import ABC, abstractmethod
 from collections.abc import Iterator
-from typing import TYPE_CHECKING, Union
+from typing import TYPE_CHECKING
 
-from astroid import nodes, util
+from astroid import helpers, nodes, util
+from astroid.exceptions import AstroidTypeError, InferenceError, MroError
 from astroid.typing import InferenceResult
 
 if sys.version_info >= (3, 11):
@@ -21,7 +23,7 @@
 if TYPE_CHECKING:
     from astroid import bases
 
-_NameNodes = Union[nodes.AssignAttr, nodes.Attribute, nodes.AssignName, nodes.Name]
+_NameNodes = nodes.AssignAttr | nodes.Attribute | nodes.AssignName | nodes.Name
 
 
 class Constraint(ABC):
@@ -77,16 +79,160 @@
     def satisfied_by(self, inferred: InferenceResult) -> bool:
         """Return True if this constraint is satisfied by the given inferred value."""
         # Assume true if uninferable
-        if isinstance(inferred, util.UninferableBase):
+        if inferred is util.Uninferable:
             return True
 
         # Return the XOR of self.negate and matches(inferred, self.CONST_NONE)
         return self.negate ^ _matches(inferred, self.CONST_NONE)
 
 
+class BooleanConstraint(Constraint):
+    """Represents an "x" or "not x" constraint."""
+
+    @classmethod
+    def match(
+        cls, node: _NameNodes, expr: nodes.NodeNG, negate: bool = False
+    ) -> Self | None:
+        """Return a new constraint for node if expr matches one of these patterns:
+
+        - direct match (expr == node): use given negate value
+        - negated match (expr == `not node`): flip negate value
+
+        Return None if no pattern matches.
+        """
+        if _matches(expr, node):
+            return cls(node=node, negate=negate)
+
+        if (
+            isinstance(expr, nodes.UnaryOp)
+            and expr.op == "not"
+            and _matches(expr.operand, node)
+        ):
+            return cls(node=node, negate=not negate)
+
+        return None
+
+    def satisfied_by(self, inferred: InferenceResult) -> bool:
+        """Return True for uninferable results, or depending on negate flag:
+
+        - negate=False: satisfied if boolean value is True
+        - negate=True: satisfied if boolean value is False
+        """
+        inferred_booleaness = inferred.bool_value()
+        if inferred is util.Uninferable or inferred_booleaness is util.Uninferable:
+            return True
+
+        return self.negate ^ inferred_booleaness
+
+
+class TypeConstraint(Constraint):
+    """Represents an "isinstance(x, y)" constraint."""
+
+    def __init__(
+        self, node: nodes.NodeNG, classinfo: nodes.NodeNG, negate: bool
+    ) -> None:
+        super().__init__(node=node, negate=negate)
+        self.classinfo = classinfo
+
+    @classmethod
+    def match(
+        cls, node: _NameNodes, expr: nodes.NodeNG, negate: bool = False
+    ) -> Self | None:
+        """Return a new constraint for node if expr matches the
+        "isinstance(x, y)" pattern. Else, return None.
+        """
+        is_instance_call = (
+            isinstance(expr, nodes.Call)
+            and isinstance(expr.func, nodes.Name)
+            and expr.func.name == "isinstance"
+            and not expr.keywords
+            and len(expr.args) == 2
+        )
+        if is_instance_call and _matches(expr.args[0], node):
+            return cls(node=node, classinfo=expr.args[1], negate=negate)
+
+        return None
+
+    def satisfied_by(self, inferred: InferenceResult) -> bool:
+        """Return True for uninferable results, or depending on negate flag:
+
+        - negate=False: satisfied when inferred is an instance of the checked types.
+        - negate=True: satisfied when inferred is not an instance of the checked types.
+        """
+        if inferred is util.Uninferable:
+            return True
+
+        try:
+            types = helpers.class_or_tuple_to_container(self.classinfo)
+            matches_checked_types = helpers.object_isinstance(inferred, types)
+
+            if matches_checked_types is util.Uninferable:
+                return True
+
+            return self.negate ^ matches_checked_types
+        except (InferenceError, AstroidTypeError, MroError):
+            return True
+
+
+class EqualityConstraint(Constraint):
+    """Represents a "==" or "!=" constraint."""
+
+    def __init__(self, node: nodes.NodeNG, operand: nodes.NodeNG, negate: bool) -> None:
+        super().__init__(node=node, negate=negate)
+        self.operand = operand
+
+    @classmethod
+    def match(
+        cls, node: _NameNodes, expr: nodes.NodeNG, negate: bool = False
+    ) -> Self | None:
+        """Return a new constraint for node if expr matches one of these patterns:
+
+        - "node == operand" or "operand == node": use given negate value
+        - "node != operand" or "operand != node": flip negate value
+
+        Return None if no pattern matches.
+        """
+        if isinstance(expr, nodes.Compare) and len(expr.ops) == 1:
+            left = expr.left
+            op, right = expr.ops[0]
+            matches_left = _matches(left, node)
+
+            if op in {"==", "!="} and (matches_left or _matches(right, node)):
+                operand = right if matches_left else left
+                negate = (op == "==" and negate) or (op == "!=" and not negate)
+                return cls(node=node, operand=operand, negate=negate)
+
+        return None
+
+    def satisfied_by(self, inferred: InferenceResult) -> bool:
+        """Return True for uninferable/ambiguous results, or depending on negate flag:
+
+        - negate=False: satisfied when both operands are equal.
+        - negate=True: satisfied when both operands are not equal.
+
+        Only comparisons between constants and callables are supported.
+        """
+        if inferred is util.Uninferable:
+            return True
+
+        operand_inferred = util.safe_infer(self.operand)
+        if operand_inferred is util.Uninferable or operand_inferred is None:
+            return True
+
+        if isinstance(inferred, nodes.Const) and isinstance(
+            operand_inferred, nodes.Const
+        ):
+            return self.negate ^ (inferred.value == operand_inferred.value)
+
+        if inferred.callable() and operand_inferred.callable():
+            return self.negate ^ (inferred is operand_inferred)
+
+        return True
+
+
 def get_constraints(
     expr: _NameNodes, frame: nodes.LocalsDictNodeNG
-) -> dict[nodes.If, set[Constraint]]:
+) -> dict[nodes.If | nodes.IfExp, set[Constraint]]:
     """Returns the constraints for the given expression.
 
     The returned dictionary maps the node where the constraint was generated to the
@@ -96,10 +242,10 @@
     Currently this only supports constraints generated from if conditions.
     """
     current_node: nodes.NodeNG | None = expr
-    constraints_mapping: dict[nodes.If, set[Constraint]] = {}
+    constraints_mapping: dict[nodes.If | nodes.IfExp, set[Constraint]] = {}
     while current_node is not None and current_node is not frame:
         parent = current_node.parent
-        if isinstance(parent, nodes.If):
+        if isinstance(parent, (nodes.If, nodes.IfExp)):
             branch, _ = parent.locate_child(current_node)
             constraints: set[Constraint] | None = None
             if branch == "body":
@@ -114,7 +260,14 @@
     return constraints_mapping
 
 
-ALL_CONSTRAINT_CLASSES = frozenset((NoneConstraint,))
+ALL_CONSTRAINT_CLASSES = frozenset(
+    (
+        NoneConstraint,
+        BooleanConstraint,
+        TypeConstraint,
+        EqualityConstraint,
+    )
+)
 """All supported constraint types."""
 
 
diff --git a/astroid/context.py b/astroid/context.py
index 777565a..fa9ed22 100644
--- a/astroid/context.py
+++ b/astroid/context.py
@@ -9,17 +9,15 @@
 import contextlib
 import pprint
 from collections.abc import Iterator, Sequence
-from typing import TYPE_CHECKING, Optional
+from typing import TYPE_CHECKING
 
 from astroid.typing import InferenceResult, SuccessfulInferenceResult
 
 if TYPE_CHECKING:
     from astroid import constraint, nodes
-    from astroid.nodes.node_classes import Keyword
-    from astroid.nodes.node_ng import NodeNG
 
 _InferenceCache = dict[
-    tuple["NodeNG", Optional[str], Optional[str], Optional[str]], Sequence["NodeNG"]
+    tuple["nodes.NodeNG", str | None, str | None, str | None], Sequence["nodes.NodeNG"]
 ]
 
 _INFERENCE_CACHE: _InferenceCache = {}
@@ -80,7 +78,9 @@
         self.extra_context: dict[SuccessfulInferenceResult, InferenceContext] = {}
         """Context that needs to be passed down through call stacks for call arguments."""
 
-        self.constraints: dict[str, dict[nodes.If, set[constraint.Constraint]]] = {}
+        self.constraints: dict[
+            str, dict[nodes.If | nodes.IfExp, set[constraint.Constraint]]
+        ] = {}
         """The constraints on nodes."""
 
     @property
@@ -168,8 +168,8 @@
 
     def __init__(
         self,
-        args: list[NodeNG],
-        keywords: list[Keyword] | None = None,
+        args: list[nodes.NodeNG],
+        keywords: list[nodes.Keyword] | None = None,
         callee: InferenceResult | None = None,
     ):
         self.args = args  # Call positional arguments
diff --git a/astroid/decorators.py b/astroid/decorators.py
index 93c5fc9..05d2dd3 100644
--- a/astroid/decorators.py
+++ b/astroid/decorators.py
@@ -11,18 +11,13 @@
 import sys
 import warnings
 from collections.abc import Callable, Generator
-from typing import TypeVar
+from typing import ParamSpec, TypeVar
 
 from astroid import util
 from astroid.context import InferenceContext
 from astroid.exceptions import InferenceError
 from astroid.typing import InferenceResult
 
-if sys.version_info >= (3, 10):
-    from typing import ParamSpec
-else:
-    from typing_extensions import ParamSpec
-
 _R = TypeVar("_R")
 _P = ParamSpec("_P")
 
diff --git a/astroid/exceptions.py b/astroid/exceptions.py
index 126acb9..e523b70 100644
--- a/astroid/exceptions.py
+++ b/astroid/exceptions.py
@@ -64,7 +64,10 @@
             setattr(self, key, value)
 
     def __str__(self) -> str:
-        return self.message.format(**vars(self))
+        try:
+            return self.message.format(**vars(self))
+        except ValueError:
+            return self.message  # Return raw message if formatting fails
 
 
 class AstroidBuildingError(AstroidError):
diff --git a/astroid/helpers.py b/astroid/helpers.py
index 62a7259..deef3d9 100644
--- a/astroid/helpers.py
+++ b/astroid/helpers.py
@@ -104,7 +104,7 @@
         types = set(_object_type(node, context))
     except InferenceError:
         return util.Uninferable
-    if len(types) > 1 or not types:
+    if len(types) != 1:
         return util.Uninferable
     return next(iter(types))
 
@@ -129,7 +129,9 @@
     # issubclass(object, (1, type)) raises TypeError
     for klass in class_seq:
         if isinstance(klass, util.UninferableBase):
-            raise AstroidTypeError("arg 2 must be a type or tuple of types")
+            raise AstroidTypeError(
+                f"arg 2 must be a type or tuple of types, not {type(klass)!r}"
+            )
 
         for obj_subclass in obj_type.mro():
             if obj_subclass == klass:
@@ -164,10 +166,34 @@
         or its type's mro doesn't work
     """
     if not isinstance(node, nodes.ClassDef):
-        raise TypeError(f"{node} needs to be a ClassDef node")
+        raise TypeError(f"{node} needs to be a ClassDef node, not {type(node)!r}")
     return _object_type_is_subclass(node, class_or_seq, context=context)
 
 
+def class_or_tuple_to_container(
+    node: InferenceResult, context: InferenceContext | None = None
+) -> list[InferenceResult]:
+    # Move inferences results into container
+    # to simplify later logic
+    # raises InferenceError if any of the inferences fall through
+    try:
+        node_infer = next(node.infer(context=context))
+    except StopIteration as e:  # pragma: no cover
+        raise InferenceError(node=node, context=context) from e
+    # arg2 MUST be a type or a TUPLE of types
+    # for isinstance
+    if isinstance(node_infer, nodes.Tuple):
+        try:
+            class_container = [
+                next(node.infer(context=context)) for node in node_infer.elts
+            ]
+        except StopIteration as e:  # pragma: no cover
+            raise InferenceError(node=node, context=context) from e
+    else:
+        class_container = [node_infer]
+    return class_container
+
+
 def has_known_bases(klass, context: InferenceContext | None = None) -> bool:
     """Return whether all base classes of a class could be inferred."""
     try:
diff --git a/astroid/interpreter/_import/spec.py b/astroid/interpreter/_import/spec.py
index 7e51cc1..af7c55b 100644
--- a/astroid/interpreter/_import/spec.py
+++ b/astroid/interpreter/_import/spec.py
@@ -20,8 +20,6 @@
 from pathlib import Path
 from typing import Literal, NamedTuple, Protocol
 
-from astroid.const import PY310_PLUS
-
 from . import util
 
 
@@ -168,56 +166,30 @@
                 if cached_os_path_isfile(file_path):
                     return ModuleSpec(name=modname, location=file_path, type=type_)
 
-        # sys.stdlib_module_names was added in Python 3.10
-        if PY310_PLUS:
-            # If the module name matches a stdlib module name, check whether this is a frozen
-            # module. Note that `find_spec` actually imports parent modules, so we want to make
-            # sure we only run this code for stuff that can be expected to be frozen. For now
-            # this is only stdlib.
-            if (modname in sys.stdlib_module_names and not processed) or (
-                processed and processed[0] in sys.stdlib_module_names
-            ):
-                try:
-                    with warnings.catch_warnings():
-                        warnings.filterwarnings("ignore", category=Warning)
-                        spec = importlib.util.find_spec(".".join((*processed, modname)))
-                except ValueError:
-                    spec = None
+        # If the module name matches a stdlib module name, check whether this is a frozen
+        # module. Note that `find_spec` actually imports parent modules, so we want to make
+        # sure we only run this code for stuff that can be expected to be frozen. For now
+        # this is only stdlib.
+        if (modname in sys.stdlib_module_names and not processed) or (
+            processed and processed[0] in sys.stdlib_module_names
+        ):
+            try:
+                with warnings.catch_warnings():
+                    warnings.filterwarnings("ignore", category=Warning)
+                    spec = importlib.util.find_spec(".".join((*processed, modname)))
+            except ValueError:
+                spec = None
 
-                if (
-                    spec
-                    and spec.loader  # type: ignore[comparison-overlap] # noqa: E501
-                    is importlib.machinery.FrozenImporter
-                ):
-                    return ModuleSpec(
-                        name=modname,
-                        location=getattr(spec.loader_state, "filename", None),
-                        type=ModuleType.PY_FROZEN,
-                    )
-        else:
-            # NOTE: This is broken code. It doesn't work on Python 3.13+ where submodules can also
-            # be frozen. However, we don't want to worry about this and we don't want to break
-            # support for older versions of Python. This is just copy-pasted from the old non
-            # working version to at least have no functional behaviour change on <=3.10.
-            # It can be removed after 3.10 is no longer supported in favour of the logic above.
-            if submodule_path is None:  # pylint: disable=else-if-used
-                try:
-                    with warnings.catch_warnings():
-                        warnings.filterwarnings("ignore", category=UserWarning)
-                        spec = importlib.util.find_spec(modname)
-                    if (
-                        spec
-                        and spec.loader  # type: ignore[comparison-overlap] # noqa: E501
-                        is importlib.machinery.FrozenImporter
-                    ):
-                        # No need for BuiltinImporter; builtins handled above
-                        return ModuleSpec(
-                            name=modname,
-                            location=getattr(spec.loader_state, "filename", None),
-                            type=ModuleType.PY_FROZEN,
-                        )
-                except ValueError:
-                    pass
+            if (
+                spec
+                and spec.loader  # type: ignore[comparison-overlap] # noqa: E501
+                is importlib.machinery.FrozenImporter
+            ):
+                return ModuleSpec(
+                    name=modname,
+                    location=getattr(spec.loader_state, "filename", None),
+                    type=ModuleType.PY_FROZEN,
+                )
 
         return None
 
@@ -298,7 +270,7 @@
         for entry_path in path:
             if entry_path not in sys.path_importer_cache:
                 try:
-                    sys.path_importer_cache[entry_path] = zipimport.zipimporter(  # type: ignore[assignment]
+                    sys.path_importer_cache[entry_path] = zipimport.zipimporter(
                         entry_path
                     )
                 except zipimport.ZipImportError:
@@ -325,6 +297,11 @@
             submodule_search_locations=path,
         )
 
+    def contribute_to_path(
+        self, spec: ModuleSpec, processed: list[str]
+    ) -> Sequence[str] | None:
+        return spec.submodule_search_locations
+
 
 class PathSpecFinder(Finder):
     """Finder based on importlib.machinery.PathFinder."""
@@ -391,19 +368,9 @@
     modpath: tuple[str, ...],
 ) -> tuple[Literal[ModuleType.PY_ZIPMODULE], str, str]:
     for filepath, importer in _get_zipimporters():
-        if PY310_PLUS:
-            found = importer.find_spec(modpath[0])
-        else:
-            found = importer.find_module(modpath[0])
+        found = importer.find_spec(modpath[0])
         if found:
-            if PY310_PLUS:
-                if not importer.find_spec(os.path.sep.join(modpath)):
-                    raise ImportError(
-                        "No module named {} in {}/{}".format(
-                            ".".join(modpath[1:]), filepath, modpath
-                        )
-                    )
-            elif not importer.find_module(os.path.sep.join(modpath)):
+            if not importer.find_spec(os.path.sep.join(modpath)):
                 raise ImportError(
                     "No module named {} in {}/{}".format(
                         ".".join(modpath[1:]), filepath, modpath
diff --git a/astroid/interpreter/_import/util.py b/astroid/interpreter/_import/util.py
index 976fc00..df1aca2 100644
--- a/astroid/interpreter/_import/util.py
+++ b/astroid/interpreter/_import/util.py
@@ -83,7 +83,6 @@
 
             # Repair last_submodule_search_locations
             if last_submodule_search_locations:
-                # pylint: disable=unsubscriptable-object
                 last_item = last_submodule_search_locations[-1]
                 # e.g. for failure example above, add 'a/b' and keep going
                 # so that find_spec('a.b.c', path=['a', 'a/b']) succeeds
@@ -96,7 +95,10 @@
             # But immediately return False if we can detect we are in stdlib
             # or external lib (e.g site-packages)
             if any(
-                any(location.startswith(lib_dir) for lib_dir in STD_AND_EXT_LIB_DIRS)
+                any(
+                    str(location).startswith(lib_dir)
+                    for lib_dir in STD_AND_EXT_LIB_DIRS
+                )
                 for location in found_spec.submodule_search_locations
             ):
                 return False
diff --git a/astroid/interpreter/dunder_lookup.py b/astroid/interpreter/dunder_lookup.py
index 727c1ad..688971e 100644
--- a/astroid/interpreter/dunder_lookup.py
+++ b/astroid/interpreter/dunder_lookup.py
@@ -12,26 +12,27 @@
 As such, the lookup for the special methods is actually simpler than
 the dot attribute access.
 """
+
 from __future__ import annotations
 
 import itertools
 from typing import TYPE_CHECKING
 
 import astroid
+from astroid import nodes
 from astroid.exceptions import AttributeInferenceError
 
 if TYPE_CHECKING:
-    from astroid import nodes
     from astroid.context import InferenceContext
 
 
 def _lookup_in_mro(node, name) -> list:
     attrs = node.locals.get(name, [])
 
-    nodes = itertools.chain.from_iterable(
+    nodes_ = itertools.chain.from_iterable(
         ancestor.locals.get(name, []) for ancestor in node.ancestors(recurs=True)
     )
-    values = list(itertools.chain(attrs, nodes))
+    values = list(itertools.chain(attrs, nodes_))
     if not values:
         raise AttributeInferenceError(attribute=name, target=node)
 
@@ -47,13 +48,11 @@
     will be returned. Otherwise, `astroid.AttributeInferenceError`
     is going to be raised.
     """
-    if isinstance(
-        node, (astroid.List, astroid.Tuple, astroid.Const, astroid.Dict, astroid.Set)
-    ):
+    if isinstance(node, (nodes.List, nodes.Tuple, nodes.Const, nodes.Dict, nodes.Set)):
         return _builtin_lookup(node, name)
     if isinstance(node, astroid.Instance):
         return _lookup_in_mro(node, name)
-    if isinstance(node, astroid.ClassDef):
+    if isinstance(node, nodes.ClassDef):
         return _class_lookup(node, name, context=context)
 
     raise AttributeInferenceError(attribute=name, target=node)
diff --git a/astroid/interpreter/objectmodel.py b/astroid/interpreter/objectmodel.py
index fd8c0c0..148e7d7 100644
--- a/astroid/interpreter/objectmodel.py
+++ b/astroid/interpreter/objectmodel.py
@@ -87,8 +87,11 @@
         string = "%(cname)s(%(fields)s)"
         alignment = len(cname) + 1
         for field in sorted(self.attributes()):
-            width = 80 - len(field) - alignment
-            lines = pprint.pformat(field, indent=2, width=width).splitlines(True)
+            width = max(80 - len(field) - alignment, 1)
+            try:
+                lines = pprint.pformat(field, indent=2, width=width).splitlines(True)
+            except ValueError:
+                lines = [f"<{type(field).__name__}>"]
 
             inner = [lines[0]]
             for line in lines[1:]:
@@ -163,6 +166,33 @@
 
         return bases.BoundMethod(proxy=node, bound=_get_bound_node(self))
 
+    # Base object attributes that return Unknown as fallback placeholders.
+    @property
+    def attr___ne__(self):
+        return node_classes.Unknown(parent=self._instance)
+
+    attr___class__ = attr___ne__
+    attr___delattr__ = attr___ne__
+    attr___dir__ = attr___ne__
+    attr___doc__ = attr___ne__
+    attr___eq__ = attr___ne__
+    attr___format__ = attr___ne__
+    attr___ge__ = attr___ne__
+    attr___getattribute__ = attr___ne__
+    attr___getstate__ = attr___ne__
+    attr___gt__ = attr___ne__
+    attr___hash__ = attr___ne__
+    attr___init_subclass__ = attr___ne__
+    attr___le__ = attr___ne__
+    attr___lt__ = attr___ne__
+    attr___reduce__ = attr___ne__
+    attr___reduce_ex__ = attr___ne__
+    attr___repr__ = attr___ne__
+    attr___setattr__ = attr___ne__
+    attr___sizeof__ = attr___ne__
+    attr___str__ = attr___ne__
+    attr___subclasshook__ = attr___ne__
+
 
 class ModuleModel(ObjectModel):
     def _builtins(self):
@@ -228,20 +258,24 @@
     @property
     def attr___spec__(self):
         # No handling for now.
-        return node_classes.Unknown()
+        return node_classes.Unknown(parent=self._instance)
 
     @property
     def attr___loader__(self):
         # No handling for now.
-        return node_classes.Unknown()
+        return node_classes.Unknown(parent=self._instance)
 
     @property
     def attr___cached__(self):
         # No handling for now.
-        return node_classes.Unknown()
+        return node_classes.Unknown(parent=self._instance)
 
 
 class FunctionModel(ObjectModel):
+    def _is_builtin_func(self) -> bool:
+        func = self._instance
+        return isinstance(func.parent, nodes.Module) and not func.root().pure_python
+
     @property
     def attr___name__(self):
         return node_classes.Const(value=self._instance.name, parent=self._instance)
@@ -260,6 +294,8 @@
     @property
     def attr___defaults__(self):
         func = self._instance
+        if self._is_builtin_func():
+            raise AttributeInferenceError(target=func, attribute="__defaults__")
         if not func.args.defaults:
             return node_classes.Const(value=None, parent=func)
 
@@ -269,6 +305,10 @@
 
     @property
     def attr___annotations__(self):
+        if self._is_builtin_func():
+            raise AttributeInferenceError(
+                target=self._instance, attribute="__annotations__"
+            )
         obj = node_classes.Dict(
             parent=self._instance,
             lineno=self._instance.lineno,
@@ -309,6 +349,8 @@
 
     @property
     def attr___dict__(self):
+        if self._is_builtin_func():
+            raise AttributeInferenceError(target=self._instance, attribute="__dict__")
         return node_classes.Dict(
             parent=self._instance,
             lineno=self._instance.lineno,
@@ -317,10 +359,27 @@
             end_col_offset=self._instance.end_col_offset,
         )
 
-    attr___globals__ = attr___dict__
+    @property
+    def attr___globals__(self):
+        if self._is_builtin_func():
+            raise AttributeInferenceError(
+                target=self._instance, attribute="__globals__"
+            )
+        return node_classes.Dict(
+            parent=self._instance,
+            lineno=self._instance.lineno,
+            col_offset=self._instance.col_offset,
+            end_lineno=self._instance.end_lineno,
+            end_col_offset=self._instance.end_col_offset,
+        )
 
     @property
     def attr___kwdefaults__(self):
+        if self._is_builtin_func():
+            raise AttributeInferenceError(
+                target=self._instance, attribute="__kwdefaults__"
+            )
+
         def _default_args(args, parent):
             for arg in args.kwonlyargs:
                 try:
@@ -352,6 +411,9 @@
     def attr___get__(self):
         func = self._instance
 
+        if self._is_builtin_func():
+            raise AttributeInferenceError(target=func, attribute="__get__")
+
         class DescriptorBoundMethod(bases.BoundMethod):
             """Bound method which knows how to understand calling descriptor
             binding.
@@ -385,8 +447,12 @@
                         "Invalid class inferred", target=self, context=context
                     )
 
-                # For some reason func is a Node that the below
-                # code is not expecting
+                # The `func` can already be a Unbound or BoundMethod. If the former, make sure to
+                # wrap as a BoundMethod like we do below when constructing the function from scratch.
+                if isinstance(func, bases.UnboundMethod):
+                    yield bases.BoundMethod(proxy=func, bound=cls)
+                    return
+
                 if isinstance(func, bases.BoundMethod):
                     yield func
                     return
@@ -427,13 +493,13 @@
                 we get a new object which has two parameters, *self* and *type*.
                 """
                 nonlocal func
-                arguments = astroid.Arguments(
+                arguments = nodes.Arguments(
                     parent=func.args.parent, vararg=None, kwarg=None
                 )
 
                 positional_or_keyword_params = func.args.args.copy()
                 positional_or_keyword_params.append(
-                    astroid.AssignName(
+                    nodes.AssignName(
                         name="type",
                         lineno=0,
                         col_offset=0,
@@ -459,30 +525,15 @@
 
         return DescriptorBoundMethod(proxy=self._instance, bound=self._instance)
 
-    # These are here just for completion.
+    # Function-specific attributes.
     @property
-    def attr___ne__(self):
-        return node_classes.Unknown()
+    def attr___call__(self):
+        return node_classes.Unknown(parent=self._instance)
 
-    attr___subclasshook__ = attr___ne__
-    attr___str__ = attr___ne__
-    attr___sizeof__ = attr___ne__
-    attr___setattr___ = attr___ne__
-    attr___repr__ = attr___ne__
-    attr___reduce__ = attr___ne__
-    attr___reduce_ex__ = attr___ne__
-    attr___lt__ = attr___ne__
-    attr___eq__ = attr___ne__
-    attr___gt__ = attr___ne__
-    attr___format__ = attr___ne__
-    attr___delattr___ = attr___ne__
-    attr___getattribute__ = attr___ne__
-    attr___hash__ = attr___ne__
-    attr___dir__ = attr___ne__
-    attr___call__ = attr___ne__
-    attr___class__ = attr___ne__
-    attr___closure__ = attr___ne__
-    attr___code__ = attr___ne__
+    attr___builtins__ = attr___call__
+    attr___closure__ = attr___call__
+    attr___code__ = attr___call__
+    attr___type_params__ = attr___call__
 
 
 class ClassModel(ObjectModel):
@@ -493,8 +544,8 @@
         super().__init__()
 
     @property
-    def attr___annotations__(self) -> node_classes.Unkown:
-        return node_classes.Unknown()
+    def attr___annotations__(self) -> node_classes.Unknown:
+        return node_classes.Unknown(parent=self._instance)
 
     @property
     def attr___module__(self):
@@ -617,7 +668,7 @@
         return self._instance._proxied
 
 
-class UnboundMethodModel(ObjectModel):
+class UnboundMethodModel(FunctionModel):
     @property
     def attr___class__(self):
         # pylint: disable=import-outside-toplevel; circular import
@@ -770,6 +821,12 @@
         return node_classes.Const("")
 
 
+class GroupExceptionInstanceModel(ExceptionInstanceModel):
+    @property
+    def attr_exceptions(self) -> nodes.Tuple:
+        return node_classes.Tuple(parent=self._instance)
+
+
 class OSErrorInstanceModel(ExceptionInstanceModel):
     @property
     def attr_filename(self):
@@ -804,6 +861,7 @@
 
 BUILTIN_EXCEPTIONS = {
     "builtins.SyntaxError": SyntaxErrorInstanceModel,
+    "builtins.ExceptionGroup": GroupExceptionInstanceModel,
     "builtins.ImportError": ImportErrorInstanceModel,
     "builtins.UnicodeDecodeError": UnicodeDecodeErrorInstanceModel,
     # These are all similar to OSError in terms of attributes
@@ -946,7 +1004,7 @@
     def attr_fset(self):
         func = self._instance
 
-        def find_setter(func: Property) -> astroid.FunctionDef | None:
+        def find_setter(func: Property) -> nodes.FunctionDef | None:
             """
             Given a property, find the corresponding setter function and returns it.
 
diff --git a/astroid/manager.py b/astroid/manager.py
index 163321b..e232886 100644
--- a/astroid/manager.py
+++ b/astroid/manager.py
@@ -412,7 +412,7 @@
 
         `hook` must be a function that accepts a single argument `modname` which
         contains the name of the module or package that could not be imported.
-        If `hook` can resolve the import, must return a node of type `astroid.Module`,
+        If `hook` can resolve the import, must return a node of type `nodes.Module`,
         otherwise, it must raise `AstroidBuildingError`.
         """
         self._failed_import_hooks.append(hook)
diff --git a/astroid/modutils.py b/astroid/modutils.py
index 29d09f8..bb2c7c4 100644
--- a/astroid/modutils.py
+++ b/astroid/modutils.py
@@ -30,15 +30,11 @@
 from collections.abc import Callable, Iterable, Sequence
 from contextlib import redirect_stderr, redirect_stdout
 from functools import lru_cache
+from sys import stdlib_module_names
 
-from astroid.const import IS_JYTHON, PY310_PLUS
+from astroid.const import IS_JYTHON
 from astroid.interpreter._import import spec, util
 
-if PY310_PLUS:
-    from sys import stdlib_module_names
-else:
-    from astroid._backport_stdlib_names import stdlib_module_names
-
 logger = logging.getLogger(__name__)
 
 
@@ -236,6 +232,18 @@
     return True
 
 
+def _is_subpath(path: str, base: str) -> bool:
+    path = os.path.normcase(os.path.normpath(path))
+    base = os.path.normcase(os.path.normpath(base))
+    if not path.startswith(base):
+        return False
+    return (
+        (len(path) == len(base))
+        or (path[len(base)] == os.path.sep)
+        or (base.endswith(os.path.sep) and path[len(base) - 1] == os.path.sep)
+    )
+
+
 def _get_relative_base_path(filename: str, path_to_check: str) -> list[str] | None:
     """Extracts the relative mod path of the file to import from.
 
@@ -252,19 +260,18 @@
         _get_relative_base_path("/a/b/c/d.py", "/a/b") ->  ["c","d"]
         _get_relative_base_path("/a/b/c/d.py", "/dev") ->  None
     """
-    importable_path = None
-    path_to_check = os.path.normcase(path_to_check)
+    path_to_check = os.path.normcase(os.path.normpath(path_to_check))
+
     abs_filename = os.path.abspath(filename)
-    if os.path.normcase(abs_filename).startswith(path_to_check):
-        importable_path = abs_filename
+    if _is_subpath(abs_filename, path_to_check):
+        base_path = os.path.splitext(abs_filename)[0]
+        relative_base_path = base_path[len(path_to_check) :].lstrip(os.path.sep)
+        return [pkg for pkg in relative_base_path.split(os.sep) if pkg]
 
     real_filename = os.path.realpath(filename)
-    if os.path.normcase(real_filename).startswith(path_to_check):
-        importable_path = real_filename
-
-    if importable_path:
-        base_path = os.path.splitext(importable_path)[0]
-        relative_base_path = base_path[len(path_to_check) :]
+    if _is_subpath(real_filename, path_to_check):
+        base_path = os.path.splitext(real_filename)[0]
+        relative_base_path = base_path[len(path_to_check) :].lstrip(os.path.sep)
         return [pkg for pkg in relative_base_path.split(os.sep) if pkg]
 
     return None
@@ -365,7 +372,7 @@
     if modpath[0] == "xml":
         # handle _xmlplus
         try:
-            return _spec_from_modpath(["_xmlplus"] + modpath[1:], path, context)
+            return _spec_from_modpath(["_xmlplus", *modpath[1:]], path, context)
         except ImportError:
             return _spec_from_modpath(modpath, path, context)
     elif modpath == ["os", "path"]:
@@ -489,8 +496,9 @@
     """
     filename = os.path.abspath(_path_from_filename(filename))
     base, orig_ext = os.path.splitext(filename)
-    if orig_ext == ".pyi" and os.path.exists(f"{base}{orig_ext}"):
-        return f"{base}{orig_ext}"
+    orig_ext = orig_ext.lstrip(".")
+    if orig_ext not in PY_SOURCE_EXTS and os.path.exists(f"{base}.{orig_ext}"):
+        return f"{base}.{orig_ext}"
     for ext in PY_SOURCE_EXTS_STUBS_FIRST if prefer_stubs else PY_SOURCE_EXTS:
         source_path = f"{base}.{ext}"
         if os.path.exists(source_path):
diff --git a/astroid/nodes/__init__.py b/astroid/nodes/__init__.py
index 7202385..6a67516 100644
--- a/astroid/nodes/__init__.py
+++ b/astroid/nodes/__init__.py
@@ -50,6 +50,7 @@
     IfExp,
     Import,
     ImportFrom,
+    Interpolation,
     JoinedStr,
     Keyword,
     List,
@@ -76,6 +77,7 @@
     Slice,
     Starred,
     Subscript,
+    TemplateStr,
     Try,
     TryStar,
     Tuple,
@@ -247,6 +249,7 @@
     "IfExp",
     "Import",
     "ImportFrom",
+    "Interpolation",
     "JoinedStr",
     "Keyword",
     "Lambda",
@@ -278,6 +281,7 @@
     "Slice",
     "Starred",
     "Subscript",
+    "TemplateStr",
     "Try",
     "TryStar",
     "Tuple",
diff --git a/astroid/nodes/_base_nodes.py b/astroid/nodes/_base_nodes.py
index ca9fcd7..df452cb 100644
--- a/astroid/nodes/_base_nodes.py
+++ b/astroid/nodes/_base_nodes.py
@@ -12,10 +12,9 @@
 import itertools
 from collections.abc import Callable, Generator, Iterator
 from functools import cached_property, lru_cache, partial
-from typing import TYPE_CHECKING, Any, ClassVar, Optional, Union
+from typing import TYPE_CHECKING, Any, ClassVar
 
 from astroid import bases, nodes, util
-from astroid.const import PY310_PLUS
 from astroid.context import (
     CallContext,
     InferenceContext,
@@ -35,10 +34,10 @@
     GetFlowFactory = Callable[
         [
             InferenceResult,
-            Optional[InferenceResult],
-            Union[nodes.AugAssign, nodes.BinOp],
+            InferenceResult | None,
+            nodes.AugAssign | nodes.BinOp,
             InferenceResult,
-            Optional[InferenceResult],
+            InferenceResult | None,
             InferenceContext,
             InferenceContext,
         ],
@@ -605,8 +604,7 @@
 
         # pylint: disable = too-many-boolean-expressions
         if (
-            PY310_PLUS
-            and op == "|"
+            op == "|"
             and (
                 isinstance(left, (bases.UnionType, nodes.ClassDef))
                 or (isinstance(left, nodes.Const) and left.value is None)
diff --git a/astroid/nodes/as_string.py b/astroid/nodes/as_string.py
index ceb7410..01007b9 100644
--- a/astroid/nodes/as_string.py
+++ b/astroid/nodes/as_string.py
@@ -14,21 +14,6 @@
 
 if TYPE_CHECKING:
     from astroid import objects
-    from astroid.nodes import Const
-    from astroid.nodes.node_classes import (
-        Match,
-        MatchAs,
-        MatchCase,
-        MatchClass,
-        MatchMapping,
-        MatchOr,
-        MatchSequence,
-        MatchSingleton,
-        MatchStar,
-        MatchValue,
-        Unknown,
-    )
-    from astroid.nodes.node_ng import NodeNG
 
 # pylint: disable=unused-argument
 
@@ -43,11 +28,11 @@
     def __init__(self, indent: str = "    "):
         self.indent: str = indent
 
-    def __call__(self, node: NodeNG) -> str:
+    def __call__(self, node: nodes.NodeNG) -> str:
         """Makes this visitor behave as a simple function"""
         return node.accept(self).replace(DOC_NEWLINE, "\n")
 
-    def _docs_dedent(self, doc_node: Const | None) -> str:
+    def _docs_dedent(self, doc_node: nodes.Const | None) -> str:
         """Stop newlines in docs being indented by self._stmt_list"""
         if not doc_node:
             return ""
@@ -67,7 +52,7 @@
         return self.indent + stmts_str.replace("\n", "\n" + self.indent)
 
     def _precedence_parens(
-        self, node: NodeNG, child: NodeNG, is_left: bool = True
+        self, node: nodes.NodeNG, child: nodes.NodeNG, is_left: bool = True
     ) -> str:
         """Wrap child in parens only if required to keep same semantics"""
         if self._should_wrap(node, child, is_left):
@@ -75,7 +60,9 @@
 
         return child.accept(self)
 
-    def _should_wrap(self, node: NodeNG, child: NodeNG, is_left: bool) -> bool:
+    def _should_wrap(
+        self, node: nodes.NodeNG, child: nodes.NodeNG, is_left: bool
+    ) -> bool:
         """Wrap child if:
         - it has lower precedence
         - same precedence with position opposite to associativity direction
@@ -109,34 +96,34 @@
         return f"async {self.visit_for(node)}"
 
     def visit_arguments(self, node: nodes.Arguments) -> str:
-        """return an astroid.Arguments node as string"""
+        """return an nodes.Arguments node as string"""
         return node.format_args()
 
     def visit_assignattr(self, node: nodes.AssignAttr) -> str:
-        """return an astroid.AssignAttr node as string"""
+        """return an nodes.AssignAttr node as string"""
         return self.visit_attribute(node)
 
     def visit_assert(self, node: nodes.Assert) -> str:
-        """return an astroid.Assert node as string"""
+        """return an nodes.Assert node as string"""
         if node.fail:
             return f"assert {node.test.accept(self)}, {node.fail.accept(self)}"
         return f"assert {node.test.accept(self)}"
 
     def visit_assignname(self, node: nodes.AssignName) -> str:
-        """return an astroid.AssignName node as string"""
+        """return an nodes.AssignName node as string"""
         return node.name
 
     def visit_assign(self, node: nodes.Assign) -> str:
-        """return an astroid.Assign node as string"""
+        """return an nodes.Assign node as string"""
         lhs = " = ".join(n.accept(self) for n in node.targets)
         return f"{lhs} = {node.value.accept(self)}"
 
     def visit_augassign(self, node: nodes.AugAssign) -> str:
-        """return an astroid.AugAssign node as string"""
+        """return an nodes.AugAssign node as string"""
         return f"{node.target.accept(self)} {node.op} {node.value.accept(self)}"
 
     def visit_annassign(self, node: nodes.AnnAssign) -> str:
-        """Return an astroid.AnnAssign node as string"""
+        """Return an nodes.AnnAssign node as string"""
 
         target = node.target.accept(self)
         annotation = node.annotation.accept(self)
@@ -145,7 +132,7 @@
         return f"{target}: {annotation} = {node.value.accept(self)}"
 
     def visit_binop(self, node: nodes.BinOp) -> str:
-        """return an astroid.BinOp node as string"""
+        """return an nodes.BinOp node as string"""
         left = self._precedence_parens(node, node.left)
         right = self._precedence_parens(node, node.right, is_left=False)
         if node.op == "**":
@@ -154,16 +141,16 @@
         return f"{left} {node.op} {right}"
 
     def visit_boolop(self, node: nodes.BoolOp) -> str:
-        """return an astroid.BoolOp node as string"""
+        """return an nodes.BoolOp node as string"""
         values = [f"{self._precedence_parens(node, n)}" for n in node.values]
         return (f" {node.op} ").join(values)
 
     def visit_break(self, node: nodes.Break) -> str:
-        """return an astroid.Break node as string"""
+        """return an nodes.Break node as string"""
         return "break"
 
     def visit_call(self, node: nodes.Call) -> str:
-        """return an astroid.Call node as string"""
+        """return an nodes.Call node as string"""
         expr_str = self._precedence_parens(node, node.func)
         args = [arg.accept(self) for arg in node.args]
         if node.keywords:
@@ -174,22 +161,31 @@
         args.extend(keywords)
         return f"{expr_str}({', '.join(args)})"
 
+    def _handle_type_params(
+        self, type_params: list[nodes.TypeVar | nodes.ParamSpec | nodes.TypeVarTuple]
+    ) -> str:
+        return (
+            f"[{', '.join(tp.accept(self) for tp in type_params)}]"
+            if type_params
+            else ""
+        )
+
     def visit_classdef(self, node: nodes.ClassDef) -> str:
-        """return an astroid.ClassDef node as string"""
+        """return an nodes.ClassDef node as string"""
         decorate = node.decorators.accept(self) if node.decorators else ""
+        type_params = self._handle_type_params(node.type_params)
         args = [n.accept(self) for n in node.bases]
         if node._metaclass and not node.has_metaclass_hack():
             args.append("metaclass=" + node._metaclass.accept(self))
         args += [n.accept(self) for n in node.keywords]
         args_str = f"({', '.join(args)})" if args else ""
         docs = self._docs_dedent(node.doc_node)
-        # TODO: handle type_params
-        return "\n\n{}class {}{}:{}\n{}\n".format(
-            decorate, node.name, args_str, docs, self._stmt_list(node.body)
+        return "\n\n{}class {}{}{}:{}\n{}\n".format(
+            decorate, node.name, type_params, args_str, docs, self._stmt_list(node.body)
         )
 
     def visit_compare(self, node: nodes.Compare) -> str:
-        """return an astroid.Compare node as string"""
+        """return an nodes.Compare node as string"""
         rhs_str = " ".join(
             f"{op} {self._precedence_parens(node, expr, is_left=False)}"
             for op, expr in node.ops
@@ -197,39 +193,39 @@
         return f"{self._precedence_parens(node, node.left)} {rhs_str}"
 
     def visit_comprehension(self, node: nodes.Comprehension) -> str:
-        """return an astroid.Comprehension node as string"""
+        """return an nodes.Comprehension node as string"""
         ifs = "".join(f" if {n.accept(self)}" for n in node.ifs)
         generated = f"for {node.target.accept(self)} in {node.iter.accept(self)}{ifs}"
         return f"{'async ' if node.is_async else ''}{generated}"
 
     def visit_const(self, node: nodes.Const) -> str:
-        """return an astroid.Const node as string"""
+        """return an nodes.Const node as string"""
         if node.value is Ellipsis:
             return "..."
         return repr(node.value)
 
     def visit_continue(self, node: nodes.Continue) -> str:
-        """return an astroid.Continue node as string"""
+        """return an nodes.Continue node as string"""
         return "continue"
 
     def visit_delete(self, node: nodes.Delete) -> str:
-        """return an astroid.Delete node as string"""
+        """return an nodes.Delete node as string"""
         return f"del {', '.join(child.accept(self) for child in node.targets)}"
 
     def visit_delattr(self, node: nodes.DelAttr) -> str:
-        """return an astroid.DelAttr node as string"""
+        """return an nodes.DelAttr node as string"""
         return self.visit_attribute(node)
 
     def visit_delname(self, node: nodes.DelName) -> str:
-        """return an astroid.DelName node as string"""
+        """return an nodes.DelName node as string"""
         return node.name
 
     def visit_decorators(self, node: nodes.Decorators) -> str:
-        """return an astroid.Decorators node as string"""
+        """return an nodes.Decorators node as string"""
         return "@%s\n" % "\n@".join(item.accept(self) for item in node.nodes)
 
     def visit_dict(self, node: nodes.Dict) -> str:
-        """return an astroid.Dict node as string"""
+        """return an nodes.Dict node as string"""
         return "{%s}" % ", ".join(self._visit_dict(node))
 
     def _visit_dict(self, node: nodes.Dict) -> Iterator[str]:
@@ -246,7 +242,7 @@
         return "**"
 
     def visit_dictcomp(self, node: nodes.DictComp) -> str:
-        """return an astroid.DictComp node as string"""
+        """return an nodes.DictComp node as string"""
         return "{{{}: {} {}}}".format(
             node.key.accept(self),
             node.value.accept(self),
@@ -254,7 +250,7 @@
         )
 
     def visit_expr(self, node: nodes.Expr) -> str:
-        """return an astroid.Expr node as string"""
+        """return an nodes.Expr node as string"""
         return node.value.accept(self)
 
     def visit_emptynode(self, node: nodes.EmptyNode) -> str:
@@ -279,7 +275,7 @@
         return ""
 
     def visit_for(self, node: nodes.For) -> str:
-        """return an astroid.For node as string"""
+        """return an nodes.For node as string"""
         fors = "for {} in {}:\n{}".format(
             node.target.accept(self), node.iter.accept(self), self._stmt_list(node.body)
         )
@@ -288,7 +284,7 @@
         return fors
 
     def visit_importfrom(self, node: nodes.ImportFrom) -> str:
-        """return an astroid.ImportFrom node as string"""
+        """return an nodes.ImportFrom node as string"""
         return "from {} import {}".format(
             "." * (node.level or 0) + node.modname, _import_string(node.names)
         )
@@ -334,17 +330,18 @@
     def handle_functiondef(self, node: nodes.FunctionDef, keyword: str) -> str:
         """return a (possibly async) function definition node as string"""
         decorate = node.decorators.accept(self) if node.decorators else ""
+        type_params = self._handle_type_params(node.type_params)
         docs = self._docs_dedent(node.doc_node)
         trailer = ":"
         if node.returns:
             return_annotation = " -> " + node.returns.as_string()
             trailer = return_annotation + ":"
-        # TODO: handle type_params
-        def_format = "\n%s%s %s(%s)%s%s\n%s"
+        def_format = "\n%s%s %s%s(%s)%s%s\n%s"
         return def_format % (
             decorate,
             keyword,
             node.name,
+            type_params,
             node.args.accept(self),
             trailer,
             docs,
@@ -352,15 +349,15 @@
         )
 
     def visit_functiondef(self, node: nodes.FunctionDef) -> str:
-        """return an astroid.FunctionDef node as string"""
+        """return an nodes.FunctionDef node as string"""
         return self.handle_functiondef(node, "def")
 
     def visit_asyncfunctiondef(self, node: nodes.AsyncFunctionDef) -> str:
-        """return an astroid.AsyncFunction node as string"""
+        """return an nodes.AsyncFunction node as string"""
         return self.handle_functiondef(node, "async def")
 
     def visit_generatorexp(self, node: nodes.GeneratorExp) -> str:
-        """return an astroid.GeneratorExp node as string"""
+        """return an nodes.GeneratorExp node as string"""
         return "({} {})".format(
             node.elt.accept(self), " ".join(n.accept(self) for n in node.generators)
         )
@@ -368,7 +365,7 @@
     def visit_attribute(
         self, node: nodes.Attribute | nodes.AssignAttr | nodes.DelAttr
     ) -> str:
-        """return an astroid.Attribute node as string"""
+        """return an nodes.Attribute node as string"""
         try:
             left = self._precedence_parens(node, node.expr)
         except RecursionError:
@@ -383,11 +380,11 @@
         return f"{left}.{node.attrname}"
 
     def visit_global(self, node: nodes.Global) -> str:
-        """return an astroid.Global node as string"""
+        """return an nodes.Global node as string"""
         return f"global {', '.join(node.names)}"
 
     def visit_if(self, node: nodes.If) -> str:
-        """return an astroid.If node as string"""
+        """return an nodes.If node as string"""
         ifs = [f"if {node.test.accept(self)}:\n{self._stmt_list(node.body)}"]
         if node.has_elif_block():
             ifs.append(f"el{self._stmt_list(node.orelse, indent=False)}")
@@ -396,7 +393,7 @@
         return "\n".join(ifs)
 
     def visit_ifexp(self, node: nodes.IfExp) -> str:
-        """return an astroid.IfExp node as string"""
+        """return an nodes.IfExp node as string"""
         return "{} if {} else {}".format(
             self._precedence_parens(node, node.body, is_left=True),
             self._precedence_parens(node, node.test, is_left=True),
@@ -404,17 +401,17 @@
         )
 
     def visit_import(self, node: nodes.Import) -> str:
-        """return an astroid.Import node as string"""
+        """return an nodes.Import node as string"""
         return f"import {_import_string(node.names)}"
 
     def visit_keyword(self, node: nodes.Keyword) -> str:
-        """return an astroid.Keyword node as string"""
+        """return an nodes.Keyword node as string"""
         if node.arg is None:
             return f"**{node.value.accept(self)}"
         return f"{node.arg}={node.value.accept(self)}"
 
     def visit_lambda(self, node: nodes.Lambda) -> str:
-        """return an astroid.Lambda node as string"""
+        """return an nodes.Lambda node as string"""
         args = node.args.accept(self)
         body = node.body.accept(self)
         if args:
@@ -423,22 +420,22 @@
         return f"lambda: {body}"
 
     def visit_list(self, node: nodes.List) -> str:
-        """return an astroid.List node as string"""
+        """return an nodes.List node as string"""
         return f"[{', '.join(child.accept(self) for child in node.elts)}]"
 
     def visit_listcomp(self, node: nodes.ListComp) -> str:
-        """return an astroid.ListComp node as string"""
+        """return an nodes.ListComp node as string"""
         return "[{} {}]".format(
             node.elt.accept(self), " ".join(n.accept(self) for n in node.generators)
         )
 
     def visit_module(self, node: nodes.Module) -> str:
-        """return an astroid.Module node as string"""
+        """return an nodes.Module node as string"""
         docs = f'"""{node.doc_node.value}"""\n\n' if node.doc_node else ""
         return docs + "\n".join(n.accept(self) for n in node.body) + "\n\n"
 
     def visit_name(self, node: nodes.Name) -> str:
-        """return an astroid.Name node as string"""
+        """return an nodes.Name node as string"""
         return node.name
 
     def visit_namedexpr(self, node: nodes.NamedExpr) -> str:
@@ -448,15 +445,18 @@
         return f"{target} := {value}"
 
     def visit_nonlocal(self, node: nodes.Nonlocal) -> str:
-        """return an astroid.Nonlocal node as string"""
+        """return an nodes.Nonlocal node as string"""
         return f"nonlocal {', '.join(node.names)}"
 
     def visit_paramspec(self, node: nodes.ParamSpec) -> str:
-        """return an astroid.ParamSpec node as string"""
-        return node.name.accept(self)
+        """return an nodes.ParamSpec node as string"""
+        default_value_str = (
+            f" = {node.default_value.accept(self)}" if node.default_value else ""
+        )
+        return f"**{node.name.accept(self)}{default_value_str}"
 
     def visit_pass(self, node: nodes.Pass) -> str:
-        """return an astroid.Pass node as string"""
+        """return an nodes.Pass node as string"""
         return "pass"
 
     def visit_partialfunction(self, node: objects.PartialFunction) -> str:
@@ -464,7 +464,7 @@
         return self.visit_functiondef(node)
 
     def visit_raise(self, node: nodes.Raise) -> str:
-        """return an astroid.Raise node as string"""
+        """return an nodes.Raise node as string"""
         if node.exc:
             if node.cause:
                 return f"raise {node.exc.accept(self)} from {node.cause.accept(self)}"
@@ -472,7 +472,7 @@
         return "raise"
 
     def visit_return(self, node: nodes.Return) -> str:
-        """return an astroid.Return node as string"""
+        """return an nodes.Return node as string"""
         if node.is_tuple_return() and len(node.value.elts) > 1:
             elts = [child.accept(self) for child in node.value.elts]
             return f"return {', '.join(elts)}"
@@ -483,17 +483,17 @@
         return "return"
 
     def visit_set(self, node: nodes.Set) -> str:
-        """return an astroid.Set node as string"""
+        """return an nodes.Set node as string"""
         return "{%s}" % ", ".join(child.accept(self) for child in node.elts)
 
     def visit_setcomp(self, node: nodes.SetComp) -> str:
-        """return an astroid.SetComp node as string"""
+        """return an nodes.SetComp node as string"""
         return "{{{} {}}}".format(
             node.elt.accept(self), " ".join(n.accept(self) for n in node.generators)
         )
 
     def visit_slice(self, node: nodes.Slice) -> str:
-        """return an astroid.Slice node as string"""
+        """return an nodes.Slice node as string"""
         lower = node.lower.accept(self) if node.lower else ""
         upper = node.upper.accept(self) if node.upper else ""
         step = node.step.accept(self) if node.step else ""
@@ -502,7 +502,7 @@
         return f"{lower}:{upper}"
 
     def visit_subscript(self, node: nodes.Subscript) -> str:
-        """return an astroid.Subscript node as string"""
+        """return an nodes.Subscript node as string"""
         idx = node.slice
         if idx.__class__.__name__.lower() == "index":
             idx = idx.value
@@ -514,7 +514,7 @@
         return f"{self._precedence_parens(node, node.value)}[{idxstr}]"
 
     def visit_try(self, node: nodes.Try) -> str:
-        """return an astroid.Try node as string"""
+        """return an nodes.Try node as string"""
         trys = [f"try:\n{self._stmt_list(node.body)}"]
         for handler in node.handlers:
             trys.append(handler.accept(self))
@@ -525,7 +525,7 @@
         return "\n".join(trys)
 
     def visit_trystar(self, node: nodes.TryStar) -> str:
-        """return an astroid.TryStar node as string"""
+        """return an nodes.TryStar node as string"""
         trys = [f"try:\n{self._stmt_list(node.body)}"]
         for handler in node.handlers:
             trys.append(handler.accept(self))
@@ -536,25 +536,33 @@
         return "\n".join(trys)
 
     def visit_tuple(self, node: nodes.Tuple) -> str:
-        """return an astroid.Tuple node as string"""
+        """return an nodes.Tuple node as string"""
         if len(node.elts) == 1:
             return f"({node.elts[0].accept(self)}, )"
         return f"({', '.join(child.accept(self) for child in node.elts)})"
 
     def visit_typealias(self, node: nodes.TypeAlias) -> str:
-        """return an astroid.TypeAlias node as string"""
-        return node.name.accept(self) if node.name else "_"
+        """return an nodes.TypeAlias node as string"""
+        type_params = self._handle_type_params(node.type_params)
+        return f"type {node.name.accept(self)}{type_params} = {node.value.accept(self)}"
 
     def visit_typevar(self, node: nodes.TypeVar) -> str:
-        """return an astroid.TypeVar node as string"""
-        return node.name.accept(self) if node.name else "_"
+        """return an nodes.TypeVar node as string"""
+        bound_str = f": {node.bound.accept(self)}" if node.bound else ""
+        default_value_str = (
+            f" = {node.default_value.accept(self)}" if node.default_value else ""
+        )
+        return f"{node.name.accept(self)}{bound_str}{default_value_str}"
 
     def visit_typevartuple(self, node: nodes.TypeVarTuple) -> str:
-        """return an astroid.TypeVarTuple node as string"""
-        return "*" + node.name.accept(self) if node.name else ""
+        """return an nodes.TypeVarTuple node as string"""
+        default_value_str = (
+            f" = {node.default_value.accept(self)}" if node.default_value else ""
+        )
+        return f"*{node.name.accept(self)}{default_value_str}"
 
     def visit_unaryop(self, node: nodes.UnaryOp) -> str:
-        """return an astroid.UnaryOp node as string"""
+        """return an nodes.UnaryOp node as string"""
         if node.op == "not":
             operator = "not "
         else:
@@ -562,14 +570,14 @@
         return f"{operator}{self._precedence_parens(node, node.operand)}"
 
     def visit_while(self, node: nodes.While) -> str:
-        """return an astroid.While node as string"""
+        """return an nodes.While node as string"""
         whiles = f"while {node.test.accept(self)}:\n{self._stmt_list(node.body)}"
         if node.orelse:
             whiles = f"{whiles}\nelse:\n{self._stmt_list(node.orelse)}"
         return whiles
 
     def visit_with(self, node: nodes.With) -> str:  # 'with' without 'as' is possible
-        """return an astroid.With node as string"""
+        """return an nodes.With node as string"""
         items = ", ".join(
             f"{expr.accept(self)}" + ((v and f" as {v.accept(self)}") or "")
             for expr, v in node.items
@@ -586,7 +594,7 @@
         return f"({expr})"
 
     def visit_yieldfrom(self, node: nodes.YieldFrom) -> str:
-        """Return an astroid.YieldFrom node as string."""
+        """Return an nodes.YieldFrom node as string."""
         yi_val = (" " + node.value.accept(self)) if node.value else ""
         expr = "yield from" + yi_val
         if node.parent.is_statement:
@@ -598,35 +606,35 @@
         """return Starred node as string"""
         return "*" + node.value.accept(self)
 
-    def visit_match(self, node: Match) -> str:
-        """Return an astroid.Match node as string."""
+    def visit_match(self, node: nodes.Match) -> str:
+        """Return an nodes.Match node as string."""
         return f"match {node.subject.accept(self)}:\n{self._stmt_list(node.cases)}"
 
-    def visit_matchcase(self, node: MatchCase) -> str:
-        """Return an astroid.MatchCase node as string."""
+    def visit_matchcase(self, node: nodes.MatchCase) -> str:
+        """Return an nodes.MatchCase node as string."""
         guard_str = f" if {node.guard.accept(self)}" if node.guard else ""
         return (
             f"case {node.pattern.accept(self)}{guard_str}:\n"
             f"{self._stmt_list(node.body)}"
         )
 
-    def visit_matchvalue(self, node: MatchValue) -> str:
-        """Return an astroid.MatchValue node as string."""
+    def visit_matchvalue(self, node: nodes.MatchValue) -> str:
+        """Return an nodes.MatchValue node as string."""
         return node.value.accept(self)
 
     @staticmethod
-    def visit_matchsingleton(node: MatchSingleton) -> str:
-        """Return an astroid.MatchSingleton node as string."""
+    def visit_matchsingleton(node: nodes.MatchSingleton) -> str:
+        """Return an nodes.MatchSingleton node as string."""
         return str(node.value)
 
-    def visit_matchsequence(self, node: MatchSequence) -> str:
-        """Return an astroid.MatchSequence node as string."""
+    def visit_matchsequence(self, node: nodes.MatchSequence) -> str:
+        """Return an nodes.MatchSequence node as string."""
         if node.patterns is None:
             return "[]"
         return f"[{', '.join(p.accept(self) for p in node.patterns)}]"
 
-    def visit_matchmapping(self, node: MatchMapping) -> str:
-        """Return an astroid.MatchMapping node as string."""
+    def visit_matchmapping(self, node: nodes.MatchMapping) -> str:
+        """Return an nodes..MatchMapping node as string."""
         mapping_strings: list[str] = []
         if node.keys and node.patterns:
             mapping_strings.extend(
@@ -637,8 +645,8 @@
             mapping_strings.append(f"**{node.rest.accept(self)}")
         return f"{'{'}{', '.join(mapping_strings)}{'}'}"
 
-    def visit_matchclass(self, node: MatchClass) -> str:
-        """Return an astroid.MatchClass node as string."""
+    def visit_matchclass(self, node: nodes.MatchClass) -> str:
+        """Return an nodes..MatchClass node as string."""
         if node.cls is None:
             raise AssertionError(f"{node} does not have a 'cls' node")
         class_strings: list[str] = []
@@ -649,29 +657,53 @@
                 class_strings.append(f"{attr}={pattern.accept(self)}")
         return f"{node.cls.accept(self)}({', '.join(class_strings)})"
 
-    def visit_matchstar(self, node: MatchStar) -> str:
-        """Return an astroid.MatchStar node as string."""
+    def visit_matchstar(self, node: nodes.MatchStar) -> str:
+        """Return an nodes..MatchStar node as string."""
         return f"*{node.name.accept(self) if node.name else '_'}"
 
-    def visit_matchas(self, node: MatchAs) -> str:
-        """Return an astroid.MatchAs node as string."""
-        # pylint: disable=import-outside-toplevel
-        # Prevent circular dependency
-        from astroid.nodes.node_classes import MatchClass, MatchMapping, MatchSequence
-
-        if isinstance(node.parent, (MatchSequence, MatchMapping, MatchClass)):
+    def visit_matchas(self, node: nodes.MatchAs) -> str:
+        """Return an nodes..MatchAs node as string."""
+        if isinstance(
+            node.parent, (nodes.MatchSequence, nodes.MatchMapping, nodes.MatchClass)
+        ):
             return node.name.accept(self) if node.name else "_"
         return (
             f"{node.pattern.accept(self) if node.pattern else '_'}"
             f"{f' as {node.name.accept(self)}' if node.name else ''}"
         )
 
-    def visit_matchor(self, node: MatchOr) -> str:
-        """Return an astroid.MatchOr node as string."""
+    def visit_matchor(self, node: nodes.MatchOr) -> str:
+        """Return an nodes.MatchOr node as string."""
         if node.patterns is None:
             raise AssertionError(f"{node} does not have pattern nodes")
         return " | ".join(p.accept(self) for p in node.patterns)
 
+    def visit_templatestr(self, node: nodes.TemplateStr) -> str:
+        """Return an nodes.TemplateStr node as string."""
+        string = ""
+        for value in node.values:
+            match value:
+                case nodes.Interpolation():
+                    string += "{" + value.accept(self) + "}"
+                case _:
+                    string += value.accept(self)[1:-1]
+        for quote in ("'", '"', '"""', "'''"):
+            if quote not in string:
+                break
+        return "t" + quote + string + quote
+
+    def visit_interpolation(self, node: nodes.Interpolation) -> str:
+        """Return an nodes.Interpolation node as string."""
+        result = f"{node.str}"
+        if node.conversion and node.conversion >= 0:
+            # e.g. if node.conversion == 114: result += "!r"
+            result += "!" + chr(node.conversion)
+        if node.format_spec:
+            # The format spec is itself a JoinedString, i.e. an f-string
+            # We strip the f and quotes of the ends
+            result += ":" + node.format_spec.accept(self)[2:-1]
+        return result
+
     # These aren't for real AST nodes, but for inference objects.
 
     def visit_frozenset(self, node: objects.FrozenSet) -> str:
@@ -689,7 +721,7 @@
     def visit_evaluatedobject(self, node: nodes.EvaluatedObject) -> str:
         return node.original.accept(self)
 
-    def visit_unknown(self, node: Unknown) -> str:
+    def visit_unknown(self, node: nodes.Unknown) -> str:
         return str(node)
 
 
diff --git a/astroid/nodes/node_classes.py b/astroid/nodes/node_classes.py
index ebfd5ff..af2131c 100644
--- a/astroid/nodes/node_classes.py
+++ b/astroid/nodes/node_classes.py
@@ -15,18 +15,11 @@
 import warnings
 from collections.abc import Callable, Generator, Iterable, Iterator, Mapping
 from functools import cached_property
-from typing import (
-    TYPE_CHECKING,
-    Any,
-    ClassVar,
-    Literal,
-    Optional,
-    Union,
-)
+from typing import TYPE_CHECKING, Any, ClassVar, Literal, Union
 
 from astroid import decorators, protocols, util
 from astroid.bases import Instance, _infer_stmts
-from astroid.const import _EMPTY_OBJECT_MARKER, Context
+from astroid.const import _EMPTY_OBJECT_MARKER, PY314_PLUS, Context
 from astroid.context import CallContext, InferenceContext, copy_context
 from astroid.exceptions import (
     AstroidBuildingError,
@@ -62,6 +55,7 @@
 if TYPE_CHECKING:
     from astroid import nodes
     from astroid.nodes import LocalsDictNodeNG
+    from astroid.nodes.node_ng import FrameType
 
 
 def _is_const(value) -> bool:
@@ -71,23 +65,24 @@
 _NodesT = typing.TypeVar("_NodesT", bound=NodeNG)
 _BadOpMessageT = typing.TypeVar("_BadOpMessageT", bound=util.BadOperationMessage)
 
+# pylint: disable-next=consider-alternative-union-syntax
 AssignedStmtsPossibleNode = Union["List", "Tuple", "AssignName", "AssignAttr", None]
 AssignedStmtsCall = Callable[
     [
         _NodesT,
         AssignedStmtsPossibleNode,
-        Optional[InferenceContext],
-        Optional[list[int]],
+        InferenceContext | None,
+        list[int] | None,
     ],
     Any,
 ]
 InferBinaryOperation = Callable[
-    [_NodesT, Optional[InferenceContext]],
-    Generator[Union[InferenceResult, _BadOpMessageT]],
+    [_NodesT, InferenceContext | None],
+    Generator[InferenceResult | _BadOpMessageT],
 ]
 InferLHS = Callable[
-    [_NodesT, Optional[InferenceContext]],
-    Generator[InferenceResult, None, Optional[InferenceErrorInfo]],
+    [_NodesT, InferenceContext | None],
+    Generator[InferenceResult, None, InferenceErrorInfo | None],
 ]
 InferUnaryOp = Callable[[_NodesT, str], ConstFactoryResult]
 
@@ -1026,9 +1021,26 @@
             if elt is not None:
                 yield elt
 
+    def get_annotations(self) -> Iterator[nodes.NodeNG]:
+        """Iterate over all annotations nodes."""
+        for elt in self.posonlyargs_annotations:
+            if elt is not None:
+                yield elt
+        for elt in self.annotations:
+            if elt is not None:
+                yield elt
+        if self.varargannotation is not None:
+            yield self.varargannotation
+
+        for elt in self.kwonlyargs_annotations:
+            if elt is not None:
+                yield elt
+        if self.kwargannotation is not None:
+            yield self.kwargannotation
+
     @decorators.raise_if_nothing_inferred
     def _infer(
-        self: nodes.Arguments, context: InferenceContext | None = None, **kwargs: Any
+        self, context: InferenceContext | None = None, **kwargs: Any
     ) -> Generator[InferenceResult]:
         # pylint: disable-next=import-outside-toplevel
         from astroid.protocols import _arguments_infer_argname
@@ -1447,7 +1459,7 @@
     @decorators.raise_if_nothing_inferred
     @decorators.path_wrapper
     def _infer(
-        self: nodes.AugAssign, context: InferenceContext | None = None, **kwargs: Any
+        self, context: InferenceContext | None = None, **kwargs: Any
     ) -> Generator[InferenceResult]:
         return self._filter_operation_errors(
             self._infer_augassign, context, util.BadBinaryOperationMessage
@@ -1562,7 +1574,7 @@
     @decorators.yes_if_nothing_inferred
     @decorators.path_wrapper
     def _infer(
-        self: nodes.BinOp, context: InferenceContext | None = None, **kwargs: Any
+        self, context: InferenceContext | None = None, **kwargs: Any
     ) -> Generator[InferenceResult]:
         return self._filter_operation_errors(
             self._infer_binop, context, util.BadBinaryOperationMessage
@@ -1639,7 +1651,7 @@
     @decorators.raise_if_nothing_inferred
     @decorators.path_wrapper
     def _infer(
-        self: nodes.BoolOp, context: InferenceContext | None = None, **kwargs: Any
+        self, context: InferenceContext | None = None, **kwargs: Any
     ) -> Generator[InferenceResult, None, InferenceErrorInfo | None]:
         """Infer a boolean operation (and / or / not).
 
@@ -1857,7 +1869,7 @@
     # TODO: move to util?
     @staticmethod
     def _to_literal(node: SuccessfulInferenceResult) -> Any:
-        # Can raise SyntaxError or ValueError from ast.literal_eval
+        # Can raise SyntaxError, ValueError, or TypeError from ast.literal_eval
         # Can raise AttributeError from node.as_string() as not all nodes have a visitor
         # Is this the stupidest idea or the simplest idea?
         return ast.literal_eval(node.as_string())
@@ -1893,7 +1905,7 @@
 
             try:
                 left, right = self._to_literal(left), self._to_literal(right)
-            except (SyntaxError, ValueError, AttributeError):
+            except (SyntaxError, ValueError, AttributeError, TypeError):
                 return util.Uninferable
 
             try:
@@ -2139,7 +2151,11 @@
                 message="Type error {error!r}", node=self, index=index, context=context
             ) from exc
 
-        raise AstroidTypeError(f"{self!r} (value={self.value})")
+        try:
+            value_str = str(self.value)
+        except ValueError:
+            value_str = f"<{type(self.value).__name__} (too large to display)>"
+        raise AstroidTypeError(f"{self!r} (value={value_str})")
 
     def has_dynamic_getattr(self) -> bool:
         """Check if the node has a custom __getattr__ or __getattribute__.
@@ -2172,8 +2188,12 @@
         """Determine the boolean value of this node.
 
         :returns: The boolean value of this node.
-        :rtype: bool
+        :rtype: bool or Uninferable
         """
+        # bool(NotImplemented) is deprecated; it raises TypeError starting from Python 3.14
+        # and returns True for versions under 3.14
+        if self.value is NotImplemented:
+            return util.Uninferable if PY314_PLUS else True
         return bool(self.value)
 
     def _infer(
@@ -2224,13 +2244,22 @@
 
         :returns: The first parent scope node.
         """
-        # skip the function node to go directly to the upper level scope
+        # skip the function or class node to go directly to the upper level scope
         if not self.parent:
             raise ParentMissingError(target=self)
         if not self.parent.parent:
             raise ParentMissingError(target=self.parent)
         return self.parent.parent.scope()
 
+    def frame(self) -> FrameType:
+        """The first parent node defining a new frame."""
+        # skip the function or class node to go directly to the upper level frame
+        if not self.parent:
+            raise ParentMissingError(target=self)
+        if not self.parent.parent:
+            raise ParentMissingError(target=self.parent)
+        return self.parent.parent.frame()
+
     def get_children(self):
         yield from self.nodes
 
@@ -3110,28 +3139,37 @@
         to inferring both branches. Otherwise, we infer either branch
         depending on the condition.
         """
-        both_branches = False
+
         # We use two separate contexts for evaluating lhs and rhs because
         # evaluating lhs may leave some undesired entries in context.path
         # which may not let us infer right value of rhs.
-
         context = context or InferenceContext()
         lhs_context = copy_context(context)
         rhs_context = copy_context(context)
+
+        # Infer bool condition. Stop inferring if in doubt and fallback to
+        # evaluating both branches.
+        condition: bool | None = None
         try:
-            test = next(self.test.infer(context=context.clone()))
-        except (InferenceError, StopIteration):
-            both_branches = True
-        else:
-            if not isinstance(test, util.UninferableBase):
-                if test.bool_value():
-                    yield from self.body.infer(context=lhs_context)
-                else:
-                    yield from self.orelse.infer(context=rhs_context)
-            else:
-                both_branches = True
-        if both_branches:
+            for test in self.test.infer(context=context.clone()):
+                if isinstance(test, util.UninferableBase):
+                    condition = None
+                    break
+                test_bool_value = test.bool_value()
+                if isinstance(test_bool_value, util.UninferableBase):
+                    condition = None
+                    break
+                if condition is None:
+                    condition = test_bool_value
+                elif test_bool_value != condition:
+                    condition = None
+                    break
+        except InferenceError:
+            condition = None
+
+        if condition is True or condition is None:
             yield from self.body.infer(context=lhs_context)
+        if condition is False or condition is None:
             yield from self.orelse.infer(context=rhs_context)
 
 
@@ -3389,9 +3427,9 @@
     <ParamSpec l.1 at 0x7f23b2e4e198>
     """
 
-    _astroid_fields = ("name",)
-
+    _astroid_fields = ("name", "default_value")
     name: AssignName
+    default_value: NodeNG | None
 
     def __init__(
         self,
@@ -3410,8 +3448,9 @@
             parent=parent,
         )
 
-    def postinit(self, *, name: AssignName) -> None:
+    def postinit(self, *, name: AssignName, default_value: NodeNG | None) -> None:
         self.name = name
+        self.default_value = default_value
 
     def _infer(
         self, context: InferenceContext | None = None, **kwargs: Any
@@ -4147,10 +4186,10 @@
     <TypeVar l.1 at 0x7f23b2e4e198>
     """
 
-    _astroid_fields = ("name", "bound")
-
+    _astroid_fields = ("name", "bound", "default_value")
     name: AssignName
     bound: NodeNG | None
+    default_value: NodeNG | None
 
     def __init__(
         self,
@@ -4169,9 +4208,16 @@
             parent=parent,
         )
 
-    def postinit(self, *, name: AssignName, bound: NodeNG | None) -> None:
+    def postinit(
+        self,
+        *,
+        name: AssignName,
+        bound: NodeNG | None,
+        default_value: NodeNG | None = None,
+    ) -> None:
         self.name = name
         self.bound = bound
+        self.default_value = default_value
 
     def _infer(
         self, context: InferenceContext | None = None, **kwargs: Any
@@ -4193,9 +4239,9 @@
     <TypeVarTuple l.1 at 0x7f23b2e4e198>
     """
 
-    _astroid_fields = ("name",)
-
+    _astroid_fields = ("name", "default_value")
     name: AssignName
+    default_value: NodeNG | None
 
     def __init__(
         self,
@@ -4214,8 +4260,11 @@
             parent=parent,
         )
 
-    def postinit(self, *, name: AssignName) -> None:
+    def postinit(
+        self, *, name: AssignName, default_value: NodeNG | None = None
+    ) -> None:
         self.name = name
+        self.default_value = default_value
 
     def _infer(
         self, context: InferenceContext | None = None, **kwargs: Any
@@ -4306,7 +4355,7 @@
         return super().op_precedence()
 
     def _infer_unaryop(
-        self: nodes.UnaryOp, context: InferenceContext | None = None, **kwargs: Any
+        self, context: InferenceContext | None = None, **kwargs: Any
     ) -> Generator[
         InferenceResult | util.BadUnaryOperationMessage, None, InferenceErrorInfo
     ]:
@@ -4372,7 +4421,7 @@
     @decorators.raise_if_nothing_inferred
     @decorators.path_wrapper
     def _infer(
-        self: nodes.UnaryOp, context: InferenceContext | None = None, **kwargs: Any
+        self, context: InferenceContext | None = None, **kwargs: Any
     ) -> Generator[InferenceResult, None, InferenceErrorInfo]:
         """Infer what an UnaryOp should return when evaluated."""
         yield from self._filter_operation_errors(
@@ -4695,6 +4744,9 @@
                     uninferable_already_generated = True
                 continue
             for value in self.value.infer(context, **kwargs):
+                if value is util.Uninferable:
+                    yield util.Uninferable
+                    return
                 value_to_format = value
                 if isinstance(value, Const):
                     value_to_format = value.value
@@ -4708,8 +4760,9 @@
                         end_col_offset=self.end_col_offset,
                     )
                     continue
-                except (ValueError, TypeError):
-                    # happens when format_spec.value is invalid
+                except (ValueError, TypeError, MemoryError):
+                    # ValueError/TypeError: invalid format spec
+                    # MemoryError: format spec with huge width (e.g. f'{0:11111111111}')
                     yield util.Uninferable
                     uninferable_already_generated = True
                 continue
@@ -4898,7 +4951,7 @@
     See astroid/protocols.py for actual implementation.
     """
 
-    def frame(self) -> nodes.FunctionDef | nodes.Module | nodes.ClassDef | nodes.Lambda:
+    def frame(self) -> FrameType:
         """The first parent frame node.
 
         A frame node is a :class:`Module`, :class:`FunctionDef`,
@@ -4954,18 +5007,19 @@
 
 class Unknown(_base_nodes.AssignTypeNode):
     """This node represents a node in a constructed AST where
-    introspection is not possible.  At the moment, it's only used in
-    the args attribute of FunctionDef nodes where function signature
-    introspection failed.
+    introspection is not possible.
+
+    Used in the args attribute of FunctionDef nodes where function signature
+    introspection failed, and as a placeholder in ObjectModel.
     """
 
     name = "Unknown"
 
     def __init__(
         self,
+        parent: NodeNG,
         lineno: None = None,
         col_offset: None = None,
-        parent: None = None,
         *,
         end_lineno: None = None,
         end_col_offset: None = None,
@@ -4986,6 +5040,9 @@
         yield util.Uninferable
 
 
+UNATTACHED_UNKNOWN = Unknown(parent=SYNTHETIC_ROOT)
+
+
 class EvaluatedObject(NodeNG):
     """Contains an object that has already been inferred
 
@@ -5487,6 +5544,114 @@
         self.patterns = patterns
 
 
+class TemplateStr(NodeNG):
+    """Class representing an :class:`ast.TemplateStr` node.
+
+    >>> import astroid
+    >>> node = astroid.extract_node('t"{name} finished {place!s}"')
+    >>> node
+    <TemplateStr l.1 at 0x103b7aa50>
+    """
+
+    _astroid_fields = ("values",)
+
+    def __init__(
+        self,
+        lineno: int | None = None,
+        col_offset: int | None = None,
+        parent: NodeNG | None = None,
+        *,
+        end_lineno: int | None = None,
+        end_col_offset: int | None = None,
+    ) -> None:
+        self.values: list[NodeNG]
+        super().__init__(
+            lineno=lineno,
+            col_offset=col_offset,
+            end_lineno=end_lineno,
+            end_col_offset=end_col_offset,
+            parent=parent,
+        )
+
+    def postinit(self, *, values: list[NodeNG]) -> None:
+        self.values = values
+
+    def get_children(self) -> Iterator[NodeNG]:
+        yield from self.values
+
+
+class Interpolation(NodeNG):
+    """Class representing an :class:`ast.Interpolation` node.
+
+    >>> import astroid
+    >>> node = astroid.extract_node('t"{name} finished {place!s}"')
+    >>> node
+    <TemplateStr l.1 at 0x103b7aa50>
+    >>> node.values[0]
+    <Interpolation l.1 at 0x103b7acf0>
+    >>> node.values[2]
+    <Interpolation l.1 at 0x10411e5d0>
+    """
+
+    _astroid_fields = ("value", "format_spec")
+    _other_fields = ("str", "conversion")
+
+    def __init__(
+        self,
+        lineno: int | None = None,
+        col_offset: int | None = None,
+        parent: NodeNG | None = None,
+        *,
+        end_lineno: int | None = None,
+        end_col_offset: int | None = None,
+    ) -> None:
+        self.value: NodeNG
+        """Any expression node."""
+
+        self.str: str
+        """Text of the interpolation expression."""
+
+        self.conversion: int
+        """The type of formatting to be applied to the value.
+
+        .. seealso::
+            :class:`ast.Interpolation`
+        """
+
+        self.format_spec: JoinedStr | None = None
+        """The formatting to be applied to the value.
+
+        .. seealso::
+            :class:`ast.Interpolation`
+        """
+
+        super().__init__(
+            lineno=lineno,
+            col_offset=col_offset,
+            end_lineno=end_lineno,
+            end_col_offset=end_col_offset,
+            parent=parent,
+        )
+
+    def postinit(
+        self,
+        *,
+        value: NodeNG,
+        str: str,  # pylint: disable=redefined-builtin
+        conversion: int = -1,
+        format_spec: JoinedStr | None = None,
+    ) -> None:
+        self.value = value
+        self.str = str
+        self.conversion = conversion
+        self.format_spec = format_spec
+
+    def get_children(self) -> Iterator[NodeNG]:
+        yield self.value
+        if self.format_spec:
+            yield self.format_spec
+
+
 # constants ##############################################################
 
 # The _proxied attribute of all container types (List, Tuple, etc.)
diff --git a/astroid/nodes/node_ng.py b/astroid/nodes/node_ng.py
index dc8942b..a1255b9 100644
--- a/astroid/nodes/node_ng.py
+++ b/astroid/nodes/node_ng.py
@@ -14,7 +14,6 @@
     Any,
     ClassVar,
     TypeVar,
-    Union,
     cast,
     overload,
 )
@@ -43,12 +42,14 @@
 if TYPE_CHECKING:
     from astroid.nodes import _base_nodes
 
+    FrameType = nodes.FunctionDef | nodes.Module | nodes.ClassDef | nodes.Lambda
+
 
 # Types for 'NodeNG.nodes_of_class()'
 _NodesT = TypeVar("_NodesT", bound="NodeNG")
 _NodesT2 = TypeVar("_NodesT2", bound="NodeNG")
 _NodesT3 = TypeVar("_NodesT3", bound="NodeNG")
-SkipKlassT = Union[None, type["NodeNG"], tuple[type["NodeNG"], ...]]
+SkipKlassT = None | type["NodeNG"] | tuple[type["NodeNG"], ...]
 
 
 class NodeNG:
@@ -197,8 +198,11 @@
         result = []
         for field in self._other_fields + self._astroid_fields:
             value = getattr(self, field, "Unknown")
-            width = 80 - len(field) - alignment
-            lines = pprint.pformat(value, indent=2, width=width).splitlines(True)
+            width = max(80 - len(field) - alignment, 1)
+            try:
+                lines = pprint.pformat(value, indent=2, width=width).splitlines(True)
+            except ValueError:
+                lines = [f"<{type(value).__name__}>"]
 
             inner = [lines[0]]
             for line in lines[1:]:
@@ -285,7 +289,7 @@
             raise StatementMissing(target=self)
         return self.parent.statement()
 
-    def frame(self) -> nodes.FunctionDef | nodes.Module | nodes.ClassDef | nodes.Lambda:
+    def frame(self) -> FrameType:
         """The first parent frame node.
 
         A frame node is a :class:`Module`, :class:`FunctionDef`,
diff --git a/astroid/nodes/scoped_nodes/mixin.py b/astroid/nodes/scoped_nodes/mixin.py
index 8874c06..d10d317 100644
--- a/astroid/nodes/scoped_nodes/mixin.py
+++ b/astroid/nodes/scoped_nodes/mixin.py
@@ -6,7 +6,8 @@
 
 from __future__ import annotations
 
-from typing import TYPE_CHECKING, TypeVar, overload
+import sys
+from typing import TYPE_CHECKING, overload
 
 from astroid.exceptions import ParentMissingError
 from astroid.filter_statements import _filter_stmts
@@ -14,11 +15,13 @@
 from astroid.nodes.scoped_nodes.utils import builtin_lookup
 from astroid.typing import InferenceResult, SuccessfulInferenceResult
 
+if sys.version_info >= (3, 11):
+    from typing import Self
+else:
+    from typing_extensions import Self
 if TYPE_CHECKING:
     from astroid import nodes
 
-_T = TypeVar("_T")
-
 
 class LocalsDictNodeNG(_base_nodes.LookupMixIn):
     """this class provides locals handling common to Module, FunctionDef
@@ -46,7 +49,7 @@
         except ParentMissingError:
             return self.name
 
-    def scope(self: _T) -> _T:
+    def scope(self) -> Self:
         """The first parent node defining a new scope.
 
         :returns: The first parent scope node.
diff --git a/astroid/nodes/scoped_nodes/scoped_nodes.py b/astroid/nodes/scoped_nodes/scoped_nodes.py
index 020ea40..6345134 100644
--- a/astroid/nodes/scoped_nodes/scoped_nodes.py
+++ b/astroid/nodes/scoped_nodes/scoped_nodes.py
@@ -13,9 +13,10 @@
 import io
 import itertools
 import os
+import sys
 from collections.abc import Generator, Iterable, Iterator, Sequence
 from functools import cached_property, lru_cache
-from typing import TYPE_CHECKING, Any, ClassVar, Literal, NoReturn, TypeVar
+from typing import TYPE_CHECKING, Any, ClassVar, Literal, NoReturn
 
 from astroid import bases, protocols, util
 from astroid.context import (
@@ -50,6 +51,11 @@
     SuccessfulInferenceResult,
 )
 
+if sys.version_info >= (3, 11):
+    from typing import Self
+else:
+    from typing_extensions import Self
+
 if TYPE_CHECKING:
     from astroid import nodes, objects
     from astroid.nodes import Arguments, Const, NodeNG
@@ -62,8 +68,6 @@
     {"classmethod", "staticmethod", "builtins.classmethod", "builtins.staticmethod"}
 )
 
-_T = TypeVar("_T")
-
 
 def _c3_merge(sequences, cls, context):
     """Merges MROs in *sequences* to a single MRO using the C3 algorithm.
@@ -587,7 +591,7 @@
     def get_children(self):
         yield from self.body
 
-    def frame(self: _T, *, future: Literal[None, True] = None) -> _T:
+    def frame(self, *, future: Literal[None, True] = None) -> Self:
         """The node's frame node.
 
         A frame node is a :class:`Module`, :class:`FunctionDef`,
@@ -1030,7 +1034,7 @@
         yield self.args
         yield self.body
 
-    def frame(self: _T, *, future: Literal[None, True] = None) -> _T:
+    def frame(self, *, future: Literal[None, True] = None) -> Self:
         """The node's frame node.
 
         A frame node is a :class:`Module`, :class:`FunctionDef`,
@@ -1223,7 +1227,7 @@
         The property will return all the callables that are used for
         decoration.
         """
-        if not self.parent or not isinstance(frame := self.parent.frame(), ClassDef):
+        if not (self.parent and isinstance(frame := self.parent.frame(), ClassDef)):
             return []
 
         decorators: list[node_classes.Call] = []
@@ -1401,6 +1405,8 @@
 
         :type: int
         """
+        if self.returns:
+            return self.returns.tolineno
         return self.args.tolineno
 
     def implicit_parameters(self) -> Literal[0, 1]:
@@ -1517,7 +1523,7 @@
     ) -> Generator[objects.Property | FunctionDef, None, InferenceErrorInfo]:
         from astroid import objects  # pylint: disable=import-outside-toplevel
 
-        if not self.decorators or not bases._is_property(self):
+        if not (self.decorators and bases._is_property(self)):
             yield self
             return InferenceErrorInfo(node=self, context=context)
 
@@ -1618,6 +1624,16 @@
                     yield node_classes.Const(None)
                 return
 
+            # Builtin dunder methods have empty bodies, return Uninferable.
+            if (
+                len(self.body) == 0
+                and self.name.startswith("__")
+                and self.name.endswith("__")
+                and self.root().qname() == "builtins"
+            ):
+                yield util.Uninferable
+                return
+
             raise InferenceError("The function does not have any return statements")
 
         for returnnode in itertools.chain((first_return,), returns):
@@ -1675,7 +1691,7 @@
             frame = self
         return frame._scope_lookup(node, name, offset)
 
-    def frame(self: _T, *, future: Literal[None, True] = None) -> _T:
+    def frame(self, *, future: Literal[None, True] = None) -> Self:
         """The node's frame node.
 
         A frame node is a :class:`Module`, :class:`FunctionDef`,
@@ -2346,8 +2362,10 @@
             values += classnode.locals.get(name, [])
 
         if name in self.special_attributes and class_context and not values:
-            result = [self.special_attributes.lookup(name)]
-            return result
+            special_attr = self.special_attributes.lookup(name)
+            if not isinstance(special_attr, node_classes.Unknown):
+                result = [special_attr]
+                return result
 
         if class_context:
             values += self._metaclass_lookup_attribute(name, context)
@@ -2725,9 +2743,10 @@
             for elt in values:
                 try:
                     for inferred in elt.infer():
-                        if not isinstance(
-                            inferred, node_classes.Const
-                        ) or not isinstance(inferred.value, str):
+                        if not (
+                            isinstance(inferred, node_classes.Const)
+                            and isinstance(inferred.value, str)
+                        ):
                             continue
                         if not inferred.value:
                             continue
@@ -2822,11 +2841,41 @@
                 baseobj = baseobj._proxied
             if not isinstance(baseobj, ClassDef):
                 continue
+            if baseobj is self:
+                # Circular base due to name rebinding (e.g. pdb.Pdb = CustomPdb
+                # where CustomPdb inherits from pdb.Pdb). Fall back to the
+                # first non-circular inferred value from the base expression.
+                baseobj = self._resolve_circular_base(stmt, context)
+                if baseobj is None:
+                    continue
             if not baseobj.hide:
                 yield baseobj
             else:
                 yield from baseobj.bases
 
+    def _resolve_circular_base(
+        self,
+        stmt: nodes.NodeNG,
+        context: InferenceContext | None,
+    ) -> ClassDef | None:
+        """Resolve a circular base reference by finding the original class.
+
+        When a name is rebound to a subclass (e.g. ``pdb.Pdb = CustomPdb``),
+        ``_infer_last`` follows the rebinding and returns the subclass itself.
+        This method iterates through all inferred values to find the first
+        non-circular ClassDef.
+        """
+        inf_context = copy_context(context)
+        try:
+            for inferred in stmt.infer(context=inf_context):
+                if isinstance(inferred, bases.Instance):
+                    inferred = inferred._proxied
+                if isinstance(inferred, ClassDef) and inferred is not self:
+                    return inferred
+        except InferenceError:
+            pass
+        return None
+
     def _compute_mro(self, context: InferenceContext | None = None):
         if self.qname() == "builtins.object":
             return [self]
@@ -2881,7 +2930,7 @@
         )
         return list(itertools.chain.from_iterable(children_assign_nodes))
 
-    def frame(self: _T, *, future: Literal[None, True] = None) -> _T:
+    def frame(self, *, future: Literal[None, True] = None) -> Self:
         """The node's frame node.
 
         A frame node is a :class:`Module`, :class:`FunctionDef`,
diff --git a/astroid/objects.py b/astroid/objects.py
index 9f638d4..bfc5ddc 100644
--- a/astroid/objects.py
+++ b/astroid/objects.py
@@ -13,9 +13,10 @@
 
 from __future__ import annotations
 
+import sys
 from collections.abc import Generator, Iterator
 from functools import cached_property
-from typing import Any, Literal, NoReturn, TypeVar
+from typing import Any, Literal, NoReturn
 
 from astroid import bases, util
 from astroid.context import InferenceContext
@@ -30,7 +31,10 @@
 from astroid.nodes import node_classes, scoped_nodes
 from astroid.typing import InferenceResult, SuccessfulInferenceResult
 
-_T = TypeVar("_T")
+if sys.version_info >= (3, 11):
+    from typing import Self
+else:
+    from typing_extensions import Self
 
 
 class FrozenSet(node_classes.BaseContainer):
@@ -190,7 +194,8 @@
                 # We can obtain different descriptors from a super depending
                 # on what we are accessing and where the super call is.
                 if inferred.type == "classmethod":
-                    yield bases.BoundMethod(inferred, cls)
+                    # Pass original caller for classmethod too
+                    yield bases.BoundMethod(inferred, cls, original_caller=self.type)
                 elif self._scope.type == "classmethod" and inferred.type == "method":
                     yield inferred
                 elif self._class_based or inferred.type == "staticmethod":
@@ -210,13 +215,17 @@
                     except InferenceError:
                         yield util.Uninferable
                 else:
-                    yield bases.BoundMethod(inferred, cls)
+                    # Pass original caller (self.type) so infer_call_result can
+                    # correctly resolve Self return types to the actual caller type
+                    yield bases.BoundMethod(inferred, cls, original_caller=self.type)
 
         # Only if we haven't found any explicit overwrites for the
         # attribute we look it up in the special attributes
         if not found and name in self.special_attributes:
-            yield self.special_attributes.lookup(name)
-            return
+            special_attr = self.special_attributes.lookup(name)
+            if not isinstance(special_attr, node_classes.Unknown):
+                yield special_attr
+                return
 
         if not found:
             raise AttributeInferenceError(target=self, attribute=name, context=context)
@@ -274,18 +283,15 @@
     """A class representing partial function obtained via functools.partial."""
 
     def __init__(self, call, name=None, lineno=None, col_offset=None, parent=None):
-        # TODO: Pass end_lineno, end_col_offset and parent as well
+        # TODO: Pass end_lineno, end_col_offset as well
         super().__init__(
             name,
             lineno=lineno,
             col_offset=col_offset,
-            parent=scoped_nodes.SYNTHETIC_ROOT,
             end_col_offset=0,
             end_lineno=0,
+            parent=parent,
         )
-        # A typical FunctionDef automatically adds its name to the parent scope,
-        # but a partial should not, so defer setting parent until after init
-        self.parent = parent
         self.filled_args = call.positional_arguments[1:]
         self.filled_keywords = call.keyword_arguments
 
@@ -358,6 +364,6 @@
         raise InferenceError("Properties are not callable")
 
     def _infer(
-        self: _T, context: InferenceContext | None = None, **kwargs: Any
-    ) -> Generator[_T]:
+        self, context: InferenceContext | None = None, **kwargs: Any
+    ) -> Generator[Self]:
         yield self
diff --git a/astroid/protocols.py b/astroid/protocols.py
index 8a837b8..6565688 100644
--- a/astroid/protocols.py
+++ b/astroid/protocols.py
@@ -15,6 +15,7 @@
 from typing import TYPE_CHECKING, Any, TypeVar
 
 from astroid import bases, decorators, nodes, util
+from astroid.builder import extract_node
 from astroid.const import Context
 from astroid.context import InferenceContext, copy_context
 from astroid.exceptions import (
@@ -142,7 +143,7 @@
     context: InferenceContext,
 ) -> _TupleListNodeT:
     node = self.__class__(parent=opnode)
-    if value <= 0 or not self.elts:
+    if not (value > 0 and self.elts):
         node.elts = []
         return node
     if len(self.elts) * value > 1e8:
@@ -162,13 +163,13 @@
 ) -> Iterator[SuccessfulInferenceResult]:
     for elt in elts:
         if isinstance(elt, util.UninferableBase):
-            yield nodes.Unknown()
+            yield node_classes.UNATTACHED_UNKNOWN
         else:
             for inferred in elt.infer(context):
                 if not isinstance(inferred, util.UninferableBase):
                     yield inferred
                 else:
-                    yield nodes.Unknown()
+                    yield node_classes.UNATTACHED_UNKNOWN
 
 
 @decorators.yes_if_nothing_inferred
@@ -527,11 +528,28 @@
 ) -> Any:
     from astroid import objects  # pylint: disable=import-outside-toplevel
 
-    for assigned in node_classes.unpack_infer(self.type):
-        if isinstance(assigned, nodes.ClassDef):
-            assigned = objects.ExceptionInstance(assigned)
+    def _generate_assigned():
+        for assigned in node_classes.unpack_infer(self.type):
+            if isinstance(assigned, nodes.ClassDef):
+                assigned = objects.ExceptionInstance(assigned)
 
+            yield assigned
+
+    if isinstance(self.parent, node_classes.TryStar):
+        # except * handler has assigned ExceptionGroup with caught
+        # exceptions under exceptions attribute
+        # pylint: disable-next=stop-iteration-return
+        eg = next(node_classes.unpack_infer(extract_node("""
+from builtins import ExceptionGroup
+ExceptionGroup
+""")))
+        assigned = objects.ExceptionInstance(eg)
+        assigned.instance_attrs["exceptions"] = [
+            nodes.List.from_elements(_generate_assigned())
+        ]
         yield assigned
+    else:
+        yield from _generate_assigned()
     return {
         "node": self,
         "unknown": node,
@@ -809,7 +827,7 @@
 
         if not isinstance(target, nodes.Tuple):
             raise InferenceError(
-                "Could not make sense of this, the target must be a tuple",
+                f"Could not make sense of this, the target must be a tuple, not {type(target)!r}",
                 context=context,
             )
 
diff --git a/astroid/raw_building.py b/astroid/raw_building.py
index 150a40b..e7c5562 100644
--- a/astroid/raw_building.py
+++ b/astroid/raw_building.py
@@ -18,7 +18,7 @@
 import warnings
 from collections.abc import Iterable
 from contextlib import redirect_stderr, redirect_stdout
-from typing import TYPE_CHECKING, Any, Union
+from typing import TYPE_CHECKING, Any
 
 from astroid import bases, nodes
 from astroid.const import _EMPTY_OBJECT_MARKER, IS_PYPY
@@ -30,14 +30,14 @@
 logger = logging.getLogger(__name__)
 
 
-_FunctionTypes = Union[
-    types.FunctionType,
-    types.MethodType,
-    types.BuiltinFunctionType,
-    types.WrapperDescriptorType,
-    types.MethodDescriptorType,
-    types.ClassMethodDescriptorType,
-]
+_FunctionTypes = (
+    types.FunctionType
+    | types.MethodType
+    | types.BuiltinFunctionType
+    | types.WrapperDescriptorType
+    | types.MethodDescriptorType
+    | types.ClassMethodDescriptorType
+)
 
 TYPE_NONE = type(None)
 TYPE_NOTIMPLEMENTED = type(NotImplemented)
@@ -78,7 +78,11 @@
     """create a Const node and register it in the locals of the given
     node with the specified name
     """
-    if name not in node.special_attributes:
+    # Special case: __hash__ = None overrides ObjectModel for unhashable types.
+    # See https://docs.python.org/3/reference/datamodel.html#object.__hash__
+    if name == "__hash__" and value is None:
+        _attach_local_node(node, nodes.const_factory(value), name)
+    elif name not in node.special_attributes:
         _attach_local_node(node, nodes.const_factory(value), name)
 
 
@@ -507,7 +511,11 @@
             elif inspect.isdatadescriptor(member):
                 child = object_build_datadescriptor(node, member)
             elif isinstance(member, tuple(node_classes.CONST_CLS)):
-                if alias in node.special_attributes:
+                # Special case: __hash__ = None overrides ObjectModel for unhashable types.
+                # See https://docs.python.org/3/reference/datamodel.html#object.__hash__
+                if alias in node.special_attributes and not (
+                    alias == "__hash__" and member is None
+                ):
                     continue
                 child = nodes.const_factory(member)
             elif inspect.isroutine(member):
diff --git a/astroid/rebuilder.py b/astroid/rebuilder.py
index b208754..f7d38a9 100644
--- a/astroid/rebuilder.py
+++ b/astroid/rebuilder.py
@@ -9,16 +9,17 @@
 from __future__ import annotations
 
 import ast
+import itertools
 import sys
 import token
-from collections.abc import Callable, Generator
+from collections.abc import Callable, Collection, Generator
 from io import StringIO
 from tokenize import TokenInfo, generate_tokens
-from typing import TYPE_CHECKING, Final, TypeVar, Union, cast, overload
+from typing import TYPE_CHECKING, Final, TypeVar, cast, overload
 
 from astroid import nodes
 from astroid._ast import ParserModule, get_parser_module, parse_function_type_comment
-from astroid.const import PY312_PLUS, Context
+from astroid.const import PY312_PLUS, PY313_PLUS, Context
 from astroid.nodes.utils import Position
 from astroid.typing import InferenceResult
 
@@ -27,14 +28,14 @@
 
     T_Doc = TypeVar(
         "T_Doc",
-        "ast.Module",
-        "ast.ClassDef",
-        Union["ast.FunctionDef", "ast.AsyncFunctionDef"],
+        ast.Module,
+        ast.ClassDef,
+        ast.FunctionDef | ast.AsyncFunctionDef,
     )
     _FunctionT = TypeVar("_FunctionT", nodes.FunctionDef, nodes.AsyncFunctionDef)
     _ForT = TypeVar("_ForT", nodes.For, nodes.AsyncFor)
     _WithT = TypeVar("_WithT", nodes.With, nodes.AsyncWith)
-    NodesWithDocsType = Union[nodes.Module, nodes.ClassDef, nodes.FunctionDef]
+    NodesWithDocsType = nodes.Module | nodes.ClassDef | nodes.FunctionDef
 
 
 REDIRECT: Final[dict[str, str]] = {
@@ -61,7 +62,7 @@
         self._manager = manager
         self._data = data.split("\n") if data else None
         self._global_names: list[dict[str, list[nodes.Global]]] = []
-        self._import_from_nodes: list[nodes.ImportFrom] = []
+        self._import_from_nodes: list[tuple[nodes.ImportFrom, Collection[str]]] = []
         self._delayed_assattr: list[nodes.AssignAttr] = []
         self._visit_meths: dict[
             type[ast.AST], Callable[[ast.AST, nodes.NodeNG], nodes.NodeNG]
@@ -72,7 +73,7 @@
         else:
             self._parser_module = parser_module
 
-    def _get_doc(self, node: T_Doc) -> tuple[T_Doc, ast.Constant | ast.Str | None]:
+    def _get_doc(self, node: T_Doc) -> tuple[T_Doc, ast.Constant | None]:
         """Return the doc ast node."""
         try:
             if node.body and isinstance(node.body[0], ast.Expr):
@@ -413,60 +414,64 @@
             self, node: ast.YieldFrom, parent: nodes.NodeNG
         ) -> nodes.YieldFrom: ...
 
-        if sys.version_info >= (3, 10):
+        @overload
+        def visit(self, node: ast.Match, parent: nodes.NodeNG) -> nodes.Match: ...
 
-            @overload
-            def visit(self, node: ast.Match, parent: nodes.NodeNG) -> nodes.Match: ...
+        @overload
+        def visit(
+            self, node: ast.match_case, parent: nodes.NodeNG
+        ) -> nodes.MatchCase: ...
+
+        @overload
+        def visit(
+            self, node: ast.MatchValue, parent: nodes.NodeNG
+        ) -> nodes.MatchValue: ...
+
+        @overload
+        def visit(
+            self, node: ast.MatchSingleton, parent: nodes.NodeNG
+        ) -> nodes.MatchSingleton: ...
+
+        @overload
+        def visit(
+            self, node: ast.MatchSequence, parent: nodes.NodeNG
+        ) -> nodes.MatchSequence: ...
+
+        @overload
+        def visit(
+            self, node: ast.MatchMapping, parent: nodes.NodeNG
+        ) -> nodes.MatchMapping: ...
+
+        @overload
+        def visit(
+            self, node: ast.MatchClass, parent: nodes.NodeNG
+        ) -> nodes.MatchClass: ...
+
+        @overload
+        def visit(
+            self, node: ast.MatchStar, parent: nodes.NodeNG
+        ) -> nodes.MatchStar: ...
+
+        @overload
+        def visit(self, node: ast.MatchAs, parent: nodes.NodeNG) -> nodes.MatchAs: ...
+
+        @overload
+        def visit(self, node: ast.MatchOr, parent: nodes.NodeNG) -> nodes.MatchOr: ...
+
+        @overload
+        def visit(self, node: ast.pattern, parent: nodes.NodeNG) -> nodes.Pattern: ...
+
+        if sys.version_info >= (3, 14):
 
             @overload
             def visit(
-                self, node: ast.match_case, parent: nodes.NodeNG
-            ) -> nodes.MatchCase: ...
+                self, node: ast.TemplateStr, parent: nodes.NodeNG
+            ) -> nodes.TemplateStr: ...
 
             @overload
             def visit(
-                self, node: ast.MatchValue, parent: nodes.NodeNG
-            ) -> nodes.MatchValue: ...
-
-            @overload
-            def visit(
-                self, node: ast.MatchSingleton, parent: nodes.NodeNG
-            ) -> nodes.MatchSingleton: ...
-
-            @overload
-            def visit(
-                self, node: ast.MatchSequence, parent: nodes.NodeNG
-            ) -> nodes.MatchSequence: ...
-
-            @overload
-            def visit(
-                self, node: ast.MatchMapping, parent: nodes.NodeNG
-            ) -> nodes.MatchMapping: ...
-
-            @overload
-            def visit(
-                self, node: ast.MatchClass, parent: nodes.NodeNG
-            ) -> nodes.MatchClass: ...
-
-            @overload
-            def visit(
-                self, node: ast.MatchStar, parent: nodes.NodeNG
-            ) -> nodes.MatchStar: ...
-
-            @overload
-            def visit(
-                self, node: ast.MatchAs, parent: nodes.NodeNG
-            ) -> nodes.MatchAs: ...
-
-            @overload
-            def visit(
-                self, node: ast.MatchOr, parent: nodes.NodeNG
-            ) -> nodes.MatchOr: ...
-
-            @overload
-            def visit(
-                self, node: ast.pattern, parent: nodes.NodeNG
-            ) -> nodes.Pattern: ...
+                self, node: ast.Interpolation, parent: nodes.NodeNG
+            ) -> nodes.Interpolation: ...
 
         @overload
         def visit(self, node: ast.AST, parent: nodes.NodeNG) -> nodes.NodeNG: ...
@@ -585,6 +590,16 @@
             type_comment_kwonlyargs=type_comment_kwonlyargs,
             type_comment_posonlyargs=type_comment_posonlyargs,
         )
+        if start_end_lineno_pairs := [
+            (arg.lineno, arg.end_lineno)
+            for arg in itertools.chain(
+                node.args, node.posonlyargs, node.kwonlyargs, [node.vararg, node.kwarg]
+            )
+            if arg
+        ]:
+            newnode.lineno = min(startend[0] for startend in start_end_lineno_pairs)
+            newnode.end_lineno = max(startend[1] for startend in start_end_lineno_pairs)
+
         # save argument names in locals:
         assert newnode.parent
         if vararg:
@@ -1095,7 +1110,9 @@
             parent=parent,
         )
         # store From names to add them to locals after building
-        self._import_from_nodes.append(newnode)
+        self._import_from_nodes.append(
+            (newnode, self._global_names[-1].keys() if self._global_names else ())
+        )
         return newnode
 
     @overload
@@ -1296,8 +1313,11 @@
         )
         # save import names in parent's locals:
         for name, asname in newnode.names:
-            name = asname or name
-            parent.set_local(name.split(".")[0], newnode)
+            name = (asname or name).split(".")[0]
+            if self._global_names and name in self._global_names[-1]:
+                parent.root().set_local(name, newnode)
+            else:
+                parent.set_local(name, newnode)
         return newnode
 
     def visit_joinedstr(
@@ -1437,7 +1457,7 @@
             )
         # XXX REMOVE me :
         if context in (Context.Del, Context.Store):  # 'Aug' ??
-            newnode = cast(Union[nodes.AssignName, nodes.DelName], newnode)
+            newnode = cast((nodes.AssignName | nodes.DelName), newnode)
             self._save_assignment(newnode)
         return newnode
 
@@ -1479,7 +1499,12 @@
         )
         # Add AssignName node for 'node.name'
         # https://bugs.python.org/issue43994
-        newnode.postinit(name=self.visit_assignname(node, newnode, node.name))
+        newnode.postinit(
+            name=self.visit_assignname(node, newnode, node.name),
+            default_value=(
+                self.visit(node.default_value, newnode) if PY313_PLUS else None
+            ),
+        )
         return newnode
 
     def visit_pass(self, node: ast.Pass, parent: nodes.NodeNG) -> nodes.Pass:
@@ -1675,6 +1700,9 @@
         newnode.postinit(
             name=self.visit_assignname(node, newnode, node.name),
             bound=self.visit(node.bound, newnode),
+            default_value=(
+                self.visit(node.default_value, newnode) if PY313_PLUS else None
+            ),
         )
         return newnode
 
@@ -1691,7 +1719,12 @@
         )
         # Add AssignName node for 'node.name'
         # https://bugs.python.org/issue43994
-        newnode.postinit(name=self.visit_assignname(node, newnode, node.name))
+        newnode.postinit(
+            name=self.visit_assignname(node, newnode, node.name),
+            default_value=(
+                self.visit(node.default_value, newnode) if PY313_PLUS else None
+            ),
+        )
         return newnode
 
     def visit_unaryop(self, node: ast.UnaryOp, parent: nodes.NodeNG) -> nodes.UnaryOp:
@@ -1790,10 +1823,160 @@
         newnode.postinit(self.visit(node.value, newnode))
         return newnode
 
-    if sys.version_info >= (3, 10):
+    def visit_match(self, node: ast.Match, parent: nodes.NodeNG) -> nodes.Match:
+        newnode = nodes.Match(
+            lineno=node.lineno,
+            col_offset=node.col_offset,
+            end_lineno=node.end_lineno,
+            end_col_offset=node.end_col_offset,
+            parent=parent,
+        )
+        newnode.postinit(
+            subject=self.visit(node.subject, newnode),
+            cases=[self.visit(case, newnode) for case in node.cases],
+        )
+        return newnode
 
-        def visit_match(self, node: ast.Match, parent: nodes.NodeNG) -> nodes.Match:
-            newnode = nodes.Match(
+    def visit_matchcase(
+        self, node: ast.match_case, parent: nodes.NodeNG
+    ) -> nodes.MatchCase:
+        newnode = nodes.MatchCase(parent=parent)
+        newnode.postinit(
+            pattern=self.visit(node.pattern, newnode),
+            guard=self.visit(node.guard, newnode),
+            body=[self.visit(child, newnode) for child in node.body],
+        )
+        return newnode
+
+    def visit_matchvalue(
+        self, node: ast.MatchValue, parent: nodes.NodeNG
+    ) -> nodes.MatchValue:
+        newnode = nodes.MatchValue(
+            lineno=node.lineno,
+            col_offset=node.col_offset,
+            end_lineno=node.end_lineno,
+            end_col_offset=node.end_col_offset,
+            parent=parent,
+        )
+        newnode.postinit(value=self.visit(node.value, newnode))
+        return newnode
+
+    def visit_matchsingleton(
+        self, node: ast.MatchSingleton, parent: nodes.NodeNG
+    ) -> nodes.MatchSingleton:
+        return nodes.MatchSingleton(
+            value=node.value,
+            lineno=node.lineno,
+            col_offset=node.col_offset,
+            end_lineno=node.end_lineno,
+            end_col_offset=node.end_col_offset,
+            parent=parent,
+        )
+
+    def visit_matchsequence(
+        self, node: ast.MatchSequence, parent: nodes.NodeNG
+    ) -> nodes.MatchSequence:
+        newnode = nodes.MatchSequence(
+            lineno=node.lineno,
+            col_offset=node.col_offset,
+            end_lineno=node.end_lineno,
+            end_col_offset=node.end_col_offset,
+            parent=parent,
+        )
+        newnode.postinit(
+            patterns=[self.visit(pattern, newnode) for pattern in node.patterns]
+        )
+        return newnode
+
+    def visit_matchmapping(
+        self, node: ast.MatchMapping, parent: nodes.NodeNG
+    ) -> nodes.MatchMapping:
+        newnode = nodes.MatchMapping(
+            lineno=node.lineno,
+            col_offset=node.col_offset,
+            end_lineno=node.end_lineno,
+            end_col_offset=node.end_col_offset,
+            parent=parent,
+        )
+        # Add AssignName node for 'node.name'
+        # https://bugs.python.org/issue43994
+        newnode.postinit(
+            keys=[self.visit(child, newnode) for child in node.keys],
+            patterns=[self.visit(pattern, newnode) for pattern in node.patterns],
+            rest=self.visit_assignname(node, newnode, node.rest),
+        )
+        return newnode
+
+    def visit_matchclass(
+        self, node: ast.MatchClass, parent: nodes.NodeNG
+    ) -> nodes.MatchClass:
+        newnode = nodes.MatchClass(
+            lineno=node.lineno,
+            col_offset=node.col_offset,
+            end_lineno=node.end_lineno,
+            end_col_offset=node.end_col_offset,
+            parent=parent,
+        )
+        newnode.postinit(
+            cls=self.visit(node.cls, newnode),
+            patterns=[self.visit(pattern, newnode) for pattern in node.patterns],
+            kwd_attrs=node.kwd_attrs,
+            kwd_patterns=[
+                self.visit(pattern, newnode) for pattern in node.kwd_patterns
+            ],
+        )
+        return newnode
+
+    def visit_matchstar(
+        self, node: ast.MatchStar, parent: nodes.NodeNG
+    ) -> nodes.MatchStar:
+        newnode = nodes.MatchStar(
+            lineno=node.lineno,
+            col_offset=node.col_offset,
+            end_lineno=node.end_lineno,
+            end_col_offset=node.end_col_offset,
+            parent=parent,
+        )
+        # Add AssignName node for 'node.name'
+        # https://bugs.python.org/issue43994
+        newnode.postinit(name=self.visit_assignname(node, newnode, node.name))
+        return newnode
+
+    def visit_matchas(self, node: ast.MatchAs, parent: nodes.NodeNG) -> nodes.MatchAs:
+        newnode = nodes.MatchAs(
+            lineno=node.lineno,
+            col_offset=node.col_offset,
+            end_lineno=node.end_lineno,
+            end_col_offset=node.end_col_offset,
+            parent=parent,
+        )
+        # Add AssignName node for 'node.name'
+        # https://bugs.python.org/issue43994
+        newnode.postinit(
+            pattern=self.visit(node.pattern, newnode),
+            name=self.visit_assignname(node, newnode, node.name),
+        )
+        return newnode
+
+    def visit_matchor(self, node: ast.MatchOr, parent: nodes.NodeNG) -> nodes.MatchOr:
+        newnode = nodes.MatchOr(
+            lineno=node.lineno,
+            col_offset=node.col_offset,
+            end_lineno=node.end_lineno,
+            end_col_offset=node.end_col_offset,
+            parent=parent,
+        )
+        newnode.postinit(
+            patterns=[self.visit(pattern, newnode) for pattern in node.patterns]
+        )
+        return newnode
+
+    if sys.version_info >= (3, 14):
+
+        def visit_templatestr(
+            self, node: ast.TemplateStr, parent: nodes.NodeNG
+        ) -> nodes.TemplateStr:
+            newnode = nodes.TemplateStr(
                 lineno=node.lineno,
                 col_offset=node.col_offset,
                 end_lineno=node.end_lineno,
@@ -1801,51 +1984,14 @@
                 parent=parent,
             )
             newnode.postinit(
-                subject=self.visit(node.subject, newnode),
-                cases=[self.visit(case, newnode) for case in node.cases],
+                values=[self.visit(value, newnode) for value in node.values]
             )
             return newnode
 
-        def visit_matchcase(
-            self, node: ast.match_case, parent: nodes.NodeNG
-        ) -> nodes.MatchCase:
-            newnode = nodes.MatchCase(parent=parent)
-            newnode.postinit(
-                pattern=self.visit(node.pattern, newnode),
-                guard=self.visit(node.guard, newnode),
-                body=[self.visit(child, newnode) for child in node.body],
-            )
-            return newnode
-
-        def visit_matchvalue(
-            self, node: ast.MatchValue, parent: nodes.NodeNG
-        ) -> nodes.MatchValue:
-            newnode = nodes.MatchValue(
-                lineno=node.lineno,
-                col_offset=node.col_offset,
-                end_lineno=node.end_lineno,
-                end_col_offset=node.end_col_offset,
-                parent=parent,
-            )
-            newnode.postinit(value=self.visit(node.value, newnode))
-            return newnode
-
-        def visit_matchsingleton(
-            self, node: ast.MatchSingleton, parent: nodes.NodeNG
-        ) -> nodes.MatchSingleton:
-            return nodes.MatchSingleton(
-                value=node.value,
-                lineno=node.lineno,
-                col_offset=node.col_offset,
-                end_lineno=node.end_lineno,
-                end_col_offset=node.end_col_offset,
-                parent=parent,
-            )
-
-        def visit_matchsequence(
-            self, node: ast.MatchSequence, parent: nodes.NodeNG
-        ) -> nodes.MatchSequence:
-            newnode = nodes.MatchSequence(
+        def visit_interpolation(
+            self, node: ast.Interpolation, parent: nodes.NodeNG
+        ) -> nodes.Interpolation:
+            newnode = nodes.Interpolation(
                 lineno=node.lineno,
                 col_offset=node.col_offset,
                 end_lineno=node.end_lineno,
@@ -1853,93 +1999,9 @@
                 parent=parent,
             )
             newnode.postinit(
-                patterns=[self.visit(pattern, newnode) for pattern in node.patterns]
-            )
-            return newnode
-
-        def visit_matchmapping(
-            self, node: ast.MatchMapping, parent: nodes.NodeNG
-        ) -> nodes.MatchMapping:
-            newnode = nodes.MatchMapping(
-                lineno=node.lineno,
-                col_offset=node.col_offset,
-                end_lineno=node.end_lineno,
-                end_col_offset=node.end_col_offset,
-                parent=parent,
-            )
-            # Add AssignName node for 'node.name'
-            # https://bugs.python.org/issue43994
-            newnode.postinit(
-                keys=[self.visit(child, newnode) for child in node.keys],
-                patterns=[self.visit(pattern, newnode) for pattern in node.patterns],
-                rest=self.visit_assignname(node, newnode, node.rest),
-            )
-            return newnode
-
-        def visit_matchclass(
-            self, node: ast.MatchClass, parent: nodes.NodeNG
-        ) -> nodes.MatchClass:
-            newnode = nodes.MatchClass(
-                lineno=node.lineno,
-                col_offset=node.col_offset,
-                end_lineno=node.end_lineno,
-                end_col_offset=node.end_col_offset,
-                parent=parent,
-            )
-            newnode.postinit(
-                cls=self.visit(node.cls, newnode),
-                patterns=[self.visit(pattern, newnode) for pattern in node.patterns],
-                kwd_attrs=node.kwd_attrs,
-                kwd_patterns=[
-                    self.visit(pattern, newnode) for pattern in node.kwd_patterns
-                ],
-            )
-            return newnode
-
-        def visit_matchstar(
-            self, node: ast.MatchStar, parent: nodes.NodeNG
-        ) -> nodes.MatchStar:
-            newnode = nodes.MatchStar(
-                lineno=node.lineno,
-                col_offset=node.col_offset,
-                end_lineno=node.end_lineno,
-                end_col_offset=node.end_col_offset,
-                parent=parent,
-            )
-            # Add AssignName node for 'node.name'
-            # https://bugs.python.org/issue43994
-            newnode.postinit(name=self.visit_assignname(node, newnode, node.name))
-            return newnode
-
-        def visit_matchas(
-            self, node: ast.MatchAs, parent: nodes.NodeNG
-        ) -> nodes.MatchAs:
-            newnode = nodes.MatchAs(
-                lineno=node.lineno,
-                col_offset=node.col_offset,
-                end_lineno=node.end_lineno,
-                end_col_offset=node.end_col_offset,
-                parent=parent,
-            )
-            # Add AssignName node for 'node.name'
-            # https://bugs.python.org/issue43994
-            newnode.postinit(
-                pattern=self.visit(node.pattern, newnode),
-                name=self.visit_assignname(node, newnode, node.name),
-            )
-            return newnode
-
-        def visit_matchor(
-            self, node: ast.MatchOr, parent: nodes.NodeNG
-        ) -> nodes.MatchOr:
-            newnode = nodes.MatchOr(
-                lineno=node.lineno,
-                col_offset=node.col_offset,
-                end_lineno=node.end_lineno,
-                end_col_offset=node.end_col_offset,
-                parent=parent,
-            )
-            newnode.postinit(
-                patterns=[self.visit(pattern, newnode) for pattern in node.patterns]
+                value=self.visit(node.value, parent),
+                str=node.str,
+                conversion=node.conversion,
+                format_spec=self.visit(node.format_spec, parent),
             )
             return newnode
diff --git a/astroid/transforms.py b/astroid/transforms.py
index 1831e74..d44ec3d 100644
--- a/astroid/transforms.py
+++ b/astroid/transforms.py
@@ -7,7 +7,7 @@
 import warnings
 from collections import defaultdict
 from collections.abc import Callable
-from typing import TYPE_CHECKING, Optional, TypeVar, Union, cast, overload
+from typing import TYPE_CHECKING, TypeVar, Union, cast, overload
 
 from astroid.context import _invalidate_cache
 from astroid.typing import SuccessfulInferenceResult, TransformFn
@@ -18,18 +18,19 @@
     _SuccessfulInferenceResultT = TypeVar(
         "_SuccessfulInferenceResultT", bound=SuccessfulInferenceResult
     )
-    _Predicate = Optional[Callable[[_SuccessfulInferenceResultT], bool]]
+    _Predicate = Callable[[_SuccessfulInferenceResultT], bool] | None
 
+# pylint: disable-next=consider-alternative-union-syntax
 _Vistables = Union[
     "nodes.NodeNG", list["nodes.NodeNG"], tuple["nodes.NodeNG", ...], str, None
 ]
-_VisitReturns = Union[
-    SuccessfulInferenceResult,
-    list[SuccessfulInferenceResult],
-    tuple[SuccessfulInferenceResult, ...],
-    str,
-    None,
-]
+_VisitReturns = (
+    SuccessfulInferenceResult
+    | list[SuccessfulInferenceResult]
+    | tuple[SuccessfulInferenceResult, ...]
+    | str
+    | None
+)
 
 
 class TransformVisitor:
diff --git a/astroid/typing.py b/astroid/typing.py
index 77cc120..37ea434 100644
--- a/astroid/typing.py
+++ b/astroid/typing.py
@@ -47,6 +47,7 @@
     _transform: transforms.TransformVisitor
 
 
+# pylint: disable=consider-alternative-union-syntax
 InferenceResult = Union["nodes.NodeNG", "util.UninferableBase", "bases.Proxy"]
 SuccessfulInferenceResult = Union["nodes.NodeNG", "bases.Proxy"]
 _SuccessfulInferenceResultT = TypeVar(
diff --git a/doc/release.md b/doc/release.md
index 7dc7453..8e4ca83 100644
--- a/doc/release.md
+++ b/doc/release.md
@@ -30,10 +30,9 @@
 git commit -am "Upgrade the version to 2.5.0-dev0 following 2.4.0 release"
 ```
 
-Check the commit and then push to a release branch
+Check the commit and then push to a release branch:
 
 - Open a merge request with the two commits (no one can push directly on `main`)
-- Trigger the "release tests" workflow in GitHub Actions.
 - After the merge, recover the merged commits on `main` and tag the first one (the
   version should be `X.Y.Z`) as `vX.Y.Z` (For example: `v2.4.0`)
 - Push the tag.
@@ -92,8 +91,8 @@
 - Fix version conflicts properly, meaning preserve the version numbers of the form
   `X.Y.0-devZ` (For example: `2.4.0-dev6`).
 - Open a merge request against main. Ensure a merge commit is used, because pre-commit
-  need the patch release tag to be in the main branch history to consider the patch
-  release as the latest version and this won't be the case with rebase or squash. You
+  needs the patch release tag to be in the main branch history to consider the patch
+  release as the latest version, and this won't be the case with rebase or squash. You
   can defend against trigger-happy future selves by enabling auto-merge with the merge
   commit strategy.
 - Wait for approval. Again, use a merge commit.
diff --git a/doc/requirements.txt b/doc/requirements.txt
index 9048111..a759a74 100644
--- a/doc/requirements.txt
+++ b/doc/requirements.txt
@@ -1,3 +1,3 @@
 -e .
-sphinx~=8.2
-furo==2024.8.6
+sphinx~=8.1
+furo==2025.12.19
diff --git a/pylintrc b/pylintrc
index 6421802..2957fff 100644
--- a/pylintrc
+++ b/pylintrc
@@ -42,10 +42,10 @@
 # A comma-separated list of package or module names from where C extensions may
 # be loaded. Extensions are loading into the active Python interpreter and may
 # run arbitrary code
-extension-pkg-whitelist=
+extension-pkg-whitelist=mypy
 
 # Minimum supported python version
-py-version = 3.9.0
+py-version = 3.10.0
 
 
 [REPORTS]
diff --git a/pyproject.toml b/pyproject.toml
index 4bf8398..04b1cc9 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,17 +1,15 @@
 [build-system]
 build-backend = "setuptools.build_meta"
-
-requires = [ "setuptools>=75.2" ]
+requires = [ "setuptools>=77" ]
 
 [project]
 name = "astroid"
 description = "An abstract syntax tree for Python with inference support."
 readme = "README.rst"
 keywords = [ "abstract syntax tree", "python", "static code analysis" ]
-license = "LGPL-2.1-or-later"
+license = "LGPL-2.1-OR-later"
 license-files = [ "LICENSE", "CONTRIBUTORS.txt" ]
-
-requires-python = ">=3.9.0"
+requires-python = ">=3.10.0"
 classifiers = [
   "Development Status :: 6 - Mature",
   "Environment :: Console",
@@ -19,11 +17,11 @@
   "Operating System :: OS Independent",
   "Programming Language :: Python",
   "Programming Language :: Python :: 3 :: Only",
-  "Programming Language :: Python :: 3.9",
   "Programming Language :: Python :: 3.10",
   "Programming Language :: Python :: 3.11",
   "Programming Language :: Python :: 3.12",
   "Programming Language :: Python :: 3.13",
+  "Programming Language :: Python :: 3.14",
   "Programming Language :: Python :: Implementation :: CPython",
   "Programming Language :: Python :: Implementation :: PyPy",
   "Topic :: Software Development :: Libraries :: Python Modules",
@@ -31,7 +29,6 @@
   "Topic :: Software Development :: Testing",
 ]
 dynamic = [ "version" ]
-
 dependencies = [
   "typing-extensions>=4; python_version<'3.11'",
 ]
@@ -40,24 +37,17 @@
 urls."Docs" = "https://pylint.readthedocs.io/projects/astroid/en/latest/"
 urls."Source Code" = "https://github.com/pylint-dev/astroid"
 
-[tool.setuptools.package-dir]
-"" = "."
-
-[tool.setuptools.packages.find]
-include = [ "astroid*" ]
-
-[tool.setuptools.dynamic]
-version = { attr = "astroid.__pkginfo__.__version__" }
+[tool.setuptools]
+dynamic.version = { attr = "astroid.__pkginfo__.__version__" }
+package-dir."" = "."
+packages.find.include = [ "astroid*" ]
 
 [tool.ruff]
-target-version = "py39"
-
+target-version = "py310"
 # ruff is less lenient than pylint and does not make any exceptions
 # (for docstrings, strings and comments in particular).
 line-length = 110
-
 extend-exclude = [ "tests/testdata/" ]
-
 lint.select = [
   "B",   # bugbear
   "E",   # pycodestyle
@@ -83,17 +73,19 @@
 ]
 lint.unfixable = [ "RUF001" ]
 
-[tool.pytest.ini_options]
-addopts = '-m "not acceptance"'
-python_files = [ "*test_*.py" ]
-testpaths = [ "tests" ]
-filterwarnings = "error"
+[tool.pyproject-fmt]
+max_supported_python = "3.14"
+
+[tool.pytest]
+ini_options.addopts = '-m "not acceptance"'
+ini_options.python_files = [ "*test_*.py" ]
+ini_options.testpaths = [ "tests" ]
+ini_options.filterwarnings = "error"
 
 [tool.mypy]
-python_version = "3.9"
+python_version = "3.10"
 files = [
   "astroid/_ast.py",
-  "astroid/_backport_stdlib_names.py",
   "astroid/astroid_manager.py",
   "astroid/brain/brain_crypt.py",
   "astroid/brain/brain_ctypes.py",
@@ -131,7 +123,6 @@
   "astroid/nodes/utils.py",
 ]
 always_false = [
-  "PY310_PLUS",
   "PY311_PLUS",
   "PY312_PLUS",
   "PY313_PLUS",
@@ -151,7 +142,6 @@
   "_io.*",
   "gi.*",
   "importlib.*",
-  "nose.*",
   "numpy.*",
   "pytest",
   "setuptools",
diff --git a/requirements_dev.txt b/requirements_dev.txt
index 77a6fd9..9f5ea56 100644
--- a/requirements_dev.txt
+++ b/requirements_dev.txt
@@ -3,5 +3,5 @@
 # Tools used during development, prefer running these with pre-commit
 black
 pre-commit
-pylint>=3.2.7
+pylint>=4.0.0
 ruff
diff --git a/requirements_full.txt b/requirements_full.txt
index 5b6f600..12efafb 100644
--- a/requirements_full.txt
+++ b/requirements_full.txt
@@ -3,12 +3,12 @@
 
 # Packages used to run additional tests
 attrs
-nose
 numpy>=1.17.0,<3; python_version<"3.12"
 python-dateutil
 PyQt6
 regex
-setuptools; python_version>="3.12"
+# Pinned as 82.0.0 removes `pkg_resources` which we require for a test.
+setuptools<82; python_version>="3.12"
 six
 urllib3>1,<2
 typing_extensions>=4.4.0
diff --git a/requirements_minimal.txt b/requirements_minimal.txt
index db9260e..c1457cf 100644
--- a/requirements_minimal.txt
+++ b/requirements_minimal.txt
@@ -3,7 +3,7 @@
 tbump~=6.11
 
 # Tools used to run tests
-coverage~=7.7
+coverage~=7.13
 pytest
-pytest-cov~=6.0
-mypy
+pytest-cov~=7.0
+mypy; platform_python_implementation!="PyPy"
diff --git a/script/.contributors_aliases.json b/script/.contributors_aliases.json
index 7bf909b..56a97d5 100644
--- a/script/.contributors_aliases.json
+++ b/script/.contributors_aliases.json
@@ -29,6 +29,10 @@
     ],
     "name": "Artem Yurchenko"
   },
+  "53538590+zenlyj@users.noreply.github.com": {
+    "mails": ["53538590+zenlyj@users.noreply.github.com", "zenlyj97@gmail.com"],
+    "name": "Zen Lee"
+  },
   "55152140+jayaddison@users.noreply.github.com": {
     "mails": ["55152140+jayaddison@users.noreply.github.com", "jay@jp-hosting.net"],
     "name": "James Addison"
@@ -72,7 +76,9 @@
     "mails": [
       "66853113+pre-commit-ci[bot]@users.noreply.github.com",
       "49699333+dependabot[bot]@users.noreply.github.com",
-      "41898282+github-actions[bot]@users.noreply.github.com"
+      "41898282+github-actions[bot]@users.noreply.github.com",
+      "212256041+pylint-backport[bot]@users.noreply.github.com",
+      "212256041+pylint-backport-bot[bot]@users.noreply.github.com"
     ],
     "name": "bot"
   },
@@ -81,6 +87,10 @@
     "name": "Bryce Guinta",
     "team": "Maintainers"
   },
+  "c.ringstrom@gmail.com": {
+    "mails": ["c.ringstrom@gmail.com"],
+    "name": "Charlie Ringström"
+  },
   "calen.pennington@gmail.com": {
     "mails": ["cale@edx.org", "calen.pennington@gmail.com"],
     "name": "Calen Pennington"
@@ -99,13 +109,20 @@
     "mails": ["david@dropbox.com", "github@euresti.com"],
     "name": "David Euresti"
   },
+  "grayjk@gmail.com": {
+    "mails": ["grayjk@gmail.com"],
+    "name": "grayjk"
+  },
   "guillaume.peillex@gmail.com": {
     "mails": ["guillaume.peillex@gmail.com"],
     "name": "Hippo91",
     "team": "Maintainers"
   },
   "hugovk@users.noreply.github.com": {
-    "mails": ["hugovk@users.noreply.github.com"],
+    "mails": [
+      "hugovk@users.noreply.github.com",
+      "1324225+hugovk@users.noreply.github.com"
+    ],
     "name": "Hugo van Kemenade"
   },
   "jacob@bogdanov.dev": {
@@ -133,6 +150,10 @@
     "mails": ["mcorcherojim@bloomberg.net", "mariocj89@gmail.com"],
     "name": "Mario Corchero"
   },
+  "matusvalo@users.noreply.github.com": {
+    "mails": ["matusvalo@users.noreply.github.com"],
+    "name": "Matus Valo"
+  },
   "me@the-compiler.org": {
     "mails": ["me@the-compiler.org"],
     "name": "Florian Bruhin",
diff --git a/script/bump_changelog.py b/script/bump_changelog.py
index a08a1ae..a00ae95 100644
--- a/script/bump_changelog.py
+++ b/script/bump_changelog.py
@@ -5,6 +5,7 @@
 """
 This script permits to upgrade the changelog in astroid or pylint when releasing a version.
 """
+
 # pylint: disable=logging-fstring-interpolation
 
 from __future__ import annotations
@@ -34,7 +35,7 @@
     if args.verbose:
         logging.basicConfig(level=logging.DEBUG)
     logging.debug(f"Launching bump_changelog with args: {args}")
-    if any(s in args.version for s in ("dev", "a", "b")):
+    if any(s in args.version for s in ("dev", "a", "b", "rc")):
         return
     with open(DEFAULT_CHANGELOG_PATH, encoding="utf-8") as f:
         content = f.read()
diff --git a/tbump.toml b/tbump.toml
index eb79c03..4fdd86b 100644
--- a/tbump.toml
+++ b/tbump.toml
@@ -1,7 +1,7 @@
 github_url = "https://github.com/pylint-dev/astroid"
 
 [version]
-current = "4.0.0dev1"
+current = "4.2.0-dev0"
 regex = '''
 ^(?P<major>0|[1-9]\d*)
 \.
diff --git a/tests/brain/numpy/test_core_einsumfunc.py b/tests/brain/numpy/test_core_einsumfunc.py
index c2760ca..95f3e23 100644
--- a/tests/brain/numpy/test_core_einsumfunc.py
+++ b/tests/brain/numpy/test_core_einsumfunc.py
@@ -17,13 +17,11 @@
 
 
 def _inferred_numpy_func_call(func_name: str, *func_args: str) -> nodes.FunctionDef:
-    node = builder.extract_node(
-        f"""
+    node = builder.extract_node(f"""
     import numpy as np
     func = np.{func_name:s}
     func({','.join(func_args):s})
-    """
-    )
+    """)
     return node.infer()
 
 
@@ -43,12 +41,10 @@
 
 @pytest.mark.skipif(not HAS_NUMPY, reason="This test requires the numpy library.")
 def test_function_parameters() -> None:
-    instance = builder.extract_node(
-        """
+    instance = builder.extract_node("""
     import numpy
     numpy.einsum #@
-    """
-    )
+    """)
     actual_args = instance.inferred()[0].args
 
     assert actual_args.vararg == "operands"
diff --git a/tests/brain/numpy/test_core_fromnumeric.py b/tests/brain/numpy/test_core_fromnumeric.py
index 1d78257..9442ab6 100644
--- a/tests/brain/numpy/test_core_fromnumeric.py
+++ b/tests/brain/numpy/test_core_fromnumeric.py
@@ -21,13 +21,11 @@
     numpy_functions = (("sum", "[1, 2]"),)
 
     def _inferred_numpy_func_call(self, func_name, *func_args):
-        node = builder.extract_node(
-            f"""
+        node = builder.extract_node(f"""
         import numpy as np
         func = np.{func_name:s}
         func({','.join(func_args):s})
-        """
-        )
+        """)
         return node.infer()
 
     def test_numpy_function_calls_inferred_as_ndarray(self):
diff --git a/tests/brain/numpy/test_core_function_base.py b/tests/brain/numpy/test_core_function_base.py
index 5d42946..f2ef004 100644
--- a/tests/brain/numpy/test_core_function_base.py
+++ b/tests/brain/numpy/test_core_function_base.py
@@ -25,13 +25,11 @@
     )
 
     def _inferred_numpy_func_call(self, func_name, *func_args):
-        node = builder.extract_node(
-            f"""
+        node = builder.extract_node(f"""
         import numpy as np
         func = np.{func_name:s}
         func({','.join(func_args):s})
-        """
-        )
+        """)
         return node.infer()
 
     def test_numpy_function_calls_inferred_as_ndarray(self):
diff --git a/tests/brain/numpy/test_core_multiarray.py b/tests/brain/numpy/test_core_multiarray.py
index e7ccde3..f06f06a 100644
--- a/tests/brain/numpy/test_core_multiarray.py
+++ b/tests/brain/numpy/test_core_multiarray.py
@@ -60,23 +60,19 @@
     )
 
     def _inferred_numpy_func_call(self, func_name, *func_args):
-        node = builder.extract_node(
-            f"""
+        node = builder.extract_node(f"""
         import numpy as np
         func = np.{func_name:s}
         func({','.join(func_args):s})
-        """
-        )
+        """)
         return node.infer()
 
     def _inferred_numpy_no_alias_func_call(self, func_name, *func_args):
-        node = builder.extract_node(
-            f"""
+        node = builder.extract_node(f"""
         import numpy
         func = numpy.{func_name:s}
         func({','.join(func_args):s})
-        """
-        )
+        """)
         return node.infer()
 
     def test_numpy_function_calls_inferred_as_ndarray(self):
diff --git a/tests/brain/numpy/test_core_numeric.py b/tests/brain/numpy/test_core_numeric.py
index 8970ca3..a11becc 100644
--- a/tests/brain/numpy/test_core_numeric.py
+++ b/tests/brain/numpy/test_core_numeric.py
@@ -30,13 +30,11 @@
     )
 
     def _inferred_numpy_func_call(self, func_name, *func_args):
-        node = builder.extract_node(
-            f"""
+        node = builder.extract_node(f"""
         import numpy as np
         func = np.{func_name:s}
         func({','.join(func_args):s})
-        """
-        )
+        """)
         return node.infer()
 
     def test_numpy_function_calls_inferred_as_ndarray(self):
@@ -68,11 +66,9 @@
     ],
 )
 def test_function_parameters(method: str, expected_args: list[str]) -> None:
-    instance = builder.extract_node(
-        f"""
+    instance = builder.extract_node(f"""
     import numpy
     numpy.{method} #@
-    """
-    )
+    """)
     actual_args = instance.inferred()[0].args.args
     assert [arg.name for arg in actual_args] == expected_args
diff --git a/tests/brain/numpy/test_core_numerictypes.py b/tests/brain/numpy/test_core_numerictypes.py
index 819cc7d..51c2cf2 100644
--- a/tests/brain/numpy/test_core_numerictypes.py
+++ b/tests/brain/numpy/test_core_numerictypes.py
@@ -80,11 +80,9 @@
     ]
 
     def _inferred_numpy_attribute(self, attrib):
-        node = builder.extract_node(
-            f"""
+        node = builder.extract_node(f"""
         import numpy.core.numerictypes as tested_module
-        missing_type = tested_module.{attrib:s}"""
-        )
+        missing_type = tested_module.{attrib:s}""")
         return next(node.value.infer())
 
     def test_numpy_core_types(self):
@@ -311,14 +309,12 @@
 
         pylint-dev/pylint#3332
         """
-        node = builder.extract_node(
-            """
+        node = builder.extract_node("""
         import numpy as np
         import datetime
         test_array = np.datetime64(1, 'us')
         test_array.astype(datetime.datetime)
-        """
-        )
+        """)
         licit_array_types = ".ndarray"
         inferred_values = list(node.infer())
         self.assertTrue(
diff --git a/tests/brain/numpy/test_core_umath.py b/tests/brain/numpy/test_core_umath.py
index a288d58..83fd731 100644
--- a/tests/brain/numpy/test_core_umath.py
+++ b/tests/brain/numpy/test_core_umath.py
@@ -101,12 +101,10 @@
     constants = ("e", "euler_gamma")
 
     def _inferred_numpy_attribute(self, func_name):
-        node = builder.extract_node(
-            f"""
+        node = builder.extract_node(f"""
         import numpy.core.umath as tested_module
         func = tested_module.{func_name:s}
-        func"""
-        )
+        func""")
         return next(node.infer())
 
     def test_numpy_core_umath_constants(self):
@@ -183,13 +181,11 @@
                 self.assertEqual(default_args_values, exact_kwargs_default_values)
 
     def _inferred_numpy_func_call(self, func_name, *func_args):
-        node = builder.extract_node(
-            f"""
+        node = builder.extract_node(f"""
         import numpy as np
         func = np.{func_name:s}
         func()
-        """
-        )
+        """)
         return node.infer()
 
     def test_numpy_core_umath_functions_return_type(self):
diff --git a/tests/brain/numpy/test_ndarray.py b/tests/brain/numpy/test_ndarray.py
index 9ccadf5..8678d54 100644
--- a/tests/brain/numpy/test_ndarray.py
+++ b/tests/brain/numpy/test_ndarray.py
@@ -105,23 +105,19 @@
     )
 
     def _inferred_ndarray_method_call(self, func_name):
-        node = builder.extract_node(
-            f"""
+        node = builder.extract_node(f"""
         import numpy as np
         test_array = np.ndarray((2, 2))
         test_array.{func_name:s}()
-        """
-        )
+        """)
         return node.infer()
 
     def _inferred_ndarray_attribute(self, attr_name):
-        node = builder.extract_node(
-            f"""
+        node = builder.extract_node(f"""
         import numpy as np
         test_array = np.ndarray((2, 2))
         test_array.{attr_name:s}
-        """
-        )
+        """)
         return node.infer()
 
     def test_numpy_function_calls_inferred_as_ndarray(self):
diff --git a/tests/brain/numpy/test_random_mtrand.py b/tests/brain/numpy/test_random_mtrand.py
index 7a3c324..91a962d 100644
--- a/tests/brain/numpy/test_random_mtrand.py
+++ b/tests/brain/numpy/test_random_mtrand.py
@@ -74,12 +74,10 @@
     }
 
     def _inferred_numpy_attribute(self, func_name):
-        node = builder.extract_node(
-            f"""
+        node = builder.extract_node(f"""
         import numpy.random.mtrand as tested_module
         func = tested_module.{func_name:s}
-        func"""
-        )
+        func""")
         return next(node.infer())
 
     def test_numpy_random_mtrand_functions(self):
diff --git a/tests/brain/test_argparse.py b/tests/brain/test_argparse.py
index 20d96e2..75b5e3f 100644
--- a/tests/brain/test_argparse.py
+++ b/tests/brain/test_argparse.py
@@ -8,13 +8,11 @@
 class TestBrainArgparse:
     @staticmethod
     def test_infer_namespace() -> None:
-        func = extract_node(
-            """
+        func = extract_node("""
         import argparse
         def make_namespace():  #@
             return argparse.Namespace(debug=True)
-        """
-        )
+        """)
         assert isinstance(func, nodes.FunctionDef)
         inferred = next(func.infer_call_result(func))
         assert isinstance(inferred, bases.Instance)
diff --git a/tests/brain/test_attr.py b/tests/brain/test_attr.py
index ef48873..63d5a74 100644
--- a/tests/brain/test_attr.py
+++ b/tests/brain/test_attr.py
@@ -20,8 +20,7 @@
 @unittest.skipUnless(HAS_ATTR, "These tests require the attr library")
 class AttrsTest(unittest.TestCase):
     def test_attr_transform(self) -> None:
-        module = astroid.parse(
-            """
+        module = astroid.parse("""
         import attr
         from attr import attrs, attrib, field
 
@@ -80,12 +79,11 @@
             d: int = attr.Factory(lambda: 3)
 
         m = Eggs(d=1)
-        """
-        )
+        """)
 
         for name in ("f", "g", "h", "i", "j", "k", "l", "m"):
             should_be_unknown = next(module.getattr(name)[0].infer()).getattr("d")[0]
-            self.assertIsInstance(should_be_unknown, astroid.Unknown)
+            self.assertIsInstance(should_be_unknown, nodes.Unknown)
 
     def test_attrs_transform(self) -> None:
         """Test brain for decorators of the 'attrs' package.
@@ -93,8 +91,7 @@
         Package added support for 'attrs' alongside 'attr' in v21.3.0.
         See: https://github.com/python-attrs/attrs/releases/tag/21.3.0
         """
-        module = astroid.parse(
-            """
+        module = astroid.parse("""
         import attrs
         from attrs import field, mutable, frozen, define
         from attrs import mutable as my_mutable
@@ -153,12 +150,11 @@
         @frozen
         class Legs:
             d = attrs.field(default=attrs.Factory(dict))
-        """
-        )
+        """)
 
         for name in ("f", "g", "h", "i", "j", "k", "l"):
             should_be_unknown = next(module.getattr(name)[0].infer()).getattr("d")[0]
-            self.assertIsInstance(should_be_unknown, astroid.Unknown, name)
+            self.assertIsInstance(should_be_unknown, nodes.Unknown, name)
 
     def test_special_attributes(self) -> None:
         """Make sure special attrs attributes exist"""
@@ -200,7 +196,7 @@
         Foo()
         """
         should_be_unknown = next(astroid.extract_node(code).infer()).getattr("bar")[0]
-        self.assertIsInstance(should_be_unknown, astroid.Unknown)
+        self.assertIsInstance(should_be_unknown, nodes.Unknown)
 
     def test_attr_with_only_annotation_fails(self) -> None:
         code = """
@@ -228,4 +224,60 @@
             should_be_unknown = next(astroid.extract_node(code).infer()).getattr(
                 attr_name
             )[0]
-            self.assertIsInstance(should_be_unknown, astroid.Unknown)
+            self.assertIsInstance(should_be_unknown, nodes.Unknown)
+
+    def test_attrs_with_class_var_annotation(self) -> None:
+        cases = {
+            "with-subscript": """
+                import attrs
+                from typing import ClassVar
+
+                @attrs.define
+                class Foo:
+                    bar: ClassVar[int] = 1
+                Foo()
+            """,
+            "no-subscript": """
+                import attrs
+                from typing import ClassVar
+
+                @attrs.define
+                class Foo:
+                    bar: ClassVar = 1
+                Foo()
+            """,
+        }
+
+        for name, code in cases.items():
+            with self.subTest(case=name):
+                instance = next(astroid.extract_node(code).infer())
+                self.assertIsInstance(instance.getattr("bar")[0], nodes.AssignName)
+                self.assertNotIn("bar", instance.instance_attrs)
+
+    def test_attrs_without_class_var_annotation(self) -> None:
+        cases = {
+            "wrong-name": """
+                import attrs
+                from typing import Final
+
+                @attrs.define
+                class Foo:
+                    bar: Final[int] = 1
+                Foo()
+            """,
+            "classvar-not-outermost": """
+                import attrs
+                from typing import ClassVar
+
+                @attrs.define
+                class Foo:
+                    bar: list[ClassVar[int]] = []
+                Foo()
+            """,
+        }
+
+        for name, code in cases.items():
+            with self.subTest(case=name):
+                instance = next(astroid.extract_node(code).infer())
+                self.assertIsInstance(instance.getattr("bar")[0], nodes.Unknown)
+                self.assertIn("bar", instance.instance_attrs)
diff --git a/tests/brain/test_brain.py b/tests/brain/test_brain.py
index 610dcd0..0b60ac2 100644
--- a/tests/brain/test_brain.py
+++ b/tests/brain/test_brain.py
@@ -21,24 +21,20 @@
     InferenceError,
     UseInferenceDefault,
 )
-from astroid.nodes.node_classes import Const
-from astroid.nodes.scoped_nodes import ClassDef
 
 
-def assertEqualMro(klass: ClassDef, expected_mro: list[str]) -> None:
+def assertEqualMro(klass: nodes.ClassDef, expected_mro: list[str]) -> None:
     """Check mro names."""
     assert [member.qname() for member in klass.mro()] == expected_mro
 
 
 class CollectionsDequeTests(unittest.TestCase):
     def _inferred_queue_instance(self) -> Instance:
-        node = builder.extract_node(
-            """
+        node = builder.extract_node("""
         import collections
         q = collections.deque([])
         q
-        """
-        )
+        """)
         return next(node.infer())
 
     def test_deque(self) -> None:
@@ -58,13 +54,11 @@
 
 class OrderedDictTest(unittest.TestCase):
     def _inferred_ordered_dict_instance(self) -> Instance:
-        node = builder.extract_node(
-            """
+        node = builder.extract_node("""
         import collections
         d = collections.OrderedDict()
         d
-        """
-        )
+        """)
         return next(node.infer())
 
     def test_ordered_dict_py34method(self) -> None:
@@ -74,14 +68,12 @@
 
 class DefaultDictTest(unittest.TestCase):
     def test_1(self) -> None:
-        node = builder.extract_node(
-            """
+        node = builder.extract_node("""
         from collections import defaultdict
 
         X = defaultdict(int)
         X[0]
-        """
-        )
+        """)
         inferred = next(node.infer())
         self.assertIs(util.Uninferable, inferred)
 
@@ -113,12 +105,10 @@
     )
     def test_sys_streams(self):
         for name in ("stdout", "stderr", "stdin"):
-            node = astroid.extract_node(
-                f"""
+            node = astroid.extract_node(f"""
             import sys
             sys.{name}
-            """
-            )
+            """)
             inferred = next(node.infer())
             buffer_attr = next(inferred.igetattr("buffer"))
             self.assertIsInstance(buffer_attr, astroid.Instance)
@@ -128,23 +118,20 @@
             self.assertEqual(raw.name, "FileIO")
 
 
-@test_utils.require_version("3.9")
 class TypeBrain(unittest.TestCase):
     def test_type_subscript(self):
         """
         Check that type object has the __class_getitem__ method
         when it is used as a subscript
         """
-        src = builder.extract_node(
-            """
+        src = builder.extract_node("""
             a: type[int] = int
-            """
-        )
+            """)
         val_inf = src.annotation.value.inferred()[0]
-        self.assertIsInstance(val_inf, astroid.ClassDef)
+        self.assertIsInstance(val_inf, nodes.ClassDef)
         self.assertEqual(val_inf.name, "type")
         meth_inf = val_inf.getattr("__class_getitem__")[0]
-        self.assertIsInstance(meth_inf, astroid.FunctionDef)
+        self.assertIsInstance(meth_inf, nodes.FunctionDef)
 
     def test_invalid_type_subscript(self):
         """
@@ -152,13 +139,11 @@
         from type does not have __class_getitem__ method even
         when it is used as a subscript
         """
-        src = builder.extract_node(
-            """
+        src = builder.extract_node("""
             a: str[int] = "abc"
-            """
-        )
+            """)
         val_inf = src.annotation.value.inferred()[0]
-        self.assertIsInstance(val_inf, astroid.ClassDef)
+        self.assertIsInstance(val_inf, nodes.ClassDef)
         self.assertEqual(val_inf.name, "str")
         with self.assertRaises(AttributeInferenceError):
             # pylint: disable=expression-not-assigned
@@ -182,7 +167,7 @@
     if PY312_PLUS and node.name == "ByteString":
         # .metaclass() finds the first metaclass in the mro(),
         # which, from 3.12, is _DeprecateByteStringMeta (unhelpful)
-        # until ByteString is removed in 3.14.
+        # until ByteString is removed in 3.17.
         # Jump over the first two ByteString classes in the mro().
         check_metaclass_is_abc(node.mro()[2])
     else:
@@ -213,20 +198,16 @@
         Test that unsubscriptable types are detected
         Hashable is not subscriptable even with python39
         """
-        wrong_node = builder.extract_node(
-            """
+        wrong_node = builder.extract_node("""
         import collections.abc
         collections.abc.Hashable[int]
-        """
-        )
+        """)
         with self.assertRaises(InferenceError):
             next(wrong_node.infer())
-        right_node = builder.extract_node(
-            """
+        right_node = builder.extract_node("""
         import collections.abc
         collections.abc.Hashable
-        """
-        )
+        """)
         inferred = next(right_node.infer())
         check_metaclass_is_abc(inferred)
         assertEqualMro(
@@ -241,12 +222,10 @@
 
     def test_collections_object_subscriptable(self):
         """Starting with python39 some object of collections module are subscriptable. Test one of them"""
-        right_node = builder.extract_node(
-            """
+        right_node = builder.extract_node("""
         import collections.abc
         collections.abc.MutableSet[int]
-        """
-        )
+        """)
         inferred = next(right_node.infer())
         check_metaclass_is_abc(inferred)
         assertEqualMro(
@@ -265,52 +244,13 @@
             inferred.getattr("__class_getitem__")[0], nodes.FunctionDef
         )
 
-    @test_utils.require_version(maxver="3.9")
-    def test_collections_object_not_yet_subscriptable(self):
-        """
-        Test that unsubscriptable types are detected as such.
-        Until python39 MutableSet of the collections module is not subscriptable.
-        """
-        wrong_node = builder.extract_node(
-            """
-        import collections.abc
-        collections.abc.MutableSet[int]
-        """
-        )
-        with self.assertRaises(InferenceError):
-            next(wrong_node.infer())
-        right_node = builder.extract_node(
-            """
-        import collections.abc
-        collections.abc.MutableSet
-        """
-        )
-        inferred = next(right_node.infer())
-        check_metaclass_is_abc(inferred)
-        assertEqualMro(
-            inferred,
-            [
-                "_collections_abc.MutableSet",
-                "_collections_abc.Set",
-                "_collections_abc.Collection",
-                "_collections_abc.Sized",
-                "_collections_abc.Iterable",
-                "_collections_abc.Container",
-                "builtins.object",
-            ],
-        )
-        with self.assertRaises(AttributeInferenceError):
-            inferred.getattr("__class_getitem__")
-
     def test_collections_object_subscriptable_2(self):
         """Starting with python39 Iterator in the collection.abc module is subscriptable"""
-        node = builder.extract_node(
-            """
+        node = builder.extract_node("""
         import collections.abc
         class Derived(collections.abc.Iterator[int]):
             pass
-        """
-        )
+        """)
         inferred = next(node.infer())
         check_metaclass_is_abc(inferred)
         assertEqualMro(
@@ -323,27 +263,13 @@
             ],
         )
 
-    @test_utils.require_version(maxver="3.9")
-    def test_collections_object_not_yet_subscriptable_2(self):
-        """Before python39 Iterator in the collection.abc module is not subscriptable"""
-        node = builder.extract_node(
-            """
-        import collections.abc
-        collections.abc.Iterator[int]
-        """
-        )
-        with self.assertRaises(InferenceError):
-            next(node.infer())
-
     def test_collections_object_subscriptable_3(self):
         """With Python 3.9 the ByteString class of the collections module is subscriptable
         (but not the same class from typing module)"""
-        right_node = builder.extract_node(
-            """
+        right_node = builder.extract_node("""
         import collections.abc
         collections.abc.ByteString[int]
-        """
-        )
+        """)
         inferred = next(right_node.infer())
         check_metaclass_is_abc(inferred)
         self.assertIsInstance(
@@ -352,13 +278,11 @@
 
     def test_collections_object_subscriptable_4(self):
         """Multiple inheritance with subscriptable collection class"""
-        node = builder.extract_node(
-            """
+        node = builder.extract_node("""
         import collections.abc
         class Derived(collections.abc.Hashable, collections.abc.Iterator[int]):
             pass
-        """
-        )
+        """)
         inferred = next(node.infer())
         assertEqualMro(
             inferred,
@@ -371,17 +295,23 @@
             ],
         )
 
+    def test_statistics_quantiles_from_import(self):
+        node = builder.extract_node("""
+        from statistics import quantiles
+        quantiles([1, 2, 3, 4, 5, 6, 7, 8, 9], n=4)
+        """)
+        inferred = next(node.infer())
+        self.assertIs(inferred, util.Uninferable)
+
 
 class TypingBrain(unittest.TestCase):
     def test_namedtuple_base(self) -> None:
-        klass = builder.extract_node(
-            """
+        klass = builder.extract_node("""
         from typing import NamedTuple
 
         class X(NamedTuple("X", [("a", int), ("b", str), ("c", bytes)])):
            pass
-        """
-        )
+        """)
         self.assertEqual(
             [anc.name for anc in klass.ancestors()], ["X", "tuple", "object"]
         )
@@ -389,8 +319,7 @@
             self.assertFalse(anc.parent is None)
 
     def test_namedtuple_can_correctly_access_methods(self) -> None:
-        klass, called = builder.extract_node(
-            """
+        klass, called = builder.extract_node("""
         from typing import NamedTuple
 
         class X(NamedTuple): #@
@@ -401,87 +330,73 @@
             def as_integer(self):
                 return 2 + 3
         X().as_integer() #@
-        """
-        )
+        """)
         self.assertEqual(len(klass.getattr("as_string")), 1)
         inferred = next(called.infer())
-        self.assertIsInstance(inferred, astroid.Const)
+        self.assertIsInstance(inferred, nodes.Const)
         self.assertEqual(inferred.value, 5)
 
     def test_namedtuple_inference(self) -> None:
-        klass = builder.extract_node(
-            """
+        klass = builder.extract_node("""
         from typing import NamedTuple
 
         class X(NamedTuple("X", [("a", int), ("b", str), ("c", bytes)])):
            pass
-        """
-        )
+        """)
         base = next(base for base in klass.ancestors() if base.name == "X")
         self.assertSetEqual({"a", "b", "c"}, set(base.instance_attrs))
 
     def test_namedtuple_inference_nonliteral(self) -> None:
         # Note: NamedTuples in mypy only work with literals.
-        klass = builder.extract_node(
-            """
+        klass = builder.extract_node("""
         from typing import NamedTuple
 
         name = "X"
         fields = [("a", int), ("b", str), ("c", bytes)]
         NamedTuple(name, fields)
-        """
-        )
+        """)
         inferred = next(klass.infer())
         self.assertIsInstance(inferred, astroid.Instance)
         self.assertEqual(inferred.qname(), "typing.NamedTuple")
 
     def test_namedtuple_instance_attrs(self) -> None:
-        result = builder.extract_node(
-            """
+        result = builder.extract_node("""
         from typing import NamedTuple
         NamedTuple("A", [("a", int), ("b", str), ("c", bytes)])(1, 2, 3) #@
-        """
-        )
+        """)
         inferred = next(result.infer())
         for name, attr in inferred.instance_attrs.items():
             self.assertEqual(attr[0].attrname, name)
 
     def test_namedtuple_simple(self) -> None:
-        result = builder.extract_node(
-            """
+        result = builder.extract_node("""
         from typing import NamedTuple
         NamedTuple("A", [("a", int), ("b", str), ("c", bytes)])
-        """
-        )
+        """)
         inferred = next(result.infer())
         self.assertIsInstance(inferred, nodes.ClassDef)
         self.assertSetEqual({"a", "b", "c"}, set(inferred.instance_attrs))
 
     def test_namedtuple_few_args(self) -> None:
-        result = builder.extract_node(
-            """
+        result = builder.extract_node("""
         from typing import NamedTuple
         NamedTuple("A")
-        """
-        )
+        """)
         inferred = next(result.infer())
         self.assertIsInstance(inferred, astroid.Instance)
         self.assertEqual(inferred.qname(), "typing.NamedTuple")
 
     def test_namedtuple_few_fields(self) -> None:
-        result = builder.extract_node(
-            """
+        result = builder.extract_node("""
         from typing import NamedTuple
         NamedTuple("A", [("a",), ("b", str), ("c", bytes)])
-        """
-        )
+        """)
         inferred = next(result.infer())
         self.assertIsInstance(inferred, astroid.Instance)
         self.assertEqual(inferred.qname(), "typing.NamedTuple")
 
     def test_namedtuple_class_form(self) -> None:
-        result = builder.extract_node(
-            """
+        result = builder.extract_node("""
         from typing import NamedTuple
 
         class Example(NamedTuple):
@@ -489,23 +404,20 @@
             mything: int
 
         Example(mything=1)
-        """
-        )
+        """)
         inferred = next(result.infer())
         self.assertIsInstance(inferred, astroid.Instance)
 
         class_attr = inferred.getattr("CLASS_ATTR")[0]
-        self.assertIsInstance(class_attr, astroid.AssignName)
+        self.assertIsInstance(class_attr, nodes.AssignName)
         const = next(class_attr.infer())
         self.assertEqual(const.value, "class_attr")
 
     def test_namedtuple_inferred_as_class(self) -> None:
-        node = builder.extract_node(
-            """
+        node = builder.extract_node("""
         from typing import NamedTuple
         NamedTuple
-        """
-        )
+        """)
         inferred = next(node.infer())
         assert isinstance(inferred, nodes.ClassDef)
         assert inferred.name == "NamedTuple"
@@ -515,38 +427,31 @@
 
         https://github.com/pylint-dev/pylint/issues/4383
         """
-        node = builder.extract_node(
-            """
+        node = builder.extract_node("""
         if True:
             def NamedTuple():
                 pass
         NamedTuple
-        """
-        )
+        """)
         next(node.infer())
 
     def test_namedtuple_uninferable_member(self) -> None:
-        call = builder.extract_node(
-            """
+        call = builder.extract_node("""
         from typing import namedtuple
-        namedtuple('uninf', {x: x for x in range(0)})  #@"""
-        )
+        namedtuple('uninf', {x: x for x in range(0)})  #@""")
         with pytest.raises(UseInferenceDefault):
             _get_namedtuple_fields(call)
 
-        call = builder.extract_node(
-            """
+        call = builder.extract_node("""
         from typing import namedtuple
         uninferable = {x: x for x in range(0)}
         namedtuple('uninferable', uninferable)  #@
-        """
-        )
+        """)
         with pytest.raises(UseInferenceDefault):
             _get_namedtuple_fields(call)
 
     def test_typing_types(self) -> None:
-        ast_nodes = builder.extract_node(
-            """
+        ast_nodes = builder.extract_node("""
         from typing import TypeVar, Iterable, Tuple, NewType, Dict, Union
         TypeVar('MyTypeVar', int, float, complex) #@
         Iterable[Tuple[MyTypeVar, MyTypeVar]] #@
@@ -554,28 +459,24 @@
         NewType('UserId', str) #@
         Dict[str, str] #@
         Union[int, str] #@
-        """
-        )
+        """)
         for node in ast_nodes:
             inferred = next(node.infer())
             self.assertIsInstance(inferred, nodes.ClassDef, node.as_string())
 
     def test_typing_type_without_tip(self):
         """Regression test for https://github.com/pylint-dev/pylint/issues/5770"""
-        node = builder.extract_node(
-            """
+        node = builder.extract_node("""
         from typing import NewType
 
         def make_new_type(t):
             new_type = NewType(f'IntRange_{t}', t) #@
-        """
-        )
+        """)
         with self.assertRaises(UseInferenceDefault):
             astroid.brain.brain_typing.infer_typing_typevar_or_newtype(node.value)
 
     def test_namedtuple_nested_class(self):
-        result = builder.extract_node(
-            """
+        result = builder.extract_node("""
         from typing import NamedTuple
 
         class Example(NamedTuple):
@@ -583,36 +484,31 @@
                 bar = "bar"
 
         Example
-        """
-        )
+        """)
         inferred = next(result.infer())
-        self.assertIsInstance(inferred, astroid.ClassDef)
+        self.assertIsInstance(inferred, nodes.ClassDef)
 
         class_def_attr = inferred.getattr("Foo")[0]
-        self.assertIsInstance(class_def_attr, astroid.ClassDef)
+        self.assertIsInstance(class_def_attr, nodes.ClassDef)
         attr_def = class_def_attr.getattr("bar")[0]
         attr = next(attr_def.infer())
         self.assertEqual(attr.value, "bar")
 
     def test_tuple_type(self):
-        node = builder.extract_node(
-            """
+        node = builder.extract_node("""
         from typing import Tuple
         Tuple[int, int]
-        """
-        )
+        """)
         inferred = next(node.infer())
         assert isinstance(inferred, nodes.ClassDef)
         assert isinstance(inferred.getattr("__class_getitem__")[0], nodes.FunctionDef)
         assert inferred.qname() == "typing.Tuple"
 
     def test_callable_type(self):
-        node = builder.extract_node(
-            """
+        node = builder.extract_node("""
         from typing import Callable, Any
         Callable[..., Any]
-        """
-        )
+        """)
         inferred = next(node.infer())
         assert isinstance(inferred, nodes.ClassDef)
         assert isinstance(inferred.getattr("__class_getitem__")[0], nodes.FunctionDef)
@@ -620,13 +516,11 @@
 
     def test_typing_generic_subscriptable(self):
         """Test typing.Generic is subscriptable with __class_getitem__ (added in PY37)"""
-        node = builder.extract_node(
-            """
+        node = builder.extract_node("""
         from typing import Generic, TypeVar
         T = TypeVar('T')
         Generic[T]
-        """
-        )
+        """)
         inferred = next(node.infer())
         assert isinstance(inferred, nodes.ClassDef)
         assert isinstance(inferred.getattr("__class_getitem__")[0], nodes.FunctionDef)
@@ -634,12 +528,10 @@
     @test_utils.require_version(minver="3.12")
     def test_typing_generic_subscriptable_pep695(self):
         """Test class using type parameters is subscriptable with __class_getitem__ (added in PY312)"""
-        node = builder.extract_node(
-            """
+        node = builder.extract_node("""
         class Foo[T]: ...
         class Bar[T](Foo[T]): ...
-        """
-        )
+        """)
         inferred = next(node.infer())
         assert isinstance(inferred, nodes.ClassDef)
         assert inferred.name == "Bar"
@@ -651,12 +543,10 @@
 
     def test_typing_annotated_subscriptable(self):
         """typing.Annotated is subscriptable with __class_getitem__ below 3.13."""
-        node = builder.extract_node(
-            """
+        node = builder.extract_node("""
         import typing
         typing.Annotated[str, "data"]
-        """
-        )
+        """)
         inferred = next(node.infer())
         if PY313_PLUS:
             assert isinstance(inferred, nodes.FunctionDef)
@@ -668,16 +558,14 @@
 
     def test_typing_generic_slots(self):
         """Test slots for Generic subclass."""
-        node = builder.extract_node(
-            """
+        node = builder.extract_node("""
         from typing import Generic, TypeVar
         T = TypeVar('T')
         class A(Generic[T]):
             __slots__ = ['value']
             def __init__(self, value):
                 self.value = value
-        """
-        )
+        """)
         inferred = next(node.infer())
         slots = inferred.slots()
         assert len(slots) == 1
@@ -685,40 +573,32 @@
         assert slots[0].value == "value"
 
     def test_typing_no_duplicates(self):
-        node = builder.extract_node(
-            """
+        node = builder.extract_node("""
         from typing import List
         List[int]
-        """
-        )
+        """)
         assert len(node.inferred()) == 1
 
     def test_typing_no_duplicates_2(self):
-        node = builder.extract_node(
-            """
+        node = builder.extract_node("""
         from typing import Optional, Tuple
         Tuple[Optional[int], ...]
-        """
-        )
+        """)
         assert len(node.inferred()) == 1
 
-    @test_utils.require_version(minver="3.10")
     def test_typing_param_spec(self):
-        node = builder.extract_node(
-            """
+        node = builder.extract_node("""
         from typing import ParamSpec
 
         P = ParamSpec("P")
-        """
-        )
+        """)
         inferred = next(node.targets[0].infer())
         assert next(inferred.igetattr("args")) is not None
         assert next(inferred.igetattr("kwargs")) is not None
 
     def test_collections_generic_alias_slots(self):
         """Test slots for a class which is a subclass of a generic alias type."""
-        node = builder.extract_node(
-            """
+        node = builder.extract_node("""
         import collections
         import typing
         Type = typing.TypeVar('Type')
@@ -726,8 +606,7 @@
             __slots__ = ('_value',)
             def __init__(self, value: collections.abc.AsyncIterator[Type]):
                 self._value = value
-        """
-        )
+        """)
         inferred = next(node.infer())
         assert isinstance(inferred, nodes.ClassDef)
         slots = inferred.slots()
@@ -736,38 +615,32 @@
         assert slots[0].value == "_value"
 
     def test_has_dunder_args(self) -> None:
-        ast_node = builder.extract_node(
-            """
+        ast_node = builder.extract_node("""
         from typing import Union
         NumericTypes = Union[int, float]
         NumericTypes.__args__ #@
-        """
-        )
+        """)
         inferred = next(ast_node.infer())
         assert isinstance(inferred, nodes.Tuple)
 
     def test_typing_namedtuple_dont_crash_on_no_fields(self) -> None:
-        node = builder.extract_node(
-            """
+        node = builder.extract_node("""
         from typing import NamedTuple
 
         Bar = NamedTuple("bar", [])
 
         Bar()
-        """
-        )
+        """)
         inferred = next(node.infer())
         self.assertIsInstance(inferred, astroid.Instance)
 
     def test_typed_dict(self):
-        code = builder.extract_node(
-            """
+        code = builder.extract_node("""
         from typing import TypedDict
         class CustomTD(TypedDict):  #@
             var: int
         CustomTD(var=1)  #@
-        """
-        )
+        """)
         inferred_base = next(code[0].bases[0].infer())
         assert isinstance(inferred_base, nodes.ClassDef)
         assert inferred_base.qname() == "typing.TypedDict"
@@ -788,8 +661,7 @@
         correctly inferred.
         typing_alias function is introduced with python37
         """
-        node = builder.extract_node(
-            """
+        node = builder.extract_node("""
         from typing import TypeVar, MutableSet
 
         T = TypeVar("T")
@@ -797,8 +669,7 @@
 
         class Derived1(MutableSet[T]):
             pass
-        """
-        )
+        """)
         inferred = next(node.infer())
         assertEqualMro(
             inferred,
@@ -822,13 +693,11 @@
         typing_alias function is introduced with python37.
         OrderedDict in the typing module appears only with python 3.7.2
         """
-        node = builder.extract_node(
-            """
+        node = builder.extract_node("""
         import typing
         class Derived2(typing.OrderedDict[int, str]):
             pass
-        """
-        )
+        """)
         inferred = next(node.infer())
         assertEqualMro(
             inferred,
@@ -843,20 +712,16 @@
 
     def test_typing_object_not_subscriptable(self):
         """Hashable is not subscriptable"""
-        wrong_node = builder.extract_node(
-            """
+        wrong_node = builder.extract_node("""
         import typing
         typing.Hashable[int]
-        """
-        )
+        """)
         with self.assertRaises(InferenceError):
             next(wrong_node.infer())
-        right_node = builder.extract_node(
-            """
+        right_node = builder.extract_node("""
         import typing
         typing.Hashable
-        """
-        )
+        """)
         inferred = next(right_node.infer())
         assertEqualMro(
             inferred,
@@ -871,12 +736,10 @@
 
     def test_typing_object_subscriptable(self):
         """Test that MutableSet is subscriptable"""
-        right_node = builder.extract_node(
-            """
+        right_node = builder.extract_node("""
         import typing
         typing.MutableSet[int]
-        """
-        )
+        """)
         inferred = next(right_node.infer())
         assertEqualMro(
             inferred,
@@ -897,13 +760,11 @@
 
     def test_typing_object_subscriptable_2(self):
         """Multiple inheritance with subscriptable typing alias"""
-        node = builder.extract_node(
-            """
+        node = builder.extract_node("""
         import typing
         class Derived(typing.Hashable, typing.Iterator[int]):
             pass
-        """
-        )
+        """)
         inferred = next(node.infer())
         assertEqualMro(
             inferred,
@@ -919,14 +780,12 @@
         )
 
     def test_typing_object_notsubscriptable_3(self):
-        """Until python39 ByteString class of the typing module is not
+        """The ByteString class of the typing module is not
         subscriptable (whereas it is in the collections' module)"""
-        right_node = builder.extract_node(
-            """
+        right_node = builder.extract_node("""
         import typing
         typing.ByteString
-        """
-        )
+        """)
         inferred = next(right_node.infer())
         check_metaclass_is_abc(inferred)
         with self.assertRaises(AttributeInferenceError):
@@ -950,51 +809,44 @@
 
     @staticmethod
     def test_typing_type_subscriptable():
-        node = builder.extract_node(
-            """
+        node = builder.extract_node("""
         from typing import Type
         Type[int]
-        """
-        )
+        """)
         inferred = next(node.infer())
         assert isinstance(inferred, nodes.ClassDef)
         assert isinstance(inferred.getattr("__class_getitem__")[0], nodes.FunctionDef)
         assert inferred.qname() == "typing.Type"
 
     def test_typing_cast(self) -> None:
-        node = builder.extract_node(
-            """
+        node = builder.extract_node("""
         from typing import cast
         class A:
             pass
 
         b = 42
         cast(A, b)
-        """
-        )
+        """)
         inferred = next(node.infer())
         assert isinstance(inferred, nodes.Const)
         assert inferred.value == 42
 
     def test_typing_cast_attribute(self) -> None:
-        node = builder.extract_node(
-            """
+        node = builder.extract_node("""
         import typing
         class A:
             pass
 
         b = 42
         typing.cast(A, b)
-        """
-        )
+        """)
         inferred = next(node.infer())
         assert isinstance(inferred, nodes.Const)
         assert inferred.value == 42
 
     def test_typing_cast_multiple_inference_calls(self) -> None:
         """Inference of an outer function should not store the result for cast."""
-        ast_nodes = builder.extract_node(
-            """
+        ast_nodes = builder.extract_node("""
         from typing import TypeVar, cast
         T = TypeVar("T")
         def ident(var: T) -> T:
@@ -1002,8 +854,7 @@
 
         ident(2)  #@
         ident("Hello")  #@
-        """
-        )
+        """)
         i0 = next(ast_nodes[0].infer())
         assert isinstance(i0, nodes.Const)
         assert i0.value == 2
@@ -1021,73 +872,20 @@
             self.assertIn(name, re_ast)
             self.assertEqual(next(re_ast[name].infer()).value, getattr(re, name))
 
-    @test_utils.require_version(maxver="3.9")
-    def test_re_pattern_unsubscriptable(self):
-        """
-        re.Pattern and re.Match are unsubscriptable until PY39.
-        """
-        right_node1 = builder.extract_node(
-            """
-        import re
-        re.Pattern
-        """
-        )
-        inferred1 = next(right_node1.infer())
-        assert isinstance(inferred1, nodes.ClassDef)
-        with self.assertRaises(AttributeInferenceError):
-            assert isinstance(
-                inferred1.getattr("__class_getitem__")[0], nodes.FunctionDef
-            )
-
-        right_node2 = builder.extract_node(
-            """
-        import re
-        re.Pattern
-        """
-        )
-        inferred2 = next(right_node2.infer())
-        assert isinstance(inferred2, nodes.ClassDef)
-        with self.assertRaises(AttributeInferenceError):
-            assert isinstance(
-                inferred2.getattr("__class_getitem__")[0], nodes.FunctionDef
-            )
-
-        wrong_node1 = builder.extract_node(
-            """
-        import re
-        re.Pattern[int]
-        """
-        )
-        with self.assertRaises(InferenceError):
-            next(wrong_node1.infer())
-
-        wrong_node2 = builder.extract_node(
-            """
-        import re
-        re.Match[int]
-        """
-        )
-        with self.assertRaises(InferenceError):
-            next(wrong_node2.infer())
-
     def test_re_pattern_subscriptable(self):
         """Test re.Pattern and re.Match are subscriptable in PY39+"""
-        node1 = builder.extract_node(
-            """
+        node1 = builder.extract_node("""
         import re
         re.Pattern[str]
-        """
-        )
+        """)
         inferred1 = next(node1.infer())
         assert isinstance(inferred1, nodes.ClassDef)
         assert isinstance(inferred1.getattr("__class_getitem__")[0], nodes.FunctionDef)
 
-        node2 = builder.extract_node(
-            """
+        node2 = builder.extract_node("""
         import re
         re.Match[str]
-        """
-        )
+        """)
         inferred2 = next(node2.infer())
         assert isinstance(inferred2, nodes.ClassDef)
         assert isinstance(inferred2.getattr("__class_getitem__")[0], nodes.FunctionDef)
@@ -1095,80 +893,112 @@
 
 class BrainNamedtupleAnnAssignTest(unittest.TestCase):
     def test_no_crash_on_ann_assign_in_namedtuple(self) -> None:
-        node = builder.extract_node(
-            """
+        node = builder.extract_node("""
         from enum import Enum
         from typing import Optional
 
         class A(Enum):
             B: str = 'B'
-        """
-        )
+        """)
         inferred = next(node.infer())
         self.assertIsInstance(inferred, nodes.ClassDef)
 
 
 class BrainUUIDTest(unittest.TestCase):
     def test_uuid_has_int_member(self) -> None:
-        node = builder.extract_node(
-            """
+        node = builder.extract_node("""
         import uuid
         u = uuid.UUID('{12345678-1234-5678-1234-567812345678}')
         u.int
-        """
-        )
+        """)
         inferred = next(node.infer())
         self.assertIsInstance(inferred, nodes.Const)
 
 
 class RandomSampleTest(unittest.TestCase):
     def test_inferred_successfully(self) -> None:
-        node = astroid.extract_node(
-            """
+        node = astroid.extract_node("""
         import random
         random.sample([1, 2], 2) #@
-        """
-        )
+        """)
         inferred = next(node.infer())
-        self.assertIsInstance(inferred, astroid.List)
+        self.assertIsInstance(inferred, nodes.List)
         elems = sorted(elem.value for elem in inferred.elts)
         self.assertEqual(elems, [1, 2])
 
     def test_arguments_inferred_successfully(self) -> None:
         """Test inference of `random.sample` when both arguments are of type `nodes.Call`."""
-        node = astroid.extract_node(
-            """
+        node = astroid.extract_node("""
         import random
 
         def sequence():
             return [1, 2]
 
         random.sample(sequence(), len([1,2])) #@
-        """
-        )
+        """)
         # Check that arguments are of type `nodes.Call`.
         sequence, length = node.args
-        self.assertIsInstance(sequence, astroid.Call)
-        self.assertIsInstance(length, astroid.Call)
+        self.assertIsInstance(sequence, nodes.Call)
+        self.assertIsInstance(length, nodes.Call)
 
         # Check the inference of `random.sample` call.
         inferred = next(node.infer())
-        self.assertIsInstance(inferred, astroid.List)
+        self.assertIsInstance(inferred, nodes.List)
         elems = sorted(elem.value for elem in inferred.elts)
         self.assertEqual(elems, [1, 2])
 
     def test_no_crash_on_evaluatedobject(self) -> None:
-        node = astroid.extract_node(
-            """
+        node = astroid.extract_node("""
         from random import sample
         class A: pass
-        sample(list({1: A()}.values()), 1)"""
-        )
+        sample(list({1: A()}.values()), 1)""")
         inferred = next(node.infer())
-        assert isinstance(inferred, astroid.List)
+        assert isinstance(inferred, nodes.List)
         assert len(inferred.elts) == 1
         assert isinstance(inferred.elts[0], nodes.Call)
 
+    def test_no_crash_on_uninferable_element(self) -> None:
+        """Test that random.sample does not crash when elements are Uninferable.
+
+        Regression test for https://github.com/pylint-dev/astroid/issues/2518
+        """
+        node = astroid.extract_node("""
+        import random
+        random.sample(1*[b], 1)  #@
+        """)
+        inferred = next(node.infer())
+        assert inferred is astroid.Uninferable
+
+    def test_no_crash_on_classdef_clone(self) -> None:
+        """Test that random.sample does not crash when cloning ClassDef nodes.
+
+        Regression test for https://github.com/pylint-dev/astroid/issues/2923
+        """
+        node = astroid.extract_node("""
+        import random
+        random.sample([dict] * 2, 1)  #@
+        """)
+        inferred = next(node.infer())
+        assert isinstance(inferred, nodes.List)
+        assert len(inferred.elts) == 1
+        assert isinstance(inferred.elts[0], nodes.ClassDef)
+        assert inferred.elts[0].name == "dict"
+
+    def test_no_crash_on_functiondef_clone(self) -> None:
+        """Test that random.sample does not crash when cloning FunctionDef nodes.
+
+        Regression test for https://github.com/pylint-dev/astroid/issues/2923
+        """
+        node = astroid.extract_node("""
+        import random
+        random.sample([len] * 2, 1)  #@
+        """)
+        inferred = next(node.infer())
+        assert isinstance(inferred, nodes.List)
+        assert len(inferred.elts) == 1
+        assert isinstance(inferred.elts[0], nodes.FunctionDef)
+        assert inferred.elts[0].name == "len"
+
 
 class SubprocessTest(unittest.TestCase):
     """Test subprocess brain"""
@@ -1177,13 +1007,11 @@
         """Make sure the args attribute exists for Popen
 
         Test for https://github.com/pylint-dev/pylint/issues/1860"""
-        name = astroid.extract_node(
-            """
+        name = astroid.extract_node("""
         import subprocess
         p = subprocess.Popen(['ls'])
         p #@
-        """
-        )
+        """)
         [inst] = name.inferred()
         self.assertIsInstance(next(inst.igetattr("args")), nodes.List)
 
@@ -1196,10 +1024,9 @@
         node = astroid.extract_node(code)
         inferred = next(node.infer())
         # Can be either str or bytes
-        assert isinstance(inferred, astroid.Const)
+        assert isinstance(inferred, nodes.Const)
         assert isinstance(inferred.value, (str, bytes))
 
-    @test_utils.require_version("3.9")
     def test_popen_does_not_have_class_getitem(self):
         code = """import subprocess; subprocess.Popen"""
         node = astroid.extract_node(code)
@@ -1227,54 +1054,34 @@
         assert _get_result("isinstance('a', int)") == "False"
 
     def test_isinstance_object_true(self) -> None:
-        assert (
-            _get_result(
-                """
+        assert _get_result("""
         class Bar(object):
             pass
         isinstance(Bar(), object)
-        """
-            )
-            == "True"
-        )
+        """) == "True"
 
     def test_isinstance_object_true3(self) -> None:
-        assert (
-            _get_result(
-                """
+        assert _get_result("""
         class Bar(object):
             pass
         isinstance(Bar(), Bar)
-        """
-            )
-            == "True"
-        )
+        """) == "True"
 
     def test_isinstance_class_false(self) -> None:
-        assert (
-            _get_result(
-                """
+        assert _get_result("""
         class Foo(object):
             pass
         class Bar(object):
             pass
         isinstance(Bar(), Foo)
-        """
-            )
-            == "False"
-        )
+        """) == "False"
 
     def test_isinstance_type_false(self) -> None:
-        assert (
-            _get_result(
-                """
+        assert _get_result("""
         class Bar(object):
             pass
         isinstance(Bar(), type)
-        """
-            )
-            == "False"
-        )
+        """) == "False"
 
     def test_isinstance_str_true(self) -> None:
         """Make sure isinstance can check builtin str types"""
@@ -1288,40 +1095,25 @@
         assert _get_result("isinstance(1, (str, int))") == "True"
 
     def test_isinstance_type_false2(self) -> None:
-        assert (
-            _get_result(
-                """
+        assert _get_result("""
         isinstance(1, type)
-        """
-            )
-            == "False"
-        )
+        """) == "False"
 
     def test_isinstance_object_true2(self) -> None:
-        assert (
-            _get_result(
-                """
+        assert _get_result("""
         class Bar(type):
             pass
         mainbar = Bar("Bar", tuple(), {})
         isinstance(mainbar, object)
-        """
-            )
-            == "True"
-        )
+        """) == "True"
 
     def test_isinstance_type_true(self) -> None:
-        assert (
-            _get_result(
-                """
+        assert _get_result("""
         class Bar(type):
             pass
         mainbar = Bar("Bar", tuple(), {})
         isinstance(mainbar, type)
-        """
-            )
-            == "True"
-        )
+        """) == "True"
 
     def test_isinstance_edge_case(self) -> None:
         """isinstance allows bad type short-circuting"""
@@ -1366,70 +1158,45 @@
         assert _get_result("issubclass(str, int)") == "False"
 
     def test_issubclass_object_true(self) -> None:
-        assert (
-            _get_result(
-                """
+        assert _get_result("""
         class Bar(object):
             pass
         issubclass(Bar, object)
-        """
-            )
-            == "True"
-        )
+        """) == "True"
 
     def test_issubclass_same_user_defined_class(self) -> None:
-        assert (
-            _get_result(
-                """
+        assert _get_result("""
         class Bar(object):
             pass
         issubclass(Bar, Bar)
-        """
-            )
-            == "True"
-        )
+        """) == "True"
 
     def test_issubclass_different_user_defined_classes(self) -> None:
-        assert (
-            _get_result(
-                """
+        assert _get_result("""
         class Foo(object):
             pass
         class Bar(object):
             pass
         issubclass(Bar, Foo)
-        """
-            )
-            == "False"
-        )
+        """) == "False"
 
     def test_issubclass_type_false(self) -> None:
-        assert (
-            _get_result(
-                """
+        assert _get_result("""
         class Bar(object):
             pass
         issubclass(Bar, type)
-        """
-            )
-            == "False"
-        )
+        """) == "False"
 
     def test_isinstance_tuple_argument(self) -> None:
         """obj just has to be a subclass of ANY class/type on the right"""
         assert _get_result("issubclass(int, (str, int))") == "True"
 
     def test_isinstance_object_true2(self) -> None:
-        assert (
-            _get_result(
-                """
+        assert _get_result("""
         class Bar(type):
             pass
         issubclass(Bar, object)
-        """
-            )
-            == "True"
-        )
+        """) == "True"
 
     def test_issubclass_short_circuit(self) -> None:
         """issubclasss allows bad type short-circuting"""
@@ -1452,7 +1219,7 @@
             _get_result_node("issubclass(int, int, str)")
 
 
-def _get_result_node(code: str) -> Const:
+def _get_result_node(code: str) -> nodes.Const:
     node = next(astroid.extract_node(code).infer())
     return node
 
@@ -1464,72 +1231,59 @@
 class TestLenBuiltinInference:
     def test_len_list(self) -> None:
         # Uses .elts
-        node = astroid.extract_node(
-            """
+        node = astroid.extract_node("""
         len(['a','b','c'])
-        """
-        )
+        """)
         node = next(node.infer())
         assert node.as_string() == "3"
         assert isinstance(node, nodes.Const)
 
     def test_len_tuple(self) -> None:
-        node = astroid.extract_node(
-            """
+        node = astroid.extract_node("""
         len(('a','b','c'))
-        """
-        )
+        """)
         node = next(node.infer())
         assert node.as_string() == "3"
 
     def test_len_var(self) -> None:
         # Make sure argument is inferred
-        node = astroid.extract_node(
-            """
+        node = astroid.extract_node("""
         a = [1,2,'a','b','c']
         len(a)
-        """
-        )
+        """)
         node = next(node.infer())
         assert node.as_string() == "5"
 
     def test_len_dict(self) -> None:
         # Uses .items
-        node = astroid.extract_node(
-            """
+        node = astroid.extract_node("""
         a = {'a': 1, 'b': 2}
         len(a)
-        """
-        )
+        """)
         node = next(node.infer())
         assert node.as_string() == "2"
 
     def test_len_set(self) -> None:
-        node = astroid.extract_node(
-            """
+        node = astroid.extract_node("""
         len({'a'})
-        """
-        )
+        """)
         inferred_node = next(node.infer())
         assert inferred_node.as_string() == "1"
 
     def test_len_object(self) -> None:
         """Test len with objects that implement the len protocol"""
-        node = astroid.extract_node(
-            """
+        node = astroid.extract_node("""
         class A:
             def __len__(self):
                 return 57
         len(A())
-        """
-        )
+        """)
         inferred_node = next(node.infer())
         assert inferred_node.as_string() == "57"
 
     def test_len_class_with_metaclass(self) -> None:
         """Make sure proper len method is located"""
-        cls_node, inst_node = astroid.extract_node(
-            """
+        cls_node, inst_node = astroid.extract_node("""
         class F2(type):
             def __new__(cls, name, bases, attrs):
                 return super().__new__(cls, name, bases, {})
@@ -1540,59 +1294,48 @@
                 return 4
         len(F) #@
         len(F()) #@
-        """
-        )
+        """)
         assert next(cls_node.infer()).as_string() == "57"
         assert next(inst_node.infer()).as_string() == "4"
 
     def test_len_object_failure(self) -> None:
         """If taking the length of a class, do not use an instance method"""
-        node = astroid.extract_node(
-            """
+        node = astroid.extract_node("""
         class F:
             def __len__(self):
                 return 57
         len(F)
-        """
-        )
+        """)
         with pytest.raises(InferenceError):
             next(node.infer())
 
     def test_len_string(self) -> None:
-        node = astroid.extract_node(
-            """
+        node = astroid.extract_node("""
         len("uwu")
-        """
-        )
+        """)
         assert next(node.infer()).as_string() == "3"
 
     def test_len_generator_failure(self) -> None:
-        node = astroid.extract_node(
-            """
+        node = astroid.extract_node("""
         def gen():
             yield 'a'
             yield 'b'
         len(gen())
-        """
-        )
+        """)
         with pytest.raises(InferenceError):
             next(node.infer())
 
     def test_len_failure_missing_variable(self) -> None:
-        node = astroid.extract_node(
-            """
+        node = astroid.extract_node("""
         len(a)
-        """
-        )
+        """)
         with pytest.raises(InferenceError):
             next(node.infer())
 
     def test_len_bytes(self) -> None:
-        node = astroid.extract_node(
-            """
+        node = astroid.extract_node("""
         len(b'uwu')
-        """
-        )
+        """)
         assert next(node.infer()).as_string() == "3"
 
     def test_int_subclass_result(self) -> None:
@@ -1602,8 +1345,7 @@
         int subclass (5) but still returns a proper integer as we
         fake the result of the `len()` call.
         """
-        node = astroid.extract_node(
-            """
+        node = astroid.extract_node("""
         class IntSubclass(int):
             pass
 
@@ -1611,21 +1353,18 @@
             def __len__(self):
                 return IntSubclass(5)
         len(F())
-        """
-        )
+        """)
         assert next(node.infer()).as_string() == "0"
 
     @pytest.mark.xfail(reason="Can't use list special astroid fields")
     def test_int_subclass_argument(self):
         """I am unable to access the length of an object which
         subclasses list"""
-        node = astroid.extract_node(
-            """
+        node = astroid.extract_node("""
         class ListSubclass(list):
             pass
         len(ListSubclass([1,2,3,4,4]))
-        """
-        )
+        """)
         assert next(node.infer()).as_string() == "5"
 
     def test_len_builtin_inference_attribute_error_str(self) -> None:
@@ -1664,47 +1403,39 @@
 
 
 def test_infer_str() -> None:
-    ast_nodes = astroid.extract_node(
-        """
+    ast_nodes = astroid.extract_node("""
     str(s) #@
     str('a') #@
     str(some_object()) #@
-    """
-    )
+    """)
     for node in ast_nodes:
         inferred = next(node.infer())
-        assert isinstance(inferred, astroid.Const)
+        assert isinstance(inferred, nodes.Const)
 
-    node = astroid.extract_node(
-        """
+    node = astroid.extract_node("""
     str(s='') #@
-    """
-    )
+    """)
     inferred = next(node.infer())
     assert isinstance(inferred, astroid.Instance)
     assert inferred.qname() == "builtins.str"
 
 
 def test_infer_int() -> None:
-    ast_nodes = astroid.extract_node(
-        """
+    ast_nodes = astroid.extract_node("""
     int(0) #@
     int('1') #@
-    """
-    )
+    """)
     for node in ast_nodes:
         inferred = next(node.infer())
-        assert isinstance(inferred, astroid.Const)
+        assert isinstance(inferred, nodes.Const)
 
-    ast_nodes = astroid.extract_node(
-        """
+    ast_nodes = astroid.extract_node("""
     int(s='') #@
     int('2.5') #@
     int('something else') #@
     int(unknown) #@
     int(b'a') #@
-    """
-    )
+    """)
     for node in ast_nodes:
         inferred = next(node.infer())
         assert isinstance(inferred, astroid.Instance)
@@ -1712,87 +1443,75 @@
 
 
 def test_infer_dict_from_keys() -> None:
-    bad_nodes = astroid.extract_node(
-        """
+    bad_nodes = astroid.extract_node("""
     dict.fromkeys() #@
     dict.fromkeys(1, 2, 3) #@
     dict.fromkeys(a=1) #@
-    """
-    )
+    """)
     for node in bad_nodes:
         with pytest.raises(InferenceError):
             if isinstance(next(node.infer()), util.UninferableBase):
                 raise InferenceError
 
     # Test uninferable values
-    good_nodes = astroid.extract_node(
-        """
+    good_nodes = astroid.extract_node("""
     from unknown import Unknown
     dict.fromkeys(some_value) #@
     dict.fromkeys(some_other_value) #@
     dict.fromkeys([Unknown(), Unknown()]) #@
     dict.fromkeys([Unknown(), Unknown()]) #@
-    """
-    )
+    """)
     for node in good_nodes:
         inferred = next(node.infer())
-        assert isinstance(inferred, astroid.Dict)
+        assert isinstance(inferred, nodes.Dict)
         assert inferred.items == []
 
     # Test inferable values
 
     # from a dictionary's keys
-    from_dict = astroid.extract_node(
-        """
+    from_dict = astroid.extract_node("""
     dict.fromkeys({'a':2, 'b': 3, 'c': 3}) #@
-    """
-    )
+    """)
     inferred = next(from_dict.infer())
-    assert isinstance(inferred, astroid.Dict)
+    assert isinstance(inferred, nodes.Dict)
     itered = inferred.itered()
-    assert all(isinstance(elem, astroid.Const) for elem in itered)
+    assert all(isinstance(elem, nodes.Const) for elem in itered)
     actual_values = [elem.value for elem in itered]
     assert sorted(actual_values) == ["a", "b", "c"]
 
     # from a string
-    from_string = astroid.extract_node(
-        """
+    from_string = astroid.extract_node("""
     dict.fromkeys('abc')
-    """
-    )
+    """)
     inferred = next(from_string.infer())
-    assert isinstance(inferred, astroid.Dict)
+    assert isinstance(inferred, nodes.Dict)
     itered = inferred.itered()
-    assert all(isinstance(elem, astroid.Const) for elem in itered)
+    assert all(isinstance(elem, nodes.Const) for elem in itered)
     actual_values = [elem.value for elem in itered]
     assert sorted(actual_values) == ["a", "b", "c"]
 
     # from bytes
-    from_bytes = astroid.extract_node(
-        """
+    from_bytes = astroid.extract_node("""
     dict.fromkeys(b'abc')
-    """
-    )
+    """)
     inferred = next(from_bytes.infer())
-    assert isinstance(inferred, astroid.Dict)
+    assert isinstance(inferred, nodes.Dict)
     itered = inferred.itered()
-    assert all(isinstance(elem, astroid.Const) for elem in itered)
+    assert all(isinstance(elem, nodes.Const) for elem in itered)
     actual_values = [elem.value for elem in itered]
     assert sorted(actual_values) == [97, 98, 99]
 
     # From list/set/tuple
-    from_others = astroid.extract_node(
-        """
+    from_others = astroid.extract_node("""
     dict.fromkeys(('a', 'b', 'c')) #@
     dict.fromkeys(['a', 'b', 'c']) #@
     dict.fromkeys({'a', 'b', 'c'}) #@
-    """
-    )
+    """)
     for node in from_others:
         inferred = next(node.infer())
-        assert isinstance(inferred, astroid.Dict)
+        assert isinstance(inferred, nodes.Dict)
         itered = inferred.itered()
-        assert all(isinstance(elem, astroid.Const) for elem in itered)
+        assert all(isinstance(elem, nodes.Const) for elem in itered)
         actual_values = [elem.value for elem in itered]
         assert sorted(actual_values) == ["a", "b", "c"]
 
@@ -1800,15 +1519,13 @@
 class TestFunctoolsPartial:
     @staticmethod
     def test_infer_partial() -> None:
-        ast_node = astroid.extract_node(
-            """
+        ast_node = astroid.extract_node("""
         from functools import partial
         def test(a, b):
             '''Docstring'''
             return a + b
         partial(test, 1)(3) #@
-        """
-        )
+        """)
         assert isinstance(ast_node.func, nodes.Call)
         inferred = ast_node.func.inferred()
         assert len(inferred) == 1
@@ -1821,8 +1538,7 @@
         assert partial.col_offset == 0
 
     def test_invalid_functools_partial_calls(self) -> None:
-        ast_nodes = astroid.extract_node(
-            """
+        ast_nodes = astroid.extract_node("""
         from functools import partial
         from unknown import Unknown
 
@@ -1836,19 +1552,17 @@
         partial(Unknown, a=1) #@
         partial(2, a=1) #@
         partial(test, unknown=1) #@
-        """
-        )
+        """)
         for node in ast_nodes:
             inferred = next(node.infer())
-            assert isinstance(inferred, (astroid.FunctionDef, astroid.Instance))
+            assert isinstance(inferred, (nodes.FunctionDef, astroid.Instance))
             assert inferred.qname() in {
                 "functools.partial",
                 "functools.partial.newfunc",
             }
 
     def test_inferred_partial_function_calls(self) -> None:
-        ast_nodes = astroid.extract_node(
-            """
+        ast_nodes = astroid.extract_node("""
         from functools import partial
         def test(a, b):
             return a + b
@@ -1866,18 +1580,16 @@
         test(1, 2) #@
         partial(other_test, 1, 2)(c=3) #@
         partial(test, b=4)(a=3) #@
-        """
-        )
+        """)
         expected_values = [4, 7, 7, 3, 12, 16, 32, 36, 3, 9, 7]
         for node, expected_value in zip(ast_nodes, expected_values):
             inferred = next(node.infer())
-            assert isinstance(inferred, astroid.Const)
+            assert isinstance(inferred, nodes.Const)
             assert inferred.value == expected_value
 
     def test_partial_assignment(self) -> None:
         """Make sure partials are not assigned to original scope."""
-        ast_nodes = astroid.extract_node(
-            """
+        ast_nodes = astroid.extract_node("""
         from functools import partial
         def test(a, b): #@
             return a + b
@@ -1886,8 +1598,7 @@
         def test3_scope(a):
             test3 = partial(test, a)
             test3 #@
-        """
-        )
+        """)
         func1, func2, func3 = ast_nodes
         assert func1.parent.scope() == func2.parent.scope()
         assert func1.parent.scope() != func3.parent.scope()
@@ -1898,16 +1609,14 @@
 
     def test_partial_does_not_affect_scope(self) -> None:
         """Make sure partials are not automatically assigned."""
-        ast_nodes = astroid.extract_node(
-            """
+        ast_nodes = astroid.extract_node("""
         from functools import partial
         def test(a, b):
             return a + b
         def scope():
             test2 = partial(test, 1)
             test2 #@
-        """
-        )
+        """)
         test2 = next(ast_nodes.infer())
         mod_scope = test2.root()
         scope = test2.parent.scope()
@@ -1916,8 +1625,7 @@
 
     def test_multiple_partial_args(self) -> None:
         "Make sure partials remember locked-in args."
-        ast_node = astroid.extract_node(
-            """
+        ast_node = astroid.extract_node("""
         from functools import partial
         def test(a, b, c, d, e=5):
             return a + b + c + d + e
@@ -1925,8 +1633,7 @@
         test2 = partial(test1, 2)
         test3 = partial(test2, 3)
         test3(4, e=6) #@
-        """
-        )
+        """)
         expected_args = [1, 2, 3, 4]
         expected_keywords = {"e": 6}
 
@@ -1944,62 +1651,52 @@
 
 
 def test_http_client_brain() -> None:
-    node = astroid.extract_node(
-        """
+    node = astroid.extract_node("""
     from http.client import OK
     OK
-    """
-    )
+    """)
     inferred = next(node.infer())
     assert isinstance(inferred, astroid.Instance)
 
 
 def test_http_status_brain() -> None:
-    node = astroid.extract_node(
-        """
+    node = astroid.extract_node("""
     import http
     http.HTTPStatus.CONTINUE.phrase
-    """
-    )
+    """)
     inferred = next(node.infer())
     # Cannot infer the exact value but the field is there.
     assert inferred.value == ""
 
-    node = astroid.extract_node(
-        """
+    node = astroid.extract_node("""
     import http
     http.HTTPStatus(200).phrase
-    """
-    )
+    """)
     inferred = next(node.infer())
-    assert isinstance(inferred, astroid.Const)
+    assert isinstance(inferred, nodes.Const)
 
 
 def test_http_status_brain_iterable() -> None:
     """Astroid inference of `http.HTTPStatus` is an iterable subclass of `enum.IntEnum`"""
-    node = astroid.extract_node(
-        """
+    node = astroid.extract_node("""
     import http
     http.HTTPStatus
-    """
-    )
+    """)
     inferred = next(node.infer())
     assert "enum.IntEnum" in [ancestor.qname() for ancestor in inferred.ancestors()]
     assert inferred.getattr("__iter__")
 
 
 def test_oserror_model() -> None:
-    node = astroid.extract_node(
-        """
+    node = astroid.extract_node("""
     try:
         1/0
     except OSError as exc:
         exc #@
-    """
-    )
+    """)
     inferred = next(node.infer())
     strerror = next(inferred.igetattr("strerror"))
-    assert isinstance(strerror, astroid.Const)
+    assert isinstance(strerror, nodes.Const)
     assert strerror.value == ""
 
 
@@ -2020,9 +1717,9 @@
 @pytest.mark.parametrize(
     "code,expected_class,expected_value",
     [
-        ("'hey'.encode()", astroid.Const, b""),
-        ("b'hey'.decode()", astroid.Const, ""),
-        ("'hey'.encode().decode()", astroid.Const, ""),
+        ("'hey'.encode()", nodes.Const, b""),
+        ("b'hey'.decode()", nodes.Const, ""),
+        ("'hey'.encode().decode()", nodes.Const, ""),
     ],
 )
 def test_str_and_bytes(code, expected_class, expected_value):
@@ -2039,14 +1736,12 @@
     This test should only raise an InferenceError and no RecursionError.
     """
     with pytest.raises(InferenceError):
-        node = astroid.extract_node(
-            """
+        node = astroid.extract_node("""
         class Crash:
             def __len__(self) -> int:
                 return len(self)
         len(Crash()) #@
-        """
-        )
+        """)
         assert isinstance(node, nodes.NodeNG)
         node.inferred()
 
@@ -2058,8 +1753,7 @@
 
     This test should succeed without any error.
     """
-    node = astroid.extract_node(
-        """
+    node = astroid.extract_node("""
     class A:
         def __len__(self) -> int:
             return 42
@@ -2070,8 +1764,7 @@
             return len(a)
 
     len(Crash()) #@
-    """
-    )
+    """)
     inferred = node.inferred()
     assert len(inferred) == 1
     assert isinstance(inferred[0], nodes.Const)
@@ -2086,8 +1779,7 @@
     This test should only raise an InferenceError and no AttributeError.
     """
     with pytest.raises(InferenceError):
-        node = astroid.extract_node(
-            """
+        node = astroid.extract_node("""
         class MyClass:
             def some_func(self):
                 return lambda: 42
@@ -2096,7 +1788,6 @@
                 return len(self.some_func())
 
         len(MyClass()) #@
-        """
-        )
+        """)
         assert isinstance(node, nodes.NodeNG)
         node.inferred()
diff --git a/tests/brain/test_builtin.py b/tests/brain/test_builtin.py
index 6c49a80..85e1a1c 100644
--- a/tests/brain/test_builtin.py
+++ b/tests/brain/test_builtin.py
@@ -14,14 +14,12 @@
 
 class BuiltinsTest(unittest.TestCase):
     def test_infer_property(self):
-        property_assign = _extract_single_node(
-            """
+        property_assign = _extract_single_node("""
         class Something:
             def getter():
                 return 5
             asd = property(getter) #@
-        """
-        )
+        """)
         inferred_property = next(iter(property_assign.value.infer()))
         self.assertTrue(isinstance(inferred_property, objects.Property))
         class_parent = property_assign.scope()
@@ -139,8 +137,7 @@
 
     def test_string_format_in_dataclass_pylint8109(self) -> None:
         """https://github.com/pylint-dev/pylint/issues/8109"""
-        function_def = extract_node(
-            """
+        function_def = extract_node("""
 from dataclasses import dataclass
 
 @dataclass
@@ -151,7 +148,6 @@
     def __str__(self): #@
         number_format = "{:,.%sf}" % self.round
         return number_format.format(self.amount).rstrip("0").rstrip(".")
-"""
-        )
+""")
         inferit = function_def.infer_call_result(function_def, context=None)
         assert [a.name for a in inferit] == [util.Uninferable]
diff --git a/tests/brain/test_dataclasses.py b/tests/brain/test_dataclasses.py
index cd3fcb4..4795327 100644
--- a/tests/brain/test_dataclasses.py
+++ b/tests/brain/test_dataclasses.py
@@ -6,7 +6,6 @@
 
 import astroid
 from astroid import bases, nodes
-from astroid.const import PY310_PLUS
 from astroid.exceptions import InferenceError
 from astroid.util import Uninferable
 
@@ -21,8 +20,7 @@
 
     Note that the argument to the constructor is ignored by the inference.
     """
-    klass, instance = astroid.extract_node(
-        f"""
+    klass, instance = astroid.extract_node(f"""
     from {module} import dataclass
 
     @dataclass
@@ -31,8 +29,7 @@
 
     A.name  #@
     A('hi').name  #@
-    """
-    )
+    """)
     with pytest.raises(InferenceError):
         klass.inferred()
 
@@ -45,8 +42,7 @@
 @parametrize_module
 def test_inference_non_field_default(module: str):
     """Test inference of dataclass attribute with a non-field default."""
-    klass, instance = astroid.extract_node(
-        f"""
+    klass, instance = astroid.extract_node(f"""
     from {module} import dataclass
 
     @dataclass
@@ -55,8 +51,7 @@
 
     A.name  #@
     A().name  #@
-    """
-    )
+    """)
     inferred = klass.inferred()
     assert len(inferred) == 1
     assert isinstance(inferred[0], nodes.Const)
@@ -76,8 +71,7 @@
     """Test inference of dataclass attribute with a field call default
     (default keyword argument given).
     """
-    klass, instance = astroid.extract_node(
-        f"""
+    klass, instance = astroid.extract_node(f"""
     from {module} import dataclass
     from dataclasses import field
 
@@ -87,8 +81,7 @@
 
     A.name  #@
     A().name  #@
-    """
-    )
+    """)
     inferred = klass.inferred()
     assert len(inferred) == 1
     assert isinstance(inferred[0], nodes.Const)
@@ -108,8 +101,7 @@
     """Test inference of dataclass attribute with a field call default
     (default_factory keyword argument given).
     """
-    klass, instance = astroid.extract_node(
-        f"""
+    klass, instance = astroid.extract_node(f"""
     from {module} import dataclass
     from dataclasses import field
 
@@ -119,8 +111,7 @@
 
     A.name  #@
     A().name  #@
-    """
-    )
+    """)
     inferred = klass.inferred()
     assert len(inferred) == 1
     assert isinstance(inferred[0], nodes.List)
@@ -142,8 +133,7 @@
 
     Based on https://github.com/pylint-dev/pylint/issues/2600
     """
-    node = astroid.extract_node(
-        f"""
+    node = astroid.extract_node(f"""
     from typing import Dict
     from {module} import dataclass
     from dataclasses import field
@@ -159,8 +149,7 @@
             for key, value in f():
                 print(key)
                 print(value)
-    """
-    )
+    """)
     inferred = next(node.value.infer())
     assert isinstance(inferred, bases.BoundMethod)
 
@@ -170,8 +159,7 @@
     """Test that class variables without type annotations are not
     turned into instance attributes.
     """
-    class_def, klass, instance = astroid.extract_node(
-        f"""
+    class_def, klass, instance = astroid.extract_node(f"""
     from {module} import dataclass
 
     @dataclass
@@ -181,8 +169,7 @@
     A  #@
     A.name  #@
     A().name #@
-    """
-    )
+    """)
     inferred = next(class_def.infer())
     assert isinstance(inferred, nodes.ClassDef)
     assert inferred.instance_attrs == {}
@@ -202,8 +189,7 @@
     """Test that class variables with a ClassVar type annotations are not
     turned into instance attributes.
     """
-    class_def, klass, instance = astroid.extract_node(
-        f"""
+    class_def, klass, instance = astroid.extract_node(f"""
     from {module} import dataclass
     from typing import ClassVar
 
@@ -214,8 +200,7 @@
     A #@
     A.name  #@
     A().name #@
-    """
-    )
+    """)
     inferred = next(class_def.infer())
     assert isinstance(inferred, nodes.ClassDef)
     assert inferred.instance_attrs == {}
@@ -235,8 +220,7 @@
     """Test that class variables with InitVar type annotations are not
     turned into instance attributes.
     """
-    class_def, klass, instance = astroid.extract_node(
-        f"""
+    class_def, klass, instance = astroid.extract_node(f"""
     from {module} import dataclass
     from dataclasses import InitVar
 
@@ -247,8 +231,7 @@
     A  #@
     A.name  #@
     A().name #@
-    """
-    )
+    """)
     inferred = next(class_def.infer())
     assert isinstance(inferred, nodes.ClassDef)
     assert inferred.instance_attrs == {}
@@ -268,8 +251,7 @@
     """Test that an attribute with a generic collection type from the
     typing module is inferred correctly.
     """
-    attr_nodes = astroid.extract_node(
-        f"""
+    attr_nodes = astroid.extract_node(f"""
     from {module} import dataclass
     from dataclasses import field
     import typing
@@ -288,8 +270,7 @@
     a.list_prop       #@
     a.set_prop        #@
     a.tuple_prop      #@
-    """
-    )
+    """)
     names = (
         "Dict",
         "FrozenSet",
@@ -318,8 +299,7 @@
 
     See issue #1129 and pylint-dev/pylint#4895
     """
-    instance = astroid.extract_node(
-        f"""
+    instance = astroid.extract_node(f"""
     from {module} import dataclass
     from {typing_module} import Any, Callable
 
@@ -328,8 +308,7 @@
         enabled: Callable[[Any], bool]
 
     A(lambda x: x == 42).enabled  #@
-    """
-    )
+    """)
     inferred = next(instance.infer())
     assert inferred is Uninferable
 
@@ -337,8 +316,7 @@
 @parametrize_module
 def test_inference_inherited(module: str):
     """Test that an attribute is inherited from a superclass dataclass."""
-    klass1, instance1, klass2, instance2 = astroid.extract_node(
-        f"""
+    klass1, instance1, klass2, instance2 = astroid.extract_node(f"""
     from {module} import dataclass
 
     @dataclass
@@ -354,8 +332,7 @@
     B(1).value  #@
     B.name  #@
     B(1).name  #@
-    """
-    )
+    """)
     with pytest.raises(InferenceError):  # B.value is not defined
         klass1.inferred()
 
@@ -378,8 +355,7 @@
 
 def test_dataclass_order_of_inherited_attributes():
     """Test that an attribute in a child does not get put at the end of the init."""
-    child, normal, keyword_only = astroid.extract_node(
-        """
+    child, normal, keyword_only = astroid.extract_node("""
     from dataclass import dataclass
 
 
@@ -416,25 +392,17 @@
     Child.__init__  #@
     NormalChild.__init__  #@
     KeywordOnlyChild.__init__  #@
-    """
-    )
+    """)
     child_init: bases.UnboundMethod = next(child.infer())
     assert [a.name for a in child_init.args.args] == ["self", "a", "b", "c"]
 
     normal_init: bases.UnboundMethod = next(normal.infer())
-    if PY310_PLUS:
-        assert [a.name for a in normal_init.args.args] == ["self", "a", "c"]
-        assert [a.name for a in normal_init.args.kwonlyargs] == ["b"]
-    else:
-        assert [a.name for a in normal_init.args.args] == ["self", "a", "b", "c"]
-        assert [a.name for a in normal_init.args.kwonlyargs] == []
+    assert [a.name for a in normal_init.args.args] == ["self", "a", "c"]
+    assert [a.name for a in normal_init.args.kwonlyargs] == ["b"]
 
     keyword_only_init: bases.UnboundMethod = next(keyword_only.infer())
-    if PY310_PLUS:
-        assert [a.name for a in keyword_only_init.args.args] == ["self"]
-        assert [a.name for a in keyword_only_init.args.kwonlyargs] == ["a", "b", "c"]
-    else:
-        assert [a.name for a in keyword_only_init.args.args] == ["self", "a", "b", "c"]
+    assert [a.name for a in keyword_only_init.args.args] == ["self"]
+    assert [a.name for a in keyword_only_init.args.kwonlyargs] == ["a", "b", "c"]
 
 
 def test_pydantic_field() -> None:
@@ -442,8 +410,7 @@
 
     (Eventually, we can extend the brain to support pydantic.Field)
     """
-    klass, instance = astroid.extract_node(
-        """
+    klass, instance = astroid.extract_node("""
     from pydantic import Field
     from pydantic.dataclasses import dataclass
 
@@ -453,8 +420,7 @@
 
     A.name  #@
     A().name #@
-    """
-    )
+    """)
 
     inferred = klass.inferred()
     assert len(inferred) == 1
@@ -470,8 +436,7 @@
 @parametrize_module
 def test_init_empty(module: str):
     """Test init for a dataclass with no attributes."""
-    node = astroid.extract_node(
-        f"""
+    node = astroid.extract_node(f"""
     from {module} import dataclass
 
     @dataclass
@@ -479,8 +444,7 @@
         pass
 
     A.__init__  #@
-    """
-    )
+    """)
     init = next(node.infer())
     assert [a.name for a in init.args.args] == ["self"]
 
@@ -488,8 +452,7 @@
 @parametrize_module
 def test_init_no_defaults(module: str):
     """Test init for a dataclass with attributes and no defaults."""
-    node = astroid.extract_node(
-        f"""
+    node = astroid.extract_node(f"""
     from {module} import dataclass
     from typing import List
 
@@ -500,8 +463,7 @@
         z: List[bool]
 
     A.__init__  #@
-    """
-    )
+    """)
     init = next(node.infer())
     assert [a.name for a in init.args.args] == ["self", "x", "y", "z"]
     assert [a.as_string() if a else None for a in init.args.annotations] == [
@@ -515,8 +477,7 @@
 @parametrize_module
 def test_init_defaults(module: str):
     """Test init for a dataclass with attributes and some defaults."""
-    node = astroid.extract_node(
-        f"""
+    node = astroid.extract_node(f"""
     from {module} import dataclass
     from dataclasses import field
     from typing import List
@@ -529,8 +490,7 @@
         z: List[bool] = field(default_factory=list)
 
     A.__init__  #@
-    """
-    )
+    """)
     init = next(node.infer())
     assert [a.name for a in init.args.args] == ["self", "w", "x", "y", "z"]
     assert [a.as_string() if a else None for a in init.args.annotations] == [
@@ -550,8 +510,7 @@
 @parametrize_module
 def test_init_initvar(module: str):
     """Test init for a dataclass with attributes and an InitVar."""
-    node = astroid.extract_node(
-        f"""
+    node = astroid.extract_node(f"""
     from {module} import dataclass
     from dataclasses import InitVar
     from typing import List
@@ -564,8 +523,7 @@
         z: List[bool]
 
     A.__init__  #@
-    """
-    )
+    """)
     init = next(node.infer())
     assert [a.name for a in init.args.args] == ["self", "x", "y", "init_var", "z"]
     assert [a.as_string() if a else None for a in init.args.annotations] == [
@@ -582,8 +540,7 @@
     """Test that no init is generated when init=False is passed to
     dataclass decorator.
     """
-    node = astroid.extract_node(
-        f"""
+    node = astroid.extract_node(f"""
     from {module} import dataclass
     from typing import List
 
@@ -594,8 +551,7 @@
         z: List[bool]
 
     A.__init__ #@
-    """
-    )
+    """)
     init = next(node.infer())
     assert init._proxied.parent.name == "object"
 
@@ -605,8 +561,7 @@
     """Test init for a dataclass with attributes with a field value where init=False
     (these attributes should not be included in the initializer).
     """
-    node = astroid.extract_node(
-        f"""
+    node = astroid.extract_node(f"""
     from {module} import dataclass
     from dataclasses import field
     from typing import List
@@ -618,8 +573,7 @@
         z: List[bool] = field(init=False)
 
     A.__init__  #@
-    """
-    )
+    """)
     init = next(node.infer())
     assert [a.name for a in init.args.args] == ["self", "x", "y"]
     assert [a.as_string() if a else None for a in init.args.annotations] == [
@@ -635,8 +589,7 @@
 
     Based on https://github.com/pylint-dev/pylint/issues/3201
     """
-    node = astroid.extract_node(
-        f"""
+    node = astroid.extract_node(f"""
     from {module} import dataclass
     from typing import List
 
@@ -652,8 +605,7 @@
         arg2: str = None
 
     B.__init__  #@
-    """
-    )
+    """)
     init = next(node.infer())
     assert [a.name for a in init.args.args] == ["self", "arg1", "arg2"]
     assert [a.as_string() if a else None for a in init.args.annotations] == [
@@ -670,8 +622,7 @@
 
     Based on https://github.com/pylint-dev/pylint/issues/3201
     """
-    node = astroid.extract_node(
-        f"""
+    node = astroid.extract_node(f"""
     from {module} import dataclass
     from typing import List
 
@@ -686,8 +637,7 @@
         arg2: list  # Overrides arg2 from A
 
     B.__init__  #@
-    """
-    )
+    """)
     init = next(node.infer())
     assert [a.name for a in init.args.args] == ["self", "arg0", "arg2", "arg1"]
     assert [a.as_string() if a else None for a in init.args.annotations] == [
@@ -703,8 +653,7 @@
     """Test that astroid doesn't generate an initializer when attribute order is
     invalid.
     """
-    node = astroid.extract_node(
-        f"""
+    node = astroid.extract_node(f"""
     from {module} import dataclass
 
     @dataclass
@@ -713,8 +662,7 @@
         arg2: str
 
     A.__init__  #@
-    """
-    )
+    """)
     init = next(node.infer())
     assert init._proxied.parent.name == "object"
 
@@ -724,16 +672,14 @@
     """Test inference of dataclass attribute with a field call in another function
     call.
     """
-    node = astroid.extract_node(
-        f"""
+    node = astroid.extract_node(f"""
     from {module} import dataclass, field
     from typing import cast
 
     @dataclass
     class A:
         attribute: int = cast(int, field(default_factory=dict))
-    """
-    )
+    """)
     inferred = node.inferred()
     assert len(inferred) == 1 and isinstance(inferred[0], nodes.ClassDef)
     assert "attribute" in inferred[0].instance_attrs
@@ -743,15 +689,13 @@
 @parametrize_module
 def test_invalid_field_call(module: str) -> None:
     """Test inference of invalid field call doesn't crash."""
-    code = astroid.extract_node(
-        f"""
+    code = astroid.extract_node(f"""
     from {module} import dataclass, field
 
     @dataclass
     class A:
         val: field()
-    """
-    )
+    """)
     inferred = code.inferred()
     assert len(inferred) == 1
     assert isinstance(inferred[0], nodes.ClassDef)
@@ -760,8 +704,7 @@
 
 def test_non_dataclass_is_not_dataclass() -> None:
     """Test that something that isn't a dataclass has the correct attribute."""
-    module = astroid.parse(
-        """
+    module = astroid.parse("""
     class A:
         val: field()
 
@@ -771,8 +714,7 @@
     @dataclass
     class B:
         val: field()
-    """
-    )
+    """)
     class_a = module.body[0].inferred()
     assert len(class_a) == 1
     assert isinstance(class_a[0], nodes.ClassDef)
@@ -786,8 +728,7 @@
 
 def test_kw_only_sentinel() -> None:
     """Test that the KW_ONLY sentinel doesn't get added to the fields."""
-    node_one, node_two = astroid.extract_node(
-        """
+    node_one, node_two = astroid.extract_node("""
     from dataclasses import dataclass, KW_ONLY
     from dataclasses import KW_ONLY as keyword_only
 
@@ -804,12 +745,8 @@
         y: str
 
     B.__init__  #@
-    """
-    )
-    if PY310_PLUS:
-        expected = ["self", "y"]
-    else:
-        expected = ["self", "_", "y"]
+    """)
+    expected = ["self", "y"]
     init = next(node_one.infer())
     assert [a.name for a in init.args.args] == expected
 
@@ -818,12 +755,8 @@
 
 
 def test_kw_only_decorator() -> None:
-    """Test that we update the signature correctly based on the keyword.
-
-    kw_only was introduced in PY310.
-    """
-    foodef, bardef, cee, dee = astroid.extract_node(
-        """
+    """Test that we update the signature correctly based on the keyword."""
+    foodef, bardef, cee, dee = astroid.extract_node("""
     from dataclasses import dataclass
 
     @dataclass(kw_only=True)
@@ -851,54 +784,29 @@
     Bar.__init__  #@
     Cee.__init__  #@
     Dee.__init__  #@
-    """
-    )
+    """)
 
     foo_init: bases.UnboundMethod = next(foodef.infer())
-    if PY310_PLUS:
-        assert [a.name for a in foo_init.args.args] == ["self"]
-        assert [a.name for a in foo_init.args.kwonlyargs] == ["a", "e"]
-    else:
-        assert [a.name for a in foo_init.args.args] == ["self", "a", "e"]
-        assert [a.name for a in foo_init.args.kwonlyargs] == []
+    assert [a.name for a in foo_init.args.args] == ["self"]
+    assert [a.name for a in foo_init.args.kwonlyargs] == ["a", "e"]
 
     bar_init: bases.UnboundMethod = next(bardef.infer())
-    if PY310_PLUS:
-        assert [a.name for a in bar_init.args.args] == ["self", "c"]
-        assert [a.name for a in bar_init.args.kwonlyargs] == ["a", "e"]
-    else:
-        assert [a.name for a in bar_init.args.args] == ["self", "a", "e", "c"]
-        assert [a.name for a in bar_init.args.kwonlyargs] == []
+    assert [a.name for a in bar_init.args.args] == ["self", "c"]
+    assert [a.name for a in bar_init.args.kwonlyargs] == ["a", "e"]
 
     cee_init: bases.UnboundMethod = next(cee.infer())
-    if PY310_PLUS:
-        assert [a.name for a in cee_init.args.args] == ["self", "c", "d"]
-        assert [a.name for a in cee_init.args.kwonlyargs] == ["a", "e"]
-    else:
-        assert [a.name for a in cee_init.args.args] == ["self", "a", "e", "c", "d"]
-        assert [a.name for a in cee_init.args.kwonlyargs] == []
+    assert [a.name for a in cee_init.args.args] == ["self", "c", "d"]
+    assert [a.name for a in cee_init.args.kwonlyargs] == ["a", "e"]
 
     dee_init: bases.UnboundMethod = next(dee.infer())
-    if PY310_PLUS:
-        assert [a.name for a in dee_init.args.args] == ["self", "c", "d"]
-        assert [a.name for a in dee_init.args.kwonlyargs] == ["a", "e", "ee"]
-    else:
-        assert [a.name for a in dee_init.args.args] == [
-            "self",
-            "a",
-            "e",
-            "c",
-            "d",
-            "ee",
-        ]
-        assert [a.name for a in dee_init.args.kwonlyargs] == []
+    assert [a.name for a in dee_init.args.args] == ["self", "c", "d"]
+    assert [a.name for a in dee_init.args.kwonlyargs] == ["a", "e", "ee"]
 
 
 def test_kw_only_in_field_call() -> None:
     """Test that keyword only fields get correctly put at the end of the __init__."""
 
-    first, second, third = astroid.extract_node(
-        """
+    first, second, third = astroid.extract_node("""
     from dataclasses import dataclass, field
 
     @dataclass
@@ -917,8 +825,7 @@
     Parent.__init__  #@
     Child.__init__ #@
     GrandChild.__init__ #@
-    """
-    )
+    """)
 
     first_init: bases.UnboundMethod = next(first.infer())
     assert [a.name for a in first_init.args.args] == ["self"]
@@ -942,8 +849,7 @@
 
     Reported in https://github.com/pylint-dev/pylint/issues/7418
     """
-    node = astroid.extract_node(
-        """
+    node = astroid.extract_node("""
     import dataclasses
 
     from unknown import Unknown
@@ -954,8 +860,7 @@
         pass
 
     MyDataclass()
-    """
-    )
+    """)
 
     assert next(node.infer())
 
@@ -965,8 +870,7 @@
 
     Reported in https://github.com/pylint-dev/pylint/issues/7422
     """
-    node = astroid.extract_node(
-        """
+    node = astroid.extract_node("""
     from dataclasses import dataclass, InitVar
 
 
@@ -977,8 +881,7 @@
         config: InitVar = None
 
     TestClass.__init__  #@
-    """
-    )
+    """)
 
     init_def: bases.UnboundMethod = next(node.infer())
     assert [a.name for a in init_def.args.args] == ["self", "config"]
@@ -989,8 +892,7 @@
 
     Reported in https://github.com/pylint-dev/pylint/issues/7425
     """
-    bad_node, good_node = astroid.extract_node(
-        """
+    bad_node, good_node = astroid.extract_node("""
     from dataclasses import dataclass
     from typing import Union
 
@@ -1013,8 +915,7 @@
         xyz: str = ""
 
     GoodExampleClass.__init__  #@
-    """
-    )
+    """)
 
     bad_init: bases.UnboundMethod = next(bad_node.infer())
     assert bad_init.args.defaults
@@ -1031,8 +932,7 @@
     Reported in https://github.com/pylint-dev/pylint/issues/7427
     Reported in https://github.com/pylint-dev/pylint/issues/7434
     """
-    first, second, overwritten, overwriting, mixed = astroid.extract_node(
-        """
+    first, second, overwritten, overwriting, mixed = astroid.extract_node("""
     from dataclasses import dataclass
 
     @dataclass
@@ -1080,8 +980,7 @@
     OverwrittenChild.__init__  #@
     OverwritingChild.__init__  #@
     ChildWithMixedParents.__init__  #@
-    """
-    )
+    """)
 
     first_init: bases.UnboundMethod = next(first.infer())
     assert [a.name for a in first_init.args.args] == ["self", "ef", "_abc", "ghi"]
@@ -1103,8 +1002,7 @@
     assert [a.name for a in mixed_init.args.args] == ["self", "_abc", "ghi"]
     assert [a.value for a in mixed_init.args.defaults] == [1, 3]
 
-    first = astroid.extract_node(
-        """
+    first = astroid.extract_node("""
     from dataclasses import dataclass
 
     @dataclass
@@ -1124,8 +1022,7 @@
         ...
 
     GrandChild.__init__  #@
-    """
-    )
+    """)
 
     first_init: bases.UnboundMethod = next(first.infer())
     assert [a.name for a in first_init.args.args] == ["self", "required", "optional"]
@@ -1142,8 +1039,7 @@
     Eventually it can be merged into test_dataclass_with_multiple_inheritance.
     """
 
-    impossible = astroid.extract_node(
-        """
+    impossible = astroid.extract_node("""
     from dataclasses import dataclass
 
     @dataclass
@@ -1167,16 +1063,14 @@
         ...
 
     ImpossibleGrandChild() #@
-    """
-    )
+    """)
 
     assert next(impossible.infer()) is Uninferable
 
 
 def test_dataclass_with_field_init_is_false() -> None:
     """When init=False it shouldn't end up in the __init__."""
-    first, second, second_child, third_child, third = astroid.extract_node(
-        """
+    first, second, second_child, third_child, third = astroid.extract_node("""
     from dataclasses import dataclass, field
 
 
@@ -1205,8 +1099,7 @@
     SecondChild.__init__  #@
     ThirdChild.__init__  #@
     Third.__init__  #@
-    """
-    )
+    """)
 
     first_init: bases.UnboundMethod = next(first.infer())
     assert [a.name for a in first_init.args.args] == ["self", "a"]
@@ -1234,8 +1127,7 @@
 
     Regression test against changes tested in test_dataclass_with_multiple_inheritance
     """
-    first, second, third = astroid.extract_node(
-        """
+    first, second, third = astroid.extract_node("""
     from dataclasses import dataclass
 
     @dataclass
@@ -1267,8 +1159,7 @@
     FirstChild.__init__  #@
     SecondChild.__init__  #@
     ThirdChild.__init__  #@
-    """
-    )
+    """)
 
     first_init: bases.UnboundMethod = next(first.infer())
     assert [a.name for a in first_init.args.args] == ["self", "_abc"]
@@ -1285,8 +1176,7 @@
 
 def test_dataclass_with_properties() -> None:
     """Tests for __init__ creation for dataclasses that use properties."""
-    first, second, third = astroid.extract_node(
-        """
+    first, second, third = astroid.extract_node("""
     from dataclasses import dataclass
 
     @dataclass
@@ -1311,8 +1201,7 @@
     Dataclass.__init__  #@
     ParentOne.__init__  #@
     ParentTwo.__init__  #@
-    """
-    )
+    """)
 
     first_init: bases.UnboundMethod = next(first.infer())
     assert [a.name for a in first_init.args.args] == ["self", "attr"]
@@ -1326,8 +1215,7 @@
     assert [a.name for a in third_init.args.args] == ["self", "attr"]
     assert [a.value for a in third_init.args.defaults] == [1]
 
-    fourth = astroid.extract_node(
-        """
+    fourth = astroid.extract_node("""
     from dataclasses import dataclass
 
     @dataclass
@@ -1344,9 +1232,78 @@
             pass
 
     Dataclass.__init__  #@
-    """
-    )
+    """)
 
     fourth_init: bases.UnboundMethod = next(fourth.infer())
     assert [a.name for a in fourth_init.args.args] == ["self", "other_attr", "attr"]
     assert [a.name for a in fourth_init.args.defaults] == ["Uninferable"]
+
+
+def test_dataclass_with_duplicate_bases_no_crash():
+    """Regression test for https://github.com/pylint-dev/astroid/issues/2628.
+
+    A dataclass inheriting from a class with duplicate bases in MRO
+    (e.g., Protocol appearing both directly and indirectly) should not
+    crash with DuplicateBasesError during AST transformation.
+    """
+    code = """
+    import dataclasses
+    from typing import TypeVar, Protocol
+
+    BaseT = TypeVar("BaseT")
+    T = TypeVar("T", bound=BaseT)
+
+    class ConfigBase(Protocol[BaseT]):
+        ...
+
+    class Config(ConfigBase[T], Protocol[T]):
+        ...
+
+    @dataclasses.dataclass
+    class DatasetConfig(Config[T]):
+        name: str = "default"
+
+    DatasetConfig.__init__  #@
+    """
+    node = astroid.extract_node(code)
+    # Should not raise DuplicateBasesError — graceful degradation instead
+    inferred = next(node.infer())
+    assert inferred is not None
+
+
+def test_dataclass_with_duplicate_bases_field_default():
+    """Regression test for _get_previous_field_default with broken MRO.
+
+    When a parent dataclass defines a field with a default and a child (with
+    duplicate bases in its MRO) re-annotates that field without a value,
+    _get_previous_field_default should not crash with DuplicateBasesError.
+
+    See https://github.com/pylint-dev/astroid/issues/2628.
+    """
+    code = """
+    import dataclasses
+    from typing import TypeVar, Protocol
+
+    BaseT = TypeVar("BaseT")
+    T = TypeVar("T", bound=BaseT)
+
+    class ConfigBase(Protocol[BaseT]):
+        ...
+
+    class Config(ConfigBase[T], Protocol[T]):
+        ...
+
+    @dataclasses.dataclass
+    class BaseConfig(Config[T]):
+        name: str = "default"
+
+    @dataclasses.dataclass
+    class ChildConfig(BaseConfig[T]):
+        name: str
+
+    ChildConfig.__init__  #@
+    """
+    node = astroid.extract_node(code)
+    # Should not raise DuplicateBasesError in _get_previous_field_default
+    inferred = next(node.infer())
+    assert inferred is not None
diff --git a/tests/brain/test_dateutil.py b/tests/brain/test_dateutil.py
index 68cf640..5a7ced2 100644
--- a/tests/brain/test_dateutil.py
+++ b/tests/brain/test_dateutil.py
@@ -19,11 +19,9 @@
 @unittest.skipUnless(HAS_DATEUTIL, "This test requires the dateutil library.")
 class DateutilBrainTest(unittest.TestCase):
     def test_parser(self):
-        module = builder.parse(
-            """
+        module = builder.parse("""
         from dateutil.parser import parse
         d = parse('2000-01-01')
-        """
-        )
+        """)
         d_type = next(module["d"].infer())
         self.assertIn(d_type.qname(), {"_pydatetime.datetime", "datetime.datetime"})
diff --git a/tests/brain/test_enum.py b/tests/brain/test_enum.py
index 127b3ed..7c9afee 100644
--- a/tests/brain/test_enum.py
+++ b/tests/brain/test_enum.py
@@ -15,8 +15,7 @@
 
 class EnumBrainTest(unittest.TestCase):
     def test_simple_enum(self) -> None:
-        module = builder.parse(
-            """
+        module = builder.parse("""
         import enum
 
         class MyEnum(enum.Enum):
@@ -26,8 +25,7 @@
             def mymethod(self, x):
                 return 5
 
-        """
-        )
+        """)
 
         enumeration = next(module["MyEnum"].infer())
         one = enumeration["one"]
@@ -38,26 +36,23 @@
             self.assertIn("builtins.property", prop.decoratornames())
 
         meth = one.getattr("mymethod")[0]
-        self.assertIsInstance(meth, astroid.FunctionDef)
+        self.assertIsInstance(meth, nodes.FunctionDef)
 
     def test_looks_like_enum_false_positive(self) -> None:
         # Test that a class named Enumeration is not considered a builtin enum.
-        module = builder.parse(
-            """
+        module = builder.parse("""
         class Enumeration(object):
             def __init__(self, name, enum_list):
                 pass
             test = 42
-        """
-        )
+        """)
         enumeration = module["Enumeration"]
         test = next(enumeration.igetattr("test"))
         self.assertEqual(test.value, 42)
 
     def test_user_enum_false_positive(self) -> None:
         # Test that a user-defined class named Enum is not considered a builtin enum.
-        ast_node = astroid.extract_node(
-            """
+        ast_node = astroid.extract_node("""
         class Enum:
             pass
 
@@ -65,12 +60,11 @@
             red = 1
 
         Color.red #@
-        """
-        )
+        """)
         assert isinstance(ast_node, nodes.NodeNG)
         inferred = ast_node.inferred()
         self.assertEqual(len(inferred), 1)
-        self.assertIsInstance(inferred[0], astroid.Const)
+        self.assertIsInstance(inferred[0], nodes.Const)
         self.assertEqual(inferred[0].value, 1)
 
     def test_ignores_with_nodes_from_body_of_enum(self) -> None:
@@ -89,8 +83,7 @@
         assert len(inferred.locals["err"]) == 1
 
     def test_enum_multiple_base_classes(self) -> None:
-        module = builder.parse(
-            """
+        module = builder.parse("""
         import enum
 
         class Mixin:
@@ -98,8 +91,7 @@
 
         class MyEnum(Mixin, enum.Enum):
             one = 1
-        """
-        )
+        """)
         enumeration = next(module["MyEnum"].infer())
         one = enumeration["one"]
 
@@ -110,14 +102,12 @@
         )
 
     def test_int_enum(self) -> None:
-        module = builder.parse(
-            """
+        module = builder.parse("""
         import enum
 
         class MyEnum(enum.IntEnum):
             one = 1
-        """
-        )
+        """)
 
         enumeration = next(module["MyEnum"].infer())
         one = enumeration["one"]
@@ -129,14 +119,12 @@
         )
 
     def test_enum_func_form_is_class_not_instance(self) -> None:
-        cls, instance = builder.extract_node(
-            """
+        cls, instance = builder.extract_node("""
         from enum import Enum
         f = Enum('Audience', ['a', 'b', 'c'])
         f #@
         f(1) #@
-        """
-        )
+        """)
         inferred_cls = next(cls.infer())
         self.assertIsInstance(inferred_cls, bases.Instance)
         inferred_instance = next(instance.infer())
@@ -145,94 +133,81 @@
         self.assertIsInstance(next(inferred_instance.igetattr("value")), nodes.Const)
 
     def test_enum_func_form_iterable(self) -> None:
-        instance = builder.extract_node(
-            """
+        instance = builder.extract_node("""
         from enum import Enum
         Animal = Enum('Animal', 'ant bee cat dog')
         Animal
-        """
-        )
+        """)
         inferred = next(instance.infer())
         self.assertIsInstance(inferred, astroid.Instance)
         self.assertTrue(inferred.getattr("__iter__"))
 
     def test_enum_func_form_subscriptable(self) -> None:
-        instance, name = builder.extract_node(
-            """
+        instance, name = builder.extract_node("""
         from enum import Enum
         Animal = Enum('Animal', 'ant bee cat dog')
         Animal['ant'] #@
         Animal['ant'].name #@
-        """
-        )
+        """)
         instance = next(instance.infer())
         self.assertIsInstance(instance, astroid.Instance)
 
         inferred = next(name.infer())
-        self.assertIsInstance(inferred, astroid.Const)
+        self.assertIsInstance(inferred, nodes.Const)
 
     def test_enum_func_form_has_dunder_members(self) -> None:
-        instance = builder.extract_node(
-            """
+        instance = builder.extract_node("""
         from enum import Enum
         Animal = Enum('Animal', 'ant bee cat dog')
         for i in Animal.__members__:
             i #@
-        """
-        )
+        """)
         instance = next(instance.infer())
-        self.assertIsInstance(instance, astroid.Const)
+        self.assertIsInstance(instance, nodes.Const)
         self.assertIsInstance(instance.value, str)
 
     def test_infer_enum_value_as_the_right_type(self) -> None:
-        string_value, int_value = builder.extract_node(
-            """
+        string_value, int_value = builder.extract_node("""
         from enum import Enum
         class A(Enum):
             a = 'a'
             b = 1
         A.a.value #@
         A.b.value #@
-        """
-        )
+        """)
         inferred_string = string_value.inferred()
         assert any(
-            isinstance(elem, astroid.Const) and elem.value == "a"
+            isinstance(elem, nodes.Const) and elem.value == "a"
             for elem in inferred_string
         )
 
         inferred_int = int_value.inferred()
         assert any(
-            isinstance(elem, astroid.Const) and elem.value == 1 for elem in inferred_int
+            isinstance(elem, nodes.Const) and elem.value == 1 for elem in inferred_int
         )
 
     def test_mingled_single_and_double_quotes_does_not_crash(self) -> None:
-        node = builder.extract_node(
-            """
+        node = builder.extract_node("""
         from enum import Enum
         class A(Enum):
             a = 'x"y"'
         A.a.value #@
-        """
-        )
+        """)
         inferred_string = next(node.infer())
         assert inferred_string.value == 'x"y"'
 
     def test_special_characters_does_not_crash(self) -> None:
-        node = builder.extract_node(
-            """
+        node = builder.extract_node("""
         import enum
         class Example(enum.Enum):
             NULL = '\\N{NULL}'
         Example.NULL.value
-        """
-        )
+        """)
         inferred_string = next(node.infer())
         assert inferred_string.value == "\N{NULL}"
 
     def test_dont_crash_on_for_loops_in_body(self) -> None:
-        node = builder.extract_node(
-            """
+        node = builder.extract_node("""
 
         class Commands(IntEnum):
             _ignore_ = 'Commands index'
@@ -244,14 +219,12 @@
                 Commands[f'DC{index + 1}'] = 0x11 + index, f'Device Control {index + 1}'
 
         Commands
-        """
-        )
+        """)
         inferred = next(node.infer())
-        assert isinstance(inferred, astroid.ClassDef)
+        assert isinstance(inferred, nodes.ClassDef)
 
     def test_enum_tuple_list_values(self) -> None:
-        tuple_node, list_node = builder.extract_node(
-            """
+        tuple_node, list_node = builder.extract_node("""
         import enum
 
         class MyEnum(enum.Enum):
@@ -259,12 +232,11 @@
             b = [2, 4]
         MyEnum.a.value #@
         MyEnum.b.value #@
-        """
-        )
+        """)
         inferred_tuple_node = next(tuple_node.infer())
         inferred_list_node = next(list_node.infer())
-        assert isinstance(inferred_tuple_node, astroid.Tuple)
-        assert isinstance(inferred_list_node, astroid.List)
+        assert isinstance(inferred_tuple_node, nodes.Tuple)
+        assert isinstance(inferred_list_node, nodes.List)
         assert inferred_tuple_node.as_string() == "(1, 2)"
         assert inferred_list_node.as_string() == "[2, 4]"
 
@@ -345,8 +317,7 @@
         assert inferred.pytype() == ".TrickyEnum.value"
 
     def test_enum_subclass_member_name(self) -> None:
-        ast_node = astroid.extract_node(
-            """
+        ast_node = astroid.extract_node("""
         from enum import Enum
 
         class EnumSubclass(Enum):
@@ -356,17 +327,15 @@
             red = 1
 
         Color.red.name #@
-        """
-        )
+        """)
         assert isinstance(ast_node, nodes.NodeNG)
         inferred = ast_node.inferred()
         self.assertEqual(len(inferred), 1)
-        self.assertIsInstance(inferred[0], astroid.Const)
+        self.assertIsInstance(inferred[0], nodes.Const)
         self.assertEqual(inferred[0].value, "red")
 
     def test_enum_subclass_member_value(self) -> None:
-        ast_node = astroid.extract_node(
-            """
+        ast_node = astroid.extract_node("""
         from enum import Enum
 
         class EnumSubclass(Enum):
@@ -376,18 +345,16 @@
             red = 1
 
         Color.red.value #@
-        """
-        )
+        """)
         assert isinstance(ast_node, nodes.NodeNG)
         inferred = ast_node.inferred()
         self.assertEqual(len(inferred), 1)
-        self.assertIsInstance(inferred[0], astroid.Const)
+        self.assertIsInstance(inferred[0], nodes.Const)
         self.assertEqual(inferred[0].value, 1)
 
     def test_enum_subclass_member_method(self) -> None:
         # See Pylint issue #2626
-        ast_node = astroid.extract_node(
-            """
+        ast_node = astroid.extract_node("""
         from enum import Enum
 
         class EnumSubclass(Enum):
@@ -398,12 +365,11 @@
             red = 1
 
         Color.red.hello_pylint()  #@
-        """
-        )
+        """)
         assert isinstance(ast_node, nodes.NodeNG)
         inferred = ast_node.inferred()
         self.assertEqual(len(inferred), 1)
-        self.assertIsInstance(inferred[0], astroid.Const)
+        self.assertIsInstance(inferred[0], nodes.Const)
         self.assertEqual(inferred[0].value, "red")
 
     def test_enum_subclass_different_modules(self) -> None:
@@ -417,47 +383,41 @@
         """,
             "a",
         )
-        ast_node = astroid.extract_node(
-            """
+        ast_node = astroid.extract_node("""
         from a import EnumSubclass
 
         class Color(EnumSubclass):
             red = 1
 
         Color.red.value #@
-        """
-        )
+        """)
         assert isinstance(ast_node, nodes.NodeNG)
         inferred = ast_node.inferred()
         self.assertEqual(len(inferred), 1)
-        self.assertIsInstance(inferred[0], astroid.Const)
+        self.assertIsInstance(inferred[0], nodes.Const)
         self.assertEqual(inferred[0].value, 1)
 
     def test_members_member_ignored(self) -> None:
-        ast_node = builder.extract_node(
-            """
+        ast_node = builder.extract_node("""
         from enum import Enum
         class Animal(Enum):
             a = 1
             __members__ = {}
         Animal.__members__ #@
-        """
-        )
+        """)
 
         inferred = next(ast_node.infer())
-        self.assertIsInstance(inferred, astroid.Dict)
+        self.assertIsInstance(inferred, nodes.Dict)
         self.assertTrue(inferred.locals)
 
     def test_enum_as_renamed_import(self) -> None:
         """Originally reported in https://github.com/pylint-dev/pylint/issues/5776."""
-        ast_node: nodes.Attribute = builder.extract_node(
-            """
+        ast_node: nodes.Attribute = builder.extract_node("""
         from enum import Enum as PyEnum
         class MyEnum(PyEnum):
             ENUM_KEY = "enum_value"
         MyEnum.ENUM_KEY
-        """
-        )
+        """)
         inferred = next(ast_node.infer())
         assert isinstance(inferred, bases.Instance)
         assert inferred._proxied.name == "ENUM_KEY"
@@ -476,21 +436,17 @@
             "module_with_class_named_enum",
         )
 
-        attribute_nodes = astroid.extract_node(
-            """
+        attribute_nodes = astroid.extract_node("""
         import module_with_class_named_enum
         module_with_class_named_enum.Enum("apple", "orange") #@
         typo_module_with_class_named_enum.Enum("apple", "orange") #@
-        """
-        )
+        """)
 
-        name_nodes = astroid.extract_node(
-            """
+        name_nodes = astroid.extract_node("""
         from module_with_class_named_enum import Enum
         Enum("apple", "orange") #@
         TypoEnum("apple", "orange") #@
-        """
-        )
+        """)
 
         # Test that both of the successfully inferred `Name` & `Attribute`
         # nodes refer to the user-defined Enum class.
@@ -513,8 +469,7 @@
         Test that only enum members `MARS` and `radius` appear in the `__members__` container while
         the attribute `mass` does not.
         """
-        enum_class = astroid.extract_node(
-            """
+        enum_class = astroid.extract_node("""
         from enum import Enum
         class Planet(Enum): #@
             MARS = (1, 2)
@@ -526,8 +481,7 @@
                 self.radius = radius
 
         Planet.MARS.value
-        """
-        )
+        """)
         enum_members = next(enum_class.igetattr("__members__"))
         assert len(enum_members.items) == 2
         mars, radius = enum_members.items
@@ -540,8 +494,7 @@
         Test that a user-defined enum class is inferred when it subclasses
         another user-defined enum class.
         """
-        enum_class_node, enum_member_value_node = astroid.extract_node(
-            """
+        enum_class_node, enum_member_value_node = astroid.extract_node("""
         import sys
 
         from enum import Enum
@@ -558,8 +511,7 @@
 
 
         Color.RED.value #@
-        """
-        )
+        """)
         assert "RED" in enum_class_node.locals
 
         enum_members = enum_class_node.locals["__members__"][0].items
@@ -575,8 +527,7 @@
         Originally reported in https://github.com/pylint-dev/pylint/issues/9015
         """
 
-        ast_node: nodes.Attribute = builder.extract_node(
-            """
+        ast_node: nodes.Attribute = builder.extract_node("""
         import enum
 
 
@@ -586,8 +537,7 @@
             _ignore_ = ["BAZ"]
             BAZ = 42
         MyEnum.__members__
-        """
-        )
+        """)
         inferred = next(ast_node.infer())
         members_names = [const_node.value for const_node, name_obj in inferred.items]
         assert members_names == ["FOO", "BAR", "BAZ"]
@@ -595,8 +545,7 @@
     def test_enum_sunder_names(self) -> None:
         """Test that both `_name_` and `_value_` sunder names exist"""
 
-        sunder_name, sunder_value = builder.extract_node(
-            """
+        sunder_name, sunder_value = builder.extract_node("""
         import enum
 
 
@@ -604,8 +553,7 @@
             APPLE = 42
         MyEnum.APPLE._name_ #@
         MyEnum.APPLE._value_ #@
-        """
-        )
+        """)
         inferred_name = next(sunder_name.infer())
         assert inferred_name.value == "APPLE"
 
diff --git a/tests/brain/test_gi.py b/tests/brain/test_gi.py
new file mode 100644
index 0000000..67ee2e4
--- /dev/null
+++ b/tests/brain/test_gi.py
@@ -0,0 +1,57 @@
+# Licensed under the LGPL: https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html
+# For details: https://github.com/pylint-dev/astroid/blob/main/LICENSE
+# Copyright (c) https://github.com/pylint-dev/astroid/blob/main/CONTRIBUTORS.txt
+
+import unittest
+
+try:
+    import gi  # pylint: disable=unused-import
+
+    HAS_GI = True
+except ImportError:
+    HAS_GI = False
+
+from astroid import builder, nodes
+
+
+@unittest.skipUnless(HAS_GI, "This test requires the gobject introspection library.")
+class GiBrainClassificationTest(unittest.TestCase):
+    """Test that gi functions are correctly classified."""
+
+    def _inferred_gi_symbol(self, namespace, version, symbol):
+        node = builder.extract_node(f"""
+        import gi
+
+        gi.require_version("{namespace}", "{version}")
+        from gi.repository import {namespace}
+        {namespace}.{symbol}
+        """)
+        return node.inferred()
+
+    def test_gi_function_classification(self):
+        """Test that global functions are correctly classified without the 'self' argument."""
+        inferred = self._inferred_gi_symbol("GLib", "2.0", "get_tmp_dir")
+        self.assertEqual(len(inferred), 1)
+        self.assertEqual(inferred[0].pytype(), "builtins.function")
+
+        funcdef = inferred[0].frame()
+        self.assertIsInstance(funcdef, nodes.FunctionDef)
+
+        args = funcdef.argnames()
+        if len(args) > 0:
+            self.assertNotEqual(args[0], "self")
+
+    def test_gi_method_classification(self):
+        """Test that methods are correctly classified and accept the 'self' argument."""
+        inferred = self._inferred_gi_symbol("GLib", "2.0", "String.append")
+        self.assertEqual(len(inferred), 1)
+        self.assertEqual(inferred[0].pytype(), "builtins.instancemethod")
+
+        funcdef = inferred[0].frame()
+        self.assertIsInstance(funcdef, nodes.FunctionDef)
+
+        self.assertIn(
+            funcdef.argnames()[0],
+            {"self", funcdef.args.vararg},
+            "Method does not accept 'self' as first argument",
+        )
diff --git a/tests/brain/test_helpers.py b/tests/brain/test_helpers.py
new file mode 100644
index 0000000..d30fd1d
--- /dev/null
+++ b/tests/brain/test_helpers.py
@@ -0,0 +1,85 @@
+# Licensed under the LGPL: https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html
+# For details: https://github.com/pylint-dev/astroid/blob/main/LICENSE
+# Copyright (c) https://github.com/pylint-dev/astroid/blob/main/CONTRIBUTORS.txt
+
+import pytest
+
+from astroid import extract_node, nodes
+from astroid.brain.helpers import is_class_var
+
+
+@pytest.mark.parametrize(
+    "code",
+    [
+        pytest.param(
+            """
+            from typing import ClassVar
+
+            foo: ClassVar[int]
+            """,
+            id="from-import",
+        ),
+        pytest.param(
+            """
+            from typing import ClassVar
+
+            foo: ClassVar
+            """,
+            id="bare-classvar",
+        ),
+        pytest.param(
+            """
+            import typing
+
+            foo: typing.ClassVar[int]
+            """,
+            id="module-import",
+        ),
+    ],
+)
+def test_is_class_var_returns_true(code):
+    node = extract_node(code)
+    assert isinstance(node, nodes.AnnAssign)
+    assert is_class_var(node.annotation)
+
+
+@pytest.mark.parametrize(
+    "code",
+    [
+        pytest.param(
+            """
+            from typing import Final
+
+            foo: Final[int]
+            """,
+            id="wrong-name",
+        ),
+        pytest.param(
+            """
+            from typing import ClassVar
+
+            foo: list[ClassVar[int]]
+            """,
+            id="classvar-not-outermost",
+        ),
+        pytest.param(
+            """
+            from typing import ClassVar
+            ClassVar = int
+
+            foo: ClassVar
+            """,
+            id="shadowed-name",
+        ),
+        pytest.param(
+            """
+            foo: ClassVar[int]
+            """,
+            id="missing-import",
+        ),
+    ],
+)
+def test_is_class_var_returns_false(code):
+    node = extract_node(code)
+    assert isinstance(node, nodes.AnnAssign)
+    assert not is_class_var(node.annotation)
diff --git a/tests/brain/test_multiprocessing.py b/tests/brain/test_multiprocessing.py
index e6a1da5..4160253 100644
--- a/tests/brain/test_multiprocessing.py
+++ b/tests/brain/test_multiprocessing.py
@@ -30,23 +30,19 @@
         # Test that module attributes are working,
         # especially on Python 3.4+, where they are obtained
         # from a context.
-        module = builder.extract_node(
-            """
+        module = builder.extract_node("""
         import multiprocessing
-        """
-        )
+        """)
         assert isinstance(module, nodes.Import)
         module = module.do_import_module("multiprocessing")
         cpu_count = next(module.igetattr("cpu_count"))
         self.assertIsInstance(cpu_count, astroid.BoundMethod)
 
     def test_module_name(self) -> None:
-        module = builder.extract_node(
-            """
+        module = builder.extract_node("""
         import multiprocessing
         multiprocessing.SyncManager()
-        """
-        )
+        """)
         inferred_sync_mgr = next(module.infer())
         module = inferred_sync_mgr.root()
         self.assertEqual(module.name, "multiprocessing.managers")
@@ -54,8 +50,7 @@
     def test_multiprocessing_manager(self) -> None:
         # Test that we have the proper attributes
         # for a multiprocessing.managers.SyncManager
-        module = builder.parse(
-            """
+        module = builder.parse("""
         import multiprocessing
         manager = multiprocessing.Manager()
         queue = manager.Queue()
@@ -72,8 +67,7 @@
         value = manager.Value()
         array = manager.Array()
         namespace = manager.Namespace()
-        """
-        )
+        """)
         ast_queue = next(module["queue"].infer())
         self.assertEqual(ast_queue.qname(), f"{queue.__name__}.Queue")
 
diff --git a/tests/brain/test_named_tuple.py b/tests/brain/test_named_tuple.py
index 40a96c7..b82dfa4 100644
--- a/tests/brain/test_named_tuple.py
+++ b/tests/brain/test_named_tuple.py
@@ -6,21 +6,18 @@
 
 import unittest
 
-import astroid
 from astroid import builder, nodes, util
 from astroid.exceptions import AttributeInferenceError
 
 
 class NamedTupleTest(unittest.TestCase):
     def test_namedtuple_base(self) -> None:
-        klass = builder.extract_node(
-            """
+        klass = builder.extract_node("""
         from collections import namedtuple
 
         class X(namedtuple("X", ["a", "b", "c"])):
            pass
-        """
-        )
+        """)
         assert isinstance(klass, nodes.ClassDef)
         self.assertEqual(
             [anc.name for anc in klass.ancestors()], ["X", "tuple", "object"]
@@ -31,41 +28,35 @@
             self.assertFalse(anc.parent is None)
 
     def test_namedtuple_inference(self) -> None:
-        klass = builder.extract_node(
-            """
+        klass = builder.extract_node("""
         from collections import namedtuple
 
         name = "X"
         fields = ["a", "b", "c"]
         class X(namedtuple(name, fields)):
            pass
-        """
-        )
+        """)
         assert isinstance(klass, nodes.ClassDef)
         base = next(base for base in klass.ancestors() if base.name == "X")
         self.assertSetEqual({"a", "b", "c"}, set(base.instance_attrs))
 
     def test_namedtuple_inference_failure(self) -> None:
-        klass = builder.extract_node(
-            """
+        klass = builder.extract_node("""
         from collections import namedtuple
 
         def foo(fields):
            return __(namedtuple("foo", fields))
-        """
-        )
+        """)
         self.assertIs(util.Uninferable, next(klass.infer()))
 
     def test_namedtuple_advanced_inference(self) -> None:
         # urlparse return an object of class ParseResult, which has a
         # namedtuple call and a mixin as base classes
-        result = builder.extract_node(
-            """
+        result = builder.extract_node("""
         from urllib.parse import urlparse
 
         result = __(urlparse('gopher://'))
-        """
-        )
+        """)
         instance = next(result.infer())
         self.assertGreaterEqual(len(instance.getattr("scheme")), 1)
         self.assertGreaterEqual(len(instance.getattr("port")), 1)
@@ -75,86 +66,72 @@
         self.assertEqual(instance.name, "ParseResult")
 
     def test_namedtuple_instance_attrs(self) -> None:
-        result = builder.extract_node(
-            """
+        result = builder.extract_node("""
         from collections import namedtuple
         namedtuple('a', 'a b c')(1, 2, 3) #@
-        """
-        )
+        """)
         inferred = next(result.infer())
         for name, attr in inferred.instance_attrs.items():
             self.assertEqual(attr[0].attrname, name)
 
     def test_namedtuple_uninferable_fields(self) -> None:
-        node = builder.extract_node(
-            """
+        node = builder.extract_node("""
         x = [A] * 2
         from collections import namedtuple
         l = namedtuple('a', x)
         l(1)
-        """
-        )
+        """)
         inferred = next(node.infer())
         self.assertIs(util.Uninferable, inferred)
 
     def test_namedtuple_access_class_fields(self) -> None:
-        node = builder.extract_node(
-            """
+        node = builder.extract_node("""
         from collections import namedtuple
         Tuple = namedtuple("Tuple", "field other")
         Tuple #@
-        """
-        )
+        """)
         inferred = next(node.infer())
         self.assertIn("field", inferred.locals)
         self.assertIn("other", inferred.locals)
 
     def test_namedtuple_rename_keywords(self) -> None:
-        node = builder.extract_node(
-            """
+        node = builder.extract_node("""
         from collections import namedtuple
         Tuple = namedtuple("Tuple", "abc def", rename=True)
         Tuple #@
-        """
-        )
+        """)
         inferred = next(node.infer())
         self.assertIn("abc", inferred.locals)
         self.assertIn("_1", inferred.locals)
 
     def test_namedtuple_rename_duplicates(self) -> None:
-        node = builder.extract_node(
-            """
+        node = builder.extract_node("""
         from collections import namedtuple
         Tuple = namedtuple("Tuple", "abc abc abc", rename=True)
         Tuple #@
-        """
-        )
+        """)
         inferred = next(node.infer())
         self.assertIn("abc", inferred.locals)
         self.assertIn("_1", inferred.locals)
         self.assertIn("_2", inferred.locals)
 
     def test_namedtuple_rename_uninferable(self) -> None:
-        node = builder.extract_node(
-            """
+        node = builder.extract_node("""
         from collections import namedtuple
         Tuple = namedtuple("Tuple", "a b c", rename=UNINFERABLE)
         Tuple #@
-        """
-        )
+        """)
         inferred = next(node.infer())
         self.assertIn("a", inferred.locals)
         self.assertIn("b", inferred.locals)
         self.assertIn("c", inferred.locals)
 
     def test_namedtuple_func_form(self) -> None:
-        node = builder.extract_node(
-            """
+        node = builder.extract_node("""
         from collections import namedtuple
         Tuple = namedtuple(typename="Tuple", field_names="a b c", rename=UNINFERABLE)
         Tuple #@
-        """
-        )
+        """)
         inferred = next(node.infer())
         self.assertEqual(inferred.name, "Tuple")
         self.assertIn("a", inferred.locals)
@@ -162,13 +139,11 @@
         self.assertIn("c", inferred.locals)
 
     def test_namedtuple_func_form_args_and_kwargs(self) -> None:
-        node = builder.extract_node(
-            """
+        node = builder.extract_node("""
         from collections import namedtuple
         Tuple = namedtuple("Tuple", field_names="a b c", rename=UNINFERABLE)
         Tuple #@
-        """
-        )
+        """)
         inferred = next(node.infer())
         self.assertEqual(inferred.name, "Tuple")
         self.assertIn("a", inferred.locals)
@@ -176,16 +151,14 @@
         self.assertIn("c", inferred.locals)
 
     def test_namedtuple_bases_are_actually_names_not_nodes(self) -> None:
-        node = builder.extract_node(
-            """
+        node = builder.extract_node("""
         from collections import namedtuple
         Tuple = namedtuple("Tuple", field_names="a b c", rename=UNINFERABLE)
         Tuple #@
-        """
-        )
+        """)
         inferred = next(node.infer())
-        self.assertIsInstance(inferred, astroid.ClassDef)
-        self.assertIsInstance(inferred.bases[0], astroid.Name)
+        self.assertIsInstance(inferred, nodes.ClassDef)
+        self.assertIsInstance(inferred.bases[0], nodes.Name)
         self.assertEqual(inferred.bases[0].name, "tuple")
 
     def test_invalid_label_does_not_crash_inference(self) -> None:
@@ -196,113 +169,95 @@
         """
         node = builder.extract_node(code)
         inferred = next(node.infer())
-        assert isinstance(inferred, astroid.ClassDef)
+        assert isinstance(inferred, nodes.ClassDef)
         assert "b" not in inferred.locals
         assert "c" not in inferred.locals
 
     def test_no_rename_duplicates_does_not_crash_inference(self) -> None:
-        node = builder.extract_node(
-            """
+        node = builder.extract_node("""
         from collections import namedtuple
         Tuple = namedtuple("Tuple", "abc abc")
         Tuple #@
-        """
-        )
+        """)
         inferred = next(node.infer())
         self.assertIs(util.Uninferable, inferred)  # would raise ValueError
 
     def test_no_rename_keywords_does_not_crash_inference(self) -> None:
-        node = builder.extract_node(
-            """
+        node = builder.extract_node("""
         from collections import namedtuple
         Tuple = namedtuple("Tuple", "abc def")
         Tuple #@
-        """
-        )
+        """)
         inferred = next(node.infer())
         self.assertIs(util.Uninferable, inferred)  # would raise ValueError
 
     def test_no_rename_nonident_does_not_crash_inference(self) -> None:
-        node = builder.extract_node(
-            """
+        node = builder.extract_node("""
         from collections import namedtuple
         Tuple = namedtuple("Tuple", "123 456")
         Tuple #@
-        """
-        )
+        """)
         inferred = next(node.infer())
         self.assertIs(util.Uninferable, inferred)  # would raise ValueError
 
     def test_no_rename_underscore_does_not_crash_inference(self) -> None:
-        node = builder.extract_node(
-            """
+        node = builder.extract_node("""
         from collections import namedtuple
         Tuple = namedtuple("Tuple", "_1")
         Tuple #@
-        """
-        )
+        """)
         inferred = next(node.infer())
         self.assertIs(util.Uninferable, inferred)  # would raise ValueError
 
     def test_invalid_typename_does_not_crash_inference(self) -> None:
-        node = builder.extract_node(
-            """
+        node = builder.extract_node("""
         from collections import namedtuple
         Tuple = namedtuple("123", "abc")
         Tuple #@
-        """
-        )
+        """)
         inferred = next(node.infer())
         self.assertIs(util.Uninferable, inferred)  # would raise ValueError
 
     def test_keyword_typename_does_not_crash_inference(self) -> None:
-        node = builder.extract_node(
-            """
+        node = builder.extract_node("""
         from collections import namedtuple
         Tuple = namedtuple("while", "abc")
         Tuple #@
-        """
-        )
+        """)
         inferred = next(node.infer())
         self.assertIs(util.Uninferable, inferred)  # would raise ValueError
 
     def test_typeerror_does_not_crash_inference(self) -> None:
-        node = builder.extract_node(
-            """
+        node = builder.extract_node("""
         from collections import namedtuple
         Tuple = namedtuple("Tuple", [123, 456])
         Tuple #@
-        """
-        )
+        """)
         inferred = next(node.infer())
         # namedtuple converts all arguments to strings so these should be too
         # and catch on the isidentifier() check
         self.assertIs(util.Uninferable, inferred)
 
     def test_pathological_str_does_not_crash_inference(self) -> None:
-        node = builder.extract_node(
-            """
+        node = builder.extract_node("""
         from collections import namedtuple
         class Invalid:
             def __str__(self):
                 return 123  # will raise TypeError
         Tuple = namedtuple("Tuple", [Invalid()])
         Tuple #@
-        """
-        )
+        """)
         inferred = next(node.infer())
         self.assertIs(util.Uninferable, inferred)
 
     def test_name_as_typename(self) -> None:
         """Reported in https://github.com/pylint-dev/pylint/issues/7429 as a crash."""
-        good_node, good_node_two, bad_node = builder.extract_node(
-            """
+        good_node, good_node_two, bad_node = builder.extract_node("""
             import collections
             collections.namedtuple(typename="MyTuple", field_names=["birth_date", "city"])  #@
             collections.namedtuple("MyTuple", field_names=["birth_date", "city"])  #@
             collections.namedtuple(["birth_date", "city"], typename="MyTuple")  #@
-        """
-        )
+        """)
         good_inferred = next(good_node.infer())
         assert isinstance(good_inferred, nodes.ClassDef)
         good_node_two_inferred = next(good_node_two.infer())
diff --git a/tests/brain/test_nose.py b/tests/brain/test_nose.py
deleted file mode 100644
index 2b615c1..0000000
--- a/tests/brain/test_nose.py
+++ /dev/null
@@ -1,45 +0,0 @@
-# Licensed under the LGPL: https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html
-# For details: https://github.com/pylint-dev/astroid/blob/main/LICENSE
-# Copyright (c) https://github.com/pylint-dev/astroid/blob/main/CONTRIBUTORS.txt
-
-from __future__ import annotations
-
-import unittest
-import warnings
-
-import astroid
-from astroid import builder
-
-try:
-    with warnings.catch_warnings():
-        warnings.simplefilter("ignore", DeprecationWarning)
-        import nose  # pylint: disable=unused-import
-    HAS_NOSE = True
-except ImportError:
-    HAS_NOSE = False
-
-
-@unittest.skipUnless(HAS_NOSE, "This test requires nose library.")
-class NoseBrainTest(unittest.TestCase):
-    def test_nose_tools(self):
-        methods = builder.extract_node(
-            """
-        from nose.tools import assert_equal
-        from nose.tools import assert_equals
-        from nose.tools import assert_true
-        assert_equal = assert_equal #@
-        assert_true = assert_true #@
-        assert_equals = assert_equals #@
-        """
-        )
-        assert isinstance(methods, list)
-        assert_equal = next(methods[0].value.infer())
-        assert_true = next(methods[1].value.infer())
-        assert_equals = next(methods[2].value.infer())
-
-        self.assertIsInstance(assert_equal, astroid.BoundMethod)
-        self.assertIsInstance(assert_true, astroid.BoundMethod)
-        self.assertIsInstance(assert_equals, astroid.BoundMethod)
-        self.assertEqual(assert_equal.qname(), "unittest.case.TestCase.assertEqual")
-        self.assertEqual(assert_true.qname(), "unittest.case.TestCase.assertTrue")
-        self.assertEqual(assert_equals.qname(), "unittest.case.TestCase.assertEqual")
diff --git a/tests/brain/test_pathlib.py b/tests/brain/test_pathlib.py
index 5aea8d3..3715ff1 100644
--- a/tests/brain/test_pathlib.py
+++ b/tests/brain/test_pathlib.py
@@ -5,25 +5,23 @@
 
 import astroid
 from astroid import bases
-from astroid.const import PY310_PLUS, PY313_PLUS
+from astroid.const import PY313
 from astroid.util import Uninferable
 
 
 def test_inference_parents() -> None:
     """Test inference of ``pathlib.Path.parents``."""
-    name_node = astroid.extract_node(
-        """
+    name_node = astroid.extract_node("""
     from pathlib import Path
 
     current_path = Path().resolve()
     path_parents = current_path.parents
     path_parents
-    """
-    )
+    """)
     inferred = name_node.inferred()
     assert len(inferred) == 1
     assert isinstance(inferred[0], bases.Instance)
-    if PY313_PLUS:
+    if PY313:
         assert inferred[0].qname() == "builtins.tuple"
     else:
         assert inferred[0].qname() == "pathlib._PathParents"
@@ -31,19 +29,17 @@
 
 def test_inference_parents_subscript_index() -> None:
     """Test inference of ``pathlib.Path.parents``, accessed by index."""
-    path = astroid.extract_node(
-        """
+    path = astroid.extract_node("""
     from pathlib import Path
 
     current_path = Path().resolve()
     current_path.parents[2]  #@
-    """
-    )
+    """)
 
     inferred = path.inferred()
     assert len(inferred) == 1
     assert isinstance(inferred[0], bases.Instance)
-    if PY313_PLUS:
+    if PY313:
         assert inferred[0].qname() == "pathlib._local.Path"
     else:
         assert inferred[0].qname() == "pathlib.Path"
@@ -51,36 +47,29 @@
 
 def test_inference_parents_subscript_slice() -> None:
     """Test inference of ``pathlib.Path.parents``, accessed by slice."""
-    name_node = astroid.extract_node(
-        """
+    name_node = astroid.extract_node("""
     from pathlib import Path
 
     current_path = Path().resolve()
     parent_path = current_path.parents[:2]
     parent_path
-    """
-    )
+    """)
     inferred = name_node.inferred()
     assert len(inferred) == 1
-    if PY310_PLUS:
-        assert isinstance(inferred[0], bases.Instance)
-        assert inferred[0].qname() == "builtins.tuple"
-    else:
-        assert inferred[0] is Uninferable
+    assert isinstance(inferred[0], bases.Instance)
+    assert inferred[0].qname() == "builtins.tuple"
 
 
 def test_inference_parents_subscript_not_path() -> None:
     """Test inference of other ``.parents`` subscripts is unaffected."""
-    name_node = astroid.extract_node(
-        """
+    name_node = astroid.extract_node("""
     class A:
         parents = 42
 
     c = A()
     error = c.parents[:2]
     error
-    """
-    )
+    """)
     inferred = name_node.inferred()
     assert len(inferred) == 1
     assert inferred[0] is Uninferable
diff --git a/tests/brain/test_pytest.py b/tests/brain/test_pytest.py
index a063f40..c448a30 100644
--- a/tests/brain/test_pytest.py
+++ b/tests/brain/test_pytest.py
@@ -8,12 +8,10 @@
 
 
 def test_pytest() -> None:
-    ast_node = builder.extract_node(
-        """
+    ast_node = builder.extract_node("""
     import pytest
     pytest #@
-    """
-    )
+    """)
     module = next(ast_node.infer())
     attrs = [
         "deprecated_call",
diff --git a/tests/brain/test_regex.py b/tests/brain/test_regex.py
index 1313ea4..bd38c81 100644
--- a/tests/brain/test_regex.py
+++ b/tests/brain/test_regex.py
@@ -29,22 +29,18 @@
     )
     def test_regex_pattern_and_match_subscriptable(self):
         """Test regex.Pattern and regex.Match are subscriptable in PY39+."""
-        node1 = builder.extract_node(
-            """
+        node1 = builder.extract_node("""
         import regex
         regex.Pattern[str]
-        """
-        )
+        """)
         inferred1 = next(node1.infer())
         assert isinstance(inferred1, nodes.ClassDef)
         assert isinstance(inferred1.getattr("__class_getitem__")[0], nodes.FunctionDef)
 
-        node2 = builder.extract_node(
-            """
+        node2 = builder.extract_node("""
         import regex
         regex.Match[str]
-        """
-        )
+        """)
         inferred2 = next(node2.infer())
         assert isinstance(inferred2, nodes.ClassDef)
         assert isinstance(inferred2.getattr("__class_getitem__")[0], nodes.FunctionDef)
diff --git a/tests/brain/test_signal.py b/tests/brain/test_signal.py
index a9d4e86..3a0033a 100644
--- a/tests/brain/test_signal.py
+++ b/tests/brain/test_signal.py
@@ -4,7 +4,6 @@
 
 """Unit Tests for the signal brain module."""
 
-
 import sys
 
 import pytest
@@ -21,12 +20,10 @@
 def test_enum(enum_name):
     """Tests that the signal module enums are handled by the brain."""
     # Extract node for signal module enum from code
-    node = builder.extract_node(
-        f"""
+    node = builder.extract_node(f"""
         import signal
         signal.{enum_name}
-        """
-    )
+        """)
 
     # Check the extracted node
     assert isinstance(node, nodes.NodeNG)
diff --git a/tests/brain/test_six.py b/tests/brain/test_six.py
index 45a40e5..71eea95 100644
--- a/tests/brain/test_six.py
+++ b/tests/brain/test_six.py
@@ -22,8 +22,7 @@
 @unittest.skipUnless(HAS_SIX, "These tests require the six library")
 class SixBrainTest(unittest.TestCase):
     def test_attribute_access(self) -> None:
-        ast_nodes = builder.extract_node(
-            """
+        ast_nodes = builder.extract_node("""
         import six
         six.moves.http_client #@
         six.moves.urllib_parse #@
@@ -31,8 +30,7 @@
         six.moves.urllib.request #@
         from six.moves import StringIO
         StringIO #@
-        """
-        )
+        """)
         assert isinstance(ast_nodes, list)
         http_client = next(ast_nodes[0].infer())
         self.assertIsInstance(http_client, nodes.Module)
@@ -79,12 +77,10 @@
         self.test_attribute_access()
 
     def test_from_imports(self) -> None:
-        ast_node = builder.extract_node(
-            """
+        ast_node = builder.extract_node("""
         from six.moves import http_client
         http_client.HTTPSConnection #@
-        """
-        )
+        """)
         inferred = next(ast_node.infer())
         self.assertIsInstance(inferred, nodes.ClassDef)
         qname = "http.client.HTTPSConnection"
@@ -95,18 +91,15 @@
 
         See pylint-dev/pylint#1640 for relevant issue
         """
-        ast_node = builder.extract_node(
-            """
+        ast_node = builder.extract_node("""
         from six.moves.urllib.parse import urlparse
         urlparse #@
-        """
-        )
+        """)
         inferred = next(ast_node.infer())
         self.assertIsInstance(inferred, nodes.FunctionDef)
 
     def test_with_metaclass_subclasses_inheritance(self) -> None:
-        ast_node = builder.extract_node(
-            """
+        ast_node = builder.extract_node("""
         class A(type):
             def test(cls):
                 return cls
@@ -119,8 +112,7 @@
             pass
 
         B #@
-        """
-        )
+        """)
         inferred = next(ast_node.infer())
         self.assertIsInstance(inferred, nodes.ClassDef)
         self.assertEqual(inferred.name, "B")
@@ -154,15 +146,13 @@
 
         MANAGER.register_transform(nodes.ClassDef, transform_class)
         try:
-            ast_node = builder.extract_node(
-                """
+            ast_node = builder.extract_node("""
                 import six
                 class A(six.with_metaclass(type, object)):
                     pass
 
                 A #@
-            """
-            )
+            """)
             inferred = next(ast_node.infer())
             assert getattr(inferred, "_test_transform", None) == 314
         finally:
diff --git a/tests/brain/test_ssl.py b/tests/brain/test_ssl.py
index 418c589..641f11e 100644
--- a/tests/brain/test_ssl.py
+++ b/tests/brain/test_ssl.py
@@ -12,15 +12,13 @@
 
 def test_ssl_brain() -> None:
     """Test ssl brain transform."""
-    module = parse(
-        """
+    module = parse("""
     import ssl
     ssl.PROTOCOL_TLSv1
     ssl.VerifyMode
     ssl.TLSVersion
     ssl.VerifyMode.CERT_REQUIRED
-    """
-    )
+    """)
     inferred_protocol = next(module.body[1].value.infer())
     assert isinstance(inferred_protocol, nodes.Const)
 
@@ -49,13 +47,11 @@
 @pytest.mark.skipif(not PY312_PLUS, reason="Uses new 3.12 constant")
 def test_ssl_brain_py312() -> None:
     """Test ssl brain transform."""
-    module = parse(
-        """
+    module = parse("""
     import ssl
     ssl.OP_LEGACY_SERVER_CONNECT
     ssl.Options.OP_LEGACY_SERVER_CONNECT
-    """
-    )
+    """)
 
     inferred_constant = next(module.body[1].value.infer())
     assert isinstance(inferred_constant, nodes.Const)
diff --git a/tests/brain/test_statistics.py b/tests/brain/test_statistics.py
new file mode 100644
index 0000000..6d18f27
--- /dev/null
+++ b/tests/brain/test_statistics.py
@@ -0,0 +1,60 @@
+# Licensed under the LGPL: https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html
+# For details: https://github.com/pylint-dev/astroid/blob/main/LICENSE
+# Copyright (c) https://github.com/pylint-dev/astroid/blob/main/CONTRIBUTORS.txt
+
+"""Tests for brain statistics module."""
+
+from __future__ import annotations
+
+import unittest
+
+from astroid import extract_node
+from astroid.util import Uninferable
+
+
+class StatisticsBrainTest(unittest.TestCase):
+    """Test the brain statistics module functionality."""
+
+    def test_statistics_quantiles_inference(self) -> None:
+        """Test that statistics.quantiles() returns Uninferable instead of empty list."""
+        node = extract_node("""
+        import statistics
+        statistics.quantiles(list(range(100)), n=4)  #@
+        """)
+        inferred = list(node.infer())
+        self.assertEqual(len(inferred), 1)
+        self.assertIs(inferred[0], Uninferable)
+
+    def test_statistics_quantiles_different_args(self) -> None:
+        """Test statistics.quantiles with different arguments."""
+        node = extract_node("""
+        import statistics
+        statistics.quantiles([1, 2, 3, 4, 5], n=10, method='inclusive')  #@
+        """)
+        inferred = list(node.infer())
+        self.assertEqual(len(inferred), 1)
+        self.assertIs(inferred[0], Uninferable)
+
+    def test_statistics_quantiles_assignment_unpacking(self) -> None:
+        """Test the specific case that was causing false positives."""
+        node = extract_node("""
+        import statistics
+        q1, q2, q3 = statistics.quantiles(list(range(100)), n=4)  #@
+        """)
+        call_node = node.value
+        inferred = list(call_node.infer())
+        self.assertEqual(len(inferred), 1)
+        self.assertIs(inferred[0], Uninferable)
+
+    def test_other_statistics_functions_not_affected(self) -> None:
+        """Test that other statistics functions are not affected by our brain module."""
+        node = extract_node("""
+        import statistics
+        statistics.mean([1, 2, 3, 4, 5])  #@
+        """)
+        inferred = list(node.infer())
+        self.assertNotEqual(len(inferred), 0)
+
+
+if __name__ == "__main__":
+    unittest.main()
diff --git a/tests/brain/test_threading.py b/tests/brain/test_threading.py
index f757649..2fe2c7f 100644
--- a/tests/brain/test_threading.py
+++ b/tests/brain/test_threading.py
@@ -13,12 +13,10 @@
 
 class ThreadingBrainTest(unittest.TestCase):
     def test_lock(self) -> None:
-        lock_instance = builder.extract_node(
-            """
+        lock_instance = builder.extract_node("""
         import threading
         threading.Lock()
-        """
-        )
+        """)
         inferred = next(lock_instance.infer())
         self.assert_is_valid_lock(inferred)
 
@@ -38,12 +36,10 @@
         self._test_lock_object("BoundedSemaphore")
 
     def _test_lock_object(self, object_name: str) -> None:
-        lock_instance = builder.extract_node(
-            f"""
+        lock_instance = builder.extract_node(f"""
         import threading
         threading.{object_name}()
-        """
-        )
+        """)
         inferred = next(lock_instance.infer())
         self.assert_is_valid_lock(inferred)
 
diff --git a/tests/brain/test_typing.py b/tests/brain/test_typing.py
index 11b77b7..55b99d2 100644
--- a/tests/brain/test_typing.py
+++ b/tests/brain/test_typing.py
@@ -15,12 +15,10 @@
     Test that an inferred `typing.TypeVar()` call produces a `nodes.ClassDef`
     node.
     """
-    call_node = builder.extract_node(
-        """
+    call_node = builder.extract_node("""
     from typing import TypeVar
     TypeVar('My.Type')
-    """
-    )
+    """)
     with pytest.raises(InferenceError):
         call_node.inferred()
 
@@ -30,12 +28,10 @@
         """
         Test that _alias() calls can be inferred.
         """
-        node = builder.extract_node(
-            """
+        node = builder.extract_node("""
             from typing import _alias
             x = _alias(int, float)
-            """
-        )
+            """)
         assert isinstance(node, nodes.Assign)
         assert isinstance(node.value, nodes.Call)
         inferred = next(node.value.infer())
@@ -59,14 +55,32 @@
 
         Test that _alias() calls with the incorrect number of arguments can be inferred.
         """
-        node = builder.extract_node(
-            f"""
+        node = builder.extract_node(f"""
             from typing import _alias
             x = _alias({alias_args})
-            """
-        )
+            """)
         assert isinstance(node, nodes.Assign)
         assert isinstance(node.value, nodes.Call)
         inferred = next(node.value.infer())
         assert isinstance(inferred, bases.Instance)
         assert inferred.name == "_SpecialGenericAlias"
+
+
+class TestSpecialAlias:
+    @pytest.mark.parametrize(
+        "code",
+        [
+            "_CallableType()",
+            "_TupleType()",
+        ],
+    )
+    def test_special_alias_no_crash_on_empty_args(self, code: str) -> None:
+        """
+        Regression test for: https://github.com/pylint-dev/astroid/issues/2772
+
+        Test that _CallableType() and _TupleType() calls with no arguments
+        do not cause an IndexError.
+        """
+        # Should not raise IndexError
+        module = builder.parse(code)
+        assert isinstance(module, nodes.Module)
diff --git a/tests/brain/test_typing_extensions.py b/tests/brain/test_typing_extensions.py
index 883428b..70f1ba1 100644
--- a/tests/brain/test_typing_extensions.py
+++ b/tests/brain/test_typing_extensions.py
@@ -29,13 +29,11 @@
         reason="Need typing_extensions>=4.4.0 to test TypeVar",
     )
     def test_typing_extensions_types() -> None:
-        ast_nodes = builder.extract_node(
-            """
+        ast_nodes = builder.extract_node("""
         from typing_extensions import TypeVar
         TypeVar('MyTypeVar', int, float, complex) #@
         TypeVar('AnyStr', str, bytes) #@
-        """
-        )
+        """)
         for node in ast_nodes:
             inferred = next(node.infer())
             assert isinstance(inferred, nodes.ClassDef)
diff --git a/tests/brain/test_unittest.py b/tests/brain/test_unittest.py
index 53f7d9f..b54dc8d 100644
--- a/tests/brain/test_unittest.py
+++ b/tests/brain/test_unittest.py
@@ -15,14 +15,12 @@
         Tests that the IsolatedAsyncioTestCase class is statically imported
         thanks to the brain_unittest module.
         """
-        node = builder.extract_node(
-            """
+        node = builder.extract_node("""
         from unittest import IsolatedAsyncioTestCase
 
         class TestClass(IsolatedAsyncioTestCase):
             pass
-        """
-        )
+        """)
         assert [n.qname() for n in node.ancestors()] == [
             "unittest.async_case.IsolatedAsyncioTestCase",
             "unittest.case.TestCase",
diff --git a/tests/test_builder.py b/tests/test_builder.py
index 9a84491..3985c48 100644
--- a/tests/test_builder.py
+++ b/tests/test_builder.py
@@ -123,8 +123,7 @@
 
     @staticmethod
     def test_decorated_class_lineno() -> None:
-        code = textwrap.dedent(
-            """
+        code = textwrap.dedent("""
         class A:  # L2
             ...
 
@@ -138,8 +137,7 @@
         )
         class C:  # L13
             ...
-        """
-        )
+        """)
 
         ast_module: nodes.Module = builder.parse(code)  # type: ignore[assignment]
 
@@ -161,8 +159,7 @@
     @staticmethod
     def test_class_with_docstring() -> None:
         """Test class nodes which only have docstrings."""
-        code = textwrap.dedent(
-            '''\
+        code = textwrap.dedent('''\
         class A:
             """My docstring"""
             var = 1
@@ -181,8 +178,7 @@
 
         class E:
             ...
-        '''
-        )
+        ''')
 
         ast_module = builder.parse(code)
 
@@ -214,8 +210,7 @@
     @staticmethod
     def test_function_with_docstring() -> None:
         """Test function defintions with only docstrings."""
-        code = textwrap.dedent(
-            '''\
+        code = textwrap.dedent('''\
         def a():
             """My docstring"""
             var = 1
@@ -236,8 +231,7 @@
             """My docstring
             is long.
             """
-        '''
-        )
+        ''')
 
         ast_module = builder.parse(code)
 
@@ -572,12 +566,10 @@
         self.assertEqual({"print_function"}, mod.future_imports)
 
     def test_two_future_imports(self) -> None:
-        mod = builder.parse(
-            """
+        mod = builder.parse("""
             from __future__ import print_function
             from __future__ import absolute_import
-            """
-        )
+            """)
         self.assertEqual({"print_function", "absolute_import"}, mod.future_imports)
 
     def test_inferred_build(self) -> None:
@@ -597,15 +589,13 @@
         self.assertIn("type", lclass.locals)
 
     def test_infer_can_assign_regular_object(self) -> None:
-        mod = builder.parse(
-            """
+        mod = builder.parse("""
             class A:
                 pass
             a = A()
             a.value = "is set"
             a.other = "is set"
-        """
-        )
+        """)
         obj = list(mod.igetattr("a"))
         self.assertEqual(len(obj), 1)
         obj = obj[0]
@@ -614,15 +604,13 @@
         self.assertIn("other", obj.instance_attrs)
 
     def test_infer_can_assign_has_slots(self) -> None:
-        mod = builder.parse(
-            """
+        mod = builder.parse("""
             class A:
                 __slots__ = ('value',)
             a = A()
             a.value = "is set"
             a.other = "not set"
-        """
-        )
+        """)
         obj = list(mod.igetattr("a"))
         self.assertEqual(len(obj), 1)
         obj = obj[0]
@@ -631,12 +619,10 @@
         self.assertNotIn("other", obj.instance_attrs)
 
     def test_infer_can_assign_no_classdict(self) -> None:
-        mod = builder.parse(
-            """
+        mod = builder.parse("""
             a = object()
             a.value = "not set"
-        """
-        )
+        """)
         obj = list(mod.igetattr("a"))
         self.assertEqual(len(obj), 1)
         obj = obj[0]
@@ -700,21 +686,17 @@
         self.assertEqual(chain.value, "None")
 
     def test_not_implemented(self) -> None:
-        node = builder.extract_node(
-            """
+        node = builder.extract_node("""
         NotImplemented #@
-        """
-        )
+        """)
         inferred = next(node.infer())
         self.assertIsInstance(inferred, nodes.Const)
         self.assertEqual(inferred.value, NotImplemented)
 
     def test_type_comments_without_content(self) -> None:
-        node = builder.parse(
-            """
+        node = builder.parse("""
             a = 1 # type: # any comment
-        """
-        )
+        """)
         assert node
 
 
@@ -781,9 +763,7 @@
     def test_function_locals(self) -> None:
         """Test the 'locals' dictionary of an astroid function."""
         _locals = self.module["global_access"].locals
-        self.assertEqual(len(_locals), 4)
-        keys = sorted(_locals.keys())
-        self.assertEqual(keys, ["i", "key", "local", "val"])
+        self.assertEqual(sorted(_locals.keys()), ["i", "key", "local", "val"])
 
     def test_class_base_props(self) -> None:
         """Test base properties and method of an astroid class."""
@@ -804,14 +784,8 @@
     def test_class_locals(self) -> None:
         """Test the 'locals' dictionary of an astroid class."""
         module = self.module
-        klass1 = module["YO"]
-        locals1 = klass1.locals
-        keys = sorted(locals1.keys())
         assert_keys = ["__annotations__", "__init__", "__module__", "__qualname__", "a"]
-        self.assertEqual(keys, assert_keys)
-        klass2 = module["YOUPI"]
-        locals2 = klass2.locals
-        keys = locals2.keys()
+        self.assertEqual(sorted(module["YO"].locals.keys()), assert_keys)
         assert_keys = [
             "__annotations__",
             "__init__",
@@ -822,50 +796,43 @@
             "method",
             "static_method",
         ]
-        self.assertEqual(sorted(keys), assert_keys)
+        self.assertEqual(sorted(module["YOUPI"].locals.keys()), assert_keys)
 
     def test_class_instance_attrs(self) -> None:
         module = self.module
-        klass1 = module["YO"]
-        klass2 = module["YOUPI"]
-        self.assertEqual(list(klass1.instance_attrs.keys()), ["yo"])
-        self.assertEqual(list(klass2.instance_attrs.keys()), ["member"])
+        self.assertEqual(list(module["YO"].instance_attrs.keys()), ["yo"])
+        self.assertEqual(list(module["YOUPI"].instance_attrs.keys()), ["member"])
 
     def test_class_basenames(self) -> None:
         module = self.module
-        klass1 = module["YO"]
-        klass2 = module["YOUPI"]
-        self.assertEqual(klass1.basenames, [])
-        self.assertEqual(klass2.basenames, ["YO"])
+        self.assertEqual(module["YO"].basenames, [])
+        self.assertEqual(module["YOUPI"].basenames, ["YO"])
 
     def test_method_base_props(self) -> None:
         """Test base properties and method of an astroid method."""
-        klass2 = self.module["YOUPI"]
-        # "normal" method
-        method = klass2["method"]
+        method = self.module["YOUPI"]["method"]
         self.assertEqual(method.name, "method")
         self.assertEqual([n.name for n in method.args.args], ["self"])
         assert isinstance(method.doc_node, nodes.Const)
         self.assertEqual(method.doc_node.value, "method\n        test")
         self.assertEqual(method.fromlineno, 48)
         self.assertEqual(method.type, "method")
-        # class method
-        method = klass2["class_method"]
+
+    def test_class_method_base_props(self) -> None:
+        method = self.module["YOUPI"]["class_method"]
         self.assertEqual([n.name for n in method.args.args], ["cls"])
         self.assertEqual(method.type, "classmethod")
-        # static method
-        method = klass2["static_method"]
+
+    def test_static_method_base_props(self) -> None:
+        method = self.module["YOUPI"]["static_method"]
         self.assertEqual(method.args.args, [])
         self.assertEqual(method.type, "staticmethod")
 
     def test_method_locals(self) -> None:
         """Test the 'locals' dictionary of an astroid method."""
         method = self.module["YOUPI"]["method"]
-        _locals = method.locals
-        keys = sorted(_locals)
         # ListComp variables are not accessible outside
-        self.assertEqual(len(_locals), 3)
-        self.assertEqual(keys, ["autre", "local", "self"])
+        self.assertEqual(sorted(method.locals), ["a", "autre", "local", "self"])
 
     def test_unknown_encoding(self) -> None:
         with self.assertRaises(AstroidSyntaxError):
@@ -881,8 +848,7 @@
 
 
 def test_parse_module_with_invalid_type_comments_does_not_crash():
-    node = builder.parse(
-        """
+    node = builder.parse("""
     # op {
     #   name: "AssignAddVariableOp"
     #   input_arg {
@@ -900,8 +866,7 @@
     #   is_stateful: true
     # }
     a, b = 2
-    """
-    )
+    """)
     assert isinstance(node, nodes.Module)
 
 
diff --git a/tests/test_constraint.py b/tests/test_constraint.py
index 63f6275..00a8018 100644
--- a/tests/test_constraint.py
+++ b/tests/test_constraint.py
@@ -3,20 +3,36 @@
 # Copyright (c) https://github.com/pylint-dev/astroid/blob/main/CONTRIBUTORS.txt
 
 """Tests for inference involving constraints."""
+
 from __future__ import annotations
 
+from unittest.mock import patch
+
 import pytest
 
 from astroid import builder, nodes
+from astroid.bases import Instance
 from astroid.util import Uninferable
 
 
+def node_info(node: nodes.NodeNG) -> str:
+    return f"Inference of {node.as_string()!r} at line {node.lineno}"
+
+
 def common_params(node: str) -> pytest.MarkDecorator:
     return pytest.mark.parametrize(
         ("condition", "satisfy_val", "fail_val"),
         (
             (f"{node} is None", None, 3),
             (f"{node} is not None", 3, None),
+            (f"{node}", 3, None),
+            (f"not {node}", None, 3),
+            (f"isinstance({node}, int)", 3, None),
+            (f"isinstance({node}, (int, str))", 3, None),
+            (f"{node} == 3", 3, None),
+            (f"{node} != 3", None, 3),
+            (f"3 == {node}", 3, None),
+            (f"3 != {node}", None, 3),
         ),
     )
 
@@ -26,8 +42,7 @@
     condition: str, satisfy_val: int | None, fail_val: int | None
 ) -> None:
     """Test constraint for a variable that is used in the first statement of an if body."""
-    node1, node2 = builder.extract_node(
-        f"""
+    node1, node2 = builder.extract_node(f"""
     def f1(x = {fail_val}):
         if {condition}:  # Filters out default value
             return (
@@ -39,8 +54,7 @@
             return (
                 x  #@
             )
-    """
-    )
+    """)
 
     inferred = node1.inferred()
     assert len(inferred) == 1
@@ -61,8 +75,7 @@
     """Test constraint for a variable that is used in an if body with multiple
     statements.
     """
-    node1, node2 = builder.extract_node(
-        f"""
+    node1, node2 = builder.extract_node(f"""
     def f1(x = {fail_val}):
         if {condition}:  # Filters out default value
             print(x)
@@ -76,8 +89,7 @@
             return (
                 x  #@
             )
-    """
-    )
+    """)
 
     inferred = node1.inferred()
     assert len(inferred) == 1
@@ -96,8 +108,7 @@
     condition: str, satisfy_val: int | None, fail_val: int | None
 ) -> None:
     """Test that constraint for a different variable doesn't apply."""
-    nodes_ = builder.extract_node(
-        f"""
+    nodes_ = builder.extract_node(f"""
     def f1(x, y = {fail_val}):
         if {condition}:  # Does not filter out fail_val
             return (
@@ -109,8 +120,7 @@
             return (
                 y  #@
             )
-    """
-    )
+    """)
     for node, val in zip(nodes_, (fail_val, satisfy_val)):
         inferred = node.inferred()
         assert len(inferred) == 2
@@ -125,8 +135,7 @@
     condition: str, satisfy_val: int | None, fail_val: int | None
 ) -> None:
     """Test that constraint in an if condition doesn't apply outside of the if."""
-    nodes_ = builder.extract_node(
-        f"""
+    nodes_ = builder.extract_node(f"""
     def f1(x = {fail_val}):
         if {condition}:
             pass
@@ -141,8 +150,7 @@
         return (
             x  #@
         )
-    """
-    )
+    """)
     for node, val in zip(nodes_, (fail_val, satisfy_val)):
         inferred = node.inferred()
         assert len(inferred) == 2
@@ -157,8 +165,7 @@
     condition: str, satisfy_val: int | None, fail_val: int | None
 ) -> None:
     """Test that constraint in an if condition applies within inner if statements."""
-    node1, node2 = builder.extract_node(
-        f"""
+    node1, node2 = builder.extract_node(f"""
     def f1(y, x = {fail_val}):
         if {condition}:
             if y is not None:
@@ -172,8 +179,7 @@
                 return (
                     x  #@
                 )
-    """
-    )
+    """)
     inferred = node1.inferred()
     assert len(inferred) == 1
     assert inferred[0] is Uninferable
@@ -190,8 +196,7 @@
     """Test that when no inferred values satisfy all constraints, Uninferable is
     inferred.
     """
-    node1, node2 = builder.extract_node(
-        """
+    node1, node2 = builder.extract_node("""
     def f1():
         x = None
         if x is not None:
@@ -203,8 +208,7 @@
             pass
         else:
             x  #@
-    """
-    )
+    """)
     inferred = node1.inferred()
     assert len(inferred) == 1
     assert inferred[0] is Uninferable
@@ -221,8 +225,7 @@
     """Test that constraint in an if condition doesn't apply when the variable
     is assigned to a failing value inside the if body.
     """
-    node = builder.extract_node(
-        f"""
+    node = builder.extract_node(f"""
     def f(x, y):
         if {condition}:
             if y:
@@ -230,8 +233,7 @@
             return (
                 x  #@
             )
-    """
-    )
+    """)
     inferred = node.inferred()
     assert len(inferred) == 2
     assert inferred[0] is Uninferable
@@ -247,8 +249,7 @@
     """Test that constraint in an if condition is negated when the variable
     is used in the elif and else branches.
     """
-    node1, node2, node3, node4 = builder.extract_node(
-        f"""
+    node1, node2, node3, node4 = builder.extract_node(f"""
     def f1(y, x = {fail_val}):
         if {condition}:
             pass
@@ -272,20 +273,21 @@
             return (
                 x  #@
             )
-    """
-    )
+    """)
     for node in (node1, node2):
+        msg = node_info(node)
         inferred = node.inferred()
-        assert len(inferred) == 2
-        assert isinstance(inferred[0], nodes.Const)
-        assert inferred[0].value == fail_val
+        assert len(inferred) == 2, msg
+        assert isinstance(inferred[0], nodes.Const), msg
+        assert inferred[0].value == fail_val, msg
 
-        assert inferred[1] is Uninferable
+        assert inferred[1] is Uninferable, msg
 
     for node in (node3, node4):
+        msg = node_info(node)
         inferred = node.inferred()
-        assert len(inferred) == 1
-        assert inferred[0] is Uninferable
+        assert len(inferred) == 1, msg
+        assert inferred[0] is Uninferable, msg
 
 
 @common_params(node="x")
@@ -295,8 +297,7 @@
     """Test that constraint in an if condition doesn't apply when the variable
     is assigned to a failing value inside the else branch.
     """
-    node = builder.extract_node(
-        f"""
+    node = builder.extract_node(f"""
     def f(x, y):
         if {condition}:
             return x
@@ -306,8 +307,7 @@
             return (
                 x  #@
             )
-    """
-    )
+    """)
     inferred = node.inferred()
     assert len(inferred) == 2
     assert inferred[0] is Uninferable
@@ -323,16 +323,14 @@
     """Test that constraint in an if condition doesn't apply when the variable
     is shadowed by an inner comprehension scope.
     """
-    node = builder.extract_node(
-        f"""
+    node = builder.extract_node(f"""
     def f(x):
         if {condition}:
             return [
                 x  #@
                 for x in [{satisfy_val}, {fail_val}]
             ]
-    """
-    )
+    """)
     inferred = node.inferred()
     assert len(inferred) == 2
 
@@ -348,16 +346,14 @@
     """Test that constraint in an if condition doesn't apply when the variable
     is shadowed by an inner function scope.
     """
-    node = builder.extract_node(
-        f"""
+    node = builder.extract_node(f"""
     x = {satisfy_val}
     if {condition}:
         def f(x = {fail_val}):
             return (
                 x  #@
             )
-    """
-    )
+    """)
     inferred = node.inferred()
     assert len(inferred) == 2
     assert isinstance(inferred[0], nodes.Const)
@@ -373,16 +369,14 @@
     """Test that constraint in an if condition doesn't apply for a parameter
     a different function call, but with the same name.
     """
-    node = builder.extract_node(
-        f"""
+    node = builder.extract_node(f"""
     def f(x = {satisfy_val}):
         if {condition}:
             g({fail_val})  #@
 
     def g(x):
         return x
-    """
-    )
+    """)
     inferred = node.inferred()
     assert len(inferred) == 1
     assert isinstance(inferred[0], nodes.Const)
@@ -394,8 +388,7 @@
     condition: str, satisfy_val: int | None, fail_val: int | None
 ) -> None:
     """Test constraint for an instance attribute in an if statement."""
-    node1, node2 = builder.extract_node(
-        f"""
+    node1, node2 = builder.extract_node(f"""
     class A1:
         def __init__(self, x = {fail_val}):
             self.x = x
@@ -411,8 +404,7 @@
         def method(self):
             if {condition}:
                 self.x  #@
-    """
-    )
+    """)
 
     inferred = node1.inferred()
     assert len(inferred) == 1
@@ -433,8 +425,7 @@
     """Test that constraint in an if condition doesn't apply to an instance attribute
     when it is assigned inside the if body.
     """
-    node1, node2 = builder.extract_node(
-        f"""
+    node1, node2 = builder.extract_node(f"""
     class A1:
         def __init__(self, x):
             self.x = x
@@ -448,8 +439,7 @@
             if {condition}:
                 self.x = {fail_val}
                 self.x  #@
-    """
-    )
+    """)
 
     inferred = node1.inferred()
     assert len(inferred) == 2
@@ -476,8 +466,7 @@
     """Test that constraint in an if condition doesn't apply to an instance attribute
     when the constraint refers to a variable with the same name.
     """
-    node1, node2 = builder.extract_node(
-        f"""
+    node1, node2 = builder.extract_node(f"""
     class A1:
         def __init__(self, x = {fail_val}):
             self.x = x
@@ -486,8 +475,7 @@
             if {condition}:
                 x  #@
                 self.x  #@
-    """
-    )
+    """)
 
     inferred = node1.inferred()
     assert len(inferred) == 1
@@ -508,8 +496,7 @@
     """Test that constraint in an if condition doesn't apply to a variable with the same
     name.
     """
-    node1, node2 = builder.extract_node(
-        f"""
+    node1, node2 = builder.extract_node(f"""
     class A1:
         def __init__(self, x = {fail_val}):
             self.x = x
@@ -518,8 +505,7 @@
             if {condition}:
                 x  #@
                 self.x  #@
-    """
-    )
+    """)
 
     inferred = node1.inferred()
     assert len(inferred) == 2
@@ -540,8 +526,7 @@
     """Test that constraint in an if condition doesn't apply to an instance attribute
     for an object of a different class.
     """
-    node = builder.extract_node(
-        f"""
+    node = builder.extract_node(f"""
     class A1:
         def __init__(self, x = {fail_val}):
             self.x = x
@@ -554,8 +539,7 @@
     class A2:
         def __init__(self):
             self.x = {fail_val}
-    """
-    )
+    """)
 
     inferred = node.inferred()
     assert len(inferred) == 1
@@ -570,8 +554,7 @@
     """Test that constraint in an if condition doesn't apply to a variable of the same name,
     when that variable is used to infer the value of the instance attribute.
     """
-    node = builder.extract_node(
-        f"""
+    node = builder.extract_node(f"""
     class A1:
         def __init__(self, x):
             self.x = x
@@ -581,8 +564,7 @@
             if {condition}:
                 self.x = x
                 self.x  #@
-    """
-    )
+    """)
 
     inferred = node.inferred()
     assert len(inferred) == 2
@@ -590,3 +572,572 @@
 
     assert isinstance(inferred[1], nodes.Const)
     assert inferred[1].value == fail_val
+
+
+@common_params(node="x")
+def test_if_exp_body(
+    condition: str, satisfy_val: int | None, fail_val: int | None
+) -> None:
+    """Test constraint for a variable that is used in an if exp body."""
+    node1, node2 = builder.extract_node(f"""
+    def f1(x = {fail_val}):
+        return (
+            x if {condition} else None  #@
+        )
+
+    def f2(x = {satisfy_val}):
+        return (
+            x if {condition} else None  #@
+        )
+    """)
+
+    inferred = node1.body.inferred()
+    assert len(inferred) == 1
+    assert inferred[0] is Uninferable
+
+    inferred = node2.body.inferred()
+    assert len(inferred) == 2
+    assert isinstance(inferred[0], nodes.Const)
+    assert inferred[0].value == satisfy_val
+    assert inferred[1] is Uninferable
+
+
+@common_params(node="x")
+def test_if_exp_else(
+    condition: str, satisfy_val: int | None, fail_val: int | None
+) -> None:
+    """Test constraint for a variable that is used in an if exp else block."""
+    node1, node2 = builder.extract_node(f"""
+    def f1(x = {satisfy_val}):
+        return (
+            None if {condition} else x  #@
+        )
+
+    def f2(x = {fail_val}):
+        return (
+            None if {condition} else x  #@
+        )
+    """)
+
+    inferred = node1.orelse.inferred()
+    assert len(inferred) == 1
+    assert inferred[0] is Uninferable
+
+    inferred = node2.orelse.inferred()
+    assert len(inferred) == 2
+    assert isinstance(inferred[0], nodes.Const)
+    assert inferred[0].value == fail_val
+    assert inferred[1] is Uninferable
+
+
+@common_params(node="x")
+def test_outside_if_exp(
+    condition: str, satisfy_val: int | None, fail_val: int | None
+) -> None:
+    """Test that constraint in an if exp condition doesn't apply outside of the if exp."""
+    nodes_ = builder.extract_node(f"""
+    def f1(x = {fail_val}):
+        x if {condition} else None
+        return (
+            x  #@
+        )
+
+    def f2(x = {satisfy_val}):
+        None if {condition} else x
+        return (
+            x  #@
+        )
+    """)
+    for node, val in zip(nodes_, (fail_val, satisfy_val)):
+        inferred = node.inferred()
+        assert len(inferred) == 2
+        assert isinstance(inferred[0], nodes.Const)
+        assert inferred[0].value == val
+        assert inferred[1] is Uninferable
+
+
+@common_params(node="x")
+def test_nested_if_exp(
+    condition: str, satisfy_val: int | None, fail_val: int | None
+) -> None:
+    """Test that constraint in an if exp condition applies within inner if exp."""
+    node1, node2 = builder.extract_node(f"""
+    def f1(y, x = {fail_val}):
+        return (
+            (x if y else None) if {condition} else None  #@
+        )
+
+    def f2(y, x = {satisfy_val}):
+        return (
+            (x if y else None) if {condition} else None  #@
+        )
+    """)
+
+    inferred = node1.body.body.inferred()
+    assert len(inferred) == 1
+    assert inferred[0] is Uninferable
+
+    inferred = node2.body.body.inferred()
+    assert len(inferred) == 2
+    assert isinstance(inferred[0], nodes.Const)
+    assert inferred[0].value == satisfy_val
+    assert inferred[1] is Uninferable
+
+
+@common_params(node="self.x")
+def test_if_exp_instance_attr(
+    condition: str, satisfy_val: int | None, fail_val: int | None
+) -> None:
+    """Test constraint for an instance attribute in an if exp."""
+    node1, node2 = builder.extract_node(f"""
+    class A1:
+        def __init__(self, x = {fail_val}):
+            self.x = x
+
+        def method(self):
+            return (
+                self.x if {condition} else None  #@
+            )
+
+    class A2:
+        def __init__(self, x = {satisfy_val}):
+            self.x = x
+
+        def method(self):
+            return (
+                self.x if {condition} else None  #@
+            )
+    """)
+
+    inferred = node1.body.inferred()
+    assert len(inferred) == 1
+    assert inferred[0] is Uninferable
+
+    inferred = node2.body.inferred()
+    assert len(inferred) == 2
+    assert isinstance(inferred[0], nodes.Const)
+    assert inferred[0].value == satisfy_val
+    assert inferred[1].value is Uninferable
+
+
+@common_params(node="self.x")
+def test_if_exp_instance_attr_varname_collision(
+    condition: str, satisfy_val: int | None, fail_val: int | None
+) -> None:
+    """Test that constraint in an if exp condition doesn't apply to a variable with the same name."""
+    node = builder.extract_node(f"""
+    class A:
+        def __init__(self, x = {fail_val}):
+            self.x = x
+
+        def method(self, x = {fail_val}):
+            return (
+                x if {condition} else None  #@
+            )
+    """)
+
+    inferred = node.body.inferred()
+    assert len(inferred) == 2
+    assert isinstance(inferred[0], nodes.Const)
+    assert inferred[0].value == fail_val
+    assert inferred[1].value is Uninferable
+
+
+def test_isinstance_equal_types() -> None:
+    """Test constraint for an object whose type is equal to the checked type."""
+    node = builder.extract_node("""
+    class A:
+        pass
+
+    x = A()
+
+    if isinstance(x, A):
+        x  #@
+    """)
+
+    inferred = node.inferred()
+    assert len(inferred) == 1
+    assert isinstance(inferred[0], Instance)
+    assert isinstance(inferred[0]._proxied, nodes.ClassDef)
+    assert inferred[0].name == "A"
+
+
+def test_isinstance_subtype() -> None:
+    """Test constraint for an object whose type is a strict subtype of the checked type."""
+    node = builder.extract_node("""
+    class A:
+        pass
+
+    class B(A):
+        pass
+
+    x = B()
+
+    if isinstance(x, A):
+        x  #@
+    """)
+
+    inferred = node.inferred()
+    assert len(inferred) == 1
+    assert isinstance(inferred[0], Instance)
+    assert isinstance(inferred[0]._proxied, nodes.ClassDef)
+    assert inferred[0].name == "B"
+
+
+def test_isinstance_unrelated_types():
+    """Test constraint for an object whose type is not related to the checked type."""
+    node = builder.extract_node("""
+    class A:
+        pass
+
+    class B:
+        pass
+
+    x = A()
+
+    if isinstance(x, B):
+        x  #@
+    """)
+
+    inferred = node.inferred()
+    assert len(inferred) == 1
+    assert inferred[0] is Uninferable
+
+
+def test_isinstance_supertype():
+    """Test constraint for an object whose type is a strict supertype of the checked type."""
+    node = builder.extract_node("""
+    class A:
+        pass
+
+    class B(A):
+        pass
+
+    x = A()
+
+    if isinstance(x, B):
+        x  #@
+    """)
+
+    inferred = node.inferred()
+    assert len(inferred) == 1
+    assert inferred[0] is Uninferable
+
+
+def test_isinstance_multiple_inheritance():
+    """Test constraint for an object that inherits from more than one parent class."""
+    n1, n2, n3 = builder.extract_node("""
+    class A:
+        pass
+
+    class B:
+        pass
+
+    class C(A, B):
+        pass
+
+    x = C()
+
+    if isinstance(x, C):
+        x  #@
+
+    if isinstance(x, A):
+        x  #@
+
+    if isinstance(x, B):
+        x  #@
+    """)
+
+    for node in (n1, n2, n3):
+        msg = node_info(node)
+        inferred = node.inferred()
+        assert len(inferred) == 1, msg
+        assert isinstance(inferred[0], Instance), msg
+        assert isinstance(inferred[0]._proxied, nodes.ClassDef), msg
+        assert inferred[0].name == "C", msg
+
+
+def test_isinstance_diamond_inheritance():
+    """Test constraint for an object that inherits from parent classes
+    in diamond inheritance.
+    """
+    n1, n2, n3, n4 = builder.extract_node("""
+    class A():
+        pass
+
+    class B(A):
+        pass
+
+    class C(A):
+        pass
+
+    class D(B, C):
+        pass
+
+    x = D()
+
+    if isinstance(x, D):
+        x  #@
+
+    if isinstance(x, B):
+        x  #@
+
+    if isinstance(x, C):
+        x  #@
+
+    if isinstance(x, A):
+        x  #@
+    """)
+
+    for node in (n1, n2, n3, n4):
+        msg = node_info(node)
+        inferred = node.inferred()
+        assert len(inferred) == 1, msg
+        assert isinstance(inferred[0], Instance), msg
+        assert isinstance(inferred[0]._proxied, nodes.ClassDef), msg
+        assert inferred[0].name == "D", msg
+
+
+def test_isinstance_keyword_arguments():
+    """Test that constraint does not apply when `isinstance` is called
+    with keyword arguments.
+    """
+    n1, n2 = builder.extract_node("""
+    x = 3
+
+    if isinstance(object=x, classinfo=str):
+        x  #@
+
+    if isinstance(x, str, object=x, classinfo=str):
+        x  #@
+    """)
+
+    for node in (n1, n2):
+        msg = node_info(node)
+        inferred = node.inferred()
+        assert len(inferred) == 1, msg
+        assert isinstance(inferred[0], nodes.Const), msg
+        assert inferred[0].value == 3, msg
+
+
+def test_isinstance_extra_argument():
+    """Test that constraint does not apply when `isinstance` is called
+    with more than two positional arguments.
+    """
+    node = builder.extract_node("""
+    x = 3
+
+    if isinstance(x, str, bool):
+        x  #@
+    """)
+
+    inferred = node.inferred()
+    assert len(inferred) == 1
+    assert isinstance(inferred[0], nodes.Const)
+    assert inferred[0].value == 3
+
+
+def test_isinstance_classinfo_inference_error():
+    """Test that constraint is satisfied when `isinstance` is called with
+    classinfo that raises an inference error.
+    """
+    node = builder.extract_node("""
+    x = 3
+
+    if isinstance(x, undefined_type):
+        x  #@
+    """)
+
+    inferred = node.inferred()
+    assert len(inferred) == 1
+    assert isinstance(inferred[0], nodes.Const)
+    assert inferred[0].value == 3
+
+
+def test_isinstance_uninferable_classinfo():
+    """Test that constraint is satisfied when `isinstance` is called with
+    uninferable classinfo.
+    """
+    node = builder.extract_node("""
+    def f(classinfo):
+        x = 3
+
+        if isinstance(x, classinfo):
+            x  #@
+    """)
+
+    inferred = node.inferred()
+    assert len(inferred) == 1
+    assert isinstance(inferred[0], nodes.Const)
+    assert inferred[0].value == 3
+
+
+def test_isinstance_mro_error():
+    """Test that constraint is satisfied when computing the object's
+    method resolution order raises an MRO error.
+    """
+    node = builder.extract_node("""
+    class A():
+        pass
+
+    class B(A, A):
+        pass
+
+    x = B()
+
+    if isinstance(x, A):
+        x  #@
+    """)
+
+    inferred = node.inferred()
+    assert len(inferred) == 1
+    assert isinstance(inferred[0], Instance)
+    assert isinstance(inferred[0]._proxied, nodes.ClassDef)
+    assert inferred[0].name == "B"
+
+
+def test_isinstance_uninferable():
+    """Test that constraint is satisfied when `isinstance` inference returns Uninferable."""
+    node = builder.extract_node("""
+    x = 3
+
+    if isinstance(x, str):
+        x  #@
+    """)
+
+    with patch(
+        "astroid.constraint.helpers.object_isinstance", return_value=Uninferable
+    ):
+        inferred = node.inferred()
+        assert len(inferred) == 1
+        assert isinstance(inferred[0], nodes.Const)
+        assert inferred[0].value == 3
+
+
+def test_equality_callable():
+    """Test constraint for equality of callables."""
+    node1, node2, node3, node4, node5, node6 = builder.extract_node("""
+    class Foo:
+        pass
+
+    def bar():
+        pass
+
+    baz = lambda i : i
+
+    x, y, z = Foo, bar, baz
+
+    if x == Foo:
+        x  #@
+    if x != Foo:
+        x  #@
+
+    if y == bar:
+        y  #@
+    if y != bar:
+        y  #@
+
+    if z == baz:
+        z  #@
+    if z != baz:
+        z  #@
+    """)
+
+    inferred = node1.inferred()
+    assert len(inferred) == 1
+    assert isinstance(inferred[0], nodes.ClassDef)
+    assert inferred[0].name == "Foo"
+
+    inferred = node3.inferred()
+    assert len(inferred) == 1
+    assert isinstance(inferred[0], nodes.FunctionDef)
+    assert inferred[0].name == "bar"
+
+    inferred = node5.inferred()
+    assert len(inferred) == 1
+    assert isinstance(inferred[0], nodes.Lambda)
+
+    for node in (node2, node4, node6):
+        msg = node_info(node)
+        inferred = node.inferred()
+        assert len(inferred) == 1, msg
+        assert inferred[0] is Uninferable, msg
+
+
+def test_equality_uninferable_operand():
+    """Test that equality constraint is satisfied when either operand is uninferable."""
+    node1, node2, node3, node4 = builder.extract_node("""
+    def f1(x):
+        if x == 3:
+            x  #@
+
+        if x != 3:
+            x  #@
+
+    def f2(y):
+        x = 3
+        if x == y:
+            x  #@
+
+        if x != y:
+            x  #@
+    """)
+
+    for node in (node1, node2):
+        msg = node_info(node)
+        inferred = node.inferred()
+        assert len(inferred) == 1, msg
+        assert inferred[0] is Uninferable, msg
+
+    for node in (node3, node4):
+        msg = node_info(node)
+        inferred = node.inferred()
+        assert len(inferred) == 1, msg
+        assert isinstance(inferred[0], nodes.Const), msg
+        assert inferred[0].value == 3, msg
+
+
+def test_equality_ambiguous_operand():
+    """Test that equality constraint is satisfied when the compared operand has multiple inferred values."""
+    node1, node2 = builder.extract_node("""
+    def f(y = 1):
+        x = 3
+        if x == y:
+            x  #@
+
+        if x != y:
+            x  #@
+    """)
+
+    for node in (node1, node2):
+        msg = node_info(node)
+        inferred = node.inferred()
+        assert len(inferred) == 1, msg
+        assert isinstance(inferred[0], nodes.Const), msg
+        assert inferred[0].value == 3, msg
+
+
+def test_equality_fractions():
+    """Test that equality constraint is satisfied when both operands are fractions."""
+    node1, node2, node3, node4 = builder.extract_node("""
+    from fractions import Fraction
+
+    x = Fraction(1, 3)
+    y = Fraction(1, 3)
+
+    if x == y:
+        x  #@
+        y  #@
+
+    if x != y:
+        x  #@
+        y  #@
+    """)
+
+    for node in (node1, node2, node3, node4):
+        msg = node_info(node)
+        inferred = node.inferred()
+        assert len(inferred) == 1, msg
+        assert isinstance(inferred[0], Instance), msg
+        assert isinstance(inferred[0]._proxied, nodes.ClassDef), msg
+        assert inferred[0]._proxied.name == "Fraction", msg
diff --git a/tests/test_get_relative_base_path.py b/tests/test_get_relative_base_path.py
new file mode 100644
index 0000000..280a725
--- /dev/null
+++ b/tests/test_get_relative_base_path.py
@@ -0,0 +1,119 @@
+# Licensed under the LGPL: https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html
+# For details: https://github.com/pylint-dev/astroid/blob/main/LICENSE
+# Copyright (c) https://github.com/pylint-dev/astroid/blob/main/CONTRIBUTORS.txt
+import os
+import tempfile
+import unittest
+
+from astroid import modutils
+
+
+class TestModUtilsRelativePath(unittest.TestCase):
+
+    def setUp(self):
+        self.cwd = os.getcwd()
+
+    def _run_relative_path_test(self, target, base, expected):
+        if not (target and base):
+            result = None
+        else:
+            base_dir = os.path.join(self.cwd, base)
+            target_path = os.path.join(self.cwd, target)
+            result = modutils._get_relative_base_path(target_path, base_dir)
+        self.assertEqual(result, expected)
+
+    def test_similar_prefixes_no_match(self):
+
+        cases = [
+            ("something", "some", None),
+            ("some-thing", "some", None),
+            ("some2", "some", None),
+            ("somedir", "some", None),
+            ("some_thing", "some", None),
+            ("some.dir", "some", None),
+        ]
+        for target, base, expected in cases:
+            with self.subTest(target=target, base=base):
+                self._run_relative_path_test(target, base, expected)
+
+    def test_valid_subdirectories(self):
+
+        cases = [
+            ("some/sub", "some", ["sub"]),
+            ("some/foo/bar", "some", ["foo", "bar"]),
+            ("some/foo-bar", "some", ["foo-bar"]),
+            ("some/foo/bar-ext", "some/foo", ["bar-ext"]),
+            ("something/sub", "something", ["sub"]),
+        ]
+        for target, base, expected in cases:
+            with self.subTest(target=target, base=base):
+                self._run_relative_path_test(target, base, expected)
+
+    def test_path_format_variations(self):
+
+        cases = [
+            ("some", "some", []),
+            ("some/", "some", []),
+            ("../some", "some", None),
+        ]
+
+        if os.path.isabs("/abs/path"):
+            cases.append(("/abs/path/some", "/abs/path", ["some"]))
+
+        for target, base, expected in cases:
+            with self.subTest(target=target, base=base):
+                self._run_relative_path_test(target, base, expected)
+
+    def test_case_sensitivity(self):
+
+        cases = [
+            ("Some/sub", "some", None if os.path.sep == "/" else ["sub"]),
+            ("some/Sub", "some", ["Sub"]),
+        ]
+        for target, base, expected in cases:
+            with self.subTest(target=target, base=base):
+                self._run_relative_path_test(target, base, expected)
+
+    def test_special_path_components(self):
+
+        cases = [
+            ("some/.hidden", "some", [".hidden"]),
+            ("some/with space", "some", ["with space"]),
+            ("some/unicode_ø", "some", ["unicode_ø"]),
+        ]
+        for target, base, expected in cases:
+            with self.subTest(target=target, base=base):
+                self._run_relative_path_test(target, base, expected)
+
+    def test_nonexistent_paths(self):
+
+        cases = [("nonexistent", "some", None), ("some/sub", "nonexistent", None)]
+        for target, base, expected in cases:
+            with self.subTest(target=target, base=base):
+                self._run_relative_path_test(target, base, expected)
+
+    def test_empty_paths(self):
+
+        cases = [("", "some", None), ("some", "", None), ("", "", None)]
+        for target, base, expected in cases:
+            with self.subTest(target=target, base=base):
+                self._run_relative_path_test(target, base, expected)
+
+    def test_symlink_resolution(self):
+        with tempfile.TemporaryDirectory() as tmpdir:
+            base_dir = os.path.join(tmpdir, "some")
+            os.makedirs(base_dir, exist_ok=True)
+
+            real_file = os.path.join(base_dir, "real.py")
+            with open(real_file, "w", encoding="utf-8") as f:
+                f.write("# dummy content")
+
+            symlink_path = os.path.join(tmpdir, "symlink.py")
+            os.symlink(real_file, symlink_path)
+
+            result = modutils._get_relative_base_path(symlink_path, base_dir)
+            self.assertEqual(result, ["real"])
+
+
+if __name__ == "__main__":
+    unittest.main()
diff --git a/tests/test_group_exceptions.py b/tests/test_group_exceptions.py
index 2ee4143..9680664 100644
--- a/tests/test_group_exceptions.py
+++ b/tests/test_group_exceptions.py
@@ -6,25 +6,30 @@
 import pytest
 
 from astroid import (
-    AssignName,
-    ExceptHandler,
-    For,
-    Name,
-    Try,
     Uninferable,
     bases,
     extract_node,
+    nodes,
 )
 from astroid.const import PY311_PLUS
 from astroid.context import InferenceContext
-from astroid.nodes import Expr, Raise, TryStar
+
+
+@pytest.mark.skipif(not PY311_PLUS, reason="Exception group introduced in Python 3.11")
+def test_group_exceptions_exceptions() -> None:
+    node = extract_node(textwrap.dedent("""
+        try:
+            raise ExceptionGroup('', [TypeError(), TypeError()])
+        except ExceptionGroup as eg:
+            eg.exceptions #@"""))
+
+    inferred = node.inferred()[0]
+    assert isinstance(inferred, nodes.Tuple)
 
 
 @pytest.mark.skipif(not PY311_PLUS, reason="Requires Python 3.11 or higher")
 def test_group_exceptions() -> None:
-    node = extract_node(
-        textwrap.dedent(
-            """
+    node = extract_node(textwrap.dedent("""
         try:
             raise ExceptionGroup("group", [ValueError(654)])
         except ExceptionGroup as eg:
@@ -32,29 +37,26 @@
                 if isinstance(err, ValueError):
                     print("Handling ValueError")
                 elif isinstance(err, TypeError):
-                    print("Handling TypeError")"""
-        )
-    )
-    assert isinstance(node, Try)
+                    print("Handling TypeError")"""))
+    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=5) == (5, 9)
-    assert isinstance(handler, ExceptHandler)
+    assert isinstance(handler, nodes.ExceptHandler)
     assert handler.type.name == "ExceptionGroup"
     children = list(handler.get_children())
     assert len(children) == 3
     exception_group, short_name, for_loop = children
-    assert isinstance(exception_group, Name)
+    assert isinstance(exception_group, nodes.Name)
     assert exception_group.block_range(1) == (1, 4)
-    assert isinstance(short_name, AssignName)
-    assert isinstance(for_loop, For)
+    assert isinstance(short_name, nodes.AssignName)
+    assert isinstance(for_loop, nodes.For)
 
 
 @pytest.mark.skipif(not PY311_PLUS, reason="Requires Python 3.11 or higher")
 def test_star_exceptions() -> None:
-    code = textwrap.dedent(
-        """
+    code = textwrap.dedent("""
     try:
         raise ExceptionGroup("group", [ValueError(654)])
     except* ValueError:
@@ -64,12 +66,11 @@
     else:
         sys.exit(127)
     finally:
-        sys.exit(0)"""
-    )
+        sys.exit(0)""")
     node = extract_node(code)
-    assert isinstance(node, TryStar)
+    assert isinstance(node, nodes.TryStar)
     assert node.as_string() == code.replace('"', "'").strip()
-    assert isinstance(node.body[0], Raise)
+    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(3) == (3, 3)
@@ -83,28 +84,54 @@
     assert node.block_range(11) == (11, 11)
     assert node.handlers
     handler = node.handlers[0]
-    assert isinstance(handler, ExceptHandler)
+    assert isinstance(handler, nodes.ExceptHandler)
     assert handler.type.name == "ValueError"
     orelse = node.orelse[0]
-    assert isinstance(orelse, Expr)
+    assert isinstance(orelse, nodes.Expr)
     assert orelse.value.args[0].value == 127
     final = node.finalbody[0]
-    assert isinstance(final, Expr)
+    assert isinstance(final, nodes.Expr)
     assert final.value.args[0].value == 0
 
 
 @pytest.mark.skipif(not PY311_PLUS, reason="Requires Python 3.11 or higher")
 def test_star_exceptions_infer_name() -> None:
-    trystar = extract_node(
-        """
+    trystar = extract_node("""
 try:
     1/0
 except* ValueError:
-    pass"""
-    )
+    pass""")
     name = "arbitraryName"
     context = InferenceContext()
     context.lookupname = name
     stmts = bases._infer_stmts([trystar], context)
     assert list(stmts) == [Uninferable]
     assert context.lookupname == name
+
+
+@pytest.mark.skipif(not PY311_PLUS, reason="Requires Python 3.11 or higher")
+def test_star_exceptions_infer_exceptions() -> None:
+    code = textwrap.dedent("""
+    try:
+        raise ExceptionGroup("group", [ValueError(654), TypeError(10)])
+    except* ValueError as ve:
+        print(e.exceptions)
+    except* TypeError as te:
+        print(e.exceptions)
+    else:
+        sys.exit(127)
+    finally:
+        sys.exit(0)""")
+    node = extract_node(code)
+    assert isinstance(node, nodes.TryStar)
+    inferred_ve = next(node.handlers[0].statement().name.infer())
+    assert inferred_ve.name == "ExceptionGroup"
+    assert isinstance(inferred_ve.getattr("exceptions")[0], nodes.List)
+    assert (
+        inferred_ve.getattr("exceptions")[0].elts[0].pytype() == "builtins.ValueError"
+    )
+
+    inferred_te = next(node.handlers[1].statement().name.infer())
+    assert inferred_te.name == "ExceptionGroup"
+    assert isinstance(inferred_te.getattr("exceptions")[0], nodes.List)
+    assert inferred_te.getattr("exceptions")[0].elts[0].pytype() == "builtins.TypeError"
diff --git a/tests/test_helpers.py b/tests/test_helpers.py
index 170176f..c927f6c 100644
--- a/tests/test_helpers.py
+++ b/tests/test_helpers.py
@@ -10,8 +10,8 @@
 from astroid import builder, helpers, manager, nodes, raw_building, util
 from astroid.builder import AstroidBuilder
 from astroid.const import IS_PYPY
-from astroid.exceptions import _NonDeducibleTypeHierarchy
-from astroid.nodes.scoped_nodes import ClassDef
+from astroid.exceptions import InferenceError, _NonDeducibleTypeHierarchy
+from astroid.nodes.node_classes import UNATTACHED_UNKNOWN
 
 
 class TestHelpers(unittest.TestCase):
@@ -22,14 +22,14 @@
         self.builtins = astroid_manager.astroid_cache[builtins_name]
         self.manager = manager.AstroidManager()
 
-    def _extract(self, obj_name: str) -> ClassDef:
+    def _extract(self, obj_name: str) -> nodes.ClassDef:
         return self.builtins.getattr(obj_name)[0]
 
-    def _build_custom_builtin(self, obj_name: str) -> ClassDef:
+    def _build_custom_builtin(self, obj_name: str) -> nodes.ClassDef:
         proxy = raw_building.build_class(obj_name, self.builtins)
         return proxy
 
-    def assert_classes_equal(self, cls: ClassDef, other: ClassDef) -> None:
+    def assert_classes_equal(self, cls: nodes.ClassDef, other: nodes.ClassDef) -> None:
         self.assertEqual(cls.name, other.name)
         self.assertEqual(cls.parent, other.parent)
         self.assertEqual(cls.qname(), other.qname())
@@ -55,8 +55,7 @@
             self.assert_classes_equal(objtype, expected)
 
     def test_object_type_classes_and_functions(self) -> None:
-        ast_nodes = builder.extract_node(
-            """
+        ast_nodes = builder.extract_node("""
         def generator():
             yield
 
@@ -76,8 +75,7 @@
         A.static_method #@
         A().static_method #@
         generator() #@
-        """
-        )
+        """)
         assert isinstance(ast_nodes, list)
         from_self = helpers.object_type(ast_nodes[0])
         cls = next(ast_nodes[1].infer())
@@ -105,14 +103,12 @@
             self.assert_classes_equal(node_type, expected_type)
 
     def test_object_type_metaclasses(self) -> None:
-        module = builder.parse(
-            """
+        module = builder.parse("""
         import abc
         class Meta(metaclass=abc.ABCMeta):
             pass
         meta_instance = Meta()
-        """
-        )
+        """)
         meta_type = helpers.object_type(module["Meta"])
         self.assert_classes_equal(meta_type, module["Meta"].metaclass())
 
@@ -121,8 +117,7 @@
         self.assert_classes_equal(instance_type, module["Meta"])
 
     def test_object_type_most_derived(self) -> None:
-        node = builder.extract_node(
-            """
+        node = builder.extract_node("""
         class A(type):
             def __new__(*args, **kwargs):
                  return type.__new__(*args, **kwargs)
@@ -132,8 +127,7 @@
         # The most derived metaclass of D is A rather than type.
         class D(B , C): #@
             pass
-        """
-        )
+        """)
         assert isinstance(node, nodes.NodeNG)
         metaclass = node.metaclass()
         self.assertEqual(metaclass.name, "A")
@@ -141,12 +135,10 @@
         self.assertEqual(metaclass, obj_type)
 
     def test_inference_errors(self) -> None:
-        node = builder.extract_node(
-            """
+        node = builder.extract_node("""
         from unknown import Unknown
         u = Unknown #@
-        """
-        )
+        """)
         self.assertEqual(helpers.object_type(node), util.Uninferable)
 
     @pytest.mark.skipif(IS_PYPY, reason="__code__ will not be Unknown on PyPy")
@@ -155,8 +147,7 @@
         self.assertIs(helpers.object_type(node), util.Uninferable)
 
     def test_object_type_too_many_types(self) -> None:
-        node = builder.extract_node(
-            """
+        node = builder.extract_node("""
         from unknown import Unknown
         def test(x):
             if x:
@@ -164,21 +155,18 @@
             else:
                 return 1
         test(Unknown) #@
-        """
-        )
+        """)
         self.assertEqual(helpers.object_type(node), util.Uninferable)
 
     def test_is_subtype(self) -> None:
-        ast_nodes = builder.extract_node(
-            """
+        ast_nodes = builder.extract_node("""
         class int_subclass(int):
             pass
         class A(object): pass #@
         class B(A): pass #@
         class C(A): pass #@
         int_subclass() #@
-        """
-        )
+        """)
         assert isinstance(ast_nodes, list)
         cls_a = ast_nodes[0]
         cls_b = ast_nodes[1]
@@ -197,16 +185,14 @@
         self.assertFalse(helpers.is_subtype(cls_a, cls_b))
 
     def test_is_subtype_supertype_mro_error(self) -> None:
-        cls_e, cls_f = builder.extract_node(
-            """
+        cls_e, cls_f = builder.extract_node("""
         class A(object): pass
         class B(A): pass
         class C(A): pass
         class D(B, C): pass
         class E(C, B): pass #@
         class F(D, E): pass #@
-        """
-        )
+        """)
         self.assertFalse(helpers.is_subtype(cls_e, cls_f))
 
         self.assertFalse(helpers.is_subtype(cls_e, cls_f))
@@ -215,48 +201,40 @@
         self.assertFalse(helpers.is_supertype(cls_f, cls_e))
 
     def test_is_subtype_supertype_unknown_bases(self) -> None:
-        cls_a, cls_b = builder.extract_node(
-            """
+        cls_a, cls_b = builder.extract_node("""
         from unknown import Unknown
         class A(Unknown): pass #@
         class B(A): pass #@
-        """
-        )
+        """)
         with self.assertRaises(_NonDeducibleTypeHierarchy):
             helpers.is_subtype(cls_a, cls_b)
         with self.assertRaises(_NonDeducibleTypeHierarchy):
             helpers.is_supertype(cls_a, cls_b)
 
     def test_is_subtype_supertype_unrelated_classes(self) -> None:
-        cls_a, cls_b = builder.extract_node(
-            """
+        cls_a, cls_b = builder.extract_node("""
         class A(object): pass #@
         class B(object): pass #@
-        """
-        )
+        """)
         self.assertFalse(helpers.is_subtype(cls_a, cls_b))
         self.assertFalse(helpers.is_subtype(cls_b, cls_a))
         self.assertFalse(helpers.is_supertype(cls_a, cls_b))
         self.assertFalse(helpers.is_supertype(cls_b, cls_a))
 
     def test_is_subtype_supertype_classes_no_type_ancestor(self) -> None:
-        cls_a = builder.extract_node(
-            """
+        cls_a = builder.extract_node("""
         class A(object): #@
             pass
-        """
-        )
+        """)
         builtin_type = self._extract("type")
         self.assertFalse(helpers.is_supertype(builtin_type, cls_a))
         self.assertFalse(helpers.is_subtype(cls_a, builtin_type))
 
     def test_is_subtype_supertype_classes_metaclasses(self) -> None:
-        cls_a = builder.extract_node(
-            """
+        cls_a = builder.extract_node("""
         class A(type): #@
             pass
-        """
-        )
+        """)
         builtin_type = self._extract("type")
         self.assertTrue(helpers.is_supertype(builtin_type, cls_a))
         self.assertTrue(helpers.is_subtype(cls_a, builtin_type))
@@ -269,9 +247,72 @@
 
 def test_safe_infer_shim() -> None:
     with pytest.warns(DeprecationWarning) as records:
-        helpers.safe_infer(nodes.Unknown())
+        helpers.safe_infer(UNATTACHED_UNKNOWN)
 
     assert (
         "Import safe_infer from astroid.util; this shim in astroid.helpers will be removed."
         in records[0].message.args[0]
     )
+
+
+def test_class_to_container() -> None:
+    node = builder.extract_node("""isinstance(3, int)""")
+
+    container = helpers.class_or_tuple_to_container(node.args[1])
+
+    assert len(container) == 1
+    assert isinstance(container[0], nodes.ClassDef)
+    assert container[0].name == "int"
+
+
+def test_tuple_to_container() -> None:
+    node = builder.extract_node("""isinstance(3, (int, str))""")
+
+    container = helpers.class_or_tuple_to_container(node.args[1])
+
+    assert len(container) == 2
+
+    assert isinstance(container[0], nodes.ClassDef)
+    assert container[0].name == "int"
+
+    assert isinstance(container[1], nodes.ClassDef)
+    assert container[1].name == "str"
+
+
+def test_class_to_container_uninferable() -> None:
+    node = builder.extract_node("""
+    def f(x):
+        isinstance(3, x)  #@
+    """)
+
+    container = helpers.class_or_tuple_to_container(node.args[1])
+
+    assert len(container) == 1
+    assert container[0] is util.Uninferable
+
+
+def test_tuple_to_container_uninferable() -> None:
+    node = builder.extract_node("""
+    def f(x, y):
+        isinstance(3, (x, y))  #@
+    """)
+
+    container = helpers.class_or_tuple_to_container(node.args[1])
+
+    assert len(container) == 2
+    assert container[0] is util.Uninferable
+    assert container[1] is util.Uninferable
+
+
+def test_class_to_container_inference_error() -> None:
+    node = builder.extract_node("""isinstance(3, undefined_type)""")
+
+    with pytest.raises(InferenceError):
+        helpers.class_or_tuple_to_container(node.args[1])
+
+
+def test_tuple_to_container_inference_error() -> None:
+    node = builder.extract_node("""isinstance(3, (int, undefined_type))""")
+
+    with pytest.raises(InferenceError):
+        helpers.class_or_tuple_to_container(node.args[1])
diff --git a/tests/test_inference.py b/tests/test_inference.py
index 8184167..024ad85 100644
--- a/tests/test_inference.py
+++ b/tests/test_inference.py
@@ -19,9 +19,6 @@
 import pytest
 
 from astroid import (
-    Assign,
-    Const,
-    Slice,
     Uninferable,
     arguments,
     manager,
@@ -34,7 +31,7 @@
 from astroid.arguments import CallSite
 from astroid.bases import BoundMethod, Generator, Instance, UnboundMethod, UnionType
 from astroid.builder import AstroidBuilder, _extract_single_node, extract_node, parse
-from astroid.const import IS_PYPY, PY310_PLUS, PY312_PLUS
+from astroid.const import IS_PYPY, PY312_PLUS, PY314_PLUS
 from astroid.context import CallContext, InferenceContext
 from astroid.exceptions import (
     AstroidTypeError,
@@ -71,7 +68,7 @@
             raise InferenceError
 
         infer_default = decoratorsmod.path_wrapper(infer_default)
-        infer_end = decoratorsmod.path_wrapper(Slice._infer)
+        infer_end = decoratorsmod.path_wrapper(nodes.Slice._infer)
         with self.assertRaises(InferenceError):
             next(infer_default(1))
         self.assertEqual(next(infer_end(1)), 1)
@@ -151,13 +148,11 @@
     ast = parse(CODE, __name__)
 
     def test_arg_keyword_no_default_value(self):
-        node = extract_node(
-            """
+        node = extract_node("""
         class Sensor:
             def __init__(self, *, description): #@
                 self._id = description.key
-        """
-        )
+        """)
         with self.assertRaises(NoDefault):
             node.args.default_value("description")
 
@@ -166,8 +161,7 @@
             node.args.default_value("name")
 
     def test_infer_abstract_property_return_values(self) -> None:
-        module = parse(
-            """
+        module = parse("""
         import abc
 
         class A(object):
@@ -177,8 +171,7 @@
 
         a = A()
         x = a.test
-        """
-        )
+        """)
         inferred = next(module["x"].infer())
         self.assertIsInstance(inferred, nodes.Const)
         self.assertEqual(inferred.value, 42)
@@ -665,7 +658,7 @@
         inferred = node.inferred()
         self.assertEqual(len(inferred), 1)
         value_node = inferred[0]
-        self.assertIsInstance(value_node, Const)
+        self.assertIsInstance(value_node, nodes.Const)
         self.assertEqual(value_node.value, "Hello John!")
 
     def test_float_complex_ambiguity(self) -> None:
@@ -724,8 +717,7 @@
             self.assertEqual(inferred.value, expected_value)
 
     def test_invalid_subscripts(self) -> None:
-        ast_nodes = extract_node(
-            """
+        ast_nodes = extract_node("""
         class NoGetitem(object):
             pass
         class InvalidGetitem(object):
@@ -737,8 +729,7 @@
         InvalidGetitem2()[10] #@
         [1, 2, 3][None] #@
         'lala'['bala'] #@
-        """
-        )
+        """)
         for node in ast_nodes:
             self.assertRaises(InferenceError, next, node.infer())
 
@@ -783,13 +774,11 @@
         self.assertEqual(list(sorted(values)), [2, 3])
 
     def test_simple_tuple(self) -> None:
-        module = parse(
-            """
+        module = parse("""
         a = (1,)
         b = (22,)
         some = a + b #@
-        """
-        )
+        """)
         ast = next(module["some"].infer())
         self.assertIsInstance(ast, nodes.Tuple)
         self.assertEqual(len(ast.elts), 2)
@@ -993,14 +982,12 @@
         reason="pathlib.Path cannot be inferred on Python 3.8",
     )
     def test_factory_methods_inside_binary_operation(self):
-        node = extract_node(
-            """
+        node = extract_node("""
         from pathlib import Path
         h = Path("/home")
         u = h / "user"
         u #@
-        """
-        )
+        """)
         assert next(node.infer()).qname() == "pathlib.Path"
 
     def test_import_as(self) -> None:
@@ -1057,29 +1044,25 @@
             self._test_const_inferred(ast["b"], True)
 
     def test_unary_op_numbers(self) -> None:
-        ast_nodes = extract_node(
-            """
+        ast_nodes = extract_node("""
         +1 #@
         -1 #@
         ~1 #@
         +2.0 #@
         -2.0 #@
-        """
-        )
+        """)
         expected = [1, -1, -2, 2.0, -2.0]
         for node, expected_value in zip(ast_nodes, expected):
             inferred = next(node.infer())
             self.assertEqual(inferred.value, expected_value)
 
     def test_matmul(self) -> None:
-        node = extract_node(
-            """
+        node = extract_node("""
         class Array:
             def __matmul__(self, other):
                 return 42
         Array() @ Array() #@
-        """
-        )
+        """)
         inferred = next(node.infer())
         self.assertIsInstance(inferred, nodes.Const)
         self.assertEqual(inferred.value, 42)
@@ -1121,15 +1104,13 @@
         self._test_const_inferred(ast["a"], 23 << 1)
 
     def test_binary_op_other_type(self) -> None:
-        ast_nodes = extract_node(
-            """
+        ast_nodes = extract_node("""
         class A:
             def __add__(self, other):
                 return other + 42
         A() + 1 #@
         1 + A() #@
-        """
-        )
+        """)
         assert isinstance(ast_nodes, list)
         first = next(ast_nodes[0].infer())
         self.assertIsInstance(first, nodes.Const)
@@ -1139,15 +1120,13 @@
         self.assertEqual(second, util.Uninferable)
 
     def test_binary_op_other_type_using_reflected_operands(self) -> None:
-        ast_nodes = extract_node(
-            """
+        ast_nodes = extract_node("""
         class A(object):
             def __radd__(self, other):
                 return other + 42
         A() + 1 #@
         1 + A() #@
-        """
-        )
+        """)
         assert isinstance(ast_nodes, list)
         first = next(ast_nodes[0].infer())
         self.assertEqual(first, util.Uninferable)
@@ -1157,14 +1136,12 @@
         self.assertEqual(second.value, 43)
 
     def test_binary_op_reflected_and_not_implemented_is_type_error(self) -> None:
-        ast_node = extract_node(
-            """
+        ast_node = extract_node("""
         class A(object):
             def __radd__(self, other): return NotImplemented
 
         1 + A() #@
-        """
-        )
+        """)
         first = next(ast_node.infer())
         self.assertEqual(first, util.Uninferable)
 
@@ -1292,57 +1269,57 @@
         tuple | int  #@
         """
         ast_nodes = extract_node(code)
-        if not PY310_PLUS:
-            for n in ast_nodes:
-                assert n.inferred() == [util.Uninferable]
-        else:
-            i0 = ast_nodes[0].inferred()[0]
-            assert isinstance(i0, UnionType)
-            assert isinstance(i0.left, nodes.ClassDef)
-            assert i0.left.name == "int"
-            assert isinstance(i0.right, nodes.Const)
-            assert i0.right.value is None
+        i0 = ast_nodes[0].inferred()[0]
+        assert isinstance(i0, UnionType)
+        assert isinstance(i0.left, nodes.ClassDef)
+        assert i0.left.name == "int"
+        assert isinstance(i0.right, nodes.Const)
+        assert i0.right.value is None
 
-            # Assert basic UnionType properties and methods
-            assert i0.callable() is False
-            assert i0.bool_value() is True
-            assert i0.pytype() == "types.UnionType"
-            assert i0.display_type() == "UnionType"
+        # Assert basic UnionType properties and methods
+        assert i0.callable() is False
+        assert i0.bool_value() is True
+        assert i0.pytype() == "types.UnionType"
+        assert i0.display_type() == "UnionType"
+        if PY314_PLUS:
+            assert str(i0) == "UnionType(Union)"
+            assert repr(i0) == f"<UnionType(Union) l.0 at 0x{id(i0)}>"
+        else:
             assert str(i0) == "UnionType(UnionType)"
             assert repr(i0) == f"<UnionType(UnionType) l.0 at 0x{id(i0)}>"
 
-            i1 = ast_nodes[1].inferred()[0]
-            assert isinstance(i1, UnionType)
+        i1 = ast_nodes[1].inferred()[0]
+        assert isinstance(i1, UnionType)
 
-            i2 = ast_nodes[2].inferred()[0]
-            assert isinstance(i2, UnionType)
-            assert isinstance(i2.left, UnionType)
-            assert isinstance(i2.left.left, nodes.ClassDef)
-            assert i2.left.left.name == "int"
-            assert isinstance(i2.left.right, nodes.ClassDef)
-            assert i2.left.right.name == "str"
-            assert isinstance(i2.right, nodes.Const)
-            assert i2.right.value is None
+        i2 = ast_nodes[2].inferred()[0]
+        assert isinstance(i2, UnionType)
+        assert isinstance(i2.left, UnionType)
+        assert isinstance(i2.left.left, nodes.ClassDef)
+        assert i2.left.left.name == "int"
+        assert isinstance(i2.left.right, nodes.ClassDef)
+        assert i2.left.right.name == "str"
+        assert isinstance(i2.right, nodes.Const)
+        assert i2.right.value is None
 
-            i3 = ast_nodes[3].inferred()[0]
-            assert isinstance(i3, UnionType)
-            assert isinstance(i3.left, nodes.ClassDef)
-            assert i3.left.name == "A"
-            assert isinstance(i3.right, nodes.ClassDef)
-            assert i3.right.name == "B"
+        i3 = ast_nodes[3].inferred()[0]
+        assert isinstance(i3, UnionType)
+        assert isinstance(i3.left, nodes.ClassDef)
+        assert i3.left.name == "A"
+        assert isinstance(i3.right, nodes.ClassDef)
+        assert i3.right.name == "B"
 
-            i4 = ast_nodes[4].inferred()[0]
-            assert isinstance(i4, UnionType)
+        i4 = ast_nodes[4].inferred()[0]
+        assert isinstance(i4, UnionType)
 
-            i5 = ast_nodes[5].inferred()[0]
-            assert isinstance(i5, UnionType)
-            assert isinstance(i5.left, nodes.ClassDef)
-            assert i5.left.name == "List"
+        i5 = ast_nodes[5].inferred()[0]
+        assert isinstance(i5, UnionType)
+        assert isinstance(i5.left, nodes.ClassDef)
+        assert i5.left.name == "List"
 
-            i6 = ast_nodes[6].inferred()[0]
-            assert isinstance(i6, UnionType)
-            assert isinstance(i6.left, nodes.ClassDef)
-            assert i6.left.name == "tuple"
+        i6 = ast_nodes[6].inferred()[0]
+        assert isinstance(i6, UnionType)
+        assert isinstance(i6.left, nodes.ClassDef)
+        assert i6.left.name == "tuple"
 
         code = """
         from typing import List
@@ -1355,26 +1332,22 @@
         Alias1 | Alias2  #@
         """
         ast_nodes = extract_node(code)
-        if not PY310_PLUS:
-            for n in ast_nodes:
-                assert n.inferred() == [util.Uninferable]
-        else:
-            i0 = ast_nodes[0].inferred()[0]
-            assert isinstance(i0, UnionType)
-            assert isinstance(i0.left, nodes.ClassDef)
-            assert i0.left.name == "List"
+        i0 = ast_nodes[0].inferred()[0]
+        assert isinstance(i0, UnionType)
+        assert isinstance(i0.left, nodes.ClassDef)
+        assert i0.left.name == "List"
 
-            i1 = ast_nodes[1].inferred()[0]
-            assert isinstance(i1, UnionType)
-            assert isinstance(i1.left, UnionType)
-            assert isinstance(i1.left.left, nodes.ClassDef)
-            assert i1.left.left.name == "str"
+        i1 = ast_nodes[1].inferred()[0]
+        assert isinstance(i1, UnionType)
+        assert isinstance(i1.left, UnionType)
+        assert isinstance(i1.left.left, nodes.ClassDef)
+        assert i1.left.left.name == "str"
 
-            i2 = ast_nodes[2].inferred()[0]
-            assert isinstance(i2, UnionType)
-            assert isinstance(i2.left, nodes.ClassDef)
-            assert i2.left.name == "List"
-            assert isinstance(i2.right, UnionType)
+        i2 = ast_nodes[2].inferred()[0]
+        assert isinstance(i2, UnionType)
+        assert isinstance(i2.left, nodes.ClassDef)
+        assert i2.left.name == "List"
+        assert isinstance(i2.right, UnionType)
 
     def test_nonregr_lambda_arg(self) -> None:
         code = """
@@ -1510,7 +1483,7 @@
 
     def test_python25_no_relative_import(self) -> None:
         ast = resources.build_file("data/package/absimport.py")
-        self.assertTrue(ast.absolute_import_activated(), True)
+        self.assertTrue(ast.absolute_import_activated())
         inferred = next(
             test_utils.get_name_node(ast, "import_package_subpackage_module").infer()
         )
@@ -1519,7 +1492,7 @@
 
     def test_nonregr_absolute_import(self) -> None:
         ast = resources.build_file("data/absimp/string.py", "data.absimp.string")
-        self.assertTrue(ast.absolute_import_activated(), True)
+        self.assertTrue(ast.absolute_import_activated())
         inferred = next(test_utils.get_name_node(ast, "string").infer())
         self.assertIsInstance(inferred, nodes.Module)
         self.assertEqual(inferred.name, "string")
@@ -1679,12 +1652,10 @@
         self.assertEqual(len(inferred), 1, inferred)
 
     def test__new__bound_methods(self) -> None:
-        node = extract_node(
-            """
+        node = extract_node("""
         class cls(object): pass
         cls().__new__(cls) #@
-        """
-        )
+        """)
         inferred = next(node.infer())
         self.assertIsInstance(inferred, Instance)
         self.assertEqual(inferred._proxied, node.root()["cls"])
@@ -1884,12 +1855,11 @@
         self.assertEqual(node.type, "function")
 
     @pytest.mark.skipif(
-        IS_PYPY and PY310_PLUS,
+        IS_PYPY,
         reason="Persistent recursion error that we ignore and never fix",
     )
     def test_no_infinite_ancestor_loop(self) -> None:
-        klass = extract_node(
-            """
+        klass = extract_node("""
             import datetime
 
             def method(self):
@@ -1897,8 +1867,7 @@
 
             class something(datetime.datetime):  #@
                 pass
-        """
-        )
+        """)
         ancestors = [base.name for base in klass.ancestors()]
         expected_subset = ["datetime", "date"]
         self.assertEqual(expected_subset, ancestors[:2])
@@ -2029,8 +1998,7 @@
         )
 
     def test_starred_in_mapping_literal_no_inference_possible(self) -> None:
-        node = extract_node(
-            """
+        node = extract_node("""
         from unknown import unknown
 
         def test(a):
@@ -2041,8 +2009,7 @@
             return {0: 1, **a}
 
         test(**func())
-        """
-        )
+        """)
         self.assertEqual(next(node.infer()), util.Uninferable)
 
     def test_starred_in_mapping_inference_issues(self) -> None:
@@ -2161,15 +2128,13 @@
             self.assertEqual(inferred.qname(), "builtins.list")
 
     def test_conversion_of_dict_methods(self) -> None:
-        ast_nodes = extract_node(
-            """
+        ast_nodes = extract_node("""
         list({1:2, 2:3}.values()) #@
         list({1:2, 2:3}.keys()) #@
         tuple({1:2, 2:3}.values()) #@
         tuple({1:2, 3:4}.keys()) #@
         set({1:2, 2:4}.keys()) #@
-        """
-        )
+        """)
         assert isinstance(ast_nodes, list)
         self.assertInferList(ast_nodes[0], [2, 3])
         self.assertInferList(ast_nodes[1], [1, 2])
@@ -2381,8 +2346,7 @@
         self.assertEqual(inferred.qname(), "collections.Counter")
 
     def test_inferring_with_statement_failures(self) -> None:
-        module = parse(
-            """
+        module = parse("""
         class NoEnter(object):
             pass
         class NoMethod(object):
@@ -2397,15 +2361,13 @@
             pass
         with NoElts() as (no_elts, no_elts1):
             pass
-        """
-        )
+        """)
         self.assertRaises(InferenceError, next, module["no_enter"].infer())
         self.assertRaises(InferenceError, next, module["no_method"].infer())
         self.assertRaises(InferenceError, next, module["no_elts"].infer())
 
     def test_inferring_with_statement(self) -> None:
-        module = parse(
-            """
+        module = parse("""
         class SelfContext(object):
             def __enter__(self):
                 return self
@@ -2430,8 +2392,7 @@
             pass
         with MultipleReturns2() as (stdout, (stderr, stdin)):
             pass
-        """
-        )
+        """)
         self_context = module["self_context"]
         inferred = next(self_context.infer())
         self.assertIsInstance(inferred, Instance)
@@ -2457,8 +2418,7 @@
         self.assertEqual(inferred.value, 2)
 
     def test_inferring_with_contextlib_contextmanager(self) -> None:
-        module = parse(
-            """
+        module = parse("""
         import contextlib
         from contextlib import contextmanager
 
@@ -2489,8 +2449,7 @@
             pass
         with manager_multiple() as (first, second):
             pass
-        """
-        )
+        """)
         none = module["none"]
         inferred = next(none.infer())
         self.assertIsInstance(inferred, nodes.Const)
@@ -2517,21 +2476,18 @@
         # indices. This is the case of contextlib.nested, where the
         # result is a list, which is mutated later on, so it's
         # undetected by astroid.
-        module = parse(
-            """
+        module = parse("""
         class Manager(object):
             def __enter__(self):
                 return []
         with Manager() as (a, b, c):
             pass
-        """
-        )
+        """)
         self.assertRaises(InferenceError, next, module["a"].infer())
 
     def test_inferring_context_manager_unpacking_inference_error(self) -> None:
         # https://github.com/pylint-dev/pylint/issues/1463
-        module = parse(
-            """
+        module = parse("""
         import contextlib
 
         @contextlib.contextmanager
@@ -2542,13 +2498,11 @@
         result = _select_source()
         with result as (a, b, c):
             pass
-        """
-        )
+        """)
         self.assertRaises(InferenceError, next, module["a"].infer())
 
     def test_inferring_with_contextlib_contextmanager_failures(self) -> None:
-        module = parse(
-            """
+        module = parse("""
         from contextlib import contextmanager
 
         def no_decorators_mgr():
@@ -2566,8 +2520,7 @@
             pass
         with no_yield_mgr() as no_yield:
             pass
-        """
-        )
+        """)
         self.assertRaises(InferenceError, next, module["no_decorators"].infer())
         self.assertRaises(InferenceError, next, module["other_decorators"].infer())
         self.assertRaises(InferenceError, next, module["no_yield"].infer())
@@ -2607,8 +2560,7 @@
         self.assertEqual(util.Uninferable, next(node.infer()))
 
     def test_unary_operands(self) -> None:
-        ast_nodes = extract_node(
-            """
+        ast_nodes = extract_node("""
         import os
         def func(): pass
         from missing import missing
@@ -2661,8 +2613,7 @@
         ~os #@
         -func #@
         +BadInstance #@
-        """
-        )
+        """)
         expected = [42, 1, 42, -1, 24, 25, 42, 1, 43]
         for node, value in zip(ast_nodes[:9], expected):
             inferred = next(node.infer())
@@ -2674,18 +2625,15 @@
             self.assertEqual(inferred, util.Uninferable)
 
     def test_unary_op_instance_method_not_callable(self) -> None:
-        ast_node = extract_node(
-            """
+        ast_node = extract_node("""
         class A:
             __pos__ = (i for i in range(10))
         +A() #@
-        """
-        )
+        """)
         self.assertRaises(InferenceError, next, ast_node.infer())
 
     def test_binary_op_type_errors(self) -> None:
-        ast_nodes = extract_node(
-            """
+        ast_nodes = extract_node("""
         import collections
         1 + "a" #@
         1 - [] #@
@@ -2727,8 +2675,7 @@
         f+=A() #@
         x = 1
         x+=[] #@
-        """
-        )
+        """)
         msg = "unsupported operand type(s) for {op}: {lhs!r} and {rhs!r}"
         expected = [
             msg.format(op="+", lhs="int", rhs="str"),
@@ -2769,8 +2716,7 @@
         self.assertEqual(errors, [])
 
     def test_unary_type_errors(self) -> None:
-        ast_nodes = extract_node(
-            """
+        ast_nodes = extract_node("""
         import collections
         ~[] #@
         ~() #@
@@ -2787,8 +2733,7 @@
         ~A() #@
         ~collections #@
         ~2.0 #@
-        """
-        )
+        """)
         msg = "bad operand type for unary {op}: {type}"
         expected = [
             msg.format(op="~", type="list"),
@@ -2814,12 +2759,10 @@
 
     def test_unary_empty_type_errors(self) -> None:
         # These aren't supported right now
-        ast_nodes = extract_node(
-            """
+        ast_nodes = extract_node("""
         ~(2 and []) #@
         -(0 or {}) #@
-        """
-        )
+        """)
         expected = [
             "bad operand type for unary ~: list",
             "bad operand type for unary -: dict",
@@ -2865,19 +2808,16 @@
         self.assertTrue(node.bool_value())
 
     def test_name_bool_value(self) -> None:
-        node = extract_node(
-            """
+        node = extract_node("""
         x = 42
         y = x
         y
-        """
-        )
+        """)
         self.assertIs(node.bool_value(), util.Uninferable)
 
     def test_bool_value(self) -> None:
         # Verify the truth value of nodes.
-        module = parse(
-            """
+        module = parse("""
         import collections
         collections_module = collections
         def function(): pass
@@ -2902,8 +2842,7 @@
         compare = 2 < 3
         const_str_true = 'testconst'
         const_str_false = ''
-        """
-        )
+        """)
         collections_module = next(module["collections_module"].infer())
         self.assertTrue(collections_module.bool_value())
         function = module["function"]
@@ -2936,8 +2875,7 @@
         self.assertEqual(compare.bool_value(), util.Uninferable)
 
     def test_bool_value_instances(self) -> None:
-        instances = extract_node(
-            """
+        instances = extract_node("""
         class FalseBoolInstance(object):
             def __bool__(self):
                 return False
@@ -2966,16 +2904,14 @@
         TrueLenInstance() #@
         AlwaysTrueInstance() #@
         ErrorInstance() #@
-        """
-        )
+        """)
         expected = (False, True, False, True, True, util.Uninferable, util.Uninferable)
         for node, expected_value in zip(instances, expected):
             inferred = next(node.infer())
             self.assertEqual(inferred.bool_value(), expected_value)
 
     def test_bool_value_variable(self) -> None:
-        instance = extract_node(
-            """
+        instance = extract_node("""
         class VariableBoolInstance(object):
             def __init__(self, value):
                 self.value = value
@@ -2983,14 +2919,20 @@
                 return self.value
 
         not VariableBoolInstance(True)
-        """
-        )
+        """)
         inferred = next(instance.infer())
         self.assertIs(inferred.bool_value(), util.Uninferable)
 
+    def test_bool_value_not_implemented(self) -> None:
+        node = extract_node("""NotImplemented""")
+        inferred = next(node.infer())
+        if PY314_PLUS:
+            self.assertIs(inferred.bool_value(), util.Uninferable)
+        else:
+            self.assertIs(inferred.bool_value(), True)
+
     def test_infer_coercion_rules_for_floats_complex(self) -> None:
-        ast_nodes = extract_node(
-            """
+        ast_nodes = extract_node("""
         1 + 1.0 #@
         1 * 1.0 #@
         2 - 1.0 #@
@@ -2999,20 +2941,17 @@
         2 * 1j #@
         2 - 1j #@
         3 / 1j #@
-        """
-        )
+        """)
         expected_values = [2.0, 1.0, 1.0, 1.0, 1 + 1j, 2j, 2 - 1j, -3j]
         for node, expected in zip(ast_nodes, expected_values):
             inferred = next(node.infer())
             self.assertEqual(inferred.value, expected)
 
     def test_binop_list_with_elts(self) -> None:
-        ast_node = extract_node(
-            """
+        ast_node = extract_node("""
         x = [A] * 1
         [1] + x
-        """
-        )
+        """)
         inferred = next(ast_node.infer())
         self.assertIsInstance(inferred, nodes.List)
         self.assertEqual(len(inferred.elts), 2)
@@ -3020,8 +2959,7 @@
         self.assertIsInstance(inferred.elts[1], nodes.Unknown)
 
     def test_binop_same_types(self) -> None:
-        ast_nodes = extract_node(
-            """
+        ast_nodes = extract_node("""
         class A(object):
             def __add__(self, other):
                 return 42
@@ -3029,8 +2967,7 @@
         1 - 1 #@
         "a" + "b" #@
         A() + A() #@
-        """
-        )
+        """)
         expected_values = [2, 0, "ab", 42]
         for node, expected in zip(ast_nodes, expected_values):
             inferred = next(node.infer())
@@ -3038,23 +2975,20 @@
             self.assertEqual(inferred.value, expected)
 
     def test_binop_different_types_reflected_only(self) -> None:
-        node = extract_node(
-            """
+        node = extract_node("""
         class A(object):
             pass
         class B(object):
             def __radd__(self, other):
                 return other
         A() + B() #@
-        """
-        )
+        """)
         inferred = next(node.infer())
         self.assertIsInstance(inferred, Instance)
         self.assertEqual(inferred.name, "A")
 
     def test_binop_different_types_unknown_bases(self) -> None:
-        node = extract_node(
-            """
+        node = extract_node("""
         from foo import bar
 
         class A(bar):
@@ -3063,14 +2997,12 @@
             def __radd__(self, other):
                 return other
         A() + B() #@
-        """
-        )
+        """)
         inferred = next(node.infer())
         self.assertIs(inferred, util.Uninferable)
 
     def test_binop_different_types_normal_not_implemented_and_reflected(self) -> None:
-        node = extract_node(
-            """
+        node = extract_node("""
         class A(object):
             def __add__(self, other):
                 return NotImplemented
@@ -3078,94 +3010,80 @@
             def __radd__(self, other):
                 return other
         A() + B() #@
-        """
-        )
+        """)
         inferred = next(node.infer())
         self.assertIsInstance(inferred, Instance)
         self.assertEqual(inferred.name, "A")
 
     def test_binop_different_types_no_method_implemented(self) -> None:
-        node = extract_node(
-            """
+        node = extract_node("""
         class A(object):
             pass
         class B(object): pass
         A() + B() #@
-        """
-        )
+        """)
         inferred = next(node.infer())
         self.assertEqual(inferred, util.Uninferable)
 
     def test_binop_different_types_reflected_and_normal_not_implemented(self) -> None:
-        node = extract_node(
-            """
+        node = extract_node("""
         class A(object):
             def __add__(self, other): return NotImplemented
         class B(object):
             def __radd__(self, other): return NotImplemented
         A() + B() #@
-        """
-        )
+        """)
         inferred = next(node.infer())
         self.assertEqual(inferred, util.Uninferable)
 
     def test_binop_subtype(self) -> None:
-        node = extract_node(
-            """
+        node = extract_node("""
         class A(object): pass
         class B(A):
             def __add__(self, other): return other
         B() + A() #@
-        """
-        )
+        """)
         inferred = next(node.infer())
         self.assertIsInstance(inferred, Instance)
         self.assertEqual(inferred.name, "A")
 
     def test_binop_subtype_implemented_in_parent(self) -> None:
-        node = extract_node(
-            """
+        node = extract_node("""
         class A(object):
             def __add__(self, other): return other
         class B(A): pass
         B() + A() #@
-        """
-        )
+        """)
         inferred = next(node.infer())
         self.assertIsInstance(inferred, Instance)
         self.assertEqual(inferred.name, "A")
 
     def test_binop_subtype_not_implemented(self) -> None:
-        node = extract_node(
-            """
+        node = extract_node("""
         class A(object):
             pass
         class B(A):
             def __add__(self, other): return NotImplemented
         B() + A() #@
-        """
-        )
+        """)
         inferred = next(node.infer())
         self.assertEqual(inferred, util.Uninferable)
 
     def test_binop_supertype(self) -> None:
-        node = extract_node(
-            """
+        node = extract_node("""
         class A(object):
             pass
         class B(A):
             def __radd__(self, other):
                  return other
         A() + B() #@
-        """
-        )
+        """)
         inferred = next(node.infer())
         self.assertIsInstance(inferred, Instance)
         self.assertEqual(inferred.name, "A")
 
     def test_binop_supertype_rop_not_implemented(self) -> None:
-        node = extract_node(
-            """
+        node = extract_node("""
         class A(object):
             def __add__(self, other):
                 return other
@@ -3173,29 +3091,25 @@
             def __radd__(self, other):
                  return NotImplemented
         A() + B() #@
-        """
-        )
+        """)
         inferred = next(node.infer())
         self.assertIsInstance(inferred, Instance)
         self.assertEqual(inferred.name, "B")
 
     def test_binop_supertype_both_not_implemented(self) -> None:
-        node = extract_node(
-            """
+        node = extract_node("""
         class A(object):
             def __add__(self): return NotImplemented
         class B(A):
             def __radd__(self, other):
                  return NotImplemented
         A() + B() #@
-        """
-        )
+        """)
         inferred = next(node.infer())
         self.assertEqual(inferred, util.Uninferable)
 
     def test_binop_inference_errors(self) -> None:
-        ast_nodes = extract_node(
-            """
+        ast_nodes = extract_node("""
         from unknown import Unknown
         class A(object):
            def __add__(self, other): return NotImplemented
@@ -3205,14 +3119,12 @@
         Unknown + A() #@
         B() + A() #@
         A() + B() #@
-        """
-        )
+        """)
         for node in ast_nodes:
             self.assertEqual(next(node.infer()), util.Uninferable)
 
     def test_binop_ambiguity(self) -> None:
-        ast_nodes = extract_node(
-            """
+        ast_nodes = extract_node("""
         class A(object):
            def __add__(self, other):
                if isinstance(other, B):
@@ -3230,8 +3142,7 @@
         B() + A() #@
         A() + C() #@
         C() + A() #@
-        """
-        )
+        """)
         for node in ast_nodes:
             self.assertEqual(next(node.infer()), util.Uninferable)
 
@@ -3240,8 +3151,7 @@
 
         Reported in https://github.com/pylint-dev/pylint/issues/4826.
         """
-        ast_nodes = extract_node(
-            """
+        ast_nodes = extract_node("""
         class A:
             def __init__(self):
                 for a in [self] + []:
@@ -3251,8 +3161,7 @@
             def __init__(self):
                 for b in [] + [self]:
                     print(b) #@
-        """
-        )
+        """)
         inferred_a = list(ast_nodes[0].args[0].infer())
         self.assertEqual(len(inferred_a), 1)
         self.assertIsInstance(inferred_a[0], Instance)
@@ -3264,8 +3173,7 @@
         self.assertEqual(inferred_b[0]._proxied.name, "B")
 
     def test_metaclass__getitem__(self) -> None:
-        ast_node = extract_node(
-            """
+        ast_node = extract_node("""
         class Meta(type):
             def __getitem__(cls, arg):
                 return 24
@@ -3273,16 +3181,14 @@
             pass
 
         A['Awesome'] #@
-        """
-        )
+        """)
         inferred = next(ast_node.infer())
         self.assertIsInstance(inferred, nodes.Const)
         self.assertEqual(inferred.value, 24)
 
     @unittest.skipUnless(HAS_SIX, "These tests require the six library")
     def test_with_metaclass__getitem__(self):
-        ast_node = extract_node(
-            """
+        ast_node = extract_node("""
         class Meta(type):
             def __getitem__(cls, arg):
                 return 24
@@ -3291,15 +3197,13 @@
             pass
 
         A['Awesome'] #@
-        """
-        )
+        """)
         inferred = next(ast_node.infer())
         self.assertIsInstance(inferred, nodes.Const)
         self.assertEqual(inferred.value, 24)
 
     def test_bin_op_classes(self) -> None:
-        ast_node = extract_node(
-            """
+        ast_node = extract_node("""
         class Meta(type):
             def __or__(self, other):
                 return 24
@@ -3307,16 +3211,14 @@
             pass
 
         A | A
-        """
-        )
+        """)
         inferred = next(ast_node.infer())
         self.assertIsInstance(inferred, nodes.Const)
         self.assertEqual(inferred.value, 24)
 
     @unittest.skipUnless(HAS_SIX, "These tests require the six library")
     def test_bin_op_classes_with_metaclass(self):
-        ast_node = extract_node(
-            """
+        ast_node = extract_node("""
         class Meta(type):
             def __or__(self, other):
                 return 24
@@ -3325,15 +3227,13 @@
             pass
 
         A | A
-        """
-        )
+        """)
         inferred = next(ast_node.infer())
         self.assertIsInstance(inferred, nodes.Const)
         self.assertEqual(inferred.value, 24)
 
     def test_bin_op_supertype_more_complicated_example(self) -> None:
-        ast_node = extract_node(
-            """
+        ast_node = extract_node("""
         class A(object):
             def __init__(self):
                 self.foo = 42
@@ -3347,53 +3247,45 @@
             return NotImplemented
 
         A() + B() #@
-        """
-        )
+        """)
         inferred = next(ast_node.infer())
         self.assertIsInstance(inferred, nodes.Const)
         self.assertEqual(int(inferred.value), 45)
 
     def test_aug_op_same_type_not_implemented(self) -> None:
-        ast_node = extract_node(
-            """
+        ast_node = extract_node("""
         class A(object):
             def __iadd__(self, other): return NotImplemented
             def __add__(self, other): return NotImplemented
         A() + A() #@
-        """
-        )
+        """)
         self.assertEqual(next(ast_node.infer()), util.Uninferable)
 
     def test_aug_op_same_type_aug_implemented(self) -> None:
-        ast_node = extract_node(
-            """
+        ast_node = extract_node("""
         class A(object):
             def __iadd__(self, other): return other
         f = A()
         f += A() #@
-        """
-        )
+        """)
         inferred = next(ast_node.infer())
         self.assertIsInstance(inferred, Instance)
         self.assertEqual(inferred.name, "A")
 
     def test_aug_op_same_type_aug_not_implemented_normal_implemented(self) -> None:
-        ast_node = extract_node(
-            """
+        ast_node = extract_node("""
         class A(object):
             def __iadd__(self, other): return NotImplemented
             def __add__(self, other): return 42
         f = A()
         f += A() #@
-        """
-        )
+        """)
         inferred = next(ast_node.infer())
         self.assertIsInstance(inferred, nodes.Const)
         self.assertEqual(inferred.value, 42)
 
     def test_aug_op_subtype_both_not_implemented(self) -> None:
-        ast_node = extract_node(
-            """
+        ast_node = extract_node("""
         class A(object):
             def __iadd__(self, other): return NotImplemented
             def __add__(self, other): return NotImplemented
@@ -3401,83 +3293,71 @@
             pass
         b = B()
         b+=A() #@
-        """
-        )
+        """)
         self.assertEqual(next(ast_node.infer()), util.Uninferable)
 
     def test_aug_op_subtype_aug_op_is_implemented(self) -> None:
-        ast_node = extract_node(
-            """
+        ast_node = extract_node("""
         class A(object):
             def __iadd__(self, other): return 42
         class B(A):
             pass
         b = B()
         b+=A() #@
-        """
-        )
+        """)
         inferred = next(ast_node.infer())
         self.assertIsInstance(inferred, nodes.Const)
         self.assertEqual(inferred.value, 42)
 
     def test_aug_op_subtype_normal_op_is_implemented(self) -> None:
-        ast_node = extract_node(
-            """
+        ast_node = extract_node("""
         class A(object):
             def __add__(self, other): return 42
         class B(A):
             pass
         b = B()
         b+=A() #@
-        """
-        )
+        """)
         inferred = next(ast_node.infer())
         self.assertIsInstance(inferred, nodes.Const)
         self.assertEqual(inferred.value, 42)
 
     def test_aug_different_types_no_method_implemented(self) -> None:
-        ast_node = extract_node(
-            """
+        ast_node = extract_node("""
         class A(object): pass
         class B(object): pass
         f = A()
         f += B() #@
-        """
-        )
+        """)
         self.assertEqual(next(ast_node.infer()), util.Uninferable)
 
     def test_aug_different_types_augop_implemented(self) -> None:
-        ast_node = extract_node(
-            """
+        ast_node = extract_node("""
         class A(object):
             def __iadd__(self, other): return other
         class B(object): pass
         f = A()
         f += B() #@
-        """
-        )
+        """)
         inferred = next(ast_node.infer())
         self.assertIsInstance(inferred, Instance)
         self.assertEqual(inferred.name, "B")
 
     def test_aug_different_types_aug_not_implemented(self) -> None:
-        ast_node = extract_node(
-            """
+        ast_node = extract_node("""
         class A(object):
             def __iadd__(self, other): return NotImplemented
             def __add__(self, other): return other
         class B(object): pass
         f = A()
         f += B() #@
-        """
-        )
+        """)
         inferred = next(ast_node.infer())
         self.assertIsInstance(inferred, Instance)
         self.assertEqual(inferred.name, "B")
 
     def test_aug_different_types_aug_not_implemented_rop_fallback(self) -> None:
-        ast_node = extract_node(
-            """
+        ast_node = extract_node("""
         class A(object):
             def __iadd__(self, other): return NotImplemented
             def __add__(self, other): return NotImplemented
@@ -3485,26 +3365,22 @@
             def __radd__(self, other): return other
         f = A()
         f += B() #@
-        """
-        )
+        """)
         inferred = next(ast_node.infer())
         self.assertIsInstance(inferred, Instance)
         self.assertEqual(inferred.name, "A")
 
     def test_augop_supertypes_none_implemented(self) -> None:
-        ast_node = extract_node(
-            """
+        ast_node = extract_node("""
         class A(object): pass
         class B(object): pass
         a = A()
         a += B() #@
-        """
-        )
+        """)
         self.assertEqual(next(ast_node.infer()), util.Uninferable)
 
     def test_augop_supertypes_not_implemented_returned_for_all(self) -> None:
-        ast_node = extract_node(
-            """
+        ast_node = extract_node("""
         class A(object):
             def __iadd__(self, other): return NotImplemented
             def __add__(self, other): return NotImplemented
@@ -3512,42 +3388,36 @@
             def __add__(self, other): return NotImplemented
         a = A()
         a += B() #@
-        """
-        )
+        """)
         self.assertEqual(next(ast_node.infer()), util.Uninferable)
 
     def test_augop_supertypes_augop_implemented(self) -> None:
-        ast_node = extract_node(
-            """
+        ast_node = extract_node("""
         class A(object):
             def __iadd__(self, other): return other
         class B(A): pass
         a = A()
         a += B() #@
-        """
-        )
+        """)
         inferred = next(ast_node.infer())
         self.assertIsInstance(inferred, Instance)
         self.assertEqual(inferred.name, "B")
 
     def test_augop_supertypes_reflected_binop_implemented(self) -> None:
-        ast_node = extract_node(
-            """
+        ast_node = extract_node("""
         class A(object):
             def __iadd__(self, other): return NotImplemented
         class B(A):
             def __radd__(self, other): return other
         a = A()
         a += B() #@
-        """
-        )
+        """)
         inferred = next(ast_node.infer())
         self.assertIsInstance(inferred, Instance)
         self.assertEqual(inferred.name, "A")
 
     def test_augop_supertypes_normal_binop_implemented(self) -> None:
-        ast_node = extract_node(
-            """
+        ast_node = extract_node("""
         class A(object):
             def __iadd__(self, other): return NotImplemented
             def __add__(self, other): return other
@@ -3556,8 +3426,7 @@
 
         a = A()
         a += B() #@
-        """
-        )
+        """)
         inferred = next(ast_node.infer())
         self.assertIsInstance(inferred, Instance)
         self.assertEqual(inferred.name, "B")
@@ -3572,12 +3441,10 @@
         self.assertEqual(errors, [])
 
     def test_string_interpolation(self):
-        ast_nodes = extract_node(
-            """
+        ast_nodes = extract_node("""
         "a%d%d" % (1, 2) #@
         "a%(x)s" % {"x": 42} #@
-        """
-        )
+        """)
         expected = ["a12", "a42"]
         for node, expected_value in zip(ast_nodes, expected):
             inferred = next(node.infer())
@@ -3585,8 +3452,7 @@
             self.assertEqual(inferred.value, expected_value)
 
     def test_mul_list_supports__index__(self) -> None:
-        ast_nodes = extract_node(
-            """
+        ast_nodes = extract_node("""
         class Index(object):
             def __index__(self): return 2
         class NotIndex(object): pass
@@ -3596,8 +3462,7 @@
         a * Index() #@
         a * NotIndex() #@
         a * NotIndex2() #@
-        """
-        )
+        """)
         assert isinstance(ast_nodes, list)
         first = next(ast_nodes[0].infer())
         self.assertIsInstance(first, nodes.List)
@@ -3607,8 +3472,7 @@
             self.assertEqual(inferred, util.Uninferable)
 
     def test_subscript_supports__index__(self) -> None:
-        ast_nodes = extract_node(
-            """
+        ast_nodes = extract_node("""
         class Index(object):
             def __index__(self): return 2
         class LambdaIndex(object):
@@ -3621,8 +3485,7 @@
         a[Index()] #@
         a[LambdaIndex()] #@
         a[NonIndex()] #@
-        """
-        )
+        """)
         assert isinstance(ast_nodes, list)
         first = next(ast_nodes[0].infer())
         self.assertIsInstance(first, nodes.Const)
@@ -3633,8 +3496,7 @@
         self.assertRaises(InferenceError, next, ast_nodes[2].infer())
 
     def test_special_method_masquerading_as_another(self) -> None:
-        ast_node = extract_node(
-            """
+        ast_node = extract_node("""
         class Info(object):
             def __add__(self, other):
                 return "lala"
@@ -3642,46 +3504,40 @@
 
         f = Info()
         f | Info() #@
-        """
-        )
+        """)
         inferred = next(ast_node.infer())
         self.assertIsInstance(inferred, nodes.Const)
         self.assertEqual(inferred.value, "lala")
 
     def test_unary_op_assignment(self) -> None:
-        ast_node = extract_node(
-            """
+        ast_node = extract_node("""
         class A(object): pass
         def pos(self):
             return 42
         A.__pos__ = pos
         f = A()
         +f #@
-        """
-        )
+        """)
         inferred = next(ast_node.infer())
         self.assertIsInstance(inferred, nodes.Const)
         self.assertEqual(inferred.value, 42)
 
     def test_unary_op_classes(self) -> None:
-        ast_node = extract_node(
-            """
+        ast_node = extract_node("""
         class Meta(type):
             def __invert__(self):
                 return 42
         class A(object, metaclass=Meta):
             pass
         ~A
-        """
-        )
+        """)
         inferred = next(ast_node.infer())
         self.assertIsInstance(inferred, nodes.Const)
         self.assertEqual(inferred.value, 42)
 
     @unittest.skipUnless(HAS_SIX, "These tests require the six library")
     def test_unary_op_classes_with_metaclass(self):
-        ast_node = extract_node(
-            """
+        ast_node = extract_node("""
         import six
         class Meta(type):
             def __invert__(self):
@@ -3689,8 +3545,7 @@
         class A(six.with_metaclass(Meta)):
             pass
         ~A
-        """
-        )
+        """)
         inferred = next(ast_node.infer())
         self.assertIsInstance(inferred, nodes.Const)
         self.assertEqual(inferred.value, 42)
@@ -3786,16 +3641,14 @@
             self.assertRaises(InferenceError, next, node.infer())
 
     def test_instance_slicing(self) -> None:
-        ast_nodes = extract_node(
-            """
+        ast_nodes = extract_node("""
         class A(object):
             def __getitem__(self, index):
                 return [1, 2, 3, 4, 5][index]
         A()[1:] #@
         A()[:2] #@
         A()[1:4] #@
-        """
-        )
+        """)
         expected_values = [[2, 3, 4, 5], [1, 2], [2, 3, 4]]
         for expected, node in zip(expected_values, ast_nodes):
             inferred = next(node.infer())
@@ -3803,42 +3656,36 @@
             self.assertEqual([elt.value for elt in inferred.elts], expected)
 
     def test_instance_slicing_slices(self) -> None:
-        ast_node = extract_node(
-            """
+        ast_node = extract_node("""
         class A(object):
             def __getitem__(self, index):
                 return index
         A()[1:] #@
-        """
-        )
+        """)
         inferred = next(ast_node.infer())
         self.assertIsInstance(inferred, nodes.Slice)
         self.assertEqual(inferred.lower.value, 1)
         self.assertIsNone(inferred.upper)
 
     def test_instance_slicing_fails(self) -> None:
-        ast_nodes = extract_node(
-            """
+        ast_nodes = extract_node("""
         class A(object):
             def __getitem__(self, index):
                 return 1[index]
         A()[4:5] #@
         A()[2:] #@
-        """
-        )
+        """)
         for node in ast_nodes:
             self.assertEqual(next(node.infer()), util.Uninferable)
 
     def test_type__new__with_metaclass(self) -> None:
-        ast_node = extract_node(
-            """
+        ast_node = extract_node("""
         class Metaclass(type):
             pass
         class Entity(object):
              pass
         type.__new__(Metaclass, 'NewClass', (Entity,), {'a': 1}) #@
-        """
-        )
+        """)
         inferred = next(ast_node.infer())
 
         self.assertIsInstance(inferred, nodes.ClassDef)
@@ -3854,90 +3701,76 @@
         self.assertEqual(attributes[0].value, 1)
 
     def test_type__new__not_enough_arguments(self) -> None:
-        ast_nodes = extract_node(
-            """
+        ast_nodes = extract_node("""
         type.__new__(type, 'foo') #@
         type.__new__(type, 'foo', ()) #@
         type.__new__(type, 'foo', (), {}, ()) #@
-        """
-        )
+        """)
         for node in ast_nodes:
             with pytest.raises(InferenceError):
                 next(node.infer())
 
     def test_type__new__invalid_mcs_argument(self) -> None:
-        ast_nodes = extract_node(
-            """
+        ast_nodes = extract_node("""
         class Class(object): pass
         type.__new__(1, 2, 3, 4) #@
         type.__new__(Class, 2, 3, 4) #@
-        """
-        )
+        """)
         for node in ast_nodes:
             with pytest.raises(InferenceError):
                 next(node.infer())
 
     def test_type__new__invalid_name(self) -> None:
-        ast_nodes = extract_node(
-            """
+        ast_nodes = extract_node("""
         class Class(type): pass
         type.__new__(Class, object, 1, 2) #@
         type.__new__(Class, 1, 1, 2) #@
         type.__new__(Class, [], 1, 2) #@
-        """
-        )
+        """)
         for node in ast_nodes:
             with pytest.raises(InferenceError):
                 next(node.infer())
 
     def test_type__new__invalid_bases(self) -> None:
-        ast_nodes = extract_node(
-            """
+        ast_nodes = extract_node("""
         type.__new__(type, 'a', 1, 2) #@
         type.__new__(type, 'a', [], 2) #@
         type.__new__(type, 'a', {}, 2) #@
         type.__new__(type, 'a', (1, ), 2) #@
         type.__new__(type, 'a', (object, 1), 2) #@
-        """
-        )
+        """)
         for node in ast_nodes:
             with pytest.raises(InferenceError):
                 next(node.infer())
 
     def test_type__new__invalid_attrs(self) -> None:
-        type_error_nodes = extract_node(
-            """
+        type_error_nodes = extract_node("""
         type.__new__(type, 'a', (), ()) #@
         type.__new__(type, 'a', (), object) #@
         type.__new__(type, 'a', (), 1) #@
-        """
-        )
+        """)
         for node in type_error_nodes:
             with pytest.raises(InferenceError):
                 next(node.infer())
 
         # Ignore invalid keys
-        ast_nodes = extract_node(
-            """
+        ast_nodes = extract_node("""
             type.__new__(type, 'a', (), {object: 1}) #@
             type.__new__(type, 'a', (), {1:2, "a":5}) #@
-        """
-        )
+        """)
         for node in ast_nodes:
             inferred = next(node.infer())
             self.assertIsInstance(inferred, nodes.ClassDef)
 
     def test_type__new__metaclass_lookup(self) -> None:
-        ast_node = extract_node(
-            """
+        ast_node = extract_node("""
         class Metaclass(type):
             def test(cls): pass
             @classmethod
             def test1(cls): pass
             attr = 42
         type.__new__(Metaclass, 'A', (), {}) #@
-        """
-        )
+        """)
         inferred = next(ast_node.infer())
         self.assertIsInstance(inferred, nodes.ClassDef)
         test = inferred.getattr("test")
@@ -3956,15 +3789,13 @@
         self.assertEqual(attr[0].value, 42)
 
     def test_type__new__metaclass_and_ancestors_lookup(self) -> None:
-        ast_node = extract_node(
-            """
+        ast_node = extract_node("""
         class Book(object):
              title = 'Ubik'
         class MetaBook(type):
              title = 'Grimus'
         type.__new__(MetaBook, 'book', (Book, ), {'title':'Catch 22'}) #@
-        """
-        )
+        """)
         inferred = next(ast_node.infer())
         self.assertIsInstance(inferred, nodes.ClassDef)
         titles = [
@@ -3987,12 +3818,10 @@
         assert not isinstance(inferred2, nodes.Const)
         assert inferred2._proxied is inferred._proxied
 
-        ast_node3 = extract_node(
-            """
+        ast_node3 = extract_node("""
         x = 43
         int.__new__(int, x)  #@
-        """
-        )
+        """)
         inferred3 = next(ast_node3.infer())
         assert isinstance(inferred3, nodes.Const)
         assert inferred3.value == 43
@@ -4001,17 +3830,14 @@
         with pytest.raises(InferenceError):
             next(ast_node4.infer())
 
-        ast_node5 = extract_node(
-            """
+        ast_node5 = extract_node("""
         class A:  pass
         A.__new__(A())  #@
-        """
-        )
+        """)
         with pytest.raises(InferenceError):
             next(ast_node5.infer())
 
-        ast_nodes6 = extract_node(
-            """
+        ast_nodes6 = extract_node("""
         class A:  pass
         class B(A):  pass
         class C: pass
@@ -4020,8 +3846,7 @@
         B.__new__(A)  #@
         B.__new__(B)  #@
         C.__new__(A)  #@
-        """
-        )
+        """)
         instance_A1 = next(ast_nodes6[0].infer())
         assert instance_A1._proxied.name == "A"
         instance_B1 = next(ast_nodes6[1].infer())
@@ -4033,8 +3858,7 @@
         instance_A3 = next(ast_nodes6[4].infer())
         assert instance_A3._proxied.name == "A"
 
-        ast_nodes7 = extract_node(
-            """
+        ast_nodes7 = extract_node("""
         import enum
         class A(enum.EnumMeta): pass
         class B(enum.EnumMeta):
@@ -4045,8 +3869,7 @@
                 return super().__new__(A, "str", (enum.Enum,), enum._EnumDict(), **kwargs)
         B("")  #@
         C()  #@
-        """
-        )
+        """)
         instance_B = next(ast_nodes7[0].infer())
         assert instance_B._proxied.name == "B"
         instance_C = next(ast_nodes7[1].infer())
@@ -4058,8 +3881,7 @@
     def test_function_metaclasses(self):
         # These are not supported right now, although
         # they will be in the future.
-        ast_node = extract_node(
-            """
+        ast_node = extract_node("""
         class BookMeta(type):
             author = 'Rushdie'
 
@@ -4069,8 +3891,7 @@
         class Book(object, metaclass=metaclass_function):
             pass
         Book #@
-        """
-        )
+        """)
         inferred = next(ast_node.infer())
         metaclass = inferred.metaclass()
         self.assertIsInstance(metaclass, nodes.ClassDef)
@@ -4081,8 +3902,7 @@
 
     def test_subscript_inference_error(self) -> None:
         # Used to raise StopIteration
-        ast_node = extract_node(
-            """
+        ast_node = extract_node("""
         class AttributeDict(dict):
             def __getitem__(self, name):
                 return self
@@ -4090,13 +3910,11 @@
         flow['app'] = AttributeDict()
         flow['app']['config'] = AttributeDict()
         flow['app']['config']['doffing'] = AttributeDict() #@
-        """
-        )
+        """)
         self.assertIsInstance(util.safe_infer(ast_node.targets[0]), Instance)
 
     def test_classmethod_inferred_by_context(self) -> None:
-        ast_node = extract_node(
-            """
+        ast_node = extract_node("""
         class Super(object):
            def instance(cls):
               return cls()
@@ -4109,15 +3927,13 @@
         # should see the Sub.instance() is returning a Sub
         # instance, not a Super instance
         Sub.instance().method() #@
-        """
-        )
+        """)
         inferred = next(ast_node.infer())
         self.assertIsInstance(inferred, Instance)
         self.assertEqual(inferred.name, "Sub")
 
     def test_infer_call_result_invalid_dunder_call_on_instance(self) -> None:
-        ast_nodes = extract_node(
-            """
+        ast_nodes = extract_node("""
         class A:
             __call__ = 42
         class B:
@@ -4127,20 +3943,17 @@
         A() #@
         B() #@
         C() #@
-        """
-        )
+        """)
         for node in ast_nodes:
             inferred = next(node.infer())
             self.assertRaises(InferenceError, next, inferred.infer_call_result(node))
 
     def test_infer_call_result_same_proxied_class(self) -> None:
-        node = extract_node(
-            """
+        node = extract_node("""
         class A:
             __call__ = A()
         A() #@
-        """
-        )
+        """)
         inferred = next(node.infer())
         fully_evaluated_inference_results = list(inferred.infer_call_result(node))
         assert fully_evaluated_inference_results[0].name == "A"
@@ -4151,8 +3964,7 @@
         self.assertIsInstance(inferred, nodes.Const)
 
     def test_context_call_for_context_managers(self) -> None:
-        ast_nodes = extract_node(
-            """
+        ast_nodes = extract_node("""
         class A:
             def __enter__(self):
                 return self
@@ -4169,8 +3981,7 @@
             b #@
         with C() as c:
             c #@
-        """
-        )
+        """)
         assert isinstance(ast_nodes, list)
         first_a = next(ast_nodes[0].infer())
         self.assertIsInstance(first_a, Instance)
@@ -4183,8 +3994,7 @@
         self.assertEqual(third_c.name, "A")
 
     def test_metaclass_subclasses_arguments_are_classes_not_instances(self) -> None:
-        ast_node = extract_node(
-            """
+        ast_node = extract_node("""
         class A(type):
             def test(cls):
                 return cls
@@ -4192,16 +4002,14 @@
             pass
 
         B.test() #@
-        """
-        )
+        """)
         inferred = next(ast_node.infer())
         self.assertIsInstance(inferred, nodes.ClassDef)
         self.assertEqual(inferred.name, "B")
 
     @unittest.skipUnless(HAS_SIX, "These tests require the six library")
     def test_with_metaclass_subclasses_arguments_are_classes_not_instances(self):
-        ast_node = extract_node(
-            """
+        ast_node = extract_node("""
         class A(type):
             def test(cls):
                 return cls
@@ -4210,16 +4018,14 @@
             pass
 
         B.test() #@
-        """
-        )
+        """)
         inferred = next(ast_node.infer())
         self.assertIsInstance(inferred, nodes.ClassDef)
         self.assertEqual(inferred.name, "B")
 
     @unittest.skipUnless(HAS_SIX, "These tests require the six library")
     def test_with_metaclass_with_partial_imported_name(self):
-        ast_node = extract_node(
-            """
+        ast_node = extract_node("""
         class A(type):
             def test(cls):
                 return cls
@@ -4228,23 +4034,20 @@
             pass
 
         B.test() #@
-        """
-        )
+        """)
         inferred = next(ast_node.infer())
         self.assertIsInstance(inferred, nodes.ClassDef)
         self.assertEqual(inferred.name, "B")
 
     def test_infer_cls_in_class_methods(self) -> None:
-        ast_nodes = extract_node(
-            """
+        ast_nodes = extract_node("""
         class A(type):
             def __call__(cls):
                 cls #@
         class B(object):
             def __call__(cls):
                 cls #@
-        """
-        )
+        """)
         assert isinstance(ast_nodes, list)
         first = next(ast_nodes[0].infer())
         self.assertIsInstance(first, nodes.ClassDef)
@@ -4253,29 +4056,25 @@
 
     @pytest.mark.xfail(reason="Metaclass arguments not inferred as classes")
     def test_metaclass_arguments_are_classes_not_instances(self):
-        ast_node = extract_node(
-            """
+        ast_node = extract_node("""
         class A(type):
             def test(cls): return cls
         A.test() #@
-        """
-        )
+        """)
         # This is not supported yet
         inferred = next(ast_node.infer())
         self.assertIsInstance(inferred, nodes.ClassDef)
         self.assertEqual(inferred.name, "A")
 
     def test_metaclass_with_keyword_args(self) -> None:
-        ast_node = extract_node(
-            """
+        ast_node = extract_node("""
         class TestMetaKlass(type):
             def __new__(mcs, name, bases, ns, kwo_arg):
                 return super().__new__(mcs, name, bases, ns)
 
         class TestKlass(metaclass=TestMetaKlass, kwo_arg=42): #@
             pass
-        """
-        )
+        """)
         inferred = next(ast_node.infer())
         self.assertIsInstance(inferred, nodes.ClassDef)
 
@@ -4285,9 +4084,7 @@
 
         See https://github.com/pylint-dev/pylint/issues/2159
         """
-        val = (
-            extract_node(
-                """
+        val = extract_node("""
         class _Meta(type):
             def __call__(cls):
                 return 1
@@ -4296,45 +4093,36 @@
                 return 5.5
 
         Clazz() #@
-        """
-            )
-            .inferred()[0]
-            .value
-        )
+        """).inferred()[0].value
         assert val == 1
 
     def test_metaclass_custom_dunder_call_boundnode(self) -> None:
         """The boundnode should be the calling class."""
-        cls = extract_node(
-            """
+        cls = extract_node("""
         class _Meta(type):
             def __call__(cls):
                 return cls
         class Clazz(metaclass=_Meta):
             pass
         Clazz() #@
-        """
-        ).inferred()[0]
+        """).inferred()[0]
         assert isinstance(cls, Instance) and cls.name == "Clazz"
 
     def test_infer_subclass_attr_outer_class(self) -> None:
-        node = extract_node(
-            """
+        node = extract_node("""
         class Outer:
             data = 123
 
         class Test(Outer):
             pass
         Test.data
-        """
-        )
+        """)
         inferred = next(node.infer())
         assert isinstance(inferred, nodes.Const)
         assert inferred.value == 123
 
     def test_infer_subclass_attr_inner_class_works_indirectly(self) -> None:
-        node = extract_node(
-            """
+        node = extract_node("""
         class Outer:
             class Inner:
                 data = 123
@@ -4343,15 +4131,13 @@
         class Test(Inner):
             pass
         Test.data
-        """
-        )
+        """)
         inferred = next(node.infer())
         assert isinstance(inferred, nodes.Const)
         assert inferred.value == 123
 
     def test_infer_subclass_attr_inner_class(self) -> None:
-        clsdef_node, attr_node = extract_node(
-            """
+        clsdef_node, attr_node = extract_node("""
         class Outer:
             class Inner:
                 data = 123
@@ -4360,8 +4146,7 @@
             pass
         Test  #@
         Test.data  #@
-            """
-        )
+            """)
         clsdef = next(clsdef_node.infer())
         assert isinstance(clsdef, nodes.ClassDef)
         inferred = next(clsdef.igetattr("data"))
@@ -4378,22 +4163,19 @@
 
     def test_infer_method_empty_body(self) -> None:
         # https://github.com/PyCQA/astroid/issues/1015
-        node = extract_node(
-            """
+        node = extract_node("""
             class A:
                 def foo(self): ...
 
             A().foo()  #@
-        """
-        )
+        """)
         inferred = next(node.infer())
         assert isinstance(inferred, nodes.Const)
         assert inferred.value is None
 
     def test_infer_method_overload(self) -> None:
         # https://github.com/PyCQA/astroid/issues/1015
-        node = extract_node(
-            """
+        node = extract_node("""
             class A:
                 def foo(self): ...
 
@@ -4401,15 +4183,13 @@
                     yield
 
             A().foo()  #@
-        """
-        )
+        """)
         inferred = list(node.infer())
         assert len(inferred) == 1
         assert isinstance(inferred[0], Generator)
 
     def test_infer_function_under_if(self) -> None:
-        node = extract_node(
-            """
+        node = extract_node("""
         if 1 in [1]:
             def func():
                 return 42
@@ -4418,14 +4198,12 @@
                 return False
 
         func()  #@
-        """
-        )
+        """)
         inferred = list(node.inferred())
         assert [const.value for const in inferred] == [42, False]
 
     def test_infer_property_setter(self) -> None:
-        node = extract_node(
-            """
+        node = extract_node("""
         class PropertyWithSetter:
             @property
             def host(self):
@@ -4436,43 +4214,37 @@
                 self._host = value
 
         PropertyWithSetter().host #@
-        """
-        )
+        """)
         assert not isinstance(next(node.infer()), Instance)
 
     def test_delayed_attributes_without_slots(self) -> None:
-        ast_node = extract_node(
-            """
+        ast_node = extract_node("""
         class A(object):
             __slots__ = ('a', )
         a = A()
         a.teta = 24
         a.a = 24
         a #@
-        """
-        )
+        """)
         inferred = next(ast_node.infer())
         with self.assertRaises(NotFoundError):
             inferred.getattr("teta")
         inferred.getattr("a")
 
     def test_lambda_as_methods(self) -> None:
-        ast_node = extract_node(
-            """
+        ast_node = extract_node("""
         class X:
            m = lambda self, arg: self.z + arg
            z = 24
 
         X().m(4) #@
-        """
-        )
+        """)
         inferred = next(ast_node.infer())
         self.assertIsInstance(inferred, nodes.Const)
         self.assertEqual(inferred.value, 28)
 
     def test_inner_value_redefined_by_subclass(self) -> None:
-        ast_node = extract_node(
-            """
+        ast_node = extract_node("""
         class X(object):
             M = lambda self, arg: "a"
             x = 24
@@ -4484,15 +4256,13 @@
             M = lambda self, arg: arg + 1
             def blurb(self):
                 self.m #@
-        """
-        )
+        """)
         inferred = next(ast_node.infer())
         self.assertIsInstance(inferred, nodes.Const)
         self.assertEqual(inferred.value, 25)
 
     def test_inner_value_redefined_by_subclass_with_mro(self) -> None:
-        ast_node = extract_node(
-            """
+        ast_node = extract_node("""
         class X(object):
             M = lambda self, arg: arg + 1
             x = 24
@@ -4507,8 +4277,7 @@
             M = lambda self, arg: arg + 1
             def blurb(self):
                 self.m #@
-        """
-        )
+        """)
         inferred = next(ast_node.infer())
         assert isinstance(inferred, nodes.Const)
         assert inferred.value == 26
@@ -4516,80 +4285,67 @@
     def test_getitem_of_class_raised_type_error(self) -> None:
         # Test that we wrap an AttributeInferenceError
         # and reraise it as a TypeError in Class.getitem
-        node = extract_node(
-            """
+        node = extract_node("""
         def test(): ...
         test()
-        """
-        )
+        """)
         inferred = next(node.infer())
         with self.assertRaises(AstroidTypeError):
             inferred.getitem(nodes.Const("4"))
 
     def test_infer_arg_called_type_is_uninferable(self) -> None:
-        node = extract_node(
-            """
+        node = extract_node("""
         def func(type):
             type #@
-        """
-        )
+        """)
         inferred = next(node.infer())
         assert inferred is util.Uninferable
 
     def test_infer_arg_called_object_when_used_as_index_is_uninferable(self) -> None:
-        node = extract_node(
-            """
+        node = extract_node("""
         def func(object):
             ['list'][
                 object #@
             ]
-        """
-        )
+        """)
         inferred = next(node.infer())
         assert inferred is util.Uninferable
 
     def test_infer_arg_called_type_when_used_as_index_is_uninferable(self):
         # https://github.com/pylint-dev/astroid/pull/958
-        node = extract_node(
-            """
+        node = extract_node("""
         def func(type):
             ['list'][
                 type #@
             ]
-        """
-        )
+        """)
         inferred = next(node.infer())
         assert not isinstance(inferred, nodes.ClassDef)  # was inferred as builtins.type
         assert inferred is util.Uninferable
 
     def test_infer_arg_called_type_when_used_as_subscript_is_uninferable(self):
         # https://github.com/pylint-dev/astroid/pull/958
-        node = extract_node(
-            """
+        node = extract_node("""
         def func(type):
             type[0] #@
-        """
-        )
+        """)
         inferred = next(node.infer())
         assert not isinstance(inferred, nodes.ClassDef)  # was inferred as builtins.type
         assert inferred is util.Uninferable
 
     def test_infer_arg_called_type_defined_in_outer_scope_is_uninferable(self):
         # https://github.com/pylint-dev/astroid/pull/958
-        node = extract_node(
-            """
+        node = extract_node("""
         def outer(type):
             def inner():
                 type[0] #@
-        """
-        )
+        """)
         inferred = next(node.infer())
         assert not isinstance(inferred, nodes.ClassDef)  # was inferred as builtins.type
         assert inferred is util.Uninferable
 
     def test_infer_subclass_attr_instance_attr_indirect(self) -> None:
-        node = extract_node(
-            """
+        node = extract_node("""
         class Parent:
             def __init__(self):
                 self.data = 123
@@ -4598,8 +4354,7 @@
             pass
         t = Test()
         t
-        """
-        )
+        """)
         inferred = next(node.infer())
         assert isinstance(inferred, Instance)
         const = next(inferred.igetattr("data"))
@@ -4607,8 +4362,7 @@
         assert const.value == 123
 
     def test_infer_subclass_attr_instance_attr(self) -> None:
-        node = extract_node(
-            """
+        node = extract_node("""
         class Parent:
             def __init__(self):
                 self.data = 123
@@ -4617,8 +4371,7 @@
             pass
         t = Test()
         t.data
-        """
-        )
+        """)
         inferred = next(node.infer())
         assert isinstance(inferred, nodes.Const)
         assert inferred.value == 123
@@ -4631,8 +4384,7 @@
 
 class GetattrTest(unittest.TestCase):
     def test_yes_when_unknown(self) -> None:
-        ast_nodes = extract_node(
-            """
+        ast_nodes = extract_node("""
         from missing import Missing
         getattr(1, Unknown) #@
         getattr(Unknown, 'a') #@
@@ -4643,8 +4395,7 @@
         getattr(Missing, Missing) #@
         getattr('a', Missing) #@
         getattr('a', Missing, Missing) #@
-        """
-        )
+        """)
         for node in ast_nodes[:4]:
             self.assertRaises(InferenceError, next, node.infer())
 
@@ -4653,36 +4404,30 @@
             self.assertEqual(inferred, util.Uninferable, node)
 
     def test_attrname_not_string(self) -> None:
-        ast_nodes = extract_node(
-            """
+        ast_nodes = extract_node("""
         getattr(1, 1) #@
         c = int
         getattr(1, c) #@
-        """
-        )
+        """)
         for node in ast_nodes:
             self.assertRaises(InferenceError, next, node.infer())
 
     def test_attribute_missing(self) -> None:
-        ast_nodes = extract_node(
-            """
+        ast_nodes = extract_node("""
         getattr(1, 'ala') #@
         getattr(int, 'ala') #@
         getattr(float, 'bala') #@
         getattr({}, 'portocala') #@
-        """
-        )
+        """)
         for node in ast_nodes:
             self.assertRaises(InferenceError, next, node.infer())
 
     def test_default(self) -> None:
-        ast_nodes = extract_node(
-            """
+        ast_nodes = extract_node("""
         getattr(1, 'ala', None) #@
         getattr(int, 'bala', int) #@
         getattr(int, 'bala', getattr(int, 'portocala', None)) #@
-        """
-        )
+        """)
         assert isinstance(ast_nodes, list)
         first = next(ast_nodes[0].infer())
         self.assertIsInstance(first, nodes.Const)
@@ -4697,8 +4442,7 @@
         self.assertIsNone(third.value)
 
     def test_lookup(self) -> None:
-        ast_nodes = extract_node(
-            """
+        ast_nodes = extract_node("""
         class A(object):
             def test(self): pass
         class B(A):
@@ -4715,8 +4459,7 @@
         class X(object):
             def test(self):
                 getattr(self, 'test') #@
-        """
-        )
+        """)
         assert isinstance(ast_nodes, list)
         first = next(ast_nodes[0].infer())
         self.assertIsInstance(first, BoundMethod)
@@ -4743,48 +4486,41 @@
         self.assertEqual(fifth.bound.name, "X")
 
     def test_lambda(self) -> None:
-        node = extract_node(
-            """
+        node = extract_node("""
         getattr(lambda x: x, 'f') #@
-        """
-        )
+        """)
         inferred = next(node.infer())
         self.assertEqual(inferred, util.Uninferable)
 
 
 class HasattrTest(unittest.TestCase):
     def test_inference_errors(self) -> None:
-        ast_nodes = extract_node(
-            """
+        ast_nodes = extract_node("""
         from missing import Missing
 
         hasattr(Unknown, 'ala') #@
 
         hasattr(Missing, 'bala') #@
         hasattr('portocala', Missing) #@
-        """
-        )
+        """)
         for node in ast_nodes:
             inferred = next(node.infer())
             self.assertEqual(inferred, util.Uninferable)
 
     def test_attribute_is_missing(self) -> None:
-        ast_nodes = extract_node(
-            """
+        ast_nodes = extract_node("""
         class A: pass
         hasattr(int, 'ala') #@
         hasattr({}, 'bala') #@
         hasattr(A(), 'portocala') #@
-        """
-        )
+        """)
         for node in ast_nodes:
             inferred = next(node.infer())
             self.assertIsInstance(inferred, nodes.Const)
             self.assertFalse(inferred.value)
 
     def test_attribute_is_not_missing(self) -> None:
-        ast_nodes = extract_node(
-            """
+        ast_nodes = extract_node("""
         class A(object):
             def test(self): pass
         class B(A):
@@ -4801,19 +4537,16 @@
         class X(object):
             def test(self):
                 hasattr(self, 'test') #@
-        """
-        )
+        """)
         for node in ast_nodes:
             inferred = next(node.infer())
             self.assertIsInstance(inferred, nodes.Const)
             self.assertTrue(inferred.value)
 
     def test_lambda(self) -> None:
-        node = extract_node(
-            """
+        node = extract_node("""
         hasattr(lambda x: x, 'f') #@
-        """
-        )
+        """)
         inferred = next(node.infer())
         self.assertIsInstance(inferred, nodes.Const)
         self.assertIs(inferred.value, False)
@@ -4844,26 +4577,22 @@
             self.assertEqual(inferred.value, expected_value)
 
     def test_yes_when_unknown(self) -> None:
-        ast_nodes = extract_node(
-            """
+        ast_nodes = extract_node("""
         from unknown import unknown, any, not_any
         0 and unknown #@
         unknown or 0 #@
         any or not_any and unknown #@
-        """
-        )
+        """)
         for node in ast_nodes:
             inferred = next(node.infer())
             self.assertEqual(inferred, util.Uninferable)
 
     def test_other_nodes(self) -> None:
-        ast_nodes = extract_node(
-            """
+        ast_nodes = extract_node("""
         def test(): pass
         test and 0 #@
         1 and test #@
-        """
-        )
+        """)
         assert isinstance(ast_nodes, list)
         first = next(ast_nodes[0].infer())
         self.assertEqual(first.value, 0)
@@ -4901,8 +4630,7 @@
             self.assertEqual(inferred.value, expected_value)
 
     def test_callable_methods(self) -> None:
-        ast_nodes = extract_node(
-            """
+        ast_nodes = extract_node("""
         class C:
             def test(self): pass
             @staticmethod
@@ -4928,34 +4656,29 @@
         property #@
         D #@
         D() #@
-        """
-        )
+        """)
         for node in ast_nodes:
             inferred = next(node.infer())
             self.assertTrue(inferred)
 
     def test_inference_errors(self) -> None:
-        ast_nodes = extract_node(
-            """
+        ast_nodes = extract_node("""
         from unknown import unknown
         callable(unknown) #@
         def test():
             return unknown
         callable(test()) #@
-        """
-        )
+        """)
         for node in ast_nodes:
             inferred = next(node.infer())
             self.assertEqual(inferred, util.Uninferable)
 
     def test_not_callable(self) -> None:
-        ast_nodes = extract_node(
-            """
+        ast_nodes = extract_node("""
         callable("") #@
         callable(1) #@
         callable(True) #@
-        """
-        )
+        """)
         for node in ast_nodes:
             inferred = next(node.infer())
             self.assertFalse(inferred.value)
@@ -4984,8 +4707,7 @@
                 self.assertEqual(inferred.value, expected)
 
     def test_bool_bool_special_method(self) -> None:
-        ast_nodes = extract_node(
-            """
+        ast_nodes = extract_node("""
         class FalseClass:
            def __bool__(self):
                return False
@@ -5012,38 +4734,33 @@
         bool(B()) #@
         bool(LambdaBoolFalse()) #@
         bool(FalseBoolLen()) #@
-        """
-        )
+        """)
         expected = [True, True, False, True, False, False, False]
         for node, expected_value in zip(ast_nodes, expected):
             inferred = next(node.infer())
             self.assertEqual(inferred.value, expected_value)
 
     def test_bool_instance_not_callable(self) -> None:
-        ast_nodes = extract_node(
-            """
+        ast_nodes = extract_node("""
         class BoolInvalid(object):
            __bool__ = 42
         class LenInvalid(object):
            __len__ = "a"
         bool(BoolInvalid()) #@
         bool(LenInvalid()) #@
-        """
-        )
+        """)
         for node in ast_nodes:
             inferred = next(node.infer())
             self.assertEqual(inferred, util.Uninferable)
 
     def test_class_subscript(self) -> None:
-        node = extract_node(
-            """
+        node = extract_node("""
         class Foo:
             def __class_getitem__(cls, *args, **kwargs):
                 return cls
 
         Foo[int]
-        """
-        )
+        """)
         inferred = next(node.infer())
         self.assertIsInstance(inferred, nodes.ClassDef)
         self.assertEqual(inferred.name, "Foo")
@@ -5118,8 +4835,7 @@
             (3,),
             (42,),
         ]
-        ast_nodes = extract_node(
-            """
+        ast_nodes = extract_node("""
         def func(*args):
             return args
         func() #@
@@ -5145,8 +4861,7 @@
         func(1, 2) #@
         func(1, 2, 3) #@
         func(1, 2, *(42, )) #@
-        """
-        )
+        """)
         for node, expected_value in zip(ast_nodes, expected_values):
             inferred = next(node.infer())
             self.assertIsInstance(inferred, nodes.Tuple)
@@ -5154,14 +4869,12 @@
 
     def test_multiple_starred_args(self) -> None:
         expected_values = [(1, 2, 3), (1, 4, 2, 3, 5, 6, 7)]
-        ast_nodes = extract_node(
-            """
+        ast_nodes = extract_node("""
         def func(a, b, *args):
             return args
         func(1, 2, *(1, ), *(2, 3)) #@
         func(1, 2, *(1, ), 4, *(2, 3), 5, *(6, 7)) #@
-        """
-        )
+        """)
         for node, expected_value in zip(ast_nodes, expected_values):
             inferred = next(node.infer())
             self.assertIsInstance(inferred, nodes.Tuple)
@@ -5169,16 +4882,14 @@
 
     def test_defaults(self) -> None:
         expected_values = [42, 3, 41, 42]
-        ast_nodes = extract_node(
-            """
+        ast_nodes = extract_node("""
         def func(a, b, c=42, *args):
             return c
         func(1, 2) #@
         func(1, 2, 3) #@
         func(1, 2, c=41) #@
         func(1, 2, 42, 41) #@
-        """
-        )
+        """)
         for node, expected_value in zip(ast_nodes, expected_values):
             inferred = next(node.infer())
             self.assertIsInstance(inferred, nodes.Const)
@@ -5186,8 +4897,7 @@
 
     def test_kwonly_args(self) -> None:
         expected_values = [24, 24, 42, 23, 24, 24, 54]
-        ast_nodes = extract_node(
-            """
+        ast_nodes = extract_node("""
         def test(*, f, b): return f
         test(f=24, b=33) #@
         def test(a, *, f): return f
@@ -5200,8 +4910,7 @@
         test(1, 2, 3) #@
         test(1, 2, 3, 4) #@
         test(1, 2, 3, 4, 5, f=54) #@
-        """
-        )
+        """)
         for node, expected_value in zip(ast_nodes, expected_values):
             inferred = next(node.infer())
             self.assertIsInstance(inferred, nodes.Const)
@@ -5209,15 +4918,13 @@
 
     def test_kwargs(self) -> None:
         expected = [[("a", 1), ("b", 2), ("c", 3)], [("a", 1)], [("a", "b")]]
-        ast_nodes = extract_node(
-            """
+        ast_nodes = extract_node("""
         def test(**kwargs):
              return kwargs
         test(a=1, b=2, c=3) #@
         test(a=1) #@
         test(**{'a': 'b'}) #@
-        """
-        )
+        """)
         for node, expected_value in zip(ast_nodes, expected):
             inferred = next(node.infer())
             self.assertIsInstance(inferred, nodes.Dict)
@@ -5225,16 +4932,14 @@
             self.assertEqual(value, expected_value)
 
     def test_kwargs_and_other_named_parameters(self) -> None:
-        ast_nodes = extract_node(
-            """
+        ast_nodes = extract_node("""
         def test(a=42, b=24, **kwargs):
             return kwargs
         test(42, 24, c=3, d=4) #@
         test(49, b=24, d=4) #@
         test(a=42, b=33, c=3, d=42) #@
         test(a=42, **{'c':42}) #@
-        """
-        )
+        """)
         expected_values = [
             [("c", 3), ("d", 4)],
             [("d", 4)],
@@ -5249,8 +4954,7 @@
 
     def test_kwargs_access_by_name(self) -> None:
         expected_values = [42, 42, 42, 24]
-        ast_nodes = extract_node(
-            """
+        ast_nodes = extract_node("""
         def test(**kwargs):
             return kwargs['f']
         test(f=42) #@
@@ -5259,8 +4963,7 @@
         def test(f=42, **kwargs):
             return kwargs['l']
         test(l=24) #@
-        """
-        )
+        """)
         for ast_node, value in zip(ast_nodes, expected_values):
             inferred = next(ast_node.infer())
             self.assertIsInstance(inferred, nodes.Const, inferred)
@@ -5268,36 +4971,31 @@
 
     def test_multiple_kwargs(self) -> None:
         expected_value = [("a", 1), ("b", 2), ("c", 3), ("d", 4), ("f", 42)]
-        ast_node = extract_node(
-            """
+        ast_node = extract_node("""
         def test(**kwargs):
              return kwargs
         test(a=1, b=2, **{'c': 3}, **{'d': 4}, f=42) #@
-        """
-        )
+        """)
         inferred = next(ast_node.infer())
         self.assertIsInstance(inferred, nodes.Dict)
         value = self._get_dict_value(inferred)
         self.assertEqual(value, expected_value)
 
     def test_kwargs_are_overridden(self) -> None:
-        ast_nodes = extract_node(
-            """
+        ast_nodes = extract_node("""
         def test(f):
              return f
         test(f=23, **{'f': 34}) #@
         def test(f=None):
              return f
         test(f=23, **{'f':23}) #@
-        """
-        )
+        """)
         for ast_node in ast_nodes:
             inferred = next(ast_node.infer())
             self.assertEqual(inferred, util.Uninferable)
 
     def test_fail_to_infer_args(self) -> None:
-        ast_nodes = extract_node(
-            """
+        ast_nodes = extract_node("""
         def test(a, **kwargs): return a
         test(*missing) #@
         test(*object) #@
@@ -5321,16 +5019,14 @@
         test(*unknown) #@
         def test(*args): return args
         test(*unknown) #@
-        """
-        )
+        """)
         for node in ast_nodes:
             inferred = next(node.infer())
             self.assertEqual(inferred, util.Uninferable)
 
     def test_args_overwritten(self) -> None:
         # https://github.com/pylint-dev/astroid/issues/180
-        node = extract_node(
-            """
+        node = extract_node("""
         next = 42
         def wrapper(next=next):
              next = 24
@@ -5338,8 +5034,7 @@
                  return next
              return test
         wrapper()() #@
-        """
-        )
+        """)
         assert isinstance(node, nodes.NodeNG)
         inferred = node.inferred()
         self.assertEqual(len(inferred), 1)
@@ -5365,8 +5060,7 @@
             self.assertEqual([elt.value for elt in inferred.elts], expected_value)
 
     def test_slice_inference_error(self) -> None:
-        ast_nodes = extract_node(
-            """
+        ast_nodes = extract_node("""
         from unknown import unknown
         [1, 2, 3][slice(None, unknown, unknown)] #@
         [1, 2, 3][slice(None, missing, missing)] #@
@@ -5376,8 +5070,7 @@
         [1, 2, 3][slice(1, 2.0, 3.0)] #@
         [1, 2, 3][slice()] #@
         [1, 2, 3][slice(1, 2, 3, 4)] #@
-        """
-        )
+        """)
         for node in ast_nodes:
             self.assertRaises(InferenceError, next, node.infer())
 
@@ -5495,7 +5188,7 @@
             else:
                 kwargs = {}
 
-            if nums:
+            if nums is not None:
                 add(*nums)
                 print(**kwargs)
         """
@@ -5515,13 +5208,11 @@
 
 class ObjectDunderNewTest(unittest.TestCase):
     def test_object_dunder_new_is_inferred_if_decorator(self) -> None:
-        node = extract_node(
-            """
+        node = extract_node("""
         @object.__new__
         class instance(object):
             pass
-        """
-        )
+        """)
         inferred = next(node.infer())
         self.assertIsInstance(inferred, Instance)
 
@@ -5567,10 +5258,32 @@
     if result is None:
         assert value_node is util.Uninferable
     else:
-        assert isinstance(value_node, Const)
+        assert isinstance(value_node, nodes.Const)
         assert value_node.value == result
 
 
+def test_fstring_large_width_no_memory_error() -> None:
+    """MemoryError should not crash inference for f-strings with huge width.
+
+    Regression test for https://github.com/pylint-dev/astroid/issues/2762
+    """
+
+    class OOMInt(int):
+        """An int whose __format__ raises MemoryError, simulating f'{0:>11111111111}'."""
+
+        def __format__(self, spec: str) -> str:
+            raise MemoryError
+
+    node = extract_node("f'{0:>9}'")
+    # Replace the Const value with our OOMInt so format() raises MemoryError
+    # without actually allocating a huge string.
+    fmt_value = node.values[0]
+    fmt_value.value.value = OOMInt(0)
+    inferred = node.inferred()
+    assert len(inferred) == 1
+    assert inferred[0] is util.Uninferable
+
+
 def test_augassign_recursion() -> None:
     """Make sure inference doesn't throw a RecursionError.
 
@@ -5590,8 +5303,7 @@
 
 
 def test_infer_custom_inherit_from_property() -> None:
-    node = extract_node(
-        """
+    node = extract_node("""
     class custom_property(property):
         pass
 
@@ -5601,34 +5313,30 @@
             return 1
 
     MyClass().my_prop
-    """
-    )
+    """)
     inferred = next(node.infer())
     assert isinstance(inferred, nodes.Const)
     assert inferred.value == 1
 
 
 def test_cannot_infer_call_result_for_builtin_methods() -> None:
-    node = extract_node(
-        """
+    node = extract_node("""
     a = "fast"
     a
-    """
-    )
+    """)
     inferred = next(node.infer())
     lenmeth = next(inferred.igetattr("__len__"))
-    with pytest.raises(InferenceError):
-        next(lenmeth.infer_call_result(None, None))
+    # Builtin dunder methods now return Uninferable instead of raising InferenceError
+    result = next(lenmeth.infer_call_result(None, None))
+    assert result is util.Uninferable
 
 
 def test_unpack_dicts_in_assignment() -> None:
-    ast_nodes = extract_node(
-        """
+    ast_nodes = extract_node("""
     a, b = {1:2, 2:3}
     a #@
     b #@
-    """
-    )
+    """)
     assert isinstance(ast_nodes, list)
     first_inferred = next(ast_nodes[0].infer())
     second_inferred = next(ast_nodes[1].infer())
@@ -5639,40 +5347,33 @@
 
 
 def test_slice_inference_in_for_loops() -> None:
-    node = extract_node(
-        """
+    node = extract_node("""
     for a, (c, *b) in [(1, (2, 3, 4)), (4, (5, 6))]:
        b #@
-    """
-    )
+    """)
     inferred = next(node.infer())
     assert isinstance(inferred, nodes.List)
     assert inferred.as_string() == "[3, 4]"
 
-    node = extract_node(
-        """
+    node = extract_node("""
     for a, *b in [(1, 2, 3, 4)]:
        b #@
-    """
-    )
+    """)
     inferred = next(node.infer())
     assert isinstance(inferred, nodes.List)
     assert inferred.as_string() == "[2, 3, 4]"
 
-    node = extract_node(
-        """
+    node = extract_node("""
     for a, *b in [(1,)]:
        b #@
-    """
-    )
+    """)
     inferred = next(node.infer())
     assert isinstance(inferred, nodes.List)
     assert inferred.as_string() == "[]"
 
 
 def test_slice_inference_in_for_loops_not_working() -> None:
-    ast_nodes = extract_node(
-        """
+    ast_nodes = extract_node("""
     from unknown import Unknown
     for a, *b in something:
         b #@
@@ -5680,8 +5381,7 @@
         b #@
     for a, *b in (1):
         b #@
-    """
-    )
+    """)
     for node in ast_nodes:
         inferred = next(node.infer())
         assert inferred == util.Uninferable
@@ -5698,34 +5398,28 @@
 
 
 def test_unpacking_starred_and_dicts_in_assignment() -> None:
-    node = extract_node(
-        """
+    node = extract_node("""
     a, *b = {1:2, 2:3, 3:4}
     b
-    """
-    )
+    """)
     inferred = next(node.infer())
     assert isinstance(inferred, nodes.List)
     assert inferred.as_string() == "[2, 3]"
 
-    node = extract_node(
-        """
+    node = extract_node("""
     a, *b = {1:2}
     b
-    """
-    )
+    """)
     inferred = next(node.infer())
     assert isinstance(inferred, nodes.List)
     assert inferred.as_string() == "[]"
 
 
 def test_unpacking_starred_empty_list_in_assignment() -> None:
-    node = extract_node(
-        """
+    node = extract_node("""
     a, *b, c = [1, 2]
     b #@
-    """
-    )
+    """)
     inferred = next(node.infer())
     assert isinstance(inferred, nodes.List)
     assert inferred.as_string() == "[]"
@@ -5776,8 +5470,7 @@
 
     See https://github.com/pylint-dev/pylint/issues/2199
     """
-    node = extract_node(
-        """
+    node = extract_node("""
     class Base:
         def __call__(self):
             return self
@@ -5787,8 +5480,7 @@
     obj = Sub()
     val = obj()
     val #@
-    """
-    )
+    """)
     assert isinstance(node, nodes.NodeNG)
     [val] = node.inferred()
     assert isinstance(val, Instance)
@@ -5802,8 +5494,7 @@
 
     @pytest.mark.xfail(reason="Relying on path copy")
     def test_call_context_propagation(self):
-        n = extract_node(
-            """
+        n = extract_node("""
         def chest(a):
             return a * a
         def best(a, b):
@@ -5811,8 +5502,7 @@
         def test(a, b, c):
             return best(a, b)
         test(4, 5, 6) #@
-        """
-        )
+        """)
         assert next(n.infer()).as_string() == "16"
 
     def test_call_starargs_propagation(self) -> None:
@@ -6136,8 +5826,7 @@
 
 def test_attribute_mro_object_inference() -> None:
     """Inference should only infer results from the first available method."""
-    inferred = extract_node(
-        """
+    inferred = extract_node("""
     class A:
         def foo(self):
             return 1
@@ -6145,30 +5834,24 @@
         def foo(self):
             return 2
     B().foo() #@
-    """
-    ).inferred()
+    """).inferred()
     assert len(inferred) == 1
     assert inferred[0].value == 2
 
 
 def test_inferred_sequence_unpacking_works() -> None:
-    inferred = next(
-        extract_node(
-            """
+    inferred = next(extract_node("""
     def test(*args):
         return (1, *args)
     test(2) #@
-    """
-        ).infer()
-    )
+    """).infer())
     assert isinstance(inferred, nodes.Tuple)
     assert len(inferred.elts) == 2
     assert [value.value for value in inferred.elts] == [1, 2]
 
 
 def test_recursion_error_inferring_slice() -> None:
-    node = extract_node(
-        """
+    node = extract_node("""
     class MyClass:
         def __init__(self):
             self._slice = slice(0, 10)
@@ -6178,15 +5861,13 @@
 
         def test(self):
             self._slice #@
-    """
-    )
+    """)
     inferred = next(node.infer())
-    assert isinstance(inferred, Slice)
+    assert isinstance(inferred, nodes.Slice)
 
 
 def test_exception_lookup_last_except_handler_wins() -> None:
-    node = extract_node(
-        """
+    node = extract_node("""
     try:
         1/0
     except ValueError as exc:
@@ -6195,8 +5876,7 @@
         1/0
     except OSError as exc:
         exc #@
-    """
-    )
+    """)
     assert isinstance(node, nodes.NodeNG)
     inferred = node.inferred()
     assert len(inferred) == 1
@@ -6205,16 +5885,14 @@
     assert inferred_exc.name == "OSError"
 
     # Two except handlers on the same Try work the same as separate
-    node = extract_node(
-        """
+    node = extract_node("""
     try:
         1/0
     except ZeroDivisionError as exc:
         pass
     except ValueError as exc:
         exc #@
-    """
-    )
+    """)
     assert isinstance(node, nodes.NodeNG)
     inferred = node.inferred()
     assert len(inferred) == 1
@@ -6224,8 +5902,7 @@
 
 
 def test_exception_lookup_name_bound_in_except_handler() -> None:
-    node = extract_node(
-        """
+    node = extract_node("""
     try:
         1/0
     except ValueError:
@@ -6235,8 +5912,7 @@
     except OSError:
         name = 2
         name #@
-    """
-    )
+    """)
     assert isinstance(node, nodes.NodeNG)
     inferred = node.inferred()
     assert len(inferred) == 1
@@ -6246,11 +5922,9 @@
 
 
 def test_builtin_inference_list_of_exceptions() -> None:
-    node = extract_node(
-        """
+    node = extract_node("""
     tuple([ValueError, TypeError])
-    """
-    )
+    """)
     inferred = next(node.infer())
     assert isinstance(inferred, nodes.Tuple)
     assert len(inferred.elts) == 2
@@ -6276,23 +5950,19 @@
 
 
 def test_cannot_getattr_ann_assigns() -> None:
-    node = extract_node(
-        """
+    node = extract_node("""
     class Cls:
         ann: int
-    """
-    )
+    """)
     inferred = next(node.infer())
     with pytest.raises(AttributeInferenceError):
         inferred.getattr("ann")
 
     # But if it had a value, then it would be okay.
-    node = extract_node(
-        """
+    node = extract_node("""
     class Cls:
         ann: int = 0
-    """
-    )
+    """)
     inferred = next(node.infer())
     values = inferred.getattr("ann")
     assert len(values) == 1
@@ -6441,6 +6111,98 @@
     assert [third[0].value, third[1].value] == [1, 2]
 
 
+def test_ifexp_with_default_arguments() -> None:
+    code = """
+    def with_default(foo: str | None = None):
+        a = 1 if foo else "bar" #@
+
+    def without_default(foo: str):
+        a = 1 if foo else "bar" #@
+
+    def some_ifexps(foo: str | None = None):
+        a = 1 if foo else 2
+        b = 3 if a else 4 #@
+        c = 4 if b else 5 #@
+        d = 5 if not foo else foo #@
+        e = d if not foo else foo #@
+    """
+
+    ast_nodes = extract_node(code)
+
+    first = ast_nodes[0].value.inferred()
+    second = ast_nodes[1].value.inferred()
+    third = ast_nodes[2].value.inferred()
+    fourth = ast_nodes[3].value.inferred()
+    fifth = ast_nodes[4].value.inferred()
+    sixth = ast_nodes[5].value.inferred()
+
+    assert len(first) == 2
+    assert [first[0].value, first[1].value] == [1, "bar"]
+
+    assert len(second) == 2
+    assert [second[0].value, second[1].value] == [1, "bar"]
+
+    assert len(third) == 1
+    assert third[0].value == 3
+
+    assert len(fourth) == 1
+    assert fourth[0].value == 4
+
+    assert len(fifth) == 2
+    assert [fifth[0].value, fifth[1].value] == [5, Uninferable]
+
+    assert len(sixth) == 3
+    assert [sixth[0].value, sixth[1].value, sixth[2].value] == [
+        5,
+        Uninferable,
+        Uninferable,
+    ]
+
+
+def test_ifexp_with_uninferables() -> None:
+    code = """
+    def truthy_and_falsy():
+        return False if unknown() else True
+
+    def truthy_and_uninferable():
+        return False if unknown() else unknown()
+
+    def calls_truthy_and_falsy():
+        return 1 if truthy_and_falsy() else 2
+
+    def calls_truthy_and_uninferable():
+        return 1 if range(10) else truthy_and_uninferable()
+
+    truthy_and_falsy() #@
+    truthy_and_uninferable() #@
+    calls_truthy_and_falsy() #@
+    calls_truthy_and_uninferable() #@
+    """
+
+    ast_nodes = extract_node(code)
+
+    first = ast_nodes[0].inferred()
+    second = ast_nodes[1].inferred()
+    third = ast_nodes[2].inferred()
+    fourth = ast_nodes[3].inferred()
+
+    assert len(first) == 2
+    assert [first[0].value, first[1].value] == [False, True]
+
+    assert len(second) == 2
+    assert [second[0].value, second[1].value] == [False, Uninferable]
+
+    assert len(third) == 2
+    assert [third[0].value, third[1].value] == [1, 2]
+
+    assert len(fourth) == 3
+    assert [fourth[0].value, fourth[1].value, fourth[2].value] == [
+        1,
+        False,
+        Uninferable,
+    ]
+
+
 def test_assert_last_function_returns_none_on_inference() -> None:
     code = """
     def check_equal(a, b):
@@ -6648,13 +6410,11 @@
     node = extract_node(code)
     inferred = next(node.infer())
     assert isinstance(inferred, objects.Property)
-    property_body = textwrap.dedent(
-        """
+    property_body = textwrap.dedent("""
     @property
     def test(self):
         return 42
-    """
-    )
+    """)
     assert inferred.as_string().strip() == property_body.strip()
 
 
@@ -6701,16 +6461,14 @@
 
 
 def test_recursion_error_inferring_builtin_containers() -> None:
-    node = extract_node(
-        """
+    node = extract_node("""
     class Foo:
         a = "foo"
     inst = Foo()
 
     b = tuple([inst.a]) #@
     inst.a = b
-    """
-    )
+    """)
     util.safe_infer(node.targets[0])
 
 
@@ -7150,12 +6908,10 @@
     operators.
     """
     mod1 = parse(
-        textwrap.dedent(
-            """
+        textwrap.dedent("""
     from top1.mod import v as z
     w = [1] + z
-    """
-        ),
+    """),
         module_name="top1",
     )
     parse("v = [2]", module_name="top1.mod")
@@ -7168,12 +6924,10 @@
 def test_imported_module_var_inferable2() -> None:
     """Version list of strings."""
     mod2 = parse(
-        textwrap.dedent(
-            """
+        textwrap.dedent("""
     from top2.mod import v as z
     w = ['1'] + z
-    """
-        ),
+    """),
         module_name="top2",
     )
     parse("v = ['2']", module_name="top2.mod")
@@ -7186,12 +6940,10 @@
 def test_imported_module_var_inferable3() -> None:
     """Version list of strings with a __dunder__ name."""
     mod3 = parse(
-        textwrap.dedent(
-            """
+        textwrap.dedent("""
     from top3.mod import __dunder_var__ as v
     __dunder_var__ = ['w'] + v
-    """
-        ),
+    """),
         module_name="top",
     )
     parse("__dunder_var__ = ['v']", module_name="top3.mod")
@@ -7371,14 +7123,10 @@
 
 def test_sys_argv_uninferable() -> None:
     """Regression test for https://github.com/pylint-dev/pylint/issues/7710."""
-    a: nodes.List = extract_node(
-        textwrap.dedent(
-            """
+    a: nodes.List = extract_node(textwrap.dedent("""
     import sys
 
-    sys.argv"""
-        )
-    )
+    sys.argv"""))
     sys_argv_value = list(a._infer())
     assert len(sys_argv_value) == 1
     assert sys_argv_value[0] is Uninferable
@@ -7418,13 +7166,31 @@
 def test_joined_str_returns_string(source, expected) -> None:
     """Regression test for https://github.com/pylint-dev/pylint/issues/9947."""
     node = extract_node(source)
-    assert isinstance(node, Assign)
+    assert isinstance(node, nodes.Assign)
     target = node.targets[0]
     assert target
     inferred = list(target.inferred())
     assert len(inferred) == 1
     if expected:
-        assert isinstance(inferred[0], Const)
+        assert isinstance(inferred[0], nodes.Const)
         inferred[0].value.startswith(expected)
     else:
         assert inferred[0] is Uninferable
+
+
+def test_joined_str_uninferable() -> None:
+    """`thing` is not known, therefore the joinedstring should be
+    Uninferable
+    """
+    code = """
+        def hey(thing):
+            return thing
+
+        f"Hello {hey()}"
+    """
+    joined_str = extract_node(code)
+    constant_value, formatted_value = joined_str.values
+    assert constant_value.value == "Hello "
+    assert formatted_value.value.as_string() == "hey()"
+    inferred = next(joined_str.infer())
+    assert inferred is util.Uninferable
diff --git a/tests/test_inference_calls.py b/tests/test_inference_calls.py
index 31be586..1afe6eb 100644
--- a/tests/test_inference_calls.py
+++ b/tests/test_inference_calls.py
@@ -10,14 +10,12 @@
 
 def test_no_return() -> None:
     """Test function with no return statements."""
-    node = builder.extract_node(
-        """
+    node = builder.extract_node("""
     def f():
         pass
 
     f()  #@
-    """
-    )
+    """)
     assert isinstance(node, nodes.NodeNG)
     inferred = node.inferred()
     assert len(inferred) == 1
@@ -26,14 +24,12 @@
 
 def test_one_return() -> None:
     """Test function with a single return that always executes."""
-    node = builder.extract_node(
-        """
+    node = builder.extract_node("""
     def f():
         return 1
 
     f()  #@
-    """
-    )
+    """)
     assert isinstance(node, nodes.NodeNG)
     inferred = node.inferred()
     assert len(inferred) == 1
@@ -46,15 +42,13 @@
 
     Note: currently, inference doesn't handle this type of control flow
     """
-    node = builder.extract_node(
-        """
+    node = builder.extract_node("""
     def f(x):
         if x:
             return 1
 
     f(1)  #@
-    """
-    )
+    """)
     assert isinstance(node, nodes.NodeNG)
     inferred = node.inferred()
     assert len(inferred) == 1
@@ -64,8 +58,7 @@
 
 def test_multiple_returns() -> None:
     """Test function with multiple returns."""
-    node = builder.extract_node(
-        """
+    node = builder.extract_node("""
     def f(x):
         if x > 10:
             return 1
@@ -75,8 +68,7 @@
             return 3
 
     f(100)  #@
-    """
-    )
+    """)
     assert isinstance(node, nodes.NodeNG)
     inferred = node.inferred()
     assert len(inferred) == 3
@@ -86,14 +78,12 @@
 
 def test_argument() -> None:
     """Test function whose return value uses its arguments."""
-    node = builder.extract_node(
-        """
+    node = builder.extract_node("""
     def f(x, y):
         return x + y
 
     f(1, 2)  #@
-    """
-    )
+    """)
     assert isinstance(node, nodes.NodeNG)
     inferred = node.inferred()
     assert len(inferred) == 1
@@ -103,8 +93,7 @@
 
 def test_inner_call() -> None:
     """Test function where return value is the result of a separate function call."""
-    node = builder.extract_node(
-        """
+    node = builder.extract_node("""
     def f():
         return g()
 
@@ -112,8 +101,7 @@
         return 1
 
     f()  #@
-    """
-    )
+    """)
     assert isinstance(node, nodes.NodeNG)
     inferred = node.inferred()
     assert len(inferred) == 1
@@ -125,8 +113,7 @@
     """Test function where return value is the result of a separate function call,
     with a constant value passed to the inner function.
     """
-    node = builder.extract_node(
-        """
+    node = builder.extract_node("""
     def f():
         return g(1)
 
@@ -134,8 +121,7 @@
         return y + 2
 
     f()  #@
-    """
-    )
+    """)
     assert isinstance(node, nodes.NodeNG)
     inferred = node.inferred()
     assert len(inferred) == 1
@@ -149,8 +135,7 @@
 
     Currently, this is Uninferable.
     """
-    node = builder.extract_node(
-        """
+    node = builder.extract_node("""
     def f(x):
         return g(x)
 
@@ -158,8 +143,7 @@
         return y + 2
 
     f(1)  #@
-    """
-    )
+    """)
     assert isinstance(node, nodes.NodeNG)
     inferred = node.inferred()
     assert len(inferred) == 1
@@ -170,8 +154,7 @@
     """Test method where the return value is based on an instance attribute with a
     constant value.
     """
-    node = builder.extract_node(
-        """
+    node = builder.extract_node("""
     class A:
         def __init__(self):
             self.x = 1
@@ -180,8 +163,7 @@
             return self.x
 
     A().get_x()  #@
-    """
-    )
+    """)
     assert isinstance(node, nodes.NodeNG)
     inferred = node.inferred()
     assert len(inferred) == 1
@@ -193,8 +175,7 @@
     """Test method where the return value is based on an instance attribute with
     multiple possible constant values, across different methods.
     """
-    node = builder.extract_node(
-        """
+    node = builder.extract_node("""
     class A:
         def __init__(self, x):
             if x:
@@ -209,8 +190,7 @@
             return self.x
 
     A().get_x()  #@
-    """
-    )
+    """)
     assert isinstance(node, nodes.NodeNG)
     inferred = node.inferred()
     assert len(inferred) == 3
@@ -226,8 +206,7 @@
     is guaranteed to override any previous assignments, all possible constant values
     are returned.
     """
-    node = builder.extract_node(
-        """
+    node = builder.extract_node("""
     class A:
         def __init__(self, x):
             if x:
@@ -243,8 +222,7 @@
             return self.x
 
     A().get_x()  #@
-    """
-    )
+    """)
     assert isinstance(node, nodes.NodeNG)
     inferred = node.inferred()
     assert len(inferred) == 4
@@ -258,8 +236,7 @@
 
     In this case, the return value is Uninferable.
     """
-    node = builder.extract_node(
-        """
+    node = builder.extract_node("""
     class A:
         def __init__(self, x):
             self.x = x
@@ -268,8 +245,7 @@
             return self.x
 
     A(1).get_x()  #@
-    """
-    )
+    """)
     assert isinstance(node, nodes.NodeNG)
     inferred = node.inferred()
     assert len(inferred) == 1
@@ -280,8 +256,7 @@
     """Test method where the return value is based on an instance attribute with
     a dynamically-set value in the same method.
     """
-    node = builder.extract_node(
-        """
+    node = builder.extract_node("""
     class A:
         # Note: no initializer, so the only assignment happens in get_x
 
@@ -290,8 +265,7 @@
             return self.x
 
     A().get_x(1)  #@
-    """
-    )
+    """)
     assert isinstance(node, nodes.NodeNG)
     inferred = node.inferred()
     assert len(inferred) == 1
@@ -305,8 +279,7 @@
 
     This is currently Uninferable.
     """
-    node = builder.extract_node(
-        """
+    node = builder.extract_node("""
     class A:
         def get_x(self, x):  # x is unused
             return self.x
@@ -315,8 +288,7 @@
             self.x = x
 
     A().get_x(10)  #@
-    """
-    )
+    """)
     assert isinstance(node, nodes.NodeNG)
     inferred = node.inferred()
     assert len(inferred) == 1
@@ -329,8 +301,7 @@
 
     This is currently Uninferable.
     """
-    node = builder.extract_node(
-        """
+    node = builder.extract_node("""
     class A:
         # Note: no initializer, so the only assignment happens in get_x
 
@@ -342,8 +313,7 @@
             self.x = x
 
     A().get_x()  #@
-    """
-    )
+    """)
     assert isinstance(node, nodes.NodeNG)
     inferred = node.inferred()
     assert len(inferred) == 1
@@ -360,8 +330,7 @@
 
     This is currently Uninferable.
     """
-    node = builder.extract_node(
-        """
+    node = builder.extract_node("""
     class A:
         # Note: no initializer, so the only assignment happens in get_x
 
@@ -373,8 +342,7 @@
             self.x = x
 
     A().get_x(1)  #@
-    """
-    )
+    """)
     assert isinstance(node, nodes.NodeNG)
     inferred = node.inferred()
     assert len(inferred) == 1
@@ -387,8 +355,7 @@
 
     This is currently Uninferable.
     """
-    node = builder.extract_node(
-        """
+    node = builder.extract_node("""
     class A:
         # Note: no initializer, so the only assignment happens in get_x
 
@@ -400,8 +367,7 @@
             self.x = x
 
     A().get_x(1)  #@
-    """
-    )
+    """)
     assert isinstance(node, nodes.NodeNG)
     inferred = node.inferred()
     assert len(inferred) == 1
@@ -414,8 +380,7 @@
     This is currently Uninferable, until we can infer instance attribute values through
     constructor calls.
     """
-    node = builder.extract_node(
-        """
+    node = builder.extract_node("""
     class A:
         def __init__(self, x):
             self.x = x
@@ -424,8 +389,7 @@
             return self.x + i
 
     A(1)[2]  #@
-    """
-    )
+    """)
     assert isinstance(node, nodes.NodeNG)
     inferred = node.inferred()
     assert len(inferred) == 1
@@ -434,8 +398,7 @@
 
 def test_instance_method() -> None:
     """Tests for instance method, both bound and unbound."""
-    nodes_ = builder.extract_node(
-        """
+    nodes_ = builder.extract_node("""
     class A:
         def method(self, x):
             return x
@@ -444,8 +407,7 @@
 
     # In this case, the 1 argument is bound to self, which is ignored in the method
     A.method(1, 42)  #@
-    """
-    )
+    """)
 
     for node in nodes_:
         assert isinstance(node, nodes.NodeNG)
@@ -457,8 +419,7 @@
 
 def test_class_method() -> None:
     """Tests for class method calls, both instance and with the class."""
-    nodes_ = builder.extract_node(
-        """
+    nodes_ = builder.extract_node("""
     class A:
         @classmethod
         def method(cls, x):
@@ -467,8 +428,7 @@
     A.method(42)  #@
     A().method(42)  #@
 
-    """
-    )
+    """)
 
     for node in nodes_:
         assert isinstance(node, nodes.NodeNG)
@@ -480,8 +440,7 @@
 
 def test_static_method() -> None:
     """Tests for static method calls, both instance and with the class."""
-    nodes_ = builder.extract_node(
-        """
+    nodes_ = builder.extract_node("""
     class A:
         @staticmethod
         def method(x):
@@ -489,8 +448,7 @@
 
     A.method(42)  #@
     A().method(42)  #@
-    """
-    )
+    """)
 
     for node in nodes_:
         assert isinstance(node, nodes.NodeNG)
@@ -505,8 +463,7 @@
 
     Based on https://github.com/pylint-dev/astroid/issues/1008.
     """
-    nodes_ = builder.extract_node(
-        """
+    nodes_ = builder.extract_node("""
     class A:
         def method(self):
             return self
@@ -520,8 +477,7 @@
     B().method()  #@
     B.method(B())  #@
     A.method(B())  #@
-    """
-    )
+    """)
     expected_names = ["A", "A", "B", "B", "B"]
     for node, expected in zip(nodes_, expected_names):
         assert isinstance(node, nodes.NodeNG)
@@ -536,8 +492,7 @@
 
     Based on https://github.com/pylint-dev/astroid/issues/1008.
     """
-    nodes_ = builder.extract_node(
-        """
+    nodes_ = builder.extract_node("""
     class A:
         @classmethod
         def method(cls):
@@ -551,8 +506,7 @@
 
     B().method()  #@
     B.method()  #@
-    """
-    )
+    """)
     expected_names = ["A", "A", "B", "B"]
     for node, expected in zip(nodes_, expected_names):
         assert isinstance(node, nodes.NodeNG)
@@ -567,8 +521,7 @@
 
     Based on https://github.com/pylint-dev/pylint/issues/4220.
     """
-    node = builder.extract_node(
-        """
+    node = builder.extract_node("""
     class A:
         def f(self):
             return 42
@@ -584,8 +537,7 @@
 
 
     B().a.f()  #@
-    """
-    )
+    """)
     assert isinstance(node, nodes.NodeNG)
     inferred = node.inferred()
     assert len(inferred) == 1
diff --git a/tests/test_lookup.py b/tests/test_lookup.py
index bcee8f6..edcef7a 100644
--- a/tests/test_lookup.py
+++ b/tests/test_lookup.py
@@ -3,6 +3,7 @@
 # Copyright (c) https://github.com/pylint-dev/astroid/blob/main/CONTRIBUTORS.txt
 
 """Tests for the astroid variable lookup capabilities."""
+
 import functools
 import unittest
 
@@ -155,12 +156,10 @@
 
     def test_list_comp_target(self) -> None:
         """Test the list comprehension target."""
-        astroid = builder.parse(
-            """
+        astroid = builder.parse("""
             ten = [ var for var in range(10) ]
             var
-        """
-        )
+        """)
         var = astroid.body[1].value
         self.assertRaises(NameInferenceError, var.inferred)
 
@@ -199,12 +198,10 @@
         self.assertEqual(xnames[1].lookup("i")[1][0].lineno, 3)
 
     def test_set_comp_closure(self) -> None:
-        astroid = builder.parse(
-            """
+        astroid = builder.parse("""
             ten = { var for var in range(10) }
             var
-        """
-        )
+        """)
         var = astroid.body[1].value
         self.assertRaises(NameInferenceError, var.inferred)
 
@@ -249,34 +246,29 @@
         self.assertEqual(xnames[0].lookup("i")[1][0].lineno, 3)
 
     def test_lambda_nested(self) -> None:
-        astroid = builder.parse(
-            """
+        astroid = builder.parse("""
             f = lambda x: (
                     lambda y: x + y)
-        """
-        )
+        """)
         xnames = [n for n in astroid.nodes_of_class(nodes.Name) if n.name == "x"]
         self.assertEqual(len(xnames[0].lookup("x")[1]), 1)
         self.assertEqual(xnames[0].lookup("x")[1][0].lineno, 2)
 
     def test_function_nested(self) -> None:
-        astroid = builder.parse(
-            """
+        astroid = builder.parse("""
             def f1(x):
                 def f2(y):
                     return x + y
 
                 return f2
-        """
-        )
+        """)
         xnames = [n for n in astroid.nodes_of_class(nodes.Name) if n.name == "x"]
         self.assertEqual(len(xnames[0].lookup("x")[1]), 1)
         self.assertEqual(xnames[0].lookup("x")[1][0].lineno, 2)
 
     def test_class_variables(self) -> None:
         # Class variables are NOT available within nested scopes.
-        astroid = builder.parse(
-            """
+        astroid = builder.parse("""
             class A:
                 a = 10
 
@@ -289,8 +281,7 @@
 
                 class _Inner:
                     inner_a = a + 1
-            """
-        )
+            """)
         names = [n for n in astroid.nodes_of_class(nodes.Name) if n.name == "a"]
         self.assertEqual(len(names), 4)
         for name in names:
@@ -298,8 +289,7 @@
 
     def test_class_in_function(self) -> None:
         # Function variables are available within classes, including methods
-        astroid = builder.parse(
-            """
+        astroid = builder.parse("""
             def f():
                 x = 10
                 class A:
@@ -314,8 +304,7 @@
 
                     class _Inner:
                         inner_a = x + 1
-        """
-        )
+        """)
         names = [n for n in astroid.nodes_of_class(nodes.Name) if n.name == "x"]
         self.assertEqual(len(names), 5)
         for name in names:
diff --git a/tests/test_manager.py b/tests/test_manager.py
index 9a7bbdb..e420e6b 100644
--- a/tests/test_manager.py
+++ b/tests/test_manager.py
@@ -15,7 +15,7 @@
 import pytest
 
 import astroid
-from astroid import manager, test_utils
+from astroid import manager, nodes, test_utils
 from astroid.const import IS_JYTHON, IS_PYPY, PY312_PLUS
 from astroid.exceptions import (
     AstroidBuildingError,
@@ -107,7 +107,7 @@
         try:
             for name in ("foo", "bar", "baz"):
                 module = self.manager.ast_from_module_name("package." + name)
-                self.assertIsInstance(module, astroid.Module)
+                self.assertIsInstance(module, nodes.Module)
         finally:
             sys.path = origpath
 
@@ -120,8 +120,15 @@
     def test_identify_old_namespace_package_protocol(self) -> None:
         # Like the above cases, this package follows the old namespace package protocol
         # astroid currently assumes such packages are in sys.modules, so import it
-        # pylint: disable-next=import-outside-toplevel
-        import tests.testdata.python3.data.path_pkg_resources_1.package.foo as _  # noqa
+        with warnings.catch_warnings():
+            warnings.filterwarnings(
+                "ignore",
+                category=UserWarning,
+                message=".*pkg_resources is deprecated.*",
+            )
+
+            # pylint: disable-next=import-outside-toplevel
+            import tests.testdata.python3.data.path_pkg_resources_1.package.foo as _  # noqa
 
         self.assertTrue(
             util.is_namespace("tests.testdata.python3.data.path_pkg_resources_1")
@@ -174,10 +181,10 @@
 
         try:
             module = self.manager.ast_from_module_name("namespace_pep_420.module")
-            self.assertIsInstance(module, astroid.Module)
+            self.assertIsInstance(module, nodes.Module)
             self.assertEqual(module.name, "namespace_pep_420.module")
             var = next(module.igetattr("var"))
-            self.assertIsInstance(var, astroid.Const)
+            self.assertIsInstance(var, nodes.Const)
             self.assertEqual(var.value, 42)
         finally:
             for _ in range(2):
@@ -195,7 +202,7 @@
             module = self.manager.ast_from_module_name("foogle.fax")
             submodule = next(module.igetattr("a"))
             value = next(submodule.igetattr("x"))
-            self.assertIsInstance(value, astroid.Const)
+            self.assertIsInstance(value, nodes.Const)
             with self.assertRaises(AstroidImportError):
                 self.manager.ast_from_module_name("foogle.moogle")
         finally:
@@ -277,6 +284,17 @@
         finally:
             os.remove(linked_file_name)
 
+    def test_ast_from_module_name_pyz_with_submodule(self) -> None:
+        with self._restore_package_cache():
+            archive_path = os.path.join(resources.RESOURCE_PATH, "x.zip")
+            sys.path.insert(0, archive_path)
+            module = self.manager.ast_from_module_name("xxx.test")
+            self.assertEqual(module.name, "xxx.test")
+            end = os.path.join(archive_path, "xxx", "test")
+            self.assertTrue(
+                module.file.endswith(end), f"{module.file} doesn't endswith {end}"
+            )
+
     def test_zip_import_data(self) -> None:
         """Check if zip_import_data works."""
         with self._restore_package_cache():
diff --git a/tests/test_modutils.py b/tests/test_modutils.py
index e1b4be3..e85e7ff 100644
--- a/tests/test_modutils.py
+++ b/tests/test_modutils.py
@@ -3,6 +3,7 @@
 # Copyright (c) https://github.com/pylint-dev/astroid/blob/main/CONTRIBUTORS.txt
 
 """Unit tests for module modutils (module manipulation utilities)."""
+
 import email
 import logging
 import os
@@ -20,7 +21,6 @@
 
 import astroid
 from astroid import modutils
-from astroid.const import PY310_PLUS
 from astroid.interpreter._import import spec
 
 from . import resources
@@ -152,6 +152,31 @@
         self.assertEqual(modutils.get_module_part(".", modutils.__file__), ".")
 
 
+class IsSubpathTest(unittest.TestCase):
+    """Tests for modutils._is_subpath,
+    which is used internally by modutils.modpath_from_file."""
+
+    @unittest.skipUnless(sys.platform == "win32", "Windows-specific path test")
+    def test_is_subpath_with_trailing_separator_unc_path(self) -> None:
+        self.assertTrue(
+            modutils._is_subpath(
+                "\\\\Mac\\Code\\tests\\test_resources.py",
+                # UNC path with trailing separator
+                "\\\\mac\\code\\",
+            )
+        )
+
+    @unittest.skipUnless(sys.platform == "win32", "Windows-specific path test")
+    def test_is_subpath_without_trailing_separator_unc_path(self) -> None:
+        self.assertTrue(
+            modutils._is_subpath(
+                "\\\\Mac\\Code\\tests\\test_resources.py",
+                # UNC path without trailing separator
+                "\\\\mac\\code",
+            )
+        )
+
+
 class ModPathFromFileTest(unittest.TestCase):
     """Given an absolute file path return the python module's path as a list."""
 
@@ -162,7 +187,7 @@
         )
 
     def test_raise_modpath_from_file_exception(self) -> None:
-        self.assertRaises(Exception, modutils.modpath_from_file, "/turlututu")
+        self.assertRaises(ImportError, modutils.modpath_from_file, "/turlututu")
 
     def test_import_symlink_with_source_outside_of_path(self) -> None:
         with tempfile.NamedTemporaryFile() as tmpfile:
@@ -335,6 +360,22 @@
             os.path.normpath(module) + "i",
         )
 
+    def test_nonstandard_extension(self) -> None:
+        package = resources.find("pyi_data/find_test")
+        modules = [
+            os.path.join(package, "__init__.weird_ext"),
+            os.path.join(package, "standalone_file.weird_ext"),
+        ]
+        for module in modules:
+            self.assertEqual(
+                modutils.get_source_file(module, prefer_stubs=True),
+                module,
+            )
+            self.assertEqual(
+                modutils.get_source_file(module),
+                module,
+            )
+
 
 class IsStandardModuleTest(resources.SysPathSetup, unittest.TestCase):
     """
@@ -486,18 +527,6 @@
         assert not modutils.module_in_path("astroid", datadir)
 
 
-class BackportStdlibNamesTest(resources.SysPathSetup, unittest.TestCase):
-    """
-    Verify backport raises exception on newer versions
-    """
-
-    @pytest.mark.skipif(not PY310_PLUS, reason="Backport valid on <=3.9")
-    def test_import_error(self) -> None:
-        with pytest.raises(AssertionError):
-            # pylint: disable-next=import-outside-toplevel, unused-import
-            from astroid import _backport_stdlib_names  # noqa
-
-
 class IsRelativeTest(unittest.TestCase):
     def test_known_values_is_relative_1(self) -> None:
         self.assertTrue(modutils.is_relative("utils", email.__path__[0]))
diff --git a/tests/test_nodes.py b/tests/test_nodes.py
index ffa5115..4bba86b 100644
--- a/tests/test_nodes.py
+++ b/tests/test_nodes.py
@@ -13,6 +13,7 @@
 import sys
 import textwrap
 import unittest
+import warnings
 from typing import Any
 
 import pytest
@@ -28,29 +29,24 @@
     transforms,
     util,
 )
-from astroid.const import IS_PYPY, PY310_PLUS, PY312_PLUS, Context
+from astroid.const import (
+    IS_PYPY,
+    PY311_PLUS,
+    PY312_PLUS,
+    PY313_PLUS,
+    PY314_PLUS,
+    Context,
+)
 from astroid.context import InferenceContext
 from astroid.exceptions import (
     AstroidBuildingError,
     AstroidSyntaxError,
+    AstroidTypeError,
     AttributeInferenceError,
     StatementMissing,
 )
-from astroid.nodes.node_classes import (
-    AssignAttr,
-    AssignName,
-    Attribute,
-    Call,
-    ImportFrom,
-    Tuple,
-)
-from astroid.nodes.scoped_nodes import (
-    SYNTHETIC_ROOT,
-    ClassDef,
-    FunctionDef,
-    GeneratorExp,
-    Module,
-)
+from astroid.nodes.node_classes import UNATTACHED_UNKNOWN
+from astroid.nodes.scoped_nodes import SYNTHETIC_ROOT
 from tests.testdata.python3.recursion_error import LONG_CHAINED_METHOD_CALL
 
 from . import resources
@@ -60,7 +56,7 @@
 
 class AsStringTest(resources.SysPathSetup, unittest.TestCase):
     def test_tuple_as_string(self) -> None:
-        def build(string: str) -> Tuple:
+        def build(string: str) -> nodes.Tuple:
             return abuilder.string_build(string).body[0].value
 
         self.assertEqual(build("1,").as_string(), "(1, )")
@@ -69,38 +65,32 @@
         self.assertEqual(build("1, 2, 3").as_string(), "(1, 2, 3)")
 
     def test_func_signature_issue_185(self) -> None:
-        code = textwrap.dedent(
-            """
+        code = textwrap.dedent("""
         def test(a, b, c=42, *, x=42, **kwargs):
             print(a, b, c, args)
-        """
-        )
+        """)
         node = parse(code)
         self.assertEqual(node.as_string().strip(), code.strip())
 
     def test_as_string_for_list_containing_uninferable(self) -> None:
-        node = builder.extract_node(
-            """
+        node = builder.extract_node("""
         def foo():
             bar = [arg] * 1
-        """
-        )
+        """)
         binop = node.body[0].value
         inferred = next(binop.infer())
         self.assertEqual(inferred.as_string(), "[Uninferable]")
         self.assertEqual(binop.as_string(), "[arg] * 1")
 
     def test_frozenset_as_string(self) -> None:
-        ast_nodes = builder.extract_node(
-            """
+        ast_nodes = builder.extract_node("""
         frozenset((1, 2, 3)) #@
         frozenset({1, 2, 3}) #@
         frozenset([1, 2, 3,]) #@
 
         frozenset(None) #@
         frozenset(1) #@
-        """
-        )
+        """)
         ast_nodes = [next(node.infer()) for node in ast_nodes]
         assert isinstance(ast_nodes, list)
         self.assertEqual(ast_nodes[0].as_string(), "frozenset((1, 2, 3))")
@@ -114,11 +104,31 @@
         ast = abuilder.string_build("raise_string(*args, **kwargs)").body[0]
         self.assertEqual(ast.as_string(), "raise_string(*args, **kwargs)")
 
-    def test_module_as_string(self) -> None:
-        """Check as_string on a whole module prepared to be returned identically."""
+    @pytest.mark.skipif(PY314_PLUS, reason="return in finally is now a syntax error")
+    def test_module_as_string_pre_3_14(self) -> None:
+        """Check as_string on a whole module prepared to be returned identically for py < 3.14."""
+        self.maxDiff = None
         module = resources.build_file("data/module.py", "data.module")
         with open(resources.find("data/module.py"), encoding="utf-8") as fobj:
-            self.assertMultiLineEqual(module.as_string(), fobj.read())
+            # Ignore comments in python file
+            data_str = "\n".join(
+                [s for s in fobj.read().split("\n") if not s.lstrip().startswith("# ")]
+            )
+            self.assertMultiLineEqual(module.as_string(), data_str)
+
+    @pytest.mark.skipif(
+        not PY314_PLUS, reason="return in finally is now a syntax error"
+    )
+    def test_module_as_string(self) -> None:
+        """Check as_string on a whole module prepared to be returned identically for py > 3.14."""
+        self.maxDiff = None
+        module = resources.build_file("data/module3.14.py", "data.module3.14")
+        with open(resources.find("data/module3.14.py"), encoding="utf-8") as fobj:
+            # Ignore comments in python file
+            data_str = "\n".join(
+                [s for s in fobj.read().split("\n") if not s.lstrip().startswith("# ")]
+            )
+            self.assertMultiLineEqual(module.as_string(), data_str)
 
     def test_module2_as_string(self) -> None:
         """Check as_string on a whole module prepared to be returned identically."""
@@ -281,8 +291,10 @@
 
     @staticmethod
     def test_as_string_unknown() -> None:
-        assert nodes.Unknown().as_string() == "Unknown.Unknown()"
-        assert nodes.Unknown(lineno=1, col_offset=0).as_string() == "Unknown.Unknown()"
+        unknown1 = nodes.Unknown(parent=SYNTHETIC_ROOT)
+        unknown2 = nodes.Unknown(lineno=1, col_offset=0, parent=SYNTHETIC_ROOT)
+        assert unknown1.as_string() == "Unknown.Unknown()"
+        assert unknown2.as_string() == "Unknown.Unknown()"
 
     @staticmethod
     @pytest.mark.skipif(
@@ -303,15 +315,34 @@
 class AsStringTypeParamNodes(unittest.TestCase):
     @staticmethod
     def test_as_string_type_alias() -> None:
-        ast = abuilder.string_build("type Point = tuple[float, float]")
-        type_alias = ast.body[0]
-        assert type_alias.as_string().strip() == "Point"
+        ast1 = abuilder.string_build("type Point = tuple[float, float]")
+        type_alias1 = ast1.body[0]
+        assert type_alias1.as_string().strip() == "type Point = tuple[float, float]"
+        ast2 = abuilder.string_build(
+            "type Point[T, **P] = tuple[float, T, Callable[P, None]]"
+        )
+        type_alias2 = ast2.body[0]
+        assert (
+            type_alias2.as_string().strip()
+            == "type Point[T, **P] = tuple[float, T, Callable[P, None]]"
+        )
 
     @staticmethod
     def test_as_string_type_var() -> None:
-        ast = abuilder.string_build("type Point[T] = tuple[float, float]")
+        ast = abuilder.string_build("type Point[T: int | str] = tuple[float, float]")
         type_var = ast.body[0].type_params[0]
-        assert type_var.as_string().strip() == "T"
+        assert type_var.as_string().strip() == "T: int | str"
+
+    @staticmethod
+    @pytest.mark.skipif(
+        not PY313_PLUS, reason="Type parameter defaults were added in 313"
+    )
+    def test_as_string_type_var_default() -> None:
+        ast = abuilder.string_build(
+            "type Point[T: int | str = int] = tuple[float, float]"
+        )
+        type_var = ast.body[0].type_params[0]
+        assert type_var.as_string().strip() == "T: int | str = int"
 
     @staticmethod
     def test_as_string_type_var_tuple() -> None:
@@ -320,10 +351,40 @@
         assert type_var_tuple.as_string().strip() == "*Ts"
 
     @staticmethod
+    @pytest.mark.skipif(
+        not PY313_PLUS, reason="Type parameter defaults were added in 313"
+    )
+    def test_as_string_type_var_tuple_defaults() -> None:
+        ast = abuilder.string_build("type Alias[*Ts = tuple[int, str]] = tuple[*Ts]")
+        type_var_tuple = ast.body[0].type_params[0]
+        assert type_var_tuple.as_string().strip() == "*Ts = tuple[int, str]"
+
+    @staticmethod
     def test_as_string_param_spec() -> None:
         ast = abuilder.string_build("type Alias[**P] = Callable[P, int]")
         param_spec = ast.body[0].type_params[0]
-        assert param_spec.as_string().strip() == "P"
+        assert param_spec.as_string().strip() == "**P"
+
+    @staticmethod
+    @pytest.mark.skipif(
+        not PY313_PLUS, reason="Type parameter defaults were added in 313"
+    )
+    def test_as_string_param_spec_defaults() -> None:
+        ast = abuilder.string_build("type Alias[**P = [str, int]] = Callable[P, int]")
+        param_spec = ast.body[0].type_params[0]
+        assert param_spec.as_string().strip() == "**P = [str, int]"
+
+    @staticmethod
+    def test_as_string_class_type_params() -> None:
+        code = abuilder.string_build("class A[T, **P]: ...")
+        cls_node = code.body[0]
+        assert cls_node.as_string().strip() == "class A[T, **P]:\n    ..."
+
+    @staticmethod
+    def test_as_string_function_type_params() -> None:
+        code = abuilder.string_build("def func[T, **P](): ...")
+        func_node = code.body[0]
+        assert func_node.as_string().strip() == "def func[T, **P]():\n    ..."
 
 
 class _NodeTest(unittest.TestCase):
@@ -332,7 +393,7 @@
     CODE = ""
 
     @property
-    def astroid(self) -> Module:
+    def astroid(self) -> nodes.Module:
         try:
             return self.__class__.__dict__["CODE_Astroid"]
         except KeyError:
@@ -527,9 +588,7 @@
         ast = self.module["modutils"]
         self.assertEqual(ast.as_string(), "from astroid import modutils")
         ast = self.module["NameNode"]
-        self.assertEqual(
-            ast.as_string(), "from astroid.nodes.node_classes import Name as NameNode"
-        )
+        self.assertEqual(ast.as_string(), "from astroid.nodes import Name as NameNode")
         ast = self.module["os"]
         self.assertEqual(ast.as_string(), "import os.path")
         code = """from . import here
@@ -646,11 +705,9 @@
         self._test("a")
 
     def test_str_kind(self):
-        node = builder.extract_node(
-            """
+        node = builder.extract_node("""
             const = u"foo"
-        """
-        )
+        """)
         assert isinstance(node.value, nodes.Const)
         assert node.value.value == "foo"
         assert node.value.kind, "u"
@@ -682,8 +739,7 @@
         """Test if the frame of NamedExpr is correctly set for certain types
         of parent nodes.
         """
-        module = builder.parse(
-            """
+        module = builder.parse("""
             def func(var_1):
                 pass
 
@@ -706,8 +762,7 @@
                 pass
 
             COMPREHENSION = [y for i in (1, 2) if (y := i ** 2)]
-        """
-        )
+        """)
         function = module.body[0]
         assert function.args.frame() == function
         assert function.args.frame() == function
@@ -745,8 +800,7 @@
         """Test if the scope of NamedExpr is correctly set for certain types
         of parent nodes.
         """
-        module = builder.parse(
-            """
+        module = builder.parse("""
             def func(var_1):
                 pass
 
@@ -769,8 +823,7 @@
                 pass
 
             COMPREHENSION = [y for i in (1, 2) if (y := i ** 2)]
-        """
-        )
+        """)
         function = module.body[0]
         assert function.args.scope() == function
 
@@ -796,11 +849,9 @@
 
 class AnnAssignNodeTest(unittest.TestCase):
     def test_primitive(self) -> None:
-        code = textwrap.dedent(
-            """
+        code = textwrap.dedent("""
             test: int = 5
-        """
-        )
+        """)
         assign = builder.extract_node(code)
         self.assertIsInstance(assign, nodes.AnnAssign)
         self.assertEqual(assign.target.name, "test")
@@ -809,11 +860,9 @@
         self.assertEqual(assign.simple, 1)
 
     def test_primitive_without_initial_value(self) -> None:
-        code = textwrap.dedent(
-            """
+        code = textwrap.dedent("""
             test: str
-        """
-        )
+        """)
         assign = builder.extract_node(code)
         self.assertIsInstance(assign, nodes.AnnAssign)
         self.assertEqual(assign.target.name, "test")
@@ -821,39 +870,33 @@
         self.assertEqual(assign.value, None)
 
     def test_complex(self) -> None:
-        code = textwrap.dedent(
-            """
+        code = textwrap.dedent("""
             test: Dict[List[str]] = {}
-        """
-        )
+        """)
         assign = builder.extract_node(code)
         self.assertIsInstance(assign, nodes.AnnAssign)
         self.assertEqual(assign.target.name, "test")
-        self.assertIsInstance(assign.annotation, astroid.Subscript)
-        self.assertIsInstance(assign.value, astroid.Dict)
+        self.assertIsInstance(assign.annotation, nodes.Subscript)
+        self.assertIsInstance(assign.value, nodes.Dict)
 
     def test_as_string(self) -> None:
-        code = textwrap.dedent(
-            """
+        code = textwrap.dedent("""
             print()
             test: int = 5
             test2: str
             test3: List[Dict[str, str]] = []
-        """
-        )
+        """)
         ast = abuilder.string_build(code)
         self.assertEqual(ast.as_string().strip(), code.strip())
 
 
 class ArgumentsNodeTC(unittest.TestCase):
     def test_linenumbering(self) -> None:
-        ast = builder.parse(
-            """
+        ast = builder.parse("""
             def func(a,
                 b): pass
             x = lambda x: None
-        """
-        )
+        """)
         self.assertEqual(ast["func"].args.fromlineno, 2)
         self.assertFalse(ast["func"].args.is_statement)
         xlambda = next(ast["x"].infer())
@@ -862,23 +905,19 @@
         self.assertFalse(xlambda.args.is_statement)
 
     def test_kwoargs(self) -> None:
-        ast = builder.parse(
-            """
+        ast = builder.parse("""
             def func(*, x):
                 pass
-        """
-        )
+        """)
         args = ast["func"].args
         assert isinstance(args, nodes.Arguments)
         assert args.is_argument("x")
         assert args.kw_defaults == [None]
 
-        ast = builder.parse(
-            """
+        ast = builder.parse("""
             def func(*, x = "default"):
                 pass
-        """
-        )
+        """)
         args = ast["func"].args
         assert isinstance(args, nodes.Arguments)
         assert args.is_argument("x")
@@ -887,12 +926,10 @@
         assert args.kw_defaults[0].value == "default"
 
     def test_positional_only(self):
-        ast = builder.parse(
-            """
+        ast = builder.parse("""
             def func(x, /, y):
                 pass
-        """
-        )
+        """)
         args = ast["func"].args
         self.assertTrue(args.is_argument("x"))
         self.assertTrue(args.is_argument("y"))
@@ -907,14 +944,12 @@
         # https://bitbucket.org/logilab/astroid/issue/91, which tests
         # that UnboundMethod doesn't call super when doing .getattr.
 
-        ast = builder.parse(
-            """
+        ast = builder.parse("""
         class A(object):
             def test(self):
                 pass
         meth = A.test
-        """
-        )
+        """)
         node = next(ast["meth"].infer())
         with self.assertRaises(AttributeInferenceError):
             node.getattr("__missssing__")
@@ -924,97 +959,290 @@
 
 
 class BoundMethodNodeTest(unittest.TestCase):
-    def test_is_property(self) -> None:
-        ast = builder.parse(
-            """
-        import abc
+    def _is_property(self, ast: nodes.Module, prop: str) -> None:
+        inferred = next(ast[prop].infer())
+        self.assertIsInstance(inferred, nodes.Const, prop)
+        self.assertEqual(inferred.value, 42, prop)
 
-        def cached_property():
-            # Not a real decorator, but we don't care
-            pass
-        def reify():
-            # Same as cached_property
-            pass
-        def lazy_property():
-            pass
-        def lazyproperty():
-            pass
-        def lazy(): pass
+    def test_is_standard_property(self) -> None:
+        # Test to make sure the Python-provided property decorators
+        # are properly interpreted as properties
+        ast = builder.parse("""
+        import abc
+        import functools
+
         class A(object):
             @property
-            def builtin_property(self):
-                return 42
+            def builtin_property(self): return 42
+
             @abc.abstractproperty
-            def abc_property(self):
-                return 42
+            def abc_property(self): return 42
+
+            @property
+            @abc.abstractmethod
+            def abstractmethod_property(self): return 42
+
+            @functools.cached_property
+            def functools_property(self): return 42
+
+        cls = A()
+        builtin_p = cls.builtin_property
+        abc_p = cls.abc_property
+        abstractmethod_p = cls.abstractmethod_property
+        functools_p = cls.functools_property
+        """)
+        for prop in (
+            "builtin_p",
+            "abc_p",
+            "abstractmethod_p",
+            "functools_p",
+        ):
+            self._is_property(ast, prop)
+
+    @pytest.mark.skipif(not PY311_PLUS, reason="Uses enum.property introduced in 3.11")
+    def test_is_standard_property_py311(self) -> None:
+        # Test to make sure the Python-provided property decorators
+        # are properly interpreted as properties
+        ast = builder.parse("""
+        import enum
+
+        class A(object):
+            @enum.property
+            def enum_property(self): return 42
+
+        cls = A()
+        enum_p = cls.enum_property
+        """)
+        self._is_property(ast, "enum_p")
+
+    def test_is_possible_property(self) -> None:
+        # Test to make sure that decorators with POSSIBLE_PROPERTIES names
+        # are properly interpreted as properties
+        ast = builder.parse("""
+        # Not real decorators, but we don't care
+        def cachedproperty(): pass
+        def cached_property(): pass
+        def reify(): pass
+        def lazy_property(): pass
+        def lazyproperty(): pass
+        def lazy(): pass
+        def lazyattribute(): pass
+        def lazy_attribute(): pass
+        def LazyProperty(): pass
+        def DynamicClassAttribute(): pass
+
+        class A(object):
+            @cachedproperty
+            def cachedproperty(self): return 42
+
             @cached_property
             def cached_property(self): return 42
+
             @reify
             def reified(self): return 42
+
             @lazy_property
             def lazy_prop(self): return 42
+
             @lazyproperty
             def lazyprop(self): return 42
-            def not_prop(self): pass
+
             @lazy
             def decorated_with_lazy(self): return 42
 
+            @lazyattribute
+            def lazyattribute(self): return 42
+
+            @lazy_attribute
+            def lazy_attribute(self): return 42
+
+            @LazyProperty
+            def LazyProperty(self): return 42
+
+            @DynamicClassAttribute
+            def DynamicClassAttribute(self): return 42
+
         cls = A()
-        builtin_property = cls.builtin_property
-        abc_property = cls.abc_property
+        cachedp = cls.cachedproperty
         cached_p = cls.cached_property
         reified = cls.reified
-        not_prop = cls.not_prop
         lazy_prop = cls.lazy_prop
         lazyprop = cls.lazyprop
         decorated_with_lazy = cls.decorated_with_lazy
-        """
-        )
+        lazya = cls.lazyattribute
+        lazy_a = cls.lazy_attribute
+        LazyP = cls.LazyProperty
+        DynamicClassA = cls.DynamicClassAttribute
+        """)
         for prop in (
-            "builtin_property",
-            "abc_property",
+            "cachedp",
             "cached_p",
             "reified",
             "lazy_prop",
             "lazyprop",
             "decorated_with_lazy",
+            "lazya",
+            "lazy_a",
+            "LazyP",
+            "DynamicClassA",
+        ):
+            self._is_property(ast, prop)
+
+    def test_is_standard_property_subclass(self) -> None:
+        # Test to make sure that subclasses of the Python-provided property decorators
+        # are properly interpreted as properties
+        ast = builder.parse("""
+        import abc
+        import functools
+        from typing import Generic, TypeVar
+
+        class user_property(property): pass
+        class user_abc_property(abc.abstractproperty): pass
+        class user_functools_property(functools.cached_property): pass
+        T = TypeVar('T')
+        class annotated_user_functools_property(functools.cached_property[T], Generic[T]): pass
+
+        class A(object):
+            @user_property
+            def user_property(self): return 42
+
+            @user_abc_property
+            def user_abc_property(self): return 42
+
+            @user_functools_property
+            def user_functools_property(self): return 42
+
+            @annotated_user_functools_property
+            def annotated_user_functools_property(self): return 42
+
+        cls = A()
+        user_p = cls.user_property
+        user_abc_p = cls.user_abc_property
+        user_functools_p = cls.user_functools_property
+        annotated_user_functools_p = cls.annotated_user_functools_property
+        """)
+        for prop in (
+            "user_p",
+            "user_abc_p",
+            "user_functools_p",
+            "annotated_user_functools_p",
+        ):
+            self._is_property(ast, prop)
+
+    @pytest.mark.skipif(not PY311_PLUS, reason="Uses enum.property introduced in 3.11")
+    def test_is_standard_property_subclass_py311(self) -> None:
+        # Test to make sure that subclasses of the Python-provided property decorators
+        # are properly interpreted as properties
+        ast = builder.parse("""
+        import enum
+
+        class user_enum_property(enum.property): pass
+
+        class A(object):
+            @user_enum_property
+            def user_enum_property(self): return 42
+
+        cls = A()
+        user_enum_p = cls.user_enum_property
+        """)
+        self._is_property(ast, "user_enum_p")
+
+    @pytest.mark.skipif(not PY312_PLUS, reason="Uses 3.12 generic typing syntax")
+    def test_is_standard_property_subclass_py312(self) -> None:
+        ast = builder.parse("""
+        from functools import cached_property
+
+        class annotated_user_cached_property[T](cached_property[T]):
+            pass
+
+        class A(object):
+            @annotated_user_cached_property
+            def annotated_user_cached_property(self): return 42
+
+        cls = A()
+        annotated_user_cached_p = cls.annotated_user_cached_property
+        """)
+        self._is_property(ast, "annotated_user_cached_p")
+
+    def test_is_not_property(self) -> None:
+        ast = builder.parse("""
+        from collections.abc import Iterator
+
+        class cached_property: pass
+        # If a decorator is named cached_property, we will accept it as a property,
+        # even if it isn't functools.cached_property.
+        # However, do not extend the same leniency to superclasses of decorators.
+        class wrong_superclass_type1(cached_property): pass
+        class wrong_superclass_type2(cached_property[float]): pass
+        cachedproperty = { float: int }
+        class wrong_superclass_type3(cachedproperty[float]): pass
+        class wrong_superclass_type4(Iterator[float]): pass
+
+        class A(object):
+            def no_decorator(self): return 42
+
+            def property(self): return 42
+
+            @wrong_superclass_type1
+            def wrong_superclass_type1(self): return 42
+
+            @wrong_superclass_type2
+            def wrong_superclass_type2(self): return 42
+
+            @wrong_superclass_type3
+            def wrong_superclass_type3(self): return 42
+
+            @wrong_superclass_type4
+            def wrong_superclass_type4(self): return 42
+
+        cls = A()
+        no_decorator = cls.no_decorator
+        not_prop = cls.property
+        bad_superclass1 = cls.wrong_superclass_type1
+        bad_superclass2 = cls.wrong_superclass_type2
+        bad_superclass3 = cls.wrong_superclass_type3
+        bad_superclass4 = cls.wrong_superclass_type4
+        """)
+        for prop in (
+            "no_decorator",
+            "not_prop",
+            "bad_superclass1",
+            "bad_superclass2",
+            "bad_superclass3",
+            "bad_superclass4",
         ):
             inferred = next(ast[prop].infer())
-            self.assertIsInstance(inferred, nodes.Const, prop)
-            self.assertEqual(inferred.value, 42, prop)
-
-        inferred = next(ast["not_prop"].infer())
-        self.assertIsInstance(inferred, bases.BoundMethod)
+            self.assertIsInstance(inferred, bases.BoundMethod)
 
 
 class AliasesTest(unittest.TestCase):
     def setUp(self) -> None:
         self.transformer = transforms.TransformVisitor()
 
-    def parse_transform(self, code: str) -> Module:
+    def parse_transform(self, code: str) -> nodes.Module:
         module = parse(code, apply_transforms=False)
         return self.transformer.visit(module)
 
     def test_aliases(self) -> None:
-        def test_from(node: ImportFrom) -> ImportFrom:
+        def test_from(node: nodes.ImportFrom) -> nodes.ImportFrom:
             node.names = [*node.names, ("absolute_import", None)]
             return node
 
-        def test_class(node: ClassDef) -> ClassDef:
+        def test_class(node: nodes.ClassDef) -> nodes.ClassDef:
             node.name = "Bar"
             return node
 
-        def test_function(node: FunctionDef) -> FunctionDef:
+        def test_function(node: nodes.FunctionDef) -> nodes.FunctionDef:
             node.name = "another_test"
             return node
 
-        def test_callfunc(node: Call) -> Call | None:
+        def test_callfunc(node: nodes.Call) -> nodes.Call | None:
             if node.func.name == "Foo":
                 node.func.name = "Bar"
                 return node
             return None
 
-        def test_assname(node: AssignName) -> AssignName | None:
+        def test_assname(node: nodes.AssignName) -> nodes.AssignName | None:
             if node.name == "foo":
                 return nodes.AssignName(
                     "bar",
@@ -1026,19 +1254,19 @@
                 )
             return None
 
-        def test_assattr(node: AssignAttr) -> AssignAttr:
+        def test_assattr(node: nodes.AssignAttr) -> nodes.AssignAttr:
             if node.attrname == "a":
                 node.attrname = "b"
                 return node
             return None
 
-        def test_getattr(node: Attribute) -> Attribute:
+        def test_getattr(node: nodes.Attribute) -> nodes.Attribute:
             if node.attrname == "a":
                 node.attrname = "b"
                 return node
             return None
 
-        def test_genexpr(node: GeneratorExp) -> GeneratorExp:
+        def test_genexpr(node: nodes.GeneratorExp) -> nodes.GeneratorExp:
             if node.elt.value == 1:
                 node.elt = nodes.Const(2, node.lineno, node.col_offset, node.parent)
                 return node
@@ -1141,46 +1369,38 @@
         self.assertEqual(ast_node.as_string().strip(), code.strip())
 
     def test_await_as_string(self) -> None:
-        code = textwrap.dedent(
-            """
+        code = textwrap.dedent("""
         async def function():
             await 42
             await x[0]
             (await x)[0]
             await (x + y)[0]
-        """
-        )
+        """)
         self._test_await_async_as_string(code)
 
     def test_asyncwith_as_string(self) -> None:
-        code = textwrap.dedent(
-            """
+        code = textwrap.dedent("""
         async def function():
             async with 42:
                 pass
-        """
-        )
+        """)
         self._test_await_async_as_string(code)
 
     def test_asyncfor_as_string(self) -> None:
-        code = textwrap.dedent(
-            """
+        code = textwrap.dedent("""
         async def function():
             async for i in range(10):
                 await 42
-        """
-        )
+        """)
         self._test_await_async_as_string(code)
 
     def test_decorated_async_def_as_string(self) -> None:
-        code = textwrap.dedent(
-            """
+        code = textwrap.dedent("""
         @decorator
         async def function():
             async for i in range(10):
                 await 42
-        """
-        )
+        """)
         self._test_await_async_as_string(code)
 
 
@@ -1231,74 +1451,65 @@
 
 def test_unknown() -> None:
     """Test Unknown node."""
-    assert isinstance(next(nodes.Unknown().infer()), type(util.Uninferable))
-    assert isinstance(nodes.Unknown().name, str)
-    assert isinstance(nodes.Unknown().qname(), str)
+    assert isinstance(next(UNATTACHED_UNKNOWN.infer()), type(util.Uninferable))
+    assert isinstance(UNATTACHED_UNKNOWN.name, str)
+    assert isinstance(UNATTACHED_UNKNOWN.qname(), str)
 
 
 def test_type_comments_with() -> None:
-    module = builder.parse(
-        """
+    module = builder.parse("""
     with a as b: # type: int
         pass
     with a as b: # type: ignore[name-defined]
         pass
-    """
-    )
+    """)
     node = module.body[0]
     ignored_node = module.body[1]
-    assert isinstance(node.type_annotation, astroid.Name)
+    assert isinstance(node.type_annotation, nodes.Name)
 
     assert ignored_node.type_annotation is None
 
 
 def test_type_comments_for() -> None:
-    module = builder.parse(
-        """
+    module = builder.parse("""
     for a, b in [1, 2, 3]: # type: List[int]
         pass
     for a, b in [1, 2, 3]: # type: ignore[name-defined]
         pass
-    """
-    )
+    """)
     node = module.body[0]
     ignored_node = module.body[1]
-    assert isinstance(node.type_annotation, astroid.Subscript)
+    assert isinstance(node.type_annotation, nodes.Subscript)
     assert node.type_annotation.as_string() == "List[int]"
 
     assert ignored_node.type_annotation is None
 
 
 def test_type_coments_assign() -> None:
-    module = builder.parse(
-        """
+    module = builder.parse("""
     a, b = [1, 2, 3] # type: List[int]
     a, b = [1, 2, 3] # type: ignore[name-defined]
-    """
-    )
+    """)
     node = module.body[0]
     ignored_node = module.body[1]
-    assert isinstance(node.type_annotation, astroid.Subscript)
+    assert isinstance(node.type_annotation, nodes.Subscript)
     assert node.type_annotation.as_string() == "List[int]"
 
     assert ignored_node.type_annotation is None
 
 
 def test_type_comments_invalid_expression() -> None:
-    module = builder.parse(
-        """
+    module = builder.parse("""
     a, b = [1, 2, 3] # type: something completely invalid
     a, b = [1, 2, 3] # typeee: 2*+4
     a, b = [1, 2, 3] # type: List[int
-    """
-    )
+    """)
     for node in module.body:
         assert node.type_annotation is None
 
 
 def test_type_comments_invalid_function_comments() -> None:
-    module = builder.parse(
-        """
+    module = builder.parse("""
     def func(
         # type: () -> int # inside parentheses
     ):
@@ -1312,16 +1523,14 @@
     def func2():
         # type: List[int
         pass
-    """
-    )
+    """)
     for node in module.body:
         assert node.type_comment_returns is None
         assert node.type_comment_args is None
 
 
 def test_type_comments_function() -> None:
-    module = builder.parse(
-        """
+    module = builder.parse("""
     def func():
         # type: (int) -> str
         pass
@@ -1331,12 +1540,11 @@
     def func2():
         # type: (int, int, str, List[int]) -> List[int]
         pass
-    """
-    )
+    """)
     expected_annotations = [
-        (["int"], astroid.Name, "str"),
-        (["int", "int", "int"], astroid.Tuple, "(str, str)"),
-        (["int", "int", "str", "List[int]"], astroid.Subscript, "List[int]"),
+        (["int"], nodes.Name, "str"),
+        (["int", "int", "int"], nodes.Tuple, "(str, str)"),
+        (["int", "int", "str", "List[int]"], nodes.Subscript, "List[int]"),
     ]
     for node, (expected_args, expected_returns_type, expected_returns_string) in zip(
         module.body, expected_annotations
@@ -1350,8 +1558,7 @@
 
 
 def test_type_comments_arguments() -> None:
-    module = builder.parse(
-        """
+    module = builder.parse("""
     def func(
         a,  # type: int
     ):
@@ -1372,8 +1579,7 @@
     ):
         # type: (...) -> List[int]
         pass
-    """
-    )
+    """)
     expected_annotations = [
         ["int"],
         ["int", "int", "int"],
@@ -1381,7 +1587,7 @@
     ]
     for node, expected_args in zip(module.body, expected_annotations):
         assert len(node.type_comment_args) == 1
-        assert isinstance(node.type_comment_args[0], astroid.Const)
+        assert isinstance(node.type_comment_args[0], nodes.Const)
         assert node.type_comment_args[0].value == Ellipsis
         assert len(node.args.type_comment_args) == len(expected_args)
         for expected_arg, actual_arg in zip(expected_args, node.args.type_comment_args):
@@ -1389,8 +1595,7 @@
 
 
 def test_type_comments_posonly_arguments() -> None:
-    module = builder.parse(
-        """
+    module = builder.parse("""
     def f_arg_comment(
         a,  # type: int
         b,  # type: int
@@ -1403,14 +1608,13 @@
     ):
         # type: (...) -> None
         pass
-    """
-    )
+    """)
     expected_annotations = [
         [["int", "int"], ["Optional[int]", "Optional[int]"], ["float", "float"]]
     ]
     for node, expected_types in zip(module.body, expected_annotations):
         assert len(node.type_comment_args) == 1
-        assert isinstance(node.type_comment_args[0], astroid.Const)
+        assert isinstance(node.type_comment_args[0], nodes.Const)
         assert node.type_comment_args[0].value == Ellipsis
         type_comments = [
             node.args.type_comment_posonlyargs,
@@ -1436,8 +1640,7 @@
 
 
 def test_is_generator_for_yield_assignments() -> None:
-    node = astroid.extract_node(
-        """
+    node = astroid.extract_node("""
     class A:
         def test(self):
             a = yield
@@ -1446,8 +1649,7 @@
                 yield a
     a = A()
     a.test
-    """
-    )
+    """)
     inferred = next(node.infer())
     assert isinstance(inferred, astroid.BoundMethod)
     assert bool(inferred.is_generator())
@@ -1455,15 +1657,13 @@
 
 class AsyncGeneratorTest(unittest.TestCase):
     def test_async_generator(self):
-        node = astroid.extract_node(
-            """
+        node = astroid.extract_node("""
         async def a_iter(n):
             for i in range(1, n + 1):
                 yield i
                 await asyncio.sleep(1)
         a_iter(2) #@
-        """
-        )
+        """)
         inferred = next(node.infer())
         assert isinstance(inferred, bases.AsyncGenerator)
         assert inferred.getattr("__aiter__")
@@ -1474,14 +1674,12 @@
 
 def test_f_string_correct_line_numbering() -> None:
     """Test that we generate correct line numbers for f-strings."""
-    node = astroid.extract_node(
-        """
+    node = astroid.extract_node("""
     def func_foo(arg_bar, arg_foo):
         dict_foo = {}
 
         f'{arg_bar.attr_bar}' #@
-    """
-    )
+    """)
     assert node.lineno == 5
     assert node.last_child().lineno == 5
     assert node.last_child().last_child().lineno == 5
@@ -1584,13 +1782,11 @@
 
 
 def test_get_doc() -> None:
-    code = textwrap.dedent(
-        """\
+    code = textwrap.dedent("""\
     def func():
         "Docstring"
         return 1
-    """
-    )
+    """)
     node: nodes.FunctionDef = astroid.extract_node(code)  # type: ignore[assignment]
     assert isinstance(node.doc_node, nodes.Const)
     assert node.doc_node.value == "Docstring"
@@ -1599,13 +1795,11 @@
     assert node.doc_node.end_lineno == 2
     assert node.doc_node.end_col_offset == 15
 
-    code = textwrap.dedent(
-        """\
+    code = textwrap.dedent("""\
     def func():
         ...
         return 1
-    """
-    )
+    """)
     node = astroid.extract_node(code)
     assert node.doc_node is None
 
@@ -1631,15 +1825,15 @@
     assert len(type_comments) == 1
 
     type_comment = type_comments[0]
-    assert isinstance(type_comment, astroid.Attribute)
-    assert isinstance(type_comment.parent, astroid.Expr)
-    assert isinstance(type_comment.parent.parent, astroid.Arguments)
+    assert isinstance(type_comment, nodes.Attribute)
+    assert isinstance(type_comment.parent, nodes.Expr)
+    assert isinstance(type_comment.parent.parent, nodes.Arguments)
 
 
 def test_const_itered() -> None:
     code = 'a = "string"'
     node = astroid.extract_node(code).value
-    assert isinstance(node, astroid.Const)
+    assert isinstance(node, nodes.Const)
     itered = node.itered()
     assert len(itered) == 6
     assert [elem.value for elem in itered] == list("string")
@@ -1681,12 +1875,10 @@
     assert bool(node.is_generator())
 
 
-@pytest.mark.skipif(not PY310_PLUS, reason="pattern matching was added in PY310")
 class TestPatternMatching:
     @staticmethod
     def test_match_simple():
-        code = textwrap.dedent(
-            """
+        code = textwrap.dedent("""
         match status:
             case 200:
                 pass
@@ -1696,8 +1888,7 @@
                 pass
             case _:
                 pass
-        """
-        ).strip()
+        """).strip()
         node = builder.extract_node(code)
         assert node.as_string() == code
         assert isinstance(node, nodes.Match)
@@ -1709,12 +1900,12 @@
 
         assert isinstance(case0.pattern, nodes.MatchValue)
         assert (
-            isinstance(case0.pattern.value, astroid.Const)
+            isinstance(case0.pattern.value, nodes.Const)
             and case0.pattern.value.value == 200
         )
         assert list(case0.pattern.get_children()) == [case0.pattern.value]
         assert case0.guard is None
-        assert isinstance(case0.body[0], astroid.Pass)
+        assert isinstance(case0.body[0], nodes.Pass)
         assert list(case0.get_children()) == [case0.pattern, case0.body[0]]
 
         assert isinstance(case1.pattern, nodes.MatchOr)
@@ -1740,13 +1931,11 @@
 
     @staticmethod
     def test_match_sequence():
-        code = textwrap.dedent(
-            """
+        code = textwrap.dedent("""
         match status:
             case [x, 2, _, *rest] as y if x > 2:
                 pass
-        """
-        ).strip()
+        """).strip()
         node = builder.extract_node(code)
         assert node.as_string() == code
         assert isinstance(node, nodes.Match)
@@ -1794,15 +1983,13 @@
 
     @staticmethod
     def test_match_mapping():
-        code = textwrap.dedent(
-            """
+        code = textwrap.dedent("""
         match status:
             case {0: x, 1: _}:
                 pass
             case {**rest}:
                 pass
-        """
-        ).strip()
+        """).strip()
         node = builder.extract_node(code)
         assert node.as_string() == code
         assert isinstance(node, nodes.Match)
@@ -1844,15 +2031,13 @@
 
     @staticmethod
     def test_match_class():
-        code = textwrap.dedent(
-            """
+        code = textwrap.dedent("""
         match x:
             case Point2D(0, a):
                 pass
             case Point3D(x=0, y=1, z=b):
                 pass
-        """
-        ).strip()
+        """).strip()
         node = builder.extract_node(code)
         assert node.as_string() == code
         assert isinstance(node, nodes.Match)
@@ -1920,8 +2105,7 @@
 
     @staticmethod
     def test_return_from_match():
-        code = textwrap.dedent(
-            """
+        code = textwrap.dedent("""
         def return_from_match(x):
             match x:
                 case 10:
@@ -1930,14 +2114,46 @@
                     return -1
 
         return_from_match(10)  #@
-        """
-        ).strip()
+        """).strip()
         node = builder.extract_node(code)
         inferred = node.inferred()
         assert len(inferred) == 2
         assert [inf.value for inf in inferred] == [10, -1]
 
 
+@pytest.mark.skipif(not PY314_PLUS, reason="TemplateStr was added in PY314")
+class TestTemplateString:
+    @staticmethod
+    def test_template_string_simple() -> None:
+        code = textwrap.dedent("""
+        name = "Foo"
+        place = 3
+        t"{name} finished {place!r:ordinal}"  #@
+        """).strip()
+        node = builder.extract_node(code)
+        assert node.as_string() == "t'{name} finished {place!r:ordinal}'"
+        assert isinstance(node, nodes.TemplateStr)
+        assert len(node.values) == 3
+        value = node.values[0]
+        assert isinstance(value, nodes.Interpolation)
+        assert isinstance(value.value, nodes.Name)
+        assert value.value.name == "name"
+        assert value.str == "name"
+        assert value.conversion == -1
+        assert value.format_spec is None
+        value = node.values[1]
+        assert isinstance(value, nodes.Const)
+        assert value.pytype() == "builtins.str"
+        assert value.value == " finished "
+        value = node.values[2]
+        assert isinstance(value, nodes.Interpolation)
+        assert isinstance(value.value, nodes.Name)
+        assert value.value.name == "place"
+        assert value.str == "place"
+        assert value.conversion == ord("r")
+        assert isinstance(value.format_spec, nodes.JoinedStr)
+
+
 @pytest.mark.parametrize(
     "node",
     [
@@ -1963,7 +2179,7 @@
             "NodeNG" in param_type.annotation
             or "SuccessfulInferenceResult" in param_type.annotation
         ):
-            args[name] = nodes.Unknown()
+            args[name] = UNATTACHED_UNKNOWN
         elif "str" in param_type.annotation:
             args[name] = ""
         else:
@@ -2007,3 +2223,73 @@
 
     node = extract_node("def fruit(seeds, flavor='good', *, peel='maybe'): ...")
     assert node.args.default_value("flavor").value == "good"
+
+
+def test_arguments_annotations():
+    node = extract_node(
+        "def fruit(eat: str, /, peel: bool, *args: int, trim: float, **kwargs: bytes): ..."
+    )
+    assert isinstance(node.args, nodes.Arguments)
+    annotation_names = [
+        ann.name for ann in node.args.get_annotations() if isinstance(ann, nodes.Name)
+    ]
+    assert all(
+        name in annotation_names for name in ("str", "bool", "int", "float", "bytes")
+    )
+
+
+def test_deprecated_nodes_import_from_toplevel():
+    # pylint: disable=import-outside-toplevel,no-name-in-module
+    with pytest.raises(
+        DeprecationWarning, match="importing 'For' from 'astroid' is deprecated"
+    ):
+        from astroid import For
+
+    with warnings.catch_warnings():
+        warnings.simplefilter("ignore", DeprecationWarning)
+        from astroid import For
+
+        assert For is nodes.For
+
+    # This should not raise a DeprecationWarning
+    # pylint: disable-next=unused-import
+    from astroid import builtin_lookup
+
+
+def test_str_long_name_no_crash() -> None:
+    """str() should not crash with ValueError on nodes with long names.
+
+    Regression test for https://github.com/pylint-dev/astroid/issues/2764
+    """
+    long_name = "a" * 200
+    code = f"class {long_name}:\n    pass"
+    module = parse(code)
+    # This should not raise ValueError('width must be != 0')
+    result = str(module.body[0])
+    assert long_name in result
+
+
+def test_str_large_int_no_crash() -> None:
+    """str() should not crash with ValueError on nodes with large integer values.
+
+    Regression test for https://github.com/pylint-dev/astroid/issues/2785
+    """
+    code = "x = 10 ** 5000"
+    module = parse(code)
+    # Infer the BinOp to get a Const with a huge int value
+    inferred = next(module.body[0].value.infer())
+    assert isinstance(inferred.value, int)
+    # This should not raise ValueError about integer string conversion limit
+    result = str(inferred)
+    assert "int" in result
+
+
+def test_str_large_int_getitem_no_crash() -> None:
+    """getitem error message should not crash with large integer values."""
+    code = "x = 10 ** 5000"
+    module = parse(code)
+    inferred = next(module.body[0].value.infer())
+    assert isinstance(inferred.value, int)
+    # Trigger the error path that formats the value
+    with pytest.raises(AstroidTypeError, match=r"too large to display|int"):
+        inferred.getitem(nodes.Const(0))
diff --git a/tests/test_nodes_lineno.py b/tests/test_nodes_lineno.py
index 875d21d..bbc1e8c 100644
--- a/tests/test_nodes_lineno.py
+++ b/tests/test_nodes_lineno.py
@@ -4,11 +4,9 @@
 
 import textwrap
 
-import pytest
-
 import astroid
 from astroid import builder, nodes
-from astroid.const import PY310_PLUS, PY312_PLUS
+from astroid.const import PY312_PLUS
 
 
 class TestLinenoColOffset:
@@ -19,16 +17,14 @@
     @staticmethod
     def test_end_lineno_container() -> None:
         """Container nodes: List, Tuple, Set."""
-        code = textwrap.dedent(
-            """
+        code = textwrap.dedent("""
         [1, 2, 3]  #@
         [  #@
             1, 2, 3
         ]
         (1, 2, 3)  #@
         {1, 2, 3}  #@
-        """
-        ).strip()
+        """).strip()
         ast_nodes = builder.extract_node(code)
         assert isinstance(ast_nodes, list) and len(ast_nodes) == 4
 
@@ -55,8 +51,7 @@
     @staticmethod
     def test_end_lineno_name() -> None:
         """Name, Assign, AssignName, Delete, DelName."""
-        code = textwrap.dedent(
-            """
+        code = textwrap.dedent("""
         var = 42  #@
         var  #@
         del var  #@
@@ -64,8 +59,7 @@
         var2 = (  #@
             1, 2, 3
         )
-        """
-        ).strip()
+        """).strip()
         ast_nodes = builder.extract_node(code)
         assert isinstance(ast_nodes, list) and len(ast_nodes) == 4
 
@@ -103,16 +97,14 @@
     @staticmethod
     def test_end_lineno_attribute() -> None:
         """Attribute, AssignAttr, DelAttr."""
-        code = textwrap.dedent(
-            """
+        code = textwrap.dedent("""
         class X:
             var = 42
 
         X.var2 = 2  #@
         X.var2  #@
         del X.var2  #@
-        """
-        ).strip()
+        """).strip()
         ast_nodes = builder.extract_node(code)
         assert isinstance(ast_nodes, list) and len(ast_nodes) == 3
 
@@ -144,11 +136,9 @@
     @staticmethod
     def test_end_lineno_call() -> None:
         """Call, Keyword."""
-        code = textwrap.dedent(
-            """
+        code = textwrap.dedent("""
         func(arg1, arg2=value)  #@
-        """
-        ).strip()
+        """).strip()
         c1 = builder.extract_node(code)
         assert isinstance(c1, nodes.Call)
         assert isinstance(c1.func, nodes.Name)
@@ -174,13 +164,11 @@
     @staticmethod
     def test_end_lineno_assignment() -> None:
         """Assign, AnnAssign, AugAssign."""
-        code = textwrap.dedent(
-            """
+        code = textwrap.dedent("""
         var = 2  #@
         var2: int = 2  #@
         var3 += 2  #@
-        """
-        ).strip()
+        """).strip()
         ast_nodes = builder.extract_node(code)
         assert isinstance(ast_nodes, list) and len(ast_nodes) == 3
 
@@ -223,8 +211,7 @@
     @staticmethod
     def test_end_lineno_mix_stmts() -> None:
         """Assert, Break, Continue, Global, Nonlocal, Pass, Raise, Return, Expr."""
-        code = textwrap.dedent(
-            """
+        code = textwrap.dedent("""
         assert True, "Some message"  #@
         break  #@
         continue  #@
@@ -234,8 +221,7 @@
         raise Exception from ex  #@
         return 42  #@
         var  #@
-        """
-        ).strip()
+        """).strip()
         ast_nodes = builder.extract_node(code)
         assert isinstance(ast_nodes, list) and len(ast_nodes) == 9
 
@@ -305,14 +291,12 @@
     @staticmethod
     def test_end_lineno_mix_nodes() -> None:
         """Await, Starred, Yield, YieldFrom."""
-        code = textwrap.dedent(
-            """
+        code = textwrap.dedent("""
         await func  #@
         *args  #@
         yield 42  #@
         yield from (1, 2)  #@
-        """
-        ).strip()
+        """).strip()
         ast_nodes = builder.extract_node(code)
         assert isinstance(ast_nodes, list) and len(ast_nodes) == 4
 
@@ -351,14 +335,12 @@
     @staticmethod
     def test_end_lineno_ops() -> None:
         """BinOp, BoolOp, UnaryOp, Compare."""
-        code = textwrap.dedent(
-            """
+        code = textwrap.dedent("""
         x + y  #@
         a and b  #@
         -var  #@
         a < b  #@
-        """
-        ).strip()
+        """).strip()
         ast_nodes = builder.extract_node(code)
         assert isinstance(ast_nodes, list) and len(ast_nodes) == 4
 
@@ -406,8 +388,7 @@
     @staticmethod
     def test_end_lineno_if() -> None:
         """If, IfExp, NamedExpr."""
-        code = textwrap.dedent(
-            """
+        code = textwrap.dedent("""
         if (  #@
             var := 2  #@
         ):
@@ -416,8 +397,7 @@
             pass
 
         2 if True else 1  #@
-        """
-        ).strip()
+        """).strip()
         ast_nodes = builder.extract_node(code)
         assert isinstance(ast_nodes, list) and len(ast_nodes) == 3
 
@@ -463,8 +443,7 @@
     @staticmethod
     def test_end_lineno_for() -> None:
         """For, AsyncFor."""
-        code = textwrap.dedent(
-            """
+        code = textwrap.dedent("""
         for i in lst:  #@
             pass
         else:
@@ -472,8 +451,7 @@
 
         async for i in lst:  #@
             pass
-        """
-        ).strip()
+        """).strip()
         ast_nodes = builder.extract_node(code)
         assert isinstance(ast_nodes, list) and len(ast_nodes) == 2
 
@@ -511,16 +489,14 @@
     @staticmethod
     def test_end_lineno_const() -> None:
         """Const (int, str, bool, None, bytes, ellipsis)."""
-        code = textwrap.dedent(
-            """
+        code = textwrap.dedent("""
         2  #@
         "Hello"  #@
         True  #@
         None  #@
         b"01"  #@
         ...  #@
-        """
-        ).strip()
+        """).strip()
         ast_nodes = builder.extract_node(code)
         assert isinstance(ast_nodes, list) and len(ast_nodes) == 6
 
@@ -558,8 +534,7 @@
     def test_end_lineno_function() -> None:
         """FunctionDef, AsyncFunctionDef, Decorators, Lambda, Arguments."""
         # pylint: disable = too-many-statements
-        code = textwrap.dedent(
-            """
+        code = textwrap.dedent("""
         def func(  #@
             a: int = 0, /,
             var: int = 1, *args: Any,
@@ -573,8 +548,7 @@
             pass
 
         lambda x: 2  #@
-        """
-        ).strip()
+        """).strip()
         ast_nodes = builder.extract_node(code)
         assert isinstance(ast_nodes, list) and len(ast_nodes) == 3
 
@@ -591,6 +565,8 @@
         assert (f1.body[0].lineno, f1.body[0].col_offset) == (6, 4)
         assert (f1.body[0].end_lineno, f1.body[0].end_col_offset) == (6, 8)
 
+        assert (f1.args.lineno, f1.args.end_lineno) == (2, 4)
+
         # pos only arguments
         # TODO fix column offset: arg -> arg (AssignName)
         assert isinstance(f1.args.posonlyargs[0], nodes.AssignName)
@@ -669,14 +645,12 @@
     @staticmethod
     def test_end_lineno_dict() -> None:
         """Dict, DictUnpack."""
-        code = textwrap.dedent(
-            """
+        code = textwrap.dedent("""
         {  #@
             1: "Hello",
             **{2: "World"}  #@
         }
-        """
-        ).strip()
+        """).strip()
         ast_nodes = builder.extract_node(code)
         assert isinstance(ast_nodes, list) and len(ast_nodes) == 2
 
@@ -699,8 +673,7 @@
     @staticmethod
     def test_end_lineno_try() -> None:
         """Try, ExceptHandler."""
-        code = textwrap.dedent(
-            """
+        code = textwrap.dedent("""
         try:  #@
             pass
         except KeyError as ex:
@@ -718,8 +691,7 @@
             pass
         finally:
             pass
-        """
-        ).strip()
+        """).strip()
         ast_nodes = builder.extract_node(code)
         assert isinstance(ast_nodes, list) and len(ast_nodes) == 2
 
@@ -762,13 +734,11 @@
     @staticmethod
     def test_end_lineno_subscript() -> None:
         """Subscript, Slice, (ExtSlice, Index)."""
-        code = textwrap.dedent(
-            """
+        code = textwrap.dedent("""
         var[0]  #@
         var[1:2:1]  #@
         var[1:2, 2]  #@
-        """
-        ).strip()
+        """).strip()
         ast_nodes = builder.extract_node(code)
         assert isinstance(ast_nodes, list) and len(ast_nodes) == 3
 
@@ -809,14 +779,12 @@
     @staticmethod
     def test_end_lineno_import() -> None:
         """Import, ImportFrom."""
-        code = textwrap.dedent(
-            """
+        code = textwrap.dedent("""
         import a.b  #@
         import a as x  #@
         from . import x  #@
         from .a import y as y  #@
-        """
-        ).strip()
+        """).strip()
         ast_nodes = builder.extract_node(code)
         assert isinstance(ast_nodes, list) and len(ast_nodes) == 4
 
@@ -843,16 +811,14 @@
     @staticmethod
     def test_end_lineno_with() -> None:
         """With, AsyncWith."""
-        code = textwrap.dedent(
-            """
+        code = textwrap.dedent("""
         with open(file) as fp, \\
                 open(file2) as fp2:  #@
             pass
 
         async with open(file) as fp:  #@
             pass
-        """
-        ).strip()
+        """).strip()
         ast_nodes = builder.extract_node(code)
         assert isinstance(ast_nodes, list) and len(ast_nodes) == 2
 
@@ -893,14 +859,12 @@
     @staticmethod
     def test_end_lineno_while() -> None:
         """While."""
-        code = textwrap.dedent(
-            """
+        code = textwrap.dedent("""
         while 2:
             pass
         else:
             pass
-        """
-        ).strip()
+        """).strip()
         w1 = builder.extract_node(code)
         assert isinstance(w1, nodes.While)
         assert isinstance(w1.test, nodes.Const)
@@ -918,12 +882,10 @@
     @staticmethod
     def test_end_lineno_string() -> None:
         """FormattedValue, JoinedStr."""
-        code = textwrap.dedent(
-            """
+        code = textwrap.dedent("""
         f"Hello World: {42.1234:02d}"  #@
         f"Hello: {name=}"  #@
-        """
-        ).strip()
+        """).strip()
         ast_nodes = builder.extract_node(code)
         assert isinstance(ast_nodes, list) and len(ast_nodes) == 2
 
@@ -987,14 +949,12 @@
         assert (s4.value.end_lineno, s4.value.end_col_offset) == (2, 14)
 
     @staticmethod
-    @pytest.mark.skipif(not PY310_PLUS, reason="pattern matching was added in PY310")
     def test_end_lineno_match() -> None:
         """Match, MatchValue, MatchSingleton, MatchSequence, MatchMapping,
         MatchClass, MatchStar, MatchOr, MatchAs.
         """
         # pylint: disable = too-many-statements
-        code = textwrap.dedent(
-            """
+        code = textwrap.dedent("""
         match x:  #@
             case 200 if True:  #@
                 pass
@@ -1010,8 +970,7 @@
                 pass
             case 200 as c:  #@
                 pass
-        """
-        ).strip()
+        """).strip()
         ast_nodes = builder.extract_node(code)
         assert isinstance(ast_nodes, list) and len(ast_nodes) == 8
 
@@ -1116,14 +1075,12 @@
     @staticmethod
     def test_end_lineno_comprehension() -> None:
         """ListComp, SetComp, DictComp, GeneratorExpr."""
-        code = textwrap.dedent(
-            """
+        code = textwrap.dedent("""
         [x for x in var]  #@
         {x for x in var}  #@
         {x: y for x, y in var}  #@
         (x for x in var)  #@
-        """
-        ).strip()
+        """).strip()
         ast_nodes = builder.extract_node(code)
         assert isinstance(ast_nodes, list) and len(ast_nodes) == 4
 
@@ -1169,14 +1126,12 @@
     @staticmethod
     def test_end_lineno_class() -> None:
         """ClassDef, Keyword."""
-        code = textwrap.dedent(
-            """
+        code = textwrap.dedent("""
         @decorator1
         @decorator2
         class X(Parent, var=42):
             pass
-        """
-        ).strip()
+        """).strip()
         c1 = builder.extract_node(code)
         assert isinstance(c1, nodes.ClassDef)
         assert isinstance(c1.decorators, nodes.Decorators)
diff --git a/tests/test_nodes_position.py b/tests/test_nodes_position.py
index 452cd05..1e93839 100644
--- a/tests/test_nodes_position.py
+++ b/tests/test_nodes_position.py
@@ -19,8 +19,7 @@
         >>> class A(Parent):
         >>> ^^^^^^^
         """
-        code = textwrap.dedent(
-            """
+        code = textwrap.dedent("""
         class A:  #@
             ...
 
@@ -40,8 +39,7 @@
         @decorator
         class F:  #@
             ...
-        """
-        ).strip()
+        """).strip()
         ast_nodes: list[nodes.NodeNG] = builder.extract_node(code)  # type: ignore[assignment]
 
         a = ast_nodes[0]
@@ -75,8 +73,7 @@
         >>> def func(var: int = 42):
         >>> ^^^^^^^^
         """
-        code = textwrap.dedent(
-            """
+        code = textwrap.dedent("""
         def a():  #@
             ...
 
@@ -92,8 +89,7 @@
         @decorator
         def e():  #@
             ...
-        """
-        ).strip()
+        """).strip()
         ast_nodes: list[nodes.NodeNG] = builder.extract_node(code)  # type: ignore[assignment]
 
         a = ast_nodes[0]
@@ -123,8 +119,7 @@
         >>> async def func(var: int = 42):
         >>> ^^^^^^^^^^^^^^
         """
-        code = textwrap.dedent(
-            """
+        code = textwrap.dedent("""
         async def a():  #@
             ...
 
@@ -140,8 +135,7 @@
         @decorator
         async def e():  #@
             ...
-        """
-        ).strip()
+        """).strip()
         ast_nodes: list[nodes.NodeNG] = builder.extract_node(code)  # type: ignore[assignment]
 
         a = ast_nodes[0]
diff --git a/tests/test_object_model.py b/tests/test_object_model.py
index 9ad4d39..89d27ae 100644
--- a/tests/test_object_model.py
+++ b/tests/test_object_model.py
@@ -38,54 +38,50 @@
         )
         assert isinstance(ast_nodes, list)
         cls = next(ast_nodes[0].infer())
-        self.assertIsInstance(cls, astroid.ClassDef)
+        self.assertIsInstance(cls, nodes.ClassDef)
         self.assertEqual(cls.name, "A")
 
         module = next(ast_nodes[1].infer())
-        self.assertIsInstance(module, astroid.Const)
+        self.assertIsInstance(module, nodes.Const)
         self.assertEqual(module.value, "fake_module")
 
         doc = next(ast_nodes[2].infer())
-        self.assertIsInstance(doc, astroid.Const)
+        self.assertIsInstance(doc, nodes.Const)
         self.assertEqual(doc.value, "test")
 
         dunder_dict = next(ast_nodes[3].infer())
-        self.assertIsInstance(dunder_dict, astroid.Dict)
-        attr = next(dunder_dict.getitem(astroid.Const("a")).infer())
-        self.assertIsInstance(attr, astroid.Const)
+        self.assertIsInstance(dunder_dict, nodes.Dict)
+        attr = next(dunder_dict.getitem(nodes.Const("a")).infer())
+        self.assertIsInstance(attr, nodes.Const)
         self.assertEqual(attr.value, 42)
 
     @pytest.mark.xfail(reason="Instance lookup cannot override object model")
     def test_instance_local_attributes_overrides_object_model(self):
         # The instance lookup needs to be changed in order for this to work.
-        ast_node = builder.extract_node(
-            """
+        ast_node = builder.extract_node("""
         class A:
             @property
             def __dict__(self):
                   return []
         A().__dict__
-        """
-        )
+        """)
         inferred = next(ast_node.infer())
-        self.assertIsInstance(inferred, astroid.List)
+        self.assertIsInstance(inferred, nodes.List)
         self.assertEqual(inferred.elts, [])
 
 
 class BoundMethodModelTest(unittest.TestCase):
     def test_bound_method_model(self) -> None:
-        ast_nodes = builder.extract_node(
-            """
+        ast_nodes = builder.extract_node("""
         class A:
             def test(self): pass
         a = A()
         a.test.__func__ #@
         a.test.__self__ #@
-        """
-        )
+        """)
         assert isinstance(ast_nodes, list)
         func = next(ast_nodes[0].infer())
-        self.assertIsInstance(func, astroid.FunctionDef)
+        self.assertIsInstance(func, nodes.FunctionDef)
         self.assertEqual(func.name, "test")
 
         self_ = next(ast_nodes[1].infer())
@@ -95,8 +91,7 @@
 
 class UnboundMethodModelTest(unittest.TestCase):
     def test_unbound_method_model(self) -> None:
-        ast_nodes = builder.extract_node(
-            """
+        ast_nodes = builder.extract_node("""
         class A:
             def test(self): pass
         t = A.test
@@ -106,55 +101,55 @@
         t.im_class #@
         t.im_func #@
         t.im_self #@
-        """
-        )
+        t.__doc__ #@
+        """)
         assert isinstance(ast_nodes, list)
         cls = next(ast_nodes[0].infer())
-        self.assertIsInstance(cls, astroid.ClassDef)
+        self.assertIsInstance(cls, nodes.ClassDef)
         unbound_name = "function"
 
         self.assertEqual(cls.name, unbound_name)
 
         func = next(ast_nodes[1].infer())
-        self.assertIsInstance(func, astroid.FunctionDef)
+        self.assertIsInstance(func, nodes.FunctionDef)
         self.assertEqual(func.name, "test")
 
         self_ = next(ast_nodes[2].infer())
-        self.assertIsInstance(self_, astroid.Const)
+        self.assertIsInstance(self_, nodes.Const)
         self.assertIsNone(self_.value)
 
         self.assertEqual(cls.name, next(ast_nodes[3].infer()).name)
         self.assertEqual(func, next(ast_nodes[4].infer()))
         self.assertIsNone(next(ast_nodes[5].infer()).value)
 
+        doc = next(ast_nodes[6].infer())
+        self.assertIsInstance(doc, nodes.Const)
+        self.assertIsNone(doc.value)
+
 
 class ClassModelTest(unittest.TestCase):
     def test_priority_to_local_defined_values(self) -> None:
-        ast_node = builder.extract_node(
-            """
+        ast_node = builder.extract_node("""
         class A:
             __doc__ = "first"
         A.__doc__ #@
-        """
-        )
+        """)
         inferred = next(ast_node.infer())
-        self.assertIsInstance(inferred, astroid.Const)
+        self.assertIsInstance(inferred, nodes.Const)
         self.assertEqual(inferred.value, "first")
 
     def test_class_model_correct_mro_subclasses_proxied(self) -> None:
-        ast_nodes = builder.extract_node(
-            """
+        ast_nodes = builder.extract_node("""
         class A(object):
             pass
         A.mro #@
         A.__subclasses__ #@
-        """
-        )
+        """)
         for node in ast_nodes:
             inferred = next(node.infer())
             self.assertIsInstance(inferred, astroid.BoundMethod)
-            self.assertIsInstance(inferred._proxied, astroid.FunctionDef)
-            self.assertIsInstance(inferred.bound, astroid.ClassDef)
+            self.assertIsInstance(inferred._proxied, nodes.FunctionDef)
+            self.assertIsInstance(inferred.bound, nodes.ClassDef)
             self.assertEqual(inferred.bound.name, "type")
 
     def test_class_model(self) -> None:
@@ -181,68 +176,63 @@
         )
         assert isinstance(ast_nodes, list)
         module = next(ast_nodes[0].infer())
-        self.assertIsInstance(module, astroid.Const)
+        self.assertIsInstance(module, nodes.Const)
         self.assertEqual(module.value, "fake_module")
 
         name = next(ast_nodes[1].infer())
-        self.assertIsInstance(name, astroid.Const)
+        self.assertIsInstance(name, nodes.Const)
         self.assertEqual(name.value, "A")
 
         qualname = next(ast_nodes[2].infer())
-        self.assertIsInstance(qualname, astroid.Const)
+        self.assertIsInstance(qualname, nodes.Const)
         self.assertEqual(qualname.value, "fake_module.A")
 
         doc = next(ast_nodes[3].infer())
-        self.assertIsInstance(doc, astroid.Const)
+        self.assertIsInstance(doc, nodes.Const)
         self.assertEqual(doc.value, "test")
 
         mro = next(ast_nodes[4].infer())
-        self.assertIsInstance(mro, astroid.Tuple)
+        self.assertIsInstance(mro, nodes.Tuple)
         self.assertEqual([cls.name for cls in mro.elts], ["A", "object"])
 
         called_mro = next(ast_nodes[5].infer())
         self.assertEqual(called_mro.elts, mro.elts)
 
         base_nodes = next(ast_nodes[6].infer())
-        self.assertIsInstance(base_nodes, astroid.Tuple)
+        self.assertIsInstance(base_nodes, nodes.Tuple)
         self.assertEqual([cls.name for cls in base_nodes.elts], ["object"])
 
         cls = next(ast_nodes[7].infer())
-        self.assertIsInstance(cls, astroid.ClassDef)
+        self.assertIsInstance(cls, nodes.ClassDef)
         self.assertEqual(cls.name, "type")
 
         cls_dict = next(ast_nodes[8].infer())
-        self.assertIsInstance(cls_dict, astroid.Dict)
+        self.assertIsInstance(cls_dict, nodes.Dict)
 
         subclasses = next(ast_nodes[9].infer())
-        self.assertIsInstance(subclasses, astroid.List)
+        self.assertIsInstance(subclasses, nodes.List)
         self.assertEqual([cls.name for cls in subclasses.elts], ["B", "C"])
 
 
 class ModuleModelTest(unittest.TestCase):
     def test_priority_to_local_defined_values(self) -> None:
-        ast_node = astroid.parse(
-            """
+        ast_node = astroid.parse("""
         __file__ = "mine"
-        """
-        )
+        """)
         file_value = next(ast_node.igetattr("__file__"))
-        self.assertIsInstance(file_value, astroid.Const)
+        self.assertIsInstance(file_value, nodes.Const)
         self.assertEqual(file_value.value, "mine")
 
     def test__path__not_a_package(self) -> None:
-        ast_node = builder.extract_node(
-            """
+        ast_node = builder.extract_node("""
         import sys
         sys.__path__ #@
-        """
-        )
+        """)
         with self.assertRaises(InferenceError):
             next(ast_node.infer())
 
     def test_module_model(self) -> None:
-        ast_nodes = builder.extract_node(
-            """
+        ast_nodes = builder.extract_node("""
         import xml
         xml.__path__ #@
         xml.__name__ #@
@@ -265,33 +255,35 @@
         xml.__setattr__ #@
         xml.__reduce_ex__ #@
         xml.__lt__ #@
+        xml.__le__ #@
         xml.__eq__ #@
+        xml.__ne__ #@
+        xml.__ge__ #@
         xml.__gt__ #@
         xml.__format__ #@
-        xml.__delattr___ #@
+        xml.__delattr__ #@
         xml.__getattribute__ #@
         xml.__hash__ #@
         xml.__dir__ #@
         xml.__call__ #@
         xml.__closure__ #@
-        """
-        )
+        """)
         assert isinstance(ast_nodes, list)
         path = next(ast_nodes[0].infer())
-        self.assertIsInstance(path, astroid.List)
-        self.assertIsInstance(path.elts[0], astroid.Const)
+        self.assertIsInstance(path, nodes.List)
+        self.assertIsInstance(path.elts[0], nodes.Const)
         self.assertEqual(path.elts[0].value, xml.__path__[0])
 
         name = next(ast_nodes[1].infer())
-        self.assertIsInstance(name, astroid.Const)
+        self.assertIsInstance(name, nodes.Const)
         self.assertEqual(name.value, "xml")
 
         doc = next(ast_nodes[2].infer())
-        self.assertIsInstance(doc, astroid.Const)
+        self.assertIsInstance(doc, nodes.Const)
         self.assertEqual(doc.value, xml.__doc__)
 
         file_ = next(ast_nodes[3].infer())
-        self.assertIsInstance(file_, astroid.Const)
+        self.assertIsInstance(file_, nodes.Const)
         self.assertEqual(file_.value, xml.__file__.replace(".pyc", ".py"))
 
         for ast_node in ast_nodes[4:7]:
@@ -299,11 +291,11 @@
             self.assertIs(inferred, astroid.Uninferable)
 
         package = next(ast_nodes[7].infer())
-        self.assertIsInstance(package, astroid.Const)
+        self.assertIsInstance(package, nodes.Const)
         self.assertEqual(package.value, "xml")
 
         dict_ = next(ast_nodes[8].infer())
-        self.assertIsInstance(dict_, astroid.Dict)
+        self.assertIsInstance(dict_, nodes.Dict)
 
         init_ = next(ast_nodes[9].infer())
         assert isinstance(init_, bases.BoundMethod)
@@ -324,38 +316,38 @@
         new_ = next(ast_nodes[10].infer())
         assert isinstance(new_, bases.BoundMethod)
 
-        # The following nodes are just here for theoretical completeness,
-        # and they either return Uninferable or raise InferenceError.
-        for ast_node in ast_nodes[11:28]:
+        # Inherited attributes return Uninferable.
+        for ast_node in ast_nodes[11:29]:
+            inferred = next(ast_node.infer())
+            self.assertIs(inferred, astroid.Uninferable)
+
+        # Attributes that don't exist on modules raise InferenceError.
+        for ast_node in ast_nodes[29:31]:
             with pytest.raises(InferenceError):
                 next(ast_node.infer())
 
 
 class FunctionModelTest(unittest.TestCase):
     def test_partial_descriptor_support(self) -> None:
-        bound, result = builder.extract_node(
-            """
+        bound, result = builder.extract_node("""
         class A(object): pass
         def test(self): return 42
         f = test.__get__(A(), A)
         f #@
         f() #@
-        """
-        )
+        """)
         bound = next(bound.infer())
         self.assertIsInstance(bound, astroid.BoundMethod)
         self.assertEqual(bound._proxied._proxied.name, "test")
         result = next(result.infer())
-        self.assertIsInstance(result, astroid.Const)
+        self.assertIsInstance(result, nodes.Const)
         self.assertEqual(result.value, 42)
 
     def test___get__has_extra_params_defined(self) -> None:
-        node = builder.extract_node(
-            """
+        node = builder.extract_node("""
         def test(self): return 42
         test.__get__
-        """
-        )
+        """)
         inferred = next(node.infer())
         self.assertIsInstance(inferred, astroid.BoundMethod)
         args = inferred.args.args
@@ -363,12 +355,10 @@
         self.assertEqual([arg.name for arg in args], ["self", "type"])
 
     def test__get__and_positional_only_args(self):
-        node = builder.extract_node(
-            """
+        node = builder.extract_node("""
         def test(self, a, b, /, c): return a + b + c
         test.__get__(test)(1, 2, 3)
-        """
-        )
+        """)
         inferred = next(node.infer())
         assert inferred is util.Uninferable
 
@@ -376,36 +366,31 @@
     def test_descriptor_not_inferrring_self(self):
         # We can't infer __get__(X, Y)() when the bounded function
         # uses self, because of the tree's parent not being propagating good enough.
-        result = builder.extract_node(
-            """
+        result = builder.extract_node("""
         class A(object):
             x = 42
         def test(self): return self.x
         f = test.__get__(A(), A)
         f() #@
-        """
-        )
+        """)
         result = next(result.infer())
-        self.assertIsInstance(result, astroid.Const)
+        self.assertIsInstance(result, nodes.Const)
         self.assertEqual(result.value, 42)
 
     def test_descriptors_binding_invalid(self) -> None:
-        ast_nodes = builder.extract_node(
-            """
+        ast_nodes = builder.extract_node("""
         class A: pass
         def test(self): return 42
         test.__get__()() #@
         test.__get__(2, 3, 4) #@
-        """
-        )
+        """)
         for node in ast_nodes:
             with self.assertRaises(InferenceError):
                 next(node.infer())
 
     def test_descriptor_error_regression(self) -> None:
         """Make sure the following code does node cause an exception."""
-        node = builder.extract_node(
-            """
+        node = builder.extract_node("""
         class MyClass:
             text = "MyText"
 
@@ -418,8 +403,7 @@
 
         cl = MyClass().mymethod2()()
         cl #@
-        """
-        )
+        """)
         assert isinstance(node, nodes.NodeNG)
         [const] = node.inferred()
         assert const.value == "MyText"
@@ -449,45 +433,52 @@
 
         func.__reduce_ex__ #@
         func.__lt__ #@
+        func.__le__ #@
         func.__eq__ #@
+        func.__ne__ #@
+        func.__ge__ #@
         func.__gt__ #@
         func.__format__ #@
-        func.__delattr___ #@
+        func.__delattr__ #@
         func.__getattribute__ #@
         func.__hash__ #@
         func.__dir__ #@
         func.__class__ #@
 
         func.__setattr__ #@
+        func.__builtins__ #@
+        func.__getstate__ #@
+        func.__init_subclass__ #@
+        func.__type_params__ #@
         ''',
             module_name="fake_module",
         )
         assert isinstance(ast_nodes, list)
         name = next(ast_nodes[0].infer())
-        self.assertIsInstance(name, astroid.Const)
+        self.assertIsInstance(name, nodes.Const)
         self.assertEqual(name.value, "func")
 
         doc = next(ast_nodes[1].infer())
-        self.assertIsInstance(doc, astroid.Const)
+        self.assertIsInstance(doc, nodes.Const)
         self.assertEqual(doc.value, "test")
 
         qualname = next(ast_nodes[2].infer())
-        self.assertIsInstance(qualname, astroid.Const)
+        self.assertIsInstance(qualname, nodes.Const)
         self.assertEqual(qualname.value, "fake_module.func")
 
         module = next(ast_nodes[3].infer())
-        self.assertIsInstance(module, astroid.Const)
+        self.assertIsInstance(module, nodes.Const)
         self.assertEqual(module.value, "fake_module")
 
         defaults = next(ast_nodes[4].infer())
-        self.assertIsInstance(defaults, astroid.Tuple)
+        self.assertIsInstance(defaults, nodes.Tuple)
         self.assertEqual([default.value for default in defaults.elts], [1, 2])
 
         dict_ = next(ast_nodes[5].infer())
-        self.assertIsInstance(dict_, astroid.Dict)
+        self.assertIsInstance(dict_, nodes.Dict)
 
         globals_ = next(ast_nodes[6].infer())
-        self.assertIsInstance(globals_, astroid.Dict)
+        self.assertIsInstance(globals_, nodes.Dict)
 
         for ast_node in ast_nodes[7:9]:
             self.assertIs(next(ast_node.infer()), astroid.Uninferable)
@@ -511,81 +502,66 @@
         new_ = next(ast_nodes[10].infer())
         assert isinstance(new_, bases.BoundMethod)
 
-        # The following nodes are just here for theoretical completeness,
-        # and they either return Uninferable or raise InferenceError.
-        for ast_node in ast_nodes[11:26]:
+        # Remaining attributes return Uninferable.
+        for ast_node in ast_nodes[11:34]:
             inferred = next(ast_node.infer())
             assert inferred is util.Uninferable
 
-        for ast_node in ast_nodes[26:27]:
-            with pytest.raises(InferenceError):
-                inferred = next(ast_node.infer())
-
     def test_empty_return_annotation(self) -> None:
-        ast_node = builder.extract_node(
-            """
+        ast_node = builder.extract_node("""
         def test(): pass
         test.__annotations__
-        """
-        )
+        """)
         annotations = next(ast_node.infer())
-        self.assertIsInstance(annotations, astroid.Dict)
+        self.assertIsInstance(annotations, nodes.Dict)
         self.assertEqual(len(annotations.items), 0)
 
     def test_builtin_dunder_init_does_not_crash_when_accessing_annotations(
         self,
     ) -> None:
-        ast_node = builder.extract_node(
-            """
+        ast_node = builder.extract_node("""
         class Class:
             @classmethod
             def class_method(cls):
                 cls.__init__.__annotations__ #@
-        """
-        )
+        """)
         inferred = next(ast_node.infer())
-        self.assertIsInstance(inferred, astroid.Dict)
+        self.assertIsInstance(inferred, nodes.Dict)
         self.assertEqual(len(inferred.items), 0)
 
     def test_annotations_kwdefaults(self) -> None:
-        ast_node = builder.extract_node(
-            """
+        ast_node = builder.extract_node("""
         def test(a: 1, *args: 2, f:4='lala', **kwarg:3)->2: pass
         test.__annotations__ #@
         test.__kwdefaults__ #@
-        """
-        )
+        """)
         annotations = next(ast_node[0].infer())
-        self.assertIsInstance(annotations, astroid.Dict)
-        self.assertIsInstance(
-            annotations.getitem(astroid.Const("return")), astroid.Const
-        )
-        self.assertEqual(annotations.getitem(astroid.Const("return")).value, 2)
-        self.assertIsInstance(annotations.getitem(astroid.Const("a")), astroid.Const)
-        self.assertEqual(annotations.getitem(astroid.Const("a")).value, 1)
-        self.assertEqual(annotations.getitem(astroid.Const("args")).value, 2)
-        self.assertEqual(annotations.getitem(astroid.Const("kwarg")).value, 3)
+        self.assertIsInstance(annotations, nodes.Dict)
+        self.assertIsInstance(annotations.getitem(nodes.Const("return")), nodes.Const)
+        self.assertEqual(annotations.getitem(nodes.Const("return")).value, 2)
+        self.assertIsInstance(annotations.getitem(nodes.Const("a")), nodes.Const)
+        self.assertEqual(annotations.getitem(nodes.Const("a")).value, 1)
+        self.assertEqual(annotations.getitem(nodes.Const("args")).value, 2)
+        self.assertEqual(annotations.getitem(nodes.Const("kwarg")).value, 3)
 
-        self.assertEqual(annotations.getitem(astroid.Const("f")).value, 4)
+        self.assertEqual(annotations.getitem(nodes.Const("f")).value, 4)
 
         kwdefaults = next(ast_node[1].infer())
-        self.assertIsInstance(kwdefaults, astroid.Dict)
+        self.assertIsInstance(kwdefaults, nodes.Dict)
         # self.assertEqual(kwdefaults.getitem('f').value, 'lala')
 
     def test_annotation_positional_only(self):
-        ast_node = builder.extract_node(
-            """
+        ast_node = builder.extract_node("""
         def test(a: 1, b: 2, /, c: 3): pass
         test.__annotations__ #@
-        """
-        )
+        """)
         annotations = next(ast_node.infer())
-        self.assertIsInstance(annotations, astroid.Dict)
+        self.assertIsInstance(annotations, nodes.Dict)
 
-        self.assertIsInstance(annotations.getitem(astroid.Const("a")), astroid.Const)
-        self.assertEqual(annotations.getitem(astroid.Const("a")).value, 1)
-        self.assertEqual(annotations.getitem(astroid.Const("b")).value, 2)
-        self.assertEqual(annotations.getitem(astroid.Const("c")).value, 3)
+        self.assertIsInstance(annotations.getitem(nodes.Const("a")), nodes.Const)
+        self.assertEqual(annotations.getitem(nodes.Const("a")).value, 1)
+        self.assertEqual(annotations.getitem(nodes.Const("b")).value, 2)
+        self.assertEqual(annotations.getitem(nodes.Const("c")).value, 3)
 
     def test_is_not_lambda(self):
         ast_node = builder.extract_node("def func(): pass")
@@ -595,8 +571,7 @@
 class TestContextManagerModel:
     def test_model(self) -> None:
         """We use a generator to test this model."""
-        ast_nodes = builder.extract_node(
-            """
+        ast_nodes = builder.extract_node("""
         def test():
            "a"
            yield
@@ -604,8 +579,7 @@
         gen = test()
         gen.__enter__ #@
         gen.__exit__ #@
-        """
-        )
+        """)
         assert isinstance(ast_nodes, list)
 
         enter = next(ast_nodes[0].infer())
@@ -633,8 +607,7 @@
 
 class GeneratorModelTest(unittest.TestCase):
     def test_model(self) -> None:
-        ast_nodes = builder.extract_node(
-            """
+        ast_nodes = builder.extract_node("""
         def test():
            "a"
            yield
@@ -647,8 +620,7 @@
         gen.send #@
         gen.__enter__ #@
         gen.__exit__ #@
-        """
-        )
+        """)
         assert isinstance(ast_nodes, list)
         name = next(ast_nodes[0].infer())
         self.assertEqual(name.value, "test")
@@ -657,11 +629,11 @@
         self.assertEqual(doc.value, "a")
 
         gi_code = next(ast_nodes[2].infer())
-        self.assertIsInstance(gi_code, astroid.ClassDef)
+        self.assertIsInstance(gi_code, nodes.ClassDef)
         self.assertEqual(gi_code.name, "gi_code")
 
         gi_frame = next(ast_nodes[3].infer())
-        self.assertIsInstance(gi_frame, astroid.ClassDef)
+        self.assertIsInstance(gi_frame, nodes.ClassDef)
         self.assertEqual(gi_frame.name, "gi_frame")
 
         send = next(ast_nodes[4].infer())
@@ -677,8 +649,7 @@
 class ExceptionModelTest(unittest.TestCase):
     @staticmethod
     def test_valueerror_py3() -> None:
-        ast_nodes = builder.extract_node(
-            """
+        ast_nodes = builder.extract_node("""
         try:
             x[42]
         except ValueError as err:
@@ -686,11 +657,10 @@
            err.__traceback__ #@
 
            err.message #@
-        """
-        )
+        """)
         assert isinstance(ast_nodes, list)
         args = next(ast_nodes[0].infer())
-        assert isinstance(args, astroid.Tuple)
+        assert isinstance(args, nodes.Tuple)
         tb = next(ast_nodes[1].infer())
         # Python 3.11: If 'contextlib' is loaded, '__traceback__'
         # could be set inside '__exit__' method in
@@ -708,33 +678,29 @@
             next(ast_nodes[2].infer())
 
     def test_syntax_error(self) -> None:
-        ast_node = builder.extract_node(
-            """
+        ast_node = builder.extract_node("""
         try:
             x[42]
         except SyntaxError as err:
            err.text #@
-        """
-        )
+        """)
         inferred = next(ast_node.infer())
-        assert isinstance(inferred, astroid.Const)
+        assert isinstance(inferred, nodes.Const)
 
     @unittest.skipIf(HAS_SIX, "This test fails if the six library is installed")
     def test_oserror(self) -> None:
-        ast_nodes = builder.extract_node(
-            """
+        ast_nodes = builder.extract_node("""
         try:
             raise OSError("a")
         except OSError as err:
            err.filename #@
            err.filename2 #@
            err.errno #@
-        """
-        )
+        """)
         expected_values = ["", "", 0]
         for node, value in zip(ast_nodes, expected_values):
             inferred = next(node.infer())
-            assert isinstance(inferred, astroid.Const)
+            assert isinstance(inferred, nodes.Const)
             assert inferred.value == value
 
     def test_unicodedecodeerror(self) -> None:
@@ -746,66 +712,58 @@
         """
         node = builder.extract_node(code)
         inferred = next(node.infer())
-        assert isinstance(inferred, astroid.Const)
+        assert isinstance(inferred, nodes.Const)
         assert inferred.value == b""
 
     def test_import_error(self) -> None:
-        ast_nodes = builder.extract_node(
-            """
+        ast_nodes = builder.extract_node("""
         try:
             raise ImportError("a")
         except ImportError as err:
            err.name #@
            err.path #@
-        """
-        )
+        """)
         for node in ast_nodes:
             inferred = next(node.infer())
-            assert isinstance(inferred, astroid.Const)
+            assert isinstance(inferred, nodes.Const)
             assert inferred.value == ""
 
     def test_exception_instance_correctly_instantiated(self) -> None:
-        ast_node = builder.extract_node(
-            """
+        ast_node = builder.extract_node("""
         try:
             raise ImportError("a")
         except ImportError as err:
            err #@
-        """
-        )
+        """)
         inferred = next(ast_node.infer())
         assert isinstance(inferred, astroid.Instance)
         cls = next(inferred.igetattr("__class__"))
-        assert isinstance(cls, astroid.ClassDef)
+        assert isinstance(cls, nodes.ClassDef)
 
 
 class DictObjectModelTest(unittest.TestCase):
     def test__class__(self) -> None:
         ast_node = builder.extract_node("{}.__class__")
         inferred = next(ast_node.infer())
-        self.assertIsInstance(inferred, astroid.ClassDef)
+        self.assertIsInstance(inferred, nodes.ClassDef)
         self.assertEqual(inferred.name, "dict")
 
     def test_attributes_inferred_as_methods(self) -> None:
-        ast_nodes = builder.extract_node(
-            """
+        ast_nodes = builder.extract_node("""
         {}.values #@
         {}.items #@
         {}.keys #@
-        """
-        )
+        """)
         for node in ast_nodes:
             inferred = next(node.infer())
             self.assertIsInstance(inferred, astroid.BoundMethod)
 
     def test_wrapper_objects_for_dict_methods_python3(self) -> None:
-        ast_nodes = builder.extract_node(
-            """
+        ast_nodes = builder.extract_node("""
         {1:1, 2:3}.values() #@
         {1:1, 2:3}.keys() #@
         {1:1, 2:3}.items() #@
-        """
-        )
+        """)
         assert isinstance(ast_nodes, list)
         values = next(ast_nodes[0].infer())
         self.assertIsInstance(values, objects.DictValues)
@@ -822,11 +780,9 @@
 
     def test_str_argument_not_required(self) -> None:
         """Test that the first argument to an exception does not need to be a str."""
-        ast_node = builder.extract_node(
-            """
+        ast_node = builder.extract_node("""
         BaseException() #@
-        """
-        )
+        """)
         args: nodes.Tuple = next(ast_node.infer()).getattr("args")[0]
         # BaseException doesn't have any required args, not even a string
         assert not args.elts
@@ -834,8 +790,7 @@
 
 @pytest.mark.parametrize("parentheses", (True, False))
 def test_lru_cache(parentheses) -> None:
-    ast_nodes = builder.extract_node(
-        f"""
+    ast_nodes = builder.extract_node(f"""
         import functools
         class Foo(object):
             @functools.lru_cache{"()" if parentheses else ""}
@@ -845,13 +800,12 @@
         f.foo.cache_clear #@
         f.foo.__wrapped__ #@
         f.foo.cache_info() #@
-        """
-    )
+        """)
     assert isinstance(ast_nodes, list)
     cache_clear = next(ast_nodes[0].infer())
     assert isinstance(cache_clear, astroid.BoundMethod)
     wrapped = next(ast_nodes[1].infer())
-    assert isinstance(wrapped, astroid.FunctionDef)
+    assert isinstance(wrapped, nodes.FunctionDef)
     assert wrapped.name == "foo"
     cache_info = next(ast_nodes[2].infer())
     assert isinstance(cache_info, astroid.Instance)
@@ -859,13 +813,11 @@
 
 def test_class_annotations() -> None:
     """Test that the `__annotations__` attribute is avaiable in the class scope"""
-    annotations, klass_attribute = builder.extract_node(
-        """
+    annotations, klass_attribute = builder.extract_node("""
         class Test:
             __annotations__  #@
         Test.__annotations__  #@
-        """
-    )
+        """)
     # Test that `__annotations__` attribute is available in the class scope:
     assert isinstance(annotations, nodes.Name)
     # The `__annotations__` attribute is `Uninferable`:
@@ -877,8 +829,7 @@
 
 def test_class_annotations_typed_dict() -> None:
     """Test that we can access class annotations on various TypedDicts"""
-    apple, pear = builder.extract_node(
-        """
+    apple, pear = builder.extract_node("""
         from typing import TypedDict
 
 
@@ -892,10 +843,176 @@
 
         Apple.__annotations__  #@
         Pear.__annotations__  #@
-        """
-    )
+        """)
 
     assert isinstance(apple, nodes.Attribute)
     assert next(apple.infer()) is astroid.Uninferable
     assert isinstance(pear, nodes.Attribute)
     assert next(pear.infer()) is astroid.Uninferable
+
+
+def test_object_dunder_methods_can_be_overridden() -> None:
+    """Test that ObjectModel dunders don't block class overrides."""
+    # Test instance method override
+    eq_result = builder.extract_node("""
+        class MyClass:
+            def __eq__(self, other):
+                return "custom equality"
+
+        MyClass().__eq__(None)  #@
+        """)
+    inferred = next(eq_result.infer())
+    assert isinstance(inferred, nodes.Const)
+    assert inferred.value == "custom equality"
+
+    # Test that __eq__ on instance returns a bound method
+    eq_method = builder.extract_node("""
+        class MyClass:
+            def __eq__(self, other):
+                return True
+
+        MyClass().__eq__  #@
+        """)
+    inferred = next(eq_method.infer())
+    assert isinstance(inferred, astroid.BoundMethod)
+
+    # Test other commonly overridden dunders
+    for dunder, return_val in (
+        ("__ne__", "not equal"),
+        ("__lt__", "less than"),
+        ("__le__", "less or equal"),
+        ("__gt__", "greater than"),
+        ("__ge__", "greater or equal"),
+        ("__str__", "string repr"),
+        ("__repr__", "repr"),
+        ("__hash__", 42),
+    ):
+        node = builder.extract_node(f"""
+            class MyClass:
+                def {dunder}(self, *args):
+                    return {return_val!r}
+
+            MyClass().{dunder}()  #@
+            """)
+        inferred = next(node.infer())
+        assert isinstance(inferred, nodes.Const), f"{dunder} failed to infer correctly"
+        assert inferred.value == return_val, f"{dunder} returned wrong value"
+
+
+def test_unoverridden_object_dunders_return_uninferable() -> None:
+    """Test that un-overridden object dunders return Uninferable when called."""
+    for dunder in (
+        "__eq__",
+        "__hash__",
+        "__lt__",
+        "__le__",
+        "__gt__",
+        "__ge__",
+        "__ne__",
+    ):
+        node = builder.extract_node(f"""
+            class MyClass:
+                pass
+
+            MyClass().{dunder}(None) if "{dunder}" != "__hash__" else MyClass().{dunder}()  #@
+            """)
+        result = next(node.infer())
+        assert result is util.Uninferable
+
+
+def test_all_object_dunders_accessible() -> None:
+    """Test that object dunders are accessible on classes and instances."""
+    # Use actual dunders from object in the current Python version
+    object_dunders = [attr for attr in dir(object) if attr.startswith("__")]
+
+    cls, instance = builder.extract_node("""
+        class MyClass:
+            pass
+
+        MyClass  #@
+        MyClass()  #@
+        """)
+    cls = next(cls.infer())
+    instance = next(instance.infer())
+
+    for dunder in object_dunders:
+        assert cls.getattr(dunder)
+        assert instance.getattr(dunder)
+
+
+def test_hash_none_for_unhashable_builtins() -> None:
+    """Test that unhashable builtin types have __hash__ = None."""
+    for type_name in ("list", "dict", "set"):
+        node = builder.extract_node(f"{type_name}  #@")
+        cls = next(node.infer())
+        hash_attr = cls.getattr("__hash__")[0]
+        assert isinstance(hash_attr, nodes.Const)
+        assert hash_attr.value is None
+
+
+def test_unbound_method_object_dunders_return_uninferable() -> None:
+    """Test that ObjectModel-only dunders on unbound methods return Uninferable."""
+    node = builder.extract_node("""
+    class A:
+        def test(self): pass
+    A.test  #@
+    """)
+    unbound = next(node.infer())
+    assert isinstance(unbound, bases.UnboundMethod)
+
+    for dunder in (
+        "__eq__",
+        "__ne__",
+        "__lt__",
+        "__le__",
+        "__gt__",
+        "__ge__",
+        "__repr__",
+        "__str__",
+        "__hash__",
+    ):
+        inferred = next(unbound.igetattr(dunder))
+        assert inferred is util.Uninferable, f"{dunder} should be Uninferable"
+
+        attrs = unbound.getattr(dunder)
+        assert attrs, f"{dunder} getattr should return results"
+
+
+def test_super_special_attributes_fallback() -> None:
+    """Test that super() special attributes use the fallback path correctly."""
+    doc_node = builder.extract_node("""
+    class Base:
+        def method(self):
+            return super().__doc__
+    Base().method()  #@
+    """)
+    doc_inferred = next(doc_node.infer())
+    assert doc_inferred is util.Uninferable
+
+    thisclass_node = builder.extract_node("""
+    class Base:
+        def method(self):
+            return super().__thisclass__
+    Base().method()  #@
+    """)
+    thisclass_inferred = next(thisclass_node.infer())
+    assert isinstance(thisclass_inferred, nodes.ClassDef)
+    assert thisclass_inferred.name == "Base"
+
+
+@pytest.mark.parametrize(
+    "attr",
+    [
+        "__get__",
+        "__defaults__",
+        "__annotations__",
+        "__dict__",
+        "__globals__",
+        "__kwdefaults__",
+    ],
+)
+def test_builtin_func_no_descriptor_attrs(attr: str) -> None:
+    """Test builtin functions lack descriptor protocol attributes."""
+    node = builder.extract_node(f"eval.{attr}")
+    with pytest.raises(InferenceError):
+        next(node.infer())
diff --git a/tests/test_objects.py b/tests/test_objects.py
index e9e8726..a13c6f4 100644
--- a/tests/test_objects.py
+++ b/tests/test_objects.py
@@ -13,11 +13,9 @@
 
 class ObjectsTest(unittest.TestCase):
     def test_frozenset(self) -> None:
-        node = builder.extract_node(
-            """
+        node = builder.extract_node("""
         frozenset({1: 2, 2: 3}) #@
-        """
-        )
+        """)
         inferred = next(node.infer())
         self.assertIsInstance(inferred, objects.FrozenSet)
 
@@ -39,22 +37,19 @@
         rely on the ._proxied attribute of an Instance.
         """
 
-        node = builder.extract_node(
-            """
+        node = builder.extract_node("""
         class ClassHavingUnknownAncestors(Unknown):
             __slots__ = ["yo"]
 
             def test(self):
                 self.not_yo = 42
-        """
-        )
+        """)
         assert node.getattr("__new__")
 
 
 class SuperTests(unittest.TestCase):
     def test_inferring_super_outside_methods(self) -> None:
-        ast_nodes = builder.extract_node(
-            """
+        ast_nodes = builder.extract_node("""
         class Module(object):
             pass
         class StaticMethod(object):
@@ -66,8 +61,7 @@
         super(Module, Module) #@
         # no argument super is not recognised outside methods as well.
         super() #@
-        """
-        )
+        """)
         assert isinstance(ast_nodes, list)
         in_static = next(ast_nodes[0].value.infer())
         self.assertIsInstance(in_static, bases.Instance)
@@ -82,26 +76,22 @@
         self.assertEqual(no_arguments.qname(), "builtins.super")
 
     def test_inferring_unbound_super_doesnt_work(self) -> None:
-        node = builder.extract_node(
-            """
+        node = builder.extract_node("""
         class Test(object):
             def __init__(self):
                 super(Test) #@
-        """
-        )
+        """)
         unbounded = next(node.infer())
         self.assertIsInstance(unbounded, bases.Instance)
         self.assertEqual(unbounded.qname(), "builtins.super")
 
     def test_use_default_inference_on_not_inferring_args(self) -> None:
-        ast_nodes = builder.extract_node(
-            """
+        ast_nodes = builder.extract_node("""
         class Test(object):
             def __init__(self):
                 super(Lala, self) #@
                 super(Test, lala) #@
-        """
-        )
+        """)
         assert isinstance(ast_nodes, list)
         first = next(ast_nodes[0].infer())
         self.assertIsInstance(first, bases.Instance)
@@ -112,8 +102,7 @@
         self.assertEqual(second.qname(), "builtins.super")
 
     def test_no_arguments_super(self) -> None:
-        ast_nodes = builder.extract_node(
-            """
+        ast_nodes = builder.extract_node("""
         class First(object): pass
         class Second(First):
             def test(self):
@@ -121,8 +110,7 @@
             @classmethod
             def test_classmethod(cls):
                 super() #@
-        """
-        )
+        """)
         assert isinstance(ast_nodes, list)
         first = next(ast_nodes[0].infer())
         self.assertIsInstance(first, objects.Super)
@@ -139,8 +127,7 @@
         self.assertEqual(second.mro_pointer.name, "Second")
 
     def test_super_simple_cases(self) -> None:
-        ast_nodes = builder.extract_node(
-            """
+        ast_nodes = builder.extract_node("""
         class First(object): pass
         class Second(First): pass
         class Third(First):
@@ -155,8 +142,7 @@
 
         class Fourth(Third):
             pass
-        """
-        )
+        """)
 
         # .type is the object which provides the mro.
         # .mro_pointer is the position in the mro from where
@@ -204,13 +190,11 @@
         self.assertEqual(fifth.mro_pointer.name, "Fourth")
 
     def test_super_infer(self) -> None:
-        node = builder.extract_node(
-            """
+        node = builder.extract_node("""
         class Super(object):
             def __init__(self):
                 super(Super, self) #@
-        """
-        )
+        """)
         inferred = next(node.infer())
         self.assertIsInstance(inferred, objects.Super)
         reinferred = next(inferred.infer())
@@ -218,8 +202,7 @@
         self.assertIs(inferred, reinferred)
 
     def test_inferring_invalid_supers(self) -> None:
-        ast_nodes = builder.extract_node(
-            """
+        ast_nodes = builder.extract_node("""
         class Super(object):
             def __init__(self):
                 # MRO pointer is not a type
@@ -230,8 +213,7 @@
                 super(Bupper, self) #@
         class Bupper(Super):
             pass
-        """
-        )
+        """)
         assert isinstance(ast_nodes, list)
         first = next(ast_nodes[0].infer())
         self.assertIsInstance(first, objects.Super)
@@ -247,21 +229,18 @@
             self.assertIsInstance(cm.exception.super_.type, invalid_type)
 
     def test_proxied(self) -> None:
-        node = builder.extract_node(
-            """
+        node = builder.extract_node("""
         class Super(object):
             def __init__(self):
                 super(Super, self) #@
-        """
-        )
+        """)
         inferred = next(node.infer())
         proxied = inferred._proxied
         self.assertEqual(proxied.qname(), "builtins.super")
         self.assertIsInstance(proxied, nodes.ClassDef)
 
     def test_super_bound_model(self) -> None:
-        ast_nodes = builder.extract_node(
-            """
+        ast_nodes = builder.extract_node("""
         class First(object):
             def method(self):
                 pass
@@ -281,8 +260,7 @@
             def method(self):
                 super(Super_Type_Object, self).method #@
                 super(Super_Type_Object, self).class_method #@
-        """
-        )
+        """)
         # Super(type, type) is the same for both functions and classmethods.
         assert isinstance(ast_nodes, list)
         first = next(ast_nodes[0].infer())
@@ -316,8 +294,7 @@
         self.assertEqual(sixth.type, "classmethod")
 
     def test_super_getattr_single_inheritance(self) -> None:
-        ast_nodes = builder.extract_node(
-            """
+        ast_nodes = builder.extract_node("""
         class First(object):
             def test(self): pass
         class Second(First):
@@ -335,8 +312,7 @@
                 super(Third, Third).test2 #@
                 super(Third, Third).test #@
 
-        """
-        )
+        """)
         assert isinstance(ast_nodes, list)
         first = next(ast_nodes[0].infer())
         self.assertIsInstance(first, bases.BoundMethod)
@@ -365,22 +341,19 @@
         self.assertEqual(second_unbound.parent.name, "First")
 
     def test_super_invalid_mro(self) -> None:
-        node = builder.extract_node(
-            """
+        node = builder.extract_node("""
         class A(object):
            test = 42
         class Super(A, A):
            def __init__(self):
                super(Super, self) #@
-        """
-        )
+        """)
         inferred = next(node.infer())
         with self.assertRaises(AttributeInferenceError):
             next(inferred.getattr("test"))
 
     def test_super_complex_mro(self) -> None:
-        ast_nodes = builder.extract_node(
-            """
+        ast_nodes = builder.extract_node("""
         class A(object):
             def spam(self): return "A"
             def foo(self): return "A"
@@ -398,8 +371,7 @@
                 super(E, self).spam #@
                 super(E, self).foo #@
                 super(E, self).static #@
-        """
-        )
+        """)
         assert isinstance(ast_nodes, list)
         first = next(ast_nodes[0].infer())
         self.assertIsInstance(first, bases.BoundMethod)
@@ -417,16 +389,14 @@
         self.assertEqual(static.parent.scope().name, "A")
 
     def test_super_data_model(self) -> None:
-        ast_nodes = builder.extract_node(
-            """
+        ast_nodes = builder.extract_node("""
         class X(object): pass
         class A(X):
             def __init__(self):
                 super(A, self) #@
                 super(A, A) #@
                 super(X, A) #@
-        """
-        )
+        """)
         assert isinstance(ast_nodes, list)
         first = next(ast_nodes[0].infer())
         thisclass = first.getattr("__thisclass__")[0]
@@ -458,8 +428,7 @@
         self.assertEqual([member.name for member in klass.super_mro()], expected_mro)
 
     def test_super_mro(self) -> None:
-        ast_nodes = builder.extract_node(
-            """
+        ast_nodes = builder.extract_node("""
         class A(object): pass
         class B(A): pass
         class C(A): pass
@@ -471,8 +440,7 @@
 
                 super(B, 1) #@
                 super(1, B) #@
-        """
-        )
+        """)
         assert isinstance(ast_nodes, list)
         first = next(ast_nodes[0].infer())
         self.assertEqualMro(first, ["C", "B", "A", "object"])
@@ -489,30 +457,76 @@
             fifth.super_mro()
 
     def test_super_yes_objects(self) -> None:
-        ast_nodes = builder.extract_node(
-            """
+        ast_nodes = builder.extract_node("""
         from collections import Missing
         class A(object):
             def __init__(self):
                 super(Missing, self) #@
                 super(A, Missing) #@
-        """
-        )
+        """)
         assert isinstance(ast_nodes, list)
         first = next(ast_nodes[0].infer())
         self.assertIsInstance(first, bases.Instance)
         second = next(ast_nodes[1].infer())
         self.assertIsInstance(second, bases.Instance)
 
+    def test_super_method_chaining_return_type(self) -> None:
+        """Test that super().method() correctly infers child type.
+
+        Regression test for: https://github.com/pylint-dev/astroid/issues/457
+        """
+        node = builder.extract_node("""
+        class Parent:
+            def method(self) -> "Parent":
+                return self
+
+        class Child(Parent):
+            def method(self) -> "Child":
+                return super().method()
+
+            def extra(self) -> "Child":
+                return self
+
+        Child().method().extra() #@
+        """)
+        inferred = next(node.infer())
+        # Should infer Child instance, not Parent
+        self.assertIsInstance(inferred, bases.Instance)
+        self.assertEqual(inferred._proxied.name, "Child")
+
+    def test_super_classmethod_chaining_return_type(self) -> None:
+        """Test that super().classmethod() correctly infers child type.
+
+        Regression test for: https://github.com/pylint-dev/astroid/issues/457
+        """
+        node = builder.extract_node("""
+        class Parent:
+            @classmethod
+            def create(cls) -> "Parent":
+                return cls()
+
+        class Child(Parent):
+            @classmethod
+            def create(cls) -> "Child":
+                return super().create()
+
+            def extra(self) -> "Child":
+                return self
+
+        Child.create().extra() #@
+        """)
+        inferred = next(node.infer())
+        # Should infer Child instance, not Parent
+        self.assertIsInstance(inferred, bases.Instance)
+        self.assertEqual(inferred._proxied.name, "Child")
+
     def test_super_invalid_types(self) -> None:
-        node = builder.extract_node(
-            """
+        node = builder.extract_node("""
         import collections
         class A(object):
             def __init__(self):
                 super(A, collections) #@
-        """
-        )
+        """)
         inferred = next(node.infer())
         with self.assertRaises(SuperError):
             inferred.super_mro()
@@ -520,8 +534,7 @@
             inferred.super_mro()
 
     def test_super_properties(self) -> None:
-        node = builder.extract_node(
-            """
+        node = builder.extract_node("""
         class Foo(object):
             @property
             def dict(self):
@@ -533,8 +546,7 @@
                 return super(Bar, self).dict
 
         Bar().dict
-        """
-        )
+        """)
         inferred = next(node.infer())
         self.assertIsInstance(inferred, nodes.Const)
         self.assertEqual(inferred.value, 42)
@@ -554,15 +566,13 @@
 
     def test_super_new_call(self) -> None:
         """Test that __new__ returns an object or node and not a (Un)BoundMethod."""
-        new_call_result: nodes.Name = builder.extract_node(
-            """
+        new_call_result: nodes.Name = builder.extract_node("""
         import enum
         class ChoicesMeta(enum.EnumMeta):
             def __new__(metacls, classname, bases, classdict, **kwds):
                 cls = super().__new__(metacls, "str", (enum.Enum,), enum._EnumDict(), **kwargs)
                 cls #@
-        """
-        )
+        """)
         inferred = list(new_call_result.infer())
         assert all(
             isinstance(i, (nodes.NodeNG, type(util.Uninferable))) for i in inferred
@@ -570,8 +580,7 @@
 
     def test_super_init_call(self) -> None:
         """Test that __init__ is still callable."""
-        init_node: nodes.Attribute = builder.extract_node(
-            """
+        init_node: nodes.Attribute = builder.extract_node("""
         class SuperUsingClass:
             @staticmethod
             def test():
@@ -581,8 +590,7 @@
             pass
         A().__new__ #@
         A().__init__ #@
-        """
-        )
+        """)
         assert isinstance(next(init_node[0].infer()), bases.BoundMethod)
         assert isinstance(next(init_node[1].infer()), bases.BoundMethod)
         assert isinstance(next(init_node[2].infer()), bases.BoundMethod)
diff --git a/tests/test_protocols.py b/tests/test_protocols.py
index 4a9f1f6..4987d2a 100644
--- a/tests/test_protocols.py
+++ b/tests/test_protocols.py
@@ -13,7 +13,7 @@
 
 import astroid
 from astroid import extract_node, nodes
-from astroid.const import PY310_PLUS, PY312_PLUS
+from astroid.const import PY312_PLUS
 from astroid.exceptions import InferenceError
 from astroid.manager import AstroidManager
 from astroid.util import Uninferable, UninferableBase
@@ -53,15 +53,13 @@
             self.assertEqual(expected_name, node.name)
 
     def test_assigned_stmts_simple_for(self) -> None:
-        assign_stmts = extract_node(
-            """
+        assign_stmts = extract_node("""
         for a in (1, 2, 3):  #@
           pass
 
         for b in range(3): #@
           pass
-        """
-        )
+        """)
 
         for1_assnode = next(assign_stmts[0].nodes_of_class(nodes.AssignName))
         assigned = list(for1_assnode.assigned_stmts())
@@ -71,12 +69,10 @@
         self.assertRaises(InferenceError, list, for2_assnode.assigned_stmts())
 
     def test_assigned_stmts_nested_for_tuple(self) -> None:
-        assign_stmts = extract_node(
-            """
+        assign_stmts = extract_node("""
         for a, (b, c) in [(1, (2, 3))]:  #@
           pass
-        """
-        )
+        """)
 
         assign_nodes = assign_stmts.nodes_of_class(nodes.AssignName)
 
@@ -89,12 +85,10 @@
         self.assertConstNodesEqual([2], assigned2)
 
     def test_assigned_stmts_nested_for_dict(self) -> None:
-        assign_stmts = extract_node(
-            """
+        assign_stmts = extract_node("""
         for a, (b, c) in {1: ("a", str), 2: ("b", bytes)}.items():  #@
             pass
-        """
-        )
+        """)
         assign_nodes = assign_stmts.nodes_of_class(nodes.AssignName)
 
         # assigned: [1, 2]
@@ -113,16 +107,14 @@
         self.assertNameNodesEqual(["str", "bytes"], assigned3)
 
     def test_assigned_stmts_starred_for(self) -> None:
-        assign_stmts = extract_node(
-            """
+        assign_stmts = extract_node("""
         for *a, b in ((1, 2, 3), (4, 5, 6, 7)): #@
             pass
-        """
-        )
+        """)
 
         for1_starred = next(assign_stmts.nodes_of_class(nodes.Starred))
         assigned = next(for1_starred.assigned_stmts())
-        assert isinstance(assigned, astroid.List)
+        assert isinstance(assigned, nodes.List)
         assert assigned.as_string() == "[1, 2]"
 
     def _get_starred_stmts(self, code: str) -> list | UninferableBase:
@@ -191,13 +183,11 @@
         )
 
     def test_assigned_stmts_assignments(self) -> None:
-        assign_stmts = extract_node(
-            """
+        assign_stmts = extract_node("""
         c = a #@
 
         d, e = b, c #@
-        """
-        )
+        """)
 
         simple_assnode = next(assign_stmts[0].nodes_of_class(nodes.AssignName))
         assigned = list(simple_assnode.assigned_stmts())
@@ -212,12 +202,10 @@
         self.assertNameNodesEqual(["c"], assigned)
 
     def test_assigned_stmts_annassignments(self) -> None:
-        annassign_stmts = extract_node(
-            """
+        annassign_stmts = extract_node("""
         a: str = "abc"  #@
         b: str  #@
-        """
-        )
+        """)
         simple_annassign_node = next(
             annassign_stmts[0].nodes_of_class(nodes.AssignName)
         )
@@ -236,12 +224,10 @@
             node.root().locals["__all__"] = [node.value]
 
         manager = astroid.MANAGER
-        with _add_transform(manager, astroid.Assign, transform):
-            module = astroid.parse(
-                """
+        with _add_transform(manager, nodes.Assign, transform):
+            module = astroid.parse("""
             __all__ = ['a']
-            """
-            )
+            """)
             module.wildcard_import_names()
 
     def test_not_passing_uninferable_in_seq_inference(self) -> None:
@@ -261,12 +247,10 @@
                 for _ in node.infer():
                     pass
 
-        parsed = extract_node(
-            """
+        parsed = extract_node("""
         a = []
         x = [a*2, a]*2*2
-        """
-        )
+        """)
         parsed.accept(Visitor())
 
     @staticmethod
@@ -364,7 +348,6 @@
     assert node.value == 1
 
 
-@pytest.mark.skipif(not PY310_PLUS, reason="Match requires python 3.10")
 class TestPatternMatching:
     @staticmethod
     def test_assigned_stmts_match_mapping():
@@ -372,14 +355,12 @@
 
         Test the result is 'Uninferable' and no exception is raised.
         """
-        assign_stmts = extract_node(
-            """
+        assign_stmts = extract_node("""
         var = {1: "Hello", 2: "World"}
         match var:
             case {**rest}:  #@
                 pass
-        """
-        )
+        """)
         match_mapping: nodes.MatchMapping = assign_stmts.pattern  # type: ignore[union-attr]
         assert match_mapping.rest
         assigned = next(match_mapping.rest.assigned_stmts())
@@ -391,14 +372,12 @@
 
         Test the result is 'Uninferable' and no exception is raised.
         """
-        assign_stmts = extract_node(
-            """
+        assign_stmts = extract_node("""
         var = (0, 1, 2)
         match var:
             case (0, 1, *rest):  #@
                 pass
-        """
-        )
+        """)
         match_sequence: nodes.MatchSequence = assign_stmts.pattern  # type: ignore[union-attr]
         match_star = match_sequence.patterns[2]
         assert isinstance(match_star, nodes.MatchStar) and match_star.name
@@ -408,8 +387,7 @@
     @staticmethod
     def test_assigned_stmts_match_as():
         """Assigned_stmts for MatchAs only implemented for the most basic case (y)."""
-        assign_stmts = extract_node(
-            """
+        assign_stmts = extract_node("""
         var = 42
         match var:  #@
             case 2 | x:  #@
@@ -418,8 +396,7 @@
                 pass
             case z:  #@
                 pass
-        """
-        )
+        """)
         subject: nodes.Const = assign_stmts[0].subject  # type: ignore[index,union-attr]
         match_or: nodes.MatchOr = assign_stmts[1].pattern  # type: ignore[index,union-attr]
         match_as_with_pattern: nodes.MatchAs = assign_stmts[2].pattern  # type: ignore[index,union-attr]
diff --git a/tests/test_python3.py b/tests/test_python3.py
index d982e6f..89d53ae 100644
--- a/tests/test_python3.py
+++ b/tests/test_python3.py
@@ -26,12 +26,10 @@
         self.assertTrue(isinstance(node.assign_type(), nodes.Assign))
 
     def test_yield_from(self) -> None:
-        body = dedent(
-            """
+        body = dedent("""
         def func():
             yield from iter([1, 2])
-        """
-        )
+        """)
         astroid = self.builder.string_build(body)
         func = astroid.body[0]
         self.assertIsInstance(func, nodes.FunctionDef)
@@ -42,25 +40,21 @@
         self.assertEqual(yieldfrom_stmt.as_string(), "yield from iter([1, 2])")
 
     def test_yield_from_is_generator(self) -> None:
-        body = dedent(
-            """
+        body = dedent("""
         def func():
             yield from iter([1, 2])
-        """
-        )
+        """)
         astroid = self.builder.string_build(body)
         func = astroid.body[0]
         self.assertIsInstance(func, nodes.FunctionDef)
         self.assertTrue(func.is_generator())
 
     def test_yield_from_as_string(self) -> None:
-        body = dedent(
-            """
+        body = dedent("""
         def func():
             yield from iter([1, 2])
             value = yield from other()
-        """
-        )
+        """)
         astroid = self.builder.string_build(body)
         func = astroid.body[0]
         self.assertEqual(func.as_string().strip(), body.strip())
@@ -81,13 +75,9 @@
         self.assertFalse(klass.metaclass())
 
     def test_metaclass_imported(self) -> None:
-        astroid = self.builder.string_build(
-            dedent(
-                """
+        astroid = self.builder.string_build(dedent("""
         from abc import ABCMeta
-        class Test(metaclass=ABCMeta): pass"""
-            )
-        )
+        class Test(metaclass=ABCMeta): pass"""))
         klass = astroid.body[1]
 
         metaclass = klass.metaclass()
@@ -105,11 +95,9 @@
         self.assertEqual(metaclass.name, "type")
 
     def test_as_string(self) -> None:
-        body = dedent(
-            """
+        body = dedent("""
         from abc import ABCMeta
-        class Test(metaclass=ABCMeta): pass"""
-        )
+        class Test(metaclass=ABCMeta): pass""")
         astroid = self.builder.string_build(body)
         klass = astroid.body[1]
 
@@ -118,52 +106,38 @@
         )
 
     def test_old_syntax_works(self) -> None:
-        astroid = self.builder.string_build(
-            dedent(
-                """
+        astroid = self.builder.string_build(dedent("""
         class Test:
             __metaclass__ = type
         class SubTest(Test): pass
-        """
-            )
-        )
+        """))
         klass = astroid["SubTest"]
         metaclass = klass.metaclass()
         self.assertIsNone(metaclass)
 
     def test_metaclass_yes_leak(self) -> None:
-        astroid = self.builder.string_build(
-            dedent(
-                """
+        astroid = self.builder.string_build(dedent("""
         # notice `ab` instead of `abc`
         from ab import ABCMeta
 
         class Meta(metaclass=ABCMeta): pass
-        """
-            )
-        )
+        """))
         klass = astroid["Meta"]
         self.assertIsNone(klass.metaclass())
 
     def test_parent_metaclass(self) -> None:
-        astroid = self.builder.string_build(
-            dedent(
-                """
+        astroid = self.builder.string_build(dedent("""
         from abc import ABCMeta
         class Test(metaclass=ABCMeta): pass
         class SubTest(Test): pass
-        """
-            )
-        )
+        """))
         klass = astroid["SubTest"]
         metaclass = klass.metaclass()
         self.assertIsInstance(metaclass, nodes.ClassDef)
         self.assertEqual(metaclass.name, "ABCMeta")
 
     def test_metaclass_ancestors(self) -> None:
-        astroid = self.builder.string_build(
-            dedent(
-                """
+        astroid = self.builder.string_build(dedent("""
         from abc import ABCMeta
 
         class FirstMeta(metaclass=ABCMeta): pass
@@ -177,9 +151,7 @@
         class SecondImpl(FirstImpl): pass
         class ThirdImpl(Simple, SecondMeta):
             pass
-        """
-            )
-        )
+        """))
         classes = {"ABCMeta": ("FirstImpl", "SecondImpl"), "type": ("ThirdImpl",)}
         for metaclass, names in classes.items():
             for name in names:
@@ -189,15 +161,11 @@
                 self.assertEqual(meta.name, metaclass)
 
     def test_annotation_support(self) -> None:
-        astroid = self.builder.string_build(
-            dedent(
-                """
+        astroid = self.builder.string_build(dedent("""
         def test(a: int, b: str, c: None, d, e,
                  *args: float, **kwargs: int)->int:
             pass
-        """
-            )
-        )
+        """))
         func = astroid["test"]
         self.assertIsInstance(func.args.varargannotation, nodes.Name)
         self.assertEqual(func.args.varargannotation.name, "float")
@@ -215,14 +183,10 @@
         self.assertIsNone(arguments.annotations[3])
         self.assertIsNone(arguments.annotations[4])
 
-        astroid = self.builder.string_build(
-            dedent(
-                """
+        astroid = self.builder.string_build(dedent("""
         def test(a: int=1, b: str=2):
             pass
-        """
-            )
-        )
+        """))
         func = astroid["test"]
         self.assertIsInstance(func.args.annotations[0], nodes.Name)
         self.assertEqual(func.args.annotations[0].name, "int")
@@ -231,14 +195,10 @@
         self.assertIsNone(func.returns)
 
     def test_kwonlyargs_annotations_supper(self) -> None:
-        node = self.builder.string_build(
-            dedent(
-                """
+        node = self.builder.string_build(dedent("""
         def test(*, a: int, b: str, c: None, d, e):
             pass
-        """
-            )
-        )
+        """))
         func = node["test"]
         arguments = func.args
         self.assertIsInstance(arguments.kwonlyargs_annotations[0], nodes.Name)
@@ -251,16 +211,12 @@
         self.assertIsNone(arguments.kwonlyargs_annotations[4])
 
     def test_annotation_as_string(self) -> None:
-        code1 = dedent(
-            """
+        code1 = dedent("""
         def test(a, b: int = 4, c=2, f: 'lala' = 4) -> 2:
-            pass"""
-        )
-        code2 = dedent(
-            """
+            pass""")
+        code2 = dedent("""
         def test(a: typing.Generic[T], c: typing.Any = 24) -> typing.Iterable:
-            pass"""
-        )
+            pass""")
         for code in (code1, code2):
             func = extract_node(code)
             self.assertEqual(func.as_string(), code)
@@ -288,12 +244,10 @@
 
     @staticmethod
     def test_unpacking_in_dict_getitem_with_ref() -> None:
-        node = extract_node(
-            """
+        node = extract_node("""
         a = {1: 2}
         {**a, 2: 3}  #@
-        """
-        )
+        """)
         assert isinstance(node, nodes.Dict)
 
         for key, expected in ((1, 2), (2, 3)):
@@ -390,10 +344,8 @@
             "return {fun: await fun() async for fun in funcs if await smth}",
         ]
         for func_body in func_bodies:
-            code = dedent(
-                f"""
+            code = dedent(f"""
             async def f():
-                {func_body}"""
-            )
+                {func_body}""")
             func = extract_node(code)
             self.assertEqual(func.as_string().strip(), code.strip())
diff --git a/tests/test_raw_building.py b/tests/test_raw_building.py
index bb7c733..fdd8603 100644
--- a/tests/test_raw_building.py
+++ b/tests/test_raw_building.py
@@ -10,7 +10,7 @@
 
 from __future__ import annotations
 
-import _io
+import _io  # pylint: disable=wrong-import-order
 import logging
 import os
 import sys
@@ -19,7 +19,6 @@
 from typing import Any
 from unittest import mock
 
-import mypy.build
 import pytest
 
 import tests.testdata.python3.data.fake_module_with_broken_getattr as fm_getattr
@@ -37,6 +36,13 @@
     object_build_class,
 )
 
+try:
+    import mypy.build
+
+    HAS_MYPY = True
+except ImportError:
+    HAS_MYPY = False
+
 DUMMY_MOD = build_module("DUMMY")
 
 
@@ -173,6 +179,7 @@
     assert not err
 
 
+@pytest.mark.skipif(not HAS_MYPY, reason="This test requires mypy")
 def test_missing__dict__():
     # This shouldn't raise an exception.
     object_build_class(DUMMY_MOD, mypy.build.ModuleNotFound)
diff --git a/tests/test_regrtest.py b/tests/test_regrtest.py
index 76a7cea..a207057 100644
--- a/tests/test_regrtest.py
+++ b/tests/test_regrtest.py
@@ -2,6 +2,7 @@
 # For details: https://github.com/pylint-dev/astroid/blob/main/LICENSE
 # Copyright (c) https://github.com/pylint-dev/astroid/blob/main/CONTRIBUTORS.txt
 
+import platform
 import sys
 import textwrap
 import unittest
@@ -13,7 +14,7 @@
 from astroid.builder import AstroidBuilder, _extract_single_node, extract_node
 from astroid.const import PY312_PLUS
 from astroid.context import InferenceContext
-from astroid.exceptions import InferenceError
+from astroid.exceptions import AstroidSyntaxError, InferenceError
 from astroid.manager import AstroidManager
 from astroid.raw_building import build_module
 from astroid.util import Uninferable
@@ -110,12 +111,10 @@
         PY312_PLUS -- This test will likely become unnecessary when Python 3.12 is
         numpy's minimum version. (numpy.distutils will be removed then.)
         """
-        node = extract_node(
-            """
+        node = extract_node("""
 from numpy.distutils.misc_util import is_sequence
 is_sequence("ABC") #@
-"""
-        )
+""")
         inferred = node.inferred()
         self.assertIsInstance(inferred[0], nodes.Const)
 
@@ -215,9 +214,7 @@
         assert result[2].lineno == 12
 
     def test_ancestors_patching_class_recursion(self) -> None:
-        node = AstroidBuilder(AstroidManager()).string_build(
-            textwrap.dedent(
-                """
+        node = AstroidBuilder(AstroidManager()).string_build(textwrap.dedent("""
         import string
         Template = string.Template
 
@@ -232,9 +229,7 @@
                 string.Template = A
             else:
                 string.Template = B
-        """
-            )
-        )
+        """))
         klass = node["A"]
         ancestors = list(klass.ancestors())
         self.assertEqual(ancestors[0].qname(), "string.Template")
@@ -243,8 +238,7 @@
         # Test for issue https://bitbucket.org/logilab/astroid/issue/84
         # This used to crash astroid with a TypeError, because an Uninferable
         # node was present in the bases
-        node = extract_node(
-            """
+        node = extract_node("""
         def with_metaclass(meta, *bases):
             class metaclass(meta):
                 def __new__(cls, name, this_bases, d):
@@ -255,21 +249,18 @@
 
         class A(with_metaclass(object, lala.lala)): #@
             pass
-        """
-        )
+        """)
         ancestors = list(node.ancestors())
         self.assertEqual(len(ancestors), 1)
         self.assertEqual(ancestors[0].qname(), "builtins.object")
 
     def test_ancestors_missing_from_function(self) -> None:
         # Test for https://www.logilab.org/ticket/122793
-        node = extract_node(
-            """
+        node = extract_node("""
         def gen(): yield
         GEN = gen()
         next(GEN)
-        """
-        )
+        """)
         self.assertRaises(InferenceError, next, node.infer())
 
     def test_unicode_in_docstring(self) -> None:
@@ -277,8 +268,7 @@
         # Test for https://bitbucket.org/logilab/astroid/issues/273/
 
         # In a regular file, "coding: utf-8" would have been used.
-        node = extract_node(
-            f"""
+        node = extract_node(f"""
         from __future__ import unicode_literals
 
         class MyClass(object):
@@ -286,30 +276,26 @@
                 "With unicode : {'’'} "
 
         instance = MyClass()
-        """
-        )
+        """)
 
         next(node.value.infer()).as_string()
 
     def test_binop_generates_nodes_with_parents(self) -> None:
-        node = extract_node(
-            """
+        node = extract_node("""
         def no_op(*args):
             pass
         def foo(*args):
             def inner(*more_args):
                 args + more_args #@
             return inner
-        """
-        )
+        """)
         inferred = next(node.infer())
         self.assertIsInstance(inferred, nodes.Tuple)
         self.assertIsNotNone(inferred.parent)
         self.assertIsInstance(inferred.parent, nodes.BinOp)
 
     def test_decorator_names_inference_error_leaking(self) -> None:
-        node = extract_node(
-            """
+        node = extract_node("""
         class Parent(object):
             @property
             def foo(self):
@@ -319,30 +305,25 @@
             @Parent.foo.getter
             def foo(self): #@
                 return super(Child, self).foo + ['oink']
-        """
-        )
+        """)
         inferred = next(node.infer())
         self.assertEqual(inferred.decoratornames(), {".Parent.foo.getter"})
 
     def test_recursive_property_method(self) -> None:
-        node = extract_node(
-            """
+        node = extract_node("""
         class APropert():
             @property
             def property(self):
                 return self
         APropert().property
-        """
-        )
+        """)
         next(node.infer())
 
     def test_uninferable_string_argument_of_namedtuple(self) -> None:
-        node = extract_node(
-            """
+        node = extract_node("""
         import collections
         collections.namedtuple('{}'.format("a"), '')()
-        """
-        )
+        """)
         next(node.infer())
 
     def test_regression_inference_of_self_in_lambda(self) -> None:
@@ -470,21 +451,17 @@
 )
 def test_recursion_during_inference(mocked) -> None:
     """Check that we don't crash if we hit the recursion limit during inference."""
-    node: nodes.Call = _extract_single_node(
-        """
+    node: nodes.Call = _extract_single_node("""
     from module import something
     something()
-    """
-    )
+    """)
     with pytest.raises(InferenceError) as error:
         next(node.infer())
     assert error.value.message.startswith("RecursionError raised")
 
 
 def test_regression_missing_callcontext() -> None:
-    node: nodes.Attribute = _extract_single_node(
-        textwrap.dedent(
-            """
+    node: nodes.Attribute = _extract_single_node(textwrap.dedent("""
         import functools
 
         class MockClass:
@@ -494,7 +471,71 @@
             enabled = property(functools.partial(_get_option, option='myopt'))
 
         MockClass().enabled
-        """
-        )
-    )
+        """))
     assert node.inferred()[0].value == "mystr"
+
+
+def test_regression_root_is_not_a_module() -> None:
+    """Regression test for #2672."""
+    node: nodes.ClassDef = _extract_single_node(textwrap.dedent("""
+        a=eval.__get__(1).__gt__
+
+        @a
+        class c: ...
+        """))
+    assert node.name == "c"
+
+
+def test_regression_eval_get_of_arg() -> None:
+    """Regression test for #2743."""
+    node = _extract_single_node("eval.__get__(1)")
+    with pytest.raises(InferenceError):
+        next(node.infer())
+
+
+def test_regression_no_crash_during_build() -> None:
+    node: nodes.Attribute = extract_node("__()")
+    assert node.args == []
+    assert node.as_string() == "__()"
+
+
+def test_regression_no_crash_on_called_slice() -> None:
+    """Regression test for issue #2721."""
+    node: nodes.Attribute = extract_node(textwrap.dedent("""
+        s = slice(-2)
+        @s()
+        @six.add_metaclass()
+        class a: ...
+        """))
+    assert isinstance(node, nodes.ClassDef)
+    assert node.name == "a"
+
+
+def test_regression_infer_dict_literal_comparison_uninferable() -> None:
+    """Regression test for issue #2522."""
+    node = extract_node("{{}}>0")
+    inferred = next(node.infer())
+    assert inferred.value == Uninferable
+
+
+def test_regression_infer_namedtuple_invalid_fieldname_error() -> None:
+    """Regression test for issue #2519."""
+    code = """
+    from collections import namedtuple
+    namedtuple('a','}')
+    """
+    node = extract_node(code)
+    inferred = next(node.infer())
+    assert inferred.value == Uninferable
+
+
+def test_regression_parse_deeply_nested_parentheses() -> None:
+    """Regression test for issue #2643."""
+    with pytest.raises(AstroidSyntaxError, match="Parsing Python code failed:") as ctx:
+        extract_node(
+            "A=((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((c,j=t"
+        )
+    expected = (
+        SyntaxError if platform.python_implementation() == "PyPy" else MemoryError
+    )
+    assert isinstance(ctx.value.error, expected)
diff --git a/tests/test_scoped_nodes.py b/tests/test_scoped_nodes.py
index f3244c6..641a69a 100644
--- a/tests/test_scoped_nodes.py
+++ b/tests/test_scoped_nodes.py
@@ -29,7 +29,7 @@
     util,
 )
 from astroid.bases import BoundMethod, Generator, Instance, UnboundMethod
-from astroid.const import WIN32
+from astroid.const import PY312_PLUS, WIN32
 from astroid.exceptions import (
     AstroidBuildingError,
     AttributeInferenceError,
@@ -134,47 +134,39 @@
         self.assertEqual(res, ["Aaa", "func", "name", "other"])
 
     def test_public_names(self) -> None:
-        m = builder.parse(
-            """
+        m = builder.parse("""
         name = 'a'
         _bla = 2
         other = 'o'
         class Aaa: pass
         def func(): print('yo')
         __all__ = 'Aaa', '_bla', 'name'
-        """
-        )
+        """)
         values = sorted(["Aaa", "name", "other", "func"])
         self.assertEqual(sorted(m.public_names()), values)
-        m = builder.parse(
-            """
+        m = builder.parse("""
         name = 'a'
         _bla = 2
         other = 'o'
         class Aaa: pass
 
         def func(): return 'yo'
-        """
-        )
+        """)
         res = sorted(m.public_names())
         self.assertEqual(res, values)
 
-        m = builder.parse(
-            """
+        m = builder.parse("""
             from missing import tzop
             trop = "test"
             __all__ = (trop, "test1", tzop, 42)
-        """
-        )
+        """)
         res = sorted(m.public_names())
         self.assertEqual(res, ["trop", "tzop"])
 
-        m = builder.parse(
-            """
+        m = builder.parse("""
             test = tzop = 42
             __all__ = ('test', ) + ('tzop', )
-        """
-        )
+        """)
         res = sorted(m.public_names())
         self.assertEqual(res, ["test", "tzop"])
 
@@ -292,12 +284,10 @@
 
     @staticmethod
     def test_singleline_docstring() -> None:
-        data = textwrap.dedent(
-            """\
+        data = textwrap.dedent("""\
             '''Hello World'''
             foo = 1
-        """
-        )
+        """)
         module = builder.parse(data, __name__)
         assert isinstance(module.doc_node, nodes.Const)
         assert module.doc_node.lineno == 1
@@ -307,15 +297,13 @@
 
     @staticmethod
     def test_multiline_docstring() -> None:
-        data = textwrap.dedent(
-            """\
+        data = textwrap.dedent("""\
             '''Hello World
 
             Also on this line.
             '''
             foo = 1
-        """
-        )
+        """)
         module = builder.parse(data, __name__)
 
         assert isinstance(module.doc_node, nodes.Const)
@@ -326,15 +314,13 @@
 
     @staticmethod
     def test_comment_before_docstring() -> None:
-        data = textwrap.dedent(
-            """\
+        data = textwrap.dedent("""\
             # Some comment
             '''This is
 
             a multiline docstring.
             '''
-        """
-        )
+        """)
         module = builder.parse(data, __name__)
 
         assert isinstance(module.doc_node, nodes.Const)
@@ -345,11 +331,9 @@
 
     @staticmethod
     def test_without_docstring() -> None:
-        data = textwrap.dedent(
-            """\
+        data = textwrap.dedent("""\
             foo = 1
-        """
-        )
+        """)
         module = builder.parse(data, __name__)
         assert module.doc_node is None
 
@@ -416,16 +400,10 @@
         self.assertEqual(func.args.format_args(), "a, b, c, d")
 
     def test_format_args_keyword_only_args(self) -> None:
-        node = (
-            builder.parse(
-                """
+        node = builder.parse("""
         def test(a: int, *, b: dict):
             pass
-        """
-            )
-            .body[-1]
-            .args
-        )
+        """).body[-1].args
         formatted = node.format_args()
         self.assertEqual(formatted, "a: int, *, b: dict")
 
@@ -446,8 +424,7 @@
         self.assertFalse(func.is_abstract(pass_is_abstract=False))
 
     def test_is_abstract_decorated(self) -> None:
-        methods = builder.extract_node(
-            """
+        methods = builder.extract_node("""
             import abc
 
             class Klass(object):
@@ -463,8 +440,7 @@
                 @some_other_decorator
                 def method2(self):  #@
                    pass
-         """
-        )
+         """)
         assert len(methods) == 3
         prop, method1, method2 = methods
         assert isinstance(prop, nodes.FunctionDef)
@@ -658,8 +634,7 @@
         self.assertEqual(func2.implicit_parameters(), 0)
 
     def test_type_builtin_descriptor_subclasses(self) -> None:
-        astroid = builder.parse(
-            """
+        astroid = builder.parse("""
             class classonlymethod(classmethod):
                 pass
             class staticonlymethod(staticmethod):
@@ -678,8 +653,7 @@
                 @staticmethod
                 def stcmethod(cls):
                     pass
-        """
-        )
+        """)
         node = astroid.locals["Node"][0]
         self.assertEqual(node.locals["clsmethod_subclass"][0].type, "classmethod")
         self.assertEqual(node.locals["clsmethod"][0].type, "classmethod")
@@ -687,8 +661,7 @@
         self.assertEqual(node.locals["stcmethod"][0].type, "staticmethod")
 
     def test_decorator_builtin_descriptors(self) -> None:
-        astroid = builder.parse(
-            """
+        astroid = builder.parse("""
             def static_decorator(platform=None, order=50):
                 def wrapper(f):
                     f.cgm_module = True
@@ -749,8 +722,7 @@
                 @long_classmethod_decorator()
                 def long_classmethod(cls):
                     pass
-        """
-        )
+        """)
         node = astroid.locals["SomeClass"][0]
         self.assertEqual(node.locals["static"][0].type, "staticmethod")
         self.assertEqual(node.locals["classmethod"][0].type, "classmethod")
@@ -761,12 +733,10 @@
         self.assertEqual(node.locals["long_classmethod"][0].type, "classmethod")
 
     def test_igetattr(self) -> None:
-        func = builder.extract_node(
-            """
+        func = builder.extract_node("""
         def test():
             pass
-        """
-        )
+        """)
         assert isinstance(func, nodes.FunctionDef)
         func.instance_attrs["value"] = [nodes.Const(42)]
         value = func.getattr("value")
@@ -778,74 +748,62 @@
         self.assertEqual(inferred.value, 42)
 
     def test_return_annotation_is_not_the_last(self) -> None:
-        func = builder.extract_node(
-            """
+        func = builder.extract_node("""
         def test() -> bytes:
             pass
             pass
             return
-        """
-        )
+        """)
         last_child = func.last_child()
         self.assertIsInstance(last_child, nodes.Return)
         self.assertEqual(func.tolineno, 5)
 
     def test_method_init_subclass(self) -> None:
-        klass = builder.extract_node(
-            """
+        klass = builder.extract_node("""
         class MyClass:
             def __init_subclass__(cls):
                 pass
-        """
-        )
+        """)
         method = klass["__init_subclass__"]
         self.assertEqual([n.name for n in method.args.args], ["cls"])
         self.assertEqual(method.type, "classmethod")
 
     def test_dunder_class_local_to_method(self) -> None:
-        node = builder.extract_node(
-            """
+        node = builder.extract_node("""
         class MyClass:
             def test(self):
                 __class__ #@
-        """
-        )
+        """)
         inferred = next(node.infer())
         self.assertIsInstance(inferred, nodes.ClassDef)
         self.assertEqual(inferred.name, "MyClass")
 
     def test_dunder_class_local_to_function(self) -> None:
-        node = builder.extract_node(
-            """
+        node = builder.extract_node("""
         def test(self):
             __class__ #@
-        """
-        )
+        """)
         with self.assertRaises(NameInferenceError):
             next(node.infer())
 
     def test_dunder_class_local_to_classmethod(self) -> None:
-        node = builder.extract_node(
-            """
+        node = builder.extract_node("""
         class MyClass:
             @classmethod
             def test(cls):
                 __class__ #@
-        """
-        )
+        """)
         inferred = next(node.infer())
         self.assertIsInstance(inferred, nodes.ClassDef)
         self.assertEqual(inferred.name, "MyClass")
 
     @staticmethod
     def test_singleline_docstring() -> None:
-        code = textwrap.dedent(
-            """\
+        code = textwrap.dedent("""\
             def foo():
                 '''Hello World'''
                 bar = 1
-        """
-        )
+        """)
         func: nodes.FunctionDef = builder.extract_node(code)  # type: ignore[assignment]
 
         assert isinstance(func.doc_node, nodes.Const)
@@ -856,16 +814,14 @@
 
     @staticmethod
     def test_multiline_docstring() -> None:
-        code = textwrap.dedent(
-            """\
+        code = textwrap.dedent("""\
             def foo():
                 '''Hello World
 
                 Also on this line.
                 '''
                 bar = 1
-        """
-        )
+        """)
         func: nodes.FunctionDef = builder.extract_node(code)  # type: ignore[assignment]
 
         assert isinstance(func.doc_node, nodes.Const)
@@ -876,15 +832,13 @@
 
     @staticmethod
     def test_multiline_docstring_async() -> None:
-        code = textwrap.dedent(
-            """\
+        code = textwrap.dedent("""\
             async def foo(var: tuple = ()):
                 '''Hello
 
                 World
                 '''
-        """
-        )
+        """)
         func: nodes.FunctionDef = builder.extract_node(code)  # type: ignore[assignment]
 
         assert isinstance(func.doc_node, nodes.Const)
@@ -895,8 +849,7 @@
 
     @staticmethod
     def test_docstring_special_cases() -> None:
-        code = textwrap.dedent(
-            """\
+        code = textwrap.dedent("""\
         def f1(var: tuple = ()):  #@
             'Hello World'
 
@@ -909,8 +862,7 @@
         def f4():  #@
             # It should work with comments too
             'Hello World'
-        """
-        )
+        """)
         ast_nodes: list[nodes.FunctionDef] = builder.extract_node(code)  # type: ignore[assignment]
         assert len(ast_nodes) == 4
 
@@ -940,48 +892,78 @@
 
     @staticmethod
     def test_without_docstring() -> None:
-        code = textwrap.dedent(
-            """\
+        code = textwrap.dedent("""\
             def foo():
                 bar = 1
-        """
-        )
+        """)
         func: nodes.FunctionDef = builder.extract_node(code)  # type: ignore[assignment]
         assert func.doc_node is None
 
     @staticmethod
     def test_display_type() -> None:
-        code = textwrap.dedent(
-            """\
+        code = textwrap.dedent("""\
             def foo():
                 bar = 1
-        """
-        )
+        """)
         func: nodes.FunctionDef = builder.extract_node(code)  # type: ignore[assignment]
         assert func.display_type() == "Function"
 
-        code = textwrap.dedent(
-            """\
+        code = textwrap.dedent("""\
             class A:
                 def foo(self):  #@
                     bar = 1
-        """
-        )
+        """)
         func: nodes.FunctionDef = builder.extract_node(code)  # type: ignore[assignment]
         assert func.display_type() == "Method"
 
     @staticmethod
     def test_inference_error() -> None:
-        code = textwrap.dedent(
-            """\
+        code = textwrap.dedent("""\
             def foo():
                 bar = 1
-        """
-        )
+        """)
         func: nodes.FunctionDef = builder.extract_node(code)  # type: ignore[assignment]
         with pytest.raises(AttributeInferenceError):
             func.getattr("")
 
+    @staticmethod
+    def test_blockstart_tolineno() -> None:
+        code = textwrap.dedent("""\
+        def f1(bar: str) -> None:  #@
+            pass
+
+        def f2(  #@
+               bar: str) -> None:
+            pass
+
+        def f3(  #@
+            bar: str
+        ) -> None:
+            pass
+
+        def f4(  #@
+            bar: str
+        ):
+            pass
+
+        def f5(  #@
+               bar: str):
+            pass
+        """)
+        ast_nodes: list[nodes.FunctionDef] = builder.extract_node(code)  # type: ignore[assignment]
+        assert len(ast_nodes) == 5
+
+        assert ast_nodes[0].blockstart_tolineno == 1
+
+        assert ast_nodes[1].blockstart_tolineno == 5
+
+        assert ast_nodes[2].blockstart_tolineno == 10
+
+        # Unimplemented, will return line 14 for now.
+        # assert ast_nodes[3].blockstart_tolineno == 15
+
+        assert ast_nodes[4].blockstart_tolineno == 19
+
 
 class ClassNodeTest(ModuleLoader, unittest.TestCase):
     def test_dict_interface(self) -> None:
@@ -1016,27 +998,23 @@
             self.assertEqual(len(cls.getattr("__mro__")), 1)
 
     def test__mro__attribute(self) -> None:
-        node = builder.extract_node(
-            """
+        node = builder.extract_node("""
         class A(object): pass
         class B(object): pass
         class C(A, B): pass
-        """
-        )
+        """)
         assert isinstance(node, nodes.ClassDef)
         mro = node.getattr("__mro__")[0]
         self.assertIsInstance(mro, nodes.Tuple)
         self.assertEqual(mro.elts, node.mro())
 
     def test__bases__attribute(self) -> None:
-        node = builder.extract_node(
-            """
+        node = builder.extract_node("""
         class A(object): pass
         class B(object): pass
         class C(A, B): pass
         class D(C): pass
-        """
-        )
+        """)
         assert isinstance(node, nodes.ClassDef)
         bases = node.getattr("__bases__")[0]
         self.assertIsInstance(bases, nodes.Tuple)
@@ -1078,8 +1056,7 @@
         self.assertEqual(r_sibling.name, "YOUPI")
 
     def test_local_attr_ancestors(self) -> None:
-        module = builder.parse(
-            """
+        module = builder.parse("""
         class A():
             def __init__(self): pass
         class B(A): pass
@@ -1087,8 +1064,7 @@
         class D(object): pass
         class F(): pass
         class E(F, D): pass
-        """
-        )
+        """)
         # Test old-style (Python 2) / new-style (Python 3+) ancestors lookups
         klass2 = module["C"]
         it = klass2.local_attr_ancestors("__init__")
@@ -1112,16 +1088,14 @@
         self.assertRaises(StopIteration, partial(next, it))
 
     def test_local_attr_mro(self) -> None:
-        module = builder.parse(
-            """
+        module = builder.parse("""
         class A(object):
             def __init__(self): pass
         class B(A):
             def __init__(self, arg, arg2): pass
         class C(A): pass
         class D(C, B): pass
-        """
-        )
+        """)
         dclass = module["D"]
         init = dclass.local_attr("__init__")[0]
         self.assertIsInstance(init, nodes.FunctionDef)
@@ -1353,46 +1327,39 @@
         self.assertEqual(astroid["g2"].tolineno, 11)
 
     def test_metaclass_error(self) -> None:
-        astroid = builder.parse(
-            """
+        astroid = builder.parse("""
             class Test(object):
                 __metaclass__ = typ
-        """
-        )
+        """)
         klass = astroid["Test"]
         self.assertFalse(klass.metaclass())
 
     def test_metaclass_yes_leak(self) -> None:
-        astroid = builder.parse(
-            """
+        astroid = builder.parse("""
             # notice `ab` instead of `abc`
             from ab import ABCMeta
 
             class Meta(object):
                 __metaclass__ = ABCMeta
-        """
-        )
+        """)
         klass = astroid["Meta"]
         self.assertIsNone(klass.metaclass())
 
     def test_metaclass_type(self) -> None:
-        klass = builder.extract_node(
-            """
+        klass = builder.extract_node("""
             def with_metaclass(meta, base=object):
                 return meta("NewBase", (base, ), {})
 
             class ClassWithMeta(with_metaclass(type)): #@
                 pass
-        """
-        )
+        """)
         assert isinstance(klass, nodes.ClassDef)
         self.assertEqual(
             ["NewBase", "object"], [base.name for base in klass.ancestors()]
         )
 
     def test_no_infinite_metaclass_loop(self) -> None:
-        klass = builder.extract_node(
-            """
+        klass = builder.extract_node("""
             class SSS(object):
 
                 class JJJ(object):
@@ -1407,8 +1374,7 @@
 
             class BBB(AAA.JJJ):
                 pass
-        """
-        )
+        """)
         assert isinstance(klass, nodes.ClassDef)
         self.assertFalse(_is_metaclass(klass))
         ancestors = [base.name for base in klass.ancestors()]
@@ -1416,8 +1382,7 @@
         self.assertIn("JJJ", ancestors)
 
     def test_no_infinite_metaclass_loop_with_redefine(self) -> None:
-        ast_nodes = builder.extract_node(
-            """
+        ast_nodes = builder.extract_node("""
             import datetime
 
             class A(datetime.date): #@
@@ -1430,21 +1395,18 @@
 
             datetime.date = A
             datetime.date = B
-        """
-        )
+        """)
         for klass in ast_nodes:
             self.assertEqual(None, klass.metaclass())
 
     @unittest.skipUnless(HAS_SIX, "These tests require the six library")
     def test_metaclass_generator_hack(self):
-        klass = builder.extract_node(
-            """
+        klass = builder.extract_node("""
             import six
 
             class WithMeta(six.with_metaclass(type, object)): #@
                 pass
-        """
-        )
+        """)
         assert isinstance(klass, nodes.ClassDef)
         self.assertEqual(["object"], [base.name for base in klass.ancestors()])
         self.assertEqual("type", klass.metaclass().name)
@@ -1452,26 +1414,22 @@
     @unittest.skipUnless(HAS_SIX, "These tests require the six library")
     def test_metaclass_generator_hack_enum_base(self):
         """Regression test for https://github.com/pylint-dev/pylint/issues/5935"""
-        klass = builder.extract_node(
-            """
+        klass = builder.extract_node("""
             import six
             from enum import Enum, EnumMeta
 
             class PetEnumPy2Metaclass(six.with_metaclass(EnumMeta, Enum)): #@
                 DOG = "dog"
-        """
-        )
+        """)
         self.assertEqual(list(klass.local_attr_ancestors("DOG")), [])
 
     def test_add_metaclass(self) -> None:
-        klass = builder.extract_node(
-            """
+        klass = builder.extract_node("""
         import abc
 
         class WithMeta(object, metaclass=abc.ABCMeta):
             pass
-        """
-        )
+        """)
         assert isinstance(klass, nodes.ClassDef)
         inferred = next(klass.infer())
         metaclass = inferred.metaclass()
@@ -1480,34 +1438,29 @@
 
     @unittest.skipUnless(HAS_SIX, "These tests require the six library")
     def test_using_invalid_six_add_metaclass_call(self):
-        klass = builder.extract_node(
-            """
+        klass = builder.extract_node("""
         import six
         @six.add_metaclass()
         class Invalid(object):
             pass
-        """
-        )
+        """)
         inferred = next(klass.infer())
         self.assertIsNone(inferred.metaclass())
 
     @staticmethod
     def test_with_invalid_metaclass():
-        klass = extract_node(
-            """
+        klass = extract_node("""
         class InvalidAsMetaclass: ...
 
         class Invalid(metaclass=InvalidAsMetaclass()):  #@
             pass
-        """
-        )
+        """)
         inferred = next(klass.infer())
         metaclass = inferred.metaclass()
         assert isinstance(metaclass, Instance)
 
     def test_nonregr_infer_callresult(self) -> None:
-        astroid = builder.parse(
-            """
+        astroid = builder.parse("""
             class Delegate(object):
                 def __get__(self, obj, cls):
                     return getattr(obj._subject, self.attribute)
@@ -1517,16 +1470,14 @@
 
             builder = CompositeBuilder(result, composite)
             tgts = builder()
-        """
-        )
+        """)
         instance = astroid["tgts"]
         # used to raise "'_Yes' object is not iterable", see
         # https://bitbucket.org/logilab/astroid/issue/17
         self.assertEqual(list(instance.infer()), [util.Uninferable])
 
     def test_slots(self) -> None:
-        astroid = builder.parse(
-            """
+        astroid = builder.parse("""
             from collections import deque
             from textwrap import dedent
 
@@ -1550,8 +1501,7 @@
                 pass
             class Ten(object): #@
                 __slots__ = dict({"a": "b", "c": "d"})
-        """
-        )
+        """)
         expected = [
             ("First", ("a", "b")),
             ("Second", ("a",)),
@@ -1572,13 +1522,11 @@
                 self.assertEqual(list(expected_value), [node.value for node in slots])
 
     def test_slots_for_dict_keys(self) -> None:
-        module = builder.parse(
-            """
+        module = builder.parse("""
         class Issue(object):
           SlotDefaults = {'id': 0, 'id1':1}
           __slots__ = SlotDefaults.keys()
-        """
-        )
+        """)
         cls = module["Issue"]
         slots = cls.slots()
         self.assertEqual(len(slots), 2)
@@ -1586,26 +1534,22 @@
         self.assertEqual(slots[1].value, "id1")
 
     def test_slots_empty_list_of_slots(self) -> None:
-        module = builder.parse(
-            """
+        module = builder.parse("""
         class Klass(object):
             __slots__ = ()
-        """
-        )
+        """)
         cls = module["Klass"]
         self.assertEqual(cls.slots(), [])
 
     def test_slots_taken_from_parents(self) -> None:
-        module = builder.parse(
-            """
+        module = builder.parse("""
         class FirstParent(object):
             __slots__ = ('a', 'b', 'c')
         class SecondParent(FirstParent):
             __slots__ = ('d', 'e')
         class Third(SecondParent):
             __slots__ = ('d', )
-        """
-        )
+        """)
         cls = module["Third"]
         slots = cls.slots()
         self.assertEqual(
@@ -1613,15 +1557,13 @@
         )
 
     def test_all_ancestors_need_slots(self) -> None:
-        module = builder.parse(
-            """
+        module = builder.parse("""
         class A(object):
             __slots__ = ('a', )
         class B(A): pass
         class C(B):
             __slots__ = ('a', )
-        """
-        )
+        """)
         cls = module["C"]
         self.assertIsNone(cls.slots())
         cls = module["B"]
@@ -1652,8 +1594,7 @@
 
     @unittest.skipUnless(HAS_SIX, "These tests require the six library")
     def test_with_metaclass_mro(self):
-        astroid = builder.parse(
-            """
+        astroid = builder.parse("""
         import six
 
         class C(object):
@@ -1662,13 +1603,11 @@
             pass
         class A(six.with_metaclass(type, B)):
             pass
-        """
-        )
+        """)
         self.assertEqualMro(astroid["A"], ["A", "B", "C", "object"])
 
     def test_mro(self) -> None:
-        astroid = builder.parse(
-            """
+        astroid = builder.parse("""
         class C(object): pass
         class D(dict, C): pass
 
@@ -1703,8 +1642,7 @@
                 pass
         class Duplicates(str, str): pass
 
-        """
-        )
+        """)
         self.assertEqualMro(astroid["D"], ["D", "dict", "C", "object"])
         self.assertEqualMro(astroid["D1"], ["D1", "B1", "C1", "A1", "object"])
         self.assertEqualMro(astroid["E1"], ["E1", "C1", "B1", "A1", "object"])
@@ -1758,9 +1696,31 @@
         self.assertIsInstance(cm.exception, MroError)
         self.assertIsInstance(cm.exception, ResolveError)
 
+    def test_mro_circular_name_rebinding(self) -> None:
+        """MRO computation should handle circular name rebinding.
+
+        When a module-level name is rebound to a subclass of itself,
+        _infer_last follows the rebinding and returns the subclass.
+        The MRO computation should resolve the cycle by falling back
+        to the original class.
+
+        Regression test for https://github.com/pylint-dev/astroid/issues/2967
+        """
+        astroid = builder.parse("""
+        import pdb
+
+        class CustomPdb(pdb.Pdb):
+            pass
+
+        pdb.Pdb = CustomPdb
+        """)
+        self.assertEqualMro(
+            astroid["CustomPdb"],
+            ["CustomPdb", "Pdb", "Bdb", "Cmd", "object"],
+        )
+
     def test_mro_with_factories(self) -> None:
-        cls = builder.extract_node(
-            """
+        cls = builder.extract_node("""
         def MixinFactory(cls):
             mixin_name = '{}Mixin'.format(cls.__name__)
             mixin_bases = (object,)
@@ -1780,8 +1740,7 @@
         class FinalClass(ClassB):
             def __init__(self):
                 self.name = 'x'
-        """
-        )
+        """)
         assert isinstance(cls, nodes.ClassDef)
         self.assertEqualMro(
             cls,
@@ -1799,8 +1758,7 @@
         )
 
     def test_mro_with_attribute_classes(self) -> None:
-        cls = builder.extract_node(
-            """
+        cls = builder.extract_node("""
         class A:
             pass
         class B:
@@ -1812,107 +1770,93 @@
         scope.B = B
         class C(scope.A, scope.B):
             pass
-        """
-        )
+        """)
         assert isinstance(cls, nodes.ClassDef)
         self.assertEqualMro(cls, ["C", "A", "B", "object"])
 
     def test_mro_generic_1(self):
-        cls = builder.extract_node(
-            """
+        cls = builder.extract_node("""
         import typing
         T = typing.TypeVar('T')
         class A(typing.Generic[T]): ...
         class B: ...
         class C(A[T], B): ...
-        """
-        )
+        """)
         assert isinstance(cls, nodes.ClassDef)
         self.assertEqualMroQName(
             cls, [".C", ".A", "typing.Generic", ".B", "builtins.object"]
         )
 
     def test_mro_generic_2(self):
-        cls = builder.extract_node(
-            """
+        cls = builder.extract_node("""
         from typing import Generic, TypeVar
         T = TypeVar('T')
         class A: ...
         class B(Generic[T]): ...
         class C(Generic[T], A, B[T]): ...
-        """
-        )
+        """)
         assert isinstance(cls, nodes.ClassDef)
         self.assertEqualMroQName(
             cls, [".C", ".A", ".B", "typing.Generic", "builtins.object"]
         )
 
     def test_mro_generic_3(self):
-        cls = builder.extract_node(
-            """
+        cls = builder.extract_node("""
         from typing import Generic, TypeVar
         T = TypeVar('T')
         class A: ...
         class B(A, Generic[T]): ...
         class C(Generic[T]): ...
         class D(B[T], C[T], Generic[T]): ...
-        """
-        )
+        """)
         assert isinstance(cls, nodes.ClassDef)
         self.assertEqualMroQName(
             cls, [".D", ".B", ".A", ".C", "typing.Generic", "builtins.object"]
         )
 
     def test_mro_generic_4(self):
-        cls = builder.extract_node(
-            """
+        cls = builder.extract_node("""
         from typing import Generic, TypeVar
         T = TypeVar('T')
         class A: ...
         class B(Generic[T]): ...
         class C(A, Generic[T], B[T]): ...
-        """
-        )
+        """)
         assert isinstance(cls, nodes.ClassDef)
         self.assertEqualMroQName(
             cls, [".C", ".A", ".B", "typing.Generic", "builtins.object"]
         )
 
     def test_mro_generic_5(self):
-        cls = builder.extract_node(
-            """
+        cls = builder.extract_node("""
         from typing import Generic, TypeVar
         T1 = TypeVar('T1')
         T2 = TypeVar('T2')
         class A(Generic[T1]): ...
         class B(Generic[T2]): ...
         class C(A[T1], B[T2]): ...
-        """
-        )
+        """)
         assert isinstance(cls, nodes.ClassDef)
         self.assertEqualMroQName(
             cls, [".C", ".A", ".B", "typing.Generic", "builtins.object"]
         )
 
     def test_mro_generic_6(self):
-        cls = builder.extract_node(
-            """
+        cls = builder.extract_node("""
         from typing import Generic as TGeneric, TypeVar
         T = TypeVar('T')
         class Generic: ...
         class A(Generic): ...
         class B(TGeneric[T]): ...
         class C(A, B[T]): ...
-        """
-        )
+        """)
         assert isinstance(cls, nodes.ClassDef)
         self.assertEqualMroQName(
             cls, [".C", ".A", ".Generic", ".B", "typing.Generic", "builtins.object"]
         )
 
     def test_mro_generic_7(self):
-        cls = builder.extract_node(
-            """
+        cls = builder.extract_node("""
         from typing import Generic, TypeVar
         T = TypeVar('T')
         class A(): ...
@@ -1920,35 +1864,54 @@
         class C(A, B[T]): ...
         class D: ...
         class E(C[str], D): ...
-        """
-        )
+        """)
         assert isinstance(cls, nodes.ClassDef)
         self.assertEqualMroQName(
             cls, [".E", ".C", ".A", ".B", "typing.Generic", ".D", "builtins.object"]
         )
 
+    @pytest.mark.skipif(not PY312_PLUS, reason="PEP 695 syntax requires Python 3.12")
+    def test_mro_generic_8(self):
+        cls = builder.extract_node("""
+        class A: ...
+        class B[T]: ...
+        class C[T](A, B[T]): ...
+        """)
+        assert isinstance(cls, nodes.ClassDef)
+        self.assertEqualMroQName(cls, [".C", ".A", ".B", "builtins.object"])
+
+    @pytest.mark.skipif(not PY312_PLUS, reason="PEP 695 syntax requires Python 3.12")
+    def test_mro_generic_9(self):
+        cls = builder.extract_node("""
+        from dataclasses import dataclass
+        @dataclass
+        class A: ...
+        @dataclass
+        class B[T]: ...
+        @dataclass
+        class C[T](A, B[T]): ...
+        """)
+        assert isinstance(cls, nodes.ClassDef)
+        self.assertEqualMroQName(cls, [".C", ".A", ".B", "builtins.object"])
+
     def test_mro_generic_error_1(self):
-        cls = builder.extract_node(
-            """
+        cls = builder.extract_node("""
         from typing import Generic, TypeVar
         T1 = TypeVar('T1')
         T2 = TypeVar('T2')
         class A(Generic[T1], Generic[T2]): ...
-        """
-        )
+        """)
         assert isinstance(cls, nodes.ClassDef)
         with self.assertRaises(DuplicateBasesError):
             cls.mro()
 
     def test_mro_generic_error_2(self):
-        cls = builder.extract_node(
-            """
+        cls = builder.extract_node("""
         from typing import Generic, TypeVar
         T = TypeVar('T')
         class A(Generic[T]): ...
         class B(A[T], A[T]): ...
-        """
-        )
+        """)
         assert isinstance(cls, nodes.ClassDef)
         with self.assertRaises(DuplicateBasesError):
             cls.mro()
@@ -1959,8 +1922,7 @@
         Regression reported in:
         https://github.com/pylint-dev/astroid/issues/1124
         """
-        module = parse(
-            """
+        module = parse("""
         import abc
         import typing
         import dataclasses
@@ -1972,8 +1934,7 @@
         class EarlyBase(typing.Generic[T], MyProtocol): pass
         class Base(EarlyBase[T], abc.ABC): pass
         class Final(Base[object]): pass
-        """
-        )
+        """)
         class_names = [
             "ABC",
             "Base",
@@ -1988,26 +1949,22 @@
         self.assertEqual(class_names, sorted(i.name for i in final_def.mro()))
 
     def test_generator_from_infer_call_result_parent(self) -> None:
-        func = builder.extract_node(
-            """
+        func = builder.extract_node("""
         import contextlib
 
         @contextlib.contextmanager
         def test(): #@
             yield
-        """
-        )
+        """)
         assert isinstance(func, nodes.FunctionDef)
         result = next(func.infer_call_result(None))
         self.assertIsInstance(result, Generator)
         self.assertEqual(result.parent, func)
 
     def test_type_three_arguments(self) -> None:
-        classes = builder.extract_node(
-            """
+        classes = builder.extract_node("""
         type('A', (object, ), {"a": 1, "b": 2, missing: 3}) #@
-        """
-        )
+        """)
         assert isinstance(classes, nodes.Call)
         first = next(classes.infer())
         self.assertIsInstance(first, nodes.ClassDef)
@@ -2021,23 +1978,19 @@
             first.getattr("missing")
 
     def test_implicit_metaclass(self) -> None:
-        cls = builder.extract_node(
-            """
+        cls = builder.extract_node("""
         class A(object):
             pass
-        """
-        )
+        """)
         assert isinstance(cls, nodes.ClassDef)
         type_cls = nodes.builtin_lookup("type")[1][0]
         self.assertEqual(cls.implicit_metaclass(), type_cls)
 
     def test_implicit_metaclass_lookup(self) -> None:
-        cls = builder.extract_node(
-            """
+        cls = builder.extract_node("""
         class A(object):
             pass
-        """
-        )
+        """)
         assert isinstance(cls, nodes.ClassDef)
         instance = cls.instantiate_class()
         func = cls.getattr("mro")
@@ -2046,29 +1999,24 @@
 
     def test_metaclass_lookup_using_same_class(self) -> None:
         """Check that we don't have recursive attribute access for metaclass."""
-        cls = builder.extract_node(
-            """
+        cls = builder.extract_node("""
         class A(object): pass
-        """
-        )
+        """)
         assert isinstance(cls, nodes.ClassDef)
         self.assertEqual(len(cls.getattr("mro")), 1)
 
     def test_metaclass_lookup_inference_errors(self) -> None:
-        module = builder.parse(
-            """
+        module = builder.parse("""
         class Metaclass(type):
             foo = lala
 
         class B(object, metaclass=Metaclass): pass
-        """
-        )
+        """)
         cls = module["B"]
         self.assertEqual(util.Uninferable, next(cls.igetattr("foo")))
 
     def test_metaclass_lookup(self) -> None:
-        module = builder.parse(
-            """
+        module = builder.parse("""
         class Metaclass(type):
             foo = 42
             @classmethod
@@ -2085,8 +2033,7 @@
 
         class A(object, metaclass=Metaclass):
             pass
-        """
-        )
+        """)
         acls = module["A"]
         normal_attr = next(acls.igetattr("foo"))
         self.assertIsInstance(normal_attr, nodes.Const)
@@ -2117,16 +2064,14 @@
         self.assertIsInstance(static, nodes.FunctionDef)
 
     def test_local_attr_invalid_mro(self) -> None:
-        cls = builder.extract_node(
-            """
+        cls = builder.extract_node("""
         # A has an invalid MRO, local_attr should fallback
         # to using .ancestors.
         class A(object, object):
             test = 42
         class B(A): #@
             pass
-        """
-        )
+        """)
         assert isinstance(cls, nodes.ClassDef)
         local = cls.local_attr("test")[0]
         inferred = next(local.infer())
@@ -2134,8 +2079,7 @@
         self.assertEqual(inferred.value, 42)
 
     def test_has_dynamic_getattr(self) -> None:
-        module = builder.parse(
-            """
+        module = builder.parse("""
         class Getattr(object):
             def __getattr__(self, attrname):
                 pass
@@ -2146,8 +2090,7 @@
 
         class ParentGetattr(Getattr):
             pass
-        """
-        )
+        """)
         self.assertTrue(module["Getattr"].has_dynamic_getattr())
         self.assertTrue(module["Getattribute"].has_dynamic_getattr())
         self.assertTrue(module["ParentGetattr"].has_dynamic_getattr())
@@ -2159,30 +2102,26 @@
         self.assertFalse(module["SequenceMatcher"].has_dynamic_getattr())
 
     def test_duplicate_bases_namedtuple(self) -> None:
-        module = builder.parse(
-            """
+        module = builder.parse("""
         import collections
         _A = collections.namedtuple('A', 'a')
 
         class A(_A): pass
 
         class B(A): pass
-        """
-        )
+        """)
         names = ["B", "A", "A", "tuple", "object"]
         mro = module["B"].mro()
         class_names = [i.name for i in mro]
         self.assertEqual(names, class_names)
 
     def test_instance_bound_method_lambdas(self) -> None:
-        ast_nodes = builder.extract_node(
-            """
+        ast_nodes = builder.extract_node("""
         class Test(object): #@
             lam = lambda self: self
             not_method = lambda xargs: xargs
         Test() #@
-        """
-        )
+        """)
         assert isinstance(ast_nodes, list)
         cls = next(ast_nodes[0].infer())
         self.assertIsInstance(next(cls.igetattr("lam")), nodes.Lambda)
@@ -2199,8 +2138,7 @@
         Test the fact that a method which is a lambda built from
         a factory is well inferred as a bound method (bug pylint 2594).
         """
-        ast_nodes = builder.extract_node(
-            """
+        ast_nodes = builder.extract_node("""
         def lambda_factory():
             return lambda self: print("Hello world")
 
@@ -2208,8 +2146,7 @@
             f2 = lambda_factory()
 
         MyClass() #@
-        """
-        )
+        """)
         assert isinstance(ast_nodes, list)
         cls = next(ast_nodes[0].infer())
         self.assertIsInstance(next(cls.igetattr("f2")), nodes.Lambda)
@@ -2219,55 +2156,46 @@
         self.assertIsInstance(f2, BoundMethod)
 
     def test_class_extra_decorators_frame_is_not_class(self) -> None:
-        ast_node = builder.extract_node(
-            """
+        ast_node = builder.extract_node("""
         def ala():
             def bala(): #@
                 func = 42
-        """
-        )
+        """)
         assert isinstance(ast_node, nodes.FunctionDef)
         self.assertEqual(ast_node.extra_decorators, [])
 
     def test_class_extra_decorators_only_callfunc_are_considered(self) -> None:
-        ast_node = builder.extract_node(
-            """
+        ast_node = builder.extract_node("""
         class Ala(object):
              def func(self): #@
                  pass
              func = 42
-        """
-        )
+        """)
         self.assertEqual(ast_node.extra_decorators, [])
 
     def test_class_extra_decorators_only_assignment_names_are_considered(self) -> None:
-        ast_node = builder.extract_node(
-            """
+        ast_node = builder.extract_node("""
         class Ala(object):
              def func(self): #@
                  pass
              def __init__(self):
                  self.func = staticmethod(func)
 
-        """
-        )
+        """)
         self.assertEqual(ast_node.extra_decorators, [])
 
     def test_class_extra_decorators_only_same_name_considered(self) -> None:
-        ast_node = builder.extract_node(
-            """
+        ast_node = builder.extract_node("""
         class Ala(object):
              def func(self): #@
                 pass
              bala = staticmethod(func)
-        """
-        )
+        """)
         self.assertEqual(ast_node.extra_decorators, [])
         self.assertEqual(ast_node.type, "method")
 
     def test_class_extra_decorators(self) -> None:
-        static_method, clsmethod = builder.extract_node(
-            """
+        static_method, clsmethod = builder.extract_node("""
         class Ala(object):
              def static(self): #@
                  pass
@@ -2275,16 +2203,14 @@
                  pass
              class_method = classmethod(class_method)
              static = staticmethod(static)
-        """
-        )
+        """)
         self.assertEqual(len(clsmethod.extra_decorators), 1)
         self.assertEqual(clsmethod.type, "classmethod")
         self.assertEqual(len(static_method.extra_decorators), 1)
         self.assertEqual(static_method.type, "staticmethod")
 
     def test_extra_decorators_only_class_level_assignments(self) -> None:
-        node = builder.extract_node(
-            """
+        node = builder.extract_node("""
         def _bind(arg):
             return arg.bind
 
@@ -2298,8 +2224,7 @@
                 bind = _bind(self)
                 return bind
         A() #@
-        """
-        )
+        """)
         inferred = next(node.infer())
         bind = next(inferred.igetattr("bind"))
         self.assertIsInstance(bind, nodes.Const)
@@ -2343,13 +2268,11 @@
 
     @staticmethod
     def test_singleline_docstring() -> None:
-        code = textwrap.dedent(
-            """\
+        code = textwrap.dedent("""\
             class Foo:
                 '''Hello World'''
                 bar = 1
-        """
-        )
+        """)
         node: nodes.ClassDef = builder.extract_node(code)  # type: ignore[assignment]
         assert isinstance(node.doc_node, nodes.Const)
         assert node.doc_node.lineno == 2
@@ -2359,16 +2282,14 @@
 
     @staticmethod
     def test_multiline_docstring() -> None:
-        code = textwrap.dedent(
-            """\
+        code = textwrap.dedent("""\
             class Foo:
                 '''Hello World
 
                 Also on this line.
                 '''
                 bar = 1
-        """
-        )
+        """)
         node: nodes.ClassDef = builder.extract_node(code)  # type: ignore[assignment]
         assert isinstance(node.doc_node, nodes.Const)
         assert node.doc_node.lineno == 2
@@ -2378,19 +2299,16 @@
 
     @staticmethod
     def test_without_docstring() -> None:
-        code = textwrap.dedent(
-            """\
+        code = textwrap.dedent("""\
             class Foo:
                 bar = 1
-        """
-        )
+        """)
         node: nodes.ClassDef = builder.extract_node(code)  # type: ignore[assignment]
         assert node.doc_node is None
 
 
 def test_issue940_metaclass_subclass_property() -> None:
-    node = builder.extract_node(
-        """
+    node = builder.extract_node("""
     class BaseMeta(type):
         @property
         def __members__(cls):
@@ -2400,16 +2318,14 @@
     class Derived(Parent):
         pass
     Derived.__members__
-    """
-    )
+    """)
     inferred = next(node.infer())
     assert isinstance(inferred, nodes.List)
     assert [c.value for c in inferred.elts] == ["a", "property"]
 
 
 def test_issue940_property_grandchild() -> None:
-    node = builder.extract_node(
-        """
+    node = builder.extract_node("""
     class Grandparent:
         @property
         def __members__(self):
@@ -2419,16 +2335,14 @@
     class Child(Parent):
         pass
     Child().__members__
-    """
-    )
+    """)
     inferred = next(node.infer())
     assert isinstance(inferred, nodes.List)
     assert [c.value for c in inferred.elts] == ["a", "property"]
 
 
 def test_issue940_metaclass_property() -> None:
-    node = builder.extract_node(
-        """
+    node = builder.extract_node("""
     class BaseMeta(type):
         @property
         def __members__(cls):
@@ -2436,16 +2350,14 @@
     class Parent(metaclass=BaseMeta):
         pass
     Parent.__members__
-    """
-    )
+    """)
     inferred = next(node.infer())
     assert isinstance(inferred, nodes.List)
     assert [c.value for c in inferred.elts] == ["a", "property"]
 
 
 def test_issue940_with_metaclass_class_context_property() -> None:
-    node = builder.extract_node(
-        """
+    node = builder.extract_node("""
     class BaseMeta(type):
         pass
     class Parent(metaclass=BaseMeta):
@@ -2455,32 +2367,28 @@
     class Derived(Parent):
         pass
     Derived.__members__
-    """
-    )
+    """)
     inferred = next(node.infer())
     assert not isinstance(inferred, nodes.List)
     assert isinstance(inferred, objects.Property)
 
 
 def test_issue940_metaclass_values_funcdef() -> None:
-    node = builder.extract_node(
-        """
+    node = builder.extract_node("""
     class BaseMeta(type):
         def __members__(cls):
             return ['a', 'func']
     class Parent(metaclass=BaseMeta):
         pass
     Parent.__members__()
-    """
-    )
+    """)
     inferred = next(node.infer())
     assert isinstance(inferred, nodes.List)
     assert [c.value for c in inferred.elts] == ["a", "func"]
 
 
 def test_issue940_metaclass_derived_funcdef() -> None:
-    node = builder.extract_node(
-        """
+    node = builder.extract_node("""
     class BaseMeta(type):
         def __members__(cls):
             return ['a', 'func']
@@ -2489,16 +2397,14 @@
     class Derived(Parent):
         pass
     Derived.__members__()
-    """
-    )
+    """)
     inferred_result = next(node.infer())
     assert isinstance(inferred_result, nodes.List)
     assert [c.value for c in inferred_result.elts] == ["a", "func"]
 
 
 def test_issue940_metaclass_funcdef_is_not_datadescriptor() -> None:
-    node = builder.extract_node(
-        """
+    node = builder.extract_node("""
     class BaseMeta(type):
         def __members__(cls):
             return ['a', 'property']
@@ -2509,8 +2415,7 @@
     class Derived(Parent):
         pass
     Derived.__members__
-    """
-    )
+    """)
     # Here the function is defined on the metaclass, but the property
     # is defined on the base class. When loading the attribute in a
     # class context, this should return the property object instead of
@@ -2521,8 +2426,7 @@
 
 def test_property_in_body_of_try() -> None:
     """Regression test for https://github.com/pylint-dev/pylint/issues/6596."""
-    node: nodes.Return = builder._extract_single_node(
-        """
+    node: nodes.Return = builder._extract_single_node("""
     def myfunc():
         try:
 
@@ -2538,14 +2442,12 @@
             pass
 
         return myfunc() #@
-    """
-    )
+    """)
     next(node.value.infer())
 
 
 def test_property_in_body_of_if() -> None:
-    node: nodes.Return = builder._extract_single_node(
-        """
+    node: nodes.Return = builder._extract_single_node("""
     def myfunc():
         if True:
 
@@ -2558,21 +2460,18 @@
             pass
 
         return myfunc() #@
-    """
-    )
+    """)
     next(node.value.infer())
 
 
 def test_issue940_enums_as_a_real_world_usecase() -> None:
-    node = builder.extract_node(
-        """
+    node = builder.extract_node("""
     from enum import Enum
     class Sounds(Enum):
         bee = "buzz"
         cat = "meow"
     Sounds.__members__
-    """
-    )
+    """)
     inferred_result = next(node.infer())
     assert isinstance(inferred_result, nodes.Dict)
     actual = [k.value for k, _ in inferred_result.items]
@@ -2585,15 +2484,13 @@
     - `member.value.value` is of type `str`
     is inferred as: `repr(member.value.value)`
     """
-    node = builder.extract_node(
-        """
+    node = builder.extract_node("""
     from enum import Enum
     class Veg(Enum):
         TOMATO: str = "sweet"
 
     Veg.TOMATO.value
-    """
-    )
+    """)
     inferred_member_value = node.inferred()[0]
     assert isinstance(inferred_member_value, nodes.Const)
     assert inferred_member_value.value == "sweet"
@@ -2605,30 +2502,26 @@
     - `member.value.value` is `None`
     is not inferred
     """
-    node = builder.extract_node(
-        """
+    node = builder.extract_node("""
     from enum import Enum
     class Veg(Enum):
         TOMATO: {annotation}
 
     Veg.TOMATO.value
-    """
-    )
+    """)
     inferred_member_value = node.inferred()[0]
     assert inferred_member_value.value is None
 
 
 def test_enums_value2member_map_() -> None:
     """Check the `_value2member_map_` member is present in an Enum class."""
-    node = builder.extract_node(
-        """
+    node = builder.extract_node("""
     from enum import Enum
     class Veg(Enum):
         TOMATO: 1
 
     Veg
-    """
-    )
+    """)
     inferred_class = node.inferred()[0]
     assert "_value2member_map_" in inferred_class.locals
 
@@ -2641,15 +2534,13 @@
     is inferred as: `member.value.value`
     """
 
-    node = builder.extract_node(
-        f"""
+    node = builder.extract_node(f"""
     from enum import Enum
     class Veg(Enum):
         TOMATO: {annotation} = {value}
 
     Veg.TOMATO.value
-    """
-    )
+    """)
     inferred_member_value = node.inferred()[0]
     assert isinstance(inferred_member_value, nodes.Const)
     assert inferred_member_value.value == value
@@ -2669,16 +2560,14 @@
     is inferred as: `member.value.as_string()`.
     """
 
-    member = builder.extract_node(
-        f"""
+    member = builder.extract_node(f"""
     from enum import Enum
 
     class Veg(Enum):
         TOMATO: {annotation} = {value}
 
     Veg.TOMATO.value
-    """
-    )
+    """)
 
     inferred_member_value = member.inferred()[0]
     assert not isinstance(inferred_member_value, nodes.Const)
@@ -2686,16 +2575,14 @@
 
 
 def test_metaclass_cannot_infer_call_yields_an_instance() -> None:
-    node = builder.extract_node(
-        """
+    node = builder.extract_node("""
     from undefined import Undefined
     class Meta(type):
         __call__ = Undefined
     class A(metaclass=Meta):
         pass
     A()
-    """
-    )
+    """)
     inferred = next(node.infer())
     assert isinstance(inferred, Instance)
 
@@ -2703,48 +2590,34 @@
 @pytest.mark.parametrize(
     "func",
     [
-        textwrap.dedent(
-            """
+        textwrap.dedent("""
     def func(a, b, /, d, e):
         pass
-    """
-        ),
-        textwrap.dedent(
-            """
+    """),
+        textwrap.dedent("""
     def func(a, b=None, /, d=None, e=None):
         pass
-    """
-        ),
-        textwrap.dedent(
-            """
+    """),
+        textwrap.dedent("""
     def func(a, other, other, b=None, /, d=None, e=None):
         pass
-    """
-        ),
-        textwrap.dedent(
-            """
+    """),
+        textwrap.dedent("""
     def func(a, other, other, b=None, /, d=None, e=None, **kwargs):
         pass
-    """
-        ),
-        textwrap.dedent(
-            """
+    """),
+        textwrap.dedent("""
     def name(p1, p2, /, p_or_kw, *, kw):
         pass
-    """
-        ),
-        textwrap.dedent(
-            """
+    """),
+        textwrap.dedent("""
     def __init__(self, other=(), /, **kw):
         pass
-    """
-        ),
-        textwrap.dedent(
-            """
+    """),
+        textwrap.dedent("""
     def __init__(self: int, other: float, /, **kw):
         pass
-    """
-        ),
+    """),
     ],
 )
 def test_posonlyargs_python_38(func):
@@ -2753,11 +2626,9 @@
 
 
 def test_posonlyargs_default_value() -> None:
-    ast_node = builder.extract_node(
-        """
+    ast_node = builder.extract_node("""
     def func(a, b=1, /, c=2): pass
-    """
-    )
+    """)
     last_param = ast_node.args.default_value("c")
     assert isinstance(last_param, nodes.Const)
     assert last_param.value == 2
@@ -2769,8 +2640,7 @@
 
 def test_ancestor_with_generic() -> None:
     # https://github.com/pylint-dev/astroid/issues/942
-    tree = builder.parse(
-        """
+    tree = builder.parse("""
     from typing import TypeVar, Generic
     T = TypeVar("T")
     class A(Generic[T]):
@@ -2778,8 +2648,7 @@
             print("hello")
     class B(A[T]): pass
     class C(B[str]): pass
-    """
-    )
+    """)
     inferred_b = next(tree["B"].infer())
     assert [cdef.name for cdef in inferred_b.ancestors()] == ["A", "Generic", "object"]
 
@@ -2793,22 +2662,42 @@
 
 
 def test_slots_duplicate_bases_issue_1089() -> None:
-    astroid = builder.parse(
-        """
+    astroid = builder.parse("""
             class First(object, object): #@
                 pass
-        """
-    )
+        """)
     with pytest.raises(NotImplementedError):
         astroid["First"].slots()
 
 
+def test_import_with_global() -> None:
+    code = builder.parse("""
+    def f1():
+        global platform
+        from sys import platform as plat
+        platform = plat
+
+    def f2():
+        global os, RE, deque, VERSION, Path
+        import os
+        import re as RE
+        from collections import deque
+        from sys import version as VERSION
+        from pathlib import *
+    """)
+    assert "platform" in code.locals
+    assert "os" in code.locals
+    assert "RE" in code.locals
+    assert "deque" in code.locals
+    assert "VERSION" in code.locals
+    assert "Path" in code.locals
+
+
 class TestFrameNodes:
     @staticmethod
     def test_frame_node():
         """Test if the frame of FunctionDef, ClassDef and Module is correctly set."""
-        module = builder.parse(
-            """
+        module = builder.parse("""
             def func():
                 var_1 = x
                 return var_1
@@ -2821,8 +2710,7 @@
                     pass
 
             VAR = lambda y = (named_expr := "walrus"): print(y)
-        """
-        )
+        """)
         function = module.body[0]
         assert function.frame() == function
         assert function.frame() == function
@@ -2845,15 +2733,44 @@
         assert module.frame() == module
 
     @staticmethod
+    def test_frame_node_for_decorators():
+        code = builder.extract_node("""
+            def deco(var):
+                def inner(arg):
+                    ...
+                return inner
+
+            @deco(
+                x := 1  #@
+            )
+            def func():  #@
+                ...
+
+            @deco(
+                y := 2  #@
+            )
+            class A:  #@
+                ...
+        """)
+        name_expr_node1, func_node, name_expr_node2, class_node = code
+        module = func_node.root()
+        assert name_expr_node1.scope() == module
+        assert name_expr_node1.frame() == module
+        assert name_expr_node2.scope() == module
+        assert name_expr_node2.frame() == module
+        assert module.locals.get("x") == [name_expr_node1.target]
+        assert module.locals.get("y") == [name_expr_node2.target]
+        assert "x" not in func_node.locals
+        assert "y" not in class_node.locals
+
+    @staticmethod
     def test_non_frame_node():
         """Test if the frame of non frame nodes is set correctly."""
-        module = builder.parse(
-            """
+        module = builder.parse("""
             VAR_ONE = 1
 
             VAR_TWO = [x for x in range(1)]
-        """
-        )
+        """)
         assert module.body[0].frame() == module
         assert module.body[0].frame() == module
 
diff --git a/tests/test_stdlib.py b/tests/test_stdlib.py
index 4027faa..d97fc86 100644
--- a/tests/test_stdlib.py
+++ b/tests/test_stdlib.py
@@ -13,12 +13,10 @@
 
     def test_sys_builtin_module_names(self) -> None:
         """Test that we can gather the elements of a living tuple object."""
-        node = _extract_single_node(
-            """
+        node = _extract_single_node("""
         import sys
         sys.builtin_module_names
-        """
-        )
+        """)
         inferred = list(node.infer())
         assert len(inferred) == 1
         assert isinstance(inferred[0], nodes.Tuple)
@@ -26,12 +24,10 @@
 
     def test_sys_modules(self) -> None:
         """Test that we can gather the items of a living dict object."""
-        node = _extract_single_node(
-            """
+        node = _extract_single_node("""
         import sys
         sys.modules
-        """
-        )
+        """)
         inferred = list(node.infer())
         assert len(inferred) == 1
         assert isinstance(inferred[0], nodes.Dict)
diff --git a/tests/test_transforms.py b/tests/test_transforms.py
index 87b26a5..d58c5a7 100644
--- a/tests/test_transforms.py
+++ b/tests/test_transforms.py
@@ -16,8 +16,6 @@
 from astroid.brain.brain_dataclasses import _looks_like_dataclass_field_call
 from astroid.const import IS_PYPY
 from astroid.manager import AstroidManager
-from astroid.nodes.node_classes import Call, Compare, Const, Name
-from astroid.nodes.scoped_nodes import FunctionDef, Module
 from tests.testdata.python3.recursion_error import LONG_CHAINED_METHOD_CALL
 
 
@@ -39,24 +37,22 @@
     def setUp(self) -> None:
         self.transformer = transforms.TransformVisitor()
 
-    def parse_transform(self, code: str) -> Module:
+    def parse_transform(self, code: str) -> nodes.Module:
         module = parse(code, apply_transforms=False)
         return self.transformer.visit(module)
 
     def test_function_inlining_transform(self) -> None:
-        def transform_call(node: Call) -> Const:
+        def transform_call(node: nodes.Call) -> nodes.Const:
             # Let's do some function inlining
             inferred = next(node.infer())
             return inferred
 
         self.transformer.register_transform(nodes.Call, transform_call)
 
-        module = self.parse_transform(
-            """
+        module = self.parse_transform("""
         def test(): return 42
         test() #@
-        """
-        )
+        """)
 
         self.assertIsInstance(module.body[1], nodes.Expr)
         self.assertIsInstance(module.body[1].value, nodes.Const)
@@ -65,34 +61,32 @@
     def test_recursive_transforms_into_astroid_fields(self) -> None:
         # Test that the transformer walks properly the tree
         # by going recursively into the _astroid_fields per each node.
-        def transform_compare(node: Compare) -> Const:
+        def transform_compare(node: nodes.Compare) -> nodes.Const:
             # Let's check the values of the ops
             _, right = node.ops[0]
             # Assume they are Consts and they were transformed before
             # us.
             return nodes.const_factory(node.left.value < right.value)
 
-        def transform_name(node: Name) -> Const:
+        def transform_name(node: nodes.Name) -> nodes.Const:
             # Should be Consts
             return next(node.infer())
 
         self.transformer.register_transform(nodes.Compare, transform_compare)
         self.transformer.register_transform(nodes.Name, transform_name)
 
-        module = self.parse_transform(
-            """
+        module = self.parse_transform("""
         a = 42
         b = 24
         a < b
-        """
-        )
+        """)
 
         self.assertIsInstance(module.body[2], nodes.Expr)
         self.assertIsInstance(module.body[2].value, nodes.Const)
         self.assertFalse(module.body[2].value.value)
 
     def test_transform_patches_locals(self) -> None:
-        def transform_function(node: FunctionDef) -> None:
+        def transform_function(node: nodes.FunctionDef) -> None:
             assign = nodes.Assign(
                 parent=node,
                 lineno=node.lineno,
@@ -114,12 +108,10 @@
 
         self.transformer.register_transform(nodes.FunctionDef, transform_function)
 
-        module = self.parse_transform(
-            """
+        module = self.parse_transform("""
         def test():
             pass
-        """
-        )
+        """)
 
         func = module.body[0]
         self.assertEqual(len(func.body), 2)
@@ -127,17 +119,16 @@
         self.assertEqual(func.body[1].as_string(), "value = 42")
 
     def test_predicates(self) -> None:
-        def transform_call(node: Call) -> Const:
+        def transform_call(node: nodes.Call) -> nodes.Const:
             inferred = next(node.infer())
             return inferred
 
-        def should_inline(node: Call) -> bool:
+        def should_inline(node: nodes.Call) -> bool:
             return node.func.name.startswith("inlineme")
 
         self.transformer.register_transform(nodes.Call, transform_call, should_inline)
 
-        module = self.parse_transform(
-            """
+        module = self.parse_transform("""
         def inlineme_1():
             return 24
         def dont_inline_me():
@@ -147,8 +138,7 @@
         inlineme_1()
         dont_inline_me()
         inlineme_2()
-        """
-        )
+        """)
         values = module.body[-3:]
         self.assertIsInstance(values[0], nodes.Expr)
         self.assertIsInstance(values[0].value, nodes.Const)
@@ -165,7 +155,7 @@
         # on a partially constructed tree anymore, which was the
         # source of crashes in the past when certain inference rules
         # were used in a transform.
-        def transform_function(node: FunctionDef) -> Const:
+        def transform_function(node: nodes.FunctionDef) -> nodes.Const:
             if node.decorators:
                 for decorator in node.decorators.nodes:
                     inferred = next(decorator.infer())
@@ -175,8 +165,7 @@
 
         manager = MANAGER
         with add_transform(manager, nodes.FunctionDef, transform_function):
-            module = builder.parse(
-                """
+            module = builder.parse("""
             import abc
             from abc import abstractmethod
 
@@ -188,8 +177,7 @@
                 @abstractmethod
                 def bala(self):
                     return 42
-            """
-            )
+            """)
 
         cls = module["A"]
         ala = cls.body[0]
@@ -201,7 +189,7 @@
 
     def test_transforms_are_called_for_builtin_modules(self) -> None:
         # Test that transforms are called for builtin modules.
-        def transform_function(node: FunctionDef) -> FunctionDef:
+        def transform_function(node: nodes.FunctionDef) -> nodes.FunctionDef:
             name = nodes.AssignName(
                 name="value",
                 lineno=0,
@@ -215,7 +203,7 @@
 
         manager = MANAGER
 
-        def predicate(node: FunctionDef) -> bool:
+        def predicate(node: nodes.FunctionDef) -> bool:
             return node.root().name == "time"
 
         with add_transform(manager, nodes.FunctionDef, transform_function, predicate):
@@ -252,8 +240,7 @@
 
         self.transformer.register_transform(nodes.ClassDef, transform_class)
 
-        self.parse_transform(
-            """
+        self.parse_transform("""
             # Change environ to automatically call putenv() if it exists
             import os
             putenv = os.putenv
@@ -264,14 +251,13 @@
                 pass
             else:
                 import UserDict
-        """
-        )
+        """)
 
     @pytest.mark.skipif(
         IS_PYPY, reason="Could not find a useful recursion limit on all versions"
     )
     def test_transform_aborted_if_recursion_limited(self):
-        def transform_call(node: Call) -> Const:
+        def transform_call(node: nodes.Call) -> nodes.Const:
             return node
 
         self.transformer.register_transform(
diff --git a/tests/test_type_params.py b/tests/test_type_params.py
index 6398f78..021aa9a 100644
--- a/tests/test_type_params.py
+++ b/tests/test_type_params.py
@@ -5,11 +5,14 @@
 import pytest
 
 from astroid import extract_node
-from astroid.const import PY312_PLUS
+from astroid.const import PY312_PLUS, PY313_PLUS
 from astroid.nodes import (
     AssignName,
+    List,
+    Name,
     ParamSpec,
     Subscript,
+    Tuple,
     TypeAlias,
     TypeVar,
     TypeVarTuple,
@@ -26,6 +29,7 @@
     assert isinstance(node.type_params[0].name, AssignName)
     assert node.type_params[0].name.name == "T"
     assert node.type_params[0].bound is None
+    assert node.type_params[0].default_value is None
 
     assert isinstance(node.value, Subscript)
     assert node.value.value.name == "list"
@@ -41,12 +45,46 @@
     assert assigned is node.value
 
 
+def test_type_var() -> None:
+    node = extract_node("type Point[T: int] = T")
+    param = node.type_params[0]
+    assert isinstance(param, TypeVar)
+    assert isinstance(param.bound, Name)
+    assert param.bound.name == "int"
+    assert param.default_value is None
+
+
+@pytest.mark.skipif(not PY313_PLUS, reason="Type parameter defaults were added in 313")
+def test_type_var_defaults() -> None:
+    node = extract_node("type Point[T: int = int] = T")
+    param = node.type_params[0]
+    assert isinstance(param, TypeVar)
+    assert isinstance(param.bound, Name)
+    assert param.bound.name == "int"
+    assert isinstance(param.default_value, Name)
+    assert param.default_value.name == "int"
+
+
 def test_type_param_spec() -> None:
     node = extract_node("type Alias[**P] = Callable[P, int]")
     params = node.type_params[0]
     assert isinstance(params, ParamSpec)
     assert isinstance(params.name, AssignName)
     assert params.name.name == "P"
+    assert params.default_value is None
+
+    assert node.inferred()[0] is node
+
+
+@pytest.mark.skipif(not PY313_PLUS, reason="Type parameter defaults were added in 313")
+def test_type_param_spec_defaults() -> None:
+    node = extract_node("type Alias[**P = [int, str]] = Callable[P, int]")
+    params = node.type_params[0]
+    assert isinstance(params, ParamSpec)
+    assert isinstance(params.name, AssignName)
+    assert params.name.name == "P"
+    assert isinstance(params.default_value, List)
+    assert len(params.default_value.elts) == 2
 
     assert node.inferred()[0] is node
 
@@ -57,6 +95,23 @@
     assert isinstance(params, TypeVarTuple)
     assert isinstance(params.name, AssignName)
     assert params.name.name == "Ts"
+    assert params.default_value is None
+
+    assert node.inferred()[0] is node
+
+
+@pytest.mark.skipif(not PY313_PLUS, reason="Type parameter defaults were added in 313")
+def test_type_var_tuple_defaults() -> None:
+    node = extract_node("type Alias[*Ts = tuple[int, str]] = tuple[*Ts]")
+    params = node.type_params[0]
+    assert isinstance(params, TypeVarTuple)
+    assert isinstance(params.name, AssignName)
+    assert params.name.name == "Ts"
+    assert isinstance(params.default_value, Subscript)
+    assert isinstance(params.default_value.value, Name)
+    assert params.default_value.value.name == "tuple"
+    assert isinstance(params.default_value.slice, Tuple)
+    assert len(params.default_value.slice.elts) == 2
 
     assert node.inferred()[0] is node
 
diff --git a/tests/test_utils.py b/tests/test_utils.py
index c06ee58..664b174 100644
--- a/tests/test_utils.py
+++ b/tests/test_utils.py
@@ -31,14 +31,12 @@
         self.assertEqual(nodes.are_exclusive(xass1, xnames[2]), False)
 
     def test_not_exclusive_walrus_operator(self) -> None:
-        node_if, node_body, node_or_else = extract_node(
-            """
+        node_if, node_body, node_or_else = extract_node("""
         if val := True:  #@
             print(val)  #@
         else:
             print(val)  #@
-        """
-        )
+        """)
         node_if: nodes.If
         node_walrus = next(node_if.nodes_of_class(nodes.NamedExpr))
 
@@ -51,16 +49,14 @@
         assert nodes.are_exclusive(node_body, node_or_else) is True
 
     def test_not_exclusive_walrus_multiple(self) -> None:
-        node_if, body_1, body_2, or_else_1, or_else_2 = extract_node(
-            """
+        node_if, body_1, body_2, or_else_1, or_else_2 = extract_node("""
         if (val := True) or (val_2 := True):  #@
             print(val)  #@
             print(val_2)  #@
         else:
             print(val)  #@
             print(val_2)  #@
-        """
-        )
+        """)
         node_if: nodes.If
         walruses = list(node_if.nodes_of_class(nodes.NamedExpr))
 
@@ -80,14 +76,12 @@
         assert nodes.are_exclusive(walruses[1], or_else_2) is False
 
     def test_not_exclusive_walrus_operator_nested(self) -> None:
-        node_if, node_body, node_or_else = extract_node(
-            """
+        node_if, node_body, node_or_else = extract_node("""
         if all((last_val := i) % 2 == 0 for i in range(10)): #@
             print(last_val)  #@
         else:
             print(last_val)  #@
-        """
-        )
+        """)
         node_if: nodes.If
         node_walrus = next(node_if.nodes_of_class(nodes.NamedExpr))
 
@@ -100,8 +94,7 @@
         assert nodes.are_exclusive(node_body, node_or_else) is True
 
     def test_if(self) -> None:
-        module = builder.parse(
-            """
+        module = builder.parse("""
         if 1:
             a = 1
             a = 2
@@ -111,8 +104,7 @@
         else:
             a = 3
             a = 4
-        """
-        )
+        """)
         a1 = module.locals["a"][0]
         a2 = module.locals["a"][1]
         a3 = module.locals["a"][2]
@@ -127,8 +119,7 @@
         self.assertEqual(nodes.are_exclusive(a5, a6), False)
 
     def test_try_except(self) -> None:
-        module = builder.parse(
-            """
+        module = builder.parse("""
         try:
             def exclusive_func2():
                 "docstring"
@@ -141,8 +132,7 @@
         else:
             def exclusive_func2():
                 "this one redefine the one defined line 42"
-        """
-        )
+        """)
         f1 = module.locals["exclusive_func2"][0]
         f2 = module.locals["exclusive_func2"][1]
         f3 = module.locals["exclusive_func2"][2]
@@ -159,24 +149,20 @@
         self.assertEqual(nodes.are_exclusive(f4, f2), True)
 
     def test_unpack_infer_uninferable_nodes(self) -> None:
-        node = builder.extract_node(
-            """
+        node = builder.extract_node("""
         x = [A] * 1
         f = [x, [A] * 2]
         f
-        """
-        )
+        """)
         inferred = next(node.infer())
         unpacked = list(nodes.unpack_infer(inferred))
         self.assertEqual(len(unpacked), 3)
         self.assertTrue(all(elt is Uninferable for elt in unpacked))
 
     def test_unpack_infer_empty_tuple(self) -> None:
-        node = builder.extract_node(
-            """
+        node = builder.extract_node("""
         ()
-        """
-        )
+        """)
         inferred = next(node.infer())
         with self.assertRaises(InferenceError):
             list(nodes.unpack_infer(inferred))
diff --git a/tests/testdata/python3/data/module.py b/tests/testdata/python3/data/module.py
index af4a75f..98da5dd 100644
--- a/tests/testdata/python3/data/module.py
+++ b/tests/testdata/python3/data/module.py
@@ -2,7 +2,7 @@
 """
 
 __revision__ = '$Id: module.py,v 1.2 2005-11-02 11:56:54 syt Exp $'
-from astroid.nodes.node_classes import Name as NameNode
+from astroid.nodes import Name as NameNode
 from astroid import modutils
 from astroid.utils import *
 import os.path
@@ -59,7 +59,9 @@
                 return 'hehe'
             global_access(local, val=autre)
         finally:
-            return local
+            # return in finally was previously tested here but became a syntax error
+            # in 3.14 and this file is used in 188/1464 tests
+            a = local
     
     def static_method():
         """static method test"""
diff --git a/tests/testdata/python3/data/module3.14.py b/tests/testdata/python3/data/module3.14.py
new file mode 100644
index 0000000..e5af6b0
--- /dev/null
+++ b/tests/testdata/python3/data/module3.14.py
@@ -0,0 +1,91 @@
+"""test module for astroid
+"""
+
+__revision__ = '$Id: module.py,v 1.2 2005-11-02 11:56:54 syt Exp $'
+from astroid.nodes import Name as NameNode
+from astroid import modutils
+from astroid.utils import *
+import os.path
+MY_DICT = {}
+
+def global_access(key, val):
+    """function test"""
+    local = 1
+    MY_DICT[key] = val
+    for i in val:
+        if i:
+            del MY_DICT[i]
+            continue
+        else:
+            break
+    else:
+        return
+
+
+class YO:
+    """hehe
+    haha"""
+    a = 1
+    
+    def __init__(self):
+        try:
+            self.yo = 1
+        except ValueError as ex:
+            pass
+        except (NameError, TypeError):
+            raise XXXError()
+        except:
+            raise
+
+
+
+class YOUPI(YO):
+    class_attr = None
+    
+    def __init__(self):
+        self.member = None
+    
+    def method(self):
+        """method
+        test"""
+        global MY_DICT
+        try:
+            MY_DICT = {}
+            local = None
+            autre = [a for (a, b) in MY_DICT if b]
+            if b in autre:
+                return
+            elif a in autre:
+                return 'hehe'
+            global_access(local, val=autre)
+        finally:
+            # return in finally was previously tested here but became a syntax error
+            # in 3.14 and is used in 188/1464 tests
+            print(local)
+    
+    def static_method():
+        """static method test"""
+        assert MY_DICT, '???'
+    static_method = staticmethod(static_method)
+    
+    def class_method(cls):
+        """class method test"""
+        exec(a, b)
+    class_method = classmethod(class_method)
+
+
+def four_args(a, b, c, d):
+    """four arguments (was nested_args)"""
+    while 1:
+        if a:
+            break
+        a += +1
+    else:
+        b += -2
+    if c:
+        d = a and (b or c)
+    else:
+        c = a and b or d
+    list(map(lambda x, y: (y, x), a))
+redirect = four_args
+
diff --git a/tests/testdata/python3/data/x.zip b/tests/testdata/python3/data/x.zip
new file mode 100644
index 0000000..4f663fb
--- /dev/null
+++ b/tests/testdata/python3/data/x.zip
Binary files differ
diff --git a/tests/testdata/python3/pyi_data/find_test/__init__.weird_ext b/tests/testdata/python3/pyi_data/find_test/__init__.weird_ext
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/testdata/python3/pyi_data/find_test/__init__.weird_ext
diff --git a/tests/testdata/python3/pyi_data/find_test/standalone_file.weird_ext b/tests/testdata/python3/pyi_data/find_test/standalone_file.weird_ext
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/testdata/python3/pyi_data/find_test/standalone_file.weird_ext
diff --git a/tox.ini b/tox.ini
index 2f089b6..b3bd055 100644
--- a/tox.ini
+++ b/tox.ini
@@ -1,5 +1,5 @@
 [tox]
-envlist = py{39,310,311,312,313}
+envlist = py{39,310,311,312,313,314}
 skip_missing_interpreters = true
 isolated_build = true