Repository: jd/pifpaf (language: python)

Issue:
pifpaf has a dependency on distutils (and current releases on pkg_resources as well) that are not installed by default on python 3.12 and above
pifpaf imports [distutils](https://github.com/jd/pifpaf/blob/d37bae254a627c0aef2e760b697336080193681f/pifpaf/drivers/__init__.py#L24)  and current release versions also import pkg_resources which was [removed here](https://github.com/jd/pifpaf/commit/16a22f67b993f0bb392877f76934bdc3ba463e2c) (but it's still on current pypi release 3.1.5)


both of these tools are no longer included in python virtual environments:

https://docs.python.org/3/whatsnew/3.12.html

> [gh-95299](https://github.com/python/cpython/issues/95299): Do not pre-install setuptools in virtual environments created with [venv](https://docs.python.org/3/library/venv.html#module-venv). This means that distutils, setuptools, pkg_resources, and easy_install will no longer available by default; to access these run pip install setuptools in the [activated](https://docs.python.org/3/library/venv.html#venv-explanation) virtual environment.


the simple solution is to add setuptools as a dependency.   alternatively, remove the use of distutils


I can't easily demonstrate the distutils failure installing from github master due to #177 , unless you modify setup.cfg to also install drivers, it then looks like this:

```
(.venv) [classic@framework pifpaf:add_valkey]$ pip install .
Processing /home/classic/dev/pifpaf
  Installing build dependencies ... done
  Getting requirements to build wheel ... done
  Preparing metadata (pyproject.toml) ... done
Collecting daiquiri (from pifpaf==3.1.6.dev47+ge7251a1.d20240808)
  Using cached daiquiri-3.2.5.1-py3-none-any.whl.metadata (1.6 kB)
Collecting click (from pifpaf==3.1.6.dev47+ge7251a1.d20240808)
  Using cached click-8.1.7-py3-none-any.whl.metadata (3.0 kB)
Collecting jinja2 (from pifpaf==3.1.6.dev47+ge7251a1.d20240808)
  Using cached jinja2-3.1.4-py3-none-any.whl.metadata (2.6 kB)
Collecting fixtures (from pifpaf==3.1.6.dev47+ge7251a1.d20240808)
  Using cached fixtures-4.1.0-py3-none-any.whl.metadata (21 kB)
Collecting packaging (from pifpaf==3.1.6.dev47+ge7251a1.d20240808)
  Using cached packaging-24.1-py3-none-any.whl.metadata (3.2 kB)
Collecting psutil (from pifpaf==3.1.6.dev47+ge7251a1.d20240808)
  Using cached psutil-6.0.0-cp36-abi3-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl.metadata (21 kB)
Collecting xattr (from pifpaf==3.1.6.dev47+ge7251a1.d20240808)
  Using cached xattr-1.1.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl.metadata (3.8 kB)
Collecting python-json-logger (from daiquiri->pifpaf==3.1.6.dev47+ge7251a1.d20240808)
  Using cached python_json_logger-2.0.7-py3-none-any.whl.metadata (6.5 kB)
Collecting pbr>=5.7.0 (from fixtures->pifpaf==3.1.6.dev47+ge7251a1.d20240808)
  Using cached pbr-6.0.0-py2.py3-none-any.whl.metadata (1.3 kB)
Collecting MarkupSafe>=2.0 (from jinja2->pifpaf==3.1.6.dev47+ge7251a1.d20240808)
  Using cached MarkupSafe-2.1.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.metadata (3.0 kB)
Collecting cffi>=1.16.0 (from xattr->pifpaf==3.1.6.dev47+ge7251a1.d20240808)
  Using cached cffi-1.17.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.metadata (1.5 kB)
Collecting pycparser (from cffi>=1.16.0->xattr->pifpaf==3.1.6.dev47+ge7251a1.d20240808)
  Using cached pycparser-2.22-py3-none-any.whl.metadata (943 bytes)
Using cached click-8.1.7-py3-none-any.whl (97 kB)
Using cached daiquiri-3.2.5.1-py3-none-any.whl (19 kB)
Using cached fixtures-4.1.0-py3-none-any.whl (64 kB)
Using cached jinja2-3.1.4-py3-none-any.whl (133 kB)
Using cached packaging-24.1-py3-none-any.whl (53 kB)
Using cached psutil-6.0.0-cp36-abi3-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl (290 kB)
Using cached xattr-1.1.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl (39 kB)
Using cached cffi-1.17.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (479 kB)
Using cached MarkupSafe-2.1.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (28 kB)
Using cached pbr-6.0.0-py2.py3-none-any.whl (107 kB)
Using cached python_json_logger-2.0.7-py3-none-any.whl (8.1 kB)
Using cached pycparser-2.22-py3-none-any.whl (117 kB)
Building wheels for collected packages: pifpaf
  Building wheel for pifpaf (pyproject.toml) ... done
  Created wheel for pifpaf: filename=pifpaf-3.1.6.dev47+ge7251a1.d20240808-py3-none-any.whl size=61472 sha256=4646f6c6d5e10e7b6fc5c7d0a96164a316be1f0e9772578c51168701b5fb055d
  Stored in directory: /tmp/pip-ephem-wheel-cache-2nk31oob/wheels/6a/5c/ed/c42abf20db70490f731c7550eee38a8793ca115412ab3a65fb
Successfully built pifpaf
Installing collected packages: python-json-logger, pycparser, psutil, pbr, packaging, MarkupSafe, click, jinja2, fixtures, daiquiri, cffi, xattr, pifpaf
Successfully installed MarkupSafe-2.1.5 cffi-1.17.0 click-8.1.7 daiquiri-3.2.5.1 fixtures-4.1.0 jinja2-3.1.4 packaging-24.1 pbr-6.0.0 pifpaf-3.1.6.dev47+ge7251a1.d20240808 psutil-6.0.0 pycparser-2.22 python-json-logger-2.0.7 xattr-1.1.0

[notice] A new release of pip is available: 24.1.2 -> 24.2
[notice] To update, run: pip install --upgrade pip
(.venv) [classic@framework pifpaf:add_valkey]$ cd ~/tmp/
(.venv) [classic@framework tmp]$ pifpaf run redis
CRITICAL [root] Traceback (most recent call last):
  File "/home/classic/tmp/.venv/bin/pifpaf", line 8, in <module>
    sys.exit(run_main())
             ^^^^^^^^^^
  File "/home/classic/tmp/.venv/lib/python3.12/site-packages/pifpaf/__main__.py", line 299, in run_main
    return main.main(standalone_mode=False)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/classic/tmp/.venv/lib/python3.12/site-packages/click/core.py", line 1078, in main
    rv = self.invoke(ctx)
         ^^^^^^^^^^^^^^^^
  File "/home/classic/tmp/.venv/lib/python3.12/site-packages/click/core.py", line 1688, in invoke
    return _process_result(sub_ctx.command.invoke(sub_ctx))
                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/classic/tmp/.venv/lib/python3.12/site-packages/click/core.py", line 1682, in invoke
    cmd_name, cmd, args = self.resolve_command(ctx, args)
                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/classic/tmp/.venv/lib/python3.12/site-packages/click/core.py", line 1729, in resolve_command
    cmd = self.get_command(ctx, cmd_name)
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/classic/tmp/.venv/lib/python3.12/site-packages/pifpaf/__main__.py", line 133, in get_command
    plugin = [e for e in DAEMONS if e.name == name][0].load()
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib64/python3.12/importlib/metadata/__init__.py", line 205, in load
    module = import_module(match.group('module'))
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib64/python3.12/importlib/__init__.py", line 90, in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "<frozen importlib._bootstrap>", line 1387, in _gcd_import
  File "<frozen importlib._bootstrap>", line 1360, in _find_and_load
  File "<frozen importlib._bootstrap>", line 1310, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 488, in _call_with_frames_removed
  File "<frozen importlib._bootstrap>", line 1387, in _gcd_import
  File "<frozen importlib._bootstrap>", line 1360, in _find_and_load
  File "<frozen importlib._bootstrap>", line 1331, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 935, in _load_unlocked
  File "<frozen importlib._bootstrap_external>", line 995, in exec_module
  File "<frozen importlib._bootstrap>", line 488, in _call_with_frames_removed
  File "/home/classic/tmp/.venv/lib/python3.12/site-packages/pifpaf/drivers/__init__.py", line 24, in <module>
    from distutils import spawn
ModuleNotFoundError: No module named 'distutils'


```

an  install from pypi fails on pkg_resources instead, we have to have setuptools in our tox dependencies to work around this:

```
[classic@framework tmp]$ python -m venv .venv
[classic@framework tmp]$ .venv/bin/pip install pifpaf
Collecting pifpaf
  Using cached pifpaf-3.1.5-py3-none-any.whl.metadata (7.0 kB)
Collecting daiquiri (from pifpaf)
  Using cached daiquiri-3.2.5.1-py3-none-any.whl.metadata (1.6 kB)
Collecting click (from pifpaf)
  Using cached click-8.1.7-py3-none-any.whl.metadata (3.0 kB)
Collecting pbr (from pifpaf)
  Using cached pbr-6.0.0-py2.py3-none-any.whl.metadata (1.3 kB)
Collecting jinja2 (from pifpaf)
  Using cached jinja2-3.1.4-py3-none-any.whl.metadata (2.6 kB)
Collecting fixtures (from pifpaf)
  Using cached fixtures-4.1.0-py3-none-any.whl.metadata (21 kB)
Collecting psutil (from pifpaf)
  Using cached psutil-6.0.0-cp36-abi3-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl.metadata (21 kB)
Collecting xattr (from pifpaf)
  Using cached xattr-1.1.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl.metadata (3.8 kB)
Collecting python-json-logger (from daiquiri->pifpaf)
  Using cached python_json_logger-2.0.7-py3-none-any.whl.metadata (6.5 kB)
Collecting MarkupSafe>=2.0 (from jinja2->pifpaf)
  Using cached MarkupSafe-2.1.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.metadata (3.0 kB)
Collecting cffi>=1.16.0 (from xattr->pifpaf)
  Using cached cffi-1.17.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.metadata (1.5 kB)
Collecting pycparser (from cffi>=1.16.0->xattr->pifpaf)
  Using cached pycparser-2.22-py3-none-any.whl.metadata (943 bytes)
Using cached pifpaf-3.1.5-py3-none-any.whl (62 kB)
Using cached click-8.1.7-py3-none-any.whl (97 kB)
Using cached daiquiri-3.2.5.1-py3-none-any.whl (19 kB)
Using cached fixtures-4.1.0-py3-none-any.whl (64 kB)
Using cached pbr-6.0.0-py2.py3-none-any.whl (107 kB)
Using cached jinja2-3.1.4-py3-none-any.whl (133 kB)
Using cached psutil-6.0.0-cp36-abi3-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl (290 kB)
Using cached xattr-1.1.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl (39 kB)
Using cached cffi-1.17.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (479 kB)
Using cached MarkupSafe-2.1.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (28 kB)
Using cached python_json_logger-2.0.7-py3-none-any.whl (8.1 kB)
Using cached pycparser-2.22-py3-none-any.whl (117 kB)
Installing collected packages: python-json-logger, pycparser, psutil, pbr, MarkupSafe, click, jinja2, fixtures, daiquiri, cffi, xattr, pifpaf
Successfully installed MarkupSafe-2.1.5 cffi-1.17.0 click-8.1.7 daiquiri-3.2.5.1 fixtures-4.1.0 jinja2-3.1.4 pbr-6.0.0 pifpaf-3.1.5 psutil-6.0.0 pycparser-2.22 python-json-logger-2.0.7 xattr-1.1.0

[notice] A new release of pip is available: 23.3.2 -> 24.2
[notice] To update, run: python3.12 -m pip install --upgrade pip
[classic@framework tmp]$ .venv/bin/pifpaf run redis
Traceback (most recent call last):
  File "/home/classic/tmp/.venv/bin/pifpaf", line 5, in <module>
    from pifpaf.__main__ import run_main
  File "/home/classic/tmp/.venv/lib64/python3.12/site-packages/pifpaf/__main__.py", line 31, in <module>
    import pkg_resources
ModuleNotFoundError: No module named 'pkg_resources'
```
setup.cfg is not functional for current pypa tooling
setup.cfg contains only the "pifpaf" module as an install:

https://github.com/jd/pifpaf/blob/d37bae254a627c0aef2e760b697336080193681f/setup.cfg#L21-L24

I'm not sure of this history of this but this fails to install "drivers", both from a pip install from github, as well as if I do a "python setup.py sdist" the drivers are missing when you do the actual install

demo one, install from master:

```
[classic@framework tmp]$ python -V
Python 3.12.4
[classic@framework tmp]$ python -m venv .venv
[classic@framework tmp]$ .venv/bin/pip install git+https://github.com/jd/pifpaf/
Collecting git+https://github.com/jd/pifpaf/
  Cloning https://github.com/jd/pifpaf/ to /tmp/pip-req-build-8tgv063q
  Running command git clone --filter=blob:none --quiet https://github.com/jd/pifpaf/ /tmp/pip-req-build-8tgv063q
  Resolved https://github.com/jd/pifpaf/ to commit d37bae254a627c0aef2e760b697336080193681f
  Installing build dependencies ... done
  Getting requirements to build wheel ... done
  Preparing metadata (pyproject.toml) ... done
Collecting daiquiri (from pifpaf==3.1.6.dev46+gd37bae2)
  Using cached daiquiri-3.2.5.1-py3-none-any.whl.metadata (1.6 kB)
Collecting click (from pifpaf==3.1.6.dev46+gd37bae2)
  Using cached click-8.1.7-py3-none-any.whl.metadata (3.0 kB)
Collecting jinja2 (from pifpaf==3.1.6.dev46+gd37bae2)
  Using cached jinja2-3.1.4-py3-none-any.whl.metadata (2.6 kB)
Collecting fixtures (from pifpaf==3.1.6.dev46+gd37bae2)
  Using cached fixtures-4.1.0-py3-none-any.whl.metadata (21 kB)
Collecting packaging (from pifpaf==3.1.6.dev46+gd37bae2)
  Using cached packaging-24.1-py3-none-any.whl.metadata (3.2 kB)
Collecting psutil (from pifpaf==3.1.6.dev46+gd37bae2)
  Using cached psutil-6.0.0-cp36-abi3-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl.metadata (21 kB)
Collecting xattr (from pifpaf==3.1.6.dev46+gd37bae2)
  Using cached xattr-1.1.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl.metadata (3.8 kB)
Collecting python-json-logger (from daiquiri->pifpaf==3.1.6.dev46+gd37bae2)
  Using cached python_json_logger-2.0.7-py3-none-any.whl.metadata (6.5 kB)
Collecting pbr>=5.7.0 (from fixtures->pifpaf==3.1.6.dev46+gd37bae2)
  Using cached pbr-6.0.0-py2.py3-none-any.whl.metadata (1.3 kB)
Collecting MarkupSafe>=2.0 (from jinja2->pifpaf==3.1.6.dev46+gd37bae2)
  Using cached MarkupSafe-2.1.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.metadata (3.0 kB)
Collecting cffi>=1.16.0 (from xattr->pifpaf==3.1.6.dev46+gd37bae2)
  Using cached cffi-1.17.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.metadata (1.5 kB)
Collecting pycparser (from cffi>=1.16.0->xattr->pifpaf==3.1.6.dev46+gd37bae2)
  Using cached pycparser-2.22-py3-none-any.whl.metadata (943 bytes)
Using cached click-8.1.7-py3-none-any.whl (97 kB)
Using cached daiquiri-3.2.5.1-py3-none-any.whl (19 kB)
Using cached fixtures-4.1.0-py3-none-any.whl (64 kB)
Using cached jinja2-3.1.4-py3-none-any.whl (133 kB)
Using cached packaging-24.1-py3-none-any.whl (53 kB)
Using cached psutil-6.0.0-cp36-abi3-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl (290 kB)
Using cached xattr-1.1.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl (39 kB)
Using cached cffi-1.17.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (479 kB)
Using cached MarkupSafe-2.1.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (28 kB)
Using cached pbr-6.0.0-py2.py3-none-any.whl (107 kB)
Using cached python_json_logger-2.0.7-py3-none-any.whl (8.1 kB)
Using cached pycparser-2.22-py3-none-any.whl (117 kB)
Building wheels for collected packages: pifpaf
  Building wheel for pifpaf (pyproject.toml) ... done
  Created wheel for pifpaf: filename=pifpaf-3.1.6.dev46+gd37bae2-py3-none-any.whl size=10519 sha256=6048c96e4578c2b1bd8fe300b630cb6d982e11e39e087520db796dbd0b0ce9a3
  Stored in directory: /tmp/pip-ephem-wheel-cache-3o3uyqfv/wheels/21/51/37/1f567de3e004a4469dc2c2da83baf62eef0247babfac0f6cdd
Successfully built pifpaf
Installing collected packages: python-json-logger, pycparser, psutil, pbr, packaging, MarkupSafe, click, jinja2, fixtures, daiquiri, cffi, xattr, pifpaf
Successfully installed MarkupSafe-2.1.5 cffi-1.17.0 click-8.1.7 daiquiri-3.2.5.1 fixtures-4.1.0 jinja2-3.1.4 packaging-24.1 pbr-6.0.0 pifpaf-3.1.6.dev46+gd37bae2 psutil-6.0.0 pycparser-2.22 python-json-logger-2.0.7 xattr-1.1.0

[notice] A new release of pip is available: 23.3.2 -> 24.2
[notice] To update, run: python3.12 -m pip install --upgrade pip
[classic@framework tmp]$ .venv/bin/pifpaf run redis
CRITICAL [root] Traceback (most recent call last):
  File "/home/classic/tmp/.venv/bin/pifpaf", line 8, in <module>
    sys.exit(run_main())
             ^^^^^^^^^^
  File "/home/classic/tmp/.venv/lib64/python3.12/site-packages/pifpaf/__main__.py", line 299, in run_main
    return main.main(standalone_mode=False)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/classic/tmp/.venv/lib64/python3.12/site-packages/click/core.py", line 1078, in main
    rv = self.invoke(ctx)
         ^^^^^^^^^^^^^^^^
  File "/home/classic/tmp/.venv/lib64/python3.12/site-packages/click/core.py", line 1688, in invoke
    return _process_result(sub_ctx.command.invoke(sub_ctx))
                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/classic/tmp/.venv/lib64/python3.12/site-packages/click/core.py", line 1682, in invoke
    cmd_name, cmd, args = self.resolve_command(ctx, args)
                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/classic/tmp/.venv/lib64/python3.12/site-packages/click/core.py", line 1729, in resolve_command
    cmd = self.get_command(ctx, cmd_name)
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/classic/tmp/.venv/lib64/python3.12/site-packages/pifpaf/__main__.py", line 133, in get_command
    plugin = [e for e in DAEMONS if e.name == name][0].load()
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib64/python3.12/importlib/metadata/__init__.py", line 205, in load
    module = import_module(match.group('module'))
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib64/python3.12/importlib/__init__.py", line 90, in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "<frozen importlib._bootstrap>", line 1387, in _gcd_import
  File "<frozen importlib._bootstrap>", line 1360, in _find_and_load
  File "<frozen importlib._bootstrap>", line 1310, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 488, in _call_with_frames_removed
  File "<frozen importlib._bootstrap>", line 1387, in _gcd_import
  File "<frozen importlib._bootstrap>", line 1360, in _find_and_load
  File "<frozen importlib._bootstrap>", line 1324, in _find_and_load_unlocked
ModuleNotFoundError: No module named 'pifpaf.drivers'

```


demo two, python setup.py sdist .  it seems to put the drivers into the tar.gz but they still dont install

```
[classic@framework tmp]$ git clone https://github.com/jd/pifpaf/
Cloning into 'pifpaf'...
remote: Enumerating objects: 2349, done.
remote: Counting objects: 100% (304/304), done.
remote: Compressing objects: 100% (129/129), done.
remote: Total 2349 (delta 182), reused 270 (delta 170), pack-reused 2045
Receiving objects: 100% (2349/2349), 802.70 KiB | 8.82 MiB/s, done.
Resolving deltas: 100% (1554/1554), done.
[classic@framework tmp]$ cd pifpaf/
[classic@framework pifpaf:master]$ python setup.py  sdist
running sdist
running egg_info
creating pifpaf.egg-info
writing pifpaf.egg-info/PKG-INFO
writing dependency_links to pifpaf.egg-info/dependency_links.txt
writing entry points to pifpaf.egg-info/entry_points.txt
writing requirements to pifpaf.egg-info/requires.txt
writing top-level names to pifpaf.egg-info/top_level.txt
writing manifest file 'pifpaf.egg-info/SOURCES.txt'
adding license file 'LICENSE'
writing manifest file 'pifpaf.egg-info/SOURCES.txt'
running check
creating pifpaf-3.1.6.dev46+gd37bae2
creating pifpaf-3.1.6.dev46+gd37bae2/.github
creating pifpaf-3.1.6.dev46+gd37bae2/.github/workflows
creating pifpaf-3.1.6.dev46+gd37bae2/pifpaf
creating pifpaf-3.1.6.dev46+gd37bae2/pifpaf.egg-info
creating pifpaf-3.1.6.dev46+gd37bae2/pifpaf/drivers
creating pifpaf-3.1.6.dev46+gd37bae2/pifpaf/drivers/templates
creating pifpaf-3.1.6.dev46+gd37bae2/pifpaf/drivers/templates/artemis
creating pifpaf-3.1.6.dev46+gd37bae2/pifpaf/drivers/templates/qdrouterd
creating pifpaf-3.1.6.dev46+gd37bae2/pifpaf/drivers/templates/swift
creating pifpaf-3.1.6.dev46+gd37bae2/pifpaf/tests
copying files to pifpaf-3.1.6.dev46+gd37bae2...
copying .dockerignore -> pifpaf-3.1.6.dev46+gd37bae2
copying .gitignore -> pifpaf-3.1.6.dev46+gd37bae2
copying .mergify.yml -> pifpaf-3.1.6.dev46+gd37bae2
copying .stestr.conf -> pifpaf-3.1.6.dev46+gd37bae2
copying Dockerfile -> pifpaf-3.1.6.dev46+gd37bae2
copying LICENSE -> pifpaf-3.1.6.dev46+gd37bae2
copying README.rst -> pifpaf-3.1.6.dev46+gd37bae2
copying pifpaf.jpg -> pifpaf-3.1.6.dev46+gd37bae2
copying pyproject.toml -> pifpaf-3.1.6.dev46+gd37bae2
copying setup.cfg -> pifpaf-3.1.6.dev46+gd37bae2
copying setup.py -> pifpaf-3.1.6.dev46+gd37bae2
copying tox.ini -> pifpaf-3.1.6.dev46+gd37bae2
copying .github/workflows/pifpaf-ci-image.yaml -> pifpaf-3.1.6.dev46+gd37bae2/.github/workflows
copying .github/workflows/pifpaf.yaml -> pifpaf-3.1.6.dev46+gd37bae2/.github/workflows
copying pifpaf/__init__.py -> pifpaf-3.1.6.dev46+gd37bae2/pifpaf
copying pifpaf/__main__.py -> pifpaf-3.1.6.dev46+gd37bae2/pifpaf
copying pifpaf/util.py -> pifpaf-3.1.6.dev46+gd37bae2/pifpaf
copying pifpaf.egg-info/PKG-INFO -> pifpaf-3.1.6.dev46+gd37bae2/pifpaf.egg-info
copying pifpaf.egg-info/SOURCES.txt -> pifpaf-3.1.6.dev46+gd37bae2/pifpaf.egg-info
copying pifpaf.egg-info/dependency_links.txt -> pifpaf-3.1.6.dev46+gd37bae2/pifpaf.egg-info
copying pifpaf.egg-info/entry_points.txt -> pifpaf-3.1.6.dev46+gd37bae2/pifpaf.egg-info
copying pifpaf.egg-info/requires.txt -> pifpaf-3.1.6.dev46+gd37bae2/pifpaf.egg-info
copying pifpaf.egg-info/top_level.txt -> pifpaf-3.1.6.dev46+gd37bae2/pifpaf.egg-info
copying pifpaf/drivers/__init__.py -> pifpaf-3.1.6.dev46+gd37bae2/pifpaf/drivers
copying pifpaf/drivers/aodh.py -> pifpaf-3.1.6.dev46+gd37bae2/pifpaf/drivers
copying pifpaf/drivers/artemis.py -> pifpaf-3.1.6.dev46+gd37bae2/pifpaf/drivers
copying pifpaf/drivers/ceph.py -> pifpaf-3.1.6.dev46+gd37bae2/pifpaf/drivers
copying pifpaf/drivers/consul.py -> pifpaf-3.1.6.dev46+gd37bae2/pifpaf/drivers
copying pifpaf/drivers/couchdb.py -> pifpaf-3.1.6.dev46+gd37bae2/pifpaf/drivers
copying pifpaf/drivers/elasticsearch.py -> pifpaf-3.1.6.dev46+gd37bae2/pifpaf/drivers
copying pifpaf/drivers/etcd.py -> pifpaf-3.1.6.dev46+gd37bae2/pifpaf/drivers
copying pifpaf/drivers/fakes3.py -> pifpaf-3.1.6.dev46+gd37bae2/pifpaf/drivers
copying pifpaf/drivers/gnocchi.py -> pifpaf-3.1.6.dev46+gd37bae2/pifpaf/drivers
copying pifpaf/drivers/httpbin.py -> pifpaf-3.1.6.dev46+gd37bae2/pifpaf/drivers
copying pifpaf/drivers/influxdb.py -> pifpaf-3.1.6.dev46+gd37bae2/pifpaf/drivers
copying pifpaf/drivers/kafka.py -> pifpaf-3.1.6.dev46+gd37bae2/pifpaf/drivers
copying pifpaf/drivers/keystone.py -> pifpaf-3.1.6.dev46+gd37bae2/pifpaf/drivers
copying pifpaf/drivers/memcached.py -> pifpaf-3.1.6.dev46+gd37bae2/pifpaf/drivers
copying pifpaf/drivers/mongodb.py -> pifpaf-3.1.6.dev46+gd37bae2/pifpaf/drivers
copying pifpaf/drivers/mysql.py -> pifpaf-3.1.6.dev46+gd37bae2/pifpaf/drivers
copying pifpaf/drivers/postgresql.py -> pifpaf-3.1.6.dev46+gd37bae2/pifpaf/drivers
copying pifpaf/drivers/qdrouterd.py -> pifpaf-3.1.6.dev46+gd37bae2/pifpaf/drivers
copying pifpaf/drivers/rabbitmq.py -> pifpaf-3.1.6.dev46+gd37bae2/pifpaf/drivers
copying pifpaf/drivers/redis.py -> pifpaf-3.1.6.dev46+gd37bae2/pifpaf/drivers
copying pifpaf/drivers/s3rver.py -> pifpaf-3.1.6.dev46+gd37bae2/pifpaf/drivers
copying pifpaf/drivers/swift.py -> pifpaf-3.1.6.dev46+gd37bae2/pifpaf/drivers
copying pifpaf/drivers/vault.py -> pifpaf-3.1.6.dev46+gd37bae2/pifpaf/drivers
copying pifpaf/drivers/zookeeper.py -> pifpaf-3.1.6.dev46+gd37bae2/pifpaf/drivers
copying pifpaf/drivers/templates/artemis/broker.xml -> pifpaf-3.1.6.dev46+gd37bae2/pifpaf/drivers/templates/artemis
copying pifpaf/drivers/templates/qdrouterd/broker_om.conf.inc -> pifpaf-3.1.6.dev46+gd37bae2/pifpaf/drivers/templates/qdrouterd
copying pifpaf/drivers/templates/qdrouterd/direct_om.conf.inc -> pifpaf-3.1.6.dev46+gd37bae2/pifpaf/drivers/templates/qdrouterd
copying pifpaf/drivers/templates/qdrouterd/qdrouterd.conf -> pifpaf-3.1.6.dev46+gd37bae2/pifpaf/drivers/templates/qdrouterd
copying pifpaf/drivers/templates/qdrouterd/sasl_qdrouterd.conf -> pifpaf-3.1.6.dev46+gd37bae2/pifpaf/drivers/templates/qdrouterd
copying pifpaf/drivers/templates/swift/account.conf -> pifpaf-3.1.6.dev46+gd37bae2/pifpaf/drivers/templates/swift
copying pifpaf/drivers/templates/swift/common.conf.inc -> pifpaf-3.1.6.dev46+gd37bae2/pifpaf/drivers/templates/swift
copying pifpaf/drivers/templates/swift/container-sync-realms.conf -> pifpaf-3.1.6.dev46+gd37bae2/pifpaf/drivers/templates/swift
copying pifpaf/drivers/templates/swift/container.conf -> pifpaf-3.1.6.dev46+gd37bae2/pifpaf/drivers/templates/swift
copying pifpaf/drivers/templates/swift/object.conf -> pifpaf-3.1.6.dev46+gd37bae2/pifpaf/drivers/templates/swift
copying pifpaf/drivers/templates/swift/proxy.conf -> pifpaf-3.1.6.dev46+gd37bae2/pifpaf/drivers/templates/swift
copying pifpaf/drivers/templates/swift/sitecustomize.py -> pifpaf-3.1.6.dev46+gd37bae2/pifpaf/drivers/templates/swift
copying pifpaf/drivers/templates/swift/swift.conf -> pifpaf-3.1.6.dev46+gd37bae2/pifpaf/drivers/templates/swift
copying pifpaf/tests/__init__.py -> pifpaf-3.1.6.dev46+gd37bae2/pifpaf/tests
copying pifpaf/tests/test_cli.py -> pifpaf-3.1.6.dev46+gd37bae2/pifpaf/tests
copying pifpaf/tests/test_drivers.py -> pifpaf-3.1.6.dev46+gd37bae2/pifpaf/tests
copying pifpaf/tests/unkillable.py -> pifpaf-3.1.6.dev46+gd37bae2/pifpaf/tests
copying pifpaf.egg-info/SOURCES.txt -> pifpaf-3.1.6.dev46+gd37bae2/pifpaf.egg-info
Writing pifpaf-3.1.6.dev46+gd37bae2/setup.cfg
creating dist
Creating tar archive
removing 'pifpaf-3.1.6.dev46+gd37bae2' (and everything under it)
[classic@framework pifpaf:master]$ cd ..
[classic@framework tmp]$ python -m venv .venv
[classic@framework tmp]$ .venv/bin/pip install pifpaf/dist/pifpaf-3.1.6.dev46+gd37bae2.tar.gz 
Processing ./pifpaf/dist/pifpaf-3.1.6.dev46+gd37bae2.tar.gz
  Installing build dependencies ... done
  Getting requirements to build wheel ... done
  Preparing metadata (pyproject.toml) ... done
Collecting daiquiri (from pifpaf==3.1.6.dev46+gd37bae2)
  Using cached daiquiri-3.2.5.1-py3-none-any.whl.metadata (1.6 kB)
Collecting click (from pifpaf==3.1.6.dev46+gd37bae2)
  Using cached click-8.1.7-py3-none-any.whl.metadata (3.0 kB)
Collecting jinja2 (from pifpaf==3.1.6.dev46+gd37bae2)
  Using cached jinja2-3.1.4-py3-none-any.whl.metadata (2.6 kB)
Collecting fixtures (from pifpaf==3.1.6.dev46+gd37bae2)
  Using cached fixtures-4.1.0-py3-none-any.whl.metadata (21 kB)
Collecting packaging (from pifpaf==3.1.6.dev46+gd37bae2)
  Using cached packaging-24.1-py3-none-any.whl.metadata (3.2 kB)
Collecting psutil (from pifpaf==3.1.6.dev46+gd37bae2)
  Using cached psutil-6.0.0-cp36-abi3-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl.metadata (21 kB)
Collecting xattr (from pifpaf==3.1.6.dev46+gd37bae2)
  Using cached xattr-1.1.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl.metadata (3.8 kB)
Collecting python-json-logger (from daiquiri->pifpaf==3.1.6.dev46+gd37bae2)
  Using cached python_json_logger-2.0.7-py3-none-any.whl.metadata (6.5 kB)
Collecting pbr>=5.7.0 (from fixtures->pifpaf==3.1.6.dev46+gd37bae2)
  Using cached pbr-6.0.0-py2.py3-none-any.whl.metadata (1.3 kB)
Collecting MarkupSafe>=2.0 (from jinja2->pifpaf==3.1.6.dev46+gd37bae2)
  Using cached MarkupSafe-2.1.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.metadata (3.0 kB)
Collecting cffi>=1.16.0 (from xattr->pifpaf==3.1.6.dev46+gd37bae2)
  Using cached cffi-1.17.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.metadata (1.5 kB)
Collecting pycparser (from cffi>=1.16.0->xattr->pifpaf==3.1.6.dev46+gd37bae2)
  Using cached pycparser-2.22-py3-none-any.whl.metadata (943 bytes)
Using cached click-8.1.7-py3-none-any.whl (97 kB)
Using cached daiquiri-3.2.5.1-py3-none-any.whl (19 kB)
Using cached fixtures-4.1.0-py3-none-any.whl (64 kB)
Using cached jinja2-3.1.4-py3-none-any.whl (133 kB)
Using cached packaging-24.1-py3-none-any.whl (53 kB)
Using cached psutil-6.0.0-cp36-abi3-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl (290 kB)
Using cached xattr-1.1.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl (39 kB)
Using cached cffi-1.17.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (479 kB)
Using cached MarkupSafe-2.1.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (28 kB)
Using cached pbr-6.0.0-py2.py3-none-any.whl (107 kB)
Using cached python_json_logger-2.0.7-py3-none-any.whl (8.1 kB)
Using cached pycparser-2.22-py3-none-any.whl (117 kB)
Building wheels for collected packages: pifpaf
  Building wheel for pifpaf (pyproject.toml) ... done
  Created wheel for pifpaf: filename=pifpaf-3.1.6.dev46+gd37bae2-py3-none-any.whl size=10519 sha256=a8030ad6260456dedce24a7a5679d4500b16430f1a41f572d72f7927b259f45a
  Stored in directory: /home/classic/.cache/pip/wheels/f7/24/4c/72741e04e537b6069a46b88f898ac9110b9a031c6b0f7a91fb
Successfully built pifpaf
Installing collected packages: python-json-logger, pycparser, psutil, pbr, packaging, MarkupSafe, click, jinja2, fixtures, daiquiri, cffi, xattr, pifpaf
Successfully installed MarkupSafe-2.1.5 cffi-1.17.0 click-8.1.7 daiquiri-3.2.5.1 fixtures-4.1.0 jinja2-3.1.4 packaging-24.1 pbr-6.0.0 pifpaf-3.1.6.dev46+gd37bae2 psutil-6.0.0 pycparser-2.22 python-json-logger-2.0.7 xattr-1.1.0

[notice] A new release of pip is available: 23.3.2 -> 24.2
[notice] To update, run: python3.12 -m pip install --upgrade pip
[classic@framework tmp]$ .venv/bin/pifpaf run redis
CRITICAL [root] Traceback (most recent call last):
  File "/home/classic/tmp/.venv/bin/pifpaf", line 8, in <module>
    sys.exit(run_main())
             ^^^^^^^^^^
  File "/home/classic/tmp/.venv/lib64/python3.12/site-packages/pifpaf/__main__.py", line 299, in run_main
    return main.main(standalone_mode=False)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/classic/tmp/.venv/lib64/python3.12/site-packages/click/core.py", line 1078, in main
    rv = self.invoke(ctx)
         ^^^^^^^^^^^^^^^^
  File "/home/classic/tmp/.venv/lib64/python3.12/site-packages/click/core.py", line 1688, in invoke
    return _process_result(sub_ctx.command.invoke(sub_ctx))
                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/classic/tmp/.venv/lib64/python3.12/site-packages/click/core.py", line 1682, in invoke
    cmd_name, cmd, args = self.resolve_command(ctx, args)
                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/classic/tmp/.venv/lib64/python3.12/site-packages/click/core.py", line 1729, in resolve_command
    cmd = self.get_command(ctx, cmd_name)
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/classic/tmp/.venv/lib64/python3.12/site-packages/pifpaf/__main__.py", line 133, in get_command
    plugin = [e for e in DAEMONS if e.name == name][0].load()
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib64/python3.12/importlib/metadata/__init__.py", line 205, in load
    module = import_module(match.group('module'))
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib64/python3.12/importlib/__init__.py", line 90, in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "<frozen importlib._bootstrap>", line 1387, in _gcd_import
  File "<frozen importlib._bootstrap>", line 1360, in _find_and_load
  File "<frozen importlib._bootstrap>", line 1310, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 488, in _call_with_frames_removed
  File "<frozen importlib._bootstrap>", line 1387, in _gcd_import
  File "<frozen importlib._bootstrap>", line 1360, in _find_and_load
  File "<frozen importlib._bootstrap>", line 1324, in _find_and_load_unlocked
ModuleNotFoundError: No module named 'pifpaf.drivers'

```


Discussion / hints:

Fix patch:
diff --git a/README.rst b/README.rst
index 39b2d16..e9cee1f 100644
--- a/README.rst
+++ b/README.rst
@@ -24,6 +24,7 @@ Pifpaf currently supports:
 * `InfluxDB`_
 * `Etcd`_ (with clustering)
 * `Redis`_ (with sentinel mode)
+* `Valkey`_
 * `Elasticsearch`_
 * `ZooKeeper`_
 * `Gnocchi`_
@@ -47,6 +48,7 @@ Pifpaf currently supports:
 .. _InfluxDB: http://influxdb.org
 .. _Etcd: https://coreos.com/etcd/
 .. _Redis: http://redis.io/
+.. _Valkey: https://valkey.io/
 .. _Elasticsearch: https://www.elastic.co/
 .. _ZooKeeper: https://zookeeper.apache.org/
 .. _Gnocchi: http://gnocchi.xyz
diff --git a/pifpaf/drivers/valkey.py b/pifpaf/drivers/valkey.py
new file mode 100644
index 0000000..07f7511
--- /dev/null
+++ b/pifpaf/drivers/valkey.py
@@ -0,0 +1,90 @@
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import os
+
+from pifpaf import drivers
+
+
+class ValkeyDriver(drivers.Driver):
+
+    DEFAULT_PORT = 6379
+    DEFAULT_PORT_SENTINEL = 6380
+    DEFAULT_PASSWORD = ''
+
+    def __init__(self, port=DEFAULT_PORT,
+                 sentinel=False, sentinel_port=DEFAULT_PORT_SENTINEL,
+                 password=DEFAULT_PASSWORD, **kwargs):
+        """Create a new Valkey server."""
+        super(ValkeyDriver, self).__init__(**kwargs)
+        self.port = port
+        self.sentinel = sentinel
+        self.sentinel_port = sentinel_port
+        self.password = password
+
+    @classmethod
+    def get_options(cls):
+        return [
+            {"param_decls": ["--port"],
+             "type": int,
+             "default": cls.DEFAULT_PORT,
+             "help": "port to use for Valkey"},
+            {"param_decls": ["--sentinel"],
+             "is_flag": True,
+             "help": "activate Valkey sentinel"},
+            {"param_decls": ["--sentinel-port"],
+             "type": int,
+             "default": cls.DEFAULT_PORT_SENTINEL,
+             "help": "port to use for Valkey sentinel"},
+            {"param_decls": ["--password"],
+             "default": cls.DEFAULT_PASSWORD,
+             "help": "Valkey and Valkey sentinel password"},
+        ]
+
+    def _setUp(self):
+        super(ValkeyDriver, self)._setUp()
+        valkey_conf = """dir %s
+port %d
+""" % (self.tempdir, self.port)
+        if self.password:
+            valkey_conf += "requirepass %s\n" % self.password
+        c, _ = self._exec(
+            ["valkey-server", "-"],
+            stdin=(valkey_conf).encode('ascii'),
+            wait_for_line="eady to accept connections")
+
+        if self.sentinel:
+            cfg = os.path.join(self.tempdir, "valkey-sentinel.conf")
+            sentinel_conf = """dir %s
+port %d
+sentinel monitor pifpaf localhost %d 1
+""" % (self.tempdir, self.sentinel_port, self.port)
+            if self.password:
+                sentinel_conf += (
+                    "sentinel auth-pass pifpaf %s\n" % self.password)
+                sentinel_conf += "requirepass %s\n" % self.password
+            with open(cfg, "w") as f:
+                f.write(sentinel_conf)
+
+            c, _ = self._exec(
+                ["valkey-sentinel", cfg],
+                wait_for_line=r"# Sentinel (runid|ID) is")
+
+            self.addCleanup(self._kill, c)
+
+            self.putenv("VALKEY_SENTINEL_PORT",
+                        str(self.sentinel_port))
+
+        self.putenv("VALKEY_PORT", str(self.port))
+        self.url = "valkey://localhost:%d" % self.port
+        self.putenv("URL", self.url)
diff --git a/setup.cfg b/setup.cfg
index 0818a22..c19fc1a 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -66,6 +66,7 @@ pifpaf.daemons =
     qdrouterd = pifpaf.drivers.qdrouterd:QdrouterdDriver
     rabbitmq = pifpaf.drivers.rabbitmq:RabbitMQDriver
     redis = pifpaf.drivers.redis:RedisDriver
+    valkey = pifpaf.drivers.valkey:ValkeyDriver
     s3rver = pifpaf.drivers.s3rver:S3rverDriver
     zookeeper = pifpaf.drivers.zookeeper:ZooKeeperDriver
     vault = pifpaf.drivers.vault:VaultDriver


Test patch:
diff --git a/pifpaf/tests/test_drivers.py b/pifpaf/tests/test_drivers.py
index 80a159c..9dcf8d6 100644
--- a/pifpaf/tests/test_drivers.py
+++ b/pifpaf/tests/test_drivers.py
@@ -49,6 +49,7 @@
 from pifpaf.drivers import redis
 from pifpaf.drivers import s3rver
 from pifpaf.drivers import swift
+from pifpaf.drivers import valkey
 from pifpaf.drivers import vault
 from pifpaf.drivers import zookeeper
 
@@ -309,6 +310,52 @@ def test_redis_sentinel_with_password(self):
                   f.sentinel_port)
         self._run("redis-cli -p %d -a secrete llen pifpaf" % f.port)
 
+    @testtools.skipUnless(shutil.which("valkey-server"),
+                          "valkey-server not found")
+    def test_valkey(self):
+        port = 6384
+        f = self.useFixture(valkey.ValkeyDriver(port=port))
+        self.assertEqual("valkey://localhost:%d" % port,
+                         os.getenv("PIFPAF_URL"))
+        self.assertEqual(str(port), os.getenv("PIFPAF_VALKEY_PORT"))
+        self._run("valkey-cli -p %d llen pifpaf" % f.port)
+
+    @testtools.skipUnless(shutil.which("valkey-server"),
+                          "valkey-server not found")
+    def test_valkey_with_password(self):
+        port = 6384
+        f = self.useFixture(valkey.ValkeyDriver(port=port, password='secrete'))
+        self.assertEqual("valkey://localhost:%d" % port,
+                         os.getenv("PIFPAF_URL"))
+        self.assertEqual(str(port), os.getenv("PIFPAF_VALKEY_PORT"))
+        self._run("valkey-cli -p %d -a secrete llen pifpaf" % f.port)
+
+    @testtools.skipUnless(shutil.which("valkey-sentinel"),
+                          "valkey-sentinel not found")
+    def test_valkey_sentinel(self):
+        port = 6385
+        f = self.useFixture(valkey.ValkeyDriver(sentinel=True, port=port))
+        self.assertEqual("valkey://localhost:%d" % port,
+                         os.getenv("PIFPAF_URL"))
+        self.assertEqual(str(port), os.getenv("PIFPAF_VALKEY_PORT"))
+        self.assertEqual("6380", os.getenv("PIFPAF_VALKEY_SENTINEL_PORT"))
+        self._run("valkey-cli -p %d sentinel master pifpaf" % f.sentinel_port)
+        self._run("valkey-cli -p %d llen pifpaf" % f.port)
+
+    @testtools.skipUnless(shutil.which("valkey-sentinel"),
+                          "valkey-sentinel not found")
+    def test_valkey_sentinel_with_password(self):
+        port = 6385
+        f = self.useFixture(valkey.ValkeyDriver(sentinel=True, port=port,
+                                                password='secrete'))
+        self.assertEqual("valkey://localhost:%d" % port,
+                         os.getenv("PIFPAF_URL"))
+        self.assertEqual(str(port), os.getenv("PIFPAF_VALKEY_PORT"))
+        self.assertEqual("6380", os.getenv("PIFPAF_VALKEY_SENTINEL_PORT"))
+        self._run("valkey-cli -p %d -a secrete sentinel master pifpaf" %
+                  f.sentinel_port)
+        self._run("valkey-cli -p %d -a secrete llen pifpaf" % f.port)
+
     @testtools.skipUnless(shutil.which(
         "zkServer.sh", path=":".join(zookeeper.ZooKeeperDriver.PATH)),
         "ZooKeeper not found")