Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enable using custom documentation index.html file per dbt project #15

Merged
merged 12 commits into from
Sep 6, 2024
35 changes: 20 additions & 15 deletions opendbt/client.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import dbt
from dbt.adapters.base.plugin import AdapterPlugin
from dbt.cli.main import dbtRunner as DbtCliRunner
from dbt.cli.main import dbtRunnerResult
from dbt.contracts.results import RunResult
Expand All @@ -11,21 +9,25 @@
# ================================================================================================================
# Monkey Patching! Override dbt lib AdapterContainer.register_adapter method with new one above
# ================================================================================================================
from opendbt import dbtcommon
from opendbt import dbtcommon as opendbt_dbtcommon
from dbt.adapters.factory import AdapterContainer

# STEP-1 add new methods
dbt.adapters.factory.AdapterContainer.get_custom_adapter_config_value = dbtcommon.get_custom_adapter_config_value
dbt.adapters.factory.AdapterContainer.get_custom_adapter_class_by_name = dbtcommon.get_custom_adapter_class_by_name
# # STEP-2 override existing method
if Version(DBT_VERSION.to_version_string(skip_matcher=True)) > Version("1.8.0"):
from opendbt import dbt18

dbt.adapters.factory.AdapterContainer.register_adapter = dbt18.register_adapter
from opendbt import dbt18 as opendbt
from dbt.task.docs.generate import GenerateTask
else:
from opendbt import dbt17

dbt.adapters.factory.AdapterContainer.register_adapter = dbt17.register_adapter

from opendbt import dbt17 as opendbt
from dbt.task.generate import GenerateTask

# ================= add new methods =======================================================
AdapterContainer.get_custom_adapter_config_value = opendbt_dbtcommon.get_custom_adapter_config_value
AdapterContainer.get_custom_adapter_class_by_name = opendbt_dbtcommon.get_custom_adapter_class_by_name
# ================= override existing methods ==============================================
# dbt docs overrides
GenerateTask.dbt_run = GenerateTask.run
GenerateTask.run = opendbt_dbtcommon.GenerateTask_run
# Adapter inheritance override
AdapterContainer.register_adapter = opendbt.register_adapter

class OpenDbtCli:

Expand Down Expand Up @@ -54,4 +56,7 @@ def run(args: list) -> dbtRunnerResult:

if _exception is None:
DbtRuntimeError(f"DBT execution failed!")
raise _exception
if _exception:
raise _exception
else:
return result
16 changes: 16 additions & 0 deletions opendbt/dbtcommon.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import importlib

DBT_CUSTOM_ADAPTER_VAR = 'dbt_custom_adapter'
import shutil
from pathlib import Path
import click


def get_custom_adapter_config_value(self, config: 'AdapterRequiredConfig') -> str:
Expand Down Expand Up @@ -30,3 +33,16 @@ def get_custom_adapter_class_by_name(self, custom_adapter_class_name: str):
return user_adapter_class
except ModuleNotFoundError as mnfe:
raise Exception(f"Module of provided adapter not found, provided: {custom_adapter_class_name}") from mnfe


def GenerateTask_run(self):
# Call the original dbt run method
self.dbt_run()
target = Path(self.config.project_target_path).joinpath("index.html")
for dir in self.config.docs_paths:
index_html = Path(self.config.project_root).joinpath(dir).joinpath("index.html")
if index_html.is_file() and index_html.exists():
# override default dbt provided index.html with user index.html file
shutil.copyfile(index_html, target)
click.echo(f"Using user provided documentation page: {index_html.as_posix()}")
break
206 changes: 206 additions & 0 deletions opendbt/docs/index.html

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions tests/resources/dbttest/dbt_project.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ seed-paths: [ "seeds" ]
# include "opendbt/macros/" macros!
macro-paths: [ "macros", "../../../opendbt/macros/" ]
snapshot-paths: [ "snapshots" ]
# include "opendbt/docs/" project folder!
docs-paths: [ "../../../opendbt/docs/" ]

clean-targets: # directories to be removed by `dbt clean`
- "target"
Expand Down
19 changes: 19 additions & 0 deletions tests/test_dbt_docs.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import unittest
from pathlib import Path
from unittest import TestCase

from opendbt import OpenDbtProject


class TestDbtDocs(TestCase):
RESOURCES_DIR = Path(__file__).parent.joinpath("resources")
DBTTEST_DIR = RESOURCES_DIR.joinpath("dbttest")

def test_run_docs_generate(self):
dp = OpenDbtProject(project_dir=self.DBTTEST_DIR, profiles_dir=self.DBTTEST_DIR)
dp.run(command="docs", args=['generate'])

@unittest.skip("reason for skipping")
def test_run_docs_serve(self):
dp = OpenDbtProject(project_dir=self.DBTTEST_DIR, profiles_dir=self.DBTTEST_DIR)
dp.run(command="docs", args=['serve'])
4 changes: 0 additions & 4 deletions tests/test_opendbt_project.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,3 @@ def test_run_compile(self):
def test_run_run(self):
dp = OpenDbtProject(project_dir=self.DBTTEST_DIR, profiles_dir=self.DBTTEST_DIR)
dp.run(command="run", args=['--select', 'my_first_dbt_model+'], use_subprocess=True)

def test_run_docs_generate(self):
dp = OpenDbtProject(project_dir=self.DBTTEST_DIR, profiles_dir=self.DBTTEST_DIR)
dp.run(command="docs", args=["generate"])
Loading