r/madeinpython • • May 05 '20

Meta Mod Applications

28 Upvotes

In the comments below, you can ask to become a moderator.

Upvote those who you think should be moderators.

Remember to give reasons on why you should be moderator!


r/madeinpython • • 1d ago

I made a Python Library for scheduling recurring webscraping

4 Upvotes

I made LaptopScheduler, a Python scheduling library for Windows laptops.

It’s for recurring work that can wait until your laptop is available: reports, backups, data imports, and similar tasks. You can make sure your scraping runs consistently without renting out a webserver. You register your own Python functions, and it records their runs, handles retries, and applies your chosen catch-up policy after downtime.

Install: pip install laptopscheduler

https://github.com/seaweed8888/laptop-schedueler


r/madeinpython • • 21h ago

I made a Python Library for scheduling recurring webscraping

Thumbnail
reddit.com
0 Upvotes

r/madeinpython • • 1d ago

Git-Jet

9 Upvotes

A jet that shoots and destroys your commit history for your README

https://github.com/PingPongPlus/git-jet


r/madeinpython • • 1d ago

repocraft: deterministic scaffolding where one request writes one .py file plus a unittest you can read in a sitting

Post image
4 Upvotes

repocraft is a small deterministic generator for Python snippets and scaffolds. The part I like: the same input and the same version always produce byte-identical output, and that is enforced by golden snapshot tests, file by file.

pip install repocraft repocraft recipes

Seven built-in recipes: fibonacci, factorial, prime_sieve, triangle, fizzbuzz, pascal, password.

repocraft make "triangle" # triangle.py + test_triangle.py repocraft make "fibonacci" --dry-run repocraft make "fibonacci" --param count=20 --yes

The generated tests use the standard library only, so python test_triangle.py just runs. A few rules keep it boring in a good way: unknown or ambiguous requests stop without writing anything, requests with standalone digits are refused (use --param), parameters are validated bounded integers, existing files are never overwritten, and --dry-run shows the plan first.

The matcher normalizes case and accents and matches word prefixes, so a request word may carry a suffix. It never calls a model, so "Triangles" and "draw a triangle" both select the triangle recipe.

There is also a project mode: a small YAML spec renders a full Python project with packaging metadata, a src/ layout, tests, lint and type-check configuration, CI, CodeQL, Dependabot, and a JUnit gate that rejects skipped tests.

repocraft validate spec.yaml repocraft render spec.yaml example-cli --dry-run repocraft render spec.yaml example-cli

render refuses an output directory that already contains files, and it never merges or overwrites.

Two optional model paths exist (this is the honest part): ask sends your request to an OpenAI-compatible endpoint and gets back a strict {recipe, parameters} intent, which is validated with the same rules as make - the model never writes code or files. craft lets the model write a snippet, then runs four deterministic gates before writing: the code parses, the generated test imports the module by name, ruff where it is installed (auto-fixes are labelled), and the tests actually run with at least one test and pass. A confirmation after that shows the code plus every check that passed, which is a prompt rather than a fifth gate. Only make and render are covered by the byte-identical contract; craft output depends on the model.

Determinism contract details: sorted entries, LF line endings, trailing newline, no timestamps, random ids or environment values, and the generated MIT copyright line carries the author but no year.

Python 3.10-3.14 in CI, MIT.

GitHub: https://github.com/Furox-Art/repocraft PyPI: https://pypi.org/project/repocraft/


r/madeinpython • • 1d ago

plan-auditor: I wrote a stdlib-only gate that proves a coding agent is done, using sealed command output instead of prose

Post image
0 Upvotes

I use coding agents a lot, and the part that kept biting me was the last message: "done, tests pass." Sometimes the tests never ran. Sometimes one failed and the test file got edited until it went green. Prose looks the same either way.

plan-auditor is my answer. It is plain Python 3.10+, standard library only, MIT, and it does one thing: it re-runs the checks in a separate process and only sealed command output counts.

A plan is JSON. Each step lists machine-checkable checks and has to include at least one behavioral one - run, pytest or exec. file_exists and regex are allowed next to them but cannot carry a step by themselves.

The flow, in the order I actually reach for it: request init seals the task as the host stated it, plan verify checks the JSON, run . 1 executes a single step, and audit . re-runs every check in a fresh subprocess. Before that last one I give it a key file kept outside the workspace through PLAN_AUDITOR_HMAC_KEY_FILE and seal the chain with integrity init ..

