From 40f8aab6ee1828d38dc2a055b0ae4827504e9049 Mon Sep 17 00:00:00 2001 From: Niall Woodward Date: Thu, 24 Mar 2022 10:56:53 +0000 Subject: [PATCH] Release 2.0.0a2 --- CHANGELOG.md | 14 +++++ dbtenv/__init__.py | 5 +- dbtenv/execute.py | 33 +++++++----- dbtenv/pip.py | 121 ++++++++++++++++++++++------------------- dbtenv/version.py | 130 ++++++++++++++++++++++----------------------- dbtenv/which.py | 23 +++----- 6 files changed, 172 insertions(+), 154 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7525d64..1f678b0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,20 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Fixed +## [2.0.0a2](https://github.com/brooklyn-data/dbtenv/compare/v2.0.0a1...v2.0.0a2) + +### Added +- The execute command's `--dbt` argument can now take either a dbt version (e.g. 1.0.0) or full pip specifier to use (e.g. dbt-snowflake==1.0.0). dbtenv will attempt to automatically detect the required adapter or version from the environment if not specified. + +### Changed +- Attempting to install a version of dbt which doesn't exist will exit cleanly, and provide a list of available versions for that adapter. +- Failed dbt version installations exit cleanly, removing the created virtual environment. +- Improved logging. + +### Fixed +- Only entries in the environment directory which are dbtenv 2.0.0 environments will be read as installed dbt versions, fixing an issue where dbtenv 1.0.0 environments caused a failure. +- Fixed version command, and all dbtenv config files. These can now take either a dbt version (e.g. 1.0.0) or full pip specifier to use (e.g. dbt-snowflake==1.0.0). dbtenv will attempt to automatically detect the required adapter or version from the environment if not specified. + ## [2.0.0a1](https://github.com/brooklyn-data/dbtenv/compare/v1.3.2...v2.0.0a1) ### Added diff --git a/dbtenv/__init__.py b/dbtenv/__init__.py index b309ac0..ad40c07 100644 --- a/dbtenv/__init__.py +++ b/dbtenv/__init__.py @@ -8,7 +8,6 @@ import os.path import platform import re -import shutil import subprocess import sys from typing import Any, List, Optional @@ -73,9 +72,11 @@ class Version(distutils.version.LooseVersion): def __init__(self, pip_specifier: str = None, adapter_type: str = None, version: str = None, source: Optional[str] = None, source_description: Optional[str] = None) -> None: if pip_specifier: self.pip_specifier = pip_specifier - self.name, self.version = re.match(r"(.*)==(.*)", pip_specifier).groups() + self.name, self.version = re.match(r"^(dbt-.+)==(.+)$", pip_specifier).groups() + self.adapter_type = self.name.replace("dbt-", "") self.pypi_version = self.version else: + self.adapter_type = adapter_type self.name = f"dbt-{adapter_type}" self.pypi_version = version self.pip_specifier = f"{self.name}=={self.pypi_version}" diff --git a/dbtenv/execute.py b/dbtenv/execute.py index 8eafad0..8624575 100644 --- a/dbtenv/execute.py +++ b/dbtenv/execute.py @@ -34,12 +34,12 @@ def add_args_parser(self, subparsers: argparse._SubParsersAction, parent_parsers ) parser.add_argument( '--dbt', - dest='dbt_version', + dest='dbt_version_specifier', type=str, - metavar='', + metavar='', help=""" - dbt version to use (e.g. 1.0.1). - If not specified, the dbt version will be automatically detected from the environment. + dbt version (e.g. 1.0.0) or full pip specifier to use (e.g. dbt-snowflake==1.0.0). + dbtenv will attempt to automatically detect the required adapter or version from the environment if not specified. """ ) parser.add_argument( @@ -59,17 +59,26 @@ def execute(self, args: Args) -> None: if arg == "--target": arg_target_name = args.dbt_args[i+1] break - adapter_type = dbtenv.version.try_get_project_adapter_type(self.env.project_file, target_name=arg_target_name) - if not adapter_type: - logger.info("Could not determine adapter, either not running inside dbt project or no default target is set for the current project in profiles.yml.") - return - if args.dbt_version: - version = Version(adapter_type=adapter_type, version=args.dbt_version) + adapter_type = dbtenv.version.try_get_project_adapter_type(self.env.project_file, target_name=arg_target_name) + if args.dbt_version_specifier: + if bool(re.search(r"^(dbt-.+)==(.+)$", args.dbt_version_specifier)): + version = Version(pip_specifier=args.dbt_version_specifier, source_description="specified using --dbt arg") + elif bool(re.search(r"^[0-9\.]+[a-z0-9]*$", args.dbt_version_specifier)): + if not adapter_type: + logger.info("Could not determine adapter type as no default target is set for the current project in profiles.yml.") + return + version = Version(adapter_type=adapter_type, version=args.dbt_version_specifier, source_description="adapter type automatically detected, version specified using --dbt arg") + else: + logger.info("The argument passed to --dbt didn't match a dbt version (e.g. 1.0.0) or full pip specifier (e.g. dbt-snowflake==1.0.0).") + return else: - arg_target_name = None version = dbtenv.version.get_version(self.env, adapter_type=adapter_type) - logger.info(f"Using {version} ({version.source_description}).") + + if not version: + return + + logger.info(f"Using {version} ({version.source_description}).") dbt = dbtenv.which.try_get_dbt(self.env, version) if not dbt: diff --git a/dbtenv/pip.py b/dbtenv/pip.py index f199deb..98c42a9 100644 --- a/dbtenv/pip.py +++ b/dbtenv/pip.py @@ -55,13 +55,31 @@ def get_installed_pip_dbt_versions(env: Environment, adapter_type: Optional[str] return [] versions = [] for entry in os.scandir(env.venvs_directory): - if not adapter_type or entry.name.startswith(f"dbt-{adapter_type}"): + if entry.is_dir() and bool(re.search(r"^(dbt-.+)==(.+)$", entry.name)) and (not adapter_type or entry.name.startswith(f"dbt-{adapter_type}==")): versions.append( Version(pip_specifier=entry.name) ) return versions +def get_pypi_package_metadata(package: str) -> str: + package_json_url = f'https://pypi.org/pypi/{package}/json' + logger.debug(f"Fetching {package} package metadata from {package_json_url}.") + with urllib.request.urlopen(package_json_url) as package_json_response: + return json.load(package_json_response) + +def get_pypi_package_versions(adapter_type: str) -> List[Version]: + package_metadata = get_pypi_package_metadata(f"dbt-{adapter_type}") + possible_versions = ((Version(adapter_type=adapter_type, version=version), files) for version, files in package_metadata['releases'].items()) + return [version for version, files in possible_versions if any(not file['yanked'] for file in files)] + +def get_pypi_all_dbt_package_versions() -> List[Version]: + versions = [] + for adapter_type in DBT_ADAPTER_TYPES: + versions += get_pypi_package_versions(adapter_type) + return versions + + class PipDbt(Dbt): """A specific version of dbt installed with pip in a Python virtual environment.""" @@ -78,6 +96,11 @@ def install(self, force: bool = False, package_location: Optional[str] = None, e else: raise DbtenvError(f"`{self.venv_directory}` already exists.") + available_adapter_versions = get_pypi_package_versions(adapter_type=self.version.adapter_type) + if self.version not in available_adapter_versions: + logger.info(f"{self.version} is not available for installation from pypi. Try one of {[v.pypi_version for v in available_adapter_versions]}") + return + python = self.env.python self._check_python_compatibility(python) @@ -86,43 +109,47 @@ def install(self, force: bool = False, package_location: Optional[str] = None, e if venv_result.returncode != 0: raise DbtenvError(f"Failed to create virtual environment in `{self.venv_directory}`.") - pip = self._find_pip() - # Upgrade pip to avoid problems with packages that might require newer pip features. - subprocess.run([pip, 'install', '--upgrade', 'pip']) - # Install wheel to avoid pip falling back to using legacy `setup.py` installs. - subprocess.run([pip, 'install', '--disable-pip-version-check', 'wheel']) - pip_args = ['install', '--disable-pip-version-check'] - if package_location: - package_source = f"`{package_location}`" - if editable: - pip_args.append('--editable') - pip_args.append(package_location) - else: - package_source = "the Python Package Index" - if self.env.simulate_release_date: - package_metadata = get_pypi_package_metadata('dbt') - release_date = date.fromisoformat(package_metadata['releases'][self.version.pypi_version][0]['upload_time'][:10]) - logger.info(f"Simulating release date {release_date} for dbt {self.version}.") - class ReleaseDateFilterPyPIRequestHandler(BaseDateFilterPyPIRequestHandler): - date = release_date - pip_filter_server = http.server.HTTPServer(('', 0), ReleaseDateFilterPyPIRequestHandler) - pip_filter_port = pip_filter_server.socket.getsockname()[1] - threading.Thread(target=pip_filter_server.serve_forever, daemon=True).start() - pip_args.extend(['--index-url', f'http://localhost:{pip_filter_port}/simple']) - elif self.version.pypi_version < '0.19.1': - # Versions prior to 0.19.1 just specified agate>=1.6, but agate 1.6.2 introduced a dependency on PyICU - # which causes installation problems, so exclude that like versions 0.19.1 and above do. - pip_args.append('agate>=1.6,<1.6.2') - - pip_args.append(self.version.pip_specifier) - logger.info(f"Installing {self.version.pip_specifier} from {package_source} into `{self.venv_directory}`.") - - logger.debug(f"Running `{pip}` with arguments {pip_args}.") - pip_result = subprocess.run([pip, *pip_args]) - if pip_result.returncode != 0: - raise DbtenvError(f"Failed to install dbt {self.version.pypi_version} from {package_source} into `{self.venv_directory}`.") - - logger.info(f"Successfully installed dbt {self.version.pypi_version} from {package_source} into `{self.venv_directory}`.") + try: + pip = self._find_pip() + # Upgrade pip to avoid problems with packages that might require newer pip features. + subprocess.run([pip, 'install', '--upgrade', 'pip']) + # Install wheel to avoid pip falling back to using legacy `setup.py` installs. + subprocess.run([pip, 'install', '--disable-pip-version-check', 'wheel']) + pip_args = ['install', '--disable-pip-version-check'] + if package_location: + package_source = f"`{package_location}`" + if editable: + pip_args.append('--editable') + pip_args.append(package_location) + else: + package_source = "the Python Package Index" + if self.env.simulate_release_date: + package_metadata = get_pypi_package_metadata('dbt') + release_date = date.fromisoformat(package_metadata['releases'][self.version.pypi_version][0]['upload_time'][:10]) + logger.info(f"Simulating release date {release_date} for dbt {self.version}.") + class ReleaseDateFilterPyPIRequestHandler(BaseDateFilterPyPIRequestHandler): + date = release_date + pip_filter_server = http.server.HTTPServer(('', 0), ReleaseDateFilterPyPIRequestHandler) + pip_filter_port = pip_filter_server.socket.getsockname()[1] + threading.Thread(target=pip_filter_server.serve_forever, daemon=True).start() + pip_args.extend(['--index-url', f'http://localhost:{pip_filter_port}/simple']) + elif self.version.pypi_version < '0.19.1': + # Versions prior to 0.19.1 just specified agate>=1.6, but agate 1.6.2 introduced a dependency on PyICU + # which causes installation problems, so exclude that like versions 0.19.1 and above do. + pip_args.append('agate>=1.6,<1.6.2') + + pip_args.append(self.version.pip_specifier) + logger.info(f"Installing {self.version.pip_specifier} from {package_source} into `{self.venv_directory}`.") + + logger.debug(f"Running `{pip}` with arguments {pip_args}.") + pip_result = subprocess.run([pip, *pip_args]) + if pip_result.returncode != 0: + raise DbtenvError(f"Failed to install dbt {self.version.pypi_version} from {package_source} into `{self.venv_directory}`.") + except Exception as e: + shutil.rmtree(self.venv_directory) + raise(e) + + logger.info(f"Successfully installed {self.version} from {package_source} into `{self.venv_directory}`.") def _check_python_compatibility(self, python: str) -> None: python_version_result = subprocess.run([python, '--version'], stdout=subprocess.PIPE) @@ -209,24 +236,6 @@ def uninstall(self, force: bool = False) -> None: logger.info(f"Successfully uninstalled dbt {self.version.pypi_version} from `{self.venv_directory}`.") -def get_pypi_package_metadata(package: str) -> str: - package_json_url = f'https://pypi.org/pypi/{package}/json' - logger.debug(f"Fetching {package} package metadata from {package_json_url}.") - with urllib.request.urlopen(package_json_url) as package_json_response: - return json.load(package_json_response) - -def get_pypi_package_versions(adapter_type: str) -> List[Version]: - package_metadata = get_pypi_package_metadata(f"dbt-{adapter_type}") - possible_versions = ((Version(adapter_type=adapter_type, version=version), files) for version, files in package_metadata['releases'].items()) - return [version for version, files in possible_versions if any(not file['yanked'] for file in files)] - -def get_pypi_all_dbt_package_versions() -> List[Version]: - versions = [] - for adapter_type in DBT_ADAPTER_TYPES: - versions += get_pypi_package_versions(adapter_type) - return versions - - class BaseDateFilterPyPIRequestHandler(http.server.BaseHTTPRequestHandler): """ HTTP request handler that proxies PEP 503-compliant requests to pypi.org and excludes files uploaded after self.date. diff --git a/dbtenv/version.py b/dbtenv/version.py index 71f3ac6..9e5a98f 100644 --- a/dbtenv/version.py +++ b/dbtenv/version.py @@ -11,7 +11,7 @@ # Local import dbtenv -from dbtenv import Args, Environment, Subcommand, Version +from dbtenv import Args, DbtenvError, Environment, Subcommand, Version import dbtenv.install import dbtenv.versions @@ -39,7 +39,7 @@ def add_args_parser(self, subparsers: argparse._SubParsersAction, parent_parsers '--global', dest='global_dbt_version', nargs='?', - type=Version, + type=str, const='', metavar='', help=f"Show/set the dbt version globally using the `{dbtenv.GLOBAL_VERSION_FILE}` file." @@ -48,7 +48,7 @@ def add_args_parser(self, subparsers: argparse._SubParsersAction, parent_parsers '--local', dest='local_dbt_version', nargs='?', - type=Version, + type=str, const='', metavar='', help=f"Show/set the dbt version for the local directory using `{dbtenv.LOCAL_VERSION_FILE}` files." @@ -71,8 +71,15 @@ def add_args_parser(self, subparsers: argparse._SubParsersAction, parent_parsers def execute(self, args: Args) -> None: if args.global_dbt_version is not None: if args.global_dbt_version != '': - dbtenv.install.ensure_dbt_is_installed(self.env, args.global_dbt_version) - set_global_version(self.env, args.global_dbt_version) + if bool(re.search(r"^(dbt-.+)==(.+)$", args.global_dbt_version)): + version = Version(pip_specifier=args.global_dbt_version) + dbtenv.install.ensure_dbt_is_installed(self.env, version) + set_global_version(self.env, version.pip_specifier) + elif bool(re.search(r"^[0-9\.]+[a-z0-9]*$", args.global_dbt_version)): + set_global_version(self.env, args.global_dbt_version) + else: + logger.info("Argument value doesn't match a dbt version (e.g. 1.0.0) or full pip specifier (e.g. dbt-snowflake==1.0.0).") + return else: global_version = try_get_global_version(self.env) if global_version: @@ -81,8 +88,15 @@ def execute(self, args: Args) -> None: logger.info(f"No global dbt version has been set using the `{dbtenv.GLOBAL_VERSION_FILE}` file.") elif args.local_dbt_version is not None: if args.local_dbt_version != '': - dbtenv.install.ensure_dbt_is_installed(self.env, args.local_dbt_version) - set_local_version(self.env, args.local_dbt_version) + if bool(re.search(r"^(dbt-.+)==(.+)$", args.local_dbt_version)): + version = Version(pip_specifier=args.local_dbt_version) + dbtenv.install.ensure_dbt_is_installed(self.env, version) + set_local_version(self.env, version.pip_specifier) + elif bool(re.search(r"^[0-9\.]+[a-z0-9]*$", args.local_dbt_version)): + set_local_version(self.env, args.local_dbt_version) + else: + logger.info("Argument value doesn't match a dbt version (e.g. 1.0.0) or full pip specifier (e.g. dbt-snowflake==1.0.0).") + return else: local_version = try_get_local_version(self.env) if local_version: @@ -116,51 +130,60 @@ def execute(self, args: Args) -> None: version = get_version(self.env) if version: print(f"{version} ({version.source_description})") - else: - logger.info("Could not determine adapter, either not running inside dbt project or no default target is set for the current project in profiles.yml.") -def read_version_file(file_path: str, adapter_type: str) -> Version: +def read_version_file(file_path: str, adapter_type: Optional[str], source_description: str) -> Optional[Version]: with open(file_path, 'r') as file: - return Version(adapter_type=adapter_type, version=file.readline().strip(), source=file_path) - + value = file.readline().strip() + if bool(re.search(r"^(dbt-.+)==(.+)$", value)): + return Version(pip_specifier=value, source_description=source_description) + elif bool(re.search(r"^[0-9\.]+[a-z0-9]*$", value)): + if adapter_type: + return Version(adapter_type=adapter_type, version=value, source_description=source_description) + else: + raise(DbtenvError(f"Invalid value in {file_path}: {value}")) -def write_version_file(file_path: str, version: Version) -> None: +def write_version_file(file_path: str, value: str) -> None: with open(file_path, 'w') as file: - file.write(str(version)) + file.write(str(value)) -def try_get_global_version(env: Environment, adapter_type: str) -> Optional[Version]: +def try_get_global_version(env: Environment, adapter_type: Optional[str]) -> Optional[Version]: if os.path.isfile(env.global_version_file): - return read_version_file(env.global_version_file, adapter_type) + return read_version_file(env.global_version_file, adapter_type, f"set by global version file {env.global_version_file}") else: return None -def set_global_version(env: Environment, version: Version) -> None: - write_version_file(env.global_version_file, version) - logger.info(f"{version} is now set as the global dbt version in `{env.global_version_file}`.") +def set_global_version(env: Environment, value: str) -> None: + write_version_file(env.global_version_file, value) + logger.info(f"{value} is now set as the global dbt version in `{env.global_version_file}`.") -def try_get_local_version(env: Environment, adapter_type: str) -> Optional[Version]: +def try_get_local_version(env: Environment, adapter_type: Optional[str]) -> Optional[Version]: version_file = env.find_file_along_working_path(dbtenv.LOCAL_VERSION_FILE) if version_file: - return read_version_file(version_file, adapter_type) + return read_version_file(version_file, adapter_type, f"set by local version file {version_file}") else: return None -def set_local_version(env: Environment, version: Version) -> None: +def set_local_version(env: Environment, value: str) -> None: version_file = os.path.join(env.working_directory, dbtenv.LOCAL_VERSION_FILE) - write_version_file(version_file, version) - logger.info(f"{version} is now set as the local dbt version in `{version_file}`.") + write_version_file(version_file, value) + logger.info(f"{value} is now set as the local dbt version in `{version_file}`.") -def try_get_shell_version(env: Environment, adapter_type: str) -> Optional[Version]: +def try_get_shell_version(env: Environment, adapter_type: Optional[str]) -> Optional[Version]: if dbtenv.DBT_VERSION_VAR in env.env_vars: - return Version(adapter_type=adapter_type, version=env.env_vars[dbtenv.DBT_VERSION_VAR], source=dbtenv.DBT_VERSION_VAR) - else: - return None + value = env.env_vars[dbtenv.DBT_VERSION_VAR] + if bool(re.search(r"^(dbt-.+)==(.+)$", value)): + return Version(pip_specifier=value) + elif bool(re.search(r"^[0-9\.]+[a-z0-9]*$", value)): + if adapter_type: + return Version(adapter_type=adapter_type, version=value) + else: + raise(DbtenvError(f"Invalid value in {dbtenv.DBT_VERSION_VAR} environment variable: {value}")) class VersionRequirement: @@ -237,7 +260,10 @@ def try_get_project_adapter_type(project_file: str, target_name: Optional[str] = if not target_name: target_name = profiles_yml.get(profile_name, {}).get("target") - return profiles_yml.get(profile_name, {}).get("outputs", {}).get(target_name, {}).get("type") + adapter_type = profiles_yml.get(profile_name, {}).get("outputs", {}).get(target_name, {}).get("type") + if not adapter_type: + logger.info("Could not determine adapter type as no default target is set for the current project in profiles.yml.") + return adapter_type def try_get_project_version(env: Environment, preferred_version: Optional[Version] = None, adapter_type: Optional[str] = None) -> Optional[Version]: @@ -250,21 +276,6 @@ def try_get_project_version(env: Environment, preferred_version: Optional[Versio project_file = os.path.basename(env.project_file) requirements_project_files = [project_file] scope_decription = "the dbt project" - has_packages_with_version_requirements = False - - package_project_files = ( - glob.glob(os.path.join(env.project_directory, 'dbt_modules', '*', 'dbt_project.yml')) + - glob.glob(os.path.join(env.project_directory, 'dbt_packages', '*', 'dbt_project.yml')) - ) - for package_project_file in package_project_files: - package_version_requirements = try_get_project_version_requirements(package_project_file, adapter_type) - if package_version_requirements: - all_version_requirements.extend(package_version_requirements) - requirements_project_files.append(os.path.relpath(package_project_file, env.project_directory)) - has_packages_with_version_requirements = True - - if has_packages_with_version_requirements: - scope_decription += " and its installed packages" if preferred_version: for requirement in all_version_requirements: @@ -291,34 +302,14 @@ def try_get_project_version(env: Environment, preferred_version: Optional[Versio return compatible_version warning = f"No available versions are compatible with all version requirements in {scope_decription}." - if has_packages_with_version_requirements: - warning += " You may need to upgrade installed packages by updating `packages.yml` and running dbt's `deps` sub-command." logger.warning(warning) - if has_packages_with_version_requirements: - logger.debug("Trying to get dbt version for the project again while ignoring installed packages in case they're out of date.") - - if preferred_version and all(requirement.is_compatible_with(preferred_version) for requirement in project_version_requirements): - return preferred_version - - compatible_version = try_get_max_compatible_version(installed_versions, project_version_requirements) - if compatible_version: - compatible_version.source == project_file - return compatible_version - - compatible_version = try_get_max_compatible_version(installable_versions, project_version_requirements) - if compatible_version: - logger.info(f"{compatible_version} is the latest installable version that is compatible with all version requirements in the dbt project.") - compatible_version.source = project_file - return compatible_version - return None def get_version(env: Environment, adapter_type: Optional[str] = None) -> Optional[Version]: - adapter_type = dbtenv.version.try_get_project_adapter_type(env.project_file) if not adapter_type: - return None + adapter_type = dbtenv.version.try_get_project_adapter_type(env.project_file) shell_version = try_get_shell_version(env, adapter_type) if shell_version: @@ -332,6 +323,11 @@ def get_version(env: Environment, adapter_type: Optional[str] = None) -> Optiona if global_version and not env.project_directory: return global_version + # All below options require an already known adapter type + if not adapter_type: + logger.info("Could not determine adapter type as no dbt --target arg specified, not running in dbt project with a default target, and no full pip specifier set in dbtenv's configuration.") + return None + preferred_version = local_version or global_version if env.project_directory: project_version = try_get_project_version(env, preferred_version, adapter_type) @@ -344,9 +340,9 @@ def get_version(env: Environment, adapter_type: Optional[str] = None) -> Optiona installed_versions = dbtenv.versions.get_installed_versions(env, adapter_type=adapter_type) if installed_versions: max_installed_version = get_max_version(installed_versions) - return Version(adapter_type=adapter_type, version=max_installed_version.pypi_version, source_description="max installed version for current adapter") + return Version(adapter_type=adapter_type, version=max_installed_version.pypi_version, source_description="max installed stable version for current adapter") installable_versions = dbtenv.versions.get_installable_versions(env, adapter_type=adapter_type) max_installable_version = get_max_version(installable_versions) - max_installable_version.source_description = "max installable version for current adapter" + max_installable_version.source_description = "max installable stable version for current adapter" return max_installable_version diff --git a/dbtenv/which.py b/dbtenv/which.py index eab6dfe..bec704b 100644 --- a/dbtenv/which.py +++ b/dbtenv/which.py @@ -44,38 +44,27 @@ def add_args_parser(self, subparsers: argparse._SubParsersAction, parent_parsers def execute(self, args: Args) -> None: adapter_type = dbtenv.version.try_get_project_adapter_type(self.env.project_file) - if not adapter_type: - logger.info("Could not determine adapter, either not running inside dbt project or no default target is set for the current project in profiles.yml.") - return if args.dbt_version: version = Version(adapter_type=adapter_type, dbt_version=args.dbt_version) else: version = dbtenv.version.get_version(self.env, adapter_type=adapter_type) - logger.info(f"Using {version} ({version.source_description}).") - print(get_dbt(self.env, version).get_executable()) + if version: + logger.info(f"Using {version} ({version.source_description}).") + print(get_dbt(self.env, version).get_executable()) def get_dbt(env: Environment, version: Version) -> Dbt: error = DbtenvError(f"No dbt {version} executable found.") - pip_dbt = None pip_dbt = dbtenv.pip.PipDbt(env, version) - try: - pip_dbt.get_executable() # Raises an appropriate error if it's not installed. - if env.primary_installer == Installer.PIP: - return pip_dbt - except DbtenvError as pip_error: - if env.installer == Installer.PIP: - raise - else: - error = pip_error + pip_dbt.get_executable() # Raises an appropriate error if it's not installed. if pip_dbt and pip_dbt.is_installed(): return pip_dbt - - raise error + else: + raise error def try_get_dbt(env: Environment, version: Version) -> Optional[Dbt]: