diff --git a/Containerfile.multiarch b/Containerfile.multiarch index 4a70e2d..35277fe 100644 --- a/Containerfile.multiarch +++ b/Containerfile.multiarch @@ -12,7 +12,7 @@ ENV TZ=UTC ADD dist/ansible_doctor-*.whl / -RUN apk --update add --virtual .build-deps build-base libffi-dev openssl-dev && \ +RUN apk --update add --virtual .build-deps build-base libffi-dev openssl-dev git && \ pip install --upgrade --no-cache-dir pip && \ pip install --no-cache-dir $(find / -name "ansible_doctor-*.whl")[ansible-core] && \ rm -f ansible_doctor-*.whl && \ diff --git a/ansibledoctor/cli.py b/ansibledoctor/cli.py index 4654657..b508ab6 100644 --- a/ansibledoctor/cli.py +++ b/ansibledoctor/cli.py @@ -18,11 +18,17 @@ class AnsibleDoctor: def __init__(self): self.log = SingleLog() self.logger = self.log.logger - self.args = self._cli_args() - self.config = self._get_config() + + try: + self.config = SingleConfig() + self.config.load(args=self._parse_args()) + self.log.register_hanlers(json=self.config.config.logging.json) + except ansibledoctor.exception.ConfigError as e: + self.log.sysexit_with_message(e) + self._execute() - def _cli_args(self): + def _parse_args(self): """ Use argparse for parsing CLI arguments. @@ -33,28 +39,40 @@ class AnsibleDoctor: description="Generate documentation from annotated Ansible roles using templates" ) parser.add_argument( - "base_dir", nargs="?", help="base directory (default: current working directory)" + "base_dir", + nargs="?", + default=self.config.config.base_dir, + help="base directory (default: current working directory)", ) parser.add_argument( - "-c", "--config", dest="config_file", help="path to configuration file" + "-c", + "--config", + dest="config_file", + help="path to configuration file", ) parser.add_argument( - "-o", "--output", dest="output_dir", action="store", help="output directory" + "-o", + "--output", + dest="renderer__dest", + action="store", + default=self.config.config.renderer.dest, + help="output directory", + metavar="OUTPUT_DIR", ) parser.add_argument( "-r", "--recursive", dest="recursive", action="store_true", - default=None, + default=self.config.config.recursive, help="run recursively over the base directory subfolders", ) parser.add_argument( "-f", "--force", - dest="force_overwrite", + dest="renderer.force_overwrite", action="store_true", - default=None, + default=self.config.config.renderer.force_overwrite, help="force overwrite output file", ) parser.add_argument( @@ -62,7 +80,7 @@ class AnsibleDoctor: "--dry-run", dest="dry_run", action="store_true", - default=None, + default=self.config.config.dry_run, help="dry run without writing", ) parser.add_argument( @@ -70,49 +88,58 @@ class AnsibleDoctor: "--no-role-detection", dest="role_detection", action="store_false", - default=None, + default=self.config.config.role.autodetect, help="disable automatic role detection", ) parser.add_argument( - "-v", dest="logging.level", action="append_const", const=-1, help="increase log level" + "-v", + dest="logging.level", + action="append_const", + const=-1, + help="increase log level", ) parser.add_argument( - "-q", dest="logging.level", action="append_const", const=1, help="decrease log level" + "-q", + dest="logging.level", + action="append_const", + const=1, + help="decrease log level", + ) + parser.add_argument( + "--version", + action="version", + version=f"%(prog)s {__version__}", ) - parser.add_argument("--version", action="version", version=f"%(prog)s {__version__}") return parser.parse_args().__dict__ - def _get_config(self): - try: - config = SingleConfig(args=self.args) - except ansibledoctor.exception.ConfigError as e: - self.log.sysexit_with_message(e) - - return config - def _execute(self): - cwd = self.config.base_dir + cwd = os.path.abspath(self.config.config.base_dir) walkdirs = [cwd] - if self.config.recursive: + if self.config.config.recursive: walkdirs = [f.path for f in os.scandir(cwd) if f.is_dir()] for item in walkdirs: os.chdir(item) - self.config.set_config(base_dir=os.getcwd()) try: - self.log.set_level(self.config.config["logging"]["level"]) + self.config.load(root_path=os.getcwd()) + self.log.register_hanlers(json=self.config.config.logging.json) + except ansibledoctor.exception.ConfigError as e: + self.log.sysexit_with_message(e) + + try: + self.log.set_level(self.config.config.logging.level) except ValueError as e: self.log.sysexit_with_message(f"Can not set log level.\n{e!s}") - self.logger.info(f"Using config file: {self.config.config_file}") + self.logger.info(f"Using config file: {self.config.config_files}") - self.logger.debug(f"Using working dir: {item}") + self.logger.debug(f"Using working directory: {os.path.relpath(item, self.log.ctx)}") - if self.config.config["role_detection"]: - if self.config.is_role: - self.logger.info(f"Ansible role detected: {self.config.config['role_name']}") + if self.config.config.role.autodetect: + if self.config.is_role(): + self.logger.info(f"Ansible role detected: {self.config.config.role_name}") else: self.log.sysexit_with_message("No Ansible role detected") else: diff --git a/ansibledoctor/config.py b/ansibledoctor/config.py index 70524a5..73aac7d 100644 --- a/ansibledoctor/config.py +++ b/ansibledoctor/config.py @@ -3,133 +3,15 @@ import os -import anyconfig -import environs -import jsonschema.exceptions -import ruamel.yaml from appdirs import AppDirs -from jsonschema._utils import format_as_index +from dynaconf import Dynaconf, ValidationError, Validator import ansibledoctor.exception from ansibledoctor.utils import Singleton -config_dir = AppDirs("ansible-doctor").user_config_dir -default_config_file = os.path.join(config_dir, "config.yml") -default_envs_prefix = "ANSIBLE_DOCTOR_" - class Config: - """ - Create an object with all necessary settings. - - Settings are loade from multiple locations in defined order (last wins): - - default settings defined by `self._get_defaults()` - - yaml config file, defaults to OS specific user config dir (https://pypi.org/project/appdirs/) - - provides cli parameters - """ - - SETTINGS = { - "config_file": { - "default": default_config_file, - "env": "CONFIG_FILE", - "type": environs.Env().str, - }, - "base_dir": { - "default": os.getcwd(), - "refresh": os.getcwd, - "env": "BASE_DIR", - "type": environs.Env().str, - }, - "role_name": { - "default": "", - "env": "ROLE_NAME", - "type": environs.Env().str, - }, - "dry_run": { - "default": False, - "env": "DRY_RUN", - "file": True, - "type": environs.Env().bool, - }, - "logging.level": { - "default": "WARNING", - "env": "LOG_LEVEL", - "file": True, - "type": environs.Env().str, - }, - "logging.json": { - "default": False, - "env": "LOG_JSON", - "file": True, - "type": environs.Env().bool, - }, - "output_dir": { - "default": os.getcwd(), - "refresh": os.getcwd, - "env": "OUTPUT_DIR", - "file": True, - "type": environs.Env().str, - }, - "recursive": { - "default": False, - "env": "RECURSIVE", - "type": environs.Env().bool, - }, - "template_dir": { - "default": os.path.join(os.path.dirname(os.path.realpath(__file__)), "templates"), - "env": "TEMPLATE_DIR", - "file": True, - "type": environs.Env().str, - }, - "template": { - "default": "readme", - "env": "TEMPLATE", - "file": True, - "type": environs.Env().str, - }, - "template_autotrim": { - "default": True, - "env": "TEMPLATE_AUTOTRIM", - "file": True, - "type": environs.Env().bool, - }, - "force_overwrite": { - "default": False, - "env": "FORCE_OVERWRITE", - "file": True, - "type": environs.Env().bool, - }, - "custom_header": { - "default": "", - "env": "CUSTOM_HEADER", - "file": True, - "type": environs.Env().str, - }, - "exclude_files": { - "default": [], - "env": "EXCLUDE_FILES", - "file": True, - "type": environs.Env().list, - }, - "exclude_tags": { - "default": [], - "env": "EXCLUDE_TAGS", - "file": True, - "type": environs.Env().list, - }, - "role_detection": { - "default": True, - "env": "ROLE_DETECTION", - "file": True, - "type": environs.Env().bool, - }, - "tabulate_variables": { - "default": False, - "env": "TABULATE_VARIABLES", - "file": True, - "type": environs.Env().bool, - }, - } + """Create configuration object.""" ANNOTATIONS = { "meta": { @@ -164,174 +46,161 @@ class Config: }, } - def __init__(self, args=None): - """ - Initialize a new settings class. + def __init__(self): + self.config_files = [ + os.path.join(AppDirs("ansible-doctor").user_config_dir, "config.yml"), + ".ansibledoctor", + ".ansibledoctor.yml", + ".ansibledoctor.yaml", + ] + self.config_merge = True + self.args = {} + self.load() - :param args: An optional dict of options, arguments and commands from the CLI. - :param config_file: An optional path to a yaml config file. - :returns: None + def load(self, root_path=None, args=None): + if args: + if args.get("config_file"): + self.config_merge = False + self.config_files = [os.path.abspath(args.get("config_file"))] + args.pop("config_file") - """ - if args is None: - self._args = {} - else: - self._args = args - self._schema = None - self.config = None - self.is_role = False - self.set_config() + self.args = args - def _get_args(self, args): - cleaned = dict(filter(lambda item: item[1] is not None, args.items())) + self.config = Dynaconf( + envvar_prefix="ANSIBLE_DOCTOR", + merge_enabled=self.config_merge, + core_loaders=["YAML"], + root_path=root_path, + settings_files=self.config_files, + fresh_vars=["base_dir", "output_dir"], + validators=[ + Validator( + "base_dir", + default=os.getcwd(), + apply_default_on_none=True, + is_type_of=str, + ), + Validator( + "dry_run", + default=False, + is_type_of=bool, + ), + Validator( + "recursive", + default=False, + is_type_of=bool, + ), + Validator( + "exclude_files", + default=[], + is_type_of=list, + ), + Validator( + "exclude_tags", + default=[], + is_type_of=list, + ), + Validator( + "role.name", + is_type_of=str, + ), + Validator( + "role.autodetect", + default=True, + is_type_of=bool, + ), + Validator( + "logging.level", + default="WARNING", + is_in=[ + "DEBUG", + "INFO", + "WARNING", + "ERROR", + "CRITICAL", + "debug", + "info", + "warning", + "error", + "critical", + ], + ), + Validator( + "logging.json", + default=False, + is_type_of=bool, + ), + Validator( + "recursive", + default=False, + is_type_of=bool, + ), + Validator( + "template.src", + default=os.path.join(os.path.dirname(os.path.realpath(__file__)), "templates"), + is_type_of=str, + ), + Validator( + "template.name", + default="readme", + is_type_of=str, + ), + Validator( + "template.options.tabulate_variables", + default=False, + is_type_of=bool, + ), + Validator( + "renderer.autotrim", + default=True, + is_type_of=bool, + ), + Validator( + "renderer.include_header", + default="", + is_type_of=str, + ), + Validator( + "renderer.dest", + default=os.path.relpath(os.getcwd()), + is_type_of=str, + ), + Validator( + "renderer.force_overwrite", + default=False, + is_type_of=bool, + ), + ], + ) - normalized = {} - for key, value in cleaned.items(): - normalized = self._add_dict_branch(normalized, key.split("."), value) + self.validate() # Override correct log level from argparse levels = ["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"] - log_level = levels.index(self.SETTINGS["logging.level"]["default"]) - if normalized.get("logging"): - for adjustment in normalized["logging"]["level"]: - log_level = min(len(levels) - 1, max(log_level + adjustment, 0)) - normalized["logging"]["level"] = levels[log_level] + log_level = levels.index(self.config.logging.level.upper()) + if self.args.get("logging.level") and isinstance(self.args["logging.level"], list): + for lvl in self.args["logging.level"]: + log_level = min(len(levels) - 1, max(log_level + lvl, 0)) - return normalized + self.args["logging__level"] = levels[log_level] - def _get_defaults(self): - normalized = {} - for key, item in self.SETTINGS.items(): - if item.get("refresh"): - item["default"] = item["refresh"]() - normalized = self._add_dict_branch(normalized, key.split("."), item["default"]) + if root_path: + self.args["base_dir"] = root_path - self.schema = anyconfig.gen_schema(normalized) - return normalized + self.config.update(self.args) + self.validate() - def _get_envs(self): - normalized = {} - for key, item in self.SETTINGS.items(): - if item.get("env"): - envname = f"{default_envs_prefix}{item['env']}" - try: - value = item["type"](envname) - normalized = self._add_dict_branch(normalized, key.split("."), value) - except environs.EnvError as e: - if f'"{envname}" not set' in str(e): - pass - else: - raise ansibledoctor.exception.ConfigError( - "Unable to read environment variable", str(e) - ) from e - - return normalized - - def set_config(self, base_dir=None): - args = self._get_args(self._args) - envs = self._get_envs() - defaults = self._get_defaults() - - self.recursive = defaults.get("recursive") - if envs.get("recursive"): - self.recursive = envs.get("recursive") - if args.get("recursive"): - self.recursive = args.get("recursive") - if "recursive" in defaults: - defaults.pop("recursive") - - self.config_file = defaults.get("config_file") - if envs.get("config_file"): - self.config_file = self._normalize_path(envs.get("config_file")) - if args.get("config_file"): - self.config_file = self._normalize_path(args.get("config_file")) - if "config_file" in defaults: - defaults.pop("config_file") - - self.base_dir = defaults.get("base_dir") - if envs.get("base_dir"): - self.base_dir = self._normalize_path(envs.get("base_dir")) - if args.get("base_dir"): - self.base_dir = self._normalize_path(args.get("base_dir")) - if base_dir: - self.base_dir = base_dir - if "base_dir" in defaults: - defaults.pop("base_dir") - - self.is_role = os.path.isdir(os.path.join(self.base_dir, "tasks")) - - # compute role_name default - defaults["role_name"] = os.path.basename(self.base_dir) - - source_files = [] - source_files.append((self.config_file, False)) - source_files.append((os.path.join(os.getcwd(), ".ansibledoctor"), True)) - source_files.append((os.path.join(os.getcwd(), ".ansibledoctor.yml"), True)) - source_files.append((os.path.join(os.getcwd(), ".ansibledoctor.yaml"), True)) - - for config, first_found in source_files: - if config and os.path.exists(config): - with open(config, encoding="utf8") as stream: - s = stream.read() - try: - file_dict = ruamel.yaml.YAML(typ="safe", pure=True).load(s) - except ( - ruamel.yaml.composer.ComposerError, - ruamel.yaml.scanner.ScannerError, - ) as e: - message = f"{e.context} {e.problem}" - raise ansibledoctor.exception.ConfigError( - f"Unable to read config file: {config}", message - ) from e - - if self._validate(file_dict): - anyconfig.merge(defaults, file_dict, ac_merge=anyconfig.MS_DICTS) - defaults["logging"]["level"] = defaults["logging"]["level"].upper() - - self.config_file = config - if first_found: - break - - if self._validate(envs): - anyconfig.merge(defaults, envs, ac_merge=anyconfig.MS_DICTS) - - if self._validate(args): - anyconfig.merge(defaults, args, ac_merge=anyconfig.MS_DICTS) - - fix_files = ["output_dir", "template_dir", "custom_header"] - for filename in fix_files: - if defaults[filename] and defaults[filename] != "": - defaults[filename] = self._normalize_path(defaults[filename]) - - defaults["logging"]["level"] = defaults["logging"]["level"].upper() - - self.config = defaults - - def _normalize_path(self, path): - if not os.path.isabs(path): - base = os.path.join(os.getcwd(), path) - return os.path.abspath(os.path.expanduser(os.path.expandvars(base))) - - return path - - def _validate(self, config): + def validate(self): try: - anyconfig.validate(config, self.schema, ac_schema_safe=False) - except jsonschema.exceptions.ValidationError as e: - schema = format_as_index(list(e.relative_schema_path)[:-1]) - schema_error = f"Failed validating '{e.validator}' in schema {schema}\n{e.message}" - raise ansibledoctor.exception.ConfigError("Configuration error", schema_error) from e + self.config.validators.validate_all() + except ValidationError as e: + raise ansibledoctor.exception.ConfigError("Configuration error", e.message) from e - return True - - def _add_dict_branch(self, tree, vector, value): - key = vector[0] - tree[key] = ( - value - if len(vector) == 1 - else self._add_dict_branch(tree.get(key, {}), vector[1:], value) + def is_role(self): + self.config.role_name = self.config.get( + "role_name", os.path.basename(self.config.base_dir) ) - return tree + return os.path.isdir(os.path.join(self.config.base_dir, "tasks")) def get_annotations_definition(self, automatic=True): annotations = {} @@ -355,9 +224,9 @@ class Config: :return: str abs path """ - template_dir = self.config.get("template_dir") - template = self.config.get("template") - return os.path.realpath(os.path.join(template_dir, template)) + template_base = self.config.get("template.src") + template_name = self.config.get("template.name") + return os.path.realpath(os.path.join(template_base, template_name)) class SingleConfig(Config, metaclass=Singleton): diff --git a/ansibledoctor/doc_generator.py b/ansibledoctor/doc_generator.py index 0b4851f..f3f5405 100644 --- a/ansibledoctor/doc_generator.py +++ b/ansibledoctor/doc_generator.py @@ -36,14 +36,14 @@ class Generator: :return: None """ - template_dir = self.config.get_template() - if os.path.isdir(template_dir): - self.logger.info(f"Using template dir: {template_dir}") + template = self.config.get_template() + if os.path.isdir(template): + self.logger.info(f"Using template: {os.path.relpath(template, self.log.ctx)}") else: - self.log.sysexit_with_message(f"Can not open template dir {template_dir}") + self.log.sysexit_with_message(f"Can not open template directory {template}") - for file in glob.iglob(template_dir + "/**/*." + self.extension, recursive=True): - relative_file = file[len(template_dir) + 1 :] + for file in glob.iglob(template + "/**/*." + self.extension, recursive=True): + relative_file = file[len(template) + 1 :] if ntpath.basename(file)[:1] != "_": self.logger.debug(f"Found template file: {relative_file}") self.template_files.append(relative_file) @@ -63,12 +63,12 @@ class Generator: for file in self.template_files: doc_file = os.path.join( - self.config.config.get("output_dir"), os.path.splitext(file)[0] + self.config.config.get("renderer.dest"), os.path.splitext(file)[0] ) if os.path.isfile(doc_file): files_to_overwite.append(doc_file) - header_file = self.config.config.get("custom_header") + header_file = self.config.config.get("renderer.include_header") role_data = self._parser.get_data() header_content = "" if bool(header_file): @@ -81,7 +81,7 @@ class Generator: if ( len(files_to_overwite) > 0 - and self.config.config.get("force_overwrite") is False + and self.config.config.get("renderer.force_overwrite") is False and not self.config.config["dry_run"] ): files_to_overwite_string = "\n".join(files_to_overwite) @@ -98,11 +98,14 @@ class Generator: for file in self.template_files: doc_file = os.path.join( - self.config.config.get("output_dir"), os.path.splitext(file)[0] + self.config.config.get("renderer.dest"), os.path.splitext(file)[0] ) source_file = self.config.get_template() + "/" + file - self.logger.debug(f"Writing doc output to: {doc_file} from: {source_file}") + self.logger.debug( + f"Writing renderer output to: {os.path.relpath(doc_file, self.log.ctx)} " + f"from: {os.path.dirname(os.path.relpath(source_file, self.log.ctx))}" + ) # make sure the directory exists self._create_dir(os.path.dirname(doc_file)) @@ -123,9 +126,9 @@ class Generator: jenv.filters["safe_join"] = self._safe_join # keep the old name of the function to not break custom templates. jenv.filters["save_join"] = self._safe_join - tabulate_vars = self.config.config.get("tabulate_variables") + template_options = self.config.config.get("template.options") data = jenv.from_string(data).render( - role_data, role=role_data, tabulate_vars=tabulate_vars + role_data, role=role_data, options=template_options ) if not self.config.config["dry_run"]: with open(doc_file, "wb") as outfile: @@ -170,12 +173,12 @@ class Generator: normalized = jinja2.filters.do_join(eval_ctx, value, d, attribute=None) - if self.config.config["template_autotrim"]: + if self.config.config.renderer.autotrim: for s in [r" +(\n|\t| )", r"(\n|\t) +"]: normalized = re.sub(s, "\\1", normalized) return jinja2.filters.do_mark_safe(normalized) def render(self): - self.logger.info(f"Using output dir: {self.config.config.get('output_dir')}") + self.logger.info(f"Using renderer destination: {self.config.config.get('renderer.dest')}") self._write_doc() diff --git a/ansibledoctor/file_registry.py b/ansibledoctor/file_registry.py index 227eb72..8edc792 100644 --- a/ansibledoctor/file_registry.py +++ b/ansibledoctor/file_registry.py @@ -21,7 +21,8 @@ class Registry: def __init__(self): self._doc = [] self.config = SingleConfig() - self.log = SingleLog().logger + self.log = SingleLog() + self.logger = self.log.logger self._scan_for_yamls() def get_files(self): @@ -35,19 +36,19 @@ class Registry: :return: None """ extensions = YAML_EXTENSIONS - base_dir = self.config.base_dir - role_name = os.path.basename(base_dir) + base_dir = self.config.config.base_dir + role_name = self.config.config.role_name excludes = self.config.config.get("exclude_files") excludespec = pathspec.PathSpec.from_lines("gitwildmatch", excludes) - self.log.debug(f"Scan for files: {base_dir}") + self.logger.debug(f"Scan for files: {os.path.relpath(base_dir,self.log.ctx)}") for extension in extensions: pattern = os.path.join(base_dir, "**/*." + extension) for filename in glob.iglob(pattern, recursive=True): if not excludespec.match_file(filename): self.log.debug( - f"Adding file to '{role_name}': {os.path.relpath(filename, base_dir)}" + f"Adding file to role '{role_name}': {os.path.relpath(filename, base_dir)}" ) self._doc.append(filename) else: diff --git a/ansibledoctor/templates/hugo-book/_toc.j2 b/ansibledoctor/templates/hugo-book/_toc.j2 index f4517da..3a39f40 100644 --- a/ansibledoctor/templates/hugo-book/_toc.j2 +++ b/ansibledoctor/templates/hugo-book/_toc.j2 @@ -2,7 +2,7 @@ {% set var = role.var | default({}) %} {% if var %} - [Default Variables](#default-variables) -{% if not tabulate_vars %} +{% if not options.tabulate_vars %} {% for key, item in var | dictsort %} - [{{ key }}](#{{ key }}) {% endfor %} diff --git a/ansibledoctor/templates/hugo-book/index.md.j2 b/ansibledoctor/templates/hugo-book/index.md.j2 index c7ae8e5..71cc24d 100644 --- a/ansibledoctor/templates/hugo-book/index.md.j2 +++ b/ansibledoctor/templates/hugo-book/index.md.j2 @@ -23,7 +23,7 @@ summary: {{ meta.summary.value | safe_join(" ") }} {% include '_requirements.j2' %} {# Vars #} -{% if tabulate_vars %} +{% if options.tabulate_vars %} {% include '_vars_tabulated.j2' %} {% else %} {% include '_vars.j2' %} diff --git a/ansibledoctor/templates/readme/README.md.j2 b/ansibledoctor/templates/readme/README.md.j2 index 7406327..ebc1aaa 100644 --- a/ansibledoctor/templates/readme/README.md.j2 +++ b/ansibledoctor/templates/readme/README.md.j2 @@ -15,7 +15,7 @@ {% include '_requirements.j2' %} {# Vars #} -{% if tabulate_vars %} +{% if options.tabulate_vars %} {% include '_vars_tabulated.j2' %} {% else %} {% include '_vars.j2' %} diff --git a/ansibledoctor/templates/readme/_toc.j2 b/ansibledoctor/templates/readme/_toc.j2 index 240652b..ef22289 100644 --- a/ansibledoctor/templates/readme/_toc.j2 +++ b/ansibledoctor/templates/readme/_toc.j2 @@ -4,7 +4,7 @@ {% set var = role.var | default({}) %} {% if var %} - [Default Variables](#default-variables) -{% if not tabulate_vars %} +{% if not options.tabulate_vars %} {% for key, item in var | dictsort %} - [{{ key }}](#{{ key }}) {% endfor %} diff --git a/ansibledoctor/utils/__init__.py b/ansibledoctor/utils/__init__.py index b65fdaa..e25a3d0 100644 --- a/ansibledoctor/utils/__init__.py +++ b/ansibledoctor/utils/__init__.py @@ -145,13 +145,10 @@ class Log: """Handle logging.""" def __init__(self, level=logging.WARNING, name="ansibledoctor", json=False): + self.ctx = os.getcwd() self.logger = logging.getLogger(name) self.logger.setLevel(level) - self.logger.addHandler(self._get_error_handler(json=json)) - self.logger.addHandler(self._get_warning_handler(json=json)) - self.logger.addHandler(self._get_info_handler(json=json)) - self.logger.addHandler(self._get_critical_handler(json=json)) - self.logger.addHandler(self._get_debug_handler(json=json)) + self.register_hanlers(json=json) self.logger.propagate = False def _get_error_handler(self, json=False): @@ -249,8 +246,24 @@ class Log: return handler + def register_hanlers(self, json=False): + """ + Enable or disable JSON logging. + + :param enable: True to enable JSON logging, False to disable + """ + # Remove all existing handlers + for handler in self.logger.handlers[:]: + self.logger.removeHandler(handler) + + self.logger.addHandler(self._get_error_handler(json=json)) + self.logger.addHandler(self._get_warning_handler(json=json)) + self.logger.addHandler(self._get_info_handler(json=json)) + self.logger.addHandler(self._get_critical_handler(json=json)) + self.logger.addHandler(self._get_debug_handler(json=json)) + def set_level(self, s): - self.logger.setLevel(s) + self.logger.setLevel(s.upper()) def debug(self, msg): """Format info messages and return string.""" diff --git a/docs/content/usage/configuration.md b/docs/content/usage/configuration.md index 2e76a79..ceef960 100644 --- a/docs/content/usage/configuration.md +++ b/docs/content/usage/configuration.md @@ -20,40 +20,17 @@ Configuration options can be set in different places, which are processed in the --- # Default is the current working directory. base_dir: -# Default is the basename of 'role_name'. -role_name: -# Auto-detect if the given directory is a role, can be disabled -# to parse loose files instead. -role_detection: True -# Don't write anything to file system + +role: + # Default is the basename of 'role_name'. + name: + # Auto-detect if the given directory is a role, can be disabled + # to parse loose files instead. + autodetect: True + +# Don't write anything to file system. dry_run: False -logging: - # Possible options debug | info | warning | error | critical - level: "warning" - # Json logging can be enabled if a parsable output is required - json: False - -# Path to write rendered template file. Default is the current working directory. -output_dir: -# Default is built-in templates directory. -template_dir: -template: readme -# By default, double spaces, spaces before and after line breaks or tab characters, etc. -# are automatically removed before the template is rendered. As a result, indenting -# with spaces does not work. If you want to use spaces to indent text, you must disable -# this option. -template_autotrim: True -# Configures whether to tabulate variables in the output. When set to `True`, -# variables will be displayed in a tabular format intsead of plain marktdown sections. -# NOTE: This option does not support rendering multiline code blocks. -tabulate_variables: False - -# Don't ask to overwrite if output file exists. -force_overwrite: False -# Load custom header from given file and append template output to it before write. -custom_header: "" - exclude_files: [] # Examples # exclude_files: @@ -63,6 +40,36 @@ exclude_files: [] # Exclude tags from automatic detection. Configured tags are only skipped # if the tag is not used in an annotation. exclude_tags: [] + +logging: + # Possible options: debug|info|warning| error|critical + level: "warning" + # JSON logging can be enabled if a parsable output is required. + json: False + +template: + name: readme + # Default is built-in templates directory. + src: + + options: + # Configures whether to tabulate variables in the output. When set to `True`, + # variables will be displayed in a tabular format intsead of plain marktdown sections. + # NOTE: This option does not support rendering multiline code blocks. + tabulate_vars: False + +renderer: + # By default, double spaces, spaces before and after line breaks or tab characters, etc. + # are automatically removed before the template is rendered. As a result, indenting + # with spaces does not work. If you want to use spaces to indent text, you must disable + # this option. + autotrim: True + # Load custom header from given file and append template output to it before write. + include_header: "" + # Path to write rendered template file. Default is the current working directory. + dest: + # Don't ask to overwrite if output file exists. + force_overwrite: False ``` ## CLI @@ -95,23 +102,25 @@ options: ## Environment Variables ```Shell -ANSIBLE_DOCTOR_CONFIG_FILE= -ANSIBLE_DOCTOR_ROLE_DETECTION=true ANSIBLE_DOCTOR_BASE_DIR= -ANSIBLE_DOCTOR_RECURSIVE=false -ANSIBLE_DOCTOR_ROLE_NAME= -ANSIBLE_DOCTOR_DRY_RUN=false -ANSIBLE_DOCTOR_LOG_LEVEL=warning -ANSIBLE_DOCTOR_LOG_JSON=false -ANSIBLE_DOCTOR_OUTPUT_DIR= -ANSIBLE_DOCTOR_TEMPLATE_DIR= -ANSIBLE_DOCTOR_TEMPLATE=readme -ANSIBLE_DOCTOR_TEMPLATE_AUTOTRIM=true -ANSIBLE_DOCTOR_TABULATE_VARIABLES=false -ANSIBLE_DOCTOR_FORCE_OVERWRITE=false -ANSIBLE_DOCTOR_CUSTOM_HEADER= +ANSIBLE_DOCTOR_DRY_RUN=False ANSIBLE_DOCTOR_EXCLUDE_FILES= -ANSIBLE_DOCTOR_EXCLUDE_FILES=molecule/,files/**/*.py +ANSIBLE_DOCTOR_EXCLUDE_TAGS= + +ANSIBLE_DOCTOR_ROLE__NAME= +ANSIBLE_DOCTOR_ROLE__AUTODETECT=True + +ANSIBLE_DOCTOR_LOGGING__LEVEL="warning" +ANSIBLE_DOCTOR_LOGGING__JSON=False + +ANSIBLE_DOCTOR_TEMPLATE__NAME=readme +ANSIBLE_DOCTOR_TEMPLATE__SRC= +ANSIBLE_DOCTOR_TEMPLATE__OPTIONS__TABULATE_VARS=False + +ANSIBLE_DOCTOR_RENDERER__AUTOTRIM=True +ANSIBLE_DOCTOR_RENDERER__INCLUDE_HEADER= +ANSIBLE_DOCTOR_RENDERER__DEST= +ANSIBLE_DOCTOR_RENDERER__FORCE_OVERWRITE=False ``` ## Pre-Commit setup diff --git a/example/demo-role/.ansibledoctor.yml b/example/demo-role/.ansibledoctor.yml index 4974bc1..9385c0d 100644 --- a/example/demo-role/.ansibledoctor.yml +++ b/example/demo-role/.ansibledoctor.yml @@ -1,5 +1,9 @@ --- -custom_header: HEADER.md logging: level: debug -template: readme + +template: + name: readme + +renderer: + include_header: HEADER.md diff --git a/example/other-role/.ansibledoctor.yml b/example/other-role/.ansibledoctor.yml index 4974bc1..9385c0d 100644 --- a/example/other-role/.ansibledoctor.yml +++ b/example/other-role/.ansibledoctor.yml @@ -1,5 +1,9 @@ --- -custom_header: HEADER.md logging: level: debug -template: readme + +template: + name: readme + +renderer: + include_header: HEADER.md diff --git a/poetry.lock b/poetry.lock index 3dcc8cb..40e246a 100644 --- a/poetry.lock +++ b/poetry.lock @@ -209,43 +209,43 @@ toml = ["tomli"] [[package]] name = "cryptography" -version = "42.0.7" +version = "42.0.8" description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers." optional = true python-versions = ">=3.7" files = [ - {file = "cryptography-42.0.7-cp37-abi3-macosx_10_12_universal2.whl", hash = "sha256:a987f840718078212fdf4504d0fd4c6effe34a7e4740378e59d47696e8dfb477"}, - {file = "cryptography-42.0.7-cp37-abi3-macosx_10_12_x86_64.whl", hash = "sha256:bd13b5e9b543532453de08bcdc3cc7cebec6f9883e886fd20a92f26940fd3e7a"}, - {file = "cryptography-42.0.7-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a79165431551042cc9d1d90e6145d5d0d3ab0f2d66326c201d9b0e7f5bf43604"}, - {file = "cryptography-42.0.7-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a47787a5e3649008a1102d3df55424e86606c9bae6fb77ac59afe06d234605f8"}, - {file = "cryptography-42.0.7-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:02c0eee2d7133bdbbc5e24441258d5d2244beb31da5ed19fbb80315f4bbbff55"}, - {file = "cryptography-42.0.7-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:5e44507bf8d14b36b8389b226665d597bc0f18ea035d75b4e53c7b1ea84583cc"}, - {file = "cryptography-42.0.7-cp37-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:7f8b25fa616d8b846aef64b15c606bb0828dbc35faf90566eb139aa9cff67af2"}, - {file = "cryptography-42.0.7-cp37-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:93a3209f6bb2b33e725ed08ee0991b92976dfdcf4e8b38646540674fc7508e13"}, - {file = "cryptography-42.0.7-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:e6b8f1881dac458c34778d0a424ae5769de30544fc678eac51c1c8bb2183e9da"}, - {file = "cryptography-42.0.7-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:3de9a45d3b2b7d8088c3fbf1ed4395dfeff79d07842217b38df14ef09ce1d8d7"}, - {file = "cryptography-42.0.7-cp37-abi3-win32.whl", hash = "sha256:789caea816c6704f63f6241a519bfa347f72fbd67ba28d04636b7c6b7da94b0b"}, - {file = "cryptography-42.0.7-cp37-abi3-win_amd64.whl", hash = "sha256:8cb8ce7c3347fcf9446f201dc30e2d5a3c898d009126010cbd1f443f28b52678"}, - {file = "cryptography-42.0.7-cp39-abi3-macosx_10_12_universal2.whl", hash = "sha256:a3a5ac8b56fe37f3125e5b72b61dcde43283e5370827f5233893d461b7360cd4"}, - {file = "cryptography-42.0.7-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:779245e13b9a6638df14641d029add5dc17edbef6ec915688f3acb9e720a5858"}, - {file = "cryptography-42.0.7-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0d563795db98b4cd57742a78a288cdbdc9daedac29f2239793071fe114f13785"}, - {file = "cryptography-42.0.7-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:31adb7d06fe4383226c3e963471f6837742889b3c4caa55aac20ad951bc8ffda"}, - {file = "cryptography-42.0.7-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:efd0bf5205240182e0f13bcaea41be4fdf5c22c5129fc7ced4a0282ac86998c9"}, - {file = "cryptography-42.0.7-cp39-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:a9bc127cdc4ecf87a5ea22a2556cab6c7eda2923f84e4f3cc588e8470ce4e42e"}, - {file = "cryptography-42.0.7-cp39-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:3577d029bc3f4827dd5bf8bf7710cac13527b470bbf1820a3f394adb38ed7d5f"}, - {file = "cryptography-42.0.7-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:2e47577f9b18723fa294b0ea9a17d5e53a227867a0a4904a1a076d1646d45ca1"}, - {file = "cryptography-42.0.7-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:1a58839984d9cb34c855197043eaae2c187d930ca6d644612843b4fe8513c886"}, - {file = "cryptography-42.0.7-cp39-abi3-win32.whl", hash = "sha256:e6b79d0adb01aae87e8a44c2b64bc3f3fe59515280e00fb6d57a7267a2583cda"}, - {file = "cryptography-42.0.7-cp39-abi3-win_amd64.whl", hash = "sha256:16268d46086bb8ad5bf0a2b5544d8a9ed87a0e33f5e77dd3c3301e63d941a83b"}, - {file = "cryptography-42.0.7-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:2954fccea107026512b15afb4aa664a5640cd0af630e2ee3962f2602693f0c82"}, - {file = "cryptography-42.0.7-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:362e7197754c231797ec45ee081f3088a27a47c6c01eff2ac83f60f85a50fe60"}, - {file = "cryptography-42.0.7-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:4f698edacf9c9e0371112792558d2f705b5645076cc0aaae02f816a0171770fd"}, - {file = "cryptography-42.0.7-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:5482e789294854c28237bba77c4c83be698be740e31a3ae5e879ee5444166582"}, - {file = "cryptography-42.0.7-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:e9b2a6309f14c0497f348d08a065d52f3020656f675819fc405fb63bbcd26562"}, - {file = "cryptography-42.0.7-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:d8e3098721b84392ee45af2dd554c947c32cc52f862b6a3ae982dbb90f577f14"}, - {file = "cryptography-42.0.7-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:c65f96dad14f8528a447414125e1fc8feb2ad5a272b8f68477abbcc1ea7d94b9"}, - {file = "cryptography-42.0.7-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:36017400817987670037fbb0324d71489b6ead6231c9604f8fc1f7d008087c68"}, - {file = "cryptography-42.0.7.tar.gz", hash = "sha256:ecbfbc00bf55888edda9868a4cf927205de8499e7fabe6c050322298382953f2"}, + {file = "cryptography-42.0.8-cp37-abi3-macosx_10_12_universal2.whl", hash = "sha256:81d8a521705787afe7a18d5bfb47ea9d9cc068206270aad0b96a725022e18d2e"}, + {file = "cryptography-42.0.8-cp37-abi3-macosx_10_12_x86_64.whl", hash = "sha256:961e61cefdcb06e0c6d7e3a1b22ebe8b996eb2bf50614e89384be54c48c6b63d"}, + {file = "cryptography-42.0.8-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e3ec3672626e1b9e55afd0df6d774ff0e953452886e06e0f1eb7eb0c832e8902"}, + {file = "cryptography-42.0.8-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e599b53fd95357d92304510fb7bda8523ed1f79ca98dce2f43c115950aa78801"}, + {file = "cryptography-42.0.8-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:5226d5d21ab681f432a9c1cf8b658c0cb02533eece706b155e5fbd8a0cdd3949"}, + {file = "cryptography-42.0.8-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:6b7c4f03ce01afd3b76cf69a5455caa9cfa3de8c8f493e0d3ab7d20611c8dae9"}, + {file = "cryptography-42.0.8-cp37-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:2346b911eb349ab547076f47f2e035fc8ff2c02380a7cbbf8d87114fa0f1c583"}, + {file = "cryptography-42.0.8-cp37-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:ad803773e9df0b92e0a817d22fd8a3675493f690b96130a5e24f1b8fabbea9c7"}, + {file = "cryptography-42.0.8-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:2f66d9cd9147ee495a8374a45ca445819f8929a3efcd2e3df6428e46c3cbb10b"}, + {file = "cryptography-42.0.8-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:d45b940883a03e19e944456a558b67a41160e367a719833c53de6911cabba2b7"}, + {file = "cryptography-42.0.8-cp37-abi3-win32.whl", hash = "sha256:a0c5b2b0585b6af82d7e385f55a8bc568abff8923af147ee3c07bd8b42cda8b2"}, + {file = "cryptography-42.0.8-cp37-abi3-win_amd64.whl", hash = "sha256:57080dee41209e556a9a4ce60d229244f7a66ef52750f813bfbe18959770cfba"}, + {file = "cryptography-42.0.8-cp39-abi3-macosx_10_12_universal2.whl", hash = "sha256:dea567d1b0e8bc5764b9443858b673b734100c2871dc93163f58c46a97a83d28"}, + {file = "cryptography-42.0.8-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c4783183f7cb757b73b2ae9aed6599b96338eb957233c58ca8f49a49cc32fd5e"}, + {file = "cryptography-42.0.8-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a0608251135d0e03111152e41f0cc2392d1e74e35703960d4190b2e0f4ca9c70"}, + {file = "cryptography-42.0.8-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:dc0fdf6787f37b1c6b08e6dfc892d9d068b5bdb671198c72072828b80bd5fe4c"}, + {file = "cryptography-42.0.8-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:9c0c1716c8447ee7dbf08d6db2e5c41c688544c61074b54fc4564196f55c25a7"}, + {file = "cryptography-42.0.8-cp39-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:fff12c88a672ab9c9c1cf7b0c80e3ad9e2ebd9d828d955c126be4fd3e5578c9e"}, + {file = "cryptography-42.0.8-cp39-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:cafb92b2bc622cd1aa6a1dce4b93307792633f4c5fe1f46c6b97cf67073ec961"}, + {file = "cryptography-42.0.8-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:31f721658a29331f895a5a54e7e82075554ccfb8b163a18719d342f5ffe5ecb1"}, + {file = "cryptography-42.0.8-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:b297f90c5723d04bcc8265fc2a0f86d4ea2e0f7ab4b6994459548d3a6b992a14"}, + {file = "cryptography-42.0.8-cp39-abi3-win32.whl", hash = "sha256:2f88d197e66c65be5e42cd72e5c18afbfae3f741742070e3019ac8f4ac57262c"}, + {file = "cryptography-42.0.8-cp39-abi3-win_amd64.whl", hash = "sha256:fa76fbb7596cc5839320000cdd5d0955313696d9511debab7ee7278fc8b5c84a"}, + {file = "cryptography-42.0.8-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:ba4f0a211697362e89ad822e667d8d340b4d8d55fae72cdd619389fb5912eefe"}, + {file = "cryptography-42.0.8-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:81884c4d096c272f00aeb1f11cf62ccd39763581645b0812e99a91505fa48e0c"}, + {file = "cryptography-42.0.8-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:c9bb2ae11bfbab395bdd072985abde58ea9860ed84e59dbc0463a5d0159f5b71"}, + {file = "cryptography-42.0.8-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:7016f837e15b0a1c119d27ecd89b3515f01f90a8615ed5e9427e30d9cdbfed3d"}, + {file = "cryptography-42.0.8-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:5a94eccb2a81a309806027e1670a358b99b8fe8bfe9f8d329f27d72c094dde8c"}, + {file = "cryptography-42.0.8-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:dec9b018df185f08483f294cae6ccac29e7a6e0678996587363dc352dc65c842"}, + {file = "cryptography-42.0.8-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:343728aac38decfdeecf55ecab3264b015be68fc2816ca800db649607aeee648"}, + {file = "cryptography-42.0.8-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:013629ae70b40af70c9a7a5db40abe5d9054e6f4380e50ce769947b73bf3caad"}, + {file = "cryptography-42.0.8.tar.gz", hash = "sha256:8d09d05439ce7baa8e9e95b07ec5b6c886f548deb7e0f69ef25f64b3bce842f2"}, ] [package.dependencies] @@ -261,6 +261,27 @@ ssh = ["bcrypt (>=3.1.5)"] test = ["certifi", "pretend", "pytest (>=6.2.0)", "pytest-benchmark", "pytest-cov", "pytest-xdist"] test-randomorder = ["pytest-randomly"] +[[package]] +name = "dynaconf" +version = "3.2.5" +description = "The dynamic configurator for your Python Project" +optional = false +python-versions = ">=3.8" +files = [ + {file = "dynaconf-3.2.5-py2.py3-none-any.whl", hash = "sha256:12202fc26546851c05d4194c80bee00197e7c2febcb026e502b0863be9cbbdd8"}, + {file = "dynaconf-3.2.5.tar.gz", hash = "sha256:42c8d936b32332c4b84e4d4df6dd1626b6ef59c5a94eb60c10cd3c59d6b882f2"}, +] + +[package.extras] +all = ["configobj", "hvac", "redis", "ruamel.yaml"] +configobj = ["configobj"] +ini = ["configobj"] +redis = ["redis"] +test = ["configobj", "django", "flask (>=0.12)", "hvac (>=1.1.0)", "pytest", "pytest-cov", "pytest-mock", "pytest-xdist", "python-dotenv", "radon", "redis", "toml"] +toml = ["toml"] +vault = ["hvac"] +yaml = ["ruamel.yaml"] + [[package]] name = "environs" version = "11.0.0" @@ -637,14 +658,24 @@ cli = ["click (>=5.0)"] [[package]] name = "python-json-logger" -version = "2.0.7" -description = "A python library adding a json log formatter" +version = "3.1.0" +description = "JSON Log Formatter for the Python Logging Package" optional = false -python-versions = ">=3.6" -files = [ - {file = "python-json-logger-2.0.7.tar.gz", hash = "sha256:23e7ec02d34237c5aa1e29a070193a4ea87583bb4e7f8fd06d3de8264c4b2e1c"}, - {file = "python_json_logger-2.0.7-py3-none-any.whl", hash = "sha256:f380b826a991ebbe3de4d897aeec42760035ac760345e57b812938dc8b35e2bd"}, -] +python-versions = ">=3.8" +files = [] +develop = false + +[package.dependencies] +typing-extensions = "*" + +[package.extras] +dev = ["backports.zoneinfo", "black", "build", "freezegun", "mdx-truly-sane-lists", "mike", "mkdocs", "mkdocs-awesome-pages-plugin", "mkdocs-gen-files", "mkdocs-literate-nav", "mkdocs-material (>=8.5)", "mkdocstrings[python]", "msgspec", "mypy", "orjson", "pylint", "pytest", "tzdata", "validate-pyproject[all]"] + +[package.source] +type = "git" +url = "https://github.com/nhairs/python-json-logger.git" +reference = "v3.1.0" +resolved_reference = "e2b40e420f4181fd921b01a2fd0b23ca82b5fc9b" [[package]] name = "pyyaml" @@ -658,7 +689,6 @@ files = [ {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:69b023b2b4daa7548bcfbd4aa3da05b3a74b772db9e23b982788168117739938"}, {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:81e0b275a9ecc9c0c0c07b4b90ba548307583c125f54d5b6946cfee6360c733d"}, {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba336e390cd8e4d1739f42dfe9bb83a3cc2e80f567d8805e11b46f4a943f5515"}, - {file = "PyYAML-6.0.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:326c013efe8048858a6d312ddd31d56e468118ad4cdeda36c719bf5bb6192290"}, {file = "PyYAML-6.0.1-cp310-cp310-win32.whl", hash = "sha256:bd4af7373a854424dabd882decdc5579653d7868b8fb26dc7d0e99f823aa5924"}, {file = "PyYAML-6.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:fd1592b3fdf65fff2ad0004b5e363300ef59ced41c2e6b3a99d4089fa8c5435d"}, {file = "PyYAML-6.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6965a7bc3cf88e5a1c3bd2e0b5c22f8d677dc88a455344035f03399034eb3007"}, @@ -666,16 +696,8 @@ files = [ {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:42f8152b8dbc4fe7d96729ec2b99c7097d656dc1213a3229ca5383f973a5ed6d"}, {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:062582fca9fabdd2c8b54a3ef1c978d786e0f6b3a1510e0ac93ef59e0ddae2bc"}, {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d2b04aac4d386b172d5b9692e2d2da8de7bfb6c387fa4f801fbf6fb2e6ba4673"}, - {file = "PyYAML-6.0.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e7d73685e87afe9f3b36c799222440d6cf362062f78be1013661b00c5c6f678b"}, {file = "PyYAML-6.0.1-cp311-cp311-win32.whl", hash = "sha256:1635fd110e8d85d55237ab316b5b011de701ea0f29d07611174a1b42f1444741"}, {file = "PyYAML-6.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34"}, - {file = "PyYAML-6.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28"}, - {file = "PyYAML-6.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9"}, - {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a08c6f0fe150303c1c6b71ebcd7213c2858041a7e01975da3a99aed1e7a378ef"}, - {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0"}, - {file = "PyYAML-6.0.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4"}, - {file = "PyYAML-6.0.1-cp312-cp312-win32.whl", hash = "sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54"}, - {file = "PyYAML-6.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:0d3304d8c0adc42be59c5f8a4d9e3d7379e6955ad754aa9d6ab7a398b59dd1df"}, {file = "PyYAML-6.0.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:50550eb667afee136e9a77d6dc71ae76a44df8b3e51e41b77f6de2932bfe0f47"}, {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1fe35611261b29bd1de0070f0b2f47cb6ff71fa6595c077e42bd0c419fa27b98"}, {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:704219a11b772aea0d8ecd7058d0082713c3562b4e271b849ad7dc4a5c90c13c"}, @@ -692,7 +714,6 @@ files = [ {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a0cd17c15d3bb3fa06978b4e8958dcdc6e0174ccea823003a106c7d4d7899ac5"}, {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:28c119d996beec18c05208a8bd78cbe4007878c6dd15091efb73a30e90539696"}, {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7e07cbde391ba96ab58e532ff4803f79c4129397514e1413a7dc761ccd755735"}, - {file = "PyYAML-6.0.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:49a183be227561de579b4a36efbb21b3eab9651dd81b1858589f796549873dd6"}, {file = "PyYAML-6.0.1-cp38-cp38-win32.whl", hash = "sha256:184c5108a2aca3c5b3d3bf9395d50893a7ab82a38004c8f61c258d4428e80206"}, {file = "PyYAML-6.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:1e2722cc9fbb45d9b87631ac70924c11d3a401b2d7f410cc0e3bbf249f2dca62"}, {file = "PyYAML-6.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9eb6caa9a297fc2c2fb8862bc5370d0303ddba53ba97e71f08023b6cd73d16a8"}, @@ -700,7 +721,6 @@ files = [ {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5773183b6446b2c99bb77e77595dd486303b4faab2b086e7b17bc6bef28865f6"}, {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b786eecbdf8499b9ca1d697215862083bd6d2a99965554781d0d8d1ad31e13a0"}, {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc1bf2925a1ecd43da378f4db9e4f799775d6367bdb94671027b73b393a7c42c"}, - {file = "PyYAML-6.0.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:04ac92ad1925b2cff1db0cfebffb6ffc43457495c9b3c39d3fcae417d7125dc5"}, {file = "PyYAML-6.0.1-cp39-cp39-win32.whl", hash = "sha256:faca3bdcf85b2fc05d06ff3fbc1f83e1391b3e724afa3feba7d13eeab355484c"}, {file = "PyYAML-6.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:510c9deebc5c0225e8c96813043e62b680ba2f9c50a08d3724c7f28a747d1486"}, {file = "PyYAML-6.0.1.tar.gz", hash = "sha256:bfdf460b1736c775f2ba9f6a92bca30bc2095067b8a9d77876d1fad6cc3b4a43"}, @@ -891,51 +911,37 @@ python-versions = ">=3.6" files = [ {file = "ruamel.yaml.clib-0.2.8-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:b42169467c42b692c19cf539c38d4602069d8c1505e97b86387fcf7afb766e1d"}, {file = "ruamel.yaml.clib-0.2.8-cp310-cp310-macosx_13_0_arm64.whl", hash = "sha256:07238db9cbdf8fc1e9de2489a4f68474e70dffcb32232db7c08fa61ca0c7c462"}, + {file = "ruamel.yaml.clib-0.2.8-cp310-cp310-manylinux2014_aarch64.whl", hash = "sha256:d92f81886165cb14d7b067ef37e142256f1c6a90a65cd156b063a43da1708cfd"}, {file = "ruamel.yaml.clib-0.2.8-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:fff3573c2db359f091e1589c3d7c5fc2f86f5bdb6f24252c2d8e539d4e45f412"}, - {file = "ruamel.yaml.clib-0.2.8-cp310-cp310-manylinux_2_24_aarch64.whl", hash = "sha256:aa2267c6a303eb483de8d02db2871afb5c5fc15618d894300b88958f729ad74f"}, - {file = "ruamel.yaml.clib-0.2.8-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:840f0c7f194986a63d2c2465ca63af8ccbbc90ab1c6001b1978f05119b5e7334"}, - {file = "ruamel.yaml.clib-0.2.8-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:024cfe1fc7c7f4e1aff4a81e718109e13409767e4f871443cbff3dba3578203d"}, {file = "ruamel.yaml.clib-0.2.8-cp310-cp310-win32.whl", hash = "sha256:c69212f63169ec1cfc9bb44723bf2917cbbd8f6191a00ef3410f5a7fe300722d"}, {file = "ruamel.yaml.clib-0.2.8-cp310-cp310-win_amd64.whl", hash = "sha256:cabddb8d8ead485e255fe80429f833172b4cadf99274db39abc080e068cbcc31"}, {file = "ruamel.yaml.clib-0.2.8-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:bef08cd86169d9eafb3ccb0a39edb11d8e25f3dae2b28f5c52fd997521133069"}, {file = "ruamel.yaml.clib-0.2.8-cp311-cp311-macosx_13_0_arm64.whl", hash = "sha256:b16420e621d26fdfa949a8b4b47ade8810c56002f5389970db4ddda51dbff248"}, + {file = "ruamel.yaml.clib-0.2.8-cp311-cp311-manylinux2014_aarch64.whl", hash = "sha256:b5edda50e5e9e15e54a6a8a0070302b00c518a9d32accc2346ad6c984aacd279"}, {file = "ruamel.yaml.clib-0.2.8-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:25c515e350e5b739842fc3228d662413ef28f295791af5e5110b543cf0b57d9b"}, - {file = "ruamel.yaml.clib-0.2.8-cp311-cp311-manylinux_2_24_aarch64.whl", hash = "sha256:1707814f0d9791df063f8c19bb51b0d1278b8e9a2353abbb676c2f685dee6afe"}, - {file = "ruamel.yaml.clib-0.2.8-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:46d378daaac94f454b3a0e3d8d78cafd78a026b1d71443f4966c696b48a6d899"}, - {file = "ruamel.yaml.clib-0.2.8-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:09b055c05697b38ecacb7ac50bdab2240bfca1a0c4872b0fd309bb07dc9aa3a9"}, {file = "ruamel.yaml.clib-0.2.8-cp311-cp311-win32.whl", hash = "sha256:53a300ed9cea38cf5a2a9b069058137c2ca1ce658a874b79baceb8f892f915a7"}, {file = "ruamel.yaml.clib-0.2.8-cp311-cp311-win_amd64.whl", hash = "sha256:c2a72e9109ea74e511e29032f3b670835f8a59bbdc9ce692c5b4ed91ccf1eedb"}, {file = "ruamel.yaml.clib-0.2.8-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:ebc06178e8821efc9692ea7544aa5644217358490145629914d8020042c24aa1"}, {file = "ruamel.yaml.clib-0.2.8-cp312-cp312-macosx_13_0_arm64.whl", hash = "sha256:edaef1c1200c4b4cb914583150dcaa3bc30e592e907c01117c08b13a07255ec2"}, + {file = "ruamel.yaml.clib-0.2.8-cp312-cp312-manylinux2014_aarch64.whl", hash = "sha256:7048c338b6c86627afb27faecf418768acb6331fc24cfa56c93e8c9780f815fa"}, {file = "ruamel.yaml.clib-0.2.8-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d176b57452ab5b7028ac47e7b3cf644bcfdc8cacfecf7e71759f7f51a59e5c92"}, - {file = "ruamel.yaml.clib-0.2.8-cp312-cp312-manylinux_2_24_aarch64.whl", hash = "sha256:1dc67314e7e1086c9fdf2680b7b6c2be1c0d8e3a8279f2e993ca2a7545fecf62"}, - {file = "ruamel.yaml.clib-0.2.8-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:3213ece08ea033eb159ac52ae052a4899b56ecc124bb80020d9bbceeb50258e9"}, - {file = "ruamel.yaml.clib-0.2.8-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:aab7fd643f71d7946f2ee58cc88c9b7bfc97debd71dcc93e03e2d174628e7e2d"}, - {file = "ruamel.yaml.clib-0.2.8-cp312-cp312-win32.whl", hash = "sha256:5c365d91c88390c8d0a8545df0b5857172824b1c604e867161e6b3d59a827eaa"}, - {file = "ruamel.yaml.clib-0.2.8-cp312-cp312-win_amd64.whl", hash = "sha256:1758ce7d8e1a29d23de54a16ae867abd370f01b5a69e1a3ba75223eaa3ca1a1b"}, {file = "ruamel.yaml.clib-0.2.8-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:a5aa27bad2bb83670b71683aae140a1f52b0857a2deff56ad3f6c13a017a26ed"}, {file = "ruamel.yaml.clib-0.2.8-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:c58ecd827313af6864893e7af0a3bb85fd529f862b6adbefe14643947cfe2942"}, {file = "ruamel.yaml.clib-0.2.8-cp37-cp37m-macosx_12_0_arm64.whl", hash = "sha256:f481f16baec5290e45aebdc2a5168ebc6d35189ae6fea7a58787613a25f6e875"}, - {file = "ruamel.yaml.clib-0.2.8-cp37-cp37m-manylinux_2_24_aarch64.whl", hash = "sha256:77159f5d5b5c14f7c34073862a6b7d34944075d9f93e681638f6d753606c6ce6"}, + {file = "ruamel.yaml.clib-0.2.8-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:3fcc54cb0c8b811ff66082de1680b4b14cf8a81dce0d4fbf665c2265a81e07a1"}, {file = "ruamel.yaml.clib-0.2.8-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:7f67a1ee819dc4562d444bbafb135832b0b909f81cc90f7aa00260968c9ca1b3"}, - {file = "ruamel.yaml.clib-0.2.8-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:4ecbf9c3e19f9562c7fdd462e8d18dd902a47ca046a2e64dba80699f0b6c09b7"}, - {file = "ruamel.yaml.clib-0.2.8-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:87ea5ff66d8064301a154b3933ae406b0863402a799b16e4a1d24d9fbbcbe0d3"}, {file = "ruamel.yaml.clib-0.2.8-cp37-cp37m-win32.whl", hash = "sha256:75e1ed13e1f9de23c5607fe6bd1aeaae21e523b32d83bb33918245361e9cc51b"}, {file = "ruamel.yaml.clib-0.2.8-cp37-cp37m-win_amd64.whl", hash = "sha256:3f215c5daf6a9d7bbed4a0a4f760f3113b10e82ff4c5c44bec20a68c8014f675"}, {file = "ruamel.yaml.clib-0.2.8-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1b617618914cb00bf5c34d4357c37aa15183fa229b24767259657746c9077615"}, {file = "ruamel.yaml.clib-0.2.8-cp38-cp38-macosx_12_0_arm64.whl", hash = "sha256:a6a9ffd280b71ad062eae53ac1659ad86a17f59a0fdc7699fd9be40525153337"}, - {file = "ruamel.yaml.clib-0.2.8-cp38-cp38-manylinux_2_24_aarch64.whl", hash = "sha256:305889baa4043a09e5b76f8e2a51d4ffba44259f6b4c72dec8ca56207d9c6fe1"}, + {file = "ruamel.yaml.clib-0.2.8-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:665f58bfd29b167039f714c6998178d27ccd83984084c286110ef26b230f259f"}, {file = "ruamel.yaml.clib-0.2.8-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:700e4ebb569e59e16a976857c8798aee258dceac7c7d6b50cab63e080058df91"}, - {file = "ruamel.yaml.clib-0.2.8-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:e2b4c44b60eadec492926a7270abb100ef9f72798e18743939bdbf037aab8c28"}, - {file = "ruamel.yaml.clib-0.2.8-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:e79e5db08739731b0ce4850bed599235d601701d5694c36570a99a0c5ca41a9d"}, {file = "ruamel.yaml.clib-0.2.8-cp38-cp38-win32.whl", hash = "sha256:955eae71ac26c1ab35924203fda6220f84dce57d6d7884f189743e2abe3a9fbe"}, {file = "ruamel.yaml.clib-0.2.8-cp38-cp38-win_amd64.whl", hash = "sha256:56f4252222c067b4ce51ae12cbac231bce32aee1d33fbfc9d17e5b8d6966c312"}, {file = "ruamel.yaml.clib-0.2.8-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:03d1162b6d1df1caa3a4bd27aa51ce17c9afc2046c31b0ad60a0a96ec22f8001"}, {file = "ruamel.yaml.clib-0.2.8-cp39-cp39-macosx_12_0_arm64.whl", hash = "sha256:bba64af9fa9cebe325a62fa398760f5c7206b215201b0ec825005f1b18b9bccf"}, - {file = "ruamel.yaml.clib-0.2.8-cp39-cp39-manylinux_2_24_aarch64.whl", hash = "sha256:a1a45e0bb052edf6a1d3a93baef85319733a888363938e1fc9924cb00c8df24c"}, + {file = "ruamel.yaml.clib-0.2.8-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:9eb5dee2772b0f704ca2e45b1713e4e5198c18f515b52743576d196348f374d3"}, {file = "ruamel.yaml.clib-0.2.8-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:da09ad1c359a728e112d60116f626cc9f29730ff3e0e7db72b9a2dbc2e4beed5"}, - {file = "ruamel.yaml.clib-0.2.8-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:184565012b60405d93838167f425713180b949e9d8dd0bbc7b49f074407c5a8b"}, - {file = "ruamel.yaml.clib-0.2.8-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:a75879bacf2c987c003368cf14bed0ffe99e8e85acfa6c0bfffc21a090f16880"}, {file = "ruamel.yaml.clib-0.2.8-cp39-cp39-win32.whl", hash = "sha256:84b554931e932c46f94ab306913ad7e11bba988104c5cff26d90d03f68258cd5"}, {file = "ruamel.yaml.clib-0.2.8-cp39-cp39-win_amd64.whl", hash = "sha256:25ac8c08322002b06fa1d49d1646181f0b2c72f5cbc15a85e80b4c30a544bb15"}, {file = "ruamel.yaml.clib-0.2.8.tar.gz", hash = "sha256:beb2e0404003de9a4cab9753a8805a8fe9320ee6673136ed7f04255fe60bb512"}, @@ -989,10 +995,21 @@ files = [ {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"}, ] +[[package]] +name = "typing-extensions" +version = "4.12.1" +description = "Backported and Experimental Type Hints for Python 3.8+" +optional = false +python-versions = ">=3.8" +files = [ + {file = "typing_extensions-4.12.1-py3-none-any.whl", hash = "sha256:6024b58b69089e5a89c347397254e35f1bf02a907728ec7fee9bf0fe837d203a"}, + {file = "typing_extensions-4.12.1.tar.gz", hash = "sha256:915f5e35ff76f56588223f15fdd5938f9a1cf9195c0de25130c627e4d597f6d1"}, +] + [extras] ansible-core = ["ansible-core"] [metadata] lock-version = "2.0" python-versions = "^3.9.0" -content-hash = "fe371a30a9ad68f7aea83715fa476b69156254aa79658db529990a692f4df89d" +content-hash = "7836ddcc834dcd41e84f8f4fbf583495bad4c72e8e831d68af607f5e4df79f0e" diff --git a/pyproject.toml b/pyproject.toml index 2027215..823ba13 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -39,8 +39,9 @@ environs = "11.0.0" jsonschema = "4.22.0" pathspec = "0.12.1" python = "^3.9.0" -python-json-logger = "2.0.7" +python-json-logger = { git = "https://github.com/nhairs/python-json-logger.git", tag = "v3.1.0" } "ruamel.yaml" = "0.18.6" +dynaconf = "3.2.5" ansible-core = { version = "2.14.17", optional = true } [tool.poetry.extras]