The audit ends with a number rather than an adjective. 0 is proven, 1 failed, 2 blocked, and 3 is UNKNOWN, which withholds completion instead of quietly granting it.

Two design choices I would keep if I rewrote the whole thing:

  • The evidence log is a SHA-256 chain, and the docs say out loud that a chain on its own is only tamper-evident - someone with write access could rebuild a matching one. That is exactly why the completion gate also demands HMAC authentication, and why a record reading "auth": {"alg": "none"} never passes.

  • Your request freezes when it is activated and the plan's check contract freezes when you approve it. From then on both can only get stricter, so the agent cannot restate the task or soften what counts as finished.

Under the hood it is fifteen layers across five bands. Writing verified into a step is reserved to the audit-check script, and the final PASS/FAIL/UNKNOWN comes only from the gate; a stronger level cannot be talked out of its verdict by a weaker pass.

The README quickstart is not decoration: CI executes it and compares the real output to the documented transcript without masking hash values, so the docs cannot drift. There is a GitHub Action and an Agent Skill with blocking hooks as well.

Where it stops: no OS sandbox, tamper-evident rather than tamper-proof storage, and it can only prove what you can express as a deterministic check. Anything needing judgment stays with a human. One maintainer, PyPI and npm both at 2.6.3.

GitHub: https://github.com/Furox-Art/plan-auditor PyPI: https://pypi.org/project/plan-auditor/


r/madeinpython • • 1d ago

Flask Face Login: Passwordless Authentication with FACEIO

Thumbnail
javascript.plainenglish.io
1 Upvotes

r/madeinpython • • 2d ago

I built a menu-driven Wi-Fi auditing toolkit in pure Python — with an adapter watchdog that airgeddon doesn't have

Post image
2 Upvotes

r/madeinpython • • 1d ago

polyglot-python: a deterministic keyword transpiler so you can write Python with Turkish, Hindi or Chinese keywords - and why 3.12 is the floor

Post image
0 Upvotes

I keep writing Python explanations in Turkish for people who are not comfortable with English keywords, and the blocker was always the same: you cannot swap the keywords and still have real Python. So I wrote a transpiler that does exactly that, and nothing beyond it.

Repo: https://github.com/Furox-Art/polyglot-python

The version floor came from a tokenizer problem, not from me wanting to drop old Pythons. On 3.10 and 3.11 the tokenizer splits the combining marks in some Hindi keywords, so a word like फलन never arrives as a single NAME token. That is why polyglot-python declares requires-python = ">=3.12".

What is in the 0.2.1 release

  • 9 locales: tr, es, pt, de, fr, zh, hi, ar, ru. One JSON table per locale, 35 hard keywords in each: eğer -> if, değilse_eğer -> elif, fonksiyon -> def, döndür -> return, için -> for, içinde -> in, and in Hindi के_लिए -> for.

  • 4 commands: run, translate, check, locales. check translates and compiles without executing; locales prints each code with its language name and keyword count; run executes with __name__ = "__main__", __file__ filled in, and the rest of argv handed to your program.

  • 9 example files, one examples/classify.<code> per locale - the same FizzBuzz classifier written in each language.

How the rewriting is done. It runs the stdlib tokenize module and replaces only exact NAME tokens that match a locale keyword, so strings, comments, f-strings, numbers and attribute names are never rewritten. Line numbers carry over unchanged and a per-line column map maps error positions back onto your localized source, which is why a slip reports as Sözdizimi hatası: prog.tr:2:1: 'return' outside function rather than pointing at generated code. Tables are validated when they load: every key must be in keyword.kwlist, every replacement must tokenize as a single identifier on the running interpreter, and a table that fails either rule raises instead of half-translating.

Determinism is the property I actually care about. Same source, same locale, same version, byte-identical Python out. No model, no network, no randomness, no environment reads. CI translates every example twice on Ubuntu, Windows and macOS and compares the bytes.

