Skip to content

Commit

Permalink
Refactor project layout to import yamllint alone
Browse files Browse the repository at this point in the history
Currently importing yamllint recursively imports its submodules, which
finally requires having pyyaml installed. This is a problem when you
just want to import APP_VERSION from yamllint. For instance, setup.py
imports yamllint to know the version, but doesn't know yet that pyyaml
is to be installed, because it is stated in setup.py itself.

To solve this, yamllint/__init__.py will only contain constants. The
linting functions will be in yamllint/linter.py.
  • Loading branch information
adrienverge committed Jan 24, 2016
1 parent 7b147cb commit dbbecb5
Show file tree
Hide file tree
Showing 17 changed files with 152 additions and 165 deletions.
5 changes: 1 addition & 4 deletions docs/development.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,5 @@ Development
yamllint provides both a script and a Python module. The latter can be used to
write your own linting tools:

.. autoclass:: yamllint.errors.LintProblem
:members:

.. automodule:: yamllint
.. automodule:: yamllint.linter
:members:
92 changes: 0 additions & 92 deletions yamllint/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,6 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.

import yaml

from yamllint.errors import LintProblem
from yamllint import parser


APP_NAME = 'yamllint'
APP_VERSION = '0.5.1'
APP_DESCRIPTION = 'A linter for YAML files.'
Expand All @@ -28,89 +22,3 @@
__copyright__ = u'Copyright 2016, Adrien Vergé'
__license__ = 'GPLv3'
__version__ = APP_VERSION


def get_costemic_problems(buffer, conf):
rules = conf.enabled_rules()

# Split token rules from line rules
token_rules = [r for r in rules if r.TYPE == 'token']
line_rules = [r for r in rules if r.TYPE == 'line']

context = {}
for rule in token_rules:
context[rule.ID] = {}

for elem in parser.token_or_line_generator(buffer):
if isinstance(elem, parser.Token):
for rule in token_rules:
rule_conf = conf.rules[rule.ID]
for problem in rule.check(rule_conf,
elem.curr, elem.prev, elem.next,
context[rule.ID]):
problem.rule = rule.ID
problem.level = rule_conf['level']
yield problem
elif isinstance(elem, parser.Line):
for rule in line_rules:
rule_conf = conf.rules[rule.ID]
for problem in rule.check(rule_conf, elem):
problem.rule = rule.ID
problem.level = rule_conf['level']
yield problem


def get_syntax_error(buffer):
try:
list(yaml.parse(buffer, Loader=yaml.BaseLoader))
except yaml.error.MarkedYAMLError as e:
problem = LintProblem(e.problem_mark.line + 1,
e.problem_mark.column + 1,
'syntax error: ' + e.problem)
problem.level = 'error'
return problem


def _lint(buffer, conf):
# If the document contains a syntax error, save it and yield it at the
# right line
syntax_error = get_syntax_error(buffer)

for problem in get_costemic_problems(buffer, conf):
# Insert the syntax error (if any) at the right place...
if (syntax_error and syntax_error.line <= problem.line and
syntax_error.column <= problem.column):
yield syntax_error

# If there is already a yamllint error at the same place, discard
# it as it is probably redundant (and maybe it's just a 'warning',
# in which case the script won't even exit with a failure status).
if (syntax_error.line == problem.line and
syntax_error.column == problem.column):
syntax_error = None
continue

syntax_error = None

yield problem

if syntax_error:
yield syntax_error


def lint(input, conf):
"""Lints a YAML source.
Returns a generator of LintProblem objects.
:param input: buffer, string or stream to read from
:param conf: yamllint configuration object
"""
if type(input) == str:
return _lint(input, conf)
elif hasattr(input, 'read'): # Python 2's file or Python 3's io.IOBase
# We need to have everything in memory to parse correctly
content = input.read()
return _lint(content, conf)
else:
raise TypeError('input should be a string or a stream')
4 changes: 2 additions & 2 deletions yamllint/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@

from yamllint import APP_DESCRIPTION, APP_NAME, APP_VERSION
from yamllint.config import YamlLintConfig, YamlLintConfigError
from yamllint import lint
from yamllint import linter


def find_files_recursively(items):
Expand Down Expand Up @@ -96,7 +96,7 @@ def run(argv):
try:
first = True
with open(file) as f:
for problem in lint(f, conf):
for problem in linter.run(f, conf):
if args.format == 'parsable':
print(Format.parsable(problem, file))
else:
Expand Down
55 changes: 0 additions & 55 deletions yamllint/errors.py

This file was deleted.

137 changes: 137 additions & 0 deletions yamllint/linter.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
# -*- coding: utf-8 -*-
# Copyright (C) 2016 Adrien Vergé
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.

import yaml

from yamllint import parser


