Skip to content

Commit

Permalink
Merge pull request #7 from Anaconda-Platform/suggest-unknown-fields
Browse files Browse the repository at this point in the history
Create nonfatal suggestions complaining about unknown fields in anaco…
  • Loading branch information
havocp committed Mar 3, 2017
2 parents eb8fdd0 + f8750ce commit 0c50402
Show file tree
Hide file tree
Showing 10 changed files with 127 additions and 77 deletions.
5 changes: 2 additions & 3 deletions anaconda_project/commands/test/test_command_commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
# ----------------------------------------------------------------------------
from __future__ import absolute_import, print_function

import os
import pytest

from anaconda_project.commands.command_commands import main
Expand Down Expand Up @@ -315,8 +314,8 @@ def check_problem_add_cmd(dirname):

out, err = capsys.readouterr()
assert '' == out
assert (("%s: command 'test' has multiple commands in it, 'notebook' can't go with 'unix'\n" % os.path.join(
dirname, DEFAULT_PROJECT_FILENAME)) + "Unable to add the command.\n") == err
assert (("%s: command 'test' has multiple commands in it, 'notebook' can't go with 'unix'\n" %
DEFAULT_PROJECT_FILENAME) + "Unable to add the command.\n") == err

with_directory_contents_completing_project_file(
{DEFAULT_PROJECT_FILENAME: ("commands:\n test:\n unix: foo\n")}, check_problem_add_cmd)
Expand Down
4 changes: 2 additions & 2 deletions anaconda_project/commands/test/test_environment_commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -232,8 +232,8 @@ def check(dirname):

out, err = capsys.readouterr()
assert '' == out
assert (("%s: env_spec 'bar' for command 'foo' does not appear in the env_specs section\n" % os.path.join(
dirname, DEFAULT_PROJECT_FILENAME)) + "Unable to load the project.\n") == err
assert (("%s: env_spec 'bar' for command 'foo' does not appear in the env_specs section\n" %
DEFAULT_PROJECT_FILENAME) + "Unable to load the project.\n") == err

