From 60dc4ec4be96f4a38913ff45592446b6bb446669 Mon Sep 17 00:00:00 2001 From: Chris Granados- Xian Date: Sun, 11 Aug 2024 11:11:59 -0300 Subject: [PATCH] Adds tokens and rules validations. Refactor save_session --- src/vfxnaming/error.py | 4 ++++ src/vfxnaming/naming.py | 52 +++++++++++++++++++++++++++-------------- src/vfxnaming/rules.py | 27 ++++++++++++++++++++- src/vfxnaming/tokens.py | 12 ++++++++++ 4 files changed, 77 insertions(+), 18 deletions(-) diff --git a/src/vfxnaming/error.py b/src/vfxnaming/error.py index b4942ac..12b356b 100644 --- a/src/vfxnaming/error.py +++ b/src/vfxnaming/error.py @@ -10,5 +10,9 @@ class TokenError(BaseException): """Raise when Token errors are detected.""" +class RuleError(BaseException): + """Raise when Rule errors are detected.""" + + class RepoError(BaseException): """Raise when Repo errors are detected.""" diff --git a/src/vfxnaming/naming.py b/src/vfxnaming/naming.py index 8f58406..c46baec 100644 --- a/src/vfxnaming/naming.py +++ b/src/vfxnaming/naming.py @@ -19,6 +19,8 @@ import os import re import json +import traceback +import shutil import vfxnaming.rules as rules import vfxnaming.tokens as tokens from pathlib import Path @@ -138,7 +140,7 @@ def validate_repo(repo: Path) -> bool: Returns: bool: True if valid, False otherwise. """ - config_file = repo / "naming.conf" + config_file = repo / "vfxnaming.conf" if not config_file.exists(): return False return True @@ -238,39 +240,55 @@ def get_repo(force_repo: Union[Path, str] = None) -> Path: raise RepoError(f"VFXNaming repo directory doesn't exist: {root}") -def save_session(repo: Union[Path, None] = None) -> bool: +def save_session(repo: Union[Path, None] = None, override=True): """Save rules, tokens and config files to the repository. Raises: - IOError, OSError: Repository directory could not be created. + RepoError: Repository directory could not be created or is not valid. + + TokenError: Not required tokens must have at least one option (fullname=abbreviation). + + TemplateError: Template patterns are not valid. Args: - repo (Path, optional): Absolue path to a repository. Defaults to None. + ``repo`` (str, optional): Path to a repository. Defaults to None. + + ``override`` (bool, optional): If True, it'll remove given directory and recreate it. Returns: - bool: True if saving session operation was successful. + [bool]: True if saving session operation was successful. """ - repo: Path = repo or get_repo() + # Validations + rules.validate_rules() + tokens.validate_tokens() + + repo = repo or get_repo() + if override: + try: + shutil.rmtree(repo) + except (IOError, OSError) as why: + raise RepoError(why, traceback.format_exc()) if not repo.exists(): try: - repo.mkdir(parents=True) + os.mkdir(repo) except (IOError, OSError) as why: - raise why - # save tokens + raise RepoError(why, traceback.format_exc()) + + # Save tokens for name, token in tokens.get_tokens().items(): - logger.debug(f"Saving token: '{name}' in {repo}") + logger.debug(f"Saving token: {name} in {repo}") tokens.save_token(name, repo) - # save rules - for name, rule in rules.get_rules().items(): - if not isinstance(rule, rules.Rule): + # Save rules + for name, template in rules.get_rules().items(): + if not isinstance(template, rules.Rule): continue - logger.debug(f"Saving rule: '{name}' in {repo}") + logger.debug(f"Saving template: {name} in {repo}") rules.save_rule(name, repo) # extra configuration active = rules.get_active_rule() - config = {"set_active_rule": active.name if active else None} - filepath = repo / "naming.conf" - logger.debug(f"Saving active rule: {active.name} in {filepath}") + config = {"set_active_template": active.name if active else None} + filepath = os.path.join(repo, "vfxnaming.conf") + logger.debug(f"Saving active template: {active.name} in {filepath}") with open(filepath, "w") as fp: json.dump(config, fp, indent=4) return True diff --git a/src/vfxnaming/rules.py b/src/vfxnaming/rules.py index df6be1c..213ddb5 100644 --- a/src/vfxnaming/rules.py +++ b/src/vfxnaming/rules.py @@ -9,7 +9,7 @@ from vfxnaming.serialize import Serializable from vfxnaming.tokens import get_token from vfxnaming.logger import logger -from vfxnaming.error import ParsingError, SolvingError +from vfxnaming.error import ParsingError, SolvingError, RuleError _rules = {"_active": None} @@ -372,6 +372,31 @@ def set_active_rule(name: AnyStr) -> bool: return False +def validate_rule_pattern(name): + """Validates rule pattern is not empty. + + Args: + name (str): The name of the rule to validate its pattern. + + Returns: + bool: True if successful, False otherwise. + """ + if has_rule(name): + template_obj = get_rule(name) + if len(template_obj.pattern) >= 1: + return True + return False + + +def validate_rules(): + not_valid = [] + for name, template in get_rules().items(): + if not validate_rule_pattern(name): + not_valid.append(name) + if len(not_valid) >= 1: + raise RuleError(f"Rules {', '.join(not_valid)}: Patterns are not valid.") + + def get_rule(name: AnyStr) -> Rule: """Gets Rule object with given name. diff --git a/src/vfxnaming/tokens.py b/src/vfxnaming/tokens.py index 26d7934..d7f52b3 100644 --- a/src/vfxnaming/tokens.py +++ b/src/vfxnaming/tokens.py @@ -445,6 +445,18 @@ def get_tokens() -> Dict: return _tokens +def validate_tokens(): + not_valid = list() + for name, token_obj in get_tokens().items(): + if not token_obj.required and len(token_obj.options) == 0: + not_valid.append(name) + if len(not_valid) >= 1: + raise TokenError( + f"Tokens {', '.join(not_valid)}: Not required tokens must " + "have at least one option (fullname=abbreviation)." + ) + + def save_token(name: AnyStr, directory: Path) -> bool: """Saves given token serialized to specified location.