Files
app/backend/pyproject.toml
T
stroblme 77dd87f1b9
Docs / docs (push) Canceled after 0s
Playwright Tests / test-playwright (1, 2) (push) Canceled after 0s
Playwright Tests / test-playwright (2, 2) (push) Canceled after 0s
Playwright Tests / merge-reports (push) Canceled after 0s
pre-commit / pre-commit (push) Canceled after 0s
Test Backend / test-backend (push) Canceled after 0s
Compose Smoke Test / test-compose (push) Canceled after 0s
Publish / publish (push) Successful in 54s
Release v0.1.5
2026-09-02 22:47:33 +02:00

217 lines
8.0 KiB
TOML

[project]
name = "fluksio"
version = "0.1.5"
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",
]
# Named because this code imports them. Four of them — python-multipart,
# email-validator, jinja2 and httpx — also arrive inside `fastapi[standard]`,
# so those lines look redundant and install nothing extra; they are here so a
# direct import does not rest on somebody else's extra keeping its contents.
dependencies = [
"fastapi[standard]<1.0.0,>=0.114.2",
"pydantic>2.0",
"pydantic-settings<3.0.0,>=2.2.1",
"sqlmodel<1.0.0,>=0.0.21",
"alembic<2.0.0,>=1.12.1",
"httpx<1.0.0,>=0.25.1",
# `Form(...)` on the OAuth token endpoint, which fastapi refuses to build
# the route without.
"python-multipart<1.0.0,>=0.0.7",
# `EmailStr` on the user model, so it is read on every start — an address
# is what a user is identified by, whether or not mail is ever sent. The
# sending itself is the `server` extra.
"email-validator<3.0.0.0,>=2.1.0.post1",
# Only the mail templates use it, and only after `send_email` — but it
# comes with `fastapi[standard]` either way, so an extra would move a line
# rather than a package.
"jinja2<4.0.0,>=3.1.4",
# Sessions, the secrets file, and the keypair an agent's token is signed
# with.
"pyjwt<3.0.0,>=2.8.0",
"pwdlib[argon2,bcrypt]>=0.3.0",
"cryptography>=44.0.0",
# The state store and the work queue, and what a panel's config is read
# through.
"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",
# The `mlp` node, which is registered at boot. Kept out of the extras
# because a data-science environment has it already.
"numpy>=2.2.6",
# The `inject` node's cron. Imported where it is used, behind a message
# that cannot fire while this line is here.
"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, and textual is built on it — named
# anyway, because a command that imports it should say so.
"rich>=13",
# `fluksio serve` opens a dashboard with it at a terminal.
"textual>=1.0",
# That dashboard subscribes to the engine's event bus over the same socket
# the browser uses. It arrives under `fastapi[standard]` either way, and is
# named here because this code imports it.
"websockets>=13",
# The encrypted-payload half of web push (RFC 8291). It brings only
# cryptography, which is already here. `pywebpush` would do the signing and
# the request too, at the cost of `requests` *and* `aiohttp` — two HTTP
# stacks beside httpx, on a machine that may be a Raspberry Pi.
"http-ece>=1.2",
]
[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
# The web push payload encoder carries no annotations.
[[tool.mypy.overrides]]
module = ["http_ece"]
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/app.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