Repository: pymc-devs/pymc (branch: ruff_linter)
Commit date: 2024-01-11T11:37:15Z

Workflow file: .github/workflows/pre-commit.yml (pre-commit)
name: pre-commit

on:
  pull_request:
  push:
    branches: [main]

jobs:
  pre-commit:
    runs-on: ubuntu-latest
    services:
      pypi_wayback:
        image: ghcr.io/waleko/pypi-wayback
        ports:
          - 8629:8080
    env:
      SKIP: no-commit-to-branch
    steps:
    - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11
    - uses: actions/setup-python@v5
      with:
        python-version: "3.9"  # Run pre-commit on oldest supported Python version
    - uses: pre-commit/action@v3.0.0
  mypy:
    runs-on: ubuntu-latest
    services:
      pypi_wayback:
        image: ghcr.io/waleko/pypi-wayback
        ports:
          - 8629:8080
    defaults:
      run:
        shell: bash -l {0}
    steps:
      - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11
      - name: Cache conda
        uses: actions/cache@v3
        env:
          # Increase this value to reset cache if environment-test.yml has not changed
          CACHE_NUMBER: 0
        with:
          path: ~/conda_pkgs_dir
          key: ${{ runner.os }}-py39-conda-${{ env.CACHE_NUMBER }}-${{
            hashFiles('conda-envs/environment-test.yml') }}
      - name: Cache multiple paths
        uses: actions/cache@v3
        env:
          # Increase this value to reset cache if requirements.txt has not changed
          CACHE_NUMBER: 0
        with:
          path: |
            ~/.cache/pip
            $RUNNER_TOOL_CACHE/Python/*
            ~\AppData\Local\pip\Cache
          key: ${{ runner.os }}-build-${{ matrix.python-version }}-${{ env.CACHE_NUMBER }}-${{
            hashFiles('requirements.txt') }}
      - uses: conda-incubator/setup-miniconda@v2
        with:
          miniforge-variant: Mambaforge
          miniforge-version: latest
          mamba-version: "*"
          activate-environment: pymc-test
          channel-priority: strict
          environment-file: conda-envs/environment-test.yml
          python-version: "3.9"  # Run pre-commit on oldest supported Python version
          use-mamba: true
          use-only-tar-bz2: false # IMPORTANT: This may break caching of conda packages! See https://github.com/conda-incubator/setup-miniconda/issues/267
      - name: Install-pymc and mypy dependencies
        run: |
          conda activate pymc-test
          pip install -e .
          pip install --pre -U polyagamma
          python --version
      - name: Run mypy
        run: |
          conda activate pymc-test
          python ./scripts/run_mypy.py --verbose

env:
  PIP_INDEX_URL: http://localhost:8629/2024-01-11
  UV_INDEX_URL: http://localhost:8629/2024-01-11


Failed build logs:
step_name: pre-commit/4_Run pre-commitaction@v3.0.0.txt
log: ##[group]Run pre-commit/action@v3.0.0
with:
  extra_args: --all-files
env:
  SKIP: no-commit-to-branch
  pythonLocation: /opt/hostedtoolcache/Python/3.9.18/x64
  PKG_CONFIG_PATH: /opt/hostedtoolcache/Python/3.9.18/x64/lib/pkgconfig
  Python_ROOT_DIR: /opt/hostedtoolcache/Python/3.9.18/x64
  Python2_ROOT_DIR: /opt/hostedtoolcache/Python/3.9.18/x64
  Python3_ROOT_DIR: /opt/hostedtoolcache/Python/3.9.18/x64
  LD_LIBRARY_PATH: /opt/hostedtoolcache/Python/3.9.18/x64/lib
##[endgroup]
##[group]Run python -m pip install pre-commit
[36;1mpython -m pip install pre-commit[0m
shell: /usr/bin/bash --noprofile --norc -e -o pipefail {0}
env:
  SKIP: no-commit-to-branch
  pythonLocation: /opt/hostedtoolcache/Python/3.9.18/x64
  PKG_CONFIG_PATH: /opt/hostedtoolcache/Python/3.9.18/x64/lib/pkgconfig
  Python_ROOT_DIR: /opt/hostedtoolcache/Python/3.9.18/x64
  Python2_ROOT_DIR: /opt/hostedtoolcache/Python/3.9.18/x64
  Python3_ROOT_DIR: /opt/hostedtoolcache/Python/3.9.18/x64
  LD_LIBRARY_PATH: /opt/hostedtoolcache/Python/3.9.18/x64/lib
##[endgroup]
Collecting pre-commit
  Downloading pre_commit-3.6.0-py2.py3-none-any.whl.metadata (1.3 kB)
Collecting cfgv>=2.0.0 (from pre-commit)
  Downloading cfgv-3.4.0-py2.py3-none-any.whl.metadata (8.5 kB)
Collecting identify>=1.0.0 (from pre-commit)
  Downloading identify-2.5.33-py2.py3-none-any.whl.metadata (4.4 kB)
Collecting nodeenv>=0.11.1 (from pre-commit)
  Downloading nodeenv-1.8.0-py2.py3-none-any.whl.metadata (21 kB)
Collecting pyyaml>=5.1 (from pre-commit)
  Downloading PyYAML-6.0.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.metadata (2.1 kB)
Collecting virtualenv>=20.10.0 (from pre-commit)
  Downloading virtualenv-20.25.0-py3-none-any.whl.metadata (4.5 kB)
Requirement already satisfied: setuptools in /opt/hostedtoolcache/Python/3.9.18/x64/lib/python3.9/site-packages (from nodeenv>=0.11.1->pre-commit) (58.1.0)
Collecting distlib<1,>=0.3.7 (from virtualenv>=20.10.0->pre-commit)
  Downloading distlib-0.3.8-py2.py3-none-any.whl.metadata (5.1 kB)
Collecting filelock<4,>=3.12.2 (from virtualenv>=20.10.0->pre-commit)
  Downloading filelock-3.13.1-py3-none-any.whl.metadata (2.8 kB)
Collecting platformdirs<5,>=3.9.1 (from virtualenv>=20.10.0->pre-commit)
  Downloading platformdirs-4.1.0-py3-none-any.whl.metadata (11 kB)
Downloading pre_commit-3.6.0-py2.py3-none-any.whl (204 kB)
   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 204.0/204.0 kB 15.9 MB/s eta 0:00:00
Downloading cfgv-3.4.0-py2.py3-none-any.whl (7.2 kB)
Downloading identify-2.5.33-py2.py3-none-any.whl (98 kB)
   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 98.9/98.9 kB 27.2 MB/s eta 0:00:00
Downloading nodeenv-1.8.0-py2.py3-none-any.whl (22 kB)
Downloading PyYAML-6.0.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (738 kB)
   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 738.9/738.9 kB 52.7 MB/s eta 0:00:00
Downloading virtualenv-20.25.0-py3-none-any.whl (3.8 MB)
   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 3.8/3.8 MB 108.7 MB/s eta 0:00:00
Downloading distlib-0.3.8-py2.py3-none-any.whl (468 kB)
   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 468.9/468.9 kB 69.4 MB/s eta 0:00:00
Downloading filelock-3.13.1-py3-none-any.whl (11 kB)
Downloading platformdirs-4.1.0-py3-none-any.whl (17 kB)
Installing collected packages: distlib, pyyaml, platformdirs, nodeenv, identify, filelock, cfgv, virtualenv, pre-commit
Successfully installed cfgv-3.4.0 distlib-0.3.8 filelock-3.13.1 identify-2.5.33 nodeenv-1.8.0 platformdirs-4.1.0 pre-commit-3.6.0 pyyaml-6.0.1 virtualenv-20.25.0

[notice] A new release of pip is available: 23.0.1 -> 23.3.2
[notice] To update, run: pip install --upgrade pip
##[group]Run python -m pip freeze --local
[36;1mpython -m pip freeze --local[0m
shell: /usr/bin/bash --noprofile --norc -e -o pipefail {0}
env:
  SKIP: no-commit-to-branch
  pythonLocation: /opt/hostedtoolcache/Python/3.9.18/x64
  PKG_CONFIG_PATH: /opt/hostedtoolcache/Python/3.9.18/x64/lib/pkgconfig
  Python_ROOT_DIR: /opt/hostedtoolcache/Python/3.9.18/x64
  Python2_ROOT_DIR: /opt/hostedtoolcache/Python/3.9.18/x64
  Python3_ROOT_DIR: /opt/hostedtoolcache/Python/3.9.18/x64
  LD_LIBRARY_PATH: /opt/hostedtoolcache/Python/3.9.18/x64/lib
##[endgroup]
cfgv==3.4.0
distlib==0.3.8
filelock==3.13.1
identify==2.5.33
nodeenv==1.8.0
platformdirs==4.1.0
pre-commit==3.6.0
PyYAML==6.0.1
virtualenv==20.25.0
##[group]Run actions/cache@v3
with:
  path: ~/.cache/pre-commit
  key: pre-commit-3|/opt/hostedtoolcache/Python/3.9.18/x64|b69a9ccf7aebb98803ff18cb769a19428ca4b15f855ee813cd0630df2c6b60db
  enableCrossOsArchive: false
  fail-on-cache-miss: false
  lookup-only: false
env:
  SKIP: no-commit-to-branch
  pythonLocation: /opt/hostedtoolcache/Python/3.9.18/x64
  PKG_CONFIG_PATH: /opt/hostedtoolcache/Python/3.9.18/x64/lib/pkgconfig
  Python_ROOT_DIR: /opt/hostedtoolcache/Python/3.9.18/x64
  Python2_ROOT_DIR: /opt/hostedtoolcache/Python/3.9.18/x64
  Python3_ROOT_DIR: /opt/hostedtoolcache/Python/3.9.18/x64
  LD_LIBRARY_PATH: /opt/hostedtoolcache/Python/3.9.18/x64/lib
##[endgroup]
Cache not found for input keys: pre-commit-3|/opt/hostedtoolcache/Python/3.9.18/x64|b69a9ccf7aebb98803ff18cb769a19428ca4b15f855ee813cd0630df2c6b60db
##[group]Run pre-commit run --show-diff-on-failure --color=always --all-files
[36;1mpre-commit run --show-diff-on-failure --color=always --all-files[0m
shell: /usr/bin/bash --noprofile --norc -e -o pipefail {0}
env:
  SKIP: no-commit-to-branch
  pythonLocation: /opt/hostedtoolcache/Python/3.9.18/x64
  PKG_CONFIG_PATH: /opt/hostedtoolcache/Python/3.9.18/x64/lib/pkgconfig
  Python_ROOT_DIR: /opt/hostedtoolcache/Python/3.9.18/x64
  Python2_ROOT_DIR: /opt/hostedtoolcache/Python/3.9.18/x64
  Python3_ROOT_DIR: /opt/hostedtoolcache/Python/3.9.18/x64
  LD_LIBRARY_PATH: /opt/hostedtoolcache/Python/3.9.18/x64/lib
##[endgroup]
[INFO][m Initializing environment for https://github.com/pre-commit/pre-commit-hooks.
[INFO][m Initializing environment for https://github.com/lucianopaz/head_of_apache.
[INFO][m Initializing environment for https://github.com/astral-sh/ruff-pre-commit.
[INFO][m Initializing environment for https://github.com/PyCQA/pydocstyle.
[INFO][m Initializing environment for https://github.com/MarcoGorelli/madforhooks.
[INFO][m Initializing environment for local:pandas,pyyaml.
[INFO][m Initializing environment for local:pyyaml.
[INFO][m Installing environment for https://github.com/pre-commit/pre-commit-hooks.
[INFO][m Once installed this environment will be reused.
[INFO][m This may take a few minutes...
[INFO][m Installing environment for https://github.com/lucianopaz/head_of_apache.
[INFO][m Once installed this environment will be reused.
[INFO][m This may take a few minutes...
[INFO][m Installing environment for https://github.com/astral-sh/ruff-pre-commit.
[INFO][m Once installed this environment will be reused.
[INFO][m This may take a few minutes...
[INFO][m Installing environment for https://github.com/PyCQA/pydocstyle.
[INFO][m Once installed this environment will be reused.
[INFO][m This may take a few minutes...
[INFO][m Installing environment for https://github.com/MarcoGorelli/madforhooks.
[INFO][m Once installed this environment will be reused.
[INFO][m This may take a few minutes...
[INFO][m Installing environment for local.
[INFO][m Once installed this environment will be reused.
[INFO][m This may take a few minutes...
[INFO][m Installing environment for local.
[INFO][m Once installed this environment will be reused.
[INFO][m This may take a few minutes...
check for merge conflicts............................................................[42mPassed[m
check toml...........................................................................[42mPassed[m
check yaml...........................................................................[42mPassed[m
debug statements (python)............................................................[42mPassed[m
fix end of files.....................................................................[42mPassed[m
don't commit to branch..............................................................[43;30mSkipped[m
fix requirements.txt.................................................................[42mPassed[m
trim trailing whitespace.............................................................[42mPassed[m
Apply Apache 2.0 License.............................................................[42mPassed[m
ruff.................................................................................[41mFailed[m
[2m- hook id: ruff[m
[2m- exit code: 1[m
[2m- files were modified by this hook[m

[1mpymc/_version.py[0m[36m:[0m157[36m:[0m13[36m:[0m [1;31mUP031[0m Use format specifiers instead of percent format
[1;38;5;12m    |[0m
[1;38;5;12m155 |[0m       if verbose:
[1;38;5;12m156 |[0m           print(
[1;38;5;12m157 |[0m               "Tried directories %s but none started with prefix %s"
[1;38;5;12m    |[0m  [1;38;5;9m_____________^[0m
[1;38;5;12m158 |[0m [1;38;5;9m|[0m             % (str(rootdirs), parentdir_prefix)
[1;38;5;12m    |[0m [1;38;5;9m|[0m[1;38;5;9m_______________________________________________^[0m [1;38;5;9mUP031[0m
[1;38;5;12m159 |[0m           )
[1;38;5;12m160 |[0m       raise NotThisMethod("rootdir doesn't start with parentdir_prefix")
[1;38;5;12m    |[0m
    [1;38;5;12m=[0m [1;38;5;14mhelp[0m: Replace with format specifiers

[1mpymc/step_methods/hmc/integration.py[0m[36m:[0m47[36m:[0m17[36m:[0m [1;31mUP031[0m Use format specifiers instead of percent format
[1;38;5;12m   |[0m
[1;38;5;12m45 |[0m           if self._potential.dtype != self._dtype:
[1;38;5;12m46 |[0m               raise ValueError(
[1;38;5;12m47 |[0m                   "dtypes of potential (%s) and logp function (%s)"
[1;38;5;12m   |[0m  [1;38;5;9m_________________^[0m
[1;38;5;12m48 |[0m [1;38;5;9m|[0m                 "don't match." % (self._potential.dtype, self._dtype)
[1;38;5;12m   |[0m [1;38;5;9m|[0m[1;38;5;9m_____________________________________________________________________^[0m [1;38;5;9mUP031[0m
[1;38;5;12m49 |[0m               )
[1;38;5;12m   |[0m
   [1;38;5;12m=[0m [1;38;5;14mhelp[0m: Replace with format specifiers

[1mpymc/variational/opvi.py[0m[36m:[0m461[36m:[0m17[36m:[0m [1;31mUP031[0m Use format specifiers instead of percent format
[1;38;5;12m    |[0m
[1;38;5;12m459 |[0m           if self.require_logq and not approx.has_logq:
[1;38;5;12m460 |[0m               raise ExplicitInferenceError(
[1;38;5;12m461 |[0m                   "%s requires logq, but %s does not implement it"
[1;38;5;12m    |[0m  [1;38;5;9m_________________^[0m
[1;38;5;12m462 |[0m [1;38;5;9m|[0m                 "please change inference method" % (self, approx)
[1;38;5;12m    |[0m [1;38;5;9m|[0m[1;38;5;9m_________________________________________________________________^[0m [1;38;5;9mUP031[0m
[1;38;5;12m463 |[0m               )
[1;38;5;12m    |[0m
    [1;38;5;12m=[0m [1;38;5;14mhelp[0m: Replace with format specifiers

[1mpymc/variational/opvi.py[0m[36m:[0m513[36m:[0m16[36m:[0m [1;31mUP031[0m Use format specifiers instead of percent format
[1;38;5;12m    |[0m
[1;38;5;12m512 |[0m       def __str__(self):  # pragma: no cover
[1;38;5;12m513 |[0m           return "%(op)s[%(ap)s]" % dict(
[1;38;5;12m    |[0m  [1;38;5;9m________________^[0m
[1;38;5;12m514 |[0m [1;38;5;9m|[0m             op=self.__class__.__name__, ap=self.approx.__class__.__name__
[1;38;5;12m515 |[0m [1;38;5;9m|[0m         )
[1;38;5;12m    |[0m [1;38;5;9m|[0m[1;38;5;9m_________^[0m [1;38;5;9mUP031[0m
[1;38;5;12m    |[0m
    [1;38;5;12m=[0m [1;38;5;14mhelp[0m: Replace with format specifiers

[1mversioneer.py[0m[36m:[0m328[36m:[0m17[36m:[0m [1;31mUP031[0m Use format specifiers instead of percent format
[1;38;5;12m    |[0m
[1;38;5;12m326 |[0m           if me_dir != vsr_dir:
[1;38;5;12m327 |[0m               print(
[1;38;5;12m328 |[0m                   "Warning: build in %s is using versioneer.py from %s"
[1;38;5;12m    |[0m  [1;38;5;9m_________________^[0m
[1;38;5;12m329 |[0m [1;38;5;9m|[0m                 % (os.path.dirname(my_path), versioneer_py)
[1;38;5;12m    |[0m [1;38;5;9m|[0m[1;38;5;9m___________________________________________________________^[0m [1;38;5;9mUP031[0m
[1;38;5;12m330 |[0m               )
[1;38;5;12m331 |[0m       except NameError:
[1;38;5;12m    |[0m
    [1;38;5;12m=[0m [1;38;5;14mhelp[0m: Replace with format specifiers

[1mversioneer.py[0m[36m:[0m1388[36m:[0m13[36m:[0m [1;31mUP031[0m Use format specifiers instead of percent format
[1;38;5;12m     |[0m
[1;38;5;12m1386 |[0m       if verbose:
[1;38;5;12m1387 |[0m           print(
[1;38;5;12m1388 |[0m               "Tried directories %s but none started with prefix %s"
[1;38;5;12m     |[0m  [1;38;5;9m_____________^[0m
[1;38;5;12m1389 |[0m [1;38;5;9m|[0m             % (str(rootdirs), parentdir_prefix)
[1;38;5;12m     |[0m [1;38;5;9m|[0m[1;38;5;9m_______________________________________________^[0m [1;38;5;9mUP031[0m
[1;38;5;12m1390 |[0m           )
[1;38;5;12m1391 |[0m       raise NotThisMethod("rootdir doesn't start with parentdir_prefix")
[1;38;5;12m     |[0m
     [1;38;5;12m=[0m [1;38;5;14mhelp[0m: Replace with format specifiers

Found 14 errors (8 fixed, 6 remaining).
No fixes available (6 hidden fixes can be enabled with the `--unsafe-fixes` option).

ruff-format..........................................................................[41mFailed[m
[2m- hook id: ruff-format[m
[2m- files were modified by this hook[m

2 files reformatted, 206 files left unchanged

pydocstyle...........................................................................[42mPassed[m
Disallow print statements............................................................[42mPassed[m
Check no tests are ignored...........................................................[42mPassed[m
Generate pip dependency from conda...................................................[42mPassed[m
No relative imports..................................................................[42mPassed[m
Check no links that should be cross-references are in the docs.......................[42mPassed[m
pre-commit hook(s) made changes.
If you are seeing this message in CI, reproduce locally with: `pre-commit run --all-files`.
To run `pre-commit` as part of git workflow, use `pre-commit install`.
All changes made by hooks:
[1mdiff --git a/pymc/gp/util.py b/pymc/gp/util.py[m
[1mindex 39eb3b6..3f829ab 100644[m
[1m--- a/pymc/gp/util.py[m
[1m+++ b/pymc/gp/util.py[m
[36m@@ -120,7 +120,7 @@[m [mdef kmeans_inducing_points(n_inducing, X, **kmeans_kwargs):[m
             "To use K-means initialization, "[m
             "please provide X as a type that "[m
             "can be cast to np.ndarray, instead "[m
[31m-            "of {}".format(type(X))[m
[32m+[m[32m            f"of {type(X)}"[m
         )[m
     scaling = np.std(X, 0)[m
     # if std of a column is very small (zero), don't normalize that column[m
[1mdiff --git a/pymc/sampling/population.py b/pymc/sampling/population.py[m
[1mindex 6dbe5cf..5ed98c0 100644[m
[1m--- a/pymc/sampling/population.py[m
[1m+++ b/pymc/sampling/population.py[m
[36m@@ -135,7 +135,7 @@[m [mdef warn_population_size([m
     if has_demcmc and chains <= initial_point_model_size:[m
         warnings.warn([m
             "DEMetropolis should be used with more chains than dimensions! "[m
[31m-            "(The model has {} dimensions.)".format(initial_point_model_size),[m
[32m+[m[32m            f"(The model has {initial_point_model_size} dimensions.)",[m
             UserWarning,[m
             stacklevel=2,[m
         )[m
[1mdiff --git a/pymc/step_methods/arraystep.py b/pymc/step_methods/arraystep.py[m
[1mindex 4c945ab..35f1443 100644[m
[1m--- a/pymc/step_methods/arraystep.py[m
[1m+++ b/pymc/step_methods/arraystep.py[m
[36m@@ -146,10 +146,8 @@[m [mclass PopulationArrayStepShared(ArrayStepShared):[m
         self.other_chains = [c for c in range(len(population)) if c != chain_index][m
         if not len(self.other_chains) > 1:[m
             raise ValueError([m
[31m-                "Population is just {} + {}. "[m
[31m-                "This is too small and the error should have been raised earlier.".format([m
[31m-                    self.this_chain, self.other_chains[m
[31m-                )[m
[32m+[m[32m                f"Population is just {self.this_chain} + {self.other_chains}. "[m
[32m+[m[32m                "This is too small and the error should have been raised earlier."[m
             )[m
         return[m
 [m
[1mdiff --git a/pymc/variational/inference.py b/pymc/variational/inference.py[m
[1mindex ce3bd02..6ee5815 100644[m
[1m--- a/pymc/variational/inference.py[m
[1m+++ b/pymc/variational/inference.py[m
[36m@@ -244,17 +244,11 @@[m [mclass Inference:[m
             if isinstance(e, StopIteration):[m
                 logger.info(str(e))[m
             if n < 10:[m
[31m-                logger.info([m
[31m-                    "Interrupted at {:,d} [{:.0f}%]: Loss = {:,.5g}".format([m
[31m-                        i, 100 * i // n, scores[i][m
[31m-                    )[m
[31m-                )[m
[32m+[m[32m                logger.info(f"Interrupted at {i:,d} [{100 * i // n:.0f}%]: Loss = {scores[i]:,.5g}")[m
             else:[m
                 avg_loss = _infmean(scores[min(0, i - 1000) : i + 1])[m
                 logger.info([m
[31m-                    "Interrupted at {:,d} [{:.0f}%]: Average Loss = {:,.5g}".format([m
[31m-                        i, 100 * i // n, avg_loss[m
[31m-                    )[m
[32m+[m[32m                    f"Interrupted at {i:,d} [{100 * i // n:.0f}%]: Average Loss = {avg_loss:,.5g}"[m
                 )[m
         else:[m
             if n == 0:[m
[1mdiff --git a/pymc/variational/opvi.py b/pymc/variational/opvi.py[m
[1mindex bd1874f..5d70575 100644[m
[1m--- a/pymc/variational/opvi.py[m
[1m+++ b/pymc/variational/opvi.py[m
[36m@@ -701,8 +701,8 @@[m [mclass Group(WithMemoization):[m
     def group_for_params(cls, params):[m
         if frozenset(params) not in cls.__param_registry:[m
             raise KeyError([m
[31m-                "No such group for the following params: {!r}, "[m
[31m-                "only the following are supported\n\n{}".format(params, cls.__param_registry)[m
[32m+[m[32m                f"No such group for the following params: {params!r}, "[m
[32m+[m[32m                f"only the following are supported\n\n{cls.__param_registry}"[m
             )[m
         return cls.__param_registry[frozenset(params)][m
 [m
[36m@@ -801,9 +801,7 @@[m [mclass Group(WithMemoization):[m
         if givens != needed:[m
             raise ParametrizationError([m
                 "Passed parameters do not have a needed set of keys, "[m
[31m-                "they should be equal, got {givens}, needed {needed}".format([m
[31m-                    givens=givens, needed=needed[m
[31m-                )[m
[32m+[m[32m                f"they should be equal, got {givens}, needed {needed}"[m
             )[m
         self._user_params = dict()[m
         spec = self.get_param_spec_for(d=self.ddim, **kwargs.pop("spec_kw", {}))[m
[1mdiff --git a/pymc/variational/updates.py b/pymc/variational/updates.py[m
[1mindex fa6e52b..4f46970 100644[m
[1m--- a/pymc/variational/updates.py[m
[1m+++ b/pymc/variational/updates.py[m
[36m@@ -1005,9 +1005,7 @@[m [mdef norm_constraint(tensor_var, max_norm, norm_axes=None, epsilon=1e-7):[m
     elif ndim in [3, 4, 5]:  # Conv{1,2,3}DLayer[m
         sum_over = tuple(range(1, ndim))[m
     else:[m
[31m-        raise ValueError([m
[31m-            "Unsupported tensor dimensionality {}." "Must specify `norm_axes`".format(ndim)[m
[31m-        )[m
[32m+[m[32m        raise ValueError(f"Unsupported tensor dimensionality {ndim}." "Must specify `norm_axes`")[m
 [m
     dtype = np.dtype(pytensor.config.floatX).type[m
     norms = pt.sqrt(pt.sum(pt.sqr(tensor_var), axis=sum_over, keepdims=True))[m
##[error]Process completed with exit code 1.


Changed files:
docs/source/contributing/python_style.md
pymc/_version.py
pymc/gp/util.py
pymc/sampling/population.py
pymc/step_methods/arraystep.py
pymc/step_methods/hmc/integration.py
pymc/variational/inference.py
pymc/variational/opvi.py
pymc/variational/updates.py
versioneer.py

Fix diff:
diff --git a/docs/source/contributing/python_style.md b/docs/source/contributing/python_style.md
index def33f053..5bb73d503 100644
--- a/docs/source/contributing/python_style.md
+++ b/docs/source/contributing/python_style.md
@@ -33,7 +33,7 @@ git commit -m "wip lol" --no-verify
 To skip one particular hook, you can set the `SKIP` environment variable. E.g. (on Linux):
 
 ```bash
-SKIP=pyupgrade git commit -m "<descriptive message>"
+SKIP=ruff git commit -m "<descriptive message>"
 ```
 
 You can manually run all `pre-commit` hooks on all files with
diff --git a/pymc/_version.py b/pymc/_version.py
index 24c8e98be..ebbf5a3a2 100644
--- a/pymc/_version.py
+++ b/pymc/_version.py
@@ -153,10 +153,7 @@ def versions_from_parentdir(parentdir_prefix, root, verbose):
         root = os.path.dirname(root)  # up a level
 
     if verbose:
-        print(
-            "Tried directories %s but none started with prefix %s"
-            % (str(rootdirs), parentdir_prefix)
-        )
+        print(f"Tried directories {str(rootdirs)} but none started with prefix {parentdir_prefix}")
     raise NotThisMethod("rootdir doesn't start with parentdir_prefix")
 
 
diff --git a/pymc/gp/util.py b/pymc/gp/util.py
index 39eb3b678..3f829ab00 100644
--- a/pymc/gp/util.py
+++ b/pymc/gp/util.py
@@ -120,7 +120,7 @@ def kmeans_inducing_points(n_inducing, X, **kmeans_kwargs):
             "To use K-means initialization, "
             "please provide X as a type that "
             "can be cast to np.ndarray, instead "
-            "of {}".format(type(X))
+            f"of {type(X)}"
         )
     scaling = np.std(X, 0)
     # if std of a column is very small (zero), don't normalize that column
diff --git a/pymc/sampling/population.py b/pymc/sampling/population.py
index 6dbe5cf90..5ed98c0a2 100644
--- a/pymc/sampling/population.py
+++ b/pymc/sampling/population.py
@@ -135,7 +135,7 @@ def warn_population_size(
     if has_demcmc and chains <= initial_point_model_size:
         warnings.warn(
             "DEMetropolis should be used with more chains than dimensions! "
-            "(The model has {} dimensions.)".format(initial_point_model_size),
+            f"(The model has {initial_point_model_size} dimensions.)",
             UserWarning,
             stacklevel=2,
         )
diff --git a/pymc/step_methods/arraystep.py b/pymc/step_methods/arraystep.py
index 4c945ab51..35f1443d8 100644
--- a/pymc/step_methods/arraystep.py
+++ b/pymc/step_methods/arraystep.py
@@ -146,10 +146,8 @@ class PopulationArrayStepShared(ArrayStepShared):
         self.other_chains = [c for c in range(len(population)) if c != chain_index]
         if not len(self.other_chains) > 1:
             raise ValueError(
-                "Population is just {} + {}. "
-                "This is too small and the error should have been raised earlier.".format(
-                    self.this_chain, self.other_chains
-                )
+                f"Population is just {self.this_chain} + {self.other_chains}. "
+                "This is too small and the error should have been raised earlier."
             )
         return
 
diff --git a/pymc/step_methods/hmc/integration.py b/pymc/step_methods/hmc/integration.py
index 8ca72ecc4..c8defa2e8 100644
--- a/pymc/step_methods/hmc/integration.py
+++ b/pymc/step_methods/hmc/integration.py
@@ -44,8 +44,8 @@ class CpuLeapfrogIntegrator:
         self._dtype = self._logp_dlogp_func.dtype
         if self._potential.dtype != self._dtype:
             raise ValueError(
-                "dtypes of potential (%s) and logp function (%s)"
-                "don't match." % (self._potential.dtype, self._dtype)
+                f"dtypes of potential ({self._potential.dtype}) and logp function ({self._dtype})"
+                "don't match."
             )
 
     def compute_state(self, q: RaveledVars, p: RaveledVars):
diff --git a/pymc/variational/inference.py b/pymc/variational/inference.py
index ce3bd02e2..6ee5815d1 100644
--- a/pymc/variational/inference.py
+++ b/pymc/variational/inference.py
@@ -244,17 +244,11 @@ class Inference:
             if isinstance(e, StopIteration):
                 logger.info(str(e))
             if n < 10:
-                logger.info(
-                    "Interrupted at {:,d} [{:.0f}%]: Loss = {:,.5g}".format(
-                        i, 100 * i // n, scores[i]
-                    )
-                )
+                logger.info(f"Interrupted at {i:,d} [{100 * i // n:.0f}%]: Loss = {scores[i]:,.5g}")
             else:
                 avg_loss = _infmean(scores[min(0, i - 1000) : i + 1])
                 logger.info(
-                    "Interrupted at {:,d} [{:.0f}%]: Average Loss = {:,.5g}".format(
-                        i, 100 * i // n, avg_loss
-                    )
+                    f"Interrupted at {i:,d} [{100 * i // n:.0f}%]: Average Loss = {avg_loss:,.5g}"
                 )
         else:
             if n == 0:
diff --git a/pymc/variational/opvi.py b/pymc/variational/opvi.py
index bd1874ffe..ae2e20ac8 100644
--- a/pymc/variational/opvi.py
+++ b/pymc/variational/opvi.py
@@ -458,8 +458,8 @@ class Operator:
         self.approx = approx
         if self.require_logq and not approx.has_logq:
             raise ExplicitInferenceError(
-                "%s requires logq, but %s does not implement it"
-                "please change inference method" % (self, approx)
+                f"{self} requires logq, but {approx} does not implement it"
+                "please change inference method"
             )
 
     inputs = property(lambda self: self.approx.inputs)
@@ -510,9 +510,7 @@ class Operator:
         return self.objective_class(self, f)
 
     def __str__(self):  # pragma: no cover
-        return "%(op)s[%(ap)s]" % dict(
-            op=self.__class__.__name__, ap=self.approx.__class__.__name__
-        )
+        return f"{self.__class__.__name__}[{self.approx.__class__.__name__}]"
 
 
 def collect_shared_to_list(params):
@@ -701,8 +699,8 @@ class Group(WithMemoization):
     def group_for_params(cls, params):
         if frozenset(params) not in cls.__param_registry:
             raise KeyError(
-                "No such group for the following params: {!r}, "
-                "only the following are supported\n\n{}".format(params, cls.__param_registry)
+                f"No such group for the following params: {params!r}, "
+                f"only the following are supported\n\n{cls.__param_registry}"
             )
         return cls.__param_registry[frozenset(params)]
 
@@ -801,9 +799,7 @@ class Group(WithMemoization):
         if givens != needed:
             raise ParametrizationError(
                 "Passed parameters do not have a needed set of keys, "
-                "they should be equal, got {givens}, needed {needed}".format(
-                    givens=givens, needed=needed
-                )
+                f"they should be equal, got {givens}, needed {needed}"
             )
         self._user_params = dict()
         spec = self.get_param_spec_for(d=self.ddim, **kwargs.pop("spec_kw", {}))
diff --git a/pymc/variational/updates.py b/pymc/variational/updates.py
index fa6e52b0e..4f46970d1 100644
--- a/pymc/variational/updates.py
+++ b/pymc/variational/updates.py
@@ -1005,9 +1005,7 @@ def norm_constraint(tensor_var, max_norm, norm_axes=None, epsilon=1e-7):
     elif ndim in [3, 4, 5]:  # Conv{1,2,3}DLayer
         sum_over = tuple(range(1, ndim))
     else:
-        raise ValueError(
-            "Unsupported tensor dimensionality {}." "Must specify `norm_axes`".format(ndim)
-        )
+        raise ValueError(f"Unsupported tensor dimensionality {ndim}." "Must specify `norm_axes`")
 
     dtype = np.dtype(pytensor.config.floatX).type
     norms = pt.sqrt(pt.sum(pt.sqr(tensor_var), axis=sum_over, keepdims=True))
diff --git a/versioneer.py b/versioneer.py
index cf8adcc9e..9c8f7b060 100644
--- a/versioneer.py
+++ b/versioneer.py
@@ -325,8 +325,7 @@ def get_root():
         vsr_dir = os.path.normcase(os.path.splitext(versioneer_py)[0])
         if me_dir != vsr_dir:
             print(
-                "Warning: build in %s is using versioneer.py from %s"
-                % (os.path.dirname(my_path), versioneer_py)
+                f"Warning: build in {os.path.dirname(my_path)} is using versioneer.py from {versioneer_py}"
             )
     except NameError:
         pass
@@ -1384,10 +1383,7 @@ def versions_from_parentdir(parentdir_prefix, root, verbose):
         root = os.path.dirname(root)  # up a level
 
     if verbose:
-        print(
-            "Tried directories %s but none started with prefix %s"
-            % (str(rootdirs), parentdir_prefix)
-        )
+        print(f"Tried directories {str(rootdirs)} but none started with prefix {parentdir_prefix}")
     raise NotThisMethod("rootdir doesn't start with parentdir_prefix")