Skip to main content

A Python implementation of the Configuration File (CF) format - a human-readable, machine-parseable data serialization format

Project description

configuration-file

A Python implementation of the Configuration File (CF) format - a human-readable, machine-parseable data serialization format for configuration files.

License Python PyPI

What is CF?

CF (Configuration File) is a modern configuration format designed to address common shortcomings of existing formats like JSON, YAML, TOML, and INI:

  • Human-readable: Clean, minimal syntax with comments
  • Machine-parseable: Simple, unambiguous LL(1) grammar
  • Whitespace-independent: Structure uses explicit delimiters ({ } and [ ]), not indentation
  • Copy-paste safe: Configuration survives email, chat, wikis, and forums
  • Type-safe: Explicit typing with no implicit conversions
  • Extensible: Includes for configuration reuse across files

See the official CF Specification for complete details, or the local copy included in this repository.

Installation

pip install configuration-file

For development:

pip install configuration-file[dev]

Usage

Simple API (dict-based)

import cf

# Parse a CF file
config = cf.load("config.cf")

# Parse a CF string
config = cf.loads('''
    app_name = "my-service"
    debug = true
''')

# Access values
print(config["app_name"])  # "my-service"
print(config["server"]["port"])  # 8080

# Serialize to CF format
cf_string = cf.dumps(config)

# Write to a file
cf.dump(config, "output.cf")

Roundtrip API (preserves formatting)

import cf

# Parse into a CFDocument that preserves comments, whitespace,
# quote styles, and separator choices
doc = cf.loads_document('''
    # Server configuration
    server {
        host = "localhost"
        port = 8080
    }
''')

# Read values
host = doc.get("server.host")  # "localhost"

# Modify values (only changed values are re-rendered)
doc.set("server.port", 9090)

# Serialize back with minimal diffs
output = doc.serialize()
# Comments, whitespace, and formatting are preserved

# Convert to plain dict when formatting isn't needed
config = doc.to_dict()

