Skip to main content

sfvparse

PyPI version License: MIT Python 3.11+

Zero-dependency RFC 8941 HTTP Structured Field Values parser and serializer for Python 3.11+.

Quick Start

pip install sfvparse
# OR (not yet on PyPI):
# pip install git+https://github.com/prasad-a-abhishek/sfvparse.git
from sfvparse import parse_item, parse_list, parse_dict, serialize_list

# Parse an Item
item = parse_item(b"text/plain;charset=utf-8")
# {"value": "text/plain", "params": {"charset": "utf-8"}}

# Parse a Link-header List
links = parse_list('<https://api.example.com/2>; rel="next", <https://api.example.com/1>; rel="prev"')
# [{"value": "https://api.example.com/2", "params": {"rel": "next"}}, ...]

# Parse a Dictionary
d = parse_dict(b"label=example;max-age=3600")
# {"label": {"value": "example", "params": {"max-age": 3600}}}

# Serialize back to bytes
out = serialize_list([{"value": "foo", "params": {"rel": "next"}}])
# b"foo; rel=next"

⚡ Performance & Benchmarks

sfvparse is benchmarked against the canonical reference Python implementation mnot/http_sfv across 50 iterations (10 workload profiles × 5 runs each). Reproduce locally:

python3 benchmarks/run_benchmark.py

Workload profiles (10 total — reproduce via python3 benchmarks/run_benchmark.py):

