icfpy
A pure-Python library to parse, validate, build in-memory, write, and convert Indent Comma Format (ICF) files, plus generate ICX companion index files.
- Implements the ICF language specification v1.1 — schema annotations
(
!indexes/!defaults/!constraints/!expressions), row!overrides, primary objects, defaults + overrides resolution, and multiline value rows — while staying fully backward compatible with v1.0 documents. - Implements the ICX index specification v1.2 — auto-harvested
Tags, per-recordSummaryproviders,@sourcebytes,join_tags/split_tagshelpers — plus the resolved exporticfpy.write_resolved(...)that bakes defaults/overrides into plain ICF output. - Python 3.9+, zero runtime dependencies (standard library only).
- JSON output is hand-rolled — no third-party JSON/CSV/XML library.
- A faithful behavioral port of the Java library
icfj.
What is ICF?
ICF is a compact, hierarchical, schema-driven data format that combines the
compactness of CSV, the readability of YAML, and the hierarchy of JSON/XML. A document
declares its schema once (@schema), optionally carries user metadata (@metadata) and
shared reference data (@masters), then stores records positionally (@data /
@record) as comma-separated rows. See the
ICF and ICX specifications for the full format definition.
Install
pip install icfpy
For development from a checkout (with the dev tools):
pip install -e ".[dev]"
Quickstart
import icfpy
# 1. Parse ICF text (or a file path) and navigate the data.
doc = icfpy.parse(open("invoice.icf", encoding="utf-8").read())
data = doc.to_icf_node()
city = data.path("indexdata").path("masterindex").path("Project").path("Location").as_text()
# `path(...)` never raises — absent fields yield IcfMissing, so chains are safe.
missing = data.path("nope").path("still_nope").as_text() # -> ""
# 2. Validate (never raises on content problems).
result = icfpy.validate(icf_text)
if not result.is_valid:
for err in result.errors:
print(err) # e.g. "ERROR (line 7) [FIELD_COUNT_MISMATCH] ..."
# 3. Build a node from scratch and write it back to ICF text.
root = icfpy.IcfNode.object()
root.put_object("vendor").put("id", "V001").put("email", "v@example.com")
root.put_array("items").add_object().put("sku", "A1").put("qty", 100)
icf = icfpy.write(root) # infers a schema; object -> one record, array -> many
# 4. Generate the ICX companion index and serialize it.
source = icfpy.parse(icf)
icx_doc = icfpy.generate_icx(source, "invoice.icf", icf) # populates Line/Offset/Size/Checksum
icx_text = icfpy.write(icx_doc)
Facade API
| Function | Description |
|---|---|
icfpy.parse(text_or_path) |
Parse; raises IcfParseError on error-level diagnostics. |
icfpy.parse_lenient(text) |
Best-effort parse; never raises on content errors. |
icfpy.validate(text_or_path) |
Returns a ValidationResult (errors + warnings). |
icfpy.is_valid(text_or_path) |
True when there are no error-level diagnostics. |
icfpy.write(doc_or_node[, path]) |
Serialize to ICF text; optionally write a UTF-8 file. |
icfpy.write_with_checksum(doc_or_node[, path]) |
Like write, but injects a computed @checksum (spec §19, honoring @hashmethod). |
icfpy.write_resolved(doc[, path]) |
Write with Phase-5 resolution baked in: defaults/overrides inlined, all annotations dropped. |
icfpy.generate_icx(source[, name[, text], summary_provider=, tag_provider=]) |
Build the ICX v1.2 index as an IcfDocument (auto-harvested Tags, optional Summary). |
icfpy.join_tags(tags) / icfpy.split_tags(cell) |
Join / split ICX Tags cells (+-separated, escape-aware). |
See DOCUMENTATION.md for the complete public API and
CLAUDE.md for the spec gotchas that shape the implementation.
Development
pip install -e .[dev]
pytest # run the test suite (includes four round-trip fixtures)
ruff check . # lint
ruff format --check .
mypy src/icfpy # type-check
License
Copyright (c) 2026 Edison Williams. The ICF/ICX specifications are licensed under CC BY 4.0. The icfpy library is licensed under MIT License.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file icfpy-1.2.1.tar.gz.
File metadata
- Download URL: icfpy-1.2.1.tar.gz
- Upload date:
- Size: 128.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/7.0.0 CPython/3.14.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
aa466e2e77594ecc177d60d8517436bbcde9025b07b249477fd6ce3378f67043
|
|
| MD5 |
94610a31d63bec3387f8932169c73a35
|
|
| BLAKE2b-256 |
89736506366235389d169533a50fa2e231e11df8c0269845ca0649ea2f8dd47b
|
File details
Details for the file icfpy-1.2.1-py3-none-any.whl.
File metadata
- Download URL: icfpy-1.2.1-py3-none-any.whl
- Upload date:
- Size: 56.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/7.0.0 CPython/3.14.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
6e1d3c715a442bbdc08307ab9b9afc7c29b6e0a4699cd45c6b5cdc3b8300ad7a
|
|
| MD5 |
5eb94033f51428c75aa1fccf55219990
|
|
| BLAKE2b-256 |
d4cad86a3f9574abca1f8a265140ec0cb9f5a8ab8254cc20075e1fe2b44cec10
|