Files
app/backend/pyproject.toml
T
stroblmeandClaude Opus 5 a4ea1dd0d6 Open a dashboard when serve is run at a terminal
`fluksio serve` printed a log stream and nothing else, so watching an engine
meant a second terminal running `status --watch`, and stopping or pairing it
meant a third. At a terminal it now opens a dashboard: the health and flow
overview `status` draws, the recent runs as a table, and the engine's own
output in a pane below — which is what the earlier decision against this
was protecting, and it is still all there.

The engine is a child process running `serve --plain`, not a thread, so it
outlives the dashboard: q leaves it running and says so, s and r stop and
restart it, c cancels the selected run and e pairs with a portal. An engine
already serving this directory is adopted rather than duplicated, and it can
be stopped from here only because the pidfile and the token together prove
it is this installation's.

`--plain` and no terminal both keep the old behaviour, which is what the
container and CI run.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019Hra4ndWMCLU5F3KjUuVAc
2026-08-29 14:21:13 +02:00

184 lines
6.2 KiB
TOML

[project]
name = "fluksio"
version = "0.1.4+dev"
description = "Node-based automation engine: flows, dashboards, batch runs"
readme = "README.md"
license = "AGPL-3.0-or-later"
license-files = ["LICENSE"]
requires-python = ">=3.12"
authors = [{ name = "Fluksio", email = "stroblme@posteo.de" }]
keywords = ["automation", "workflow", "dataflow", "experiment-tracking", "mlops"]
classifiers = [
"Development Status :: 3 - Alpha",
"Intended Audience :: Developers",
"Intended Audience :: Science/Research",
"Operating System :: MacOS",
"Operating System :: POSIX :: Linux",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
"Topic :: Home Automation",
"Topic :: Scientific/Engineering",
"Topic :: System :: Distributed Computing",
]
dependencies = [
"fastapi[standard]<1.0.0,>=0.114.2",
"python-multipart<1.0.0,>=0.0.7",
"email-validator<3.0.0.0,>=2.1.0.post1",
"pydantic>2.0",
"jinja2<4.0.0,>=3.1.4",
"alembic<2.0.0,>=1.12.1",
"httpx<1.0.0,>=0.25.1",
"sqlmodel<1.0.0,>=0.0.21",
"pydantic-settings<3.0.0,>=2.2.1",
"pyjwt<3.0.0,>=2.8.0",
"pwdlib[argon2,bcrypt]>=0.3.0",
"numpy>=2.2.6",
"redis>=7.1.0",
# Every message costs a round trip's worth of encode and decode — state,
# the journal, the worker pipe. Engine-side only: `fluksio-worker` is
# copied onto other people's machines and stays dependency-free.
"orjson>=3.10",
"cryptography>=44.0.0",
"croniter>=1.3.0",
"mcp>=1.29,<2",
"fluksio-worker>=0.1,<0.2",
# The Modules screen installs node code's packages with it, into a venv of
# the user's own. Present in the image; a pip install would otherwise have
# to find one on PATH, and quietly fall back to the engine's interpreter.
"uv>=0.5",
# `fluksio status` draws with it. Already here underneath fastapi's CLI,
# named because a command that depends on it should say so.
"rich>=13",
# `fluksio serve` opens a dashboard with it at a terminal. Pure python and
# mostly rich underneath, which is already here.
"textual>=1.0",
]
[project.optional-dependencies]
# `fluksio export --format parquet` converts the exported rows with it. An
# extra rather than a dependency: csv and jsonl need nothing, and pyarrow is
# tens of megabytes for whoever wants dtypes kept.
parquet = ["pyarrow>=17"]
# What a deployment has and a laptop does not: the device connectors, outbound
# mail and error reporting. The engine, the CLI and every python node work
# without them — `pip install fluksio` in a data-science environment is the
# case this exists for, and lxml and the aiohttp stack are most of its wait.
# Each import is guarded and names this extra. The image installs it.
server = [
"emails<1.0,>=0.6",
"sentry-sdk[fastapi]>=2.20.0",
"aiomqtt>=2.0.0",
"influxdb-client[async]>=1.40.0",
]
[project.urls]
Homepage = "https://fluksio.com"
Documentation = "https://docs.fluksio.com"
"Getting started" = "https://docs.fluksio.com/getting-started/data-science/"
[project.scripts]
fluksio = "fluksio.cli:main"
[tool.uv.sources]
fluksio-worker = { workspace = true }
[dependency-groups]
dev = [
"pytest<8.0.0,>=7.4.3",
"mypy<2.0.0,>=1.8.0",
"ruff<1.0.0,>=0.2.2",
"prek>=0.2.24,<1.0.0",
"coverage<8.0.0,>=7.4.3",
]
[tool.hatch.build.targets.wheel]
packages = ["fluksio"]
# Named rather than excluded: this directory also holds a working tree's
# runtime data — `flow-data/` with the user venv in it — which is not source.
[tool.hatch.build.targets.sdist]
include = ["fluksio", "tests", "scripts", "alembic.ini", "pyproject.toml", "README.md"]
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
[tool.mypy]
strict = true
exclude = ["venv", ".venv", "alembic"]
# influxdb_client's Point builder carries no annotations; calling it is not a
# reason to stop checking the caller (fluksio/flow/nodes/influx.py).
untyped_calls_exclude = ["influxdb_client"]
# Every module is checked strictly. influxdb_client is typed but re-exports its
# names implicitly, which strict mode refuses to follow. (croniter, the other
# untyped dependency, is ignored at its two import sites.)
[[tool.mypy.overrides]]
module = ["influxdb_client"]
implicit_reexport = true
# The parquet extra. Not installed here, and the import that uses it is inside
# the try/except that says so.
[[tool.mypy.overrides]]
module = ["pyarrow", "pyarrow.*"]
ignore_missing_imports = true
[tool.ruff]
target-version = "py312"
exclude = ["alembic"]
[tool.ruff.lint]
select = [
"E", # pycodestyle errors
"W", # pycodestyle warnings
"F", # pyflakes
"I", # isort
"B", # flake8-bugbear
"C4", # flake8-comprehensions
"UP", # pyupgrade
"ARG001", # unused arguments in functions
"T201", # print statements are not allowed
]
ignore = [
"E501", # line too long, handled by black
"B008", # do not perform function calls in argument defaults
"W191", # indentation contains tabs
"B904", # Allow raising exceptions without from e, for HTTPException
]
[tool.ruff.lint.per-file-ignores]
# The node API's stubs carry the real signatures and raise; unused arguments
# are what a stub is.
"fluksio/__init__.py" = ["ARG001"]
# It talks to whoever ran it; that is what a command line is.
"fluksio/cli.py" = ["T201"]
"fluksio/sdk/cli.py" = ["T201"]
# What it prints is the line left in the terminal after the dashboard closes.
"fluksio/tui.py" = ["T201"]
# Node functions take `params` whether or not they use it — that is the
# contract the engine calls them with.
"fluksio/flow/nodes.py" = ["ARG001", "ARG002"]
"tests/flow/*" = ["ARG001"]
# Node functions declared for a test take the ports they declare, used or not.
"tests/sdk/*" = ["ARG001"]
# Printing is what this one is about: node code is user code, and `print` is
# how it says things.
"tests/flow/test_logs.py" = ["ARG001", "T201"]
[tool.ruff.lint.pyupgrade]
# Preserve types, even if a file imports `from __future__ import annotations`.
keep-runtime-typing = true
[tool.coverage.run]
source = ["fluksio"]
dynamic_context = "test_function"
[tool.coverage.report]
show_missing = true
sort = "-Cover"
[tool.coverage.html]
show_contexts = true