class LintProblem(object):
"""Represents a linting problem found by yamllint."""
def __init__(self, line, column, desc='<no description>', rule=None):
#: Line on which the problem was found (starting at 1)
self.line = line
#: Column on which the problem was found (starting at 1)
self.column = column
#: Human-readable description of the problem
self.desc = desc
#: Identifier of the rule that detected the problem
self.rule = rule
self.level = None

@property
def message(self):
if self.rule is not None:
return '%s (%s)' % (self.desc, self.rule)
return self.desc

def __eq__(self, other):
return (self.line == other.line and
self.column == other.column and
self.rule == other.rule)

def __lt__(self, other):
return (self.line < other.line or
(self.line == other.line and self.column < other.column))

def __repr__(self):
return '%d:%d: %s' % (self.line, self.column, self.message)


def get_costemic_problems(buffer, conf):
rules = conf.enabled_rules()

# Split token rules from line rules
token_rules = [r for r in rules if r.TYPE == 'token']
line_rules = [r for r in rules if r.TYPE == 'line']

context = {}
for rule in token_rules:
context[rule.ID] = {}

for elem in parser.token_or_line_generator(buffer):
if isinstance(elem, parser.Token):
for rule in token_rules:
rule_conf = conf.rules[rule.ID]
for problem in rule.check(rule_conf,
elem.curr, elem.prev, elem.next,
context[rule.ID]):
problem.rule = rule.ID
problem.level = rule_conf['level']
yield problem
elif isinstance(elem, parser.Line):
for rule in line_rules:
rule_conf = conf.rules[rule.ID]
for problem in rule.check(rule_conf, elem):
problem.rule = rule.ID
problem.level = rule_conf['level']
yield problem


def get_syntax_error(buffer):
try:
list(yaml.parse(buffer, Loader=yaml.BaseLoader))
except yaml.error.MarkedYAMLError as e:
problem = LintProblem(e.problem_mark.line + 1,
e.problem_mark.column + 1,
'syntax error: ' + e.problem)
problem.level = 'error'
return problem


def _run(buffer, conf):
# If the document contains a syntax error, save it and yield it at the
# right line
syntax_error = get_syntax_error(buffer)

for problem in get_costemic_problems(buffer, conf):
# Insert the syntax error (if any) at the right place...
if (syntax_error and syntax_error.line <= problem.line and
syntax_error.column <= problem.column):
yield syntax_error

# If there is already a yamllint error at the same place, discard
# it as it is probably redundant (and maybe it's just a 'warning',
# in which case the script won't even exit with a failure status).
if (syntax_error.line == problem.line and
syntax_error.column == problem.column):
syntax_error = None
continue

syntax_error = None

yield problem

if syntax_error:
yield syntax_error


def run(input, conf):
"""Lints a YAML source.
Returns a generator of LintProblem objects.
:param input: buffer, string or stream to read from
:param conf: yamllint configuration object
"""
if type(input) == str:
return _run(input, conf)
elif hasattr(input, 'read'): # Python 2's file or Python 3's io.IOBase
# We need to have everything in memory to parse correctly
content = input.read()
return _run(content, conf)
else:
raise TypeError('input should be a string or a stream')
2 changes: 1 addition & 1 deletion yamllint/rules/commas.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@

import yaml

from yamllint.errors import LintProblem
from yamllint.linter import LintProblem
from yamllint.rules.common import spaces_after, spaces_before


Expand Down
2 changes: 1 addition & 1 deletion yamllint/rules/comments.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@

import yaml

from yamllint.errors import LintProblem
from yamllint.linter import LintProblem
from yamllint.rules.common import get_comments_between_tokens


Expand Down
2 changes: 1 addition & 1 deletion yamllint/rules/comments_indentation.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@

import yaml

from yamllint.errors import LintProblem
from yamllint.linter import LintProblem
from yamllint.rules.common import get_line_indent, get_comments_between_tokens


Expand Down
2 changes: 1 addition & 1 deletion yamllint/rules/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@

import yaml

from yamllint.errors import LintProblem
from yamllint.linter import LintProblem


def spaces_after(token, prev, next, min=-1, max=-1,
Expand Down
2 changes: 1 addition & 1 deletion yamllint/rules/document_end.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@

import yaml

from yamllint.errors import LintProblem
from yamllint.linter import LintProblem


ID = 'document-end'
Expand Down
2 changes: 1 addition & 1 deletion yamllint/rules/document_start.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@

import yaml

from yamllint.errors import LintProblem
from yamllint.linter import LintProblem


ID = 'document-start'
Expand Down
2 changes: 1 addition & 1 deletion yamllint/rules/empty_lines.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@
"""


from yamllint.errors import LintProblem
from yamllint.linter import LintProblem


ID = 'empty-lines'
Expand Down
2 changes: 1 addition & 1 deletion yamllint/rules/indentation.py
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@

import yaml

from yamllint.errors import LintProblem
from yamllint.linter import LintProblem
from yamllint.rules.common import is_explicit_key


Expand Down
Loading

0 comments on commit dbbecb5

Please sign in to comment.