Repository: dbt-labs/dbt-core

Issue:
Write better error message for schema test list indices
## Issue
Typing `- column_name` instead of `column_name` in the tests section of a schema file results in this error message `TypeError: list indices must be integers or slices, not dict`. This error message should be more useful. @drewbanin suggests 
```
i think in this case, we can actually just check if the argument is a list instead of a dict and then show a better error
```

### Issue description
I ran into this issue after typing `- column_name` instead of `column_name` in the tests section of a scheme.yml file.

### Results
I got this error 

```
2019-02-27 12:11:45,010 (MainThread): Parsing test.dbt_utils.at_least_one_eng_active_subs_next_fy_earliest_subscription_engagement_date
2019-02-27 12:11:45,014 (MainThread): Flushing usage events
2019-02-27 12:11:45,014 (MainThread): Encountered an error:
2019-02-27 12:11:45,014 (MainThread): list indices must be integers or slices, not dict
2019-02-27 12:11:45,019 (MainThread): Traceback (most recent call last):
  File "/usr/local/Cellar/dbt/0.12.2/libexec/lib/python3.7/site-packages/dbt/main.py", line 77, in main
    results, succeeded = handle_and_check(args)
  File "/usr/local/Cellar/dbt/0.12.2/libexec/lib/python3.7/site-packages/dbt/main.py", line 151, in handle_and_check
    task, res = run_from_args(parsed)
  File "/usr/local/Cellar/dbt/0.12.2/libexec/lib/python3.7/site-packages/dbt/main.py", line 207, in run_from_args
    results = run_from_task(task, cfg, parsed)
  File "/usr/local/Cellar/dbt/0.12.2/libexec/lib/python3.7/site-packages/dbt/main.py", line 215, in run_from_task
    result = task.run()
  File "/usr/local/Cellar/dbt/0.12.2/libexec/lib/python3.7/site-packages/dbt/task/test.py", line 43, in run
    results = RunManager(self.config, query, TestRunner).run()
  File "/usr/local/Cellar/dbt/0.12.2/libexec/lib/python3.7/site-packages/dbt/runner.py", line 37, in __init__
    manifest, linker = self.compile(self.config)
  File "/usr/local/Cellar/dbt/0.12.2/libexec/lib/python3.7/site-packages/dbt/runner.py", line 216, in compile
    return compiler.compile()
  File "/usr/local/Cellar/dbt/0.12.2/libexec/lib/python3.7/site-packages/dbt/compilation.py", line 246, in compile
    manifest = dbt.loader.GraphLoader.load_all(self.config, all_projects)
  File "/usr/local/Cellar/dbt/0.12.2/libexec/lib/python3.7/site-packages/dbt/loader.py", line 140, in load_all
    return cls(project_config, all_projects).load()
  File "/usr/local/Cellar/dbt/0.12.2/libexec/lib/python3.7/site-packages/dbt/loader.py", line 122, in load
    self._load_schema_tests()
  File "/usr/local/Cellar/dbt/0.12.2/libexec/lib/python3.7/site-packages/dbt/loader.py", line 101, in _load_schema_tests
    relative_dirs=project.source_paths
  File "/usr/local/Cellar/dbt/0.12.2/libexec/lib/python3.7/site-packages/dbt/parser/schemas.py", line 459, in load_and_parse
    for result_type, node in v2_results:
  File "/usr/local/Cellar/dbt/0.12.2/libexec/lib/python3.7/site-packages/dbt/parser/schemas.py", line 381, in parse_v2_yml
    for node_type, node in iterator:
  File "/usr/local/Cellar/dbt/0.12.2/libexec/lib/python3.7/site-packages/dbt/parser/schemas.py", line 421, in parse_model
    test_args, root_dir, path)
  File "/usr/local/Cellar/dbt/0.12.2/libexec/lib/python3.7/site-packages/dbt/parser/schemas.py", line 226, in build_node
    original_file_path)
  File "/usr/local/Cellar/dbt/0.12.2/libexec/lib/python3.7/site-packages/dbt/parser/schemas.py", line 159, in build_unparsed_node
    test_args)
  File "/usr/local/Cellar/dbt/0.12.2/libexec/lib/python3.7/site-packages/dbt/parser/schemas.py", line 75, in build_test_raw_sql
    kwargs = [as_kwarg(key, test_args[key]) for key in sorted(test_args)]
  File "/usr/local/Cellar/dbt/0.12.2/libexec/lib/python3.7/site-packages/dbt/parser/schemas.py", line 75, in <listcomp>
    kwargs = [as_kwarg(key, test_args[key]) for key in sorted(test_args)]
TypeError: list indices must be integers or slices, not dict
```

