Metadata-Version: 2.4
Name: caput
Version: 1.1
Summary: Manage file metadata with YAML front-matter.
Project-URL: Homepage, https://github.com/eykd/caput
Project-URL: Issues, https://github.com/eykd/caput/issues
Project-URL: Repository, https://github.com/eykd/caput
Author-email: David Eyk <david@worldsenoughstudios.com>
License-Expression: MIT
License-File: LICENSE.md
Classifier: Development Status :: 5 - Production/Stable
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: BSD License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Topic :: Software Development :: Libraries
Requires-Python: >=3.11
Requires-Dist: funcy
Requires-Dist: ruamel-yaml
Description-Content-Type: text/x-rst

Caput
=====

Easy file metadata.

Store metadata in a special YAML configuration header for text files, or a
sidecar "shadow" configuration file for binary files.

*Caput:* **n.** Latin for "head" or "top". Root of many English words, such as
"captain", "capital", and "decapitate".

Install
-------

Caput is available from PyPI::

    pip install caput

Usage
-----

Say that you're building a static site generator. You can add a metadata header
to any textfile. The first three bytes *must* be ``---\n``. In ``index.md``::

    ---
    title: My Site
    author: Me
    featured_image: /images/my-header.jpg
    ---
    # Welcome to my site!

Read the metadata header::

    >>> import caput

    >>> caput.read_config('./index.md', defaults={'markup': 'markdown'})
    {'markup': 'markdown',
     'title': 'My Site',
     'author': 'Me',
     'featured_image': '/images/my-header.jpg'}

Read the file contents::

    >>> caput.read_contents('./index.md')
    '# Welcome to my site!\n'

Write metadata headers to files::

    >>> metadata = {
    ...     'title': 'My New Post',
    ...     'author': 'Me',
    ...     'date': '2024-01-15'
    ... }

    >>> content = '# This is my new post\n\nLorem ipsum...'

    >>> caput.write_config('./new-post.md', metadata, content)

    >>> # Verify the file was written correctly
    >>> caput.read_config('./new-post.md')
    {'title': 'My New Post', 'author': 'Me', 'date': '2024-01-15'}

    >>> caput.read_contents('./new-post.md')
    '# This is my new post\n\nLorem ipsum...'

Update existing metadata::

    >>> # Read existing metadata
    >>> config = caput.read_config('./index.md')
    >>> config['updated'] = '2024-01-15'
    >>> config['tags'] = ['blog', 'personal']

    >>> # Write back with updated metadata
    >>> caput.write_config('./index.md', config)

Read & write contents::

    >>> content = caput.read_contents('./index.md')
    >>> config = caput.read_config('./index.md')
    >>> config['updated'] = '2025-09-09'
    >>> content += '\n\nUpdated on 2025-09-09'
    >>> caput.write_contents('./index.md', content, config)


Shadow Files for Binary Content
--------------------------------

You can add metadata to binary files with a "shadow" header. For your featured
image, add a ``.yml`` file with the same base name, e.g. for
``./images/my-header.jpg`` you would add ``./images/my-header.yml``::

    title: My Site Header
    credit: Me

Read the metadata header::

    >>> caput.read_config('./images/my-header.jpg')
    {'title': 'My Site Header', 'credit': 'Me')

Read the file contents::

    >>> caput.read_contents('./images/my-header.jpg', encoding=None)
    b'...binary data...'

Write metadata for binary files::

    >>> # Create metadata for a binary file using a shadow YAML file
    >>> binary_metadata = {
    ...     'title': 'Site Logo',
    ...     'credit': 'Design Team',
    ...     'license': 'CC BY 4.0'
    ... }

    >>> caput.write_shadow_config('./images/logo.png', binary_metadata)

    >>> # This creates ./images/logo.yml with the metadata
    >>> caput.read_config('./images/logo.png')
    {'title': 'Site Logo', 'credit': 'Design Team', 'license': 'CC BY 4.0'}
