Skip to main content

Configurable fitness functions plugin for SQLMesh projects

This project has been archived.

The maintainers of this project have marked this project as archived. No new releases are expected.

Project description

sqlmesh-ff

Configurable fitness functions plugin for SQLMesh projects.

Ships SQLMesh linter rules (classification macros, SQL complexity, metadata, naming) and architectural checks (layer integrity, custom exclusions, schema contracts, dependency graph) with a unified Rich lint report.

Installation

# Install directly from GitHub:
uv add git+https://github.com/tjirab/sqlmesh-ff.git

# Or from a local checkout:
uv add ../sqlmesh-ff

Quick start

  1. Add fitness_functions.yaml to your SQLMesh project root (see Configuration).
  2. Add a small config.py bootstrap (see Where configuration lives) — SQLMesh requires the loader as a Python class and cannot load config.py and config.yaml in the same folder.
  3. Run lint:
sqlmesh-ff lint

Where configuration lives

There are three layers. Only the YAML/JSON files in your project are user-editable settings.

Layer File Role You edit this?
Plugin defaults sqlmesh_ff/config.py (installed package) Pydantic schema and built-in defaults (e.g. fan_out_warn: 15) No — library code, never overwritten
SQLMesh project settings.yaml Gateways, linter.rules, variables, CI/CD bot Yes — normal SQLMesh config
Fitness functions fitness_functions.yaml Thresholds, rule toggles, column naming/type rules, paths to JSON data Yes — main FF config
Loader bootstrap config.py (project root) Loads settings.yaml and registers FitnessLoader Rarely — ~15 lines of wiring
Contract data linter_contract_groups.json, linter_exclusions.json Repo-specific schema parity and dependency exclusions Yes — project data

Merge order for fitness settings: plugin defaults → fitness_functions.yaml → optional loader_kwargs overrides in config.py. Your YAML always wins over plugin defaults. The project config.py does not hold fitness thresholds — it only points at fitness_functions.yaml.

Why config.py exists: SQLMesh accepts loader: FitnessLoader only as a Python class, not as a YAML string. Because SQLMesh rejects having both config.py and config.yaml in one folder, projects use settings.yaml (SQLMesh settings) plus config.py (loader registration).

Example bootstrap:

from pathlib import Path

from sqlmesh.core.config import Config
from sqlmesh.utils.yaml import load as yaml_load
from sqlmesh_ff.loader import FitnessLoader

_settings = yaml_load(Path(__file__).parent / "settings.yaml")
config = Config.parse_obj(_settings).update_with({
    "loader": FitnessLoader,
    "loader_kwargs": {"fitness_functions_config": "fitness_functions.yaml"},
})

Enable individual SQLMesh rules in settings.yaml under linter.rules / linter.warn_rules.

Configuration

Fitness function settings live in fitness_functions.yaml at the project root. Override the file path or individual keys via loader_kwargs in config.py (advanced — most projects only set fitness_functions_config).

Example fitness_functions.yaml

contract_groups_path: linter_contract_groups.json
exclusions_path: linter_exclusions.json

layers:
  order: [sources, derived, core, marts, export]

checks:
  layer_integrity: { enabled: true }
  custom_exclusions: { enabled: true }
  schema_contracts: { enabled: true }
  dependency_graph:
    enabled: true
    fan_out_warn: 15
    fan_out_fail: 25
    fan_in_warn: 10

rules:
  classification_macros:
    enabled: true
    skip_layers: [sources]
    columns:
      product_type: "@product_type\\b|@PRODUCT_TYPE\\b"
  sql_complexity:
    enabled: true
    thresholds:
      decision_points: [15, 25]
      cte_count: [8, 12]
      join_count: [8, 12]
      line_count: [250, 400]
  mart_naming:
    enabled: true
    layer_name: marts
    rule: prefix_with_subdirectory
  column_names:
    enabled: true
    replacements: {}
  column_types:
    enabled: true
    rules: []
    equivalent_types:
      text: [text, varchar]
  metadata:
    owner: true
    description: true
    grain: true
  filename_equals_modelname:
    enabled: true

Project-specific JSON

Keep repo-specific contract and exclusion data in your project:

  • linter_contract_groups.json — cross-model schema parity groups
  • linter_exclusions.json — blocked dependency patterns and allowed exceptions