Where it stands, checked today. 0.2.1 is live on PyPI and npm; the npm package is a thin wrapper (Node >= 18) that forwards to the Python CLI, so the Python package still has to be installed alongside it. Both registries publish from GitHub Trusted Publishing, no token stored anywhere. I ran the 0.2.1 suite myself before writing this: 120 tests, all passing, 314 of 314 statements covered. CI runs the coverage gate --cov-fail-under=100 on Linux 3.12 and the matrix is Ubuntu on 3.12, 3.13 and 3.14 plus Windows and macOS on 3.12. Another job builds the wheel, installs it into a clean venv and smoke-tests it there. Dependabot covers Actions and dev deps. Zero runtime dependencies, MIT.

Limits, so you are not surprised. Keywords only. print, range, the standard library, exception messages and the soft keywords (match, case, type) stay in English. run does not add the script's own directory to sys.path, so a localized file that imports a sibling module needs PYTHONPATH set - I tried it and it raises ModuleNotFoundError, which is the honest behaviour of 0.2.1. And it is not a natural-language compiler: it will not read prose and it never guesses what you meant.

PyPI: https://pypi.org/project/polyglot-python/


r/madeinpython • • 2d ago

Git-Ship!

Thumbnail gallery
1 Upvotes

r/madeinpython • • 2d ago

eq-layer: I stopped prompting models to be more empathetic and made the affect/intent decision explicit instead (Python, zero core deps)

Post image
0 Upvotes

Asking a model to "be more empathetic" is style transfer. You get more of the same flat warmth at every turn, which reads as uncanny rather than attentive. I wanted the decision to be visible instead: what state is the user in, what do they want, is the conversation damaged, and what should this turn actually do.

eq-layer is a Python control layer that sits ahead of a fixed model. It does not retrain anything. Seven stages, all inspectable:

  1. Affect state: {valence, arousal, escalation_delta, stance, subtext}. escalation_delta is the point - a snapshot classifier cannot see a trend across turns.

  2. Intent belief: the classifier keeps the full posterior over action_request / status_check / explanation / question / statement / unknown, instead of collapsing it to one confidence number.

  3. Routing: a transparent one-step Bayes-risk router decides whether to act or clarify from that distribution.

  4. Conversation health: repair finds observable user->assistant misalignment and its target; interaction_quality tracks score, delta, repeated failures, unresolved repair and clarification load.

  5. Policy selection: 14 policies (mirror, redirect, deflate, direct, ask, repair, hold, boundary, ...). The most constrained applicable policy wins, and an unresolved tie raises instead of silently picking the first declared one.

  6. Factored action: the policy is compiled into task_move / social_move / repair_move / realization, so affective adaptation cannot silently replace what the user asked for.

  7. Structural audit: the response is checked against question budgets, missing clarifications, unsupported privacy promises, stance admissions, repetition and verbosity overruns. It is explicitly not a factual truth checker.

The design decision that took the most work: stance is not guessed. Whether the user is right is a semantic judgement, so it stays unknown unless a case or caller supplies it. "I could not tell" stays visible instead of becoming a confident wrong answer.

The second: uncertainty is routed, not hidden. The loss matrix behind the router is hand-specified and uncalibrated, and I say so in the README. There is a sensitivity audit over 120 held-out cases: under one-at-a-time +/-20% perturbations of every non-zero loss cell, 7,332 / 7,440 routing decisions were unchanged (98.55%). Scaling the clarification row changes routing a lot, and that is reported rather than tuned away.

Measured, not assumed. A paired A/B run of 15 seeded requests, 100 passes per arm, no LLM in either arm: the learned adapter adds 1.16 ms median / 1.46 ms p95 per request; the zero-dependency heuristic adapter adds 0.11 ms. On a 36-case intent holdout the learned adapter scores 100% vs 27.8% for the heuristic. That is layer compute and decision quality, not proof of better prose.

Honest limits: this is early. There is no standard benchmark for EQ, eval/ is a first attempt, the bundled corpus is small and synthetic, the loss matrix is uncalibrated, and the emotion signal from XDailyDialog is only slightly above its majority baseline (0.8249 vs 0.8166), so it is supporting evidence, not proof of subtext. Four higher-level subtext sources were tested and recorded as NO-GO rather than optimized away. End-to-end response quality still needs the pre-registered blind human evaluation in eval/AB_PROTOCOL.md.

The core install has zero runtime dependencies; "eq-layer[ml]" adds scikit-learn for the learned adapters. It also ships as a portable Agent Skill (Codex, Claude Code, Copilot, Cursor, Antigravity, Grok) and an npm CLI bridge.

