Metadata-Version: 2.3
Name: dbt-core-interface
Version: 1.1.7
Summary: Dbt Core Interface
Keywords: dbt,sqlfluff
Author: Alex Butler
Author-email: Alex Butler <butler.alex2010@gmail.com>
License: MIT
Classifier: Development Status :: 4 - Beta
Requires-Dist: dbt-core>=1.8.0,<2.0.0
Requires-Dist: dbt-adapters>=1.3.2
Requires-Dist: rich>10.0
Requires-Dist: typing-extensions ; python_full_version < '3.10'
Requires-Dist: requests>=2.31.0
Requires-Dist: dbt-duckdb ; extra == 'dev'
Requires-Dist: ruff~=0.12.0 ; extra == 'dev'
Requires-Dist: coverage[toml]>=6.2,<7 ; extra == 'dev'
Requires-Dist: pytest>=8.0.0,<9 ; extra == 'dev'
Requires-Dist: sqlfluff>=2.3.2,<4 ; extra == 'dev'
Requires-Dist: mypy>=1.0.0 ; extra == 'dev'
Requires-Dist: types-requests>=2.31.0 ; extra == 'dev'
Requires-Dist: fastapi~=0.115.14 ; extra == 'server'
Requires-Dist: uvicorn~=0.35.0 ; extra == 'server'
Requires-Dist: sqlfluff>=2.3.2,<4 ; extra == 'sqlfluff'
Requires-Dist: dbt-postgres~=1.8.0 ; extra == 'test'
Requires-Dist: dbt-core~=1.8.0 ; extra == 'test'
Requires-Dist: httpx>=0.24.0 ; extra == 'test'
Requires-Dist: psycopg2-binary>=2.8,<3.0 ; extra == 'test'
Requires-Dist: sqlfluff>=2.3.2,<4 ; extra == 'test'
Requires-Python: >=3.10, <3.14
Project-URL: Changelog, https://github.com/z3z1ma/dbt-core-interface/releases
Project-URL: Documentation, https://dbt-core-interface.readthedocs.io
Project-URL: Homepage, https://github.com/z3z1ma/dbt-core-interface
Project-URL: Repository, https://github.com/z3z1ma/dbt-core-interface
Provides-Extra: dev
Provides-Extra: server
Provides-Extra: sqlfluff
Provides-Extra: test
Description-Content-Type: text/markdown

<div id="top">

<!-- HEADER STYLE: CLASSIC -->

<div align="left">

<img src="https://chatgpt.com/backend-api/public_content/enc/eyJpZCI6Im1fNjg2NDkwZjkzNjU4ODE5MTgyYTg0ZDA4YTJmZDU4ZGI6ZmlsZV8wMDAwMDAwMDk4Nzg2MWY1YTAyNGVkOGZjZDQ4MDIyOCIsInRzIjoiNDg2NTA1IiwicCI6InB5aSIsInNpZyI6IjgwM2NlMDg1NzM1YTNjMjEzMzVhYWFhMzg5NDcxMThmYTgzYTE4MzhiNGVkMzRjNTNkNjMzZTVlOTg0NGU3NTAiLCJ2IjoiMCIsImdpem1vX2lkIjpudWxsfQ==" width="30%" style="position: relative; top: 0; right: 0;" alt="Project Logo"/>

# DBT-CORE-INTERFACE

<em>Lightweight, thread-safe, multi-project Python interface to dbt-core</em>

<!-- BADGES -->

<img src="https://img.shields.io/github/license/z3z1ma/dbt-core-interface?style=flat-square&logo=opensourceinitiative&logoColor=white&color=0080ff" alt="license">
<img src="https://img.shields.io/github/last-commit/z3z1ma/dbt-core-interface?style=flat-square&logo=git&logoColor=white&color=0080ff" alt="last-commit">
<img src="https://img.shields.io/github/languages/top/z3z1ma/dbt-core-interface?style=flat-square&color=0080ff" alt="repo-top-language">
<img src="https://img.shields.io/github/languages/count/z3z1ma/dbt-core-interface?style=flat-square&color=0080ff" alt="repo-language-count">

<em>Built with the tools and technologies:</em>

<img src="https://img.shields.io/badge/TOML-9C4121.svg?style=flat-square&logo=TOML&logoColor=white" alt="TOML">
<img src="https://img.shields.io/badge/Rich-FAE742.svg?style=flat-square&logo=Rich&logoColor=black" alt="Rich">
<img src="https://img.shields.io/badge/Ruff-D7FF64.svg?style=flat-square&logo=Ruff&logoColor=black" alt="Ruff">
<img src="https://img.shields.io/badge/GNU%20Bash-4EAA25.svg?style=flat-square&logo=GNU-Bash&logoColor=white" alt="GNU%20Bash">
<img src="https://img.shields.io/badge/FastAPI-009688.svg?style=flat-square&logo=FastAPI&logoColor=white" alt="FastAPI">
<br>
<img src="https://img.shields.io/badge/Pytest-0A9EDC.svg?style=flat-square&logo=Pytest&logoColor=white" alt="Pytest">
<img src="https://img.shields.io/badge/Docker-2496ED.svg?style=flat-square&logo=Docker&logoColor=white" alt="Docker">
<img src="https://img.shields.io/badge/Python-3776AB.svg?style=flat-square&logo=Python&logoColor=white" alt="Python">
<img src="https://img.shields.io/badge/GitHub%20Actions-2088FF.svg?style=flat-square&logo=GitHub-Actions&logoColor=white" alt="GitHub%20Actions">
<img src="https://img.shields.io/badge/uv-DE5FE9.svg?style=flat-square&logo=uv&logoColor=white" alt="uv">
</div>

