diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml
index 7bee9c2ee..b9b28d6e7 100644
--- a/.github/ISSUE_TEMPLATE/config.yml
+++ b/.github/ISSUE_TEMPLATE/config.yml
@@ -1,11 +1,11 @@
 blank_issues_enabled: true
 contact_links:
-    - name: "Start a discussion (GitHub)"
-      about: "How do I…?"
-      url: https://github.com/scikit-hep/uproot5/discussions
-    - name: "StackOverflow: [uproot] tag"
-      about: "How do I…?"
-      url: https://stackoverflow.com/questions/tagged/uproot
-    - name: "Gitter: Scikit-HEP/uproot room"
-      about: "Getting help in real-time…"
-      url: https://gitter.im/Scikit-HEP/uproot
+  - name: Start a discussion (GitHub)
+    about: How do I…?
+    url: https://github.com/scikit-hep/uproot5/discussions
+  - name: 'StackOverflow: [uproot] tag'
+    about: How do I…?
+    url: https://stackoverflow.com/questions/tagged/uproot
+  - name: 'Gitter: Scikit-HEP/uproot room'
+    about: Getting help in real-time…
+    url: https://gitter.im/Scikit-HEP/uproot
diff --git a/.github/dependabot.yml b/.github/dependabot.yml
index 6fddca0d6..5f9ac8bdb 100644
--- a/.github/dependabot.yml
+++ b/.github/dependabot.yml
@@ -1,7 +1,7 @@
 version: 2
 updates:
   # Maintain dependencies for GitHub Actions
-  - package-ecosystem: "github-actions"
-    directory: "/"
+  - package-ecosystem: github-actions
+    directory: /
     schedule:
-      interval: "weekly"
+      interval: weekly
diff --git a/.github/workflows/build-test.yml b/.github/workflows/build-test.yml
index 83a86d9b6..cb7698571 100644
--- a/.github/workflows/build-test.yml
+++ b/.github/workflows/build-test.yml
@@ -1,10 +1,10 @@
-name: "Test build"
+name: Test build
 
 on:
   workflow_dispatch:
   pull_request:
   push:
-    branches: ["main"]
+    branches: [main]
 
 concurrency:
   group: ${{ github.workflow }}-${{ github.ref }}
@@ -15,46 +15,46 @@ jobs:
     strategy:
       fail-fast: false
       matrix:
-        platform: ["windows-latest", "macos-latest", "ubuntu-latest"]
-        python-version: ["3.8", "3.9", "3.10", "3.11", "3.12"]
+        platform: [windows-latest, macos-latest, ubuntu-latest]
+        python-version: ['3.8', '3.9', '3.10', '3.11', '3.12']
 
-    runs-on: "${{ matrix.platform }}"
+    runs-on: ${{ matrix.platform }}
     timeout-minutes: 30
 
     # Required for miniconda to activate conda
     defaults:
       run:
-        shell: "bash -l {0}"
+        shell: bash -l {0}
 
     steps:
-      - uses: "actions/checkout@v4"
+      - uses: actions/checkout@v4
 
-      - name: "Get conda"
-        uses: "conda-incubator/setup-miniconda@v2"
+      - name: Get conda
+        uses: conda-incubator/setup-miniconda@v2
         with:
           auto-update-conda: true
           python-version: ${{ matrix.python-version }}
           miniforge-variant: Mambaforge
           use-mamba: true
 
-      - name: "Install ROOT"
-        if: "matrix.python-version == 3.8  &&  runner.os != 'macOS'  &&  runner.os != 'Windows'"
+      - name: Install ROOT
+        if: matrix.python-version == 3.8  &&  runner.os != 'macOS'  &&  runner.os != 'Windows'
         run: |
           conda env list
           mamba install root
           conda list
 
-      - name: "Install XRootD"
-        if: "runner.os != 'macOS'  &&  runner.os != 'Windows'"
+      - name: Install XRootD
+        if: runner.os != 'macOS'  &&  runner.os != 'Windows'
         run: |
           conda env list
           mamba install xrootd
           conda list
 
-      - name: "Pip install the package"
+      - name: Pip install the package
         run: python -m pip install .[test,dev]
 
-      - name: "Run pytest"
+      - name: Run pytest
         run: |
           python -m pytest -vv tests \
             --reruns 3 --reruns-delay 30 \
@@ -64,22 +64,22 @@ jobs:
     strategy:
       fail-fast: false
       matrix:
-        platform: ["windows-latest", "ubuntu-latest", "macos-latest"]
-        python-version: ["3.11"]
+        platform: [windows-latest, ubuntu-latest, macos-latest]
+        python-version: ['3.11']
 
