Example #1
0
 def setUp(self):
     self.model = ParsedNode(alias='model_one',
                             name='model_one',
                             schema='analytics',
                             resource_type='model',
                             unique_id='model.root.model_one',
                             fqn=['root', 'model_one'],
                             empty=False,
                             package_name='root',
                             original_file_path='model_one.sql',
                             root_path='/usr/src/app',
                             refs=[],
                             depends_on={
                                 'nodes': [],
                                 'macros': []
                             },
                             config={
                                 'enabled': True,
                                 'materialized': 'view',
                                 'post-hook': [],
                                 'pre-hook': [],
                                 'vars': {},
                                 'quoting': {},
                                 'column_types': {},
                                 'tags': [],
                             },
                             tags=[],
                             path='model_one.sql',
                             raw_sql='',
                             description='',
                             columns={})
     self.context = mock.MagicMock()
Example #2
0
    def as_node_list(self, selected_nodes, ephemeral_only=False):
        dependency_list = self.linker.as_dependency_list(
            selected_nodes, ephemeral_only=ephemeral_only)

        concurrent_dependency_list = []
        for level in dependency_list:
            node_level = [
                ParsedNode(**self.linker.get_node(node)) for node in level
            ]
            concurrent_dependency_list.append(node_level)

        return concurrent_dependency_list
Example #3
0
    def parse_node(self,
                   node,
                   node_path,
                   package_project_config,
                   tags=None,
                   fqn_extra=None,
                   fqn=None,
                   agate_table=None,
                   archive_config=None,
                   column_name=None):
        """Parse a node, given an UnparsedNode and any other required information.

        agate_table should be set if the node came from a seed file.
        archive_config should be set if the node is an Archive node.
        column_name should be set if the node is a Test node associated with a
        particular column.
        """
        logger.debug("Parsing {}".format(node_path))

        tags = coalesce(tags, [])
        fqn_extra = coalesce(fqn_extra, [])

        if fqn is None:
            fqn = self.get_fqn(node.path, package_project_config, fqn_extra)

        config = SourceConfig(self.root_project_config, package_project_config,
                              fqn, node.resource_type)

        parsed_dict = self._build_intermediate_node_dict(
            config, node.serialize(), node_path, config, tags, fqn,
            agate_table, archive_config, column_name)
        parsed_node = ParsedNode(**parsed_dict)

        self._render_with_context(parsed_node, config)
        self._update_parsed_node_info(parsed_node, config)

        parsed_node.validate()

        return parsed_node
Example #4
0
    def parse_node(self, node, node_path, package_project_config, tags=None,
                   fqn_extra=None, fqn=None, agate_table=None,
                   archive_config=None, column_name=None):
        """Parse a node, given an UnparsedNode and any other required information.

        agate_table should be set if the node came from a seed file.
        archive_config should be set if the node is an Archive node.
        column_name should be set if the node is a Test node associated with a
        particular column.
        """
        logger.debug("Parsing {}".format(node_path))

        tags = coalesce(tags, [])
        fqn_extra = coalesce(fqn_extra, [])

        if fqn is None:
            fqn = self.get_fqn(node.path, package_project_config, fqn_extra)

        config = SourceConfig(
            self.root_project_config,
            package_project_config,
            fqn,
            node.resource_type)

        parsed_dict = self._build_intermediate_node_dict(
            config, node.serialize(), node_path, config, tags, fqn,
            agate_table, archive_config, column_name
        )
        parsed_node = ParsedNode(**parsed_dict)

        self._render_with_context(parsed_node, config)
        self._update_parsed_node_info(parsed_node, config)

        parsed_node.validate()

        return parsed_node
Example #5
0
 def test_get_resource_fqns(self):
     nodes = copy.copy(self.nested_nodes)
     nodes['seed.root.seed'] = ParsedNode(name='seed',
                                          database='dbt',
                                          schema='analytics',
                                          alias='seed',
                                          resource_type='seed',
                                          unique_id='seed.root.seed',
                                          fqn=['root', 'seed'],
                                          empty=False,
                                          package_name='root',
                                          refs=[['events']],
                                          sources=[],
                                          depends_on={
                                              'nodes': [],
                                              'macros': []
                                          },
                                          config=self.model_config,
                                          tags=[],
                                          path='seed.csv',
                                          original_file_path='seed.csv',
                                          root_path='',
                                          raw_sql='-- csv --')
     manifest = Manifest(nodes=nodes,
                         macros={},
                         docs={},
                         generated_at=timestring(),
                         disabled=[])
     expect = {
         'models':
         frozenset([
             ('snowplow', 'events'),
             ('root', 'events'),
             ('root', 'dep'),
             ('root', 'nested'),
             ('root', 'sibling'),
             ('root', 'multi'),
         ]),
         'seeds':
         frozenset([('root', 'seed')]),
     }
     resource_fqns = manifest.get_resource_fqns()
     self.assertEqual(resource_fqns, expect)
Example #6
0
    def setUp(self):
        dbt.flags.STRICT_MODE = True

        self.maxDiff = None

        self.model_config = {
            'enabled': True,
            'materialized': 'view',
            'post-hook': [],
            'pre-hook': [],
            'vars': {},
            'quoting': {},
            'column_types': {},
        }

        self.nested_nodes = {
            'model.snowplow.events': ParsedNode(
                name='events',
                schema='analytics',
                alias='events',
                resource_type='model',
                unique_id='model.snowplow.events',
                fqn=['snowplow', 'events'],
                empty=False,
                package_name='snowplow',
                refs=[],
                depends_on={
                    'nodes': [],
                    'macros': []
                },
                config=self.model_config,
                tags=[],
                path='events.sql',
                original_file_path='events.sql',
                root_path='',
                raw_sql='does not matter'
            ),
            'model.root.events': ParsedNode(
                name='events',
                schema='analytics',
                alias='events',
                resource_type='model',
                unique_id='model.root.events',
                fqn=['root', 'events'],
                empty=False,
                package_name='root',
                refs=[],
                depends_on={
                    'nodes': [],
                    'macros': []
                },
                config=self.model_config,
                tags=[],
                path='events.sql',
                original_file_path='events.sql',
                root_path='',
                raw_sql='does not matter'
            ),
            'model.root.dep': ParsedNode(
                name='dep',
                schema='analytics',
                alias='dep',
                resource_type='model',
                unique_id='model.root.dep',
                fqn=['root', 'dep'],
                empty=False,
                package_name='root',
                refs=[['events']],
                depends_on={
                    'nodes': ['model.root.events'],
                    'macros': []
                },
                config=self.model_config,
                tags=[],
                path='multi.sql',
                original_file_path='multi.sql',
                root_path='',
                raw_sql='does not matter'
            ),
            'model.root.nested': ParsedNode(
                name='nested',
                schema='analytics',
                alias='nested',
                resource_type='model',
                unique_id='model.root.nested',
                fqn=['root', 'nested'],
                empty=False,
                package_name='root',
                refs=[['events']],
                depends_on={
                    'nodes': ['model.root.dep'],
                    'macros': []
                },
                config=self.model_config,
                tags=[],
                path='multi.sql',
                original_file_path='multi.sql',
                root_path='',
                raw_sql='does not matter'
            ),
            'model.root.sibling': ParsedNode(
                name='sibling',
                schema='analytics',
                alias='sibling',
                resource_type='model',
                unique_id='model.root.sibling',
                fqn=['root', 'sibling'],
                empty=False,
                package_name='root',
                refs=[['events']],
                depends_on={
                    'nodes': ['model.root.events'],
                    'macros': []
                },
                config=self.model_config,
                tags=[],
                path='multi.sql',
                original_file_path='multi.sql',
                root_path='',
                raw_sql='does not matter'
            ),
            'model.root.multi': ParsedNode(
                name='multi',
                schema='analytics',
                alias='multi',
                resource_type='model',
                unique_id='model.root.multi',
                fqn=['root', 'multi'],
                empty=False,
                package_name='root',
                refs=[['events']],
                depends_on={
                    'nodes': ['model.root.nested', 'model.root.sibling'],
                    'macros': []
                },
                config=self.model_config,
                tags=[],
                path='multi.sql',
                original_file_path='multi.sql',
                root_path='',
                raw_sql='does not matter'
            ),
        }
