Skip to content

Commit

Permalink
add --no-static-parser flag
Browse files Browse the repository at this point in the history
  • Loading branch information
Nathaniel May committed Sep 28, 2021
1 parent b893e7e commit 6a8b9a5
Show file tree
Hide file tree
Showing 7 changed files with 113 additions and 20 deletions.
1 change: 1 addition & 0 deletions core/dbt/contracts/project.py
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,7 @@ class UserConfig(ExtensibleDbtClassMixin, Replaceable, UserConfigContract):
version_check: Optional[bool] = None
fail_fast: Optional[bool] = None
use_experimental_parser: Optional[bool] = None
static_parser: Optional[bool] = None


@dataclass
Expand Down
8 changes: 6 additions & 2 deletions core/dbt/flags.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@

# Global CLI commands
USE_EXPERIMENTAL_PARSER = None
STATIC_PARSER = None
WARN_ERROR = None
WRITE_JSON = None
PARTIAL_PARSE = None
Expand All @@ -37,6 +38,7 @@
# Environment variables use the pattern 'DBT_{flag name}', like DBT_PROFILES_DIR
flag_defaults = {
"USE_EXPERIMENTAL_PARSER": False,
"STATIC_PARSER": True,
"WARN_ERROR": False,
"WRITE_JSON": True,
"PARTIAL_PARSE": False,
Expand Down Expand Up @@ -93,8 +95,8 @@ def _get_context():

def set_from_args(args, user_config):
global STRICT_MODE, FULL_REFRESH, WARN_ERROR, \
USE_EXPERIMENTAL_PARSER, WRITE_JSON, PARTIAL_PARSE, USE_COLORS, \
STORE_FAILURES, PROFILES_DIR, DEBUG, LOG_FORMAT, GREEDY, \
USE_EXPERIMENTAL_PARSER, STATIC_PARSER, WRITE_JSON, PARTIAL_PARSE, \
USE_COLORS, STORE_FAILURES, PROFILES_DIR, DEBUG, LOG_FORMAT, GREEDY, \
VERSION_CHECK, FAIL_FAST, SEND_ANONYMOUS_USAGE_STATS, PRINTER_WIDTH

STRICT_MODE = False # backwards compatibility
Expand All @@ -105,6 +107,7 @@ def set_from_args(args, user_config):

# global cli flags with env var and user_config alternatives
USE_EXPERIMENTAL_PARSER = get_flag_value('USE_EXPERIMENTAL_PARSER', args, user_config)
STATIC_PARSER = get_flag_value('STATIC_PARSER', args, user_config)
WARN_ERROR = get_flag_value('WARN_ERROR', args, user_config)
WRITE_JSON = get_flag_value('WRITE_JSON', args, user_config)
PARTIAL_PARSE = get_flag_value('PARTIAL_PARSE', args, user_config)
Expand Down Expand Up @@ -147,6 +150,7 @@ def get_flag_value(flag, args, user_config):
def get_flag_dict():
return {
"use_experimental_parser": USE_EXPERIMENTAL_PARSER,
"static_parser": STATIC_PARSER,
"warn_error": WARN_ERROR,
"write_json": WRITE_JSON,
"partial_parse": PARTIAL_PARSE,
Expand Down
18 changes: 15 additions & 3 deletions core/dbt/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -1066,14 +1066,26 @@ def parse_args(args, cls=DBTArgumentParser):
help=argparse.SUPPRESS,
)

# if set, will use the tree-sitter-jinja2 parser and extractor instead of
# jinja rendering when possible.
# if set, will use the latest features from the static parser instead of
# the stable static parser.
p.add_argument(
'--use-experimental-parser',
action='store_true',
default=None,
help='''
Uses an experimental parser to extract jinja values.
Enables experimental parsing features.
'''
)

# if set, will disable the use of the stable static parser and instead
# always rely on jinja rendering.
p.add_argument(
'--no-static-parser',
default=None,
dest='static_parser',
action='store_false',
help='''
Disables the static parser.
'''
)

Expand Down
2 changes: 1 addition & 1 deletion core/dbt/parser/manifest.py
Original file line number Diff line number Diff line change
Expand Up @@ -577,7 +577,7 @@ def read_manifest_for_partial_parse(self) -> Optional[Manifest]:
def build_perf_info(self):
mli = ManifestLoaderInfo(
is_partial_parse_enabled=flags.PARTIAL_PARSE,
is_static_analysis_enabled=flags.USE_EXPERIMENTAL_PARSER
is_static_analysis_enabled=flags.STATIC_PARSER
)
for project in self.all_projects.values():
project_info = ProjectLoaderInfo(
Expand Down
11 changes: 9 additions & 2 deletions core/dbt/parser/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,12 @@ def get_compiled_path(cls, block: FileBlock):
def render_update(
self, node: ParsedModelNode, config: ContextConfig
) -> None:
if not flags.STATIC_PARSER:
# jinja rendering
super().render_update(node, config)
logger.debug(f"1605: jinja rendering because of STATIC_PARSER flag. file: {node.path}")
return

# only sample on normal runs, not when the experimental parser flag is on.
sample: bool = False
if not flags.USE_EXPERIMENTAL_PARSER:
Expand All @@ -47,11 +53,12 @@ def render_update(

# sample the experimental parser during a normal run
if sample:
logger.debug(f"1610: conducting experimental parser sample on {node.path}")
experimental_sample = self.run_experimental_parser(node)
# use the experimental parser exclusively if the flag is on
if flags.USE_EXPERIMENTAL_PARSER:
statically_parsed = self.run_experimental_parser(node)
# run the stable static parser by default
# run the stable static parser unless it is explicitly turned off
else:
statically_parsed = self.run_static_parser(node)

Expand Down Expand Up @@ -147,7 +154,7 @@ def run_experimental_parser(
# the code at the beginning of the line change the tests in
# test/integration/072_experimental_parser_tests/test_all_experimental_parser.py
logger.debug(
f"1601: parser fallback to jinja because of macro override for {node.path}"
f"1601: detected macro override of ref/source/config in the scope of {node.path}"
)
return "has_banned_macro"

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,50 @@ def schema(self):
def models(self):
return "basic"

@use_profile('postgres')
def test_postgres_env_use_experimental_parser(self):
def cleanup():
del os.environ['DBT_USE_EXPERIMENTAL_PARSER']

self.addCleanup(cleanup)
os.environ['DBT_USE_EXPERIMENTAL_PARSER'] = 'true'
_, log_output = self.run_dbt_and_capture(['--debug', 'parse'])

# successful stable static parsing
self.assertFalse("1699: " in log_output)
# successful experimental static parsing
self.assertTrue("1698: " in log_output)
# experimental parser failed
self.assertFalse("1604: " in log_output)
# static parser failed
self.assertFalse("1603: " in log_output)
# jinja rendering
self.assertFalse("1602: " in log_output)

@use_profile('postgres')
def test_postgres_env_static_parser(self):
def cleanup():
del os.environ['DBT_STATIC_PARSER']

self.addCleanup(cleanup)
os.environ['DBT_STATIC_PARSER'] = 'false'
_, log_output = self.run_dbt_and_capture(['--debug', 'parse'])

print(log_output)

# jinja rendering because of --no-static-parser
self.assertTrue("1605: " in log_output)
# successful stable static parsing
self.assertFalse("1699: " in log_output)
# successful experimental static parsing
self.assertFalse("1698: " in log_output)
# experimental parser failed
self.assertFalse("1604: " in log_output)
# static parser failed
self.assertFalse("1603: " in log_output)
# fallback jinja rendering
self.assertFalse("1602: " in log_output)

# test that the experimental parser extracts some basic ref, source, and config calls.
@use_profile('postgres')
def test_postgres_experimental_parser_basic(self):
Expand All @@ -34,18 +78,11 @@ def test_postgres_experimental_parser_basic(self):
self.assertEqual(node.config._extra, {'x': True})
self.assertEqual(node.config.tags, ['hello', 'world'])

@use_profile('postgres')
def test_postgres_env_experimental_parser(self):
os.environ['DBT_USE_EXPERIMENTAL_PARSER'] = 'true'
results = self.run_dbt(['parse'])

# test that the static parser extracts some basic ref, source, and config calls by default
# without the experimental flag
# without the experimental flag and without rendering jinja
@use_profile('postgres')
def test_postgres_static_parser_basic(self):
_, log_output = self.run_dbt_and_capture(['--debug', 'parse'])

print(log_output)

# successful stable static parsing
self.assertTrue("1699: " in log_output)
Expand All @@ -55,6 +92,8 @@ def test_postgres_static_parser_basic(self):
self.assertFalse("1604: " in log_output)
# static parser failed
self.assertFalse("1603: " in log_output)
# jinja rendering
self.assertFalse("1602: " in log_output)

manifest = get_manifest()
node = manifest.nodes['model.test.model_a']
Expand All @@ -63,6 +102,24 @@ def test_postgres_static_parser_basic(self):
self.assertEqual(node.config._extra, {'x': True})
self.assertEqual(node.config.tags, ['hello', 'world'])

# test that the static parser doesn't run when the flag is set
@use_profile('postgres')
def test_postgres_static_parser_is_disabled(self):
_, log_output = self.run_dbt_and_capture(['--debug', '--no-static-parser', 'parse'])

# jinja rendering because of --no-static-parser
self.assertTrue("1605: " in log_output)
# successful stable static parsing
self.assertFalse("1699: " in log_output)
# successful experimental static parsing
self.assertFalse("1698: " in log_output)
# experimental parser failed
self.assertFalse("1604: " in log_output)
# static parser failed
self.assertFalse("1603: " in log_output)
# fallback jinja rendering
self.assertFalse("1602: " in log_output)


class TestRefOverrideExperimentalParser(DBTIntegrationTest):
@property
Expand Down Expand Up @@ -116,8 +173,6 @@ def project_config(self):
@use_profile('postgres')
def test_postgres_experimental_parser_source_override(self):
_, log_output = self.run_dbt_and_capture(['--debug', '--use-experimental-parser', 'parse'])

print(log_output)

# successful experimental static parsing
self.assertFalse("1698: " in log_output)
Expand Down Expand Up @@ -148,8 +203,6 @@ def project_config(self):
@use_profile('postgres')
def test_postgres_experimental_parser_config_override(self):
_, log_output = self.run_dbt_and_capture(['--debug', '--use-experimental-parser', 'parse'])

print(log_output)

# successful experimental static parsing
self.assertFalse("1698: " in log_output)
Expand Down
16 changes: 16 additions & 0 deletions test/unit/test_flags.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,22 @@ def test__flags(self):
flags.USE_EXPERIMENTAL_PARSER = False
self.user_config.use_experimental_parser = None

# static_parser
self.user_config.static_parser = False
flags.set_from_args(self.args, self.user_config)
self.assertEqual(flags.STATIC_PARSER, False)
os.environ['DBT_STATIC_PARSER'] = 'true'
flags.set_from_args(self.args, self.user_config)
self.assertEqual(flags.STATIC_PARSER, True)
setattr(self.args, 'static_parser', False)
flags.set_from_args(self.args, self.user_config)
self.assertEqual(flags.STATIC_PARSER, False)
# cleanup
os.environ.pop('DBT_STATIC_PARSER')
delattr(self.args, 'static_parser')
flags.STATIC_PARSER = True
self.user_config.static_parser = None

# warn_error
self.user_config.warn_error = False
flags.set_from_args(self.args, self.user_config)
Expand Down

0 comments on commit 6a8b9a5

Please sign in to comment.