Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Let users choose the file encoding #190

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 14 additions & 11 deletions yamale/command_line.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@

import argparse
import glob
import locale
import os
from multiprocessing import Pool
from .yamale_error import YamaleError
Expand All @@ -20,18 +21,18 @@
schemas = {}


def _validate(schema_path, data_path, parser, strict, _raise_error):
def _validate(schema_path, data_path, parser, strict, _raise_error, encoding):
schema = schemas.get(schema_path)
try:
if not schema:
schema = yamale.make_schema(schema_path, parser)
schema = yamale.make_schema(schema_path, parser, encoding=encoding)
schemas[schema_path] = schema
except (SyntaxError, ValueError) as e:
results = [Result([str(e)])]
if not _raise_error:
return results
raise YamaleError(results)
data = yamale.make_data(data_path, parser)
data = yamale.make_data(data_path, parser, encoding=encoding)
return yamale.validate(schema, data, strict, _raise_error)


Expand Down Expand Up @@ -60,15 +61,15 @@ def _find_schema(data_path, schema_name):
return _find_data_path_schema(data_path, schema_name)


def _validate_single(yaml_path, schema_name, parser, strict):
def _validate_single(yaml_path, schema_name, parser, strict, encoding):
print('Validating %s...' % yaml_path)
s = _find_schema(yaml_path, schema_name)
if not s:
raise ValueError("Invalid schema name for '{}' or schema not found.".format(schema_name))
_validate(s, yaml_path, parser, strict, True)
_validate(s, yaml_path, parser, strict, True, encoding)


def _validate_dir(root, schema_name, cpus, parser, strict):
def _validate_dir(root, schema_name, cpus, parser, strict, encoding):
pool = Pool(processes=cpus)
res = []
error_messages = []
Expand All @@ -80,7 +81,7 @@ def _validate_dir(root, schema_name, cpus, parser, strict):
s = _find_schema(d, schema_name)
if s:
res.append(pool.apply_async(_validate,
(s, d, parser, strict, False)))
(s, d, parser, strict, False, encoding)))
else:
print('No schema found for: %s' % d)

Expand All @@ -97,12 +98,12 @@ def _validate_dir(root, schema_name, cpus, parser, strict):
raise ValueError('\n----\n'.join(set(error_messages)))


def _router(root, schema_name, cpus, parser, strict=True):
def _router(root: str, schema_name: str, cpus: int, parser: str, strict: bool=True, encoding: str=locale.getpreferredencoding(False)):
root = os.path.abspath(root)
if os.path.isfile(root):
_validate_single(root, schema_name, parser, strict)
_validate_single(root, schema_name, parser, strict, encoding)
else:
_validate_dir(root, schema_name, cpus, parser, strict)
_validate_dir(root, schema_name, cpus, parser, strict, encoding)


def main():
Expand All @@ -117,9 +118,11 @@ def main():
help='YAML library to load files. Choices are "ruamel" or "pyyaml" (default).')
parser.add_argument('--no-strict', action='store_true',
help='Disable strict mode, unexpected elements in the data will be accepted.')
parser.add_argument('-e', '--encoding', default=locale.getpreferredencoding(False),
help='Character encoding of the files. Default is the system default.')
args = parser.parse_args()
try:
_router(args.path, args.schema, args.cpu_num, args.parser, not args.no_strict)
_router(args.path, args.schema, args.cpu_num, args.parser, not args.no_strict, args.encoding)
print('Validation success! 👍')
except (SyntaxError, NameError, TypeError, ValueError) as e:
print('Validation failed!\n%s' % str(e))
Expand Down
4 changes: 2 additions & 2 deletions yamale/readers/yaml_reader.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,15 +23,15 @@ def _ruamel(f):
}


