Skip to content
Snippets Groups Projects
Commit de4500dd authored by André Anjos's avatar André Anjos :speech_balloon:
Browse files

[doc] Improve documentation with pixi examples

parent a0662a82
No related branches found
No related tags found
1 merge request!33Full dev environment based on pixi-only
Pipeline #86292 passed
...@@ -8,54 +8,60 @@ ...@@ -8,54 +8,60 @@
Installation Installation
============== ==============
We support two installation modes, through pip_, or mamba_ (conda). Installation may follow one of three paths: deployment for CPU-only execution,
development, or mixed development/deployment with Nvidia CUDA support. Choose
the relevant tab for details on each of those installation paths.
.. tab:: CPU only deployment
.. tab:: pip Install using pip_, or your preferred Python project management solution (e.g.
uv_, rye_ or poetry_).
Stable, from PyPI: **Stable** release, from PyPI:
.. code:: sh .. code:: sh
pip install mednet pip install mednet
mednet info
Latest beta, from GitLab package registry: **Latest** development branch, from its git repository:
.. code:: sh .. code:: sh
pip install --pre --index-url https://gitlab.idiap.ch/api/v4/groups/software/-/packages/pypi/simple --extra-index-url https://pypi.org/simple mednet pip install git+https://gitlab.idiap.ch/biosignal/software/mednet@main
mednet info
.. tip::
To avoid long command-lines you may configure pip to define the indexes and
package search priorities as you like.
.. tab:: mamba/conda .. tab:: Development
Stable: Checkout the repository, and then use pixi_ to setup a full development
environment:
.. code:: sh .. code:: sh
mamba install -c https://www.idiap.ch/software/biosignal/conda -c conda-forge mednet git clone git@gitlab.idiap.ch:biosignal/software/mednet
pixi install --frozen
Latest beta: pixi run mednet info
.. code:: sh
mamba install -c https://www.idiap.ch/software/biosignal/conda/label/beta -c conda-forge mednet
.. tip:: .. tip::
To force-install Nvidia GPU support on Linux machines, execute: The ``--frozen`` flag will ensure that the latest lock-file available
with sources is used. If you'd like to update the lock-file to the
latest set of compatible dependencies, remove that option.
.. code:: sh
$ mamba install pytorch-gpu .. tab:: CUDA
# or, to force the Nvidia CUDA version (environments w/o Nvidia setup): Checkout the repository on a **CUDA-enabled machine**, then use pixi_ to
create a mixed deployment and development environment for the checkout:
.. code:: sh
$ CONDA_OVERRIDE_CUDA=12.0 mamba install 'pytorch-gpu=*=cuda118*' git clone git@gitlab.idiap.ch:biosignal/software/mednet
ln -s pixi-cuda.toml pixi.toml
rm -rf .pixi pixi.lock # clean-up any previous CPU-only install
pixi install
pixi run mednet info
.. _mednet.setup: .. _mednet.setup:
......
...@@ -12,7 +12,10 @@ ...@@ -12,7 +12,10 @@
.. _conda: https://conda.io .. _conda: https://conda.io
.. _python: http://www.python.org .. _python: http://www.python.org
.. _pip: https://pip.pypa.io/en/stable/ .. _pip: https://pip.pypa.io/en/stable/
.. _mamba: https://mamba.readthedocs.io/en/latest/index.html .. _uv: https://github.com/astral-sh/uv
.. _rye: https://github.com/astral-sh/rye
.. _poetry: https://python-poetry.org
.. _pixi: https://pixi.sh
.. _pytorch: https://pytorch.org .. _pytorch: https://pytorch.org
.. _lightning: https://lightning.ai .. _lightning: https://lightning.ai
......
...@@ -19,12 +19,6 @@ ...@@ -19,12 +19,6 @@
# $ ln -s pixi-cuda.toml pixi.toml # $ ln -s pixi-cuda.toml pixi.toml
# $ rm -rf .pixi pixi.lock # clean-up # $ rm -rf .pixi pixi.lock # clean-up
# $ pixi install # this will install all support libraries # $ pixi install # this will install all support libraries
# $ pixi run build # this may fail, see next
#
# If `pixi run build` does not work (in the case you are building on a machine
# w/o CUDA support), then do the following:
#
# $ uv pip install --no-build-isolation --no-deps --editable ../mednet
[project] [project]
name = "mednet" name = "mednet"
...@@ -58,10 +52,9 @@ pytorch-cuda = { version = "12.1.*", channel = "pytorch" } ...@@ -58,10 +52,9 @@ pytorch-cuda = { version = "12.1.*", channel = "pytorch" }
[host-dependencies] [host-dependencies]
hatch = "*" hatch = "*"
versioningit = "*" versioningit = "*"
uv = "*"
[system-requirements] [system-requirements]
cuda = "12.1" cuda = "12.1"
[tasks] [pypi-dependencies]
build = "uv pip install --no-build-isolation --no-deps --editable ../mednet" mednet = { path = ".", editable = true }
This diff is collapsed.
...@@ -101,6 +101,9 @@ versioningit = "*" ...@@ -101,6 +101,9 @@ versioningit = "*"
[tool.pixi.feature.self.pypi-dependencies] [tool.pixi.feature.self.pypi-dependencies]
mednet = { path = ".", editable = true } mednet = { path = ".", editable = true }
[tool.pixi.feature.self.tasks]
info = "mednet info"
[tool.pixi.feature.py311.dependencies] [tool.pixi.feature.py311.dependencies]
python = "~=3.11.0" python = "~=3.11.0"
...@@ -150,12 +153,15 @@ build = "hatch build" ...@@ -150,12 +153,15 @@ build = "hatch build"
check = "twine check dist/*" check = "twine check dist/*"
upload = "twine upload dist/*" upload = "twine upload dist/*"
[tool.pixi.feature.dev.dependencies]
pdbpp = "*"
[tool.pixi.environments] [tool.pixi.environments]
default = { features = [ "qa", "doc", "test", "py312", "self" ], solve-group = "prod-group" } default = { features = [ "qa", "doc", "test", "dev", "py312", "self" ], solve-group = "prod-group" }
qa-only = { features = ["qa", "py312"], solve-group = "prod-group" } qa-only = { features = ["qa", "py312"], solve-group = "prod-group" }
doc-only = { features = ["doc", "py312", "self"], solve-group = "prod-group" } doc-only = { features = ["doc", "py312", "self"], solve-group = "prod-group" }
test-only-312 = { features = ["test", "py312", "self"], solve-group = "prod-group" } test-only-312 = { features = ["test", "dev", "py312", "self"], solve-group = "prod-group" }
test-only-311 = { features = ["test", "py311", "self"] } test-only-311 = { features = ["test", "dev", "py311", "self"] }
build-only = { features = ["build", "py312"], solve-group = "prod-group" } build-only = { features = ["build", "py312"], solve-group = "prod-group" }
prod = { features = ["py312", "self"], solve-group = "prod-group" } prod = { features = ["py312", "self"], solve-group = "prod-group" }
......
...@@ -17,6 +17,7 @@ def cli(): ...@@ -17,6 +17,7 @@ def cli():
pass pass
cli.add_command(importlib.import_module("..info", package=__name__).info)
cli.add_command(importlib.import_module("..config", package=__name__).config) cli.add_command(importlib.import_module("..config", package=__name__).config)
cli.add_command( cli.add_command(
importlib.import_module("..database", package=__name__).database, importlib.import_module("..database", package=__name__).database,
......
# SPDX-FileCopyrightText: Copyright © 2024 Idiap Research Institute <contact@idiap.ch>
#
# SPDX-License-Identifier: GPL-3.0-or-later
import click
from clapper.click import verbosity_option
from clapper.logging import setup
logger = setup(__name__.split(".")[0], format="%(levelname)s: %(message)s")
@click.command(
epilog="""Examples:
1. Provide information about the current installation:
.. code:: sh
mednet info
""",
)
@verbosity_option(logger=logger, expose_value=False)
def info(
**_,
) -> None: # numpydoc ignore=PR01
"""Provide information about the current installation."""
import typing
from ..utils.rc import load_rc
from .database import _get_raw_databases
from .utils import execution_metadata
def _echo(left: str, right: str, color: str = "white") -> None:
s = [
click.style(left, bold=True),
click.style(": ", bold=True),
click.style(right, fg=color),
]
click.echo("".join(s))
m = execution_metadata()
c = load_rc()
_echo("mednet version", typing.cast(str, m["package-version"]), "green")
_echo("platform", typing.cast(str, m["platform"]), "yellow")
_echo(
"accelerators",
", ".join(typing.cast(list[str], m["accelerators"])),
"cyan",
)
if not c.path.exists():
_echo("configuration", f"{str(c.path)} [MISSING]", "white")
else:
_echo("configuration", str(c.path), "white")
dbs = _get_raw_databases()
click.secho("configured databases:", bold=True)
for k, v in dbs.items():
if "datadir" not in v:
# this database does not have a "datadir"
continue
if v["datadir"] is not None:
_echo(f" - {k} ({v['module']})", f"{v['datadir']}", "green")
else:
_echo(f" - {k} ({v['module']})", "NOT installed", "red")
click.secho("dependencies:", bold=True)
python = typing.cast(dict[str, str], m["python"])
_echo(
" - python",
f"{python['version']} ({python['path']})",
"white",
)
deps = typing.cast(dict[str, str], m["dependencies"])
for name, version in deps.items():
_echo(f" - {name}", version, "white")
...@@ -81,7 +81,9 @@ def device_properties( ...@@ -81,7 +81,9 @@ def device_properties(
return retval return retval
def execution_metadata() -> dict[str, int | float | str | dict[str, str]]: def execution_metadata() -> (
dict[str, int | float | str | dict[str, str] | list[str]]
):
"""Produce metadata concerning the running script, in the form of a """Produce metadata concerning the running script, in the form of a
dictionary. dictionary.
...@@ -101,6 +103,7 @@ def execution_metadata() -> dict[str, int | float | str | dict[str, str]]: ...@@ -101,6 +103,7 @@ def execution_metadata() -> dict[str, int | float | str | dict[str, str]]:
* ``command-line``: the command-line that is being run * ``command-line``: the command-line that is being run
* ``hostname``: machine hostname (e.g. ``localhost``) * ``hostname``: machine hostname (e.g. ``localhost``)
* ``platform``: machine platform (e.g. ``darwin``) * ``platform``: machine platform (e.g. ``darwin``)
* ``accelerator``: acceleration devices available (e.g. ``cuda``)
""" """
import importlib.metadata import importlib.metadata
...@@ -118,7 +121,7 @@ def execution_metadata() -> dict[str, int | float | str | dict[str, str]]: ...@@ -118,7 +121,7 @@ def execution_metadata() -> dict[str, int | float | str | dict[str, str]]:
# current date time, in ISO8610 format # current date time, in ISO8610 format
datetime = __import__("datetime").datetime.now().astimezone().isoformat() datetime = __import__("datetime").datetime.now().astimezone().isoformat()
# collects dependence information # collects dependency information
package_name = ( package_name = (
__package__.split(".")[0] if __package__ is not None else "unknown" __package__.split(".")[0] if __package__ is not None else "unknown"
) )
...@@ -150,10 +153,37 @@ def execution_metadata() -> dict[str, int | float | str | dict[str, str]]: ...@@ -150,10 +153,37 @@ def execution_metadata() -> dict[str, int | float | str | dict[str, str]]:
logger.debug(f"Error {e}") logger.debug(f"Error {e}")
pass pass
# checks if any acceleration device is present in the current platform
accelerators = [f"cpu ({torch.backends.cpu.get_cpu_capability()})"]
if torch.cuda.is_available() and torch.backends.cuda.is_built():
accelerators.append("cuda")
if torch.backends.cudnn.is_available():
accelerators.append("cudnn")
if torch.backends.mps.is_available():
accelerators.append("mps")
if torch.backends.mkl.is_available():
accelerators.append("mkl")
if torch.backends.mkldnn.is_available():
accelerators.append("mkldnn")
if torch.backends.openmp.is_available():
accelerators.append("openmp")
python = {
"version": ".".join([str(k) for k in sys.version_info[:3]]),
"path": sys.executable,
}
return { return {
"datetime": datetime, "datetime": datetime,
"package-name": package_name, "package-name": package_name,
"package-version": current_version, "package-version": current_version,
"python": python,
"dependencies": dependencies, "dependencies": dependencies,
"user": __import__("getpass").getuser(), "user": __import__("getpass").getuser(),
"conda-env": os.environ.get("CONDA_DEFAULT_ENV", ""), "conda-env": os.environ.get("CONDA_DEFAULT_ENV", ""),
...@@ -161,6 +191,7 @@ def execution_metadata() -> dict[str, int | float | str | dict[str, str]]: ...@@ -161,6 +191,7 @@ def execution_metadata() -> dict[str, int | float | str | dict[str, str]]:
"command-line": " ".join(args), "command-line": " ".join(args),
"hostname": __import__("platform").node(), "hostname": __import__("platform").node(),
"platform": sys.platform, "platform": sys.platform,
"accelerators": accelerators,
} }
......
...@@ -40,6 +40,26 @@ def _check_help(entry_point): ...@@ -40,6 +40,26 @@ def _check_help(entry_point):
assert result.output.startswith("Usage:") assert result.output.startswith("Usage:")
def test_info_help():
from mednet.scripts.info import info
_check_help(info)
def test_info():
from mednet.scripts.info import info
runner = CliRunner()
result = runner.invoke(info)
_assert_exit_0(result)
assert "platform:" in result.output
assert "accelerators:" in result.output
assert "version:" in result.output
assert "configured databases:" in result.output
assert "dependencies:" in result.output
assert "python:" in result.output
def test_config_help(): def test_config_help():
from mednet.scripts.config import config from mednet.scripts.config import config
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment