Skip to main content

mgnolia

Declarative filesystem structure and content validation for Python.

Define the expected layout of a directory using Dir and File nodes, optionally attach content validation rules, then call validate_all() to check a real directory against your schema. All errors are collected and returned as typed objects—nothing raises.

Installation

pip:

pip install mgnolia

uv:

uv add mgnolia

Quick Start

from mgnolia import Dir, File, Schema

# Define expected structure
schema = Schema(
    children=[
        Dir(
            path="data",
            description="Data directory",
            children=[
                File(path="input.csv"),
                File(path="output.json"),
            ],
        ),
        File(path="config.yaml"),
    ]
)

# Validate a directory
ok = schema.validate_all("/path/to/project")

if not ok:
    for error in schema.errors:
        print(error)
else:
    print("All checks passed!")

Content Rules

Attach validation rules to files to check their contents:

from mgnolia import File
from mgnolia.content import FileNotEmptyRule, CSVSchemaRule
from pydantic import BaseModel

class UserRow(BaseModel):
    id: int
    name: str
    email: str

File(
    path="users.csv",
    content_rules=[
        FileNotEmptyRule(),
        CSVSchemaRule(schema=UserRow),
    ],
)

Built-in rules:

  • FileNotEmptyRule() — fails if file is empty
  • CSVSchemaRule(schema=PydanticModel) — validates CSV against a Pydantic model using pandera

Rules can also publish a value for a later node to use:

from mgnolia import File, Schema, Value
from mgnolia.content import RowCountRule

user_count = Value[int]("users.row_count")
avatar_count = Value[int]("avatars.match_count")

schema = Schema(children=[
    File(path="users.parquet", content_rules=[
        RowCountRule(min=1, max=10_000, output=user_count),
    ]),
    File(
        path="user_avatars/*.png",
        min_matches=0,
        max_matches=user_count.ref(),
        output=avatar_count,
    ),
])

Custom rules: Custom rules are subclasses of ContentRule (and optionally raising subclasses of ContentValidationError), which implemennt a validate method on the node (Dir or more typically File). They may also publish custom Values for use in later rules.

As a realistic example, to validate that a directory contains TSV files named by a known format like an Accession, e.g. ERR123456.tsv, ERR987654.tsv etc, AND that each file contains the same accession it is named by (so like grep -q 'ERR123456' ERR123456.tsv) we could define the following custom rules and values:

import re
from pathlib import Path

from mgnolia import Dir, File, Ref, Schema, Value
from mgnolia.content import ContentRule
from mgnolia.errors import ContentValidationError
from mgnolia.schema import Node


class FilenameRule(ContentRule):
    def __init__(self, output: Value[str]) -> None:
        super().__init__(output)
        self.accession = output

    def validate(self, node: Node, path: Path) -> list[ContentValidationError]:
        self.accession.set(path.stem)
        if re.fullmatch(r"ERR\d{6}\.tsv", path.name):
            return []
        return [ContentValidationError(node, path)]


class ContainsTextRule(ContentRule):
    def __init__(self, expected: Ref[str]) -> None:
        super().__init__()
        self.expected = expected

    def validate(self, node: Node, path: Path) -> list[ContentValidationError]:
        expected = self.expected.resolve()
        if expected in path.read_text(encoding="utf-8"):
            return []
        return [ContentValidationError(node, path)]


accession = Value[str]("current_accession")

schema = Schema(children=[
    Dir(path="runs", children=[
        File(
            path="*.tsv",
            max_matches=None,
            content_rules=[
                FilenameRule(output=accession),
                ContainsTextRule(accession.ref()),
            ],
        ),
    ]),
])

This example works because content rules run in list order for each matched file. Thus, for ERR123456.tsv, FilenameRule publishes ERR123456 and ContainsTextRule consumes it while validating that same file.

References between separate nodes resolve in declaration order, so the top-level subtree producing a value must appear before the subtree consuming it. Compatible Ref values can be used for any parameter of the built-in content rules, as well as min_matches and max_matches.

Observations can be published with output= even when their validation fails (so that the validation report is as "complete" as possible):

  • File and Dir output their actual number of matches.
  • FileNotEmptyRule outputs the file size in bytes.
  • CSVSchemaRule and ParquetSchemaRule output the actual Polars schema.
  • RowCountRule outputs the actual row count.
  • SortedRule outputs the column's (min, max) values.

Error Types

When validation fails, schema.errors contains typed error objects:

  • Structure errors: FileMissingError, DirectoryMissingError, MinMatchError, MaxMatchError
  • Content errors: FileEmptyError, ContentSchemaError

All inherit from ValidationError and have .path and .node attributes. Use str(error) to get a formatted message.

Pattern Matching

Dir and File paths support glob patterns to match multiple files or directories:

File(path="*.log", min_matches=1)  # At least one .log file
Dir(path="test_*", max_matches=5)  # At most 5 test_* directories

License

MIT

Download files

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

Source Distribution

mgnolia-0.4.0.tar.gz (8.8 kB view details)

Uploaded Source

Built Distribution

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

mgnolia-0.4.0-py3-none-any.whl (10.8 kB view details)

Uploaded Python 3

File details

Details for the file mgnolia-0.4.0.tar.gz.

File metadata

  • Download URL: mgnolia-0.4.0.tar.gz
  • Upload date:
  • Size: 8.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for mgnolia-0.4.0.tar.gz
Algorithm Hash digest
SHA256 b4eda690d9d405ad042b2277b85b1a936460e59c70e8082125d52f72fdba0b0d
MD5 1325b9a49fbbdd50e313b8f8a2a3456a
BLAKE2b-256 d24b3e2f8bffba174b0c45534200107b62d18a87bccbbd99542ea92e2745f515

See more details on using hashes here.

Provenance

The following attestation bundles were made for mgnolia-0.4.0.tar.gz:

Publisher: release.yml on EBI-Metagenomics/mgnolia

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file mgnolia-0.4.0-py3-none-any.whl.

File metadata

  • Download URL: mgnolia-0.4.0-py3-none-any.whl
  • Upload date:
  • Size: 10.8 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for mgnolia-0.4.0-py3-none-any.whl
Algorithm Hash digest
SHA256 47249c910ff603395198cca9ad9727e92b0fdc0829a13d0770aa9cf8ac22f663
MD5 55547a1651ff589b127d59a698366cb8
BLAKE2b-256 4681c1c5c95237fc5c353b64b0102e6b189abf4e922e9effab3c279c648f80fa

See more details on using hashes here.

Provenance

The following attestation bundles were made for mgnolia-0.4.0-py3-none-any.whl:

Publisher: release.yml on EBI-Metagenomics/mgnolia

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Release history Release notifications | RSS feed

This release

0.4.0 This release

2 files

0.3.0

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