import importlib import re import subprocess import platform import sys import unicodedata from pathlib import Path from os.path import expandvars import json import glob def install_module(module_name, package_name=None): '''Install a python module with pip or return it if already installed''' try: module = importlib.import_module(module_name) except ModuleNotFoundError: print(f'Installing Module {module_name} ....') subprocess.call([sys.executable, '-m', 'ensurepip', '--upgrade']) subprocess.call([sys.executable, '-m', 'pip', 'install', package_name or module_name]) module = importlib.import_module(module_name) return module def import_module_from_path(path): from importlib import util try: path = Path(path) spec = util.spec_from_file_location(path.stem, str(path)) mod = util.module_from_spec(spec) spec.loader.exec_module(mod) return mod except Exception as e: print(f'Cannot import file {path}') print(e) def fuzzy_match(s1, s2, case_sensitive=False): '''Tell how much two passed strings are similar 1.0 being exactly similar''' from difflib import SequenceMatcher if case_sensitive: similarity = SequenceMatcher(None, s1, s2) else: similarity = SequenceMatcher(None, s1.lower(), s2.lower()) return similarity.ratio() def norm_str(string, separator='_', format=str.lower, padding=0): string = str(string) string = string.replace('_', ' ') string = string.replace('-', ' ') string = re.sub('[ ]+', ' ', string) string = re.sub('[ ]+\/[ ]+', '/', string) string = string.strip() if format: string = format(string) # Padd rightest number string = re.sub(r'(\d+)(?!.*\d)', lambda x : x.group(1).zfill(padding), string) string = string.replace(' ', separator) string = unicodedata.normalize('NFKD', string).encode('ASCII', 'ignore').decode("utf-8") return string def norm_name(string, separator='_', format=str.lower, padding=0): string = str(string) string = string.split('/')[-1] #used to remove first slash -> albert / albert_casque -> albert_casque string = string.replace('_', ' ') string = string.replace('-', ' ') string = re.sub('[ ]+', ' ', string) string = re.sub('[ ]+\/[ ]+', '/', string) string = string.strip() if format: string = format(string) # Padd rightest number string = re.sub(r'(\d+)(?!.*\d)', lambda x : x.group(1).zfill(padding), string) string = string.replace(' ', separator) string = unicodedata.normalize('NFKD', string).encode('ASCII', 'ignore').decode("utf-8") return string def read_file(path): '''Read a file with an extension in (json, yaml, yml, txt, log)''' exts = ('.json', '.yaml', '.yml', '.txt', '.log') if not path: print('Try to read empty file') path = Path(path) if not path.exists(): print('File not exist', path) return if path.suffix not in exts: print(f'Cannot read file {path}, extension must be in {exts}') return txt = path.read_text() data = None if path.suffix.lower() in ('.yaml', '.yml'): yaml = install_module('yaml') try: data = yaml.safe_load(txt) except Exception as e: print(e) print(f'Could not load yaml file {path}') return elif path.suffix.lower() == '.json': try: data = json.loads(txt) except Exception as e: print(e) print(f'Could not load json file {path}') return else: data = txt return data def open_file(filepath, env=None, select=False): if platform.system() == 'Darwin': # macOS cmd = ['open'] if select: cmd += ['-R'] elif platform.system() == 'Windows': # Windows cmd = ['explorer'] if select: cmd += ['/select,'] else: # linux variants cmd = ['xdg-open'] if select: cmd = ['nemo'] cmd += [str(filepath)] subprocess.Popen(cmd, env=env) # def parse(string, template): # template = re.sub(r'{index:(.+?)}', r'(?P.+)', template) # reg = re.sub(r'{(.+?)}', r'(?P<_\1>.+)', template) # values = list(re.search(reg, string).groups()) # keys = re.findall(r'{(.+?)}', template) + ['index'] # return dict(zip(keys, values)) def parse(template, string): reg = re.sub(r'{[^}]*}|\.', lambda m: m.group() if m.group().startswith('{') else r'\.', template) reg = re.sub(r'{(.+?)}', r'(?P<\1>.*)', reg) #print(string, template, reg) if result := re.match(reg, string): return result.groupdict() def expand(template, **kargs): template = Path(template).as_posix() template = expandvars(template) for key, value in kargs.items(): template = re.sub(r'\{%s\}'%key, value, template) return template def find_last(template, **kargs): pattern = expand(template, **kargs) pattern = re.sub(r'{\w+:(\d{2})d}', lambda x : '?' * int(x.groups()[0]), pattern) pattern = re.sub(r'{.*?}', '*', pattern) filepaths = glob.glob(pattern) if filepaths: return Path(max(filepaths)) else: print(f'No preview found for template {pattern}')