187 lines
5.3 KiB
Python
187 lines
5.3 KiB
Python
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<index>.+)', 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}') |