Passed
Push — master ( c9e9cc...a2e9e4 )
by Yu
01:20
created

ChangeFilename.async_filename_to_digit_number()   A

Complexity

Conditions 1

Size

Total Lines 22
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 12
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 12
nop 1
dl 0
loc 22
ccs 12
cts 12
cp 1
crap 1
rs 9.8
c 0
b 0
f 0
1
# -*- coding: utf-8 -*-
2 1
"""Rename file name.
3
"""
4 1
import os
5 1
import os.path
6 1
import re
7
8 1
from .core import Common
9 1
from .exceptions import InvalidNumberParameterTypeError, \
10
    ChangeFileNameOSError, InvalidImageParameterTypeError
11 1
from .utils.logging import get_logger
12
13 1
_logger = get_logger("change_filename")
14
15
16 1
class ChangeFilename(Common):
17
    """Change file name to only digit name.
18
    """
19
20 1
    def __init__(self, directory_path, digits, extension):
21
        """Constructor
22
23
        Args:
24
            directory_path (str): Target directory path.
25
            digits (str): Regex target digit.
26
            extension (str): Target file extension.
27
        """
28 1
        super().__init__()
29 1
        self.__directory_path = directory_path
30 1
        self.__digits = digits
31 1
        self.__exist_files = []
32 1
        self.__extension = self._convert_extension_with_dot(extension)
33 1
        self.__max_digit = self._check_digit_format(self.__digits)
34 1
        self.__regex_ext = re.compile(self.__extension)
35 1
        os.chdir(self.__directory_path)
36
37 1
    @staticmethod
38
    def _create_new_name(num, digit, extension):
39
        """Create only digit file name.
40
41
        Args:
42
            num (Match): Match object
43
            digit (int): digit number
44
            extension (str): File Extension like ".jpg"
45
46
        Returns:
47
            str: Only digit file name.
48
49
        Raises:
50
            InvalidNumberParameterTypeError: If input digit is not Match object.
51
52
        """
53 1
        try:
54 1
            return num.group().zfill(digit) + extension
55 1
        except AttributeError as attribute_error:
56 1
            _logger.exception(attribute_error)
57 1
            raise InvalidNumberParameterTypeError()
58
59 1
    def __check_exist_file(self, new_name, old_name, append_list):
60
        """Check current directory and exists same name file, return true.
61
        Args:
62
            new_name (str): Target file name.
63
            old_name (str): before name
64
            append_list (bool): If true, make duplicate name list
65
66
        Returns:
67
            bool: If success, return true
68
69
        Raises:
70
            ChangeFileNameOSError: If input a bad filename or path.
71
        """
72 1
        try:
73 1
            if os.path.isfile(new_name):
74 1
                _logger.info("File Exist: {filename}".format(filename=new_name))
75 1
                if old_name != new_name and append_list:
76 1
                    _logger.debug("Append exist files list: {filename}".format(filename=old_name))
77 1
                    self.__exist_files.append(old_name)
78 1
                return True
79
            else:
80 1
                return False
81 1
        except OSError as os_error:
82 1
            _logger.exception(os_error)
83 1
            raise ChangeFileNameOSError()
84
85 1
    def __input_new_file_name(self, old_name, overwrite):
86
        """Provide input command prompt.
87
        Args:
88
            old_name (str): Old name
89
            overwrite (bool): If true, ignore exist file name.
90
91
        Returns:
92
            str: new file name.
93
        """
94 1
        new_name = input("Input new name? {old_name} =>".format(old_name=old_name))
95 1
        while self.__check_exist_file(new_name, new_name, False) and not overwrite:
96 1
            _logger.warn("Already file exist: {new_name}")
97 1
            new_name = input("Input Another file name {old_name} => ?".format(new_name=new_name,
98
                                                                              old_name=old_name))
99 1
        return new_name
100
101 1
    def filename_to_digit_number(self):
102
        """Change file name to only digit name.
103
104
        Change file name contains digit like "foo001bar.txt" to
105
        only digit file name like "001.txt".
106
107
        Returns:
108
            List[str]: Skipping files list by exists same name.
109
        """
110 1
        count = 0
111 1
        files = self._make_file_list(self.__directory_path)
112
113 1
        _logger.info("Target directory: {directory_path}".format(directory_path=self.__directory_path))
114 1
        _logger.info("Digit: {digits}".format(digits=self.__digits))
115 1
        _logger.info("Extension: {extension}".format(extension=self.__extension))
116 1
        _logger.info("-" * 55)
117
118 1
        for file in files:
119 1
            self._rename_digit_filename(file)
120 1
            count += 1
121
122 1
        _logger.info("-" * 55)
123 1
        _logger.info("Finished! Rename file count: {count}".format(count=count))
124 1
        return self.__exist_files
125
126 1
    def async_filename_to_digit_number(self):
