2016-12-20 13:22:44 +00:00
|
|
|
from os.path import basename, dirname
|
|
|
|
from os.path import join as joinpath
|
2018-09-02 13:52:52 +00:00
|
|
|
from re import sub
|
2018-09-04 19:08:48 +00:00
|
|
|
from collections.abc import Iterable
|
2018-09-02 13:52:52 +00:00
|
|
|
|
|
|
|
from unidecode import unidecode
|
2016-12-08 17:15:56 +00:00
|
|
|
|
2017-05-28 17:55:21 +00:00
|
|
|
|
2018-09-02 13:52:52 +00:00
|
|
|
class Normalisename:
|
2018-09-04 20:45:42 +00:00
|
|
|
def __init__(self, separator, whitelist, operation=None):
|
2018-09-02 13:52:52 +00:00
|
|
|
self._separator = separator
|
|
|
|
self._whitelist = set(whitelist)
|
2018-09-04 20:45:42 +00:00
|
|
|
self._operation = None
|
|
|
|
self.operation = operation or self.noop
|
2018-09-02 13:52:52 +00:00
|
|
|
|
2017-08-23 20:34:02 +00:00
|
|
|
@property
|
|
|
|
def operation(self):
|
|
|
|
return self._operation
|
|
|
|
|
|
|
|
@operation.setter
|
|
|
|
def operation(self, value):
|
|
|
|
if not callable(value):
|
|
|
|
raise ValueError('Operation must be callable!')
|
|
|
|
self._operation = value
|
|
|
|
|
2018-09-04 20:45:42 +00:00
|
|
|
@staticmethod
|
|
|
|
def noop(*_):
|
|
|
|
pass
|
|
|
|
|
2017-08-23 16:48:49 +00:00
|
|
|
@property
|
|
|
|
def separator(self):
|
|
|
|
return self._separator
|
|
|
|
|
|
|
|
@property
|
|
|
|
def whitelist(self):
|
2018-09-02 14:15:24 +00:00
|
|
|
return self._whitelist.union({self.separator})
|
2017-08-23 16:48:49 +00:00
|
|
|
|
2018-09-04 19:08:48 +00:00
|
|
|
def __call__(self, path_or_paths):
|
|
|
|
if isinstance(path_or_paths, str):
|
2018-09-04 20:45:42 +00:00
|
|
|
return self.normalise(path_or_paths)
|
|
|
|
if isinstance(path_or_paths, Iterable):
|
|
|
|
return self.normalise_all(path_or_paths)
|
|
|
|
raise ValueError('Argument must be str Iterable[str]!')
|
2018-09-04 19:08:48 +00:00
|
|
|
|
|
|
|
def normalise_all(self, paths):
|
2018-09-04 20:45:42 +00:00
|
|
|
return [self.normalise(path) for path in paths]
|
2018-09-04 19:08:48 +00:00
|
|
|
|
|
|
|
def normalise(self, path):
|
2018-09-08 22:54:36 +00:00
|
|
|
path = self.strip_trailing_slash(path)
|
2018-09-04 19:08:48 +00:00
|
|
|
directory = dirname(path)
|
|
|
|
filename = basename(path)
|
|
|
|
normalpath = joinpath(directory, self.normalname(filename))
|
2018-09-08 22:54:36 +00:00
|
|
|
|
2018-09-04 19:08:48 +00:00
|
|
|
if path != normalpath:
|
|
|
|
self.operation(path, normalpath) # pylint: disable=not-callable
|
2018-09-04 20:45:42 +00:00
|
|
|
return normalpath
|
2017-08-23 20:34:02 +00:00
|
|
|
|
2018-09-08 22:54:36 +00:00
|
|
|
@staticmethod
|
|
|
|
def strip_trailing_slash(path):
|
|
|
|
if path[-1] == '/':
|
|
|
|
path = path[:-1]
|
|
|
|
return path
|
|
|
|
|
2017-08-23 16:48:49 +00:00
|
|
|
def normalname(self, filename):
|
2018-09-02 13:52:52 +00:00
|
|
|
return unidecode(
|
|
|
|
''.join(
|
|
|
|
ch for ch in sub(r'\s+', self.separator, filename)
|
|
|
|
if ch.isalnum()
|
|
|
|
or ch in self.whitelist
|
|
|
|
)
|
|
|
|
)
|
2018-09-08 22:49:03 +00:00
|
|
|
|
|
|
|
def check_normal(self, path):
|
|
|
|
filename = basename(path)
|
|
|
|
return filename == self.normalname(filename)
|