From 7688d0e7c49b6faccefe1d6daaa6c2159cda1d38 Mon Sep 17 00:00:00 2001 From: Cedric Leporcq Date: Fri, 19 Nov 2021 18:24:35 +0100 Subject: [PATCH] Refactoring collection options (3) --- ordigi/cli.py | 66 +++++++++++---------- ordigi/collection.py | 123 +++++++++++++++------------------------ ordigi/config.py | 74 +++++++++++------------ ordigi/media.py | 23 +++----- tests/test_collection.py | 22 +++++-- tests/test_config.py | 4 +- 6 files changed, 149 insertions(+), 163 deletions(-) diff --git a/ordigi/cli.py b/ordigi/cli.py index 84c31eb..a82503e 100755 --- a/ordigi/cli.py +++ b/ordigi/cli.py @@ -184,7 +184,6 @@ def _check(**kwargs): def _clean(**kwargs): """Remove empty folders""" - dry_run = kwargs['dry_run'] folders = kwargs['folders'] log_level = log.get_level(kwargs['verbose']) log.console(LOG, level=log_level) @@ -195,10 +194,12 @@ def _clean(**kwargs): collection = Collection( root, - dry_run=dry_run, - exclude=kwargs['exclude'], - extensions=kwargs['ext'], - glob=kwargs['glob'], + { + "dry_run": kwargs['dry_run'], + "exclude": kwargs['exclude'], + "extensions": kwargs['ext'], + "glob": kwargs['glob'], + }, ) # TODO @@ -253,7 +254,6 @@ def _compare(**kwargs): Sort similar images in directories """ - dry_run = kwargs['dry_run'] subdirs = kwargs['subdirs'] root = kwargs['collection'] @@ -263,10 +263,12 @@ def _compare(**kwargs): collection = Collection( root, - exclude=kwargs['exclude'], - extensions=kwargs['ext'], - glob=kwargs['glob'], - dry_run=dry_run, + { + "exclude": kwargs['exclude'], + "extensions": kwargs['ext'], + "glob": kwargs['glob'], + "dry_run": kwargs['dry_run'], + }, ) for path in paths: @@ -338,16 +340,18 @@ def _import(**kwargs): collection = Collection( root, - kwargs['album_from_folder'], - False, - kwargs['dry_run'], - kwargs['exclude'], - kwargs['ext'], - kwargs['glob'], - kwargs['interactive'], - kwargs['ignore_tags'], - kwargs['use_date_filename'], - kwargs['use_file_dates'], + { + 'album_from_folder': kwargs['album_from_folder'], + 'cache': False, + 'ignore_tags': kwargs['ignore_tags'], + 'use_date_filename': kwargs['use_date_filename'], + 'use_file_dates': kwargs['use_file_dates'], + 'exclude': kwargs['exclude'], + 'extensions': kwargs['ext'], + 'glob': kwargs['glob'], + 'dry_run': kwargs['dry_run'], + 'interactive': kwargs['interactive'], + } ) # TODO retrieve collection.opt @@ -396,16 +400,18 @@ def _sort(**kwargs): collection = Collection( root, - kwargs['album_from_folder'], - cache, - kwargs['dry_run'], - kwargs['exclude'], - kwargs['ext'], - kwargs['glob'], - kwargs['interactive'], - kwargs['ignore_tags'], - kwargs['use_date_filename'], - kwargs['use_file_dates'], + { + 'album_from_folder': kwargs['album_from_folder'], + 'cache': cache, + 'ignore_tags': kwargs['ignore_tags'], + 'use_date_filename': kwargs['use_date_filename'], + 'use_file_dates': kwargs['use_file_dates'], + 'exclude': kwargs['exclude'], + 'extensions': kwargs['ext'], + 'glob': kwargs['glob'], + 'dry_run': kwargs['dry_run'], + 'interactive': kwargs['interactive'], + } ) # TODO retrieve collection.opt diff --git a/ordigi/collection.py b/ordigi/collection.py index d501649..a5fe3f7 100644 --- a/ordigi/collection.py +++ b/ordigi/collection.py @@ -308,28 +308,21 @@ class FileIO: class Paths: """Get filtered files paths""" - def __init__( - self, - exclude=None, - extensions=None, - glob='**/*', - interactive=False, - max_deep=None, - ): + def __init__(self, filters, interactive=False): - # Options - self.exclude = exclude + self.filters = filters - if extensions and '%media' in extensions: - extensions.remove('%media') - self.extensions = extensions.union(Medias.extensions) - else: - self.extensions = extensions + self.extensions = self.filters['extensions'] + if not self.extensions: + self.extensions = set() + elif '%media' in self.extensions: + self.extensions.remove('%media') + self.extensions = self.extensions.union(Medias.extensions) + + self.glob = self.filters['glob'] - self.glob = glob self.interactive = interactive self.log = LOG.getChild(self.__class__.__name__) - self.max_deep = max_deep self.paths_list = [] # Attributes @@ -382,10 +375,11 @@ class Paths: if path / '.ordigi' in file_path.parents: continue - if self.max_deep is not None: - if level > self.max_deep: + if self.filters['max_deep'] is not None: + if level > self.filters['max_deep']: continue + self.exclude = self.filters['exclude'] if self.exclude: matched = False for exclude in self.exclude: @@ -695,34 +689,10 @@ class SortMedias: class Collection(SortMedias): """Class of the media collection.""" - def __init__( - self, - root, - album_from_folder=False, - cache=False, - dry_run=False, - exclude=None, - extensions=None, - glob='**/*', - interactive=False, - ignore_tags=None, - use_date_filename=False, - use_file_dates=False, - ): + def __init__(self, root, cli_options=None): - # TODO move to cli - cli_options = { - 'album_from_folder': album_from_folder, - 'cache': cache, - 'dry_run': dry_run, - 'exclude': exclude, - 'extensions': extensions, - 'glob': '**/*', - 'interactive': interactive, - 'ignore_tags': ignore_tags, - 'use_date_filename': use_date_filename, - 'use_file_dates': use_file_dates, - } + if not cli_options: + cli_options = {} self.log = LOG.getChild(self.__class__.__name__) @@ -734,34 +704,30 @@ class Collection(SortMedias): self.root = root # Get config options - config = self.get_config() - self.opt = config.get_options() + self.opt = self.get_config_options() # Set client options for option, value in cli_options.items(): - self.opt[option] = value - self._set_cli_option('exclude', exclude) + for section in self.opt: + self.opt[section][option] = value + + self.exclude = self.opt['Filters']['exclude'] + if not self.exclude: + self.exclude = set() self.db = CollectionDb(root) - self.fileio = FileIO(self.opt['dry_run']) + self.fileio = FileIO(self.opt['Terminal']['dry_run']) self.paths = Paths( - self.opt['exclude'], - self.opt['extensions'], - self.opt['glob'], - self.opt['interactive'], - self.opt['max_deep'], + self.opt['Filters'], + interactive=self.opt['Terminal']['interactive'], ) self.medias = Medias( self.paths, root, - self.opt['album_from_folder'], - self.opt['cache'], + self.opt['Exif'], self.db, - self.opt['interactive'], - self.opt['ignore_tags'], - self.opt['use_date_filename'], - self.opt['use_file_dates'], + self.opt['Terminal']['interactive'], ) # Features @@ -770,30 +736,37 @@ class Collection(SortMedias): self.medias, root, self.db, - self.opt['dry_run'], - self.opt['interactive'], + self.opt['Terminal']['dry_run'], + self.opt['Terminal']['interactive'], ) # Attributes self.summary = Summary(self.root) self.theme = request.load_theme() - def get_config(self): + def get_config_options(self): """Get collection config""" - return Config(self.root.joinpath('.ordigi', 'ordigi.conf')) + config = Config(self.root.joinpath('.ordigi', 'ordigi.conf')) - def _set_cli_option(self, option, cli_option): + return config.get_config_options() + + def _set_option(self, section, option, cli_option): """if client option is set overwrite collection option value""" if cli_option: - self.opt['option'] = cli_option + self.opt[section][option] = cli_option def get_collection_files(self, exclude=True): if exclude: - exclude = self.paths.exclude + exclude = self.exclude paths = Paths( - exclude, - interactive=self.opt['interactive'], + filters = { + 'exclude': exclude, + 'extensions': None, + 'glob': '**/*', + 'max_deep': None, + }, + interactive=self.opt['Terminal']['interactive'], ) for file_path in paths.get_files(self.root): yield file_path @@ -905,7 +878,7 @@ class Collection(SortMedias): """Remove excluded files in collection""" # get all files for file_path in self.get_collection_files(exclude=False): - for exclude in self.paths.exclude: + for exclude in self.exclude: if fnmatch(file_path, exclude): self.fileio.remove(file_path) self.summary.append('remove', True, file_path) @@ -953,7 +926,7 @@ class Collection(SortMedias): files = os.listdir(directory) if len(files) == 0 and remove_root: self.log.info(f"Removing empty folder: {directory}") - if not self.opt['dry_run']: + if not self.opt['Terminal']['dry_run']: os.rmdir(directory) self.summary.append('remove', True, directory) @@ -970,13 +943,13 @@ class Collection(SortMedias): self._init_check_db(loc) # if path format client option is set overwrite it - self._set_cli_option('path_format', path_format) + self._set_option('Path', 'path_format', path_format) # Get medias data subdirs = set() for src_path, metadata in self.medias.get_metadatas(src_dirs, imp=imp, loc=loc): # Get the destination path according to metadata - fpath = FPath(path_format, self.opt['day_begins']) + fpath = FPath(path_format, self.opt['Path']['day_begins']) metadata['file_path'] = fpath.get_path(metadata) subdirs.add(src_path.parent) diff --git a/ordigi/config.py b/ordigi/config.py index ca723bc..1594dbd 100644 --- a/ordigi/config.py +++ b/ordigi/config.py @@ -42,36 +42,6 @@ def check_re(getoption): class Config: """Manage config file""" - # Initialize with default options - options: dict = { - 'Console': { - 'dry_run': False, - 'interactive': False, - }, - 'Database': { - 'cache': False, - 'album_from_folder': False, - 'ignore_tags': None, - 'use_date_filename': False, - 'use_file_dates': False, - }, - 'Filters': { - 'exclude': None, - 'extensions': None, - 'glob': '**/*', - 'max_deep': None, - }, - 'Geolocation': { - 'geocoder': constants.DEFAULT_GEOCODER, - 'prefer_english_names': False, - 'timeout': gopt.default_timeout, - }, - 'Path': { - 'day_begins': 0, - 'path_format': constants.DEFAULT_PATH_FORMAT, - }, - } - def __init__(self, conf_path=constants.CONFIG_FILE, conf=None): self.conf_path = conf_path if conf is None: @@ -83,6 +53,39 @@ class Config: else: self.conf = conf + self.options = self.set_default_options() + + def set_default_options(self) -> dict: + # Initialize with default options + return { + 'Exif': { + 'album_from_folder': False, + 'cache': False, + 'ignore_tags': None, + 'use_date_filename': False, + 'use_file_dates': False, + }, + 'Filters': { + 'exclude': None, + 'extensions': None, + 'glob': '**/*', + 'max_deep': None, + }, + 'Geolocation': { + 'geocoder': constants.DEFAULT_GEOCODER, + 'prefer_english_names': False, + 'timeout': gopt.default_timeout, + }, + 'Path': { + 'day_begins': 0, + 'path_format': constants.DEFAULT_PATH_FORMAT, + }, + 'Terminal': { + 'dry_run': False, + 'interactive': False, + }, + } + def write(self, conf): with open(self.conf_path, 'w') as conf_file: conf.write(conf_file) @@ -125,7 +128,7 @@ class Config: return re.compile(self.conf.get(section, option)) getre = check_re(_getre) - def get_option(self, section, option): + def get_config_option(self, section, option): bool_options = { 'cache', 'dry_run', @@ -176,16 +179,13 @@ class Config: return value - def get_options(self) -> dict: + def get_config_options(self) -> dict: """Get config options""" - old_options = {} for section in self.options: for option in self.options[section]: # Option is in section - # TODO make a function - value = self.get_option(section, option) - old_options[option] = value + value = self.get_config_option(section, option) self.options[section][option] = value - return old_options + return self.options diff --git a/ordigi/media.py b/ordigi/media.py index 15eee47..09d8ae1 100644 --- a/ordigi/media.py +++ b/ordigi/media.py @@ -611,13 +611,9 @@ class Medias: self, paths, root, - album_from_folder=False, - cache=False, + exif_options, db=None, interactive=False, - ignore_tags=None, - use_date_filename=False, - use_file_dates=False, ): # Modules @@ -628,13 +624,11 @@ class Medias: self.root = root # Options - self.cache = cache - self.album_from_folder = album_from_folder - self.ignore_tags = ignore_tags + self.exif_opt = exif_options + self.album_from_folder = self.exif_opt['album_from_folder'] + self.ignore_tags = self.exif_opt['ignore_tags'] self.interactive = interactive self.log = LOG.getChild(self.__class__.__name__) - self.use_date_filename = use_date_filename - self.use_file_dates = use_file_dates # Attributes # List to store medias datas @@ -648,16 +642,17 @@ class Medias: self.album_from_folder, self.ignore_tags, self.interactive, - self.use_date_filename, - self.use_file_dates, + self.exif_opt['use_date_filename'], + self.exif_opt['use_file_dates'], ) return media def get_metadata(self, file_path, src_dir, loc=None): media = self.get_media(file_path, src_dir) - media.get_metadata(self.root, loc, self.db.sqlite, - self.cache) + media.get_metadata( + self.root, loc, self.db.sqlite, self.exif_opt['cache'] + ) return media.metadata diff --git a/tests/test_collection.py b/tests/test_collection.py index 5421b3d..f157593 100644 --- a/tests/test_collection.py +++ b/tests/test_collection.py @@ -137,7 +137,8 @@ class TestCollection: assert summary.success_table.sum('sort') == nb def test_sort_files(self, tmp_path): - collection = Collection(tmp_path, album_from_folder=True) + cli_options = {'album_from_folder': True} + collection = Collection(tmp_path, cli_options=cli_options) loc = GeoLocation() summary = collection.sort_files([self.src_path], self.path_format, loc, imp='copy') @@ -150,14 +151,20 @@ class TestCollection: assert not summary.errors # check if album value are set - paths = Paths(glob='**/*').get_files(tmp_path) + filters = { + 'exclude': None, + 'extensions': None, + 'glob': '**/*', + 'max_deep': None, + } + paths = Paths(filters).get_files(tmp_path) for file_path in paths: if '.db' not in str(file_path): media = Media(file_path, tmp_path, album_from_folder=True) for value in ReadExif(file_path).get_key_values('album'): assert value != '' or None - collection = Collection(tmp_path, album_from_folder=True) + collection = Collection(tmp_path, cli_options=cli_options) # Try to change path format and sort files again path = '{city}/{%Y}-{name}.%l{ext}' summary = collection.sort_files([tmp_path], @@ -222,8 +229,13 @@ class TestCollection: shutil.copyfile(dest_path, src_path) def test_get_files(self): - exclude={'**/*.dng',} - paths = Paths(exclude=exclude, max_deep=1) + filters = { + 'exclude': {'**/*.dng',}, + 'extensions': None, + 'glob': '**/*', + 'max_deep': 1, + } + paths = Paths(filters) paths = list(paths.get_files(self.src_path)) assert len(paths) == 9 assert Path(self.src_path, 'test_exif/photo.dng') not in paths diff --git a/tests/test_config.py b/tests/test_config.py index 5d49f98..ce3c801 100644 --- a/tests/test_config.py +++ b/tests/test_config.py @@ -58,8 +58,8 @@ class TestConfig: # path = config.get_path_definition() # assert path == '%u{%Y-%m}/{city}|{city}-{%Y}/{folders[:1]}/{folder}/{%Y-%m-%b-%H-%M-%S}-{basename}.%l{ext}' - def test_get_options(self, conf): + def test_get_config_options(self, conf): config = Config(conf=conf) - options = config.get_options() + options = config.get_config_options() assert isinstance(options, dict) # assert isinstance(options['Path'], dict)