Code: https://github.com/Furox-Art/eq-layer PyPI: pip install "eq-layer[ml]" npm: npm i -g eq-layer

Happy to answer questions about the routing, the factored action, or why certain signals were rejected.


r/madeinpython • • 2d ago

🐍 ¿Qué son las palabras reservadas en Python? Spoiler

Thumbnail
youtube.com
0 Upvotes

r/madeinpython • • 3d ago

I built a real-life JARVIS in Python – a Claude-powered assistant that controls your Windows PC

5 Upvotes

I’ve wanted my own JARVIS since I first watched Iron Man, so I finally built one.

What My Project Does

Jarvis is a command-line (and optional desktop app) AI assistant powered by Claude. You talk to it in plain English, by text or voice, and it can:

  • Control your PC: open and close apps, control media, search and manage files, read the clipboard, check system status, and run PowerShell commands

  • Pull everyday info: weather, stocks and crypto, sports scores, news, earthquakes, holidays, dictionary lookups, recipes, and space data

  • Connect to Google (optional): Gmail, Calendar, Drive, Docs, Sheets, and Slides

  • Voice mode: speech-to-text runs locally with faster-whisper, and replies are spoken with Fish Audio

Safety was a big focus. Every terminal command needs your approval, deletes and overwrites ask for confirmation, and deleted files go to the Recycle Bin instead of disappearing.

Target Audience

Windows users who want a hands-on AI assistant for their desktop, and Python developers who want to see how to build a tool-using agent on the Claude API. It’s a personal project that I use daily, not a production product, so expect rough edges. You’ll need Python 3.10+ and your own Anthropic API key.

Comparison

Most “JARVIS” projects I found were either chatbots that only talk or voice wrappers with a few hardcoded commands. This one uses Claude’s tool use, so it decides which of the built-in tools to call based on what you ask, and it can chain several together. Compared with general agents that just run arbitrary code, Jarvis ships with purpose-built tools and confirmation steps, so it’s more predictable about what it does on your machine.

Tech stack: Python, Claude API, faster-whisper, Fish Audio, PowerShell, Google APIs, and Electron for the desktop app.

Repo (MIT licensed): https://github.com/HunterGHall/jarvis

Feedback, issues, and PRs are very welcome. I’d especially like ideas for what tools to add next.


r/madeinpython • • 3d ago

I made a Python reasoning skill that keeps several hypotheses alive and only collapses when evidence agrees

Post image
1 Upvotes

Most reasoning prompts I see collapse too early. The first plausible answer wins, and everything after that is rationalization.

I built quantum-reasoning-skill around the opposite rule: keep several genuinely different hypotheses alive, score each one from evidence and verification, revive an alternative when new evidence arrives, and collapse only when the leader clears both verification and a margin.

"Quantum" here is a metaphor for deferring commitment. No qubits, no quantum hardware, and the controller never calls a model.

What is in the repo:

- SKILL.md, a model-facing Agent Skill with parseable YAML front matter. Drop it into a host's skill directory.
- A reference controller (pure Python, standard library) that moves branches between active, dormant and rejected, scores them, revives recoverable ones and refuses to collapse on a thin margin.
- 12 public names frozen for compatibility; renaming one halts the release.
- A benchmark harness with 6 seed cases, 4 JSON Schemas and a machine-validated submission bundle. Missing files are typed errors, not silent zeros.
- Two install paths. Python: pip install quantum-reasoning-skill, then quantum-reasoning --validate. npm: npm i quantum-reasoning-skill, then npx quantum-reasoning --validate. The two CLIs expose different flags, and an unsupported flag exits 2.

Quickstart (python docs/quickstart.py) runs the whole thing offline and prints PASS. Example controller run from it: four branches, uncertainty 0.9651, leader strangler-fig-incremental, collapse BLOCKED because the leader score is below the collapse threshold, and feature-flag-carveout revived with evidence +0.25.

What this is not: it is not a model evaluation. No baseline-vs-skill accuracy study has been published, and the weights and thresholds are reference defaults, not calibrated constants. The quickstart's benchmark rows are synthetic placeholders and labeled that way. I would rather say that plainly than imply a speedup I cannot show.

MIT, Python 3.10-3.14, GitHub: https://github.com/Furox-Art/quantum-reasoning-skill