with_directory_contents_completing_project_file(
{
Expand Down
2 changes: 1 addition & 1 deletion anaconda_project/commands/test/test_prepare.py
Original file line number Diff line number Diff line change
Expand Up @@ -578,7 +578,7 @@ def mock_console_input(prompt, encrypted):

assert out == ""
assert err == ("%s: env_specs should be a dictionary from environment name to environment attributes, not 42\n"
"Unable to load the project.\n") % os.path.join(dirname, "anaconda-project.yml")
"Unable to load the project.\n") % DEFAULT_PROJECT_FILENAME

with_directory_contents_completing_project_file(
{DEFAULT_PROJECT_FILENAME: """
Expand Down
8 changes: 3 additions & 5 deletions anaconda_project/commands/test/test_project_load.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
# ----------------------------------------------------------------------------
from __future__ import absolute_import, print_function

import os
import sys

from anaconda_project.project import Project
Expand Down Expand Up @@ -53,7 +52,7 @@ def mock_isatty_true():

out, err = capsys.readouterr()
assert out == ("%s: The env_specs section is empty.\nAdd an environment spec to anaconda-project.yml? " %
os.path.join(dirname, DEFAULT_PROJECT_FILENAME))
DEFAULT_PROJECT_FILENAME)
assert err == ""

with_directory_contents({DEFAULT_PROJECT_FILENAME: "name: foo"}, check)
Expand All @@ -73,12 +72,11 @@ def mock_isatty_true():
_monkeypatch_input(monkeypatch, ["n"])

project = load_project(dirname)
assert project.problems == ["%s: The env_specs section is empty." % os.path.join(dirname,
DEFAULT_PROJECT_FILENAME)]
assert project.problems == ["%s: The env_specs section is empty." % DEFAULT_PROJECT_FILENAME]

out, err = capsys.readouterr()
assert out == ("%s: The env_specs section is empty.\nAdd an environment spec to anaconda-project.yml? " %
os.path.join(dirname, DEFAULT_PROJECT_FILENAME))
DEFAULT_PROJECT_FILENAME)
assert err == ""

with_directory_contents({DEFAULT_PROJECT_FILENAME: "name: foo"}, check)
Original file line number Diff line number Diff line change
Expand Up @@ -263,8 +263,8 @@ def test_provide_wrong_form(monkeypatch):
def provide_download(dirname):
project = project_no_dedicated_env(dirname)
prepare_without_interaction(project, environ=minimal_environ(PROJECT_DIR=dirname))
assert ("%s: 'downloads:' section should be a dictionary, found ['http://localhost/data.csv']" % os.path.join(
dirname, DEFAULT_PROJECT_FILENAME)) in project.problems
assert ("%s: 'downloads:' section should be a dictionary, found ['http://localhost/data.csv']" %
DEFAULT_PROJECT_FILENAME) in project.problems

with_directory_contents_completing_project_file({DEFAULT_PROJECT_FILENAME: ERR_DATAFILE_CONTENT}, provide_download)

Expand Down
21 changes: 20 additions & 1 deletion anaconda_project/project.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ def __init__(self,
if filename is None:
self.text = text
else:
self.text = "%s: %s" % (filename, text)
self.text = "%s: %s" % (os.path.basename(filename), text)
self.fix_prompt = fix_prompt
self.fix_function = fix_function
self.no_fix_function = no_fix_function
Expand Down Expand Up @@ -102,6 +102,14 @@ def _file_problem(problems, yaml_file, text):
problems.append(ProjectProblem(text=text, filename=yaml_file.filename))


def _unknown_field_suggestions(project_file, problems, yaml_dict, known_fields):
for key in yaml_dict.keys():
if key not in known_fields:
problems.append(ProjectProblem(text="Unknown field name '%s'" % (key),
filename=project_file.filename,
only_a_suggestion=True))


class _ConfigCache(object):
def __init__(self, directory_path, registry):
self.directory_path = directory_path
Expand Down Expand Up @@ -147,6 +155,10 @@ def update(self, project_file, conda_meta_file):
column_number=project_file.corrupted_maybe_column))

if project_exists and not (project_file.corrupted or conda_meta_file.corrupted):
_unknown_field_suggestions(project_file, problems, project_file.root,
('name', 'description', 'icon', 'variables', 'downloads', 'services',
'env_specs', 'commands', 'packages', 'channels', 'skip_imports'))

self._update_name(problems, project_file, conda_meta_file)
self._update_description(problems, project_file)
self._update_icon(problems, project_file, conda_meta_file)
Expand Down Expand Up @@ -426,6 +438,9 @@ def _parse_packages(parent_dict):

if first_env_spec_name is None:
first_env_spec_name = name

_unknown_field_suggestions(project_file, problems, attrs, ('packages', 'channels', 'description',
'inherit_from'))
else:
_file_problem(problems, project_file,
"env_specs should be a dictionary from environment name to environment attributes, not %r" %
Expand Down Expand Up @@ -583,6 +598,10 @@ def _update_commands(self, problems, project_file, conda_meta_file, requirements
failed = True
continue

_unknown_field_suggestions(project_file, problems, attrs,
('description', 'env_spec', 'supports_http_options', 'bokeh_app', 'notebook',
'unix', 'windows', 'conda_app_entry'))

if 'description' in attrs and not is_string(attrs['description']):
_file_problem(problems, project_file,
"'description' field of command {} must be a string".format(name))
Expand Down
2 changes: 1 addition & 1 deletion anaconda_project/test/test_prepare.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ def unprepare_problems(dirname):
assert not status
assert status.status_description == 'Unable to load the project.'
assert status.errors == [('%s: variables section contains wrong value type 42, ' +
'should be dict or list of requirements') % project.project_file.filename]
'should be dict or list of requirements') % project.project_file.basename]

with_directory_contents_completing_project_file({DEFAULT_PROJECT_FILENAME: "variables:\n 42"}, unprepare_problems)

Expand Down

0 comments on commit 0c50402

Please sign in to comment.