Skip to main content

Pytest plugin that allows you to easily define data-driven fixtures based on external files.

Project description

Fingest — Pytest Data-Driven Fixtures

PyPI version Python versions License: MIT

A pytest plugin that turns JSON, CSV, and XML files into fully-typed, iterable test fixtures — no boilerplate required.

Quick Start

1. Install

pip install fingest

2. Point pytest at your data

# pytest.ini  (or pyproject.toml under [tool.pytest.ini_options])
[pytest]
fingest_fixture_path = tests/data

3. Define fixtures in conftest.py

from fingest import data_fixture, JSONFixture, CSVFixture, XMLFixture

@data_fixture("users.json", description="Test user data")
class user_data(JSONFixture):
    pass

@data_fixture("products.csv", description="Product catalog")
class product_data(CSVFixture):
    pass

@data_fixture("config.xml", description="App configuration")
class config_data(XMLFixture):
    pass

4. Use them in tests

def test_users(user_data):
    assert len(user_data) == 2
    assert "Alice" in [u["name"] for u in user_data]  # iterable!

def test_expensive_products(product_data):
    expensive = product_data.filter_rows(price=lambda p: float(p) > 100)
    assert len(expensive) >= 1

def test_db_host(config_data):
    assert config_data.get_text("database/host") == "localhost"

Fixture Types

BaseFixture

All fixtures inherit from BaseFixture, which gives you:

Feature Example
Length len(fixture)
Truthiness if fixture:
Iteration for item in fixture:
Containment "key" in fixture
Equality fixture_a == fixture_b
Raw data fixture.data

JSONFixture

For dict or list JSON data.

fixture["users"]          # direct indexing
fixture.get("key", None)  # safe access
fixture.keys()            # dict keys
for key in fixture:       # iterate keys (dict) or items (list)
"name" in fixture         # containment check

CSVFixture

For tabular CSV data.

fixture.rows              # all rows as list of dicts
fixture.row_count         # number of rows
fixture.columns           # column names
fixture.get_column("age") # all values from one column
fixture[0]                # first row

# filter with exact values or predicates
fixture.filter_rows(city="NYC")
fixture.filter_rows(price=lambda p: float(p) > 100)

for row in fixture:       # iterate rows
{"name": "Bob"} in fixture  # row membership

XMLFixture

For XML data, powered by lxml.

fixture.root              # root Element
fixture.tag               # root tag name
fixture.find("db/host")   # first matching element
fixture.findall("items/item")  # all matches
fixture.xpath("//feature[@enabled='true']")
fixture.get_text("settings/timeout", default="30")
fixture.to_dict()         # recursive XML → dict conversion

Cloud Storage Adapters

Fingest includes decorators for AWS S3, GCP GCS, and Azure Blob Storage. These are designed for mock-first development: by default, they load data from your local fingest_fixture_path, simulating cloud responses.

1. Define Cloud Fixtures

from fingest import aws_bucket_fixture, gcs_fixture, azure_blob_fixture
from fingest import JSONFixture, CSVFixture, XMLFixture

# AWS S3 (Bucket: "my-bucket", Key: "data/users.json")
@aws_bucket_fixture("my-bucket", "data/users.json", description="S3 users")
class s3_users(JSONFixture): pass

# GCP GCS (Bucket: "my-bucket", Key: "data/products.csv")
@gcs_fixture("my-bucket", "data/products.csv", description="GCS products")
class gcs_products(CSVFixture): pass

# Azure Blob (Container: "my-container", Blob: "data/config.xml")
@azure_blob_fixture("my-container", "data/config.xml", description="Azure config")
class azure_config(XMLFixture): pass

2. Mocking vs. Live Mode

The adapters are in mock mode by default. They will look for files in your local fixture directory using the key as a relative path (e.g., tests/data/data/users.json for the examples above).

To enable live mode (hitting the real cloud SDKs), set mock=False. Note that cloud SDKs (boto3, google-cloud-storage, azure-storage-blob) are optional dependencies and must be installed separately.

@aws_bucket_fixture("my-bucket", "data/users.json", mock=False)
class live_s3_data(JSONFixture): pass

Function-Based Fixtures

For custom data transformations or fixtures that depend on other pytest fixtures:

@data_fixture("raw_data.json")
def processed_users(data):
    """data is injected by fingest; remaining params are pytest fixtures."""
    return [{"name": f"{u['first']} {u['last']}"} for u in data["users"]]

@data_fixture("config.json")
def config_with_db(data, database_fixture):
    """Depends on another pytest fixture — works seamlessly."""
    return {"config": data, "db": database_fixture}

Custom Data Loaders

Support any file format by registering a loader:

from fingest import register_loader
import yaml

def yaml_loader(path):
    with open(path) as f:
        return yaml.safe_load(f)

register_loader("yaml", yaml_loader)

Or use a one-off loader for a single fixture:

@data_fixture("data.toml", loader=toml_loader)
class toml_config(BaseFixture):
    pass

API Reference

@data_fixture(file_path, description="", loader=None)

Register a class or function as a data-driven fixture.

Parameter Type Description
file_path str Path to data file, relative to fingest_fixture_path
description str Optional label for debugging / docs
loader callable Optional custom loader (Path) → Any

register_loader(extension, loader_func)

Register a custom data loader globally for a file extension (without dot).

Base Classes

Class Key Methods
BaseFixture data, description, len(), bool(), iter(), in, ==
JSONFixture keys(), values(), items(), get(), length(), []
CSVFixture rows, row_count, columns, get_column(), filter_rows(), []
XMLFixture root, tag, find(), findall(), xpath(), get_text(), to_dict()

Development

git clone https://github.com/0x68/fingest.git
cd fingest
uv sync
uv run pytest

License

MIT — see LICENSE.


Made with ❤️ by Tim Fiedler

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

fingest-1.1.0.tar.gz (70.8 kB view details)

Uploaded Source

Built Distribution

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

fingest-1.1.0-py3-none-any.whl (15.1 kB view details)

Uploaded Python 3

File details

Details for the file fingest-1.1.0.tar.gz.

File metadata

  • Download URL: fingest-1.1.0.tar.gz
  • Upload date:
  • Size: 70.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for fingest-1.1.0.tar.gz
Algorithm Hash digest
SHA256 a274bac8f36f75558d8994be0d521ed931074ac4fa9f3c8ef4b23dee3b02ae51
MD5 0dbf1790f5439b8f6ab688e3bd3c1501
BLAKE2b-256 278da59a9503b23baa608d9a41bd8234969b4dfb56bec279b2a943fe3fc1d407

See more details on using hashes here.

Provenance

The following attestation bundles were made for fingest-1.1.0.tar.gz:

Publisher: workflow.yml on 0x68/fingest

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

File details

Details for the file fingest-1.1.0-py3-none-any.whl.

File metadata

  • Download URL: fingest-1.1.0-py3-none-any.whl
  • Upload date:
  • Size: 15.1 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for fingest-1.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 97ea89af043c8a1fa750f2ee0e6290a26b0a7fbe456d96d031aa530cd35efc05
MD5 2fbd008ed533f2f9bc105e27d7268b4d
BLAKE2b-256 1b5cef2dd90188281a7fb5dd197d13065d74b53ce24ac7fbada6928a67fde318

See more details on using hashes here.

Provenance

The following attestation bundles were made for fingest-1.1.0-py3-none-any.whl:

Publisher: workflow.yml on 0x68/fingest

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

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