tontine-core
Build a simple, transparent, auditable, and reusable Python engine for community tontines.
Package Identity
- Distribution name:
tontine-core - Python import name:
tontine - Supported Python: 3.12+
Development
This repository uses uv to create the isolated environment, resolve dependencies, run tools, and build the package.
uv sync
uv run pytest
uv run pytest --cov=tontine --cov-report=html --cov-report=term
uv run ruff check src tests
uv run mypy src
uv build
Import the package with:
import tontine
The core package is framework-independent and has no runtime dependency on a database, web framework, payment provider, or financial institution.
Capabilities
The package provides focused, composable domain primitives rather than one large application object:
- Groups and members: validated groups, optional jurisdiction metadata, member roles, residence metadata, membership start dates, and lifecycle transitions.
- Contributions: daily, weekly, and monthly rules; contribution cycles; pending, paid, partial, late, and missed statuses; outstanding totals; and separate fixed penalty assessments.
- Classic tontines: deterministic member rotations, expected payouts, duplicate-payout protection, and configurable unpaid-contribution policy.
- Investment tracking: allocation schedules, asset definitions, manual valuations, purchases, sales, income, fees, and supplied FX-rate records.
- Ownership and liabilities: Decimal member-unit issuance and redemption, ownership percentages, member values, and manually supplied liability records aggregated by currency.
- Ledger and audit: balanced double-entry journals, derived balances, reversals, adjustments, immutable audit events, and provenance fields.
- Governance: versioned rulesets, rotation proposals, one-member-one-vote decisions, approval thresholds, and effective rotations.
- Reporting and repositories: structured member/group statements and typed in-memory repository implementations suitable for application adapters.
Quick Start
Create a group and a cycle through the top-level API:
from datetime import date
import tontine
group = tontine.create_group(
"tokyo-cameroon",
"Tokyo Cameroon Circle",
"JPY",
jurisdiction="JP",
)
cycle = tontine.create_contribution_cycle(
"2027-01",
date(2027, 1, 1),
date(2027, 1, 31),
"Asia/Tokyo",
)
Members and contributions
from datetime import date, datetime, timezone
from decimal import Decimal
from tontine.contributions import ContributionCycle
from tontine.members import Member, MemberRole
member = Member.create(
"member-001",
"Amina",
MemberRole.MEMBER,
date(2027, 1, 1),
residence_country="CM",
)
cycle = ContributionCycle(
"2027-02",
date(2027, 2, 1),
date(2027, 2, 15),
"Africa/Lagos",
grace_period_days=2,
late_penalty=Decimal("500"),
)
cycle.add_expected_contribution(member.member_id, Decimal("30000"))
record = cycle.record_contribution(
member.member_id,
Decimal("30000"),
payment_date=datetime(2027, 2, 18, tzinfo=timezone.utc),
)
assert record.penalty == Decimal("500")
assert record.penalty_record.destination.value == "common_reserve"
Penalties are group money, separate from contributions, and do not create
investment units. The default destination is COMMON_RESERVE.
Classic rotation
from tontine.classic import ClassicRotation
rotation = ClassicRotation.from_active_members(("member-001", "member-002"))
assert rotation.recipient_for_cycle(1) == "member-001"
expected_pool = rotation.expected_payout(
{"member-001": Decimal("30000"), "member-002": Decimal("30000")}
)
Investment ownership and liabilities
from tontine.investments import (
InvestmentValuation,
Liability,
LiabilityRegistry,
MemberUnitLedger,
)
liabilities = LiabilityRegistry()
liabilities.record(
Liability("fee-001", Decimal("100"), "JPY", date(2027, 2, 1), "invoice")
)
valuation = InvestmentValuation.from_liabilities(
assets=Decimal("10000"),
liabilities=liabilities,
currency="JPY",
units_outstanding=Decimal("100"),
asset_currency="JPY",
)
units = MemberUnitLedger()
member_units = units.issue("member-001", Decimal("3000"), valuation.unit_price, "issue-001")
ownership = valuation.member_ownership_percentage(member_units)
value = valuation.member_value(member_units)
The valuation derives NAV = assets - liabilities, unit price, ownership
percentage, and member value from explicit Decimal inputs. Asset and activity
aggregation remains the responsibility of the consuming application.
Structured reporting
from tontine.reporting import InvestmentSummary, build_member_statement
investment = InvestmentSummary.from_valuation(valuation, member_units, "JPY")
statement = build_member_statement(
"member-001",
"Amina",
"JPY",
contributions=(),
payouts=(),
investment=investment,
)
assert statement.investment.ownership_percentage == ownership
Application layers can turn these structured records into web pages, exports, or other user interfaces without adding presentation dependencies to the core.
Structured Reporting
Reporting APIs expose structured member and group statement data, including
contribution history, outstanding amounts, payouts, investment units, ownership,
cash, investments, liabilities, NAV, and proposals. For example, a consumer can
use a MemberStatement as the source for a web view or export. PDF, Excel, HTML,
and web rendering remain application-layer responsibilities.
Financial Account Registry
The account registry records external custody context only. For example, a bank
account may be represented with ****1234, NG, and a logical ledger identifier
such as ledger-cash-ngn. The package does not store credentials, connect to
institutions, retrieve live balances, initiate payments, or move real money.
Metadata
Release files for tontine-core 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| tontine_core-0.1.0.tar.gz | 29.7 kB | With provenance | Details for tontine_core-0.1.0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| tontine_core-0.1.0-py3-none-any.whl | Python 3 | none | any | Details for tontine_core-0.1.0-py3-none-any.whl |
Total release size: 64.1 kB
Release files / tontine_core-0.1.0.tar.gz
| Download URL | tontine_core-0.1.0.tar.gz |
|---|---|
| Size | 29.7 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
33b56b2cf3734ec092f70dc153965c5739444457b44cb58a96026cd84503e50c
|
|
BLAKE2b-256 checksum How to use checksums |
e4d5d0f0cdacff5d9714fb9d69ada2e8f275e2d3fcb26f1c97a11910859e700c
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 13, 2026.
Transparency logRelease files / tontine_core-0.1.0-py3-none-any.whl
| Download URL | tontine_core-0.1.0-py3-none-any.whl |
|---|---|
| Size | 34.5 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
a9379f309174a40fbc155ef08d5684c3b79d0e13c8797184e9970856ca2bedf6
|
|
BLAKE2b-256 checksum How to use checksums |
71e216ee934ab984875313a26ac6da82a0d22a7cf73c28246d1925a8a144aeff
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 13, 2026.
Transparency logSecurity for tontine-core 0.1.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
All 2 files in this release have been uploaded with provenance metadata.
Attestation for tontine_core-0.1.0.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 13, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.