Skip to content

Commit

Permalink
feat: 💄 Validate DBT Postgres Validator
Browse files Browse the repository at this point in the history
  • Loading branch information
afranzi committed Jan 2, 2024
0 parents commit 5181197
Show file tree
Hide file tree
Showing 36 changed files with 3,008 additions and 0 deletions.
5 changes: 5 additions & 0 deletions .flake8
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
[flake8]
extend-ignore = E203, E266, E501, B008, C901, W503
max-line-length = 120
max-complexity = 12
select = B,C,E,F,W,T4,B9
34 changes: 34 additions & 0 deletions .github/workflows/ci-deploy.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
name: Deploy to Pypi

on:
push:
branches:
- main

jobs:
deploy:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v3

- name: Setup Python
uses: actions/setup-python@v4
with:
python-version: "3.10"

- name: Install Poetry & Tox
run: pip install poetry tox

- name: Install Dependencies
run: poetry install

- name: Run Tox
run: tox -e py310

- name: Poetry Publish
run: |
poetry build -f sdist
poetry publish
env:
POETRY_PYPI_TOKEN_PYPI: ${{ secrets.PYPI_TOKEN }}
28 changes: 28 additions & 0 deletions .github/workflows/ci-test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
name: CI PyTests

on:
push:
branches:
- main
pull_request:

jobs:
tests:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v3

- name: Setup Python
uses: actions/setup-python@v4
with:
python-version: "3.10"

- name: Install Poetry & Tox
run: pip install poetry tox

- name: Install Dependencies
run: poetry install

- name: Run Tox
run: tox -e py310
127 changes: 127 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
profiles.yml
target/
dbt_packages/
logs/

# Other
.DS_Store
.idea
.vscode

# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class

# C extensions
*.so

# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
pip-wheel-metadata/
share/python-wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST

# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec

# Installer logs
pip-log.txt
pip-delete-this-directory.txt

# Unit test / coverage reports
htmlcov/
.tox/
.nox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
*.py,cover
.hypothesis/
.pytest_cache/

# Translations
*.mo
*.pot

# PyBuilder
target/

# Jupyter Notebook
.ipynb_checkpoints

# IPython
profile_default/
ipython_config.py

# pyenv
.python-version

# pipenv
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
# However, in case of collaboration, if having platform-specific dependencies or dependencies
# having no cross-platform support, pipenv may install dependencies that don't work, or not
# install all needed dependencies.
#Pipfile.lock

# PEP 582; used by e.g. github.com/David-OConnor/pyflow
__pypackages__/

# Celery stuff
celerybeat-schedule
celerybeat.pid

# SageMath parsed files
*.sage.py

# Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/


# mkdocs documentation
/site

# mypy
.mypy_cache/
.dmypy.json
dmypy.json

# Pyre type checker
.pyre/

# Elementary
edr_target/

# DBT
.user.yml

# local scripts
scripts/db*
scripts/create_seed.sh
47 changes: 47 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
repos:
- repo: https://github.com/psf/black
rev: 23.1.0
hooks:
- id: black
- repo: https://github.com/pycqa/flake8
rev: 6.0.0
hooks:
- id: flake8
- repo: https://github.com/pycqa/isort
rev: 5.12.0
hooks:
- id: isort
args: [ --filter-files ]
- repo: https://github.com/pre-commit/mirrors-mypy
rev: v1.1.1
hooks:
- id: mypy
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.4.0
hooks:
- id: check-added-large-files
args: [ --maxkb=800 ]
- id: check-merge-conflict
- id: trailing-whitespace
- id: end-of-file-fixer
- id: check-docstring-first
- id: check-yaml
- id: debug-statements
- id: detect-aws-credentials
args: [ --allow-missing-credentials ]
- id: detect-private-key
- id: mixed-line-ending
- repo: https://github.com/asottile/add-trailing-comma
rev: v2.4.0
hooks:
- id: add-trailing-comma
- repo: https://github.com/sqlfluff/sqlfluff
rev: 2.1.3
hooks:
- id: sqlfluff-lint
stages: [manual]
additional_dependencies : ['sqlfluff-templater-dbt', 'dbt-postgres']
- id: sqlfluff-fix
stages: [manual]
additional_dependencies: [ 'sqlfluff-templater-dbt', 'dbt-postgres']
verbose: true
55 changes: 55 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
# PyTest DBT Postgres

This project aims to provide an easy way to validate a DBT project by enabling the
unit-testing capability.

## Dependencies

This project is based on the [pytest-postgresql](https://pypi.org/project/pytest-postgresql/) library, so we can
validate our DBT postgres project without relying on an existing database.

## Usage

The initial idea resides on pytest-postgres providing us an empty and isolated postgres where we can
validate different use-cases with our DBT code.

> If your project uses external sources, you will need to make sure they are properly defined in the yml files, since
> the project generates the DDLs from there.
```python
import unittest

from pytest_dbt_postgres import auto_inject_fixtures
from pytest_dbt_postgres.dbt_executor import DbtExecutor
from pytest_dbt_postgres.dbt_validator import DbtValidator
from pytest_dbt_postgres.postgres.connector import PostgresConnector
from pytest_dbt_postgres.postgres.sql_methods import export_credentials_to_env, get_credentials

dbt_project_dir = '...'
resources_folder = '...'


@auto_inject_fixtures("postgresql")
class TestDbtValidator(unittest.TestCase):
def setUp(self) -> None:
credentials = get_credentials(self.postgresql)
self.connector = PostgresConnector(credentials)

# SETUP
export_credentials_to_env(credentials)
executor = DbtExecutor(dbt_project_dir=dbt_project_dir, profiles_dir=resources_folder)
self.validator = DbtValidator(connector=self.connector, executor=executor, resources_folder=resources_folder)

def test_orders(self) -> None:
# GIVEN
sources_to_load = [
("external.customers", "csv/input/customers.csv"),
("external.orders", "csv/input/orders.csv"),
]
selector = "orders"
outputs_to_validate = [
("dbt_unittest.orders", "csv/output/orders.csv"),
]
# THEN
self.validator.validate(sources_to_load, selector, outputs_to_validate)
```
19 changes: 19 additions & 0 deletions mypy.ini
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
[mypy]
disallow_untyped_defs = True
disallow_incomplete_defs = True
warn_redundant_casts = True
warn_unused_ignores = False
allow_redefinition = True
disable_error_code = attr-defined,call-arg,union-attr,misc

[mypy-absl.*]
ignore_missing_imports = True

[mypy-psycopg2.*]
ignore_missing_imports = True

[mypy-pandas.*]
ignore_missing_imports = True

[mypy-numpy.*]
ignore_missing_imports = True
Loading

0 comments on commit 5181197

Please sign in to comment.