Source code for rkd.core.yaml_parser

"""
Generic YAML file parsing module

Uses standard YAML parser, adds additional features, such as:
  - Schema validation
  - RKD lookup paths integration
"""

import os
from typing import List
from yaml import load as yaml_load
from yaml import Loader as YamlLoader
from json import load as json_load
from jsonschema import validate
from jsonschema import ValidationError
from jsonschema import draft7_format_checker
from . import env
from .exception import YAMLFileValidationError
from .packaging import get_user_site_packages

CURRENT_SCRIPT_PATH = os.path.dirname(os.path.realpath(__file__))


[docs]class YamlFileLoader(object): """YAML loader extended by schema validation support YAML schema is stored as JSON files in .rkd/schema directories. The Loader looks in all paths defined in RKD_PATH as well as in paths provided by ApplicationContext """ paths: List[str] def __init__(self, paths: List[str]): self.paths = paths
[docs] def load_from_file(self, filename: str, schema_name: str): """Loads a YAML file from given path, a wrapper to load()""" file_path = self.find_path_by_name(filename, '') if not file_path: raise FileNotFoundError('YAML file "%s" not found in any of lookup paths: %s' % ( filename, str(self.get_lookup_paths('')) )) with open(file_path, 'rb') as f: return self.load(f.read(), schema_name)
[docs] def load(self, stream, schema_name: str): """Loads a YAML, validates and return parsed as dict/list """ schema_name = schema_name.replace('/', '-') + '.json' schema_path = self.find_path_by_name(schema_name, 'schema') if not schema_path: raise FileNotFoundError('Schema "%s" cannot be found, looked in: %s' % ( schema_name, str(self.get_lookup_paths('schema')) )) parsed = yaml_load(stream, YamlLoader) with open(schema_path, 'rb') as f: try: validate(instance=parsed, schema=json_load(f), format_checker=draft7_format_checker) except ValidationError as e: raise YAMLFileValidationError(e) return parsed
[docs] def find_path_by_name(self, filename: str, subdir: str) -> str: """Find schema in one of RKD directories or in current path """ if "/" in filename and os.path.isfile(filename): return filename for path in self.get_lookup_paths(subdir): file_path = path + '/' + filename if os.path.isfile(file_path): return file_path return ''
def get_lookup_paths(self, subdirectory: str) -> List[str]: paths = [ os.getcwd(), os.getcwd() + '/' + subdirectory, (os.getcwd() + '/.%s/' + subdirectory) % env.distribution_name() ] global_paths = env.rkd_paths() global_paths.reverse() for path in self.paths: paths.append(path + '/' + subdirectory) for path in global_paths: paths.append(path + '/' + subdirectory) paths.append(CURRENT_SCRIPT_PATH + '/misc/internal/' + subdirectory) paths.append(get_user_site_packages() + '/usr/share/%s/internal' % env.distribution_name()) paths.append((get_user_site_packages() + '/usr/share/%s/internal/' + subdirectory) % env.distribution_name()) paths.append('/usr/share/%s/internal' % env.distribution_name()) return list(dict.fromkeys(paths))