-    runs-on: "${{ matrix.platform }}"
+    runs-on: ${{ matrix.platform }}
     timeout-minutes: 30
 
     steps:
-      - uses: "actions/checkout@v4"
+      - uses: actions/checkout@v4
 
-      - uses: "actions/setup-python@v4"
+      - uses: actions/setup-python@v4
         with:
-          python-version: "${{ matrix.python-version }}"
+          python-version: ${{ matrix.python-version }}
 
-      - name: "Pip install the package"
+      - name: Pip install the package
         run: python -m pip install .[test,dev]
 
-      - name: "Run pytest"
+      - name: Run pytest
         run: |
           python -m pytest -vv tests --reruns 3 --reruns-delay 30 --only-rerun requests.exceptions.HTTPError
diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml
index 511b61377..bc538e7e4 100644
--- a/.github/workflows/deploy.yml
+++ b/.github/workflows/deploy.yml
@@ -4,23 +4,23 @@ on:
   workflow_dispatch:
   release:
     types:
-    - published
+      - published
 
 jobs:
   dist:
     runs-on: ubuntu-latest
     steps:
-    - uses: actions/checkout@v4
+      - uses: actions/checkout@v4
 
-    - name: Build wheel and SDist
-      run: pipx run build
+      - name: Build wheel and SDist
+        run: pipx run build
 