Example #7
0
    def parse_node(cls,
                   node,
                   node_path,
                   root_project_config,
                   package_project_config,
                   all_projects,
                   tags=None,
                   fqn_extra=None,
                   fqn=None,
                   macros=None,
                   agate_table=None,
                   archive_config=None):
        """Parse a node, given an UnparsedNode and any other required information.

        agate_table should be set if the node came from a seed file.
        archive_config should be set if the node is an Archive node.
        """
        logger.debug("Parsing {}".format(node_path))

        node = node.serialize()

        if agate_table is not None:
            node['agate_table'] = agate_table
        tags = coalesce(tags, [])
        fqn_extra = coalesce(fqn_extra, [])
        macros = coalesce(macros, {})

        node.update({
            'refs': [],
            'depends_on': {
                'nodes': [],
                'macros': [],
            }
        })

        if fqn is None:
            fqn = cls.get_fqn(node.get('path'), package_project_config,
                              fqn_extra)

        config = dbt.model.SourceConfig(root_project_config,
                                        package_project_config, fqn,
                                        node['resource_type'])

        node['unique_id'] = node_path
        node['empty'] = ('raw_sql' in node
                         and len(node['raw_sql'].strip()) == 0)
        node['fqn'] = fqn
        node['tags'] = tags
        node['config_reference'] = config

        # Set this temporarily. Not the full config yet (as config() hasn't
        # been called from jinja yet). But the Var() call below needs info
        # about project level configs b/c they might contain refs.
        # TODO: Restructure this?
        config_dict = coalesce(archive_config, {})
        config_dict.update(config.config)
        node['config'] = config_dict

        # Set this temporarily so get_rendered() has access to a schema & alias
        profile = dbt.utils.get_profile_from_project(root_project_config)
        default_schema = profile.get('schema', 'public')
        node['schema'] = default_schema
        default_alias = node.get('name')
        node['alias'] = default_alias

        context = dbt.context.parser.generate(node, root_project_config,
                                              {"macros": macros})

        dbt.clients.jinja.get_rendered(node.get('raw_sql'),
                                       context,
                                       node,
                                       capture_macros=True)

        # Clean up any open conns opened by adapter functions that hit the db
        db_wrapper = context['adapter']
        adapter = db_wrapper.adapter
        profile = db_wrapper.profile
        adapter.release_connection(profile, node.get('name'))

        # Special macro defined in the global project
        schema_override = config.config.get('schema')
        get_schema = context.get('generate_schema_name',
                                 lambda x: default_schema)
        node['schema'] = get_schema(schema_override)
        node['alias'] = config.config.get('alias', default_alias)

        # Overwrite node config
        config_dict = node.get('config', {})
        config_dict.update(config.config)
        node['config'] = config_dict

        for hook_type in dbt.hooks.ModelHookType.Both:
            node['config'][hook_type] = dbt.hooks.get_hooks(node, hook_type)

        del node['config_reference']

        return ParsedNode(**node)
Example #8
0
    def parse_node(cls,
                   node,
                   node_path,
                   root_project_config,
                   package_project_config,
                   all_projects,
                   tags=None,
                   fqn_extra=None,
                   fqn=None,
                   macros=None,
                   agate_table=None,
                   archive_config=None,
                   column_name=None):
        """Parse a node, given an UnparsedNode and any other required information.

        agate_table should be set if the node came from a seed file.
        archive_config should be set if the node is an Archive node.
        column_name should be set if the node is a Test node associated with a
        particular column.
        """
        logger.debug("Parsing {}".format(node_path))

        node = node.serialize()

        if agate_table is not None:
            node['agate_table'] = agate_table
        tags = coalesce(tags, [])
        fqn_extra = coalesce(fqn_extra, [])
        macros = coalesce(macros, {})

        node.update({
            'refs': [],
            'depends_on': {
                'nodes': [],
                'macros': [],
            }
        })

        if fqn is None:
            fqn = cls.get_fqn(node.get('path'), package_project_config,
                              fqn_extra)

        config = dbt.model.SourceConfig(root_project_config,
                                        package_project_config, fqn,
                                        node['resource_type'])

        node['unique_id'] = node_path
        node['empty'] = ('raw_sql' in node
                         and len(node['raw_sql'].strip()) == 0)
        node['fqn'] = fqn
        node['tags'] = tags

        # Set this temporarily. Not the full config yet (as config() hasn't
        # been called from jinja yet). But the Var() call below needs info
        # about project level configs b/c they might contain refs.
        # TODO: Restructure this?
        config_dict = coalesce(archive_config, {})
        config_dict.update(config.config)
        node['config'] = config_dict

        # Set this temporarily so get_rendered() has access to a schema & alias
        default_schema = getattr(root_project_config.credentials, 'schema',
                                 'public')
        node['schema'] = default_schema
        default_alias = node.get('name')
        node['alias'] = default_alias

        # if there's a column, it should end up part of the ParsedNode
        if column_name is not None:
            node['column_name'] = column_name

        # make a manifest with just the macros to get the context
        manifest = Manifest(macros=macros,
                            nodes={},
                            docs={},
                            generated_at=dbt.utils.timestring())

        parsed_node = ParsedNode(**node)
        context = dbt.context.parser.generate(parsed_node, root_project_config,
                                              manifest, config)

        dbt.clients.jinja.get_rendered(parsed_node.raw_sql,
                                       context,
                                       parsed_node.to_shallow_dict(),
                                       capture_macros=True)

        # Clean up any open conns opened by adapter functions that hit the db
        db_wrapper = context['adapter']
        adapter = db_wrapper.adapter
        runtime_config = db_wrapper.config
        adapter.release_connection(parsed_node.name)

        # Special macro defined in the global project
        schema_override = config.config.get('schema')
        get_schema = context.get('generate_schema_name',
                                 lambda x: default_schema)
        parsed_node.schema = get_schema(schema_override)
        parsed_node.alias = config.config.get('alias', default_alias)

        # Overwrite node config
        config_dict = parsed_node.get('config', {})
        config_dict.update(config.config)
        parsed_node.config = config_dict

        for hook_type in dbt.hooks.ModelHookType.Both:
            parsed_node.config[hook_type] = dbt.hooks.get_hooks(
                parsed_node, hook_type)

        parsed_node.validate()

        return parsed_node