Profile Input size sfvparse mean http_sfv mean Speedup Notes
Single item (token) 10 B 6.78 µs 6.59 µs ~1.0× Equal speed
Single item (param'd) 32 B 13.04 µs 14.38 µs 1.10× sfvparse slightly faster
Single item (string+escape) 16 B 9.16 µs 6.15 µs 0.67× http_sfv ~1.5× faster on strings
Short list (3 items) 39 B 24.77 µs 15.22 µs 0.61× http_sfv ~1.6× faster on lists
Long list (50 items) 1268 B 2359.75 µs 711.16 µs 0.30× http_sfv ~3.3× faster; sfvparse has O(n²) inner-list handling
Dict (5 keys, params) 48 B 42.06 µs 48.30 µs 1.15× Roughly equal
Link header (realistic) 80 B 20.19 µs ERR http_sfv HttpHeader.parse throws on bare rel tokens in params
Accept-Language header 44 B 41.04 µs 59.32 µs 1.45× sfvparse faster
Inner-list member 12 B 19.88 µs 17.95 µs 0.90× Roughly equal
Deeply nested params 70 B 27.32 µs 36.75 µs 1.34× sfvparse faster

Honest summary: sfvparse and http_sfv are comparable on most workloads. sfvparse is ~1.1-1.5× faster on dict, accept-language, and deeply-nested params workloads. http_sfv is ~1.5-3× faster on string-heavy and list-heavy workloads; the long-list case is the most pronounced gap (sfvparse has O(n²) inner-list handling). Both use negligible memory (~1-2 KB peak). sfvparse wins on API ergonomics (single-function entry points vs class-then-parse) and on having a published PyPI package with type hints.

Why sfvparse?

Python developers building HTTP clients, REST API clients, or HTTP servers need standards-compliant RFC 8941 parsing — used in headers like Link, Sec-WebSocket-Extensions, Accept-Language, and Signature — without taking on a heavy dependency.

Competitor landscape:

Package PyPI Zero-deps RFC 8941 Maintenance
mnot/http_sfv (reference) No (GitHub only) Yes Yes Reference (14★)
http_sfv (PyPI) Yes No (deps on http_sfv) Partial Stale
linkheader Yes Yes RFC 5988 only Unmaintained (Python 2 era)
httplink Yes Yes RFC 8288 only Niche
sfvparse Yes Yes Full RFC 8941 Active

sfvparse trade-offs:

  • Zero runtime dependenciespyproject.toml has dependencies = []. Only the Python standard library.
  • RFC 8941 compliant — full Item, List, Dictionary, and bare-item parsing (sf-token, sf-string, sf-integer, sf-decimal, sf-boolean, sf-binary) with parameter lists.
  • RFC 8288 Link-header extension<URI> member syntax recognized automatically.
  • Inner-list extension( member member ; param ) syntax.
  • Type-hinted TypedDict APIItem, ListMember, DictMember for static type-checkers.
  • Works on Python 3.11+ with full PEP 604 union types and structural pattern matching.
  • ⚠️ Byte-sequence asymmetry — the parser returns raw base64 (between the : : markers) per spec AC6; the serializer expects decoded bytes. Callers that want to round-trip byte sequences should base64.b64decode(...) between parse and serialize. This is intentional and documented.
  • ⚠️ Spec deviations from strict RFC 8941 ABNF — see "Limitations / non-goals" below.

Key Features & Complete API Reference

Public functions

Function Returns Description
parse_item(data) Item Parse a single Item (bare item + parameters)
parse_list(data) list[ListMember] Parse a List of Items / dictionary-style members
parse_dict(data) dict[str, DictMember] Parse a Dictionary
parse_token(data) str Parse a single sf-token
parse_string(data) str Parse a single sf-string
parse_integer(data) int Parse a single sf-integer
parse_decimal(data) float Parse a single sf-decimal
parse_boolean(data) bool Parse a single sf-boolean (?0 or ?1)
parse_byte_sequence(data) bytes Parse a single sf-binary (returns raw base64 inside : : per spec)
serialize_item(member) bytes Serialize one Item
serialize_list(members) bytes Serialize a list of Items
serialize_dict(d) bytes Serialize a dictionary

All parse_* functions accept bytes or str input; serialize_* functions return bytes.

TypedDict types

from sfvparse import Item, ListMember, DictMember, Value

# Value = Union[str, int, float, bool, bytes, list]

item: Item = {"value": "text/plain", "params": {"charset": "utf-8"}}
member: ListMember = {"value": "https://example.com", "params": {"rel": "next"}}
dm: DictMember = {"key": "foo", "value": "bar", "params": {"max-age": 3600}}

CLI usage

sfvparse is a library-first package (no CLI of its own). Use it programmatically:

python3 -c "from sfvparse import parse_item; import sys; print(parse_item(sys.stdin.buffer.read()))"

Error handling

All parse_* functions raise ValueError on malformed input and TypeError on wrong input types. This is the only contract — no ParseError class hierarchy.

Test count

pytest collection reports 282 passing tests as of this release (covering all 25 spec acceptance criteria plus edge cases, round-trip checks, and TypeHint integration). Run python3 -m pytest tests/ --collect-only -q to see the full list.

Limitations / Non-Goals

  • No RFC 9651 extensionssfvparse implements the RFC 8941 subset only. Items, Lists, Dictionaries, and the six bare-item types. No structured-fields extensions from RFC 9651 are parsed.
  • No HTTP client / server — this is a parsing/serialization library only.
  • No binary content-transfer encodings (e.g., quoted-printable, base64 transport).
  • No caching-aware content negotiation (RFC 2295).
  • Spec deviations from strict RFC 8941:
    • Integer digit count is unbounded (Python ints are arbitrary-precision).
    • Decimal fractional-digit count is unbounded (Python floats can hold the full IEEE 754 range).
    • Parameter and dictionary keys are lowercased before storage (RFC 8941 says they are case-insensitive; we normalize for consistency).
    • parse_token greedily scans until end-of-input, including any internal whitespace. Strict RFC 8941 expects parse_token to be called on a slice bounded by other syntax.
    • Bare-item tokens ending in 2+ consecutive punctuation tchar (e.g. text/plain!!!) are split — the punctuation run is treated as trailing junk that parse_item then rejects.

License

MIT License — Copyright (c) 2026 sfvparse contributors. See LICENSE for full text.

Built by the Hermes repo-factory. See benchmarks/BENCHMARK.md for full benchmark methodology and raw numbers.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

sfvparse-0.1.0.tar.gz (26.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

sfvparse-0.1.0-py3-none-any.whl (12.0 kB view details)

Uploaded Python 3

File details

Details for the file sfvparse-0.1.0.tar.gz.

File metadata

  • Download URL: sfvparse-0.1.0.tar.gz
  • Upload date:
  • Size: 26.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.15

File hashes

Hashes for sfvparse-0.1.0.tar.gz
Algorithm Hash digest
SHA256 59c0a1604be387d30136f0b98a874218c84088a85d6cc7e1a0ecadfb4cecdc98
MD5 1550a9f01ba84317935d07af9e1aa721
BLAKE2b-256 5a4c5cb426c102c48eeeda1413666401cf637a9dbd4c54d7094591db84a9f819

See more details on using hashes here.

File details

Details for the file sfvparse-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: sfvparse-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 12.0 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.15

File hashes

Hashes for sfvparse-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 43f104bd1d9e5147191a9fcec5cc892f0585bb192e2b478f9615edc1d70a2352
MD5 0b4ed1a714b0aac19f6a4837917e0003
BLAKE2b-256 8ec66e71bc8d3daed965b1a2fba22d3623d54a04ef65b5b7b949ea45eea753f7

See more details on using hashes here.

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 files

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page