### System information
The output of `dbt --version`:
```
installed version: 0.12.2
   latest version: 0.12.2

Up to date!
```

The operating system you're running on:
```
Mac OS X 10.14.3
```
The python version you're using (probably the output of `python --version`)
```
Python 3.6.8 :: Anaconda, Inc.
```

### Steps to reproduce
I had code like
```
- name: eng_active_subs
    tests:
      - unique:
          - column_name: "concat(billing_id, fy)"
```
When running dbt test or dbt compile, this failed with the above error. Removing the `-` in front of column_name fixed it.




Discussion:
thanks for the report @tjengel - prioritized for our Wilt Chamberlain release (should be 0.14.0)
As of `0.13.0`, this actually works like it should, I think:
```
$ dbt test
Running with dbt=0.13.0
in models/schema.yml: test arguments must be dict, got <class 'list'> (value [{'column_name': 'id'}])
Found 1 models, 0 tests, 0 archives, 0 analyses, 94 macros, 0 operations, 0 seed files, 0 sources
WARNING: Nothing to do. Try checking your model configs and model specification args
```

The message comes from [here](https://github.com/fishtown-analytics/dbt/blob/da4c135e23b9f12607811745cb184ae81d5ebd26/core/dbt/parser/schemas.py#L158-L163).

I find that error reasonably informative. I'm open to changing it if we want to detect the exact case where a user passed a list there, though we should maybe also handle some other cases there (like null).

@beckjake hmm, this message is definitely a lot better than a stack trace! What would the error message look like if `None` or a string was provided here? There might be some merit to formatting this warning a little better, but looks like we're already pretty close!
`test_args=None`:
`"test arguments must be dict, got <class 'NoneType'> (value None)"`

`test_args='hello'`:
`"test arguments must be dict, got <class 'str'> (value hello)"`
Ok, I think that's great! Let's just format this a little better then. 

Instead of
```
$ dbt test
Running with dbt=0.13.0
in models/schema.yml: test arguments must be dict, got <class 'str'> (value abc)
```

Let's aim for:
```
$ dbt test
Running with dbt=0.13.0
Compilation warning: Invalid test config given in models/schema.yml at line 17:
  Test arguments must be dict, got <class 'str'> (value abc)
```

I don't know if we are able to capture a line number here... if not, just leave that part out. This format is more in line with other compiler warning test output, like if you supply a `dict` instead of a `list` as an arg to `tests:`.

Resolving patch:
diff --git a/core/dbt/parser/schemas.py b/core/dbt/parser/schemas.py
--- a/core/dbt/parser/schemas.py
+++ b/core/dbt/parser/schemas.py
@@ -232,7 +232,8 @@ def _parse_column(self, target, column, package_name, root_dir, path,
                 )
             except dbt.exceptions.CompilationException as exc:
                 dbt.exceptions.warn_or_error(
-                    'in {}: {}'.format(path, exc.msg), None
+                    'Compilation warning: Invalid test config given in {}:'
+                    '\n\t{}'.format(path, exc.msg), None
                 )
                 continue
 
@@ -342,7 +343,8 @@ def parse_models_entry(self, model_dict, path, package_name, root_dir):
                                             root_dir, path)
             except dbt.exceptions.CompilationException as exc:
                 dbt.exceptions.warn_or_error(
-                    'in {}: {}'.format(path, exc.msg), test
+                    'Compilation warning: Invalid test config given in {}:'
+                    '\n\t{}'.format(path, exc.msg), None
                 )
                 continue
             yield 'test', node


Test patch: