vse_toolbox/file_utils.py

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}')