127
        """Change file name to only digit name on async.
128
129
        If use this function, a little bit speedy
130
        compare with filename_to_digit_number function.
131
132
        Returns:
133
            List[str]: Skipping files list by exists same name.
134
        """
135 1
        files = self._make_file_list(self.__directory_path)
136
137 1
        _logger.info("Target directory: {directory_path}".format(directory_path=self.__directory_path))
138 1
        _logger.info("Digit: {digits}".format(digits=self.__digits))
139 1
        _logger.info("Extension: {extension}".format(extension=self.__extension))
140 1
        _logger.info("-" * 55)
141
142 1
        loop = self._get_eventloop()
143 1
        queue = self._create_task_queue(files)
144 1
        loop.run_until_complete(self._execute_queuing_tasks(queue, loop, None, self._rename_digit_filename))
145 1
        _logger.info("-" * 55)
146 1
        _logger.info("Finished! Async rename")
147 1
        return self.__exist_files
148
149 1
    def _rename_digit_filename(self, file):
150 1
        num = self._check_serial_number(file, self.__digits)
151 1
        if not self._check_skip_file(file, self.__regex_ext, num):
152 1
            new_name = self._create_new_name(num, self.__max_digit, self.__extension)
153 1
            if not self.__check_exist_file(new_name, file, True):
154 1
                self._rename_file(file, new_name)
155 1
        return True
156
157 1
    def change_name_manually(self, overwrite=False):
158
        """Change filename manually looking exist_file list.
159
160
        After changing file name for filename_to_digit_number() method,
161
        duplicate file name change manually.
162
163
        Args:
164
            overwrite (bool): If true, overwrite file name even if exist same name file.
165
166
        Returns:
167
            bool: If success, return True.
168
169
        """
170 1
        def _flag_yes():
171 1
            new_name_y = self.__input_new_file_name(file, overwrite)
172 1
            self._rename_file(file, new_name_y)
173 1
            _logger.info("Rename: {old_name} => {new_name} \n".format(old_name=file, new_name=new_name_y))
174
175 1
        def _flag_rename():
176 1
            flag_delete = input("Will be {file} deleted? "
177
                                "OK? (y/n/c/r)".format(file=file))  # y="Yes" n="No" c="check" r="rename"
178 1
            if flag_delete == "c":
179 1
                self._check_image_file(file)
180 1
            elif flag_delete in ("Y", "y"):
181 1
                self._remove_file(file)
182 1
            elif flag_delete == "r":
183 1
                new_name_rename = self.__input_new_file_name(file, overwrite)
184 1
                self._rename_file(file, new_name_rename)
185
            else:
186 1
                _logger.info("Leave file: {file}\n".format(file=file))
187
188 1
        _logger.info("-" * 55)
189 1
        _logger.info("Manually determine file names duplicated by the serial number\n")
190 1
        for file in self.__exist_files:
191 1
            _logger.info("File name: {file_name}")
192 1
            flag = input("Does it rename? (y/n/r)".format(file_name=file))  # y="Yes" n="No" r="Remove"
193 1
            if flag in ("Y", "y"):
194 1
                _flag_yes()
195 1
            elif flag == "r":
196 1
                try:
197 1
                    _flag_rename()
198 1
                except InvalidImageParameterTypeError as invalid_image_parameter_type:
199 1
                    _logger.warn(invalid_image_parameter_type)
200 1
                    _logger.info("Skip..")
201
            else:
202 1
                _logger.info("Leave file: {file}\n".format(file=file))
203 1
        _logger.info("Finished.")
204 1
        return True
205
206 1
    def add_before_after_str(self, before, after):
207
        """Add file name specify string.
208
209
        After changing file name for filename_to_digit_number() method,
210
        add specify string before or after file name.
211
212
        Args:
213
            before (str): String before file name
214
            after (str): String after file name
215
216
        Returns:
217
            bool: If success, return True.
218
219
        """
220 1
        _logger.info("-" * 55)
221 1
        files = self._make_file_list(self.__directory_path)
222 1
        if before is not None:
223 1
            _logger.info("Add {before} before serial digit".format(before=before))
224
        else:
225 1
            before = ""
226 1
        if after is not None:
227 1
            _logger.info("Add {after} before serial digit".format(after=after))
228
        else:
229 1
            after = ""
230
231 1
        for file in files:
232 1
            num = self._check_serial_number(file, self.__digits)
233 1
            if not num:
234 1
                _logger.debug("Skip(No number): {filename}".format(filename=str(file)))
235
            else:
236 1
                if self.__regex_ext.search(file):
237 1
                    _, center, _ = self._split_dir_root_ext(file)
238 1
                    new_name = before + center + after + self.__extension
239 1
                    if self.__check_exist_file(new_name, new_name, False):
240 1
                        pass
241
                    else:
242 1
                        self._rename_file(file, new_name)
243
        return True
244