DeCatenator
decat is a small command-line tool that unpacks code embedded in Markdown.
It reads headings that look like file paths and writes the accompanying code
to real files.
- Input rule – a level-2 or level-3 heading whose text is a single path
segment (no spaces).
Examples:
## main.py,### src/utils/helpers.js. Anything with spaces (e.g.## My Heading) is ignored. - Code source
- If the heading is followed (after optional blank lines) by a fenced block
opened with triple back-ticks, those lines become the file content.
The closing fence must be exactly
```(no language tag). - Otherwise, all lines until the next matching heading (or EOF) are taken as the file content.
- If the heading is followed (after optional blank lines) by a fenced block
opened with triple back-ticks, those lines become the file content.
The closing fence must be exactly
- Creates parent directories as needed and overwrites existing files.
- Works with a file argument or
stdin.
Note: This project is the inverse of Catenator.
Quick start
pip install decat
CLI
# write files into the current directory
decat article.md
# write into a different root
decat article.md -o ./extracted
# read from stdin
cat article.md | decat -
# version
decat --version
Example – fenced
### src/hello.py
```python
print("Hello, world!")
Running `decat readme.md` generates `src/hello.py` containing:
```python
print("Hello, world!")
Example – unfenced
## scripts/build.sh
#!/usr/bin/env bash
echo "building"
decat docs.md writes scripts/build.sh with the two lines above.
Programmatic use
from pathlib import Path
from decat import extract_files, write_files
with open("notes.md", "r", encoding="utf-8") as f:
lines = f.readlines()
pairs = extract_files(lines) # yields (rel_path, code)
write_files(pairs, Path("out")) # creates ./out/...
How it works
-
Regex
^#{2,3}\s+([^\s]+)\s*$recognises valid headings. -
Searches forward:
- if the next non-blank line matches
^```.*$, capture until a bare ```; otherwise capture until the next valid heading.
- if the next non-blank line matches
-
Raises
SyntaxErrorif a fenced block is unterminated. -
All IO logic is isolated in
src/decat/_core.py; CLI lives insrc/decat/cli.py.
Repository layout
./
│ README.md
│ pyproject.toml
│ MANIFEST.in
├── src/
│ └── decat/
│ ├── _core.py
│ ├── cli.py
│ └── __init__.py
└── tests/
└── test_core.py
Development
# editable install
pip install -e .
# run the test suite
pytest
# build sdist & wheel
python -m build
# upload (requires credentials)
twine upload dist/*
Metadata
Release files for decatenator 0.1.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 | Provenance | Actions |
|---|---|---|---|---|
| decatenator-0.1.0.tar.gz | 13.6 kB | Without provenance | Details for decatenator-0.1.0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| decatenator-0.1.0-py3-none-any.whl | Python 3 | none | any | Details for decatenator-0.1.0-py3-none-any.whl |
Total release size: 24.4 kB
Release files / decatenator-0.1.0.tar.gz
| Download URL | decatenator-0.1.0.tar.gz |
|---|---|
| Size | 13.6 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
7c699575b8be28ee081dceeac45357459e5702c9bbda9c5fdb6b300f6c795992
|
|
BLAKE2b-256 checksum How to use checksums |
915130a960d119ef479adae248027d914133c28aab6408b6e25f811e34bded40
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.1.0 CPython/3.12.3
|
Release files / decatenator-0.1.0-py3-none-any.whl
| Download URL | decatenator-0.1.0-py3-none-any.whl |
|---|---|
| Size | 10.8 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
7a20b63934fee86c29bb238c82319be50645ec6e7c868c288ab4b5949fc29c26
|
|
BLAKE2b-256 checksum How to use checksums |
52511773ad0f36cc9698a0d2eba35ccf9399853f33ab57d26a2fc7b963d4f595
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.1.0 CPython/3.12.3
|
Security for decatenator 0.1.0
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.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.