From bed433d31c6cf2330574e3ae7a2630f362e13ce8 Mon Sep 17 00:00:00 2001 From: Dat Nguyen Date: Fri, 8 Sep 2023 17:11:30 +0700 Subject: [PATCH] Feature/49 add dbt selection (#50) * chore: minor docs correction * feat: add dbt selection + some code refactors * test: get 100% code cov * docs: update cli references * fix: lint --- .gitignore | 1 + SECURITY.md | 1 + dbterd/adapters/{factory.py => adapter.py} | 0 dbterd/adapters/algos/base.py | 2 +- dbterd/adapters/algos/test_relationship.py | 12 +- dbterd/adapters/base.py | 108 +++- dbterd/adapters/dbt_invocation.py | 76 +++ dbterd/adapters/{algos => }/filter.py | 55 +- dbterd/adapters/{algos => }/meta.py | 9 + dbterd/adapters/worker.py | 11 - dbterd/cli/main.py | 8 +- dbterd/cli/params.py | 29 +- docs/nav/guide/cli-references.md | 98 ++- poetry.lock | 606 +++++++++++++++++- pyproject.toml | 1 + .../adapters/algos/test_test_relationship.py | 2 +- .../targets/d2/test_d2_test_relationship.py | 2 +- .../dbml/test_dbml_test_relationship.py | 2 +- .../test_graphviz_test_relationship.py | 2 +- .../mermaid/test_mermaid_test_relationship.py | 2 +- .../test_plantuml_test_relationship.py | 2 +- .../{test_factory.py => test_adapter.py} | 6 +- tests/unit/adapters/test_base.py | 95 ++- tests/unit/adapters/test_dbt_invocation.py | 65 ++ tests/unit/adapters/test_filter.py | 51 ++ tests/unit/cli/test_runner.py | 34 + 26 files changed, 1210 insertions(+), 70 deletions(-) rename dbterd/adapters/{factory.py => adapter.py} (100%) create mode 100644 dbterd/adapters/dbt_invocation.py rename dbterd/adapters/{algos => }/filter.py (68%) rename dbterd/adapters/{algos => }/meta.py (79%) delete mode 100644 dbterd/adapters/worker.py rename tests/unit/adapters/{test_factory.py => test_adapter.py} (57%) create mode 100644 tests/unit/adapters/test_dbt_invocation.py create mode 100644 tests/unit/adapters/test_filter.py diff --git a/.gitignore b/.gitignore index c1051c7..8ec7dbe 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,7 @@ /target /samples/local CHANGELOG.md +/dbt_packages # Byte-compiled / optimized / DLL files __pycache__/ diff --git a/SECURITY.md b/SECURITY.md index 6d7dc40..cd9b4aa 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -7,6 +7,7 @@ currently being supported with security updates. | Version | Supported | | ------- | ------------------ | +| 1.3+ | :white_check_mark: | | 1.2.x | :white_check_mark: | | 1.1.x | :white_check_mark: | | 1.0.x | :white_check_mark: | diff --git a/dbterd/adapters/factory.py b/dbterd/adapters/adapter.py similarity index 100% rename from dbterd/adapters/factory.py rename to dbterd/adapters/adapter.py diff --git a/dbterd/adapters/algos/base.py b/dbterd/adapters/algos/base.py index 6060bec..b8d3a2f 100644 --- a/dbterd/adapters/algos/base.py +++ b/dbterd/adapters/algos/base.py @@ -1,6 +1,6 @@ import copy -from dbterd.adapters.algos.meta import Column, Table +from dbterd.adapters.meta import Column, Table def get_tables(manifest, catalog): diff --git a/dbterd/adapters/algos/test_relationship.py b/dbterd/adapters/algos/test_relationship.py index f7ca267..92fb913 100644 --- a/dbterd/adapters/algos/test_relationship.py +++ b/dbterd/adapters/algos/test_relationship.py @@ -1,11 +1,12 @@ from dbterd.adapters.algos import base -from dbterd.adapters.algos.filter import is_selected_table -from dbterd.adapters.algos.meta import Ref +from dbterd.adapters.filter import is_selected_table +from dbterd.adapters.meta import Ref from dbterd.constants import ( DEFAULT_ALGO_RULE, TEST_META_IGNORE_IN_ERD, TEST_META_RELATIONSHIP_TYPE, ) +from dbterd.helpers.log import logger def parse(manifest, catalog, **kwargs): @@ -27,9 +28,9 @@ def parse(manifest, catalog, **kwargs): for table in tables if is_selected_table( table=table, - select_rules=(kwargs.get("select") or []), + select_rules=kwargs.get("select") or [], resource_types=kwargs.get("resource_type", []), - exclude_rules=kwargs.get("exclude", []), + exclude_rules=kwargs.get("exclude") or [], ) ] @@ -47,6 +48,9 @@ def parse(manifest, catalog, **kwargs): tables=tables, relationships=relationships ) + logger.info( + f"Collected {len(tables)} table(s) and {len(relationships)} relationship(s)" + ) return (tables, relationships) diff --git a/dbterd/adapters/base.py b/dbterd/adapters/base.py index 69db2b7..7b12171 100644 --- a/dbterd/adapters/base.py +++ b/dbterd/adapters/base.py @@ -1,15 +1,19 @@ -import abc +import os +from pathlib import Path import click -from dbterd.adapters import factory +from dbterd import default +from dbterd.adapters import adapter +from dbterd.adapters.dbt_invocation import DbtInvocation +from dbterd.adapters.filter import has_unsupported_rule from dbterd.helpers import cli_messaging from dbterd.helpers import file as file_handlers from dbterd.helpers.log import logger -class Executor(abc.ABC): - """Base executor""" +class Executor: + """Main Executor""" ctx: click.Context @@ -19,11 +23,82 @@ def __init__(self, ctx) -> None: self.filename_manifest = "manifest.json" self.filename_catalog = "catalog.json" - @abc.abstractmethod def run(self, **kwargs): """Main function helps to run by the target strategy""" + kwargs = self.evaluate_kwargs(**kwargs) self.__run_by_strategy(**kwargs) + def evaluate_kwargs(self, **kwargs) -> dict: + """Re-calculate the options + + Raises: + click.UsageError: Not Supported exception + + Returns: + dict: kwargs dict + """ + artifacts_dir, dbt_project_dir = self.__get_dir(**kwargs) + logger.info(f"Using dbt artifact dir at: {artifacts_dir}") + logger.info(f"Using dbt project dir at: {dbt_project_dir}") + + select = list(kwargs.get("select")) or [] + exclude = list(kwargs.get("exclude")) or [] + if kwargs.get("dbt"): + select = self.__get_selection(**kwargs) + exclude = [] + else: + unsupported, rule = has_unsupported_rule( + rules=select.extend(exclude) if exclude else select + ) + if unsupported: + message = f"Unsupported Selection found: {rule}" + logger.error(message) + raise click.UsageError(message) + + kwargs["artifacts_dir"] = artifacts_dir + kwargs["dbt_project_dir"] = dbt_project_dir + kwargs["select"] = select + kwargs["exclude"] = exclude + + return kwargs + + def __get_dir(self, **kwargs) -> str: + """Calculate the dbt artifact directory and dbt project directory + + Returns: + tuple(str, str): Path to target directory and dbt project directory + """ + artifact_dir = ( + f"{kwargs.get('artifacts_dir') or kwargs.get('dbt_project_dir')}" # default + ) + project_dir = ( + f"{kwargs.get('dbt_project_dir') or kwargs.get('artifacts_dir')}" # default + ) + + if not artifact_dir: + return ( + default.default_artifact_path(), + str(Path(default.default_artifact_path()).parent.absolute()), + ) + + artifact_dir = Path(artifact_dir).absolute() + project_dir = Path(project_dir).absolute() + + if not os.path.isfile(f"{artifact_dir}/{self.filename_manifest}"): + artifact_dir = f"{project_dir}/target" # try child target + + return (str(artifact_dir), str(project_dir)) + + def __get_selection(self, **kwargs): + """Override the Selection using dbt's one with `--dbt`""" + return DbtInvocation( + dbt_project_dir=kwargs.get("dbt_project_dir"), + dbt_target=kwargs.get("dbt_target"), + ).get_selection( + select_rules=kwargs.get("select"), + exclude_rules=kwargs.get("exclude"), + ) + def __read_manifest(self, mp: str, mv: int = None): """Read the Manifest content @@ -55,24 +130,29 @@ def __read_catalog(self, cp: str, cv: int = None): def __run_by_strategy(self, **kwargs): """Read artifacts and export the diagram file following the target""" - target = factory.load_executor(name=kwargs["target"]) # import {target} + target = adapter.load_executor(name=kwargs["target"]) # import {target} run_operation_dispatcher = getattr(target, "run_operation_dispatcher") operation_default = getattr(target, "run_operation_default") operation = run_operation_dispatcher.get( f"{kwargs['target']}_{kwargs['algo'].split(':')[0]}", operation_default, ) + manifest = self.__read_manifest( - mp=kwargs.get("manifest_path") or kwargs["artifacts_dir"], - mv=kwargs["manifest_version"], + mp=kwargs.get("artifacts_dir"), + mv=kwargs.get("manifest_version"), ) catalog = self.__read_catalog( - cp=kwargs.get("manifest_path") or kwargs["artifacts_dir"], - cv=kwargs["catalog_version"], + cp=kwargs.get("artifacts_dir"), + cv=kwargs.get("catalog_version"), ) result = operation(manifest=manifest, catalog=catalog, **kwargs) - path = kwargs["output"] + f"/{result[0]}" - with open(path, "w") as f: - logger.info(path) - f.write(result[1]) + path = kwargs.get("output") + f"/{result[0]}" + try: + with open(path, "w") as f: + logger.info(path) + f.write(result[1]) + except Exception as e: + logger.error(str(e)) + raise click.FileError(f"Could not save the output: {str(e)}") diff --git a/dbterd/adapters/dbt_invocation.py b/dbterd/adapters/dbt_invocation.py new file mode 100644 index 0000000..fb90dd1 --- /dev/null +++ b/dbterd/adapters/dbt_invocation.py @@ -0,0 +1,76 @@ +import os +import importlib.util +from importlib.metadata import version +from pathlib import Path +from typing import List + +import click +from dbt.cli.main import dbtRunner, dbtRunnerResult + +from dbterd.helpers.log import logger + + +class DbtInvocation: + """Runner of dbt (https://docs.getdbt.com/reference/programmatic-invocations)""" + + def __init__(self, dbt_project_dir: str = None, dbt_target: str = None) -> None: + """Initialization + + Args: + dbt_project_dir (str, optional): Custom dbt project directory path. Defaults to None. + dbt_target (str, optional): Custom dbt target name. Defaults to None - using default target + """ + self.__ensure_dbt_installed() + self.dbt = dbtRunner() + self.project_dir = ( + dbt_project_dir or os.environ.get("DBT_PROJECT_DIR") or str(Path.cwd()) + ) + self.target = dbt_target + + def __ensure_dbt_installed(self): + dbt_spec = importlib.util.find_spec("dbt") + if dbt_spec and dbt_spec.loader: + installed_path = dbt_spec.submodule_search_locations[0] + logger.debug( + f"Found dbt v{version('dbt-core')} installed at {installed_path}" + ) + else: + message = ( + "dbt module is not found or unsupported version, " + "please try to install dbt-core v1.5 or later, " + "OR let's try again without `--dbt` flag" + ) + logger.error(message) + raise click.UsageError(message) + + def get_selection( + self, select_rules: List[str] = [], exclude_rules: List[str] = [] + ) -> List[str]: + """Get dbt selected models + + Args: + select_rules (List[str], optional): Model inclusives. Defaults to []. + exclude_rules (List[str], optional): Model exclusives. Defaults to []. + + Returns: + List[str]: Selected node names with 'exact' rule + """ + args = ["ls", "--project-dir", self.project_dir, "--resource-type", "model"] + if select_rules: + args.extend(["--select", " ".join(select_rules)]) + if exclude_rules: + args.extend(["--exclude", " ".join(exclude_rules)]) + if self.target: + args.extend(["--target", self.target]) + + logger.info(f"Invoking: `dbt {' '.join(args)}` at {self.project_dir}") + r: dbtRunnerResult = self.dbt.invoke(args) + + if not r.success: + logger.error(str(r)) + raise click.UsageError("str(r)") + + return [ + f"exact:model.{str(x).split('.')[0]}.{str(x).split('.')[-1]}" + for x in r.result + ] diff --git a/dbterd/adapters/algos/filter.py b/dbterd/adapters/filter.py similarity index 68% rename from dbterd/adapters/algos/filter.py rename to dbterd/adapters/filter.py index dc7bad3..a0e4403 100644 --- a/dbterd/adapters/algos/filter.py +++ b/dbterd/adapters/filter.py @@ -2,7 +2,29 @@ from fnmatch import fnmatch from typing import List -from dbterd.adapters.algos.meta import Table +from dbterd.adapters.meta import Table + +RULE_FUNC_PREFIX = "is_satisfied_by_" + + +def has_unsupported_rule(rules: List[str] = []) -> bool: + """Verify if existing the unsupported selection rule + + Args: + rules (List[str]): Any (selection or/and exclusion) rules + + Returns: + bool: True if existing any unsupported one + """ + for rule in rules: + type = rule.split(":") + if len(type) == 1: + continue + rule_func = f"{RULE_FUNC_PREFIX}{type[0]}" + if not hasattr(sys.modules[__name__], rule_func): + return (True, type[0]) + + return (False, None) def is_selected_table( @@ -28,6 +50,7 @@ def is_selected_table( selected = any([evaluate_rule(table=table, rule=rule) for rule in select_rules]) if resource_types: selected = selected and table.resource_type in resource_types + # Exclusion excluded = False if exclude_rules: @@ -55,12 +78,15 @@ def evaluate_rule(table: Table, rule: str): type, rule = "name", rule_parts[0] if len(rule_parts) > 1: type, rule = tuple(rule_parts[:2]) - selected_func = getattr(sys.modules[__name__], f"__is_satisfied_by_{type}") + + rule_func = f"{RULE_FUNC_PREFIX}{type}" + selected_func = getattr(sys.modules[__name__], rule_func) results.append(selected_func(table=table, rule=rule)) + return all(results) -def __is_satisfied_by_name(table: Table, rule: str = ""): +def is_satisfied_by_name(table: Table, rule: str = ""): """Evaluate rule by Name Args: @@ -75,7 +101,22 @@ def __is_satisfied_by_name(table: Table, rule: str = ""): return table.name.startswith(rule) -def __is_satisfied_by_schema(table: Table, rule: str = ""): +def is_satisfied_by_exact(table: Table, rule: str = ""): + """Evaluate rule by model name with exact match + + Args: + table (Table): Table object + rule (str, optional): Rule def. Defaults to "". + + Returns: + bool: True if satisfied `equal` logic applied to Table name + """ + if not rule: + return True + return table.name == rule + + +def is_satisfied_by_schema(table: Table, rule: str = ""): """Evaluate rule by Schema name Args: @@ -96,7 +137,7 @@ def __is_satisfied_by_schema(table: Table, rule: str = ""): ) -def __is_satisfied_by_wildcard(table: Table, rule: str = "*"): +def is_satisfied_by_wildcard(table: Table, rule: str = "*"): """Evaluate rule by Wildcard (Unix Style) Args: @@ -111,7 +152,7 @@ def __is_satisfied_by_wildcard(table: Table, rule: str = "*"): return fnmatch(table.name, rule) -def __is_satisfied_by_exposure(table: Table, rule: str = ""): +def is_satisfied_by_exposure(table: Table, rule: str = ""): """Evaluate rule by dbt Exposure name Args: @@ -119,7 +160,7 @@ def __is_satisfied_by_exposure(table: Table, rule: str = ""): rule (str, optional): Rule def. Defaults to "". Returns: - bool: True if satisfied table name matched the pattern + bool: True if satisfied exposure name exists in the table's exposures """ if not rule: return True diff --git a/dbterd/adapters/algos/meta.py b/dbterd/adapters/meta.py similarity index 79% rename from dbterd/adapters/algos/meta.py rename to dbterd/adapters/meta.py index e4a20fa..36f52c0 100644 --- a/dbterd/adapters/algos/meta.py +++ b/dbterd/adapters/meta.py @@ -1,4 +1,5 @@ from dataclasses import dataclass, field +from enum import Enum from typing import List, Optional, Tuple @@ -32,3 +33,11 @@ class Ref: table_map: Tuple[str, str] column_map: Tuple[str, str] type: str = "n1" + + +class SelectionType(Enum): + START_WITH_NAME = "" + EXACT_NAME = "exact" + SCHEMA = "schema" + WILDCARD = "wildcard" + EXPOSURE = "exposure" diff --git a/dbterd/adapters/worker.py b/dbterd/adapters/worker.py deleted file mode 100644 index 91589a3..0000000 --- a/dbterd/adapters/worker.py +++ /dev/null @@ -1,11 +0,0 @@ -from dbterd.adapters.base import Executor - - -class DbtWorker(Executor): - """dbt executor""" - - def __init__(self, ctx) -> None: - super().__init__(ctx) - - def run(self, **kwargs): - super().run(**kwargs) diff --git a/dbterd/cli/main.py b/dbterd/cli/main.py index 9285148..6cd5fd9 100644 --- a/dbterd/cli/main.py +++ b/dbterd/cli/main.py @@ -3,7 +3,7 @@ import click -from dbterd.adapters.worker import DbtWorker +from dbterd.adapters.base import Executor from dbterd.cli import params from dbterd.helpers import jsonify from dbterd.helpers.log import logger @@ -62,8 +62,8 @@ def debug(ctx, **kwargs): """Inspect the hidden magics""" logger.info("**Arguments used**") logger.debug(jsonify.to_json(kwargs)) - logger.info("**Context used**") - logger.debug(jsonify.to_json(ctx.obj)) + logger.info("**Arguments evaluated**") + logger.debug(jsonify.to_json(Executor(ctx).evaluate_kwargs(**kwargs))) # dbterd run @@ -72,4 +72,4 @@ def debug(ctx, **kwargs): @params.common_params def run(ctx, **kwargs): """Run the convert""" - DbtWorker(ctx).run(**kwargs) + Executor(ctx).run(**kwargs) diff --git a/dbterd/cli/params.py b/dbterd/cli/params.py index 7e8040f..45f8cfc 100644 --- a/dbterd/cli/params.py +++ b/dbterd/cli/params.py @@ -9,15 +9,14 @@ def common_params(func): @click.option( "--artifacts-dir", "-ad", - help="Specified the full path to dbt artifacts path which known as /target directory", - default=default.default_artifact_path(), - show_default=True, + help="Specified the path to dbt artifact directory which known as /target directory", + default="", type=click.STRING, ) @click.option( "--output", "-o", - help="Output the result file. Default to the same target dir", + help="Output the result file. Default to the cwd/target", default=default.default_output_path(), show_default=True, type=click.STRING, @@ -76,6 +75,28 @@ def common_params(func): multiple=True, type=click.STRING, ) + @click.option( + "--dbt", + help="Flag to indicate the Selecton to follow dbt's one leveraging Programmatic Invocation", + is_flag=True, + default=False, + show_default=True, + ) + @click.option( + "--dbt-project-dir", + "-dpd", + help="Specified dbt project directory path", + default="", + show_default=True, + type=click.STRING, + ) + @click.option( + "--dbt-target", + "-dt", + help="Specified dbt target name", + default=None, + type=click.STRING, + ) @functools.wraps(func) def wrapper(*args, **kwargs): return func(*args, **kwargs) # pragma: no cover diff --git a/docs/nav/guide/cli-references.md b/docs/nav/guide/cli-references.md index c1ce0d5..b4f1746 100644 --- a/docs/nav/guide/cli-references.md +++ b/docs/nav/guide/cli-references.md @@ -61,7 +61,10 @@ Command to generate diagram-as-a-code file ### --artifacts-dir (-ad) Configure the path to directory containing dbt artifact files. -> Default to `./target` + +It will take the the nested `/target` directory of `--dbt-project-dir` if not specified. + +> Default to the current directory's `/target` if both this option and `--dbt-project-dir` option are not specified **Examples:** === "CLI" @@ -274,6 +277,59 @@ Specified dbt resource type(seed, model, source, snapshot). dbterd run --resource-type model ``` +### --dbt + +Flag to indicate the Selecton to follow dbt's one leveraging Programmatic Invocation +> Default to `False` + +**Examples:** +=== "CLI (use dbt selection)" + + ```bash + dbterd run -s +something --dbt + # select 'something' and the upstream + ``` +=== "CLI (use dbterd selection)" + + ```bash + dbterd run -s something + # select starts with 'something' + ``` + +### --dbt-project-dir (-dpd) + +Specified dbt project directory path + +You should specified this option if your CWD is not the dbt project dir, and normally used with `--dbt` enabled. It will take the value of `--artifacts-dir` if not specified. + +> Default to the current directory if both this option and `--artifacts-dir` option are not specified + +**Examples:** +=== "CLI" + + ```bash + dbterd run -s +something --dbt-project-dir /path/to/dbt/project --dbt + # select 'something' and the upstream of the dbt project located at /path/to/dbt/project + # the artifacts dir will probably be assumed as: /path/to/dbt/project/target + ``` + +### --dbt-target (-dt) + +Specified dbt target name + +Probably used with `--dbt` enabled. + +> Default to the dbt's profile configuration + +**Examples:** +=== "CLI" + + ```bash + dbterd run -s +something --dbt-project-dir /path/to/dbt/project --dbt --dbt-target prod + # select 'something' and the upstream of the dbt project located at /path/to/dbt/project using target name 'prod' + # the artifacts dir will probably be assumed as: /path/to/dbt/project/target + ``` + ## debug Shows hidden configured values @@ -282,21 +338,41 @@ Shows hidden configured values === "Output" ``` - 2023-04-08 10:15:03,611 - dbterd - INFO - Run with dbterd==0.2.0 (main.py:43) - 2023-04-08 10:15:03,612 - dbterd - INFO - **Arguments used** (main.py:52) - 2023-04-08 10:15:03,613 - dbterd - DEBUG - { + 2023-09-08 16:43:45,066 - dbterd - INFO - Run with dbterd==1.0.0 (main.py:54) + 2023-09-08 16:43:45,071 - dbterd - INFO - **Arguments used** (main.py:63) + 2023-09-08 16:43:45,073 - dbterd - DEBUG - { + "artifacts_dir": "", + "output": "C:\\Users\\DAT\\Documents\\Sources\\dbterd\\target", + "select": [], + "exclude": [], + "target": "dbml", + "algo": "test_relationship", + "manifest_version": null, + "catalog_version": null, + "resource_type": [ + "model" + ], + "dbt": false, + "dbt_project_dir": "", + "dbt_target": null + } (main.py:64) + 2023-09-08 16:43:45,079 - dbterd - INFO - **Arguments evaluated** (main.py:65) + 2023-09-08 16:43:45,081 - dbterd - INFO - Using dbt artifact dir at: C:\Users\DAT\Documents\Sources\dbterd\target (base.py:41) + 2023-09-08 16:43:45,082 - dbterd - INFO - Using dbt project dir at: C:\Users\DAT\Documents\Sources\dbterd (base.py:42) + 2023-09-08 16:43:45,084 - dbterd - DEBUG - { "artifacts_dir": "C:\\Users\\DAT\\Documents\\Sources\\dbterd\\target", - "manifest_path": null, "output": "C:\\Users\\DAT\\Documents\\Sources\\dbterd\\target", - "select": null, - "exclude": null, + "select": [], + "exclude": [], "target": "dbml", "algo": "test_relationship", "manifest_version": null, + "catalog_version": null, "resource_type": [ "model" - ] - } (main.py:53) - 2023-04-08 10:15:03,614 - dbterd - INFO - **Context used** (main.py:54) - 2023-04-08 10:15:03,614 - dbterd - DEBUG - {} (main.py:55) + ], + "dbt": false, + "dbt_project_dir": "C:\\Users\\DAT\\Documents\\Sources\\dbterd", + "dbt_target": null + } (main.py:66) ``` diff --git a/poetry.lock b/poetry.lock index 7356ab7..89c9326 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,5 +1,29 @@ # This file is automatically @generated by Poetry 1.4.0 and should not be changed by hand. +[[package]] +name = "agate" +version = "1.7.0" +description = "A data analysis library that is optimized for humans instead of machines." +category = "dev" +optional = false +python-versions = "*" +files = [ + {file = "agate-1.7.0-py2.py3-none-any.whl", hash = "sha256:ad529c80fe6943906ab3d3bc59c12307e1181d35993e6055db59fa72dc79a6bd"}, + {file = "agate-1.7.0.tar.gz", hash = "sha256:a835a1069247b39b0c340e31eb56e1a95e79f679ad37512192118a5ea3336020"}, +] + +[package.dependencies] +Babel = ">=2.0" +isodate = ">=0.5.4" +leather = ">=0.3.2" +parsedatetime = ">=2.1,<2.5 || >2.5,<2.6 || >2.6" +python-slugify = ">=1.2.1" +pytimeparse = ">=1.1.5" + +[package.extras] +docs = ["Sphinx (>=1.2.2)", "sphinx-rtd-theme (>=0.1.6)"] +test = ["PyICU (>=2.4.2)", "coverage (>=3.7.1)", "cssselect (>=0.9.1)", "lxml (>=3.6.0)", "pytest", "pytest-cov", "pytz (>=2015.4)"] + [[package]] name = "argcomplete" version = "3.1.1" @@ -121,6 +145,83 @@ files = [ {file = "certifi-2023.7.22.tar.gz", hash = "sha256:539cc1d13202e33ca466e88b2807e29f4c13049d6d87031a3c110744495cb082"}, ] +[[package]] +name = "cffi" +version = "1.15.1" +description = "Foreign Function Interface for Python calling C code." +category = "dev" +optional = false +python-versions = "*" +files = [ + {file = "cffi-1.15.1-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:a66d3508133af6e8548451b25058d5812812ec3798c886bf38ed24a98216fab2"}, + {file = "cffi-1.15.1-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:470c103ae716238bbe698d67ad020e1db9d9dba34fa5a899b5e21577e6d52ed2"}, + {file = "cffi-1.15.1-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:9ad5db27f9cabae298d151c85cf2bad1d359a1b9c686a275df03385758e2f914"}, + {file = "cffi-1.15.1-cp27-cp27m-win32.whl", hash = "sha256:b3bbeb01c2b273cca1e1e0c5df57f12dce9a4dd331b4fa1635b8bec26350bde3"}, + {file = "cffi-1.15.1-cp27-cp27m-win_amd64.whl", hash = "sha256:e00b098126fd45523dd056d2efba6c5a63b71ffe9f2bbe1a4fe1716e1d0c331e"}, + {file = "cffi-1.15.1-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:d61f4695e6c866a23a21acab0509af1cdfd2c013cf256bbf5b6b5e2695827162"}, + {file = "cffi-1.15.1-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:ed9cb427ba5504c1dc15ede7d516b84757c3e3d7868ccc85121d9310d27eed0b"}, + {file = "cffi-1.15.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:39d39875251ca8f612b6f33e6b1195af86d1b3e60086068be9cc053aa4376e21"}, + {file = "cffi-1.15.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:285d29981935eb726a4399badae8f0ffdff4f5050eaa6d0cfc3f64b857b77185"}, + {file = "cffi-1.15.1-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3eb6971dcff08619f8d91607cfc726518b6fa2a9eba42856be181c6d0d9515fd"}, + {file = "cffi-1.15.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:21157295583fe8943475029ed5abdcf71eb3911894724e360acff1d61c1d54bc"}, + {file = "cffi-1.15.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5635bd9cb9731e6d4a1132a498dd34f764034a8ce60cef4f5319c0541159392f"}, + {file = "cffi-1.15.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2012c72d854c2d03e45d06ae57f40d78e5770d252f195b93f581acf3ba44496e"}, + {file = "cffi-1.15.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd86c085fae2efd48ac91dd7ccffcfc0571387fe1193d33b6394db7ef31fe2a4"}, + {file = "cffi-1.15.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:fa6693661a4c91757f4412306191b6dc88c1703f780c8234035eac011922bc01"}, + {file = "cffi-1.15.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:59c0b02d0a6c384d453fece7566d1c7e6b7bae4fc5874ef2ef46d56776d61c9e"}, + {file = "cffi-1.15.1-cp310-cp310-win32.whl", hash = "sha256:cba9d6b9a7d64d4bd46167096fc9d2f835e25d7e4c121fb2ddfc6528fb0413b2"}, + {file = "cffi-1.15.1-cp310-cp310-win_amd64.whl", hash = "sha256:ce4bcc037df4fc5e3d184794f27bdaab018943698f4ca31630bc7f84a7b69c6d"}, + {file = "cffi-1.15.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3d08afd128ddaa624a48cf2b859afef385b720bb4b43df214f85616922e6a5ac"}, + {file = "cffi-1.15.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:3799aecf2e17cf585d977b780ce79ff0dc9b78d799fc694221ce814c2c19db83"}, + {file = "cffi-1.15.1-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a591fe9e525846e4d154205572a029f653ada1a78b93697f3b5a8f1f2bc055b9"}, + {file = "cffi-1.15.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3548db281cd7d2561c9ad9984681c95f7b0e38881201e157833a2342c30d5e8c"}, + {file = "cffi-1.15.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:91fc98adde3d7881af9b59ed0294046f3806221863722ba7d8d120c575314325"}, + {file = "cffi-1.15.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:94411f22c3985acaec6f83c6df553f2dbe17b698cc7f8ae751ff2237d96b9e3c"}, + {file = "cffi-1.15.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:03425bdae262c76aad70202debd780501fabeaca237cdfddc008987c0e0f59ef"}, + {file = "cffi-1.15.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:cc4d65aeeaa04136a12677d3dd0b1c0c94dc43abac5860ab33cceb42b801c1e8"}, + {file = "cffi-1.15.1-cp311-cp311-win32.whl", hash = "sha256:a0f100c8912c114ff53e1202d0078b425bee3649ae34d7b070e9697f93c5d52d"}, + {file = "cffi-1.15.1-cp311-cp311-win_amd64.whl", hash = "sha256:04ed324bda3cda42b9b695d51bb7d54b680b9719cfab04227cdd1e04e5de3104"}, + {file = "cffi-1.15.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:50a74364d85fd319352182ef59c5c790484a336f6db772c1a9231f1c3ed0cbd7"}, + {file = "cffi-1.15.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e263d77ee3dd201c3a142934a086a4450861778baaeeb45db4591ef65550b0a6"}, + {file = "cffi-1.15.1-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:cec7d9412a9102bdc577382c3929b337320c4c4c4849f2c5cdd14d7368c5562d"}, + {file = "cffi-1.15.1-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4289fc34b2f5316fbb762d75362931e351941fa95fa18789191b33fc4cf9504a"}, + {file = "cffi-1.15.1-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:173379135477dc8cac4bc58f45db08ab45d228b3363adb7af79436135d028405"}, + {file = "cffi-1.15.1-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:6975a3fac6bc83c4a65c9f9fcab9e47019a11d3d2cf7f3c0d03431bf145a941e"}, + {file = "cffi-1.15.1-cp36-cp36m-win32.whl", hash = "sha256:2470043b93ff09bf8fb1d46d1cb756ce6132c54826661a32d4e4d132e1977adf"}, + {file = "cffi-1.15.1-cp36-cp36m-win_amd64.whl", hash = "sha256:30d78fbc8ebf9c92c9b7823ee18eb92f2e6ef79b45ac84db507f52fbe3ec4497"}, + {file = "cffi-1.15.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:198caafb44239b60e252492445da556afafc7d1e3ab7a1fb3f0584ef6d742375"}, + {file = "cffi-1.15.1-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5ef34d190326c3b1f822a5b7a45f6c4535e2f47ed06fec77d3d799c450b2651e"}, + {file = "cffi-1.15.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8102eaf27e1e448db915d08afa8b41d6c7ca7a04b7d73af6514df10a3e74bd82"}, + {file = "cffi-1.15.1-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5df2768244d19ab7f60546d0c7c63ce1581f7af8b5de3eb3004b9b6fc8a9f84b"}, + {file = "cffi-1.15.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a8c4917bd7ad33e8eb21e9a5bbba979b49d9a97acb3a803092cbc1133e20343c"}, + {file = "cffi-1.15.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0e2642fe3142e4cc4af0799748233ad6da94c62a8bec3a6648bf8ee68b1c7426"}, + {file = "cffi-1.15.1-cp37-cp37m-win32.whl", hash = "sha256:e229a521186c75c8ad9490854fd8bbdd9a0c9aa3a524326b55be83b54d4e0ad9"}, + {file = "cffi-1.15.1-cp37-cp37m-win_amd64.whl", hash = "sha256:a0b71b1b8fbf2b96e41c4d990244165e2c9be83d54962a9a1d118fd8657d2045"}, + {file = "cffi-1.15.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:320dab6e7cb2eacdf0e658569d2575c4dad258c0fcc794f46215e1e39f90f2c3"}, + {file = "cffi-1.15.1-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1e74c6b51a9ed6589199c787bf5f9875612ca4a8a0785fb2d4a84429badaf22a"}, + {file = "cffi-1.15.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a5c84c68147988265e60416b57fc83425a78058853509c1b0629c180094904a5"}, + {file = "cffi-1.15.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3b926aa83d1edb5aa5b427b4053dc420ec295a08e40911296b9eb1b6170f6cca"}, + {file = "cffi-1.15.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:87c450779d0914f2861b8526e035c5e6da0a3199d8f1add1a665e1cbc6fc6d02"}, + {file = "cffi-1.15.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4f2c9f67e9821cad2e5f480bc8d83b8742896f1242dba247911072d4fa94c192"}, + {file = "cffi-1.15.1-cp38-cp38-win32.whl", hash = "sha256:8b7ee99e510d7b66cdb6c593f21c043c248537a32e0bedf02e01e9553a172314"}, + {file = "cffi-1.15.1-cp38-cp38-win_amd64.whl", hash = "sha256:00a9ed42e88df81ffae7a8ab6d9356b371399b91dbdf0c3cb1e84c03a13aceb5"}, + {file = "cffi-1.15.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:54a2db7b78338edd780e7ef7f9f6c442500fb0d41a5a4ea24fff1c929d5af585"}, + {file = "cffi-1.15.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:fcd131dd944808b5bdb38e6f5b53013c5aa4f334c5cad0c72742f6eba4b73db0"}, + {file = "cffi-1.15.1-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7473e861101c9e72452f9bf8acb984947aa1661a7704553a9f6e4baa5ba64415"}, + {file = "cffi-1.15.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6c9a799e985904922a4d207a94eae35c78ebae90e128f0c4e521ce339396be9d"}, + {file = "cffi-1.15.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3bcde07039e586f91b45c88f8583ea7cf7a0770df3a1649627bf598332cb6984"}, + {file = "cffi-1.15.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:33ab79603146aace82c2427da5ca6e58f2b3f2fb5da893ceac0c42218a40be35"}, + {file = "cffi-1.15.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5d598b938678ebf3c67377cdd45e09d431369c3b1a5b331058c338e201f12b27"}, + {file = "cffi-1.15.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:db0fbb9c62743ce59a9ff687eb5f4afbe77e5e8403d6697f7446e5f609976f76"}, + {file = "cffi-1.15.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:98d85c6a2bef81588d9227dde12db8a7f47f639f4a17c9ae08e773aa9c697bf3"}, + {file = "cffi-1.15.1-cp39-cp39-win32.whl", hash = "sha256:40f4774f5a9d4f5e344f31a32b5096977b5d48560c5592e2f3d2c4374bd543ee"}, + {file = "cffi-1.15.1-cp39-cp39-win_amd64.whl", hash = "sha256:70df4e3b545a17496c9b3f41f5115e69a4f2e77e94e1d2a8e1070bc0c38c8a3c"}, + {file = "cffi-1.15.1.tar.gz", hash = "sha256:d400bfb9a37b1351253cb402671cea7e89bdecc294e8016a707f6d1d8ac934f9"}, +] + +[package.dependencies] +pycparser = "*" + [[package]] name = "cfgv" version = "3.4.0" @@ -387,6 +488,84 @@ pydantic = ">=1.6,<2.0" dev = ["build (==0.7.0)", "flit (==3.7.1)", "pdoc3 (>=0.9.2)", "pre-commit (>=2.15.0)", "pyyaml (>=5.3)", "yapf (>=0.29.0)"] test = ["black (==21.9b0)", "flake8 (>=3.8.3,<4.0.0)", "isort (>=5.0.6,<6.0.0)", "mypy (==0.910)", "pylint (>=2.12.0)", "pytest (>=6.2.4,<7.0.0)", "yapf (>=0.29.0)"] +[[package]] +name = "dbt-core" +version = "1.5.6" +description = "With dbt, data analysts and engineers can build analytics the way engineers build applications." +category = "dev" +optional = false +python-versions = ">=3.7.2" +files = [ + {file = "dbt-core-1.5.6.tar.gz", hash = "sha256:af3c03cd4a1fc92481362888014ca1ffed2ffef0b0e0d98463ad0f26c49ef458"}, + {file = "dbt_core-1.5.6-py3-none-any.whl", hash = "sha256:030d2179f9efbf8ccea079296d0c79278d963bb2475c0bcce9ca4bbb0d8c393c"}, +] + +[package.dependencies] +agate = ">=1.6,<1.7.1" +cffi = ">=1.9,<2.0.0" +click = "<9" +colorama = ">=0.3.9,<0.4.7" +dbt-extractor = ">=0.4.1,<0.5.0" +hologram = ">=0.0.14,<=0.0.16" +idna = ">=2.5,<4" +isodate = ">=0.6,<0.7" +Jinja2 = "3.1.2" +logbook = ">=1.5,<1.6" +mashumaro = {version = "3.6", extras = ["msgpack"]} +minimal-snowplow-tracker = "0.0.2" +networkx = {version = ">=2.3,<3", markers = "python_version >= \"3.8\""} +packaging = ">20.9" +pathspec = ">=0.9,<0.12" +protobuf = ">=4.0.0" +pytz = ">=2015.7" +pyyaml = ">=6.0" +requests = "<3.0.0" +sqlparse = ">=0.2.3,<0.5" +typing-extensions = ">=3.7.4" +werkzeug = ">=1,<3" + +[[package]] +name = "dbt-extractor" +version = "0.4.1" +description = "A tool to analyze and extract information from Jinja used in dbt projects." +category = "dev" +optional = false +python-versions = ">=3.6.1" +files = [ + {file = "dbt_extractor-0.4.1-cp36-abi3-macosx_10_7_x86_64.whl", hash = "sha256:4dc715bd740e418d8dc1dd418fea508e79208a24cf5ab110b0092a3cbe96bf71"}, + {file = "dbt_extractor-0.4.1-cp36-abi3-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl", hash = "sha256:bc9e0050e3a2f4ea9fe58e8794bc808e6709a0c688ed710fc7c5b6ef3e5623ec"}, + {file = "dbt_extractor-0.4.1-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:76872cdee659075d6ce2df92dc62e59a74ba571be62acab2e297ca478b49d766"}, + {file = "dbt_extractor-0.4.1-cp36-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:81435841610be1b07806d72cd89b1956c6e2a84c360b9ceb3f949c62a546d569"}, + {file = "dbt_extractor-0.4.1-cp36-abi3-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:7c291f9f483eae4f60dd5859097d7ba51d5cb6c4725f08973ebd18cdea89d758"}, + {file = "dbt_extractor-0.4.1-cp36-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:822b1e911db230e1b9701c99896578e711232001027b518c44c32f79a46fa3f9"}, + {file = "dbt_extractor-0.4.1-cp36-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:554d27741a54599c39e5c0b7dbcab77400d83f908caba284a3e960db812e5814"}, + {file = "dbt_extractor-0.4.1-cp36-abi3-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a805d51a25317f53cbff951c79b9cf75421cf48e4b3e1dfb3e9e8de6d824b76c"}, + {file = "dbt_extractor-0.4.1-cp36-abi3-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:cad90ddc708cb4182dc16fe2c87b1f088a1679877b93e641af068eb68a25d582"}, + {file = "dbt_extractor-0.4.1-cp36-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:34783d788b133f223844e280e37b3f5244f2fb60acc457aa75c2667e418d5442"}, + {file = "dbt_extractor-0.4.1-cp36-abi3-musllinux_1_2_armv7l.whl", hash = "sha256:9da211869a1220ea55c5552c1567a3ea5233a6c52fa89ca87a22465481c37bc9"}, + {file = "dbt_extractor-0.4.1-cp36-abi3-musllinux_1_2_i686.whl", hash = "sha256:7d7c47774dc051b8c18690281a55e2e3d3320e823b17e04b06bc3ff81b1874ba"}, + {file = "dbt_extractor-0.4.1-cp36-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:037907a7c7ae0391045d81338ca77ddaef899a91d80f09958f09fe374594e19b"}, + {file = "dbt_extractor-0.4.1-cp36-abi3-win32.whl", hash = "sha256:3fe8d8e28a7bd3e0884896147269ca0202ca432d8733113386bdc84c824561bf"}, + {file = "dbt_extractor-0.4.1-cp36-abi3-win_amd64.whl", hash = "sha256:35265a0ae0a250623b0c2e3308b2738dc8212e40e0aa88407849e9ea090bb312"}, + {file = "dbt_extractor-0.4.1.tar.gz", hash = "sha256:75b1c665699ec0f1ffce1ba3d776f7dfce802156f22e70a7b9c8f0b4d7e80f42"}, +] + +[[package]] +name = "dbt-postgres" +version = "1.5.6" +description = "The postgres adapter plugin for dbt (data build tool)" +category = "dev" +optional = false +python-versions = ">=3.7" +files = [ + {file = "dbt-postgres-1.5.6.tar.gz", hash = "sha256:b74e471dc661819a3d4bda2d11497935661ac2e25786c8a5b7314d8241b18582"}, + {file = "dbt_postgres-1.5.6-py3-none-any.whl", hash = "sha256:bc5711c9ab0ec4b57ab814b2c4e4c973554c8374b7da94b06814ac81c91f67ef"}, +] + +[package.dependencies] +dbt-core = "1.5.6" +psycopg2-binary = ">=2.8,<3.0" + [[package]] name = "distlib" version = "0.3.7" @@ -471,6 +650,17 @@ mccabe = ">=0.7.0,<0.8.0" pycodestyle = ">=2.11.0,<2.12.0" pyflakes = ">=3.1.0,<3.2.0" +[[package]] +name = "future" +version = "0.18.3" +description = "Clean single-source support for Python 3 and 2" +category = "dev" +optional = false +python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" +files = [ + {file = "future-0.18.3.tar.gz", hash = "sha256:34a17436ed1e96697a86f9de3d15a3b0be01d8bc8de9c1dffd59fb8234ed5307"}, +] + [[package]] name = "genson" version = "1.2.2" @@ -500,6 +690,22 @@ python-dateutil = ">=2.8.1" [package.extras] dev = ["flake8", "markdown", "twine", "wheel"] +[[package]] +name = "hologram" +version = "0.0.16" +description = "JSON schema generation from dataclasses" +category = "dev" +optional = false +python-versions = "*" +files = [ + {file = "hologram-0.0.16-py3-none-any.whl", hash = "sha256:4e56bd525336bb64a18916f871977a4125b64be8aaa750233583003333cda361"}, + {file = "hologram-0.0.16.tar.gz", hash = "sha256:1c2c921b4e575361623ea0e0d0aa5aee377b1a333cc6c6a879e213ed34583e55"}, +] + +[package.dependencies] +jsonschema = ">=3.0" +python-dateutil = ">=2.8,<2.9" + [[package]] name = "htmlmin2" version = "0.1.13" @@ -586,6 +792,21 @@ files = [ {file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"}, ] +[[package]] +name = "isodate" +version = "0.6.1" +description = "An ISO 8601 date/time/duration parser and formatter" +category = "dev" +optional = false +python-versions = "*" +files = [ + {file = "isodate-0.6.1-py2.py3-none-any.whl", hash = "sha256:0751eece944162659049d35f4f549ed815792b38793f07cf73381c1c87cbed96"}, + {file = "isodate-0.6.1.tar.gz", hash = "sha256:48c5881de7e8b0a0d648cb024c8062dc84e7b840ed81e864c7614fd3c127bde9"}, +] + +[package.dependencies] +six = "*" + [[package]] name = "isort" version = "5.12.0" @@ -717,6 +938,51 @@ files = [ {file = "lazy_object_proxy-1.9.0-cp39-cp39-win_amd64.whl", hash = "sha256:db1c1722726f47e10e0b5fdbf15ac3b8adb58c091d12b3ab713965795036985f"}, ] +[[package]] +name = "leather" +version = "0.3.4" +description = "Python charting for 80% of humans." +category = "dev" +optional = false +python-versions = "*" +files = [ + {file = "leather-0.3.4-py2.py3-none-any.whl", hash = "sha256:5e741daee96e9f1e9e06081b8c8a10c4ac199301a0564cdd99b09df15b4603d2"}, + {file = "leather-0.3.4.tar.gz", hash = "sha256:b43e21c8fa46b2679de8449f4d953c06418666dc058ce41055ee8a8d3bb40918"}, +] + +[package.dependencies] +six = ">=1.6.1" + +[[package]] +name = "logbook" +version = "1.5.3" +description = "A logging replacement for Python" +category = "dev" +optional = false +python-versions = "*" +files = [ + {file = "Logbook-1.5.3-cp27-cp27m-win32.whl", hash = "sha256:56ee54c11df3377314cedcd6507638f015b4b88c0238c2e01b5eb44fd3a6ad1b"}, + {file = "Logbook-1.5.3-cp27-cp27m-win_amd64.whl", hash = "sha256:2dc85f1510533fddb481e97677bb7bca913560862734c0b3b289bfed04f78c92"}, + {file = "Logbook-1.5.3-cp35-cp35m-win32.whl", hash = "sha256:94e2e11ff3c2304b0d09a36c6208e5ae756eb948b210e5cbd63cd8d27f911542"}, + {file = "Logbook-1.5.3-cp35-cp35m-win_amd64.whl", hash = "sha256:97fee1bd9605f76335b169430ed65e15e457a844b2121bd1d90a08cf7e30aba0"}, + {file = "Logbook-1.5.3-cp36-cp36m-win32.whl", hash = "sha256:7c533eb728b3d220b1b5414ba4635292d149d79f74f6973b4aa744c850ca944a"}, + {file = "Logbook-1.5.3-cp36-cp36m-win_amd64.whl", hash = "sha256:e18f7422214b1cf0240c56f884fd9c9b4ff9d0da2eabca9abccba56df7222f66"}, + {file = "Logbook-1.5.3-cp37-cp37m-win32.whl", hash = "sha256:8f76a2e7b1f72595f753228732f81ce342caf03babc3fed6bbdcf366f2f20f18"}, + {file = "Logbook-1.5.3-cp37-cp37m-win_amd64.whl", hash = "sha256:0cf2cdbfb65a03b5987d19109dacad13417809dcf697f66e1a7084fb21744ea9"}, + {file = "Logbook-1.5.3.tar.gz", hash = "sha256:66f454ada0f56eae43066f604a222b09893f98c1adc18df169710761b8f32fe8"}, +] + +[package.extras] +all = ["Jinja2", "brotli", "cython", "execnet (>=1.0.9)", "mock", "pytest", "pytest-cov (<2.6)", "pyzmq", "redis", "sqlalchemy"] +compression = ["brotli"] +dev = ["cython", "mock", "pytest", "pytest-cov (<2.6)"] +execnet = ["execnet (>=1.0.9)"] +jinja = ["Jinja2"] +redis = ["redis"] +sqlalchemy = ["sqlalchemy"] +test = ["mock", "pytest", "pytest-cov (<2.6)"] +zmq = ["pyzmq"] + [[package]] name = "markdown" version = "3.4.4" @@ -796,6 +1062,28 @@ files = [ {file = "MarkupSafe-2.1.3.tar.gz", hash = "sha256:af598ed32d6ae86f1b747b82783958b1a4ab8f617b06fe68795c7f026abbdcad"}, ] +[[package]] +name = "mashumaro" +version = "3.6" +description = "Fast serialization library on top of dataclasses" +category = "dev" +optional = false +python-versions = ">=3.7" +files = [ + {file = "mashumaro-3.6-py3-none-any.whl", hash = "sha256:77403e3e2ecd0a7d0e22d472c08e33282460e48726eabe356c5163efbdf9c7ee"}, + {file = "mashumaro-3.6.tar.gz", hash = "sha256:ceb3de53029219bbbb0385ca600b59348dcd14e0c68523986c6d51889ad338f5"}, +] + +[package.dependencies] +msgpack = {version = ">=0.5.6", optional = true, markers = "extra == \"msgpack\""} +typing-extensions = ">=4.1.0" + +[package.extras] +msgpack = ["msgpack (>=0.5.6)"] +orjson = ["orjson"] +toml = ["tomli (>=1.1.0)", "tomli-w (>=1.0)"] +yaml = ["pyyaml (>=3.13)"] + [[package]] name = "mccabe" version = "0.7.0" @@ -842,6 +1130,21 @@ verspec = "*" dev = ["coverage", "flake8 (>=3.0)", "shtab"] test = ["coverage", "flake8 (>=3.0)", "shtab"] +[[package]] +name = "minimal-snowplow-tracker" +version = "0.0.2" +description = "A minimal snowplow event tracker for Python. Add analytics to your Python and Django apps, webapps and games" +category = "dev" +optional = false +python-versions = "*" +files = [ + {file = "minimal-snowplow-tracker-0.0.2.tar.gz", hash = "sha256:acabf7572db0e7f5cbf6983d495eef54081f71be392330eb3aadb9ccb39daaa4"}, +] + +[package.dependencies] +requests = ">=2.2.1,<3.0" +six = ">=1.9.0,<2.0" + [[package]] name = "mkdocs" version = "1.5.2" @@ -929,6 +1232,79 @@ htmlmin2 = ">=0.1.13" jsmin = ">=3.0.1" mkdocs = ">=1.4.1" +[[package]] +name = "msgpack" +version = "1.0.5" +description = "MessagePack serializer" +category = "dev" +optional = false +python-versions = "*" +files = [ + {file = "msgpack-1.0.5-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:525228efd79bb831cf6830a732e2e80bc1b05436b086d4264814b4b2955b2fa9"}, + {file = "msgpack-1.0.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:4f8d8b3bf1ff2672567d6b5c725a1b347fe838b912772aa8ae2bf70338d5a198"}, + {file = "msgpack-1.0.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:cdc793c50be3f01106245a61b739328f7dccc2c648b501e237f0699fe1395b81"}, + {file = "msgpack-1.0.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5cb47c21a8a65b165ce29f2bec852790cbc04936f502966768e4aae9fa763cb7"}, + {file = "msgpack-1.0.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e42b9594cc3bf4d838d67d6ed62b9e59e201862a25e9a157019e171fbe672dd3"}, + {file = "msgpack-1.0.5-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:55b56a24893105dc52c1253649b60f475f36b3aa0fc66115bffafb624d7cb30b"}, + {file = "msgpack-1.0.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:1967f6129fc50a43bfe0951c35acbb729be89a55d849fab7686004da85103f1c"}, + {file = "msgpack-1.0.5-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:20a97bf595a232c3ee6d57ddaadd5453d174a52594bf9c21d10407e2a2d9b3bd"}, + {file = "msgpack-1.0.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:d25dd59bbbbb996eacf7be6b4ad082ed7eacc4e8f3d2df1ba43822da9bfa122a"}, + {file = "msgpack-1.0.5-cp310-cp310-win32.whl", hash = "sha256:382b2c77589331f2cb80b67cc058c00f225e19827dbc818d700f61513ab47bea"}, + {file = "msgpack-1.0.5-cp310-cp310-win_amd64.whl", hash = "sha256:4867aa2df9e2a5fa5f76d7d5565d25ec76e84c106b55509e78c1ede0f152659a"}, + {file = "msgpack-1.0.5-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:9f5ae84c5c8a857ec44dc180a8b0cc08238e021f57abdf51a8182e915e6299f0"}, + {file = "msgpack-1.0.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:9e6ca5d5699bcd89ae605c150aee83b5321f2115695e741b99618f4856c50898"}, + {file = "msgpack-1.0.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:5494ea30d517a3576749cad32fa27f7585c65f5f38309c88c6d137877fa28a5a"}, + {file = "msgpack-1.0.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1ab2f3331cb1b54165976a9d976cb251a83183631c88076613c6c780f0d6e45a"}, + {file = "msgpack-1.0.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:28592e20bbb1620848256ebc105fc420436af59515793ed27d5c77a217477705"}, + {file = "msgpack-1.0.5-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fe5c63197c55bce6385d9aee16c4d0641684628f63ace85f73571e65ad1c1e8d"}, + {file = "msgpack-1.0.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:ed40e926fa2f297e8a653c954b732f125ef97bdd4c889f243182299de27e2aa9"}, + {file = "msgpack-1.0.5-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:b2de4c1c0538dcb7010902a2b97f4e00fc4ddf2c8cda9749af0e594d3b7fa3d7"}, + {file = "msgpack-1.0.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:bf22a83f973b50f9d38e55c6aade04c41ddda19b00c4ebc558930d78eecc64ed"}, + {file = "msgpack-1.0.5-cp311-cp311-win32.whl", hash = "sha256:c396e2cc213d12ce017b686e0f53497f94f8ba2b24799c25d913d46c08ec422c"}, + {file = "msgpack-1.0.5-cp311-cp311-win_amd64.whl", hash = "sha256:6c4c68d87497f66f96d50142a2b73b97972130d93677ce930718f68828b382e2"}, + {file = "msgpack-1.0.5-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:a2b031c2e9b9af485d5e3c4520f4220d74f4d222a5b8dc8c1a3ab9448ca79c57"}, + {file = "msgpack-1.0.5-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4f837b93669ce4336e24d08286c38761132bc7ab29782727f8557e1eb21b2080"}, + {file = "msgpack-1.0.5-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b1d46dfe3832660f53b13b925d4e0fa1432b00f5f7210eb3ad3bb9a13c6204a6"}, + {file = "msgpack-1.0.5-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:366c9a7b9057e1547f4ad51d8facad8b406bab69c7d72c0eb6f529cf76d4b85f"}, + {file = "msgpack-1.0.5-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:4c075728a1095efd0634a7dccb06204919a2f67d1893b6aa8e00497258bf926c"}, + {file = "msgpack-1.0.5-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:f933bbda5a3ee63b8834179096923b094b76f0c7a73c1cfe8f07ad608c58844b"}, + {file = "msgpack-1.0.5-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:36961b0568c36027c76e2ae3ca1132e35123dcec0706c4b7992683cc26c1320c"}, + {file = "msgpack-1.0.5-cp36-cp36m-win32.whl", hash = "sha256:b5ef2f015b95f912c2fcab19c36814963b5463f1fb9049846994b007962743e9"}, + {file = "msgpack-1.0.5-cp36-cp36m-win_amd64.whl", hash = "sha256:288e32b47e67f7b171f86b030e527e302c91bd3f40fd9033483f2cacc37f327a"}, + {file = "msgpack-1.0.5-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:137850656634abddfb88236008339fdaba3178f4751b28f270d2ebe77a563b6c"}, + {file = "msgpack-1.0.5-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0c05a4a96585525916b109bb85f8cb6511db1c6f5b9d9cbcbc940dc6b4be944b"}, + {file = "msgpack-1.0.5-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:56a62ec00b636583e5cb6ad313bbed36bb7ead5fa3a3e38938503142c72cba4f"}, + {file = "msgpack-1.0.5-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ef8108f8dedf204bb7b42994abf93882da1159728a2d4c5e82012edd92c9da9f"}, + {file = "msgpack-1.0.5-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:1835c84d65f46900920b3708f5ba829fb19b1096c1800ad60bae8418652a951d"}, + {file = "msgpack-1.0.5-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:e57916ef1bd0fee4f21c4600e9d1da352d8816b52a599c46460e93a6e9f17086"}, + {file = "msgpack-1.0.5-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:17358523b85973e5f242ad74aa4712b7ee560715562554aa2134d96e7aa4cbbf"}, + {file = "msgpack-1.0.5-cp37-cp37m-win32.whl", hash = "sha256:cb5aaa8c17760909ec6cb15e744c3ebc2ca8918e727216e79607b7bbce9c8f77"}, + {file = "msgpack-1.0.5-cp37-cp37m-win_amd64.whl", hash = "sha256:ab31e908d8424d55601ad7075e471b7d0140d4d3dd3272daf39c5c19d936bd82"}, + {file = "msgpack-1.0.5-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:b72d0698f86e8d9ddf9442bdedec15b71df3598199ba33322d9711a19f08145c"}, + {file = "msgpack-1.0.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:379026812e49258016dd84ad79ac8446922234d498058ae1d415f04b522d5b2d"}, + {file = "msgpack-1.0.5-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:332360ff25469c346a1c5e47cbe2a725517919892eda5cfaffe6046656f0b7bb"}, + {file = "msgpack-1.0.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:476a8fe8fae289fdf273d6d2a6cb6e35b5a58541693e8f9f019bfe990a51e4ba"}, + {file = "msgpack-1.0.5-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a9985b214f33311df47e274eb788a5893a761d025e2b92c723ba4c63936b69b1"}, + {file = "msgpack-1.0.5-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:48296af57cdb1d885843afd73c4656be5c76c0c6328db3440c9601a98f303d87"}, + {file = "msgpack-1.0.5-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:addab7e2e1fcc04bd08e4eb631c2a90960c340e40dfc4a5e24d2ff0d5a3b3edb"}, + {file = "msgpack-1.0.5-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:916723458c25dfb77ff07f4c66aed34e47503b2eb3188b3adbec8d8aa6e00f48"}, + {file = "msgpack-1.0.5-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:821c7e677cc6acf0fd3f7ac664c98803827ae6de594a9f99563e48c5a2f27eb0"}, + {file = "msgpack-1.0.5-cp38-cp38-win32.whl", hash = "sha256:1c0f7c47f0087ffda62961d425e4407961a7ffd2aa004c81b9c07d9269512f6e"}, + {file = "msgpack-1.0.5-cp38-cp38-win_amd64.whl", hash = "sha256:bae7de2026cbfe3782c8b78b0db9cbfc5455e079f1937cb0ab8d133496ac55e1"}, + {file = "msgpack-1.0.5-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:20c784e66b613c7f16f632e7b5e8a1651aa5702463d61394671ba07b2fc9e025"}, + {file = "msgpack-1.0.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:266fa4202c0eb94d26822d9bfd7af25d1e2c088927fe8de9033d929dd5ba24c5"}, + {file = "msgpack-1.0.5-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:18334484eafc2b1aa47a6d42427da7fa8f2ab3d60b674120bce7a895a0a85bdd"}, + {file = "msgpack-1.0.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:57e1f3528bd95cc44684beda696f74d3aaa8a5e58c816214b9046512240ef437"}, + {file = "msgpack-1.0.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:586d0d636f9a628ddc6a17bfd45aa5b5efaf1606d2b60fa5d87b8986326e933f"}, + {file = "msgpack-1.0.5-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a740fa0e4087a734455f0fc3abf5e746004c9da72fbd541e9b113013c8dc3282"}, + {file = "msgpack-1.0.5-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:3055b0455e45810820db1f29d900bf39466df96ddca11dfa6d074fa47054376d"}, + {file = "msgpack-1.0.5-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:a61215eac016f391129a013c9e46f3ab308db5f5ec9f25811e811f96962599a8"}, + {file = "msgpack-1.0.5-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:362d9655cd369b08fda06b6657a303eb7172d5279997abe094512e919cf74b11"}, + {file = "msgpack-1.0.5-cp39-cp39-win32.whl", hash = "sha256:ac9dd47af78cae935901a9a500104e2dea2e253207c924cc95de149606dc43cc"}, + {file = "msgpack-1.0.5-cp39-cp39-win_amd64.whl", hash = "sha256:06f5174b5f8ed0ed919da0e62cbd4ffde676a374aba4020034da05fab67b9164"}, + {file = "msgpack-1.0.5.tar.gz", hash = "sha256:c075544284eadc5cddc70f4757331d99dcbc16b2bbd4849d15f8aae4cf36d31c"}, +] + [[package]] name = "mypy-extensions" version = "1.0.0" @@ -941,6 +1317,25 @@ files = [ {file = "mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782"}, ] +[[package]] +name = "networkx" +version = "2.8.8" +description = "Python package for creating and manipulating graphs and networks" +category = "dev" +optional = false +python-versions = ">=3.8" +files = [ + {file = "networkx-2.8.8-py3-none-any.whl", hash = "sha256:e435dfa75b1d7195c7b8378c3859f0445cd88c6b0375c181ed66823a9ceb7524"}, + {file = "networkx-2.8.8.tar.gz", hash = "sha256:230d388117af870fce5647a3c52401fcf753e94720e6ea6b4197a5355648885e"}, +] + +[package.extras] +default = ["matplotlib (>=3.4)", "numpy (>=1.19)", "pandas (>=1.3)", "scipy (>=1.8)"] +developer = ["mypy (>=0.982)", "pre-commit (>=2.20)"] +doc = ["nb2plots (>=0.6)", "numpydoc (>=1.5)", "pillow (>=9.2)", "pydata-sphinx-theme (>=0.11)", "sphinx (>=5.2)", "sphinx-gallery (>=0.11)", "texext (>=0.6.6)"] +extra = ["lxml (>=4.6)", "pydot (>=1.4.2)", "pygraphviz (>=1.9)", "sympy (>=1.10)"] +test = ["codecov (>=2.1)", "pytest (>=7.2)", "pytest-cov (>=4.0)"] + [[package]] name = "nodeenv" version = "1.8.0" @@ -1016,6 +1411,21 @@ files = [ {file = "paginate-0.5.6.tar.gz", hash = "sha256:5e6007b6a9398177a7e1648d04fdd9f8c9766a1a945bceac82f1929e8c78af2d"}, ] +[[package]] +name = "parsedatetime" +version = "2.4" +description = "Parse human-readable date/time text." +category = "dev" +optional = false +python-versions = "*" +files = [ + {file = "parsedatetime-2.4-py2-none-any.whl", hash = "sha256:9ee3529454bf35c40a77115f5a596771e59e1aee8c53306f346c461b8e913094"}, + {file = "parsedatetime-2.4.tar.gz", hash = "sha256:3d817c58fb9570d1eec1dd46fa9448cd644eeed4fb612684b02dfda3a79cb84b"}, +] + +[package.dependencies] +future = "*" + [[package]] name = "pastel" version = "0.2.1" @@ -1149,6 +1559,99 @@ nodeenv = ">=0.11.1" pyyaml = ">=5.1" virtualenv = ">=20.10.0" +[[package]] +name = "protobuf" +version = "4.24.3" +description = "" +category = "dev" +optional = false +python-versions = ">=3.7" +files = [ + {file = "protobuf-4.24.3-cp310-abi3-win32.whl", hash = "sha256:20651f11b6adc70c0f29efbe8f4a94a74caf61b6200472a9aea6e19898f9fcf4"}, + {file = "protobuf-4.24.3-cp310-abi3-win_amd64.whl", hash = "sha256:3d42e9e4796a811478c783ef63dc85b5a104b44aaaca85d4864d5b886e4b05e3"}, + {file = "protobuf-4.24.3-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:6e514e8af0045be2b56e56ae1bb14f43ce7ffa0f68b1c793670ccbe2c4fc7d2b"}, + {file = "protobuf-4.24.3-cp37-abi3-manylinux2014_aarch64.whl", hash = "sha256:ba53c2f04798a326774f0e53b9c759eaef4f6a568ea7072ec6629851c8435959"}, + {file = "protobuf-4.24.3-cp37-abi3-manylinux2014_x86_64.whl", hash = "sha256:f6ccbcf027761a2978c1406070c3788f6de4a4b2cc20800cc03d52df716ad675"}, + {file = "protobuf-4.24.3-cp37-cp37m-win32.whl", hash = "sha256:1b182c7181a2891e8f7f3a1b5242e4ec54d1f42582485a896e4de81aa17540c2"}, + {file = "protobuf-4.24.3-cp37-cp37m-win_amd64.whl", hash = "sha256:b0271a701e6782880d65a308ba42bc43874dabd1a0a0f41f72d2dac3b57f8e76"}, + {file = "protobuf-4.24.3-cp38-cp38-win32.whl", hash = "sha256:e29d79c913f17a60cf17c626f1041e5288e9885c8579832580209de8b75f2a52"}, + {file = "protobuf-4.24.3-cp38-cp38-win_amd64.whl", hash = "sha256:067f750169bc644da2e1ef18c785e85071b7c296f14ac53e0900e605da588719"}, + {file = "protobuf-4.24.3-cp39-cp39-win32.whl", hash = "sha256:2da777d34b4f4f7613cdf85c70eb9a90b1fbef9d36ae4a0ccfe014b0b07906f1"}, + {file = "protobuf-4.24.3-cp39-cp39-win_amd64.whl", hash = "sha256:f631bb982c5478e0c1c70eab383af74a84be66945ebf5dd6b06fc90079668d0b"}, + {file = "protobuf-4.24.3-py3-none-any.whl", hash = "sha256:f6f8dc65625dadaad0c8545319c2e2f0424fede988368893ca3844261342c11a"}, + {file = "protobuf-4.24.3.tar.gz", hash = "sha256:12e9ad2ec079b833176d2921be2cb24281fa591f0b119b208b788adc48c2561d"}, +] + +[[package]] +name = "psycopg2-binary" +version = "2.9.7" +description = "psycopg2 - Python-PostgreSQL Database Adapter" +category = "dev" +optional = false +python-versions = ">=3.6" +files = [ + {file = "psycopg2-binary-2.9.7.tar.gz", hash = "sha256:1b918f64a51ffe19cd2e230b3240ba481330ce1d4b7875ae67305bd1d37b041c"}, + {file = "psycopg2_binary-2.9.7-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ea5f8ee87f1eddc818fc04649d952c526db4426d26bab16efbe5a0c52b27d6ab"}, + {file = "psycopg2_binary-2.9.7-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2993ccb2b7e80844d534e55e0f12534c2871952f78e0da33c35e648bf002bbff"}, + {file = "psycopg2_binary-2.9.7-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dbbc3c5d15ed76b0d9db7753c0db40899136ecfe97d50cbde918f630c5eb857a"}, + {file = "psycopg2_binary-2.9.7-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:692df8763b71d42eb8343f54091368f6f6c9cfc56dc391858cdb3c3ef1e3e584"}, + {file = "psycopg2_binary-2.9.7-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9dcfd5d37e027ec393a303cc0a216be564b96c80ba532f3d1e0d2b5e5e4b1e6e"}, + {file = "psycopg2_binary-2.9.7-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:17cc17a70dfb295a240db7f65b6d8153c3d81efb145d76da1e4a096e9c5c0e63"}, + {file = "psycopg2_binary-2.9.7-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:e5666632ba2b0d9757b38fc17337d84bdf932d38563c5234f5f8c54fd01349c9"}, + {file = "psycopg2_binary-2.9.7-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:7db7b9b701974c96a88997d458b38ccb110eba8f805d4b4f74944aac48639b42"}, + {file = "psycopg2_binary-2.9.7-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:c82986635a16fb1fa15cd5436035c88bc65c3d5ced1cfaac7f357ee9e9deddd4"}, + {file = "psycopg2_binary-2.9.7-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:4fe13712357d802080cfccbf8c6266a3121dc0e27e2144819029095ccf708372"}, + {file = "psycopg2_binary-2.9.7-cp310-cp310-win32.whl", hash = "sha256:122641b7fab18ef76b18860dd0c772290566b6fb30cc08e923ad73d17461dc63"}, + {file = "psycopg2_binary-2.9.7-cp310-cp310-win_amd64.whl", hash = "sha256:f8651cf1f144f9ee0fa7d1a1df61a9184ab72962531ca99f077bbdcba3947c58"}, + {file = "psycopg2_binary-2.9.7-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:4ecc15666f16f97709106d87284c136cdc82647e1c3f8392a672616aed3c7151"}, + {file = "psycopg2_binary-2.9.7-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:3fbb1184c7e9d28d67671992970718c05af5f77fc88e26fd7136613c4ece1f89"}, + {file = "psycopg2_binary-2.9.7-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8a7968fd20bd550431837656872c19575b687f3f6f98120046228e451e4064df"}, + {file = "psycopg2_binary-2.9.7-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:094af2e77a1976efd4956a031028774b827029729725e136514aae3cdf49b87b"}, + {file = "psycopg2_binary-2.9.7-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:26484e913d472ecb6b45937ea55ce29c57c662066d222fb0fbdc1fab457f18c5"}, + {file = "psycopg2_binary-2.9.7-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f309b77a7c716e6ed9891b9b42953c3ff7d533dc548c1e33fddc73d2f5e21f9"}, + {file = "psycopg2_binary-2.9.7-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:6d92e139ca388ccfe8c04aacc163756e55ba4c623c6ba13d5d1595ed97523e4b"}, + {file = "psycopg2_binary-2.9.7-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:2df562bb2e4e00ee064779902d721223cfa9f8f58e7e52318c97d139cf7f012d"}, + {file = "psycopg2_binary-2.9.7-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:4eec5d36dbcfc076caab61a2114c12094c0b7027d57e9e4387b634e8ab36fd44"}, + {file = "psycopg2_binary-2.9.7-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:1011eeb0c51e5b9ea1016f0f45fa23aca63966a4c0afcf0340ccabe85a9f65bd"}, + {file = "psycopg2_binary-2.9.7-cp311-cp311-win32.whl", hash = "sha256:ded8e15f7550db9e75c60b3d9fcbc7737fea258a0f10032cdb7edc26c2a671fd"}, + {file = "psycopg2_binary-2.9.7-cp311-cp311-win_amd64.whl", hash = "sha256:8a136c8aaf6615653450817a7abe0fc01e4ea720ae41dfb2823eccae4b9062a3"}, + {file = "psycopg2_binary-2.9.7-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:2dec5a75a3a5d42b120e88e6ed3e3b37b46459202bb8e36cd67591b6e5feebc1"}, + {file = "psycopg2_binary-2.9.7-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fc10da7e7df3380426521e8c1ed975d22df678639da2ed0ec3244c3dc2ab54c8"}, + {file = "psycopg2_binary-2.9.7-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ee919b676da28f78f91b464fb3e12238bd7474483352a59c8a16c39dfc59f0c5"}, + {file = "psycopg2_binary-2.9.7-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:eb1c0e682138f9067a58fc3c9a9bf1c83d8e08cfbee380d858e63196466d5c86"}, + {file = "psycopg2_binary-2.9.7-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:00d8db270afb76f48a499f7bb8fa70297e66da67288471ca873db88382850bf4"}, + {file = "psycopg2_binary-2.9.7-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:9b0c2b466b2f4d89ccc33784c4ebb1627989bd84a39b79092e560e937a11d4ac"}, + {file = "psycopg2_binary-2.9.7-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:51d1b42d44f4ffb93188f9b39e6d1c82aa758fdb8d9de65e1ddfe7a7d250d7ad"}, + {file = "psycopg2_binary-2.9.7-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:11abdbfc6f7f7dea4a524b5f4117369b0d757725798f1593796be6ece20266cb"}, + {file = "psycopg2_binary-2.9.7-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:f02f4a72cc3ab2565c6d9720f0343cb840fb2dc01a2e9ecb8bc58ccf95dc5c06"}, + {file = "psycopg2_binary-2.9.7-cp37-cp37m-win32.whl", hash = "sha256:81d5dd2dd9ab78d31a451e357315f201d976c131ca7d43870a0e8063b6b7a1ec"}, + {file = "psycopg2_binary-2.9.7-cp37-cp37m-win_amd64.whl", hash = "sha256:62cb6de84d7767164a87ca97e22e5e0a134856ebcb08f21b621c6125baf61f16"}, + {file = "psycopg2_binary-2.9.7-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:59f7e9109a59dfa31efa022e94a244736ae401526682de504e87bd11ce870c22"}, + {file = "psycopg2_binary-2.9.7-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:95a7a747bdc3b010bb6a980f053233e7610276d55f3ca506afff4ad7749ab58a"}, + {file = "psycopg2_binary-2.9.7-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8c721ee464e45ecf609ff8c0a555018764974114f671815a0a7152aedb9f3343"}, + {file = "psycopg2_binary-2.9.7-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f4f37bbc6588d402980ffbd1f3338c871368fb4b1cfa091debe13c68bb3852b3"}, + {file = "psycopg2_binary-2.9.7-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ac83ab05e25354dad798401babaa6daa9577462136ba215694865394840e31f8"}, + {file = "psycopg2_binary-2.9.7-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:024eaeb2a08c9a65cd5f94b31ace1ee3bb3f978cd4d079406aef85169ba01f08"}, + {file = "psycopg2_binary-2.9.7-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:1c31c2606ac500dbd26381145684d87730a2fac9a62ebcfbaa2b119f8d6c19f4"}, + {file = "psycopg2_binary-2.9.7-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:42a62ef0e5abb55bf6ffb050eb2b0fcd767261fa3faf943a4267539168807522"}, + {file = "psycopg2_binary-2.9.7-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:7952807f95c8eba6a8ccb14e00bf170bb700cafcec3924d565235dffc7dc4ae8"}, + {file = "psycopg2_binary-2.9.7-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:e02bc4f2966475a7393bd0f098e1165d470d3fa816264054359ed4f10f6914ea"}, + {file = "psycopg2_binary-2.9.7-cp38-cp38-win32.whl", hash = "sha256:fdca0511458d26cf39b827a663d7d87db6f32b93efc22442a742035728603d5f"}, + {file = "psycopg2_binary-2.9.7-cp38-cp38-win_amd64.whl", hash = "sha256:d0b16e5bb0ab78583f0ed7ab16378a0f8a89a27256bb5560402749dbe8a164d7"}, + {file = "psycopg2_binary-2.9.7-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:6822c9c63308d650db201ba22fe6648bd6786ca6d14fdaf273b17e15608d0852"}, + {file = "psycopg2_binary-2.9.7-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:8f94cb12150d57ea433e3e02aabd072205648e86f1d5a0a692d60242f7809b15"}, + {file = "psycopg2_binary-2.9.7-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a5ee89587696d808c9a00876065d725d4ae606f5f7853b961cdbc348b0f7c9a1"}, + {file = "psycopg2_binary-2.9.7-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ad5ec10b53cbb57e9a2e77b67e4e4368df56b54d6b00cc86398578f1c635f329"}, + {file = "psycopg2_binary-2.9.7-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:642df77484b2dcaf87d4237792246d8068653f9e0f5c025e2c692fc56b0dda70"}, + {file = "psycopg2_binary-2.9.7-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a6a8b575ac45af1eaccbbcdcf710ab984fd50af048fe130672377f78aaff6fc1"}, + {file = "psycopg2_binary-2.9.7-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:f955aa50d7d5220fcb6e38f69ea126eafecd812d96aeed5d5f3597f33fad43bb"}, + {file = "psycopg2_binary-2.9.7-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:ad26d4eeaa0d722b25814cce97335ecf1b707630258f14ac4d2ed3d1d8415265"}, + {file = "psycopg2_binary-2.9.7-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:ced63c054bdaf0298f62681d5dcae3afe60cbae332390bfb1acf0e23dcd25fc8"}, + {file = "psycopg2_binary-2.9.7-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:2b04da24cbde33292ad34a40db9832a80ad12de26486ffeda883413c9e1b1d5e"}, + {file = "psycopg2_binary-2.9.7-cp39-cp39-win32.whl", hash = "sha256:18f12632ab516c47c1ac4841a78fddea6508a8284c7cf0f292cb1a523f2e2379"}, + {file = "psycopg2_binary-2.9.7-cp39-cp39-win_amd64.whl", hash = "sha256:eb3b8d55924a6058a26db69fb1d3e7e32695ff8b491835ba9f479537e14dcf9f"}, +] + [[package]] name = "py" version = "1.11.0" @@ -1173,6 +1676,18 @@ files = [ {file = "pycodestyle-2.11.0.tar.gz", hash = "sha256:259bcc17857d8a8b3b4a2327324b79e5f020a13c16074670f9c8c8f872ea76d0"}, ] +[[package]] +name = "pycparser" +version = "2.21" +description = "C parser in Python" +category = "dev" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +files = [ + {file = "pycparser-2.21-py2.py3-none-any.whl", hash = "sha256:8ee45429555515e1f6b185e78100aea234072576aa43ab53aefcae078162fca9"}, + {file = "pycparser-2.21.tar.gz", hash = "sha256:e644fdec12f7872f86c58ff790da456218b10f863970249516d60a5eaca77206"}, +] + [[package]] name = "pydantic" version = "1.10.12" @@ -1385,6 +1900,48 @@ files = [ [package.dependencies] six = ">=1.5" +[[package]] +name = "python-slugify" +version = "8.0.1" +description = "A Python slugify application that also handles Unicode" +category = "dev" +optional = false +python-versions = ">=3.7" +files = [ + {file = "python-slugify-8.0.1.tar.gz", hash = "sha256:ce0d46ddb668b3be82f4ed5e503dbc33dd815d83e2eb6824211310d3fb172a27"}, + {file = "python_slugify-8.0.1-py2.py3-none-any.whl", hash = "sha256:70ca6ea68fe63ecc8fa4fcf00ae651fc8a5d02d93dcd12ae6d4fc7ca46c4d395"}, +] + +[package.dependencies] +text-unidecode = ">=1.3" + +[package.extras] +unidecode = ["Unidecode (>=1.1.1)"] + +[[package]] +name = "pytimeparse" +version = "1.1.8" +description = "Time expression parser" +category = "dev" +optional = false +python-versions = "*" +files = [ + {file = "pytimeparse-1.1.8-py2.py3-none-any.whl", hash = "sha256:04b7be6cc8bd9f5647a6325444926c3ac34ee6bc7e69da4367ba282f076036bd"}, + {file = "pytimeparse-1.1.8.tar.gz", hash = "sha256:e86136477be924d7e670646a98561957e8ca7308d44841e21f5ddea757556a0a"}, +] + +[[package]] +name = "pytz" +version = "2023.3.post1" +description = "World timezone definitions, modern and historical" +category = "dev" +optional = false +python-versions = "*" +files = [ + {file = "pytz-2023.3.post1-py2.py3-none-any.whl", hash = "sha256:ce42d816b81b68506614c11e8937d3aa9e41007ceb50bfdcb0749b921bf646c7"}, + {file = "pytz-2023.3.post1.tar.gz", hash = "sha256:7b4fddbeb94a1eba4b557da24f19fdf9db575192544270a9101d8509f9f43d7b"}, +] + [[package]] name = "pyyaml" version = "6.0.1" @@ -1679,6 +2236,23 @@ files = [ {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"}, ] +[[package]] +name = "sqlparse" +version = "0.4.4" +description = "A non-validating SQL parser." +category = "dev" +optional = false +python-versions = ">=3.5" +files = [ + {file = "sqlparse-0.4.4-py3-none-any.whl", hash = "sha256:5430a4fe2ac7d0f93e66f1efc6e1338a41884b7ddf2a350cedd20ccc4d9d28f3"}, + {file = "sqlparse-0.4.4.tar.gz", hash = "sha256:d446183e84b8349fa3061f0fe7f06ca94ba65b426946ffebe6e3e8295332420c"}, +] + +[package.extras] +dev = ["build", "flake8"] +doc = ["sphinx"] +test = ["pytest", "pytest-cov"] + [[package]] name = "termcolor" version = "2.3.0" @@ -1694,6 +2268,18 @@ files = [ [package.extras] tests = ["pytest", "pytest-cov"] +[[package]] +name = "text-unidecode" +version = "1.3" +description = "The most basic Text::Unidecode port" +category = "dev" +optional = false +python-versions = "*" +files = [ + {file = "text-unidecode-1.3.tar.gz", hash = "sha256:bad6603bb14d279193107714b288be206cac565dfa49aa5b105294dd5c4aab93"}, + {file = "text_unidecode-1.3-py2.py3-none-any.whl", hash = "sha256:1311f10e8b895935241623731c2ba64f4c455287888b18189350b67134a822e8"}, +] + [[package]] name = "toml" version = "0.10.2" @@ -1824,6 +2410,24 @@ files = [ [package.extras] watchmedo = ["PyYAML (>=3.10)"] +[[package]] +name = "werkzeug" +version = "2.3.7" +description = "The comprehensive WSGI web application library." +category = "dev" +optional = false +python-versions = ">=3.8" +files = [ + {file = "werkzeug-2.3.7-py3-none-any.whl", hash = "sha256:effc12dba7f3bd72e605ce49807bbe692bd729c3bb122a3b91747a6ae77df528"}, + {file = "werkzeug-2.3.7.tar.gz", hash = "sha256:2b8c0e447b4b9dbcc85dd97b6eeb4dcbaf6c8b6c3be0bd654e25553e0a2157d8"}, +] + +[package.dependencies] +MarkupSafe = ">=2.1.1" + +[package.extras] +watchdog = ["watchdog (>=2.3)"] + [[package]] name = "zipp" version = "3.16.2" @@ -1843,4 +2447,4 @@ testing = ["big-O", "jaraco.functools", "jaraco.itertools", "more-itertools", "p [metadata] lock-version = "2.0" python-versions = "^3.9" -content-hash = "0659ce885d2120a04911ed12b3f6b15e72fa40903ffa721cc66672c988f7101d" +content-hash = "82222dccc8b8416318fde948f1dc8f1e9047870b864dbf8c1fde6e18021b55cf" diff --git a/pyproject.toml b/pyproject.toml index a27ae8f..b4f1a8f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -32,6 +32,7 @@ click = "^8.1.3" dbt-artifacts-parser = "^0.4" [tool.poetry.group.dev.dependencies] +dbt-postgres = "^1.5" pytest = "^6.2.5" pytest-sugar = "^0.9.6" black = "^22.10.0" diff --git a/tests/unit/adapters/algos/test_test_relationship.py b/tests/unit/adapters/algos/test_test_relationship.py index 24a7e51..1987949 100644 --- a/tests/unit/adapters/algos/test_test_relationship.py +++ b/tests/unit/adapters/algos/test_test_relationship.py @@ -6,7 +6,7 @@ from dbterd.adapters.algos import base as base_algo from dbterd.adapters.algos import test_relationship as algo -from dbterd.adapters.algos.meta import Column, Ref, Table +from dbterd.adapters.meta import Column, Ref, Table @dataclass diff --git a/tests/unit/adapters/targets/d2/test_d2_test_relationship.py b/tests/unit/adapters/targets/d2/test_d2_test_relationship.py index 16ee9ad..0278bf1 100644 --- a/tests/unit/adapters/targets/d2/test_d2_test_relationship.py +++ b/tests/unit/adapters/targets/d2/test_d2_test_relationship.py @@ -2,7 +2,7 @@ import pytest -from dbterd.adapters.algos.meta import Column, Ref, Table +from dbterd.adapters.meta import Column, Ref, Table from dbterd.adapters.targets.d2 import d2_test_relationship as engine diff --git a/tests/unit/adapters/targets/dbml/test_dbml_test_relationship.py b/tests/unit/adapters/targets/dbml/test_dbml_test_relationship.py index c74756c..d365444 100644 --- a/tests/unit/adapters/targets/dbml/test_dbml_test_relationship.py +++ b/tests/unit/adapters/targets/dbml/test_dbml_test_relationship.py @@ -2,7 +2,7 @@ import pytest -from dbterd.adapters.algos.meta import Column, Ref, Table +from dbterd.adapters.meta import Column, Ref, Table from dbterd.adapters.targets.dbml import dbml_test_relationship as engine diff --git a/tests/unit/adapters/targets/graphviz/test_graphviz_test_relationship.py b/tests/unit/adapters/targets/graphviz/test_graphviz_test_relationship.py index 6991a5b..0f86050 100644 --- a/tests/unit/adapters/targets/graphviz/test_graphviz_test_relationship.py +++ b/tests/unit/adapters/targets/graphviz/test_graphviz_test_relationship.py @@ -2,7 +2,7 @@ import pytest -from dbterd.adapters.algos.meta import Column, Ref, Table +from dbterd.adapters.meta import Column, Ref, Table from dbterd.adapters.targets.graphviz import graphviz_test_relationship as engine diff --git a/tests/unit/adapters/targets/mermaid/test_mermaid_test_relationship.py b/tests/unit/adapters/targets/mermaid/test_mermaid_test_relationship.py index b130d2f..e178842 100644 --- a/tests/unit/adapters/targets/mermaid/test_mermaid_test_relationship.py +++ b/tests/unit/adapters/targets/mermaid/test_mermaid_test_relationship.py @@ -2,7 +2,7 @@ import pytest -from dbterd.adapters.algos.meta import Column, Ref, Table +from dbterd.adapters.meta import Column, Ref, Table from dbterd.adapters.targets.mermaid import mermaid_test_relationship as engine diff --git a/tests/unit/adapters/targets/plantuml/test_plantuml_test_relationship.py b/tests/unit/adapters/targets/plantuml/test_plantuml_test_relationship.py index 68b3f7d..5d39823 100644 --- a/tests/unit/adapters/targets/plantuml/test_plantuml_test_relationship.py +++ b/tests/unit/adapters/targets/plantuml/test_plantuml_test_relationship.py @@ -2,7 +2,7 @@ import pytest -from dbterd.adapters.algos.meta import Column, Ref, Table +from dbterd.adapters.meta import Column, Ref, Table from dbterd.adapters.targets.plantuml import plantuml_test_relationship as engine diff --git a/tests/unit/adapters/test_factory.py b/tests/unit/adapters/test_adapter.py similarity index 57% rename from tests/unit/adapters/test_factory.py rename to tests/unit/adapters/test_adapter.py index 9f81108..ea4a9f8 100644 --- a/tests/unit/adapters/test_factory.py +++ b/tests/unit/adapters/test_adapter.py @@ -1,13 +1,13 @@ import pytest -from dbterd.adapters import factory +from dbterd.adapters import adapter from dbterd.adapters.targets import dbml class TestFactory: def test_load_executor_failed(self): with pytest.raises(Exception): - factory.load_executor(name="dummy") + adapter.load_executor(name="dummy") def test_load_executor(self): - assert factory.load_executor(name="dbml") == dbml + assert adapter.load_executor(name="dbml") == dbml diff --git a/tests/unit/adapters/test_base.py b/tests/unit/adapters/test_base.py index 5f6404e..6b96051 100644 --- a/tests/unit/adapters/test_base.py +++ b/tests/unit/adapters/test_base.py @@ -2,8 +2,10 @@ from unittest import mock import click +import pytest -from dbterd.adapters.worker import DbtWorker +from dbterd import default +from dbterd.adapters.base import Executor class TestBase: @@ -15,12 +17,12 @@ class TestBase: # ) def test_worker(self): - worker = DbtWorker(ctx=click.Context(command=click.BaseCommand("dummy"))) + worker = Executor(ctx=click.Context(command=click.BaseCommand("dummy"))) assert worker.filename_manifest == "manifest.json" assert worker.filename_catalog == "catalog.json" def test___read_manifest(self): - worker = DbtWorker(ctx=click.Context(command=click.BaseCommand("dummy"))) + worker = Executor(ctx=click.Context(command=click.BaseCommand("dummy"))) with mock.patch( "dbterd.helpers.file.read_manifest", return_value=dict({}) ) as mock_read_manifest: @@ -32,7 +34,7 @@ def test___read_manifest(self): mock_read_manifest.assert_called_once_with(path=Path.cwd(), version=None) def test___read_catalog(self): - worker = DbtWorker(ctx=click.Context(command=click.BaseCommand("dummy"))) + worker = Executor(ctx=click.Context(command=click.BaseCommand("dummy"))) with mock.patch( "dbterd.helpers.file.read_catalog", return_value=dict({}) ) as mock_read_catalog: @@ -42,3 +44,88 @@ def test___read_catalog(self): assert worker._Executor__read_catalog(cp=Path.cwd()) == dict({}) mock_check_existence.assert_called_once_with(Path.cwd(), "catalog.json") mock_read_catalog.assert_called_once_with(path=Path.cwd(), version=None) + + @mock.patch( + "dbterd.adapters.base.DbtInvocation.get_selection", return_value="dummy" + ) + def test__get_selection(self, mock_dbt_invocation): + worker = Executor(ctx=click.Context(command=click.BaseCommand("dummy"))) + assert "dummy" == worker._Executor__get_selection( + select_rules=[], exclude_rules=[] + ) + mock_dbt_invocation.assert_called_once() + + @pytest.mark.parametrize( + "kwargs, expected", + [ + ( + dict( + select=[], + exclude=[], + ), + dict( + artifacts_dir="/path/ad", + dbt_project_dir="/path/dpd", + select=[], + exclude=[], + ), + ), + ( + dict(select=[], exclude=[], dbt=True), + dict( + dbt=True, + artifacts_dir="/path/ad", + dbt_project_dir="/path/dpd", + select=["yolo"], + exclude=[], + ), + ), + ], + ) + @mock.patch("dbterd.adapters.base.Executor._Executor__get_dir") + @mock.patch("dbterd.adapters.base.Executor._Executor__get_selection") + def test_evaluate_kwargs(self, mock_get_selection, mock_get_dir, kwargs, expected): + worker = Executor(ctx=click.Context(command=click.BaseCommand("dummy"))) + mock_get_dir.return_value = ("/path/ad", "/path/dpd") + mock_get_selection.return_value = ["yolo"] + assert expected == worker.evaluate_kwargs(**kwargs) + mock_get_dir.assert_called_once() + + @pytest.mark.parametrize( + "kwargs, mock_isfile_se, expected", + [ + ( + dict(artifacts_dir=Path.cwd(), dbt_project_dir=Path.cwd()), + [False], + (str(f"{Path.cwd()}/target"), str(Path.cwd())), + ), + ( + dict(artifacts_dir=Path.cwd(), dbt_project_dir=Path.cwd()), + [True], + (str(Path.cwd()), str(Path.cwd())), + ), + ( + dict(artifacts_dir=None, dbt_project_dir=Path.cwd()), + [True], + (str(Path.cwd()), str(Path.cwd())), + ), + ( + dict(artifacts_dir=Path.cwd(), dbt_project_dir=None), + [True], + (str(Path.cwd()), str(Path.cwd())), + ), + ( + dict(artifacts_dir="", dbt_project_dir=""), + [True], + ( + str(default.default_artifact_path()), + str(Path(default.default_artifact_path()).parent.absolute()), + ), + ), + ], + ) + @mock.patch("os.path.isfile") + def test__get_dir(self, mock_isfile, kwargs, mock_isfile_se, expected): + worker = Executor(ctx=click.Context(command=click.BaseCommand("dummy"))) + mock_isfile.side_effect = mock_isfile_se + assert worker._Executor__get_dir(**kwargs) == expected diff --git a/tests/unit/adapters/test_dbt_invocation.py b/tests/unit/adapters/test_dbt_invocation.py new file mode 100644 index 0000000..5fdf354 --- /dev/null +++ b/tests/unit/adapters/test_dbt_invocation.py @@ -0,0 +1,65 @@ +from importlib.machinery import ModuleSpec +from unittest import mock + +import click +import pytest +from dbt.cli.main import dbtRunnerResult + +from dbterd.adapters.dbt_invocation import DbtInvocation + + +class TestDbtInvocation: + @mock.patch("importlib.util.find_spec") + def test__ensure_dbt_installed__no_dbt_installed(self, mock_find_spec): + mock_find_spec.return_value = ModuleSpec(name="dbt", loader=None) + with pytest.raises(click.UsageError): + DbtInvocation()._DbtInvocation__ensure_dbt_installed() + + @pytest.mark.parametrize( + "select_rules, exclude_rules, mock_dbtRunner_invoke_rv, expected", + [ + ([], [], dbtRunnerResult(success=True, result=[]), []), + ( + [], + [], + dbtRunnerResult(success=True, result=["p1.p2.p3.p4"]), + ["exact:model.p1.p4"], + ), + ( + ["dummy"], + ["dummy"], + dbtRunnerResult(success=True, result=["p1.p2.p3.p4"]), + ["exact:model.p1.p4"], + ), + ], + ) + @mock.patch("dbterd.adapters.dbt_invocation.dbtRunner.invoke") + def test_get_selection( + self, + mock_dbtRunner_invoke, + select_rules, + exclude_rules, + mock_dbtRunner_invoke_rv, + expected, + ): + mock_dbtRunner_invoke.return_value = mock_dbtRunner_invoke_rv + invoker = DbtInvocation() + actual = invoker.get_selection( + select_rules=select_rules, exclude_rules=exclude_rules + ) + assert actual == expected + + args = ["ls", "--project-dir", invoker.project_dir, "--resource-type", "model"] + if select_rules: + args.extend(["--select", " ".join(select_rules)]) + if exclude_rules: + args.extend(["--exclude", " ".join(exclude_rules)]) + mock_dbtRunner_invoke.assert_called_once_with(args) + + @mock.patch("dbterd.adapters.dbt_invocation.dbtRunner.invoke") + def test_get_selection__failed(self, mock_dbtRunner_invoke): + mock_dbtRunner_invoke.return_value = dbtRunnerResult(success=False) + with pytest.raises(click.UsageError): + DbtInvocation(dbt_target="dummy").get_selection( + select_rules=[], exclude_rules=[] + ) diff --git a/tests/unit/adapters/test_filter.py b/tests/unit/adapters/test_filter.py new file mode 100644 index 0000000..3950640 --- /dev/null +++ b/tests/unit/adapters/test_filter.py @@ -0,0 +1,51 @@ +import pytest + +from dbterd.adapters import filter +from dbterd.adapters.meta import Table + + +class TestFilter: + @pytest.mark.parametrize( + "rule, expected", + [ + ([], (False, None)), + (["dummy_name"], (False, None)), + (["schema:dummy_name"], (False, None)), + (["exact:dummy_name"], (False, None)), + (["exposure:dummy_name"], (False, None)), + (["dummy:dummy_name"], (True, "dummy")), + ], + ) + def test_has_unsupported_rule(self, rule, expected): + actual = filter.has_unsupported_rule(rules=rule) + assert actual == expected + + @pytest.mark.parametrize( + "table, rule, expected", + [ + ( + Table( + name="model.dummy.table1", database="dummydb", schema="dummyschema" + ), + "", + True, + ), + ( + Table( + name="model.dummy.table1", database="dummydb", schema="dummyschema" + ), + "table1", + False, + ), + ( + Table( + name="model.dummy.table1", database="dummydb", schema="dummyschema" + ), + "model.dummy.table1", + True, + ), + ], + ) + def test_is_satisfied_by_exact(self, table, rule, expected): + actual = filter.is_satisfied_by_exact(table=table, rule=rule) + assert actual == expected diff --git a/tests/unit/cli/test_runner.py b/tests/unit/cli/test_runner.py index acc2348..100c96a 100644 --- a/tests/unit/cli/test_runner.py +++ b/tests/unit/cli/test_runner.py @@ -100,3 +100,37 @@ def test_invoke_run_ok(self, target, output, dbterd: dbterdRunner) -> None: ["run", "--target", target, "--output", "/custom/path"] ) mock_open_w.assert_called_with(f"/custom/path/{output}", "w") + + def test_command_invalid_selection_rule(self, dbterd: dbterdRunner) -> None: + with pytest.raises(Exception): + dbterd.invoke(["run", "--select", "notexist:dummy"]) + + @pytest.mark.parametrize( + "target, output", + [ + ("dbml", "output.dbml"), + ], + ) + def test_invoke_run_failed_to_write_output( + self, target, output, dbterd: dbterdRunner + ) -> None: + with mock.patch( + "dbterd.adapters.base.Executor._Executor__read_manifest", return_value=None + ) as mock_read_m: + with mock.patch( + "dbterd.adapters.base.Executor._Executor__read_catalog", + return_value=None, + ) as mock_read_c: + with mock.patch( + f"dbterd.adapters.targets.{target}.{target}_test_relationship.parse", + return_value="--irrelevant--", + ) as mock_engine_parse: + with mock.patch( + "builtins.open", return_value=PermissionError() + ) as mock_open_w: + with pytest.raises(click.FileError): + dbterd.invoke(["run", "--target", target]) + mock_read_m.assert_called_once() + mock_read_c.assert_called_once() + mock_engine_parse.assert_called_once() + mock_open_w.assert_called_once()