---

## Overview

`dbt-core-interface` is a lightweight, high-performance Python interface for working directly with `dbt-core` (v1.8+). It allows developers to manage and run dbt projects entirely in memory using an intuitive Python API—enabling runtime SQL compilation, macro evaluation, SQLFluff linting/formatting, and more, all through FastAPI or local usage.

It supports dynamic multi-project environments, automatic re-parsing, file watchers, and asynchronous usage. It is the foundation for more complex interfaces such as `dbt-fastapi` and is designed to rapidly prototype ideas outside the constraints of the dbt-core repo itself.

---

## Features

* 🧐 In-memory dbt-core 1.8+ interface with full `RuntimeConfig` hydration
* ⚡ Fast, thread-safe SQL compilation and execution via FastAPI
* 🔬 Interactive linting and formatting with SQLFluff
* 🌐 Live REST API server via FastAPI
* 🌍 Supports multiple projects simultaneously using `DbtProjectContainer`
* 🚀 Dynamic macro parsing, Jinja rendering, manifest manipulation
* 🔄 Background file watching for auto-reparsing
* ⚖ Direct dbt command passthrough (e.g. `run`, `test`, `docs serve`, etc.)
* 🔍 **Automated data quality monitoring and alerting**

---

## Requirements

* Python 3.9+
* `dbt-core >= 1.8.0`

Install via PyPI:

```bash
pip install dbt-core-interface
```

---

## Usage

### Programmatic

```python
from dbt_core_interface import DbtProject

# Load your project
project = DbtProject(project_dir="/path/to/dbt_project")

# Run a simple SQL query
res = project.execute_sql("SELECT current_date AS today")
print(res.table)

# Compile SQL (but don't run it)
compiled = project.compile_sql("SELECT * FROM {{ ref('my_model') }}")
print(compiled.compiled_code)

# Execute a ref() lookup
node = project.ref("my_model")
print(node.resource_type, node.name)

# Load a source node
source = project.source("my_source", "my_table")
print(source.description)

# Incrementally parse the project
project.parse_project(write_manifest=True)

# Re-parse a specific path
project.parse_paths("models/my_model.sql")

# Compile a node from path
node = project.get_node_by_path("models/my_model.sql")
compiled = project.compile_node(node)
print(compiled.compiled_code)

# Run a dbt command programmatically
project.run("-s +orders")
project.test()

# SQLFluff linting
lint_result = project.lint(sql="select 1 AS foo")
lint_result = project.lint(sql=Path("models/my_model.sql"))
print(lint_result)

# SQLFluff formatting
success, formatted_sql = project.format(sql="Select * FROM orders as o")
success, formatted_sql = project.format(sql=Path("models/my_model.sql"))
print(formatted_sql)

# Use the DbtProjectContainer to manage multiple projects
from dbt_core_interface import DbtProjectContainer

container = DbtProjectContainer()
container.create_project(project_dir="/path/to/dbt_project_1")
container.create_project(project_dir="/path/to/dbt_project_2")
print(container.registered_projects())
```

### Server Mode (FastAPI)

Run:

```bash
python -m dbt_core_interface.server --host 0.0.0.0 --port 8581
```

Register a project:

```bash
curl -X POST 'http://localhost:8581/register?project_dir=/your/dbt_project'
```

Compile SQL:

```bash
curl -X POST 'http://localhost:8581/compile' \
     -H 'X-dbt-Project: /your/dbt_project' \
     -d 'select * from {{ ref("orders" }}'
```

### Client Usage

Run the server and use the bundled client to interact with it:

```python
from dbt_core_interface.client import DbtInterfaceClient, ServerError

client = DbtInterfaceClient(
    project_dir="/path/to/project",
    profiles_dir="/path/to/profiles.yml",
    target="dev",
    base_url="http://localhost:8581",
    timeout=(5.0, 15.0)
)

# Health & heartbeat
print(client.health_check())  # {'status': 'ok', ...}
print(client.heartbeat())     # {'alive': True, 'uptime': ...}

# Run SQL with limit & path which allows resolving {{ this }}
result = client.run_sql("SELECT * FROM {{ this }} ORDER BY id", limit=500, path="models/my_model.sql")
print(result.table.rows)

# Compile without execution
comp = client.compile_sql("SELECT * FROM {{ ref('users') }}")
print(comp.compiled_code)

# Lint & format
lint = client.lint_sql(raw_sql="select * from {{ ref('users') }}")
print(lint.violations)
fmt = client.format_sql(raw_sql="select * from {{ ref('users') }}")
print(fmt.formatted_code)

# Arbitrary dbt command
docs = client.command("docs", "generate")
print(docs)

# On object deletion, project is unregistered automatically
del client
```

