golded-ftn-msg
Repository: golded-ftn-msg-python.
The distribution remains golded-ftn-msg; imports use golded_ftn_msg.
The source is public on GitHub. Version 1.2.0 is available on PyPI.
Install with Python 3.12 or newer:
python -m pip install golded-ftn-msg==1.2.0
Read and write explicit FTSC and Opus .MSG areas with a 190-byte header.
The local 1.3.0 development version adds Opus writing; the published 1.2.0
version writes FTSC only.
Python 3.12 or newer. MIT licensed.
The public API exports MsgReader, MsgWriter and MsgSession. Message values, options and
protocols come from golded-ftn>=1.2.0,<2.
from pathlib import Path
from golded_ftn import MessagePatch, OutgoingMessage
from golded_ftn_msg import MsgReader, MsgWriter
area = Path("messages")
writer = MsgWriter()
writer.create(area)
with writer.open(area) as session:
added = session.append(
OutgoingMessage(
from_name="Alice", to_name="Bob", subject="Hello", body_text="First line"
)
)
current = session.read(added.identity.msgno)
session.update(current.identity, MessagePatch(subject="Revised"), current.revision)
assert list(MsgReader().read(area))[-1].subject == "Revised"
Installation
For local development, keep the two repositories beside each other:
golded-dev/
golded-ftn-python/
golded-ftn-msg-python/
cd golded-ftn-msg-python
uv sync --locked
uv run pytest
uv uses the sibling core checkout during development. Wheel and sdist dependency
metadata contains the version constraint only. To install local built wheels:
uv build ../golded-ftn-python --out-dir /tmp/golded-wheels
uv build --out-dir /tmp/golded-wheels
uv pip install /tmp/golded-wheels/*.whl
Behaviour and limits
MsgReader(header_format="ftsc") is the default. Use MsgReader("opus")
explicitly for Opus areas; there is no automatic header detection. Opus bytes
176–183 contain DOS written/arrived timestamps rather than zone/point words.
The written timestamp supplies a naive date with two-second precision, using
1980–2107; zero or invalid written timestamps fall back to the textual date.
Addresses use header net/node plus INTL/FMPT/TOPT, without treating timestamp
bits as address metadata. Opus provenance uses source_type="opus"; FTSC
provenance remains "msg". Use MsgWriter().create(path, header_format="opus") and
MsgWriter().open(path, header_format="opus") for Opus writing. Selection is
explicit on each operation; it does not detect or convert an existing variant.
write(..., header_format="opus") uses the same selection.
New Opus posted_at values must be naive, 1980–2069, without microseconds and
with even seconds. The DOS fields can encode 1980–2107, but the textual MSG date
and GoldED's read path impose the narrower writer range. Odd seconds are rejected,
not rounded. None writes zero DOS written words and an empty textual date.
New arrived words are zero because OutgoingMessage has no arrival date field.
Updates preserve arrived words and unknown header bytes; only a posted_at patch
changes written words and textual date. Existing invalid/zero written words retain
the reader's textual fallback. Zones/points use INTL/FMPT/TOPT. A nonzero zone
requires both addresses or a consistent INTL declaration; incomplete representation
is rejected before mutation. GoldED interoperability is still unverified.
The reader accepts positive numeric filenames with case-insensitive .msg
extensions. It sorts numerically and rejects duplicate message numbers.
Filesystem errors identify missing or invalid area paths. Malformed message files
raise ParserException with the file path and original cause.
Text decoding is strict, using the core charset helpers and CP850 fallback.
Kludges remain in the normalized body; mojibake is never repaired automatically.
Dates use English month names and the 1970–2069 two-digit year window. Invalid
reader dates become None. Header addresses and INTL/FMPT/TOPT must agree.
Provenance records the actual file path and message number; offsets are unknown.
MsgWriter.create(path) initializes a new area. A context-managed open(path)
session provides read, append, update and delete. Updates and deletes
require the revision returned by a consistent session read. Unrelated message
changes do not invalidate that revision. Unknown header bytes and controls survive
updates; attribute-only updates preserve the original text bytes. The revision
contains format/base/message identity, the physical filename number and SHA-256
over the raw file. Omitted patch fields stay unchanged; explicit None clears
only representable optional values. control_lines replaces general controls;
omitted MSGID, addresses and routing retain their structured fields. Body-only
changes preserve controls and routing. Conflicting metadata is rejected.
Appends publish a complete temporary file without replacing an existing number.
Updates replace the complete file; deletes remove it. A sidecar lock serializes
Python sessions and retains the highest allocated number. Each operation rolls
back I/O failures where possible; a failed rollback poisons the session. The legacy
write convenience method returns the number of completed appends. Earlier
operations remain committed if a later one fails.
Only offline FTSC editing is supported. Opus editing and concurrent=True are
rejected. GoldED read/write interoperability is pending. POSIX publication uses a
hard link; Windows uses a non-replacing rename. Windows runtime behaviour has not
been verified. Linux execution has not been exercised here either. Process death
and power loss are outside the rollback guarantee;
a controlled exit test observes an unpublished temporary file after interrupted
append.
Header names allow 35 encoded bytes; subjects allow 71. Encoding is strict. Header fields reject nulls and line breaks. Dates must be naive, have no microseconds, and fall within 1970–2069. Address components and attributes must fit unsigned 16-bit fields. Domain addresses are unsupported.
The writer preserves body kludges, quoting and routing, and adds missing declared control lines, charset and address kludges. Conflicting metadata is rejected. An external MSGID may be supplied; synthetic hash IDs cannot become MSGID. MSGID is never generated automatically. Provenance is not serialized. Body lines use CR and end with one null byte.
Development
uv sync --locked
uv run pytest
uv run ruff check .
uv run ruff format --check .
uv run mypy
uv run python -m mypy.stubtest golded_ftn_msg
uv build
uv run twine check dist/*
uv run python scripts/verify_distribution.py
See writer source notes for the original GoldED layout, locking limits and the distinction between source evidence and build tests.
Archive mode
Strict reading remains the default. For damaged archives, opt in explicitly:
from golded_ftn import ReaderIssue, ReaderOptions
from golded_ftn_msg import MsgReader
issues: list[ReaderIssue] = []
options = ReaderOptions(archive_mode=True, on_issue=issues.append)
# Replace "messages" with the actual archive directory.
messages = list(MsgReader("opus").read("messages", options))
Archive mode requires a callback. It skips malformed message files with a
record_parse_error issue and continues to later files. If declared ASCII cannot
decode a message, it tries the configured fallback strictly and reports
ascii_decode_fallback after successful parsing. Invalid UTF-8 and address
conflicts are skipped, never repaired. Original charset controls remain unchanged.
Duplicate numeric filenames make identity ambiguous: the reader reports
duplicate_message_number with action stopped before reading any messages.
Callback exceptions propagate. ReaderIssue carries the source identity, action,
code and a description without message contents. Recovery includes the failed
ASCII byte offset; record errors without a known location use None.
This package does not discover areas, provide a database, or integrate with Nornir.
See CONTRIBUTING.md, SECURITY.md, and the release checklist.
Metadata
Release files for golded-ftn-msg 1.3.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 | |
|---|---|---|---|
| golded_ftn_msg-1.3.0.tar.gz | 34.4 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| golded_ftn_msg-1.3.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 52.6 kB
Release files / golded_ftn_msg-1.3.0.tar.gz
| Download URL | golded_ftn_msg-1.3.0.tar.gz |
|---|---|
| Size | 34.4 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
705b4671c67f221e166fdae5dd2212a7845b705f491a79b8acd8c5b0d940ccce
|
|
BLAKE2b-256 checksum How to use checksums |
6eb007766941d9aef860a7a9cde3b574f4fa9b3a5c1af4a157dc2639467c57de
|
| 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 Oct 7, 2026.
Transparency logRelease files / golded_ftn_msg-1.3.0-py3-none-any.whl
| Download URL | golded_ftn_msg-1.3.0-py3-none-any.whl |
|---|---|
| Size | 18.2 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
e78fb55a36429005c93b101c133db0ad557b7e44a2c30d6b8ee317dbf00d4314
|
|
BLAKE2b-256 checksum How to use checksums |
eba3a85d9d282e3678f69561b26e9fcbfb32708d7133a9cf0bd98b2a85c8e1ba
|
| 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 Oct 7, 2026.
Transparency log