def _get_profile_data(profile, profile_name, target_name): if 'outputs' not in profile: raise DbtProfileError( "outputs not specified in profile '{}'".format(profile_name)) outputs = profile['outputs'] if target_name not in outputs: outputs = '\n'.join(' - {}'.format(output) for output in outputs) msg = ("The profile '{}' does not have a target named '{}'. The " "valid target names for this profile are:\n{}".format( profile_name, target_name, outputs)) raise DbtProfileError(msg, result_type='invalid_target') profile_data = outputs[target_name] return profile_data
def render_schema_source(self, as_parsed): try: return deep_map(self._render_schema_source_data, as_parsed) except RecursionException: raise DbtProfileError( 'Cycle detected: schema.yml input has a reference to itself', project=as_parsed)
def validate(self): if self.credentials: self.credentials.validate() try: ProfileConfig(**self.to_profile_info(serialize_credentials=True)) except ValidationException as exc: raise DbtProfileError(str(exc))
def _credentials_from_profile(profile, profile_name, target_name): # credentials carry their 'type' in their actual type, not their # attributes. We do want this in order to pick our Credentials class. if 'type' not in profile: raise DbtProfileError( 'required field "type" not found in profile {} and target {}'. format(profile_name, target_name)) typename = profile.pop('type') try: credentials = create_credentials(typename, profile) except dbt.exceptions.RuntimeException as e: raise DbtProfileError( 'Credentials in profile "{}", target "{}" invalid: {}'.format( profile_name, target_name, str(e))) return credentials
def render_profile_data(self, as_parsed): """Render the chosen profile entry, as it was parsed.""" try: return deep_map(self._render_profile_data, as_parsed) except RecursionException: raise DbtProfileError( 'Cycle detected: Profile input has a reference to itself', project=as_parsed)
def validate(self): try: if self.credentials: self.credentials.to_dict(validate=True) ProfileConfig.from_dict( self.to_profile_info(serialize_credentials=True)) except ValidationError as exc: raise DbtProfileError(validator_error_message(exc)) from exc
def validate(self): try: if self.credentials: dct = self.credentials.to_dict(omit_none=True) self.credentials.validate(dct) dct = self.to_profile_info(serialize_credentials=True) ProfileConfig.validate(dct) except ValidationError as exc: raise DbtProfileError(validator_error_message(exc)) from exc
def _get_profile_data(profile: Dict[str, Any], profile_name: str, target_name: str) -> Dict[str, Any]: if 'outputs' not in profile: raise DbtProfileError( "outputs not specified in profile '{}'".format(profile_name)) outputs = profile['outputs'] if target_name not in outputs: outputs = '\n'.join(' - {}'.format(output) for output in outputs) msg = ("The profile '{}' does not have a target named '{}'. The " "valid target names for this profile are:\n{}".format( profile_name, target_name, outputs)) raise DbtProfileError(msg, result_type='invalid_target') profile_data = outputs[target_name] if not isinstance(profile_data, dict): msg = (f"output '{target_name}' of profile '{profile_name}' is " f"misconfigured in profiles.yml") raise DbtProfileError(msg, result_type='invalid_target') return profile_data
def _credentials_from_profile(profile, profile_name, target_name): # avoid an import cycle from dbt.adapters.factory import load_plugin # credentials carry their 'type' in their actual type, not their # attributes. We do want this in order to pick our Credentials class. if 'type' not in profile: raise DbtProfileError( 'required field "type" not found in profile {} and target {}'. format(profile_name, target_name)) typename = profile.pop('type') try: cls = load_plugin(typename) credentials = cls.from_dict(profile) except (RuntimeException, ValidationError) as e: msg = str(e) if isinstance(e, RuntimeException) else e.message raise DbtProfileError( 'Credentials in profile "{}", target "{}" invalid: {}'.format( profile_name, target_name, msg)) from e return credentials
def read_profile(profiles_dir: str) -> Dict[str, Any]: path = os.path.join(profiles_dir, 'profiles.yml') contents = None if os.path.isfile(path): try: contents = load_file_contents(path, strip=False) yaml_content = load_yaml_text(contents) if not yaml_content: msg = f'The profiles.yml file at {path} is empty' raise DbtProfileError( INVALID_PROFILE_MESSAGE.format(error_string=msg)) return yaml_content except ValidationException as e: msg = INVALID_PROFILE_MESSAGE.format(error_string=e) raise ValidationException(msg) from e return {}
def from_raw_profiles( cls, raw_profiles: Dict[str, Any], profile_name: str, renderer: ProfileRenderer, target_override: Optional[str] = None, threads_override: Optional[int] = None, ) -> 'Profile': """ :param raw_profiles: The profile data, from disk as yaml. :param profile_name: The profile name to use. :param renderer: The config renderer. :param target_override: The target to use, if provided on the command line. :param threads_override: The thread count to use, if provided on the command line. :raises DbtProjectError: If there is no profile name specified in the project or the command line arguments :raises DbtProfileError: If the profile is invalid or missing, or the target could not be found :returns: The new Profile object. """ if profile_name not in raw_profiles: raise DbtProjectError( "Could not find profile named '{}'".format(profile_name)) # First, we've already got our final decision on profile name, and we # don't render keys, so we can pluck that out raw_profile = raw_profiles[profile_name] if not raw_profile: msg = (f'Profile {profile_name} in profiles.yml is empty') raise DbtProfileError( INVALID_PROFILE_MESSAGE.format(error_string=msg)) user_cfg = raw_profiles.get('config') return cls.from_raw_profile_info( raw_profile=raw_profile, profile_name=profile_name, renderer=renderer, user_cfg=user_cfg, target_override=target_override, threads_override=threads_override, )
def render_profile( cls, raw_profile: Dict[str, Any], profile_name: str, target_override: Optional[str], renderer: ProfileRenderer, ) -> Tuple[str, Dict[str, Any]]: """This is a containment zone for the hateful way we're rendering profiles. """ # rendering profiles is a bit complex. Two constraints cause trouble: # 1) users should be able to use environment/cli variables to specify # the target in their profile. # 2) Missing environment/cli variables in profiles/targets that don't # end up getting selected should not cause errors. # so first we'll just render the target name, then we use that rendered # name to extract a profile that we can render. if target_override is not None: target_name = target_override elif 'target' in raw_profile: # render the target if it was parsed from yaml target_name = renderer.render_value(raw_profile['target']) else: target_name = 'default' logger.debug( "target not specified in profile '{}', using '{}'".format( profile_name, target_name)) raw_profile_data = cls._get_profile_data(raw_profile, profile_name, target_name) try: profile_data = renderer.render_data(raw_profile_data) except CompilationException as exc: raise DbtProfileError(str(exc)) from exc return target_name, profile_data