import re import os from pathlib import Path from fnmatch import fnmatch from glob import glob class Template: field_pattern = re.compile(r'{(\w+)\*{0,2}}') field_pattern_recursive = re.compile(r'{(\w+)\*{2}}') def __init__(self, template): #asset_data_path = Path(lib_path) / ASSETLIB_FILENAME self.template = template @property def glob_pattern(self): pattern = self.field_pattern_recursive.sub('**', self.template) pattern = self.field_pattern.sub('*', pattern) return pattern @property def re_pattern(self): pattern = self.field_pattern_recursive.sub('([\\\w -_.\/]+)', self.template) pattern = self.field_pattern.sub('([\\\w -_.]+)', pattern) pattern = pattern.replace('?', '.') pattern = pattern.replace('*', '.*') return re.compile(pattern) @property def fields(self): return self.field_pattern.findall(self.template) #return [f or '0' for f in fields] def parse(self, path): path = Path(path).as_posix() res = self.re_pattern.findall(path) if not res: print('Could not parse {path} with {self.re_pattern}') return {} fields = self.fields if len(fields) == 1: field_values = res else: field_values = res[0] return {k:v for k,v in zip(fields, field_values)} def format(self, data=None, **kargs): #print('format', self.template, data, kargs) data = {**(data or {}), **kargs} try: path = self.template.format(**data) except KeyError: print(f'Cannot format {self.template} with {data}') return path = os.path.expandvars(path) return Path(path) def glob(self, directory, pattern=None): '''If pattern is given it need to be absolute''' if pattern is None: pattern = Path(directory, self.glob_pattern).as_posix() for entry in os.scandir(directory): entry_path = Path(entry.path) if entry.is_file() and fnmatch(entry_path.as_posix(), pattern): yield entry_path elif entry.is_dir(): yield from self.glob(entry.path, pattern) def find(self, data, **kargs): pattern = self.format(data, **kargs) paths = glob(pattern.as_posix()) if paths: return Path(paths[0]) def __repr__(self): return f'Template({self.template})'