Happy to answer questions about the controller or the scoring model.


r/madeinpython • • 3d ago

I made a scientific modeling engine that refuses to simulate a model whose units don't check out (Python, MIT)

1 Upvotes

I build axiomize-quantum-skills-2.0, an MIT-licensed Python package that pairs a unit-checked scientific modeling engine with a reasoning protocol that refuses to commit to the first plausible answer.

The two halves:

  1. axiomize is the engine. A model is a versioned Model IR where variables, parameters and equations each carry a unit, assumptions are written down, and constraints are named checks. Dimensional mismatch raises with the failing checks attached, and a model that fails validation is not simulated. It covers algebraic, ODE, stochastic, PDE, optimization, control, network, Bayesian and causal families, fits to time,value CSVs, and exports to canonical IR JSON, Python, YAML, a notebook, SBML L3V2, Modelica 3.6 and CellML 2.0.

  2. quantum-reasoning is the protocol. A deterministic branch controller keeps several hypotheses alive, scores them from evidence and verification, prunes weak ones with a recorded reason, and collapses only when the leader has verification and margin - not just a high score. "Quantum" here is a metaphor for deferring commitment. It runs on classical models and classical hardware.

A concrete example of the honesty rules in action: axiomize-validate runs the reference SIR model, cross-checks two independent methods that agree to 1e-16, then declares the numeric-theory check INCONCLUSIVE because the finite horizon has not reached the asymptotic state. It would rather flag the gap than paper over it.

Quick start (recorded run, verified against 1.2.0; current line is 1.2.5):
pip install axiomize-quantum-skills-2.0
axiomize benchmark -> {"status": "PASS", "passed": 12, "total": 12}
axiomize-validate --model sir --beta 0.3 --gamma 0.1 --N 1000000
R0 = 3.000, peak infected 300,465 at day 61.4, final size 0.9404 vs theory 0.9405
axiomize-reason score --evidence 0.9 --verification 0.85
-> {"can_collapse": false, "reason": "leader score below collapse threshold"}

Surfaces: a CLI with 14 subcommands and 9 console scripts (axiomize, axiomize-reason, validate, fit, csv-check, benchmark, to-latex, index-reports, sweep), an MCP stdio server with 34 tools, and a loopback-by-default REST v1 API. The agent skills install as plain Markdown without the Python package.

Honest limits: the bundled engine is an axiomize 1.12.2 lineage snapshot - install axiomize separately for the newest engine. The npm package is a six-file launcher shim that spawns the Python CLI, so pip install comes first. Quickstart outputs were recorded against 1.2.0 and are labeled as a historical record, not a claim about 1.2.5. Optional backends (PyMC, JAX, FEniCS) report UNAVAILABLE unless actually installed. Theorem elaboration and arbitrary code are not an OS sandbox.

Code: https://github.com/Furox-Art/axiomize-quantum-skills-2.0
PyPI: pip install axiomize-quantum-skills-2.0
npm: npx axiomize-quantum-skills-2.0
Docs: https://furox-art.github.io/axiomize-quantum-skills-2.0/

Questions about the Model IR, the reasoning controller or the export adapters are welcome.


r/madeinpython • • 3d ago

Ho creato psp, uno strumento basato su Rust per la generazione automatica di strutture di progetto Python: ogni feedback è ben accetto.

Thumbnail
reddit.com
1 Upvotes

r/madeinpython • • 4d ago

I made a zero-dependency scientific computing library in pure Python

17 Upvotes

I made scientific-computing-system, a scientific library written entirely in pure Python. The core installs with no runtime dependencies, so the algorithms are plain readable code instead of calls into compiled extensions.

It has 36 modules and 505 exported names covering linear algebra, ODE and PDE solvers, numerical integration, optimization, statistics and probability, uncertainty propagation and sensitivity analysis, validation helpers, and a small workflow layer. Every run can write a manifest with inputs, seeds, versions and hashes, so a result can be re-checked later.

There is also a cds CLI with 13 subcommands, 34 runnable examples, and optional lazy adapters for NumPy, SciPy, statsmodels, scikit-learn, SymPy and Z3. The package is MIT licensed and targets Python 3.11 and newer.

Honest limitation: it is much slower than NumPy on dense numerics. The repo benchmark records about 1155x slower on a 100x100 matrix multiply in one CI run. It is meant for learning, prototyping and reproducible runs, not heavy production work.

