scripts/screenshots.py runs MeshTerm --demo in the emulator's session, with no window, and types its way to the main menu, the chat on Public, the paths of a message, and the map. It saves each screen for the terminal (80x24, drawn in Cascadia Mono with its own box, braille, and Powerline shapes), the Cardputer Zero, and the PicoCalc (the emulator's own raster, at 3x), into docs/screenshots/<set>/. Two runs give the same pixels: the clock is pinned to 11:42 on Thursday 15 October 2026 in Montréal (time-machine and TZ), and the demo device plays no background traffic during a capture (PLAY_BACKGROUND). Gabriel in Beloeil joins the demo, so the message shown in Message paths arrives on five paths through Mont-St-Hilaire, and the map opens at z10. Pillow, fontTools, and time-machine join the dev extras. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
142 lines
6.2 KiB
TOML
142 lines
6.2 KiB
TOML
[build-system]
|
|
# Hatchling 1.26 is the first version that writes the PEP 639 fields below
|
|
# (`License-Expression`, `License-File`) into the metadata. An older version builds a
|
|
# wheel that says nothing about the licence, and it gives no warning.
|
|
requires = ["hatchling>=1.26"]
|
|
build-backend = "hatchling.build"
|
|
|
|
[project]
|
|
# This is only the name of the distribution. The import package and the console script stay
|
|
# `meshterm`. PyPI prohibits that name (refer to pypi/support#12162), but the app does not
|
|
# change because of this. The `[tool.hatch.build.targets.wheel]` section below makes the
|
|
# wheel contain the `meshterm/` package under this different name.
|
|
name = "mesh-term"
|
|
dynamic = ["version"]
|
|
description = "MeshTerm is a full-featured TUI MeshCore client for your terminal. Connects to a companion over USB, Bluetooth, or TCP. For Windows, macOS, and Linux."
|
|
readme = "README.md"
|
|
requires-python = ">=3.10"
|
|
authors = [{ name = "Jean-Pierre Martineau" }]
|
|
license = "Apache-2.0"
|
|
license-files = ["LICENSE", "NOTICE"]
|
|
keywords = ["meshcore", "lora", "mesh", "radio", "cli"]
|
|
# There is no `License ::` entry, because PEP 639 does not permit one with the SPDX expression above.
|
|
classifiers = [
|
|
"Development Status :: 4 - Beta",
|
|
"Environment :: Console",
|
|
"Intended Audience :: End Users/Desktop",
|
|
"Operating System :: MacOS",
|
|
"Operating System :: Microsoft :: Windows",
|
|
"Operating System :: POSIX :: Linux",
|
|
"Programming Language :: Python :: 3.10",
|
|
"Programming Language :: Python :: 3.11",
|
|
"Programming Language :: Python :: 3.12",
|
|
"Programming Language :: Python :: 3.13",
|
|
"Programming Language :: Python :: 3.14",
|
|
"Programming Language :: Python :: 3.14",
|
|
"Topic :: Communications :: Ham Radio",
|
|
"Topic :: System :: Networking",
|
|
]
|
|
|
|
dependencies = [
|
|
"meshcore>=2.3", # companion-device protocol (serial/BLE/TCP)
|
|
"pycryptodome>=3.20", # AES/HMAC for decrypting overheard channel packets
|
|
"pyserial>=3.5", # serial-port enumeration for device discovery
|
|
"bleak>=0.22", # Bluetooth LE scanning + companion connection
|
|
"typer>=0.12", # scripted CLI. The subcommands mirror the menu
|
|
"rich>=13.7", # modern console rendering (progress, tables, panels)
|
|
"markdown-it-py>=3.0", # CommonMark parser behind the written About pages
|
|
"prompt_toolkit>=3.0", # full-screen interactive TUI (terminal, input, resize)
|
|
"segno>=1.6", # pure-Python QR codes (channel share links)
|
|
"tomli>=2.0; python_version < '3.11'", # TOML config reader on 3.10
|
|
"tomli-w>=1.0", # TOML writer: preferences and device-config backups
|
|
]
|
|
|
|
[project.optional-dependencies]
|
|
dev = [
|
|
"pytest>=8.0",
|
|
"pytest-asyncio>=0.23",
|
|
# The version is pinned to one minor line. A formatter that is different on different
|
|
# machines is not a gate. Ruff 0.16 formats Python inside Markdown and 0.15 does not.
|
|
# With an unpinned `ruff>=0.4`, CI and a laptop disagreed about a tree with no errors.
|
|
"ruff>=0.16.6,<0.17",
|
|
# The node of the SPI radio. tests/test_radionode_live.py runs it with a fake radio.
|
|
# The library alone is pure Python on all systems. Only the `hardware` extra needs Linux.
|
|
"openhop-core>=1.1.3",
|
|
# scripts/screenshots.py: it draws the screenshots of the website (Pillow, with the
|
|
# glyph tables of fontTools) at a fixed time on the clock (time-machine).
|
|
"pillow>=10.0",
|
|
"fonttools>=4.40",
|
|
"time-machine>=2.14",
|
|
]
|
|
# A LoRa chip on this machine's own SPI bus (the uConsole AIO). A node that MeshTerm runs
|
|
# itself controls it (refer to meshterm/core/spiradio.py). It works only on Linux, so
|
|
# the other systems do not need it.
|
|
spi = [
|
|
"openhop-core[hardware]>=1.1.3",
|
|
]
|
|
|
|
[project.urls]
|
|
Homepage = "https://github.com/jpmartineau/MeshTerm"
|
|
Repository = "https://github.com/jpmartineau/MeshTerm"
|
|
Issues = "https://github.com/jpmartineau/MeshTerm/issues"
|
|
Changelog = "https://github.com/jpmartineau/MeshTerm/blob/main/CHANGELOG.md"
|
|
|
|
[project.scripts]
|
|
meshterm = "meshterm.cli:main"
|
|
|
|
# This is the one place where we write the version. `[project] version` is dynamic, so the
|
|
# package attribute and the distribution metadata cannot become different.
|
|
[tool.hatch.version]
|
|
path = "meshterm/__init__.py"
|
|
|
|
[tool.hatch.build.targets.wheel]
|
|
packages = ["meshterm"]
|
|
|
|
# The sdist is the source of the package. It is not the source of the repository. It has
|
|
# what a person needs to build and test the wheel. By default, Hatchling includes each file
|
|
# that git does not ignore. This included the Claude skills, the GitHub configuration, the
|
|
# PyInstaller spec, the shell scripts for the device (one of which has data under another
|
|
# licence), and the template of the developer environment. None of these builds, tests, or
|
|
# documents the package. The sdist keeps the package, the tests and their fixture, the
|
|
# manual, and the files that a build reads.
|
|
[tool.hatch.build.targets.sdist]
|
|
exclude = [
|
|
"/.claude",
|
|
"/.github",
|
|
"/.dev.env.example",
|
|
"/.git-blame-ignore-revs",
|
|
"/.gitattributes",
|
|
"/CLAUDE.md",
|
|
"/docs/development/survey-*.md",
|
|
"/packaging",
|
|
"/scripts",
|
|
]
|
|
|
|
[tool.ruff]
|
|
line-length = 100
|
|
target-version = "py310"
|
|
# The helper scripts for the Claude skills are not part of the package. Also exclude `docs/`.
|
|
# It has survey documents with dates. Ruff formats Python blocks inside Markdown, and the
|
|
# code in these documents is an excerpt that shows how a file looked on a past date. If
|
|
# ruff formats a quotation, it changes the record. The excerpts are fragments of calls and
|
|
# not complete programs. Thus the formatter would change them into something that never
|
|
# existed.
|
|
extend-exclude = [".claude", "docs"]
|
|
|
|
[tool.ruff.lint]
|
|
select = ["E", "F", "I", "UP", "B", "D"]
|
|
ignore = ["D203", "D213"] # select one style for the blank line before a class and for the multi-line summary
|
|
|
|
[tool.ruff.lint.pydocstyle]
|
|
convention = "google"
|
|
|
|
[tool.ruff.lint.flake8-bugbear]
|
|
# Typer declares CLI parameters when the default value calls these functions. The objects
|
|
# that they return are inert markers, and the command never changes them. B008 guards
|
|
# against this kind of change.
|
|
extend-immutable-calls = ["typer.Argument", "typer.Option"]
|
|
|
|
[tool.pytest.ini_options]
|
|
asyncio_mode = "auto"
|
|
testpaths = ["tests"]
|