hank-format
Shared string formatting functions for standardizing names, dates, and times across the Hank AI stack.
pip install hank-format
Usage
from hank_format import as_name, as_date, as_date_str, as_datetime_str, as_time_str
as_name("Primary: John Doe") # 'DOE, JOHN'
as_name("Steven Hardman, APRN - CRNA") # 'HARDMAN, STEVEN, APRN, CRNA'
as_name(last="Doe", first="John", suffix="Jr, MD") # 'DOE, JOHN, JR, MD'
as_name(provider_dict={"fn": "John", "ln": "Doe", "tit": "MD"}) # 'DOE, JOHN, MD'
as_date("12/31/2020 (age 30 yrs)") # datetime.date(2020, 12, 31)
as_date_str("01012024") # '2024-01-01'
as_datetime_str("2020-12-31T23:59") # '2020-12-31 23:59:00'
as_datetime_str("23:59", precision="minute", default_date="2020-12-31") # '2020-12-31 23:59'
as_time_str("11:30 pm") # '23:30'
API
| Function | Returns | Notes |
|---|---|---|
as_name(value) |
str |
LAST, FIRST MIDDLE, SUFFIX, upper case. Strips Label: prefixes, [notes], (notes), *, and text after ;. |
as_name(*, last, first=None, middle=None, suffix=None) |
str |
Same output, built from parts. suffix may hold several credentials ("Jr, MD"). |
as_name(*, provider_dict) |
str |
Same output, built from a dumped hank-medicalnotes Provider (ln, fn, m, sfx, tit). tit is appended as a credential unless it is OTHER or UNKNOWN; other keys are ignored. ProviderDict is exported for typing. |
is_date(value) |
bool |
True when a year, month, and day are present. |
has_time(value) |
bool |
True when an hour and minute are present. |
as_date(value) |
date | None |
Calendar date only. |
as_date_str(value) |
str |
YYYY-MM-DD or "". |
as_datetime(value, *, default_date=None) |
datetime | None |
Midnight when no time is present. Time-only input needs default_date. |
as_datetime_str(value, *, precision="second", default_date=None) |
str |
YYYY-MM-DD HH:MM:SS, or YYYY-MM-DD HH:MM with precision="minute". |
as_time(value) |
time | None |
Clock time only. |
as_time_str(value, *, precision="minute") |
str |
HH:MM, or HH:MM:SS with precision="second". |
Conventions:
- Inputs may be strings,
date,datetime,time, orNone. Other types raiseTypeError. as_nametakes exactly one input shape (free text, parts, orprovider_dict); omitting or mixing them raisesTypeError, and a suppliedNonemeans empty. Every shape runs through the same parser, so the output is always a fixed point ofas_name.- Object variants return
Noneand string variants return""when no usable value exists. - Returned values are timezone-naive and have no microseconds.
precisiontruncates, never rounds. - Any parsed date more than two days in the future rolls back 100 years, including four-digit years and year-less
MM/DD(12/31/45is 1945;12/26without a time is 1926 when today is 2026-10-08). This is a two-digit-year heuristic inherited from pdf-extractor; strip or validate far-future dates before calling if you need them intact. - Year-less
MM/DD HH:MMstrings take the current year, or the previous year if that would be in the future.
Migrating from pdf-extractor utils
| Legacy | hank-format |
|---|---|
as_name(s) |
as_name(s) (lists and vStr handling stay in pdf-extractor) |
as_date(v, date_only=True, as_dt=True) |
as_date(v) (returns date) |
as_date(v, date_only=True) |
as_date_str(v) |
as_date(v, as_dt=True) |
as_datetime(v) |
as_date(v) |
as_datetime_str(v) |
as_time(v, with_date=False) |
as_time_str(v) |
as_time(v, strict=True) |
as_datetime_str(v, precision="minute") if has_time(v) else "" |
as_time(v, default_date=d) |
as_datetime_str(v, precision="minute", default_date=d) if has_time(v) else "" |
as_time(v) |
as_datetime_str(v, precision="minute") if is_date(v) and has_time(v) else as_time_str(v) |
Legacy as_time returned "" for anything without a time; the new datetime
functions format a date-only value as midnight, hence the has_time guards.
Development
Requires uv.
uv sync # create .venv with Python 3.12 and the dev group
uv run pytest # tests with 100% coverage enforced
uv run ruff check . && uv run ruff format --check .
uv run pyright
uv build # sdist + wheel into dist/
Releasing
- Open a PR against
mainand add exactly one label:release:patch,release:minor, orrelease:major. - On merge, the
Releaseworkflow bumps__version__inhank_format/__init__.py, runs the tests, builds, commitsRelease vX.Y.Z, tags it, and pushes. A separatepublishjob then uploads the built artifacts to PyPI. - If only the
publishjob fails, fix the cause and re-run that failed job. Do not re-run the whole workflow: the version is already bumped and tagged, so a full re-run would bump it again.
Metadata
Release files for hank-format 0.2.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 | |
|---|---|---|---|
| hank_format-0.2.0.tar.gz | 11.7 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| hank_format-0.2.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 23.4 kB
Release files / hank_format-0.2.0.tar.gz
| Download URL | hank_format-0.2.0.tar.gz |
|---|---|
| Size | 11.7 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
8f27d01c7f974ae9a87872b75a7fe0ba1cd0e5eb49c19ba7f0912c63665218fc
|
|
BLAKE2b-256 checksum How to use checksums |
1f0a875ed395f8da22f7b2248c6edfae6673815a0e5b32b2c95ac94a76601036
|
| 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 16, 2026.
Transparency logRelease files / hank_format-0.2.0-py3-none-any.whl
| Download URL | hank_format-0.2.0-py3-none-any.whl |
|---|---|
| Size | 11.7 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
281bb54c010ca584dbb01ee95a0f5e27e64e380dba5832f3d541d3bc9d29817e
|
|
BLAKE2b-256 checksum How to use checksums |
58ff66503f5f4c63459aa32adf2153d2a90820745910179519381e8cceddd300
|
| 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 16, 2026.
Transparency log