dbt-selly/dbt-env/lib/python3.8/site-packages/dbt/contracts/project.py

277 lines
7.4 KiB
Python
Raw Normal View History

2022-03-22 15:13:27 +00:00
from dbt.contracts.util import Replaceable, Mergeable, list_str
from dbt.contracts.connection import UserConfigContract, QueryComment
from dbt.helper_types import NoValue
from dbt.logger import GLOBAL_LOGGER as logger # noqa
from dbt import tracking
from dbt import ui
from dbt.dataclass_schema import (
dbtClassMixin, ValidationError,
HyphenatedDbtClassMixin,
ExtensibleDbtClassMixin,
register_pattern, ValidatedStringMixin
)
from dataclasses import dataclass, field
from typing import Optional, List, Dict, Union, Any
from mashumaro.types import SerializableType
PIN_PACKAGE_URL = 'https://docs.getdbt.com/docs/package-management#section-specifying-package-versions' # noqa
DEFAULT_SEND_ANONYMOUS_USAGE_STATS = True
class Name(ValidatedStringMixin):
ValidationRegex = r'^[^\d\W]\w*$'
register_pattern(Name, r'^[^\d\W]\w*$')
class SemverString(str, SerializableType):
def _serialize(self) -> str:
return self
@classmethod
def _deserialize(cls, value: str) -> 'SemverString':
return SemverString(value)
# this does not support the full semver (does not allow a trailing -fooXYZ) and
# is not restrictive enough for full semver, (allows '1.0'). But it's like
# 'semver lite'.
register_pattern(
SemverString,
r'^(?:0|[1-9]\d*)\.(?:0|[1-9]\d*)(\.(?:0|[1-9]\d*))?$',
)
@dataclass
class Quoting(dbtClassMixin, Mergeable):
schema: Optional[bool] = None
database: Optional[bool] = None
project: Optional[bool] = None
identifier: Optional[bool] = None
@dataclass
class Package(Replaceable, HyphenatedDbtClassMixin):
pass
@dataclass
class LocalPackage(Package):
local: str
# `float` also allows `int`, according to PEP484 (and jsonschema!)
RawVersion = Union[str, float]
@dataclass
class GitPackage(Package):
git: str
revision: Optional[RawVersion] = None
warn_unpinned: Optional[bool] = None
subdirectory: Optional[str] = None
def get_revisions(self) -> List[str]:
if self.revision is None:
return []
else:
return [str(self.revision)]
@dataclass
class RegistryPackage(Package):
package: str
version: Union[RawVersion, List[RawVersion]]
install_prerelease: Optional[bool] = False
def get_versions(self) -> List[str]:
if isinstance(self.version, list):
return [str(v) for v in self.version]
else:
return [str(self.version)]
PackageSpec = Union[LocalPackage, GitPackage, RegistryPackage]
@dataclass
class PackageConfig(dbtClassMixin, Replaceable):
packages: List[PackageSpec]
@dataclass
class ProjectPackageMetadata:
name: str
packages: List[PackageSpec]
@classmethod
def from_project(cls, project):
return cls(name=project.project_name,
packages=project.packages.packages)
@dataclass
class Downloads(ExtensibleDbtClassMixin, Replaceable):
tarball: str
@dataclass
class RegistryPackageMetadata(
ExtensibleDbtClassMixin,
ProjectPackageMetadata,
):
downloads: Downloads
# A list of all the reserved words that packages may not have as names.
BANNED_PROJECT_NAMES = {
'_sql_results',
'adapter',
'api',
'column',
'config',
'context',
'database',
'env',
'env_var',
'exceptions',
'execute',
'flags',
'fromjson',
'fromyaml',
'graph',
'invocation_id',
'load_agate_table',
'load_result',
'log',
'model',
'modules',
'post_hooks',
'pre_hooks',
'ref',
'render',
'return',
'run_started_at',
'schema',
'source',
'sql',
'sql_now',
'store_result',
'store_raw_result',
'target',
'this',
'tojson',
'toyaml',
'try_or_compiler_error',
'var',
'write',
}
@dataclass
class Project(HyphenatedDbtClassMixin, Replaceable):
name: Name
version: Union[SemverString, float]
config_version: int
project_root: Optional[str] = None
source_paths: Optional[List[str]] = None
macro_paths: Optional[List[str]] = None
data_paths: Optional[List[str]] = None
test_paths: Optional[List[str]] = None
analysis_paths: Optional[List[str]] = None
docs_paths: Optional[List[str]] = None
asset_paths: Optional[List[str]] = None
target_path: Optional[str] = None
snapshot_paths: Optional[List[str]] = None
clean_targets: Optional[List[str]] = None
profile: Optional[str] = None
log_path: Optional[str] = None
modules_path: Optional[str] = None
quoting: Optional[Quoting] = None
on_run_start: Optional[List[str]] = field(default_factory=list_str)
on_run_end: Optional[List[str]] = field(default_factory=list_str)
require_dbt_version: Optional[Union[List[str], str]] = None
dispatch: List[Dict[str, Any]] = field(default_factory=list)
models: Dict[str, Any] = field(default_factory=dict)
seeds: Dict[str, Any] = field(default_factory=dict)
snapshots: Dict[str, Any] = field(default_factory=dict)
analyses: Dict[str, Any] = field(default_factory=dict)
sources: Dict[str, Any] = field(default_factory=dict)
tests: Dict[str, Any] = field(default_factory=dict)
vars: Optional[Dict[str, Any]] = field(
default=None,
metadata=dict(
description='map project names to their vars override dicts',
),
)
packages: List[PackageSpec] = field(default_factory=list)
query_comment: Optional[Union[QueryComment, NoValue, str]] = NoValue()
@classmethod
def validate(cls, data):
super().validate(data)
if data['name'] in BANNED_PROJECT_NAMES:
raise ValidationError(
f"Invalid project name: {data['name']} is a reserved word"
)
# validate dispatch config
if 'dispatch' in data and data['dispatch']:
entries = data['dispatch']
for entry in entries:
if ('macro_namespace' not in entry or 'search_order' not in entry or
not isinstance(entry['search_order'], list)):
raise ValidationError(f"Invalid project dispatch config: {entry}")
@dataclass
class UserConfig(ExtensibleDbtClassMixin, Replaceable, UserConfigContract):
send_anonymous_usage_stats: bool = DEFAULT_SEND_ANONYMOUS_USAGE_STATS
use_colors: Optional[bool] = None
partial_parse: Optional[bool] = None
printer_width: Optional[int] = None
def set_values(self, cookie_dir):
if self.send_anonymous_usage_stats:
tracking.initialize_tracking(cookie_dir)
else:
tracking.do_not_track()
if self.use_colors is not None:
ui.use_colors(self.use_colors)
if self.printer_width:
ui.printer_width(self.printer_width)
@dataclass
class ProfileConfig(HyphenatedDbtClassMixin, Replaceable):
profile_name: str = field(metadata={'preserve_underscore': True})
target_name: str = field(metadata={'preserve_underscore': True})
config: UserConfig
threads: int
# TODO: make this a dynamic union of some kind?
credentials: Optional[Dict[str, Any]]
@dataclass
class ConfiguredQuoting(Quoting, Replaceable):
identifier: bool = True
schema: bool = True
database: Optional[bool] = None
project: Optional[bool] = None
@dataclass
class Configuration(Project, ProfileConfig):
cli_vars: Dict[str, Any] = field(
default_factory=dict,
metadata={'preserve_underscore': True},
)
quoting: Optional[ConfiguredQuoting] = None
@dataclass
class ProjectList(dbtClassMixin):
projects: Dict[str, Project]