Compare commits

...

9 Commits

Author SHA1 Message Date
Adrien Vergé
f9709bc6e6 yamllint version 1.8.0 2017-06-28 15:30:39 +02:00
Adrien Vergé
5060917e40 style(cli): Space import sections 2017-06-28 15:20:24 +02:00
Adrien Vergé
a052cf7dba chore(tests): Add flake8-import-order linter plugin 2017-06-28 15:18:40 +02:00
Adrien Vergé
ae33716529 chore(tests): Also run tests on Python 3.6 2017-06-28 15:14:46 +02:00
Adrien Vergé
df26cc0438 feat(config): Add support to ignore paths on per-rule basis
Example of configuration to use this feature:

    # For all rules
    ignore: |
      *.dont-lint-me.yaml
      /bin/
      !/bin/*.lint-me-anyway.yaml

    rules:
      key-duplicates:
        ignore: |
          generated
          *.template.yaml
      trailing-spaces:
        ignore: |
          *.ignore-trailing-spaces.yaml
          /ascii-art/*

Closes #43.
2017-06-28 15:14:46 +02:00
Adrien Vergé
342d7b49dd tests(cli): Create a temp test workspace only once
Do not re-create it for every test in the class.
2017-06-28 15:11:24 +02:00
Adrien Vergé
7d638d47b9 tests(cli): Refactor temp test workspace recreation
Make it simpler and re-usable.
2017-06-28 15:11:24 +02:00
Adrien Vergé
db116eaaaf Merge pull request #51 from sedrubal/feature_use-argparse-mutually_exclusive_group
Use argparse mutually_exclusive_group for --config-file and --config-data
2017-05-31 22:43:44 +02:00
sedrubal
30dfa78923 Use argparse mutually_exclusive_group for --config-file and --config-data
This does the same as your solution 😉
2017-05-28 22:59:33 +02:00
12 changed files with 299 additions and 80 deletions

View File

@@ -5,9 +5,10 @@ python:
- 3.3 - 3.3
- 3.4 - 3.4
- 3.5 - 3.5
- 3.6
- nightly - nightly
install: install:
- pip install pyyaml flake8 coveralls - pip install pyyaml flake8 flake8-import-order coveralls
- pip install . - pip install .
script: script:
- flake8 . - flake8 .

View File

@@ -119,6 +119,27 @@ or for a whole block:
consectetur : adipiscing elit consectetur : adipiscing elit
# yamllint enable # yamllint enable
Specific files can be ignored (totally or for some rules only) using a
``.gitignore``-style pattern:
.. code:: yaml
# For all rules
ignore: |
*.dont-lint-me.yaml
/bin/
!/bin/*.lint-me-anyway.yaml
rules:
key-duplicates:
ignore: |
generated
*.template.yaml
trailing-spaces:
ignore: |
*.ignore-trailing-spaces.yaml
/ascii-art/*
`Read more in the complete documentation! <https://yamllint.readthedocs.io/>`_ `Read more in the complete documentation! <https://yamllint.readthedocs.io/>`_
License License

View File

@@ -114,3 +114,57 @@ return code will be:
* ``0`` if no errors or warnings occur * ``0`` if no errors or warnings occur
* ``1`` if one or more errors occur * ``1`` if one or more errors occur
* ``2`` if no errors occur, but one or more warnings occur * ``2`` if no errors occur, but one or more warnings occur
Ignoring paths
--------------
It is possible to exclude specific files or directories, so that the linter
doesn't process them.
You can either totally ignore files (they won't be looked at):
.. code-block:: yaml
extends: default
ignore: |
/this/specific/file.yaml
/all/this/directory/
*.template.yaml
or ignore paths only for specific rules:
.. code-block:: yaml
extends: default
rules:
trailing-spaces:
ignore: |
/this-file-has-trailing-spaces-but-it-is-OK.yaml
/generated/*.yaml
Note that this ``.gitignore``-style path pattern allows complex path
exclusion/inclusion, see the `pathspec README file
<https://pypi.python.org/pypi/pathspec>`_ for more details.
Here is a more complex example:
.. code-block:: yaml
# For all rules
ignore: |
*.dont-lint-me.yaml
/bin/
!/bin/*.lint-me-anyway.yaml
extends: default
rules:
key-duplicates:
ignore: |
generated
*.template.yaml
trailing-spaces:
ignore: |
*.ignore-trailing-spaces.yaml
/ascii-art/*

View File

@@ -1,2 +1,5 @@
[bdist_wheel] [bdist_wheel]
universal = 1 universal = 1
[flake8]
import-order-style = pep8

View File

@@ -46,7 +46,7 @@ setup(
entry_points={'console_scripts': ['yamllint=yamllint.cli:run']}, entry_points={'console_scripts': ['yamllint=yamllint.cli:run']},
package_data={'yamllint': ['conf/*.yaml'], package_data={'yamllint': ['conf/*.yaml'],
'tests': ['yaml-1.2-spec-examples/*']}, 'tests': ['yaml-1.2-spec-examples/*']},
install_requires=['pyyaml'], install_requires=['pathspec', 'pyyaml'],
tests_require=['nose'], tests_require=['nose'],
test_suite='nose.collector', test_suite='nose.collector',
) )

View File

@@ -14,6 +14,8 @@
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
import os
import tempfile
import unittest import unittest
import yaml import yaml
@@ -49,3 +51,21 @@ class RuleTestCase(unittest.TestCase):
real_problems = list(linter.run(source, self.build_fake_config(conf))) real_problems = list(linter.run(source, self.build_fake_config(conf)))
self.assertEqual(real_problems, expected_problems) self.assertEqual(real_problems, expected_problems)
def build_temp_workspace(files):
tempdir = tempfile.mkdtemp(prefix='yamllint-tests-')
for path, content in files.items():
path = os.path.join(tempdir, path)
if not os.path.exists(os.path.dirname(path)):
os.makedirs(os.path.dirname(path))
if type(content) is list:
os.mkdir(path)
else:
mode = 'wb' if isinstance(content, bytes) else 'w'
with open(path, mode) as f:
f.write(content)
return tempdir

View File

@@ -23,65 +23,54 @@ import locale
import os import os
import pty import pty
import shutil import shutil
import tempfile
import unittest import unittest
import sys import sys
from yamllint import cli from yamllint import cli
from tests.common import build_temp_workspace
class CommandLineTestCase(unittest.TestCase): class CommandLineTestCase(unittest.TestCase):
def setUp(self): @classmethod
self.wd = tempfile.mkdtemp(prefix='yamllint-tests-') def setUpClass(cls):
super(CommandLineTestCase, cls).setUpClass()
# .yaml file at root cls.wd = build_temp_workspace({
with open(os.path.join(self.wd, 'a.yaml'), 'w') as f: # .yaml file at root
f.write('---\n' 'a.yaml': '---\n'
'- 1 \n' '- 1 \n'
'- 2') '- 2',
# file with only one warning
'warn.yaml': 'key: value\n',
# .yml file at root
'empty.yml': '',
# file in dir
'sub/ok.yaml': '---\n'
'key: value\n',
# file in very nested dir
's/s/s/s/s/s/s/s/s/s/s/s/s/s/s/file.yaml': '---\n'
'key: value\n'
'key: other value\n',
# empty dir
'empty-dir': [],
# non-YAML file
'no-yaml.json': '---\n'
'key: value\n',
# non-ASCII chars
'non-ascii/utf-8': (
u'---\n'
u'- hétérogénéité\n'
u'# 19.99 €\n'
u'- お早う御座います。\n'
u'# الأَبْجَدِيَّة العَرَبِيَّة\n').encode('utf-8'),
})
# file with only one warning @classmethod
with open(os.path.join(self.wd, 'warn.yaml'), 'w') as f: def tearDownClass(cls):
f.write('key: value\n') super(CommandLineTestCase, cls).tearDownClass()
# .yml file at root shutil.rmtree(cls.wd)
open(os.path.join(self.wd, 'empty.yml'), 'w').close()
# file in dir
os.mkdir(os.path.join(self.wd, 'sub'))
with open(os.path.join(self.wd, 'sub', 'ok.yaml'), 'w') as f:
f.write('---\n'
'key: value\n')
# file in very nested dir
dir = self.wd
for i in range(15):
dir = os.path.join(dir, 's')
os.mkdir(dir)
with open(os.path.join(dir, 'file.yaml'), 'w') as f:
f.write('---\n'
'key: value\n'
'key: other value\n')
# empty dir
os.mkdir(os.path.join(self.wd, 'empty-dir'))
# non-YAML file
with open(os.path.join(self.wd, 'no-yaml.json'), 'w') as f:
f.write('---\n'
'key: value\n')
# non-ASCII chars
os.mkdir(os.path.join(self.wd, 'non-ascii'))
with open(os.path.join(self.wd, 'non-ascii', 'utf-8'), 'wb') as f:
f.write((u'---\n'
u'- hétérogénéité\n'
u'# 19.99 €\n'
u'- お早う御座います。\n'
u'# الأَبْجَدِيَّة العَرَبِيَّة\n').encode('utf-8'))
def tearDown(self):
shutil.rmtree(self.wd)
def test_find_files_recursively(self): def test_find_files_recursively(self):
self.assertEqual( self.assertEqual(
@@ -145,8 +134,11 @@ class CommandLineTestCase(unittest.TestCase):
out, err = sys.stdout.getvalue(), sys.stderr.getvalue() out, err = sys.stdout.getvalue(), sys.stderr.getvalue()
self.assertEqual(out, '') self.assertEqual(out, '')
self.assertRegexpMatches(err, r'^Options --config-file and ' self.assertRegexpMatches(
r'--config-data cannot be used') err.splitlines()[-1],
r'^yamllint: error: argument -d\/--config-data: '
r'not allowed with argument -c\/--config-file$'
)
def test_run_with_bad_config(self): def test_run_with_bad_config(self):
sys.stdout, sys.stderr = StringIO(), StringIO() sys.stdout, sys.stderr = StringIO(), StringIO()

View File

@@ -14,10 +14,20 @@
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
try:
from cStringIO import StringIO
except ImportError:
from io import StringIO
import os
import shutil
import sys
import unittest import unittest
from yamllint import cli
from yamllint import config from yamllint import config
from tests.common import build_temp_workspace
class SimpleConfigTestCase(unittest.TestCase): class SimpleConfigTestCase(unittest.TestCase):
def test_parse_config(self): def test_parse_config(self):
@@ -30,7 +40,7 @@ class SimpleConfigTestCase(unittest.TestCase):
self.assertEqual(new.rules['colons']['max-spaces-before'], 0) self.assertEqual(new.rules['colons']['max-spaces-before'], 0)
self.assertEqual(new.rules['colons']['max-spaces-after'], 1) self.assertEqual(new.rules['colons']['max-spaces-after'], 1)
self.assertEqual(len(new.enabled_rules()), 1) self.assertEqual(len(new.enabled_rules(None)), 1)
def test_invalid_conf(self): def test_invalid_conf(self):
with self.assertRaises(config.YamlLintConfigError): with self.assertRaises(config.YamlLintConfigError):
@@ -170,7 +180,7 @@ class ExtendedConfigTestCase(unittest.TestCase):
self.assertEqual(new.rules['colons']['max-spaces-after'], 1) self.assertEqual(new.rules['colons']['max-spaces-after'], 1)
self.assertEqual(new.rules['hyphens']['max-spaces-after'], 2) self.assertEqual(new.rules['hyphens']['max-spaces-after'], 2)
self.assertEqual(len(new.enabled_rules()), 2) self.assertEqual(len(new.enabled_rules(None)), 2)
def test_extend_remove_rule(self): def test_extend_remove_rule(self):
old = config.YamlLintConfig('rules:\n' old = config.YamlLintConfig('rules:\n'
@@ -187,7 +197,7 @@ class ExtendedConfigTestCase(unittest.TestCase):
self.assertEqual(new.rules['colons'], False) self.assertEqual(new.rules['colons'], False)
self.assertEqual(new.rules['hyphens']['max-spaces-after'], 2) self.assertEqual(new.rules['hyphens']['max-spaces-after'], 2)
self.assertEqual(len(new.enabled_rules()), 1) self.assertEqual(len(new.enabled_rules(None)), 1)
def test_extend_edit_rule(self): def test_extend_edit_rule(self):
old = config.YamlLintConfig('rules:\n' old = config.YamlLintConfig('rules:\n'
@@ -207,7 +217,7 @@ class ExtendedConfigTestCase(unittest.TestCase):
self.assertEqual(new.rules['colons']['max-spaces-after'], 4) self.assertEqual(new.rules['colons']['max-spaces-after'], 4)
self.assertEqual(new.rules['hyphens']['max-spaces-after'], 2) self.assertEqual(new.rules['hyphens']['max-spaces-after'], 2)
self.assertEqual(len(new.enabled_rules()), 2) self.assertEqual(len(new.enabled_rules(None)), 2)
def test_extend_reenable_rule(self): def test_extend_reenable_rule(self):
old = config.YamlLintConfig('rules:\n' old = config.YamlLintConfig('rules:\n'
@@ -225,7 +235,7 @@ class ExtendedConfigTestCase(unittest.TestCase):
self.assertEqual(new.rules['colons']['max-spaces-after'], 1) self.assertEqual(new.rules['colons']['max-spaces-after'], 1)
self.assertEqual(new.rules['hyphens']['max-spaces-after'], 2) self.assertEqual(new.rules['hyphens']['max-spaces-after'], 2)
self.assertEqual(len(new.enabled_rules()), 2) self.assertEqual(len(new.enabled_rules(None)), 2)
class ExtendedLibraryConfigTestCase(unittest.TestCase): class ExtendedLibraryConfigTestCase(unittest.TestCase):
@@ -270,3 +280,93 @@ class ExtendedLibraryConfigTestCase(unittest.TestCase):
self.assertEqual(sorted(new.rules.keys()), sorted(old.rules.keys())) self.assertEqual(sorted(new.rules.keys()), sorted(old.rules.keys()))
for rule in new.rules: for rule in new.rules:
self.assertEqual(new.rules[rule], old.rules[rule]) self.assertEqual(new.rules[rule], old.rules[rule])
class IgnorePathConfigTestCase(unittest.TestCase):
@classmethod
def setUpClass(cls):
super(IgnorePathConfigTestCase, cls).setUpClass()
bad_yaml = ('---\n'
'- key: val1\n'
' key: val2\n'
'- trailing space \n'
'- lonely hyphen\n')
cls.wd = build_temp_workspace({
'bin/file.lint-me-anyway.yaml': bad_yaml,
'bin/file.yaml': bad_yaml,
'file-at-root.yaml': bad_yaml,
'file.dont-lint-me.yaml': bad_yaml,
'ign-dup/file.yaml': bad_yaml,
'ign-dup/sub/dir/file.yaml': bad_yaml,
'ign-trail/file.yaml': bad_yaml,
'include/ign-dup/sub/dir/file.yaml': bad_yaml,
's/s/ign-trail/file.yaml': bad_yaml,
's/s/ign-trail/s/s/file.yaml': bad_yaml,
's/s/ign-trail/s/s/file2.lint-me-anyway.yaml': bad_yaml,
'.yamllint': 'ignore: |\n'
' *.dont-lint-me.yaml\n'
' /bin/\n'
' !/bin/*.lint-me-anyway.yaml\n'
'\n'
'extends: default\n'
'\n'
'rules:\n'
' key-duplicates:\n'
' ignore: |\n'
' /ign-dup\n'
' trailing-spaces:\n'
' ignore: |\n'
' ign-trail\n'
' !*.lint-me-anyway.yaml\n',
})
cls.backup_wd = os.getcwd()
os.chdir(cls.wd)
@classmethod
def tearDownClass(cls):
super(IgnorePathConfigTestCase, cls).tearDownClass()
os.chdir(cls.backup_wd)
shutil.rmtree(cls.wd)
def test_run_with_ignored_path(self):
sys.stdout = StringIO()
with self.assertRaises(SystemExit):
cli.run(('-f', 'parsable', '.'))
out = sys.stdout.getvalue()
out = '\n'.join(sorted(out.splitlines()))
keydup = '[error] duplication of key "key" in mapping (key-duplicates)'
trailing = '[error] trailing spaces (trailing-spaces)'
hyphen = '[error] too many spaces after hyphen (hyphens)'
self.assertEqual(out, '\n'.join((
'./bin/file.lint-me-anyway.yaml:3:3: ' + keydup,
'./bin/file.lint-me-anyway.yaml:4:17: ' + trailing,
'./bin/file.lint-me-anyway.yaml:5:5: ' + hyphen,
'./file-at-root.yaml:3:3: ' + keydup,
'./file-at-root.yaml:4:17: ' + trailing,
'./file-at-root.yaml:5:5: ' + hyphen,
'./ign-dup/file.yaml:4:17: ' + trailing,
'./ign-dup/file.yaml:5:5: ' + hyphen,
'./ign-dup/sub/dir/file.yaml:4:17: ' + trailing,
'./ign-dup/sub/dir/file.yaml:5:5: ' + hyphen,
'./ign-trail/file.yaml:3:3: ' + keydup,
'./ign-trail/file.yaml:5:5: ' + hyphen,
'./include/ign-dup/sub/dir/file.yaml:3:3: ' + keydup,
'./include/ign-dup/sub/dir/file.yaml:4:17: ' + trailing,
'./include/ign-dup/sub/dir/file.yaml:5:5: ' + hyphen,
'./s/s/ign-trail/file.yaml:3:3: ' + keydup,
'./s/s/ign-trail/file.yaml:5:5: ' + hyphen,
'./s/s/ign-trail/s/s/file.yaml:3:3: ' + keydup,
'./s/s/ign-trail/s/s/file.yaml:5:5: ' + hyphen,
'./s/s/ign-trail/s/s/file2.lint-me-anyway.yaml:3:3: ' + keydup,
'./s/s/ign-trail/s/s/file2.lint-me-anyway.yaml:4:17: ' + trailing,
'./s/s/ign-trail/s/s/file2.lint-me-anyway.yaml:5:5: ' + hyphen,
)))

View File

@@ -22,7 +22,7 @@ indentation, etc."""
APP_NAME = 'yamllint' APP_NAME = 'yamllint'
APP_VERSION = '1.7.0' APP_VERSION = '1.8.0'
APP_DESCRIPTION = __doc__ APP_DESCRIPTION = __doc__
__author__ = u'Adrien Vergé' __author__ = u'Adrien Vergé'

View File

@@ -15,6 +15,7 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
from __future__ import print_function from __future__ import print_function
import os.path import os.path
import sys import sys
@@ -78,11 +79,13 @@ def run(argv=None):
description=APP_DESCRIPTION) description=APP_DESCRIPTION)
parser.add_argument('files', metavar='FILE_OR_DIR', nargs='+', parser.add_argument('files', metavar='FILE_OR_DIR', nargs='+',
help='files to check') help='files to check')
parser.add_argument('-c', '--config-file', dest='config_file', config_group = parser.add_mutually_exclusive_group()
action='store', help='path to a custom configuration') config_group.add_argument('-c', '--config-file', dest='config_file',
parser.add_argument('-d', '--config-data', dest='config_data', action='store',
action='store', help='path to a custom configuration')
help='custom configuration (as YAML source)') config_group.add_argument('-d', '--config-data', dest='config_data',
action='store',
help='custom configuration (as YAML source)')
parser.add_argument('-f', '--format', parser.add_argument('-f', '--format',
choices=('parsable', 'standard'), default='standard', choices=('parsable', 'standard'), default='standard',
help='format for parsing output') help='format for parsing output')
@@ -97,11 +100,6 @@ def run(argv=None):
args = parser.parse_args(argv) args = parser.parse_args(argv)
if args.config_file is not None and args.config_data is not None:
print('Options --config-file and --config-data cannot be used '
'simultaneously.', file=sys.stderr)
sys.exit(-1)
# User-global config is supposed to be in ~/.config/yamllint/config # User-global config is supposed to be in ~/.config/yamllint/config
if 'XDG_CONFIG_HOME' in os.environ: if 'XDG_CONFIG_HOME' in os.environ:
user_global_config = os.path.join( user_global_config = os.path.join(
@@ -129,10 +127,11 @@ def run(argv=None):
max_level = 0 max_level = 0
for file in find_files_recursively(args.files): for file in find_files_recursively(args.files):
filepath = file[2:] if file.startswith('./') else file
try: try:
first = True first = True
with open(file) as f: with open(file) as f:
for problem in linter.run(f, conf): for problem in linter.run(f, conf, filepath):
if args.format == 'parsable': if args.format == 'parsable':
print(Format.parsable(problem, file)) print(Format.parsable(problem, file))
elif sys.stdout.isatty(): elif sys.stdout.isatty():

View File

@@ -16,6 +16,7 @@
import os.path import os.path
import pathspec
import yaml import yaml
import yamllint.rules import yamllint.rules
@@ -29,6 +30,8 @@ class YamlLintConfig(object):
def __init__(self, content=None, file=None): def __init__(self, content=None, file=None):
assert (content is None) ^ (file is None) assert (content is None) ^ (file is None)
self.ignore = None
if file is not None: if file is not None:
with open(file) as f: with open(file) as f:
content = f.read() content = f.read()
@@ -36,9 +39,14 @@ class YamlLintConfig(object):
self.parse(content) self.parse(content)
self.validate() self.validate()
def enabled_rules(self): def is_file_ignored(self, filepath):
return self.ignore and self.ignore.match_file(filepath)
def enabled_rules(self, filepath):
return [yamllint.rules.get(id) for id, val in self.rules.items() return [yamllint.rules.get(id) for id, val in self.rules.items()
if val is not False] if val is not False and (
filepath is None or 'ignore' not in val or
not val['ignore'].match_file(filepath))]
def extend(self, base_config): def extend(self, base_config):
assert isinstance(base_config, YamlLintConfig) assert isinstance(base_config, YamlLintConfig)
@@ -53,6 +61,9 @@ class YamlLintConfig(object):
self.rules = base_config.rules self.rules = base_config.rules
if base_config.ignore is not None:
self.ignore = base_config.ignore
def parse(self, raw_content): def parse(self, raw_content):
try: try:
conf = yaml.safe_load(raw_content) conf = yaml.safe_load(raw_content)
@@ -73,6 +84,13 @@ class YamlLintConfig(object):
except Exception as e: except Exception as e:
raise YamlLintConfigError('invalid config: %s' % e) raise YamlLintConfigError('invalid config: %s' % e)
if 'ignore' in conf:
if type(conf['ignore']) != str:
raise YamlLintConfigError(
'invalid config: ignore should be a list of patterns')
self.ignore = pathspec.PathSpec.from_lines(
'gitwildmatch', conf['ignore'].splitlines())
def validate(self): def validate(self):
for id in self.rules: for id in self.rules:
try: try:
@@ -90,6 +108,14 @@ def validate_rule_conf(rule, conf):
conf = {} conf = {}
if type(conf) == dict: if type(conf) == dict:
if ('ignore' in conf and
type(conf['ignore']) != pathspec.pathspec.PathSpec):
if type(conf['ignore']) != str:
raise YamlLintConfigError(
'invalid config: ignore should be a list of patterns')
conf['ignore'] = pathspec.PathSpec.from_lines(
'gitwildmatch', conf['ignore'].splitlines())
if 'level' not in conf: if 'level' not in conf:
conf['level'] = 'error' conf['level'] = 'error'
elif conf['level'] not in ('error', 'warning'): elif conf['level'] not in ('error', 'warning'):
@@ -98,7 +124,7 @@ def validate_rule_conf(rule, conf):
options = getattr(rule, 'CONF', {}) options = getattr(rule, 'CONF', {})
for optkey in conf: for optkey in conf:
if optkey == 'level': if optkey in ('ignore', 'level'):
continue continue
if optkey not in options: if optkey not in options:
raise YamlLintConfigError( raise YamlLintConfigError(

View File

@@ -63,8 +63,8 @@ class LintProblem(object):
return '%d:%d: %s' % (self.line, self.column, self.message) return '%d:%d: %s' % (self.line, self.column, self.message)
def get_cosmetic_problems(buffer, conf): def get_cosmetic_problems(buffer, conf, filepath):
rules = conf.enabled_rules() rules = conf.enabled_rules(filepath)
# Split token rules from line rules # Split token rules from line rules
token_rules = [r for r in rules if r.TYPE == 'token'] token_rules = [r for r in rules if r.TYPE == 'token']
@@ -185,7 +185,7 @@ def get_syntax_error(buffer):
return problem return problem
def _run(buffer, conf): def _run(buffer, conf, filepath):
assert hasattr(buffer, '__getitem__'), \ assert hasattr(buffer, '__getitem__'), \
'_run() argument must be a buffer, not a stream' '_run() argument must be a buffer, not a stream'
@@ -193,7 +193,7 @@ def _run(buffer, conf):
# right line # right line
syntax_error = get_syntax_error(buffer) syntax_error = get_syntax_error(buffer)
for problem in get_cosmetic_problems(buffer, conf): for problem in get_cosmetic_problems(buffer, conf, filepath):
# Insert the syntax error (if any) at the right place... # Insert the syntax error (if any) at the right place...
if (syntax_error and syntax_error.line <= problem.line and if (syntax_error and syntax_error.line <= problem.line and
syntax_error.column <= problem.column): syntax_error.column <= problem.column):
@@ -215,7 +215,7 @@ def _run(buffer, conf):
yield syntax_error yield syntax_error
def run(input, conf): def run(input, conf, filepath=None):
"""Lints a YAML source. """Lints a YAML source.
Returns a generator of LintProblem objects. Returns a generator of LintProblem objects.
@@ -223,11 +223,14 @@ def run(input, conf):
:param input: buffer, string or stream to read from :param input: buffer, string or stream to read from
:param conf: yamllint configuration object :param conf: yamllint configuration object
""" """
if conf.is_file_ignored(filepath):
return ()
if type(input) in (type(b''), type(u'')): # compat with Python 2 & 3 if type(input) in (type(b''), type(u'')): # compat with Python 2 & 3
return _run(input, conf) return _run(input, conf, filepath)
elif hasattr(input, 'read'): # Python 2's file or Python 3's io.IOBase elif hasattr(input, 'read'): # Python 2's file or Python 3's io.IOBase
# We need to have everything in memory to parse correctly # We need to have everything in memory to parse correctly
content = input.read() content = input.read()
return _run(content, conf) return _run(content, conf, filepath)
else: else:
raise TypeError('input should be a string or a stream') raise TypeError('input should be a string or a stream')