Skip to content
This repository has been archived by the owner on Apr 29, 2020. It is now read-only.

Commit

Permalink
v1.1.0 Release (#1)
Browse files Browse the repository at this point in the history
Prepare v1.1.0 release

New features:
    Regex tag groups
    Tag group inheritance
    Clean input/output folder flag
    Tag in group (/?TIG|) operator for format strings
    Format strings in subfolder names

New formats:
    Tag group format v1.1
        Adds support for regex tag groups and tag group inheritance
    Schema format v1.1
        Adds support for format string subfolder names and tag in group
        (/?TIG|) operator

Bugfixes:
    Improved regex handling (warn if malformed regexes in schema, don't
    throw exceptions
    Residual '/'s in format strings now cause errors, not warnings, (as
    they prevent files from being moved/renamed)
    Minor formatting/typo fixes
  • Loading branch information
SiriusStarr authored May 13, 2019
1 parent c568740 commit 2849945
Show file tree
Hide file tree
Showing 21 changed files with 1,879 additions and 732 deletions.
535 changes: 343 additions & 192 deletions README.md

Large diffs are not rendered by default.

9 changes: 5 additions & 4 deletions autotagical/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,10 @@
-----
autotagical [-h] [-V] [-C <config file>] [-H] [-i <input path>]
[-I <ignore file>] [-R] [-o <output path>] [-O]
[-g <tag group file>] [-s <schema file>] [-A] [-F] [-k] [-m]
[-M] [-n] [-N] [-t] [--debug] [-l <log file>] [-L] [-P]
[-q] [-v] [--force] [--yes]
[-g <tag group file>] [-s <schema file>] [-A] [--cleanin]
[--cleanout] [-c] [-F] [-k] [-m] [-M] [-n] [-N] [-t]
[--debug] [-l <log file>] [-L] [-P] [-q] [-v] [--force]
[--yes]
"""

__version__ = '1.0.0' # Define the current version
__version__ = '1.1.0' # Define the current version
132 changes: 89 additions & 43 deletions autotagical/file_handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
---------
Functions
---------
clean_folder(folder_path, trial_run=False):
Removes all empty directories/subdirectories from the specified folder.
check_windows_compat(name, full_path)
Checks a file name and path for Windows-unsafe characters.
check_output_location(settings)
Expand Down Expand Up @@ -39,15 +41,51 @@
import logging


def clean_folder(folder_path, trial_run=False):
"""
Removes all empty directories/subdirectories from the specified folder.
Parameters
----------
folder_path: str
Path to folder to clean.
trial_run: bool
If True, do not actually delete folders, only log that they will be.
Returns
-------
bool
True if successful, False if errors were encountered.
"""
successful = True
for root, dirs, _ in os.walk(top=folder_path, topdown=False):
for directory in dirs:
full_path = os.path.join(root, directory)
try:
if not os.listdir(full_path):
logging.info('Cleaning (deleting) folder at %s',
full_path)
if not trial_run:
os.rmdir(full_path)
else:
logging.info('Skipping cleaning non-empty directory at: '
'%s', full_path)
except OSError as err:
logging.warning('Could not clean directory at %s:\n%s',
full_path, str(err))
successful = False
return successful


def check_windows_compat(name, full_path):
"""
Checks a file name and path for Windows-unsafe characters.
Parameters
----------
name : str
name: str
Name of file (no directories).
full_path : str
full_path: str
Full path of the file
Returns
Expand Down Expand Up @@ -192,10 +230,10 @@ def move_files(move_list, settings):
Parameters
----------
move_list : list of AutotagicalFile
move_list: list of AutotagicalFile
A list of AutotagicalFile objects, each representing a file to be
moved/renamed.
settings : AutotagicalSettings
settings: AutotagicalSettings
An AutotagicalSettings object holding the settings for the movement.
Returns
Expand Down Expand Up @@ -252,25 +290,25 @@ class AutotagicalFile: # pylint: disable=R0902
Attributes
----------
dest_folder : str
dest_folder: str
The folder the file is to be moved to.
extension : str
extension: str
The extension of the original file.
move_failed : bool
move_failed: bool
True is no applicable movement schema was found, False otherwise.
name : str
name: str
Original file name, less tags and extension.
original_path : str
original_path: str
Complete path to original file, including directories and file name.
output_name : str
output_name: str
The file name the file is to be renamed to.
raw_name : str
raw_name: str
The original file name with tags and extension.
rename_failed : bool
rename_failed: bool
True if no applicable renaming schema was found, False otherwise.
tags : str
tags: str
Complete tags on the original file, including any delimiters.
tag_array : list of str
tag_array: list of str
List of strings, each a tag on the original file.
Class Methods
Expand All @@ -297,17 +335,17 @@ def __init__(self, name, tags, extension, tag_array, raw_name,
Parameters
----------
name : str
name: str
Original file name, less tags and extension.
tags : str
tags: str
Complete tags on the original file, including any delimiters.
extension : str
extension: str
The extension of the original file.
tag_array : list of str
tag_array: list of str
List of strings, each a tag on the original file.
raw_name : str
raw_name: str
The original file name with tags and extension.
original_path : str
original_path: str
Complete path to original file, including all directories and file
name.
"""
Expand Down Expand Up @@ -351,17 +389,17 @@ def load_file(cls, name, path, tag_patterns, ignore_patterns):
Parameters
----------
name : str
name: str
The full name of the file to load.
path : str
path: str
Complete path to original file, including directories and file name
tag_patterns : list of dict
tag_patterns: list of dict
List of dictionaries, each of the following form:
{
'tag_pattern' : Regular Expression Object,
'tag_split_pattern' : Regular Expression Object
'tag_pattern': Regular Expression Object,
'tag_split_pattern': Regular Expression Object
}
ignore_patterns : list of Regular Expression Objects
ignore_patterns: list of Regular Expression Objects
A list of compiled regexes full-matching file patterns to ignore.
Returns
Expand Down Expand Up @@ -404,14 +442,14 @@ class AutotagicalFileHandler:
Instance Attributes
-------------------
__file_list : list of AutotagicalFile
__ignore_patterns : list of Regular Expression Objects
__file_list: list of AutotagicalFile
__ignore_patterns: list of Regular Expression Objects
A list of compiled regexes full-matching file patterns to ignore.
__tag_patterns : list of dict
__tag_patterns: list of dict
List of dictionaries, each of the following form:
{
'tag_pattern' : Regular Expression Object,
'tag_split_pattern' : Regular Expression Object
'tag_pattern': Regular Expression Object,
'tag_split_pattern': Regular Expression Object
}
Methods
Expand Down Expand Up @@ -446,10 +484,18 @@ def __init__(self, tag_formats):
"""
self.__file_list = []
self.__ignore_patterns = []
self.__tag_patterns = [{
'tag_pattern': re.compile(pattern['tag_pattern']),
'tag_split_pattern': re.compile(pattern['tag_split_pattern'])
} for pattern in tag_formats]
self.__tag_patterns = []
# Try to compile tag patterns as a regex or warn
for pattern in tag_formats:
try:
self.__tag_patterns.append({
'tag_pattern': re.compile(pattern['tag_pattern']),
'tag_split_pattern':
re.compile(pattern['tag_split_pattern'])
})
except re.error as err:
logging.warning('Regex error in tag format: %s\n%s',
pattern, str(err))

def load_ignore_file(self, path):
"""
Expand All @@ -458,7 +504,7 @@ def load_ignore_file(self, path):
Parameters
----------
path : str
path: str
The complete path to the file, including folders and the complete
file name.
Expand Down Expand Up @@ -496,9 +542,9 @@ def check_new(self, name, path):
Parameters
----------
name : str
name: str
The full name of the file.
path : str
path: str
The path to the file (including file name)
Returns
Expand All @@ -522,9 +568,9 @@ def load_file(self, name, path):
Parameters
----------
name : str
name: str
The full name of the file.
path : str
path: str
The path to the file (including file name)
Returns
Expand All @@ -549,11 +595,11 @@ def load_folder(self, input_folder, recurse=False, process_hidden=False):
Parameters
----------
input_folder : str
input_folder: str
Path to folder to load files from.
recurse : bool
recurse: bool
If True, will descend into subfolders recursively.
process_hidden : bool
process_hidden: bool
If True, will process files beginning with '.' and (if recurse is
True) descend into directories beginning with '.'
Expand Down
27 changes: 12 additions & 15 deletions autotagical/filtering.py
Original file line number Diff line number Diff line change
Expand Up @@ -99,14 +99,14 @@ def check_condition(tag_array, condition, tag_groups):
Parameters
----------
tag_array : list of str
tag_array: list of str
A list of strings, each holding a tag. These tags will be considered
as a whole against the provided condition. It should be in the form:
['tag1', 'tag2', ...]
condition : str
condition: str
A string with the condition against which the tags will be matched.
This may contain various special operators.
tag_groups : AutotagicalGroups
tag_groups: AutotagicalGroups
An AutotagicalGroups object that will be used to resolve tag group
operators.
Expand Down Expand Up @@ -138,12 +138,9 @@ def check_condition(tag_array, condition, tag_groups):

# If it's a tag group
if match.group('tag_group'):
# Load what tags are in that tag_group
group_tags = tag_groups.get_tags_in_group(match.group('tag_group'))
# See if any tag is in the tag gorup and return accordingly
for tag in tag_array:
if tag in group_tags:
return match_found
# See if tags match the group
if tag_groups.tag_in_group(tag_array, match.group('tag_group')):
return match_found
return not match_found

# If here, something went horribly wrong, throw an error
Expand All @@ -160,15 +157,15 @@ def check_against_condition_set(tag_array, condition_set, tag_groups):
Parameters
----------
tag_array : list of str
tag_array: list of str
A list of strings, each holding a tag. These tags will be considered
as a whole against the provided condition set. It should be in the
form: ['tag1', 'tag2', ...]
condition_set : str
condition_set: str
A string with the condition set against which the tags will be
matched. This may contain various special operators, and may be
multiple conditions concatenated with the AND operator /&|.
tag_groups : AutotagicalGroups
tag_groups: AutotagicalGroups
An AutotagicalGroups object that will be used to resolve group
operators.
Expand Down Expand Up @@ -204,15 +201,15 @@ def check_against_filter(tag_array, check_filter, tag_groups):
Parameters
----------
tag_array : list of str
tag_array: list of str
A list of strings, each holding a tag. These tags will be considered
as a whole against the provided filter. It should be in the form:
['tag1', 'tag2', ...]
filter : list of str
filter: list of str
A list of strings, each containing a condition set against which the
tags will be matched. Each may contain various special operators and
may be multiple conditions concatenated with the AND operator /&|.
tag_groups : AutotagicalGroups
tag_groups: AutotagicalGroups
An AutotagicalGroups object that will be used to resolve group
operators.
Expand Down
Loading

0 comments on commit 2849945

Please sign in to comment.