-    - name: Check metadata
-      run: pipx run twine check dist/*
+      - name: Check metadata
+        run: pipx run twine check dist/*
 
-    - uses: actions/upload-artifact@v3
-      with:
-        path: dist/*
+      - uses: actions/upload-artifact@v3
+        with:
+          path: dist/*
 
 
   publish:
@@ -29,11 +29,11 @@ jobs:
     if: github.event_name == 'release' && github.event.action == 'published'
 
     steps:
-    - uses: actions/download-artifact@v3
-      with:
-        name: artifact
-        path: dist
-
-    - uses: pypa/gh-action-pypi-publish@release/v1
-      with:
-        password: ${{ secrets.pypi_password }}
+      - uses: actions/download-artifact@v3
+        with:
+          name: artifact
+          path: dist
+
+      - uses: pypa/gh-action-pypi-publish@release/v1
+        with:
+          password: ${{ secrets.pypi_password }}
diff --git a/.github/workflows/semantic-pr-title.yml b/.github/workflows/semantic-pr-title.yml
index 8491e8eb7..4629c8e3a 100644
--- a/.github/workflows/semantic-pr-title.yml
+++ b/.github/workflows/semantic-pr-title.yml
@@ -1,4 +1,4 @@
-name: "Lint PR"
+name: Lint PR
 
 on:
   pull_request:
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 742949656..20e558391 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -1,36 +1,44 @@
 ci:
-  autoupdate_commit_msg: "chore: update pre-commit hooks"
-  autofix_commit_msg: "style: pre-commit fixes"
+  autoupdate_commit_msg: 'chore: update pre-commit hooks'
+  autofix_commit_msg: 'style: pre-commit fixes'
 
 repos:
-- repo: https://github.com/pre-commit/pre-commit-hooks
-  rev: v4.5.0
-  hooks:
-  - id: check-added-large-files
-  - id: check-case-conflict
-  - id: check-merge-conflict
-  - id: check-symlinks
-  - id: check-yaml
-  - id: debug-statements
-  - id: end-of-file-fixer
-  - id: mixed-line-ending
-  - id: requirements-txt-fixer
-  - id: trailing-whitespace
+  - repo: https://github.com/pre-commit/pre-commit-hooks
+    rev: v4.5.0
+    hooks:
+      - id: check-added-large-files
+      - id: check-case-conflict
+      - id: check-merge-conflict
+      - id: check-symlinks
+      - id: check-yaml
+      - id: debug-statements
+      - id: end-of-file-fixer
+      - id: mixed-line-ending
+      - id: requirements-txt-fixer
+      - id: trailing-whitespace
 
-- repo: https://github.com/psf/black-pre-commit-mirror
-  rev: 23.9.1
-  hooks:
-  - id: black
+  - repo: https://github.com/psf/black-pre-commit-mirror
+    rev: 23.9.1
+    hooks:
+      - id: black
 
-- repo: https://github.com/astral-sh/ruff-pre-commit
-  rev: "v0.0.292"
-  hooks:
-    - id: ruff
-      args: ["--fix", "--show-fixes"]
+  - repo: https://github.com/astral-sh/ruff-pre-commit
+    rev: v0.0.292
+    hooks:
+      - id: ruff
+        args: [--fix, --show-fixes]
 
 
-- repo: https://github.com/asottile/pyupgrade
-  rev: v3.15.0
-  hooks:
-  - id: pyupgrade
-    args: ["--py38-plus"]
+  - repo: https://github.com/asottile/pyupgrade
+    rev: v3.15.0
+    hooks:
+      - id: pyupgrade
+        args: [--py38-plus]
+
+  - repo: https://github.com/macisamuele/language-formatters-pre-commit-hooks
+    rev: v2.11.0
+    hooks:
+      - id: pretty-format-toml
+        args: [--autofix]
+      - id: pretty-format-yaml
+        args: [--autofix, --indent, '2', --offset, '2']
diff --git a/pyproject.toml b/pyproject.toml
index 622e95125..a28d05c97 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,74 +1,74 @@
 [build-system]
+build-backend = "hatchling.build"
 requires = [
-    "hatchling",
+  "hatchling"
 ]
-build-backend = "hatchling.build"
 
 [project]
-name = "uproot"
-description = "ROOT I/O in pure Python and NumPy."
-readme = "README.md"
-license = "BSD-3-Clause"
-requires-python = ">=3.8"
 authors = [
-    { name = "Jim Pivarski", email = "pivarski@princeton.edu" },
+  {name = "Jim Pivarski", email = "pivarski@princeton.edu"}
 ]
 classifiers = [
-    "Development Status :: 5 - Production/Stable",
-    "Intended Audience :: Developers",
-    "Intended Audience :: Information Technology",
-    "Intended Audience :: Science/Research",
-    "License :: OSI Approved :: BSD License",
-    "Operating System :: MacOS",
-    "Operating System :: POSIX",
-    "Operating System :: Unix",
-    "Programming Language :: Python",
-    "Programming Language :: Python :: 3",
-    "Programming Language :: Python :: 3 :: Only",
-    "Programming Language :: Python :: 3.8",
-    "Programming Language :: Python :: 3.9",
-    "Programming Language :: Python :: 3.10",
-    "Programming Language :: Python :: 3.11",
-    "Programming Language :: Python :: 3.12",
-    "Topic :: Scientific/Engineering",
-    "Topic :: Scientific/Engineering :: Information Analysis",
-    "Topic :: Scientific/Engineering :: Mathematics",
-    "Topic :: Scientific/Engineering :: Physics",
-    "Topic :: Software Development",
-    "Topic :: Utilities",
+  "Development Status :: 5 - Production/Stable",
+  "Intended Audience :: Developers",
+  "Intended Audience :: Information Technology",
+  "Intended Audience :: Science/Research",
+  "License :: OSI Approved :: BSD License",
+  "Operating System :: MacOS",
+  "Operating System :: POSIX",
+  "Operating System :: Unix",
+  "Programming Language :: Python",
+  "Programming Language :: Python :: 3",
+  "Programming Language :: Python :: 3 :: Only",
+  "Programming Language :: Python :: 3.8",
+  "Programming Language :: Python :: 3.9",
+  "Programming Language :: Python :: 3.10",
+  "Programming Language :: Python :: 3.11",
+  "Programming Language :: Python :: 3.12",
+  "Topic :: Scientific/Engineering",
+  "Topic :: Scientific/Engineering :: Information Analysis",
+  "Topic :: Scientific/Engineering :: Mathematics",
+  "Topic :: Scientific/Engineering :: Physics",
+  "Topic :: Software Development",
+  "Topic :: Utilities"
 ]
 dependencies = [
-    "awkward>=2.4.6",
-    "importlib-metadata;python_version<\"3.8\"",
-    "numpy",
-    "packaging",
-    "typing_extensions>=4.1.0; python_version < \"3.11\""
+  "awkward>=2.4.6",
+  "importlib-metadata;python_version<\"3.8\"",
+  "numpy",
+  "packaging",
+  "typing_extensions>=4.1.0; python_version < \"3.11\""
 ]
+description = "ROOT I/O in pure Python and NumPy."
 dynamic = [
-    "version",
+  "version"
 ]
+license = "BSD-3-Clause"
+name = "uproot"
+readme = "README.md"
+requires-python = ">=3.8"
 
 [project.optional-dependencies]
 dev = [
-    "boost_histogram>=0.13",
-    "dask-awkward>=2023.10.0",
-    "dask[array]",
-    "hist>=1.2",
-    "pandas",
-    "awkward-pandas",
+  "boost_histogram>=0.13",
+  "dask-awkward>=2023.10.0",
+  "dask[array]",
+  "hist>=1.2",
+  "pandas",
+  "awkward-pandas"
 ]
 test = [
-    "lz4",
-    "minio",
-    "aiohttp; python_version<\"3.12\"",
-    "fsspec",
-    "fsspec-xrootd",
-    "pytest>=6",
-    "pytest-timeout",
-    "pytest-rerunfailures",
-    "requests",
-    "scikit-hep-testdata",
-    "xxhash",
+  "lz4",
+  "minio",
+  "aiohttp; python_version<\"3.12\"",
+  "fsspec",
+  "fsspec-xrootd",
+  "pytest>=6",
+  "pytest-timeout",
+  "pytest-rerunfailures",
+  "requests",
+  "scikit-hep-testdata",
+  "xxhash"
 ]
 
 [project.urls]
@@ -78,61 +78,63 @@ Homepage = "https://github.com/scikit-hep/uproot5"
 [tool.hatch.version]
 path = "src/uproot/version.py"
 
+[tool.isort]
+profile = "black"
 
 [tool.pytest.ini_options]
-minversion = "6.0"
 addopts = ["-ra", "--showlocals", "--strict-markers", "--strict-config"]
-xfail_strict = true
 filterwarnings = [
-    "error",
-    "default:module 'sre_.*' is deprecated:DeprecationWarning"
+  "error",
+  "default:module 'sre_.*' is deprecated:DeprecationWarning"
 ]
 log_cli_level = "info"
-testpaths = ["tests"]
 markers = [
-    "slow",
-    "network",
-    "xrootd",
+  "slow",
+  "network",
+  "xrootd"
 ]
+minversion = "6.0"
+testpaths = ["tests"]
 timeout = 600
-
-[tool.isort]
-profile = "black"
+xfail_strict = true
 
 [tool.ruff]
-select = [
-    "E", "F", "W", # flake8
-    "B", "B904",   # flake8-bugbear
-    "I",           # isort
-    # "ARG",         # flake8-unused-arguments
-    "C4",          # flake8-comprehensions
-    "ISC",         # flake8-implicit-str-concat
-    "PGH",         # pygrep-hooks
-    "PIE",         # flake8-pie
-    "PL",          # pylint
-    "PT",          # flake8-pytest-style
-    "RUF",         # Ruff-specific
-    "SIM",         # flake8-simplify
-    "T20",         # flake8-print
-    "UP",          # pyupgrade
-    "YTT",         # flake8-2020
+exclude = [
+  "tests/*.py",
+  "src/uproot/__init__.py",
+  "docs-sphinx/*.py"
 ]
 ignore = [
-    "E501",
-    "E722",
-    "PLR",
-    "PLW0120", # else on loop without break
-    "SIM118",  # key in dict, broken since uproot doesn't behave like a dict
-    "PGH003",  # too-broad type ignore
-    "SIM114",  # combine `if` branches using logical `or` operator
-    "PGH001",  # no eval allowed
-    "PLC1901", # empty string is falsey (but I don't want to rely on such weak typing)
-    "RUF012",  # enforces type annotations on a codebase that lacks type annotations
+  "E501",
+  "E722",
+  "PLR",
+  "PLW0120",  # else on loop without break
+  "SIM118",  # key in dict, broken since uproot doesn't behave like a dict
+  "PGH003",  # too-broad type ignore
+  "SIM114",  # combine `if` branches using logical `or` operator
+  "PGH001",  # no eval allowed
+  "PLC1901",  # empty string is falsey (but I don't want to rely on such weak typing)
+  "RUF012"  # enforces type annotations on a codebase that lacks type annotations
 ]
-exclude = [
-    "tests/*.py",
-    "src/uproot/__init__.py",
-    "docs-sphinx/*.py",
+select = [
+  "E",
+  "F",
+  "W",  # flake8
+  "B",
+  "B904",  # flake8-bugbear
+  "I",  # isort
+  # "ARG",         # flake8-unused-arguments
+  "C4",  # flake8-comprehensions
+  "ISC",  # flake8-implicit-str-concat
+  "PGH",  # pygrep-hooks
+  "PIE",  # flake8-pie
+  "PL",  # pylint
+  "PT",  # flake8-pytest-style
+  "RUF",  # Ruff-specific
+  "SIM",  # flake8-simplify
+  "T20",  # flake8-print
+  "UP",  # pyupgrade
+  "YTT"  # flake8-2020
 ]
 src = ["src"]
 
@@ -141,4 +143,4 @@ max-complexity = 100
 
 [tool.ruff.per-file-ignores]
 "dev/*" = ["T20"]
-"src/uproot/*/file.py" =  ["SIM115"]
+"src/uproot/*/file.py" = ["SIM115"]