Features

  • Full CF 1.0 specification support
  • Comments: Hash (#), double-slash (//), and block (/* */) comments
  • Data types: Strings, integers, floats, booleans, null, dates, times, datetimes
  • Collections: Objects and arrays with flexible syntax
  • String variants: Double-quoted, single-quoted, triple-quoted, and raw strings
  • Environment variable substitution: ${VAR}, ${VAR:-default}, ${VAR:?error}
  • File includes: include "path/to/file.cf"
  • Roundtrip preservation: Parse, modify, and serialize with minimal diffs

Development

Setup

  1. Clone the repository:
git clone https://codeberg.org/configuration-file/py.git
cd py
  1. Create a virtual environment and install dependencies:
python -m venv .venv
source .venv/bin/activate  # On Windows: .venv\Scripts\activate
pip install -e ".[dev]"

Running Tests

pytest

With coverage:

pytest --cov=cf --cov-report=html

Code Quality

Lint and format code:

ruff check .
ruff format .

Type checking:

mypy src/cf

Full Example

CF files use the .cf extension. Here is a comprehensive example demonstrating all features of the CF format:

# =============================================================================
# Complete CF 1.0 Feature Demonstration
# =============================================================================

# -----------------------------------------------------------------------------
# Comments
# -----------------------------------------------------------------------------
# Hash comments (like this one)
// Double-slash comments (C++ style)
/* Block comments
   can span multiple
   lines */

# -----------------------------------------------------------------------------
# String Types
# -----------------------------------------------------------------------------
strings {
    double_quoted = "Hello, World!"
    with_escapes = "Line 1\nLine 2\tTabbed"
    with_unicode = "Caf\u00E9 \U0001F600"
    with_quotes = "She said \"Hello\""

    single_quoted = 'It\'s working'
    contains_double = 'He said "hello"'

    # Triple-quoted strings (no escape processing, preserves whitespace)
    multiline = """
        SELECT id, name, email
        FROM users
        WHERE active = true
        ORDER BY created_at DESC
    """

    # Raw strings (no escape processing)
    raw_double = r"C:\Program Files\App\config.ini"
    raw_single = r'^\d{3}-\d{4}$'
    regex_pattern = r"https?://[\w\-\.]+\.[a-z]{2,}"

    empty_double = ""
    empty_single = ''
}

# -----------------------------------------------------------------------------
# Number Types
# -----------------------------------------------------------------------------
numbers {
    decimal = 42
    negative = -17
    zero = 0
    large = 9223372036854775807
    with_separators = 1_000_000_000

    hexadecimal = 0xFF
    octal = 0o755
    binary = 0b10101010

    simple_float = 3.14159
    negative_float = -273.15
    scientific = 6.022e23
    float_with_sep = 1_234.567_890

    positive_infinity = inf
    negative_infinity = -inf
    not_a_number = nan
}

# -----------------------------------------------------------------------------
# Boolean and Null Types
# -----------------------------------------------------------------------------
primitives {
    enabled = true
    disabled = false
    optional_value = null
}

# -----------------------------------------------------------------------------
# Date and Time Types (ISO 8601)
# -----------------------------------------------------------------------------
temporal {
    release_date = 2024-06-15
    meeting_time = 14:30:00
    precise_time = 09:15:30.123456

    local_datetime = 2024-06-15T10:30:00
    utc_datetime = 2024-06-15T10:30:00Z
    positive_offset = 2024-06-15T10:30:00+05:30
    negative_offset = 2024-06-15T10:30:00-08:00
    with_microseconds = 2024-06-15T10:30:00.123456Z
}

# -----------------------------------------------------------------------------
# Objects
# -----------------------------------------------------------------------------
# HCL-style (without =)
server {
    host = "localhost"
    port = 8080
}

# JSON-style (with =)
database = {
    driver = "postgres"
    host = "db.example.com"
}

# Inline with semicolons or commas
point = { x = 10; y = 20; z = 30 }
color = { r = 255, g = 128, b = 64 }

# Empty object
empty_config = {}

# Deeply nested
deeply_nested {
    level1 {
        level2 {
            level3 {
                value = "deep"
            }
        }
    }
}

# -----------------------------------------------------------------------------
# Arrays
# -----------------------------------------------------------------------------
arrays {
    numbers = [1, 2, 3, 4, 5]
    strings = ["apple", "banana", "cherry"]

    # Multi-line with newline separators
    fruits = [
        "apple"
        "banana"
        "cherry"
        "date"
    ]

    # Semicolon separators
    ports = [8080; 8443; 9000]

    # Heterogeneous arrays (mixed types)
    mixed_types = [42, "hello", true, null, 3.14, 2024-06-15]

    # Nested arrays (matrix)
    matrix = [
        [1, 2, 3]
        [4, 5, 6]
        [7, 8, 9]
    ]

    # Array of objects
    users = [
        { name = "Alice"; role = "admin"; active = true }
        { name = "Bob"; role = "user"; active = true }
        { name = "Charlie"; role = "user"; active = false }
    ]

    empty = []
}

# -----------------------------------------------------------------------------
# Identifiers (Keys)
# -----------------------------------------------------------------------------
identifiers {
    simple = "value"
    with_underscore = "value"
    _private = "value"
    my-key = "value"

    # Unicode identifiers
    café = "coffee"
    日本語 = "Japanese"

    # Quoted keys for special characters
    "123numeric" = "starts with digit"
    "hello world" = "contains space"
    "key=value" = "contains special char"
}

# -----------------------------------------------------------------------------
# Environment Variable Substitution
# -----------------------------------------------------------------------------
environment {
    home_dir = ${HOME}
    server_host = ${SERVER_HOST:-localhost}
    server_port = ${SERVER_PORT:-8080}

    # String interpolation
    database_url = "postgresql://${DB_USER:-postgres}:${DB_PASS:-secret}@${DB_HOST:-localhost}:${DB_PORT:-5432}/${DB_NAME:-myapp}"
    log_path = "${LOG_DIR:-/var/log}/app.log"

    # Escaped (literal ${})
    literal_syntax = "Use \${VAR} for variable syntax"
}

# -----------------------------------------------------------------------------
# Real-World Example
# -----------------------------------------------------------------------------
application {
    name = "MyApplication"
    version = "2.0.0"

    server {
        host = "0.0.0.0"
        port = 8080
        workers = 4

        ssl {
            enabled = true
            cert = "/etc/ssl/certs/app.crt"
            key = "/etc/ssl/private/app.key"
            protocols = ["TLSv1.2", "TLSv1.3"]
        }

        timeouts { connect = 5; read = 30; write = 10 }
    }

    database {
        primary {
            driver = "postgres"
            host = ${DB_HOST:-db.example.com}
            port = 5432
            pool = { min = 5, max = 20, idle_timeout = 300 }
        }
    }

    features = ["auth", "api", "webhooks", "analytics"]

    cron_jobs = [
        { name = "cleanup"; schedule = "0 2 * * *"; command = "cleanup.sh" }
        { name = "backup"; schedule = "0 3 * * *"; command = "backup.sh" }
    ]

    metadata {
        created = 2024-01-15T10:30:00Z
        updated = 2024-06-15T14:45:00Z
        maintainer = "devops@example.com"
    }
}

License

This project is licensed under the BSD-3-Clause License - see the LICENSE file for details.

Copyright (c) 2026 Dejan Lekić.

Project details


Download files

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

Source Distribution

configuration_file-2.1.2.tar.gz (46.4 kB view details)

Uploaded Source

Built Distribution

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

configuration_file-2.1.2-py3-none-any.whl (38.3 kB view details)

Uploaded Python 3

File details

Details for the file configuration_file-2.1.2.tar.gz.

File metadata

  • Download URL: configuration_file-2.1.2.tar.gz
  • Upload date:
  • Size: 46.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.4

File hashes

Hashes for configuration_file-2.1.2.tar.gz
Algorithm Hash digest
SHA256 d279ead7cf1c61ca799f7244dd9e23e699d215de77cd81c2e2d150e867f7c9f6
MD5 24d88382ccfd2c0fc1fbf2e04406ac1c
BLAKE2b-256 89d4307cf8ba3c65149f9258f18772f21fbbaa969b2e1eb825ec7b4cf3fe9297

See more details on using hashes here.

File details

Details for the file configuration_file-2.1.2-py3-none-any.whl.

File metadata

File hashes

Hashes for configuration_file-2.1.2-py3-none-any.whl
Algorithm Hash digest
SHA256 45298a3f2f19b36b85326ec3ed57504b77faa12cae22da0472aa9bed9e6810d3
MD5 cb3c43e4b68ae0d5603bbd34d27226bf
BLAKE2b-256 08cc554e9b4763ec67521804329de8c356906ac207b0b51b8a39ae905112bf3d

See more details on using hashes here.

Supported by

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