ebook_homebrew.rename   A
last analyzed

Complexity

Total Complexity 32

Size/Duplication

Total Lines 268
Duplicated Lines 0 %

Test Coverage

Coverage 100%

Importance

Changes 0
Metric Value
eloc 140
dl 0
loc 268
ccs 125
cts 125
cp 1
rs 9.84
c 0
b 0
f 0
wmc 32

9 Methods

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