Skip to main content

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, or None. Other types raise TypeError.
  • as_name takes exactly one input shape (free text, parts, or provider_dict); omitting or mixing them raises TypeError, and a supplied None means empty. Every shape runs through the same parser, so the output is always a fixed point of as_name.
  • Object variants return None and string variants return "" when no usable value exists.
  • Returned values are timezone-naive and have no microseconds. precision truncates, 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/45 is 1945; 12/26 without 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:MM strings 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

  1. Open a PR against main and add exactly one label: release:patch, release:minor, or release:major.
  2. On merge, the Release workflow bumps __version__ in hank_format/__init__.py, runs the tests, builds, commits Release vX.Y.Z, tags it, and pushes. A separate publish job then uploads the built artifacts to PyPI.
  3. If only the publish job 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)

Source distribution for hank-format 0.2.0
File Size Uploaded
hank_format-0.2.0.tar.gz 11.7 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for hank-format 0.2.0
File Interpreter ABI Platform
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 log

Release 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

Release history Release notifications | RSS feed

This release

0.2.0 This release

2 release files

0.1.1

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page