Reference their paths from fitness_functions.yaml. The plugin ships generic engines only; examples live in this README.

Rule name mapping

SQLMesh uses lowercase class names in linter.rules:

Config key SQLMesh rule name
classification_macros classificationmacros
sql_complexity sqlcomplexity
mart_naming martmodelnamingconvention
column_names columnnames
column_types columntypes
metadata.owner nomissingowner
metadata.description nomissingdescription
metadata.grain nomissinggrain
filename_equals_modelname filenameequalsmodelname

CLI

sqlmesh-ff lint [--project PATH] [--config PATH] [--checks CHECK,...] [--fail-level error|warning] [--group-by connascence|model]
  • Default: all enabled checks plus SQLMesh linter rules
  • --checks layer_integrity,custom_exclusions: run subset (for pre-push hooks)
  • --fail-level warning: treat warnings as failures
  • --group-by connascence|model: change how violations are grouped in the report (default: connascence)

Integration example

Example overrides. api_request should always be named api_call. _id columns should always be of type text and is_ columns should always be of type boolean.

column_names:
  replacements:
    api_request: api_call
column_types:
  rules:
    - name: id_is_text
      pattern: "_id$"
      data_type: text
    - name: boolean
      pattern: "^is_"
      data_type: boolean

Examples

A complete, runnable example project showcasing the configuration of sqlmesh-ff rules, exclusions, contracts, and a continuous integration workflow is located in the examples/ directory.

To run the linter against the example project locally, run:

sqlmesh-ff lint --project examples/minimal-sqlmesh-project

See examples/minimal-sqlmesh-project/fitness_functions.yaml to inspect the configured rules.

Development

Initialize your local environment and configure the Git pre-push hook:

make init

Run linter, tests, or check diff coverage:

make lint
make test
make coverage

Releases and PR titles

Releases are automated with release-please on merges to main. Use Conventional Commits in PR titles so changelog entries and semver bumps are correct.

PR titles must start with a type prefix, for example:

  • feat: add dependency graph fan-in check
  • fix: remove unused import in loader tests
  • docs: document fitness_functions.yaml merge order
  • ci: add release-please workflow

Supported types include feat, fix, docs, style, refactor, perf, test, build, ci, and chore. The PR title check in CI enforces this format.

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

sqlmesh_ff-0.1.3.tar.gz (104.8 kB view details)

Uploaded Source

Built Distribution

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

sqlmesh_ff-0.1.3-py3-none-any.whl (29.6 kB view details)

Uploaded Python 3

File details

Details for the file sqlmesh_ff-0.1.3.tar.gz.

File metadata

  • Download URL: sqlmesh_ff-0.1.3.tar.gz
  • Upload date:
  • Size: 104.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for sqlmesh_ff-0.1.3.tar.gz
Algorithm Hash digest
SHA256 c955b9b1d4a0a13ab1d0c3aa203df11fc7f5b17a54f9e8f6acefe8073835f7cf
MD5 9ec65834de9e91e5e235ec49850a48be
BLAKE2b-256 2961988e6c64c62d1e0406c68e341fecefec005ec5a25ca94be39bc9a5165615

See more details on using hashes here.

Provenance

The following attestation bundles were made for sqlmesh_ff-0.1.3.tar.gz:

Publisher: release-please.yml on tjirab/sqlmesh-ff

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

File details

Details for the file sqlmesh_ff-0.1.3-py3-none-any.whl.

File metadata

  • Download URL: sqlmesh_ff-0.1.3-py3-none-any.whl
  • Upload date:
  • Size: 29.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for sqlmesh_ff-0.1.3-py3-none-any.whl
Algorithm Hash digest
SHA256 67e930ea5c13c5a36097e5d32dd271ffc0778b3b7ada4f55c8fa8521ed716e14
MD5 b17fdbc6ff48673114cb0e93f38c5b42
BLAKE2b-256 18f6f63cd5408a27be90cb7628a65cd1daa8d98bcfa43b0de2bb99ff443aa467

See more details on using hashes here.

Provenance

The following attestation bundles were made for sqlmesh_ff-0.1.3-py3-none-any.whl:

Publisher: release-please.yml on tjirab/sqlmesh-ff

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