### Data Quality Monitoring

`dbt-core-interface` includes automated data quality monitoring and alerting capabilities:

```python
from dbt_core_interface import DbtProject, RowCountCheck, NullPercentageCheck
from dbt_core_interface import Severity, WebhookAlertChannel

# Load your project
project = DbtProject(project_dir="/path/to/dbt_project")

# Access the quality monitor
monitor = project.quality_monitor

# Add quality checks to your models
monitor.add_check(
    "my_model",
    RowCountCheck(
        name="row_count_validation",
        min_rows=1,
        max_rows=1000000,
        severity=Severity.ERROR,
    )
)

monitor.add_check(
    "my_model",
    NullPercentageCheck(
        name="null_id_check",
        column_name="id",
        max_null_percentage=0.0,
        severity=Severity.CRITICAL,
    )
)

# Add alert channels
monitor.add_alert_channel(
    WebhookAlertChannel(url="https://hooks.slack.com/services/YOUR/WEBHOOK/URL")
)

# Run all quality checks
results = monitor.run_checks(model_name="my_model")
for result in results:
    print(f"{result.check_name}: {result.status} - {result.message}")

# Run checks for all models
all_results = monitor.run_checks()
```

#### Available Check Types

- **RowCountCheck**: Validate row counts are within min/max bounds
- **NullPercentageCheck**: Ensure null percentage in a column is acceptable
- **DuplicateCheck**: Detect duplicate rows based on key columns
- **ValueRangeCheck**: Verify numeric values are within expected range
- **CustomSqlCheck**: Define custom SQL-based validation logic

#### Server API Endpoints

When running the FastAPI server, use these endpoints for quality monitoring:

```bash
# Add a quality check
curl -X POST 'http://localhost:8581/api/v1/quality/checks' \
  -H 'X-dbt-Project: /your/dbt_project' \
  -d '{
    "name": "row_count_check",
    "check_type": "row_count",
    "model_name": "my_model",
    "severity": "warning",
    "config": {"min_rows": 1, "max_rows": 1000000}
  }'

# List all quality checks
curl 'http://localhost:8581/api/v1/quality/checks?project_dir=/your/dbt_project'

# Run quality checks
curl -X POST 'http://localhost:8581/api/v1/quality/run?project_dir=/your/dbt_project&model_name=my_model'

# Add an alert channel
curl -X POST 'http://localhost:8581/api/v1/quality/alerts' \
  -H 'X-dbt-Project: /your/dbt_project' \
  -d '{
    "channel_type": "webhook",
    "config": {"url": "https://hooks.slack.com/..."}
  }'
```

---

### Generic Test Library

`dbt-core-interface` includes a comprehensive library of reusable generic dbt tests that can be easily configured via YAML schema files:

```python
from dbt_core_interface import DbtProject, GenericTestLibrary

# Load your project
project = DbtProject(project_dir="/path/to/dbt_project")

# Initialize the test library
library = GenericTestLibrary(project)

# List all available tests
for test in library.list_tests():
    print(f"{test.name}: {test.description}")

# Generate schema.yml with suggested tests
columns = {"id": {}, "email": {}, "status": {}}
schema_yml = library.generate_schema_yml("users", columns)
print(schema_yml)
```

#### Available Generic Tests

- **unique**: Ensures a column has unique values (no duplicates)
- **not_null**: Ensures a column has no null values
- **relationships**: Ensures referential integrity between tables
- **accepted_values**: Ensures column values are from a specified list
- **recency**: Checks data freshness within a time window
- **cardinality_equals**: Ensures distinct count matches another table

#### Example YAML Configuration

```yaml
version: 2

models:
  - name: users
    columns:
      - name: id
        tests:
          - unique
          - not_null

      - name: email
        tests:
          - unique
          - not_null

      - name: status
        tests:
          - accepted_values:
              values: ['active', 'inactive', 'pending']
```

#### Auto-Suggest Tests

The library can automatically suggest appropriate tests based on column naming patterns:

```python
# Get suggestions for specific columns
for col_name in ["id", "user_id", "email", "status"]:
    suggestions = library.suggest_tests_for_column(col_name)
    for suggestion in suggestions:
        print(f"{col_name}: {suggestion.test_type.value}")
```

For detailed documentation, see `src/dbt_core_interface/generic_tests/docs.md`.

---

## License

This project is licensed under the MIT License. See the [LICENSE](https://github.com/z3z1ma/dbt-core-interface/blob/main/LICENSE) file for more info.

---

## Acknowledgments

Thanks to the dbt-core maintainers and contributors whose work makes this project possible.