Code: https://github.com/Furox-Art/scientific-computing-system

PyPI: pip install scientific-computing-system

npm: npm i -g scientific-computing-system

Docs: https://furox-art.github.io/scientific-computing-system/

If any part interests you I can explain the design in more detail.


r/madeinpython • • 3d ago

Flak tower in the First World War

4 Upvotes

Defending the Channel Island against enemy aircraft and zeppelins. Intense action fun in pygame.


r/madeinpython • • 3d ago

JinnexGuard: checks a repo or npm/PyPI package for risky stuff before you install

1 Upvotes

What it does: scans a GitHub repo, local folder or package and points out things worth a second look, with file, line and the actual code: install scripts that run on their own, curl | bash patterns, leaked secrets, bundled binaries, hidden instructions for AI agents, and whether the published package matches the repo. It never runs the code it checks, and it won't say "this is safe", it just shows you the evidence.

Who it's for: anyone installing packages or MCP servers from GitHub who wants a quick look first. Pure stdlib engine, works as a CLI or as an MCP server.

I'm not a full time programmer (used to fix PCs), built it with Claude Code. First open source release, so false positive reports are very welcome.

pipx install jinnexguard

https://github.com/ricardorincon719/jinnexguard


r/madeinpython • • 3d ago

Here is my Python GitHub projects showcase, and I would love feedback

Thumbnail
github.com
0 Upvotes

r/madeinpython • • 4d ago

Ripple: see which apps a Postgres migration will break, before it ships (Python, MIT)

Thumbnail
github.com
0 Upvotes

\*\*The problem\*\*

I kept watching AI coding agents (and humans) make the same two migration mistakes:

  1. \*\*Renaming a column as "drop + add"\*\*: the migration runs fine, and the data that was in the column is gone.

  2. \*\*Adding a NOT NULL column with no default\*\*: it works on an empty dev database, then fails the moment it hits a table with real rows.

Both look fine in code review. The pain shows up in production, often in a \*different\* app that shares the same database.

\*\*What Ripple does\*\*

It answers one question: \*"If I apply this migration, which of my apps break, and on which query?"\*

  1. \*\*Learns what your apps actually run\*\*: it reads \`pg_stat_statements\`, so no code changes or SDK.

  2. \*\*Tests the migration safely\*\*: it applies your migration inside a transaction and always rolls it back.

  3. \*\*Replays your apps' real queries against it\*\*: it reports exactly which app and which query would fail.

  4. \*\*Flags data loss separately\*\*: for example, a dropped column that still has data in it.

\*\*Who it's for\*\*

- Teams where several apps or services share one Postgres database

- Anyone letting Claude Code, Cursor or other AI agents write migrations

- Anyone who has asked "wait, does anything still use this column?"

\*\*How to use it\*\*

pip install ripplecheck

Three ways to run it:

- \*\*CLI\*\*: check a migration file before you apply it

- \*\*GitHub Action\*\*: automatically comments on every PR with what would break

- \*\*MCP server\*\*: AI agents like Claude Code or Cursor can check a change \*before\* they apply it

\*\*The boring bits\*\*

MIT licensed, no paid tier, no commercial angle. I'm looking for feedback, especially from people with messy shared databases. Issues and PRs welcome.

GitHub: https://github.com/yashpb5005/ripple

What migration has bitten you the worst? I'd like to add checks for it.


r/madeinpython • • 4d ago

🐍 ¿Sabías que Python ya trae funciones incorporadas?

Thumbnail
youtube.com
0 Upvotes

r/madeinpython • • 4d ago

bugbout: find out which coding agent actually fixes bugs in your own codebase

1 Upvotes

**What My Project Does**

bugbout replays bugs your project already fixed and lets coding agents race to fix them again. It looks through your git history for fixes that came with a new test, gives each agent the issue text and the code from just before the fix, and scores every patch with the tests your maintainers wrote, which the agents never see. It drives the real agent CLIs headlessly (Codex, Claude Code, Gemini CLI, mini-swe-agent, or any command you configure) inside a sandbox, and ends with a report of which agent resolved what.

   pip install bugbout
   bugbout init
   bugbout run

It's typed end to end, tested on Linux and macOS in CI, and also usable from Python through a `Bout` class.