def parse_yaml(path=None, parser='pyyaml', content=None):
def parse_yaml(path: str=None, parser: str='pyyaml', content: str=None, encoding: str='utf-8'):
try:
parse = _parsers[parser.lower()]
except KeyError:
raise NameError('Parser "' + parser + '" is not supported\nAvailable parsers are listed below:\nPyYAML\nruamel')
if (path is None and content is None) or (path is not None and content is not None):
raise TypeError("Pass either path= or content=, not both")
if path is not None:
with open(path) as f:
with open(path, encoding=encoding) as f:
return parse(f)
else:
return parse(StringIO(content))
4 changes: 2 additions & 2 deletions yamale/schema/schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ def _parse_schema_item(self, path, expression, validators):
error = str(e) + ' at node \'%s\'' % str(path)
raise SyntaxError(error)

def validate(self, data, data_name, strict):
def validate(self, data: str, data_name: str, strict: bool) -> ValidationResult:
path = DataPath()
errors = self._validate(self._schema, data, path, strict)
return ValidationResult(data_name, self.name, errors)
Expand All @@ -75,7 +75,7 @@ def _validate_item(self, validator, data, path, strict, key):

return self._validate(validator, data_item, path, strict)

def _validate(self, validator, data, path, strict):
def _validate(self, validator, data: str, path: DataPath, strict: bool):
"""
Validate data with validator.
Special handling of non-primitive validators.
Expand Down
39 changes: 33 additions & 6 deletions yamale/yamale.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,25 @@
#!/usr/bin/env python
import locale
from typing import Any, List

from yamale.schema.validationresults import ValidationResult
from .schema import Schema
from .yamale_error import YamaleError


def make_schema(path=None, parser='PyYAML', validators=None, content=None):
def make_schema(path: str=None, parser: str='PyYAML', validators=None, content: str=None, encoding: str=locale.getpreferredencoding(False)) -> Schema:
"""
Reads YAML schemas from files or a string.
:param path: Path to the schema file or directory.
:param parser: Parser to use. Can be 'PyYAML' or 'ruamel'.
:param validators: List of validators to use.
:param content: Content of the YAML schema. If not provided, the schema is read from `path`.
:param encoding: Encoding of the YAML schema files. Only used if `path` is provided.
"""
# validators = None means use default.
# Import readers here so we can get version information in setup.py.
from . import readers
raw_schemas = readers.parse_yaml(path, parser, content=content)
raw_schemas = readers.parse_yaml(path, parser, content=content, encoding=encoding)
if not raw_schemas:
raise ValueError('{} is an empty file!'.format(path))
# First document is the base schema
Expand All @@ -24,16 +36,31 @@ def make_schema(path=None, parser='PyYAML', validators=None, content=None):
return s


def make_data(path=None, parser='PyYAML', content=None):
def make_data(path: str=None, parser: str='PyYAML', content: str=None, encoding: str=locale.getpreferredencoding(False)):
"""
Reads a YAML file containing the data.
:param path: Path to the YAML file or directory.
:param parser: Parser to use. Can be 'PyYAML' or 'ruamel'.
:param content: Content of the YAML file. If not provided, the data is read from `path`.
:param encoding: Encoding of the YAML files. Only used if `path` is provided.
:return: A list of parsed YAML files. The object types depend on the parser used.
"""
from . import readers
raw_data = readers.parse_yaml(path, parser, content=content)
raw_data = readers.parse_yaml(path, parser, content=content, encoding=encoding)
if len(raw_data) == 0:
return [({}, path)]
return [(d, path) for d in raw_data]


def validate(schema, data, strict=True, _raise_error=True):
results = []
def validate(schema: Schema, data: List[Any], strict: bool=True, _raise_error: bool=True) -> List[ValidationResult]:
"""
Validates the list of YAML files against the schema.
:param schema: Schema to validate against.
:param data: List of YAML files to validate.
:param strict: If True, unexpected elements in the data will cause validation errors.
:param _raise_error: If True, raises an exception if a validation error occurs.
"""
results: List[ValidationResult] = []
is_valid = True
for d, path in data:
result = schema.validate(d, path, strict)
Expand Down