pyproject.toml
Rama main · réplica de lectura del repositorio original.
# Packaging Scholion for PyPI.
#
# Two decisions worth explaining, because neither is obvious:
#
# 1. One dependency, and it is deliberate. Reading laboratory PDFs is not a
# side feature — for most people it is the first thing the tool does with
# their data, and `pdfplumber` is what does it. Declaring it means `pip
# install scholion` gives a working application.
#
# It used to be an extra, and the ingest code compensated by running
# `pip install pdfplumber` on its own when a PDF turned up — including with
# `--break-system-packages`. A project that promises nothing happens without
# the user's command must not install packages into their interpreter behind
# their back. Declared beats silent.
#
# `pysam` stays an extra: it needs compilation, it is platform-specific, and
# the genome path needs external tools (bcftools, samtools) anyway. Without
# it the built-in tabixlite works — slower, on the standard library.
#
# 2. The version is read from the VERSION file. That file is already the single
# source of truth for the changelog and for publication — there is no reason
# to keep a second one. `__version__` in `src/scholion/__init__.py` is not a
# constant: it comes from the metadata of the installed distribution, or, when
# running from the sources, from that same VERSION file.
[build-system]
requires = ["hatchling>=1.27"]
build-backend = "hatchling.build"
[project]
name = "scholion"
dynamic = ["version"]
description = "Local health insights for patients and clinicians: connect lab trends, genetics, prescriptions and wearable data"
readme = "README.md"
requires-python = ">=3.10"
# PEP 639: a licence expression plus the list of files. The code is Apache-2.0,
# but the curated knowledge base inside the package is CC BY 4.0, and both files,
# together with the required source notices, are obliged to travel in the
# distribution.
license = "Apache-2.0"
license-files = ["LICENSE", "LICENSE-DATA", "NOTICE", "ATTRIBUTION.md"]
# The e-mail belongs HERE, in the field the metadata standard has for it, and not
# in `[project.urls]`. PyPI rejects a `mailto:` there — «is not a valid url» — and
# it rejects it at UPLOAD, after the build, after `twine check` has passed, which
# is why two releases reached GitHub and neither reached PyPI.
authors = [{ name = "CrossRead", email = "scholion.dev@proton.me" }]
keywords = [
"genomics", "pharmacogenomics", "clinvar", "acmg", "cpic",
"polygenic-score", "laboratory", "wearables", "personal-health",
"second-opinion", "n-of-1",
]
# A `License ::` classifier is deliberately absent — PEP 639 prescribes the
# `license` field instead.
classifiers = [
"Development Status :: 4 - Beta",
"Environment :: Console",
"Environment :: Web Environment",
"Intended Audience :: End Users/Desktop",
"Intended Audience :: Healthcare Industry",
"Intended Audience :: Science/Research",
"Natural Language :: English",
"Natural Language :: Russian",
"Operating System :: MacOS",
"Operating System :: POSIX :: Linux",
# Added with the matrix cell that checks it, not before. Everything
# this package does by itself runs there; what needs a Unix machine
# is the OPTIONAL genome preparation in src/ingest — shell scripts
# driving bwa, samtools and mosdepth — and the tools it looks for
# are each behind a `which`, so their absence is reported rather
# than fatal. If the Windows cell goes red, this line comes out.
"Operating System :: Microsoft :: Windows",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
"Topic :: Scientific/Engineering :: Bio-Informatics",
"Topic :: Scientific/Engineering :: Medical Science Apps.",
]
# PDF extraction and, on Windows, the IANA database absent from the OS.
dependencies = [
# Lab PDFs are the first data most people load. See the note at the top.
"pdfplumber>=0.11",
"tzdata; sys_platform == 'win32'",
]
[project.optional-dependencies]
# Kept so that `pip install "scholion[pdf]"` from older instructions still works;
# pdfplumber is a plain dependency now, so this extra adds nothing.
pdf = []
# Fast VCF access. Without it the built-in tabixlite is used — slower, but on
# the standard library alone.
genome = ["pysam>=0.22"]
all = ["scholion[pdf,genome]"]
[project.scripts]
scholion = "scholion.cli:main"
# A second entry point over the same core: `crossread` — "read your sources
# against each other". The CLI takes the program name from whatever it was called
# as, so the help text reads correctly either way.
crossread = "scholion.cli:main"
[project.urls]
Homepage = "https://github.com/CrossRead/scholion"
Repository = "https://github.com/CrossRead/scholion"
Changelog = "https://github.com/CrossRead/scholion/blob/main/CHANGELOG.md"
Issues = "https://github.com/CrossRead/scholion/issues"
# Every value under [project.urls] must be a URL, and PyPI means it. The address
# itself now travels in `authors`, where it is metadata rather than a link; this
# points at the section of the README that explains what to write about and, more
# importantly, what NOT to send.
Contact = "https://github.com/CrossRead/scholion#contact"
[tool.hatch.version]
path = "VERSION"
pattern = "(?P<version>[^\\s]+)"
[tool.hatch.build.targets.wheel]
packages = ["src/scholion"]
# The same canonical readers serve source and installed commands. A wheel cannot
# rely on src/ingest beside the user's personal data directory.
[tool.hatch.build.targets.wheel.force-include]
"src/ingest/ingest_garmin.py" = "scholion/readers/ingest_garmin.py"
"src/ingest/ingest_whoop.py" = "scholion/readers/ingest_whoop.py"
# The sdist carries exactly what is needed for a reproducible build and for
# understanding the legal position. The personal directories (profile/, genome/)
# are not here and cannot be: they never reach git either.
# The tests and the checking tools travel in the sdist deliberately. The release
# gate requires running them INSIDE the unpacked artefact rather than in the
# repository: a green run at the author's end with a red one at the recipient's
# does not mean "verified", it means "the state of the artefact is unknown".
# Without tests/ and run_tests.sh such a run is impossible in principle.
[tool.hatch.build.targets.sdist]
include = [
"/.gitattributes",
"/docs",
"/src/scholion",
"/src/tools",
# The data-preparation scripts: the genome build guide points at them, and
# part of the test suite leans on them too (the n-of-1 maths lives in
# src/ingest/nof1.py). Without them the sdist builds fine and the run inside
# it dies on an import — which is what the gate caught on its first run.
"/src/ingest",
"/tests",
"/run_tests.sh",
"/README.md",
"/CHANGELOG.md",
"/CONTRIBUTING.md",
"/DISCLAIMER.md",
"/SECURITY.md",
"/THREAT_MODEL.md",
"/PRIVACY.md",
"/CITATION.cff",
"/ASSISTANT-RULES.md",
"/VERSION",
]
exclude = [
"**/__pycache__",
"**/*.pyc",
"**/.DS_Store",
]
# Lint — run in CI only (`.github/workflows/tests.yml`, job `lint`); the package
# itself still depends on nothing, and `run_tests.sh` asks nothing of the person
# who unpacked it. Rule set F (pyflakes): names used but never defined, imports
# never used, a name redefined before use. The first of these is the class that
# `set -u` catches in shell only when the branch runs — here it is caught on
# every push, whatever branch the name sits in.
[tool.ruff]
target-version = "py310"
[tool.ruff.lint]
select = ["F"]
[tool.ruff.lint.per-file-ignores]
# The engine package is a facade: it re-exports the names every face calls it by.
"src/scholion/engine/__init__.py" = ["F401"]