import logging, re from pathlib import Path from openpyxl import load_workbook from backend.db.models import BasicSubmission, SubmissionType from tools import jinja_template_loading from jinja2 import Template logger = logging.getLogger(f"submissions.{__name__}") class RSLNamer(object): """ Object that will enforce proper formatting on RSL plate names. """ def __init__(self, filename:str, sub_type:str|None=None, data:dict|None=None): self.submission_type = sub_type if self.submission_type == None: # logger.debug("Creating submission type because none exists") self.submission_type = self.retrieve_submission_type(filename=filename) logger.debug(f"got submission type: {self.submission_type}") if self.submission_type != None: # logger.debug("Retrieving BasicSubmission subclass") enforcer = BasicSubmission.find_polymorphic_subclass(polymorphic_identity=self.submission_type) self.parsed_name = self.retrieve_rsl_number(filename=filename, regex=enforcer.get_regex()) if data == None: data = dict(submission_type=self.submission_type) if "submission_type" not in data.keys(): data['submission_type'] = self.submission_type self.parsed_name = enforcer.enforce_name(instr=self.parsed_name, data=data) @classmethod def retrieve_submission_type(cls, filename:str|Path) -> str: """ Gets submission type from excel file properties or sheet names or regex pattern match or user input Args: filename (str | Path): filename Returns: str: parsed submission type """ match filename: case Path(): logger.debug(f"Using path method for {filename}.") if filename.exists(): wb = load_workbook(filename) try: submission_type = [item.strip().title() for item in wb.properties.category.split(";")][0] except AttributeError: try: sts = {item.name:item.get_template_file_sheets() for item in SubmissionType.query()} for k,v in sts.items(): # This gets the *first* submission type that matches the sheet names in the workbook if wb.sheetnames == v: submission_type = k.title() break except: # On failure recurse using filename as string for string method submission_type = cls.retrieve_submission_type(filename=filename.stem.__str__()) else: submission_type = cls.retrieve_submission_type(filename=filename.stem.__str__()) case str(): regex = BasicSubmission.construct_regex() logger.debug(f"Using string method for {filename}.") m = regex.search(filename) try: submission_type = m.lastgroup except AttributeError as e: logger.critical("No RSL plate number found or submission type found!") case _: submission_type = None try: check = submission_type == None except UnboundLocalError: check = True if check: # logger.debug("Final option, ask the user for submission type") from frontend.widgets import SubmissionTypeSelector dlg = SubmissionTypeSelector(title="Couldn't parse submission type.", message="Please select submission type from list below.") if dlg.exec(): submission_type = dlg.parse_form() submission_type = submission_type.replace("_", " ") return submission_type @classmethod def retrieve_rsl_number(cls, filename:str|Path, regex:str|None=None): """ Uses regex to retrieve the plate number and submission type from an input string Args: in_str (str): string to be parsed """ logger.debug(f"Input string to be parsed: {filename}") if regex == None: regex = BasicSubmission.construct_regex() else: regex = re.compile(rf'{regex}', re.IGNORECASE | re.VERBOSE) logger.debug(f"Using regex: {regex}") match filename: case Path(): m = regex.search(filename.stem) case str(): logger.debug(f"Using string method.") m = regex.search(filename) case _: pass if m != None: try: parsed_name = m.group().upper().strip(".") except: parsed_name = None else: parsed_name = None logger.debug(f"Got parsed submission name: {parsed_name}") return parsed_name @classmethod def construct_new_plate_name(cls, data:dict) -> str: """ Make a brand new plate name from submission data. Args: data (dict): incoming submission data Returns: str: Output filename """ if "submitted_date" in data.keys(): if isinstance(data['submitted_date'], dict): if data['submitted_date']['value'] != None: today = data['submitted_date']['value'] else: today = datetime.now() else: today = data['submitted_date'] else: try: today = re.search(r"\d{4}(_|-)?\d{2}(_|-)?\d{2}", data['rsl_plate_num']) today = parse(today.group()) except (AttributeError, KeyError): today = datetime.now() if "rsl_plate_num" in data.keys(): plate_number = data['rsl_plate_num'].split("-")[-1][0] else: previous = BasicSubmission.query(start_date=today, end_date=today, submission_type=data['submission_type']) plate_number = len(previous) + 1 return f"RSL-{data['abbreviation']}-{today.year}{str(today.month).zfill(2)}{str(today.day).zfill(2)}-{plate_number}" @classmethod def construct_export_name(cls, template:Template, **kwargs) -> str: """ Make export file name from jinja template. (currently unused) Args: template (jinja2.Template): Template stored in BasicSubmission Returns: str: output file name. """ logger.debug(f"Kwargs: {kwargs}") logger.debug(f"Template: {template}") environment = jinja_template_loading() template = environment.from_string(template) return template.render(**kwargs) from .pydant import *