forked from LiveCarta/BookConverter
Annotations in Epub converter
This commit is contained in:
@@ -4,8 +4,7 @@ import argparse
|
||||
|
||||
def parse_args():
|
||||
parser = argparse.ArgumentParser(description="Utility for folders's clean up.")
|
||||
parser.add_argument('-f', '--folders', type=str, nargs='*', help='Names of the folders to be cleaned.')
|
||||
|
||||
parser.add_argument("-f", "--folders", type=str, nargs="*", help="Names of the folders to be cleaned.")
|
||||
args = parser.parse_args()
|
||||
return args
|
||||
|
||||
@@ -18,10 +17,10 @@ def check_dir(dir_path):
|
||||
raise exc
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
if __name__ == "__main__":
|
||||
folders = parse_args().folders
|
||||
if not folders:
|
||||
folders = ['docx', 'html', 'json', 'logs', 'config']
|
||||
folders = ["docx", "html", "json", "logs", "config"]
|
||||
|
||||
folder_path = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||||
folders = [os.path.join(folder_path, folder) for folder in folders]
|
||||
|
||||
@@ -6,15 +6,15 @@ import subprocess
|
||||
|
||||
def parse_args():
|
||||
parser = argparse.ArgumentParser(description="Utility for checking installed packages.")
|
||||
parser.add_argument('-p', '--packages', type=str, nargs='*', help='Names of the packages.')
|
||||
parser.add_argument("-p", "--packages", type=str, nargs="*", help="Names of the packages.")
|
||||
|
||||
args = parser.parse_args()
|
||||
return args
|
||||
|
||||
|
||||
def check_packages(required_packs):
|
||||
inst = subprocess.check_output([sys.executable, '-m', 'pip', 'freeze'])
|
||||
installed_packages = [r.decode().split('==')[0] for r in inst.split()]
|
||||
inst = subprocess.check_output([sys.executable, "-m", "pip", "freeze"])
|
||||
installed_packages = [r.decode().split("==")[0] for r in inst.split()]
|
||||
|
||||
to_be_installed = []
|
||||
for package in required_packs:
|
||||
@@ -24,19 +24,19 @@ def check_packages(required_packs):
|
||||
return to_be_installed
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
if __name__ == "__main__":
|
||||
required_packs = parse_args().packages
|
||||
if not required_packs:
|
||||
folder_path = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||||
req_path = os.path.join(folder_path, 'requirements.txt')
|
||||
req_path = os.path.join(folder_path, "requirements.txt")
|
||||
|
||||
with open(req_path, 'r') as f:
|
||||
with open(req_path, "r") as f:
|
||||
packs = f.readlines()
|
||||
|
||||
required_packs = [pack.split('>=')[0] for pack in packs]
|
||||
required_packs = [pack.split(">=")[0] for pack in packs]
|
||||
|
||||
not_inst_packs = check_packages(required_packs)
|
||||
if not_inst_packs:
|
||||
raise Exception(f'{" ".join(not_inst_packs)} are not installed.')
|
||||
raise Exception(f"{' '.join(not_inst_packs)} are not installed.")
|
||||
else:
|
||||
print('All required packages has been installed.')
|
||||
print("All required packages has been installed.")
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import re
|
||||
|
||||
from typing import Tuple
|
||||
from colorsys import hls_to_rgb
|
||||
from webcolors import html4_hex_to_names, hex_to_rgb, rgb_to_name, rgb_percent_to_hex, rgb_to_hex, css3_names_to_hex
|
||||
|
||||
@@ -48,7 +48,7 @@ def hex2color_name(color):
|
||||
return closest_name
|
||||
|
||||
|
||||
def str2closest_html_color_name(s: str):
|
||||
def str2closest_html_color_name(s: str) -> str:
|
||||
""" Transform str -> closest color name """
|
||||
if 'rgb' in s:
|
||||
rgb_str = 'rgba' if ('rgba' in s) else 'rgb'
|
||||
@@ -82,7 +82,7 @@ def str2closest_html_color_name(s: str):
|
||||
return ''
|
||||
|
||||
|
||||
def rgba2rgb(r, g, b, alpha):
|
||||
def rgba2rgb(r: int, g: int, b: int, alpha: float) -> Tuple[int, int, int]:
|
||||
""" Transform rgba -> rgb """
|
||||
r_background, g_background, b_background = 255, 255, 255
|
||||
r_new = int((1 - alpha) * r_background + alpha * r)
|
||||
@@ -91,7 +91,7 @@ def rgba2rgb(r, g, b, alpha):
|
||||
return r_new, g_new, b_new
|
||||
|
||||
|
||||
def str2hex(s: str):
|
||||
def str2hex(s: str) -> str:
|
||||
""" Transform str -> hex """
|
||||
if '#' in s and (len(s) <= 7):
|
||||
return s.lower()
|
||||
@@ -131,7 +131,6 @@ def str2hex(s: str):
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
colors = [
|
||||
(75, 0, 130), (255, 0, 255),
|
||||
(139, 69, 19), (46, 139, 87),
|
||||
|
||||
@@ -1,51 +1,60 @@
|
||||
import os
|
||||
import logging
|
||||
from typing import Union
|
||||
|
||||
|
||||
class ColoredFormatter(logging.Formatter):
|
||||
""" Class to prettify logger and command line output """
|
||||
MAPPING = {
|
||||
'DEBUG': 37, # white
|
||||
'INFO': 36, # cyan
|
||||
'WARNING': 33, # yellow
|
||||
'ERROR': 31, # red
|
||||
'CRITICAL': 41, # white on red bg
|
||||
"DEBUG": 37, # white
|
||||
"INFO": 36, # cyan
|
||||
"WARNING": 33, # yellow
|
||||
"ERROR": 31, # red
|
||||
"CRITICAL": 41, # white on red bg
|
||||
}
|
||||
|
||||
PREFIX = '\033['
|
||||
SUFFIX = '\033[0m'
|
||||
PREFIX = "\033["
|
||||
SUFFIX = "\033[0m"
|
||||
|
||||
def __init__(self, pattern):
|
||||
logging.Formatter.__init__(self, pattern)
|
||||
|
||||
def format(self, record):
|
||||
seq = self.MAPPING.get(record.levelname, 37) # default white
|
||||
record.levelname = '{0}{1}m{2}{3}' \
|
||||
record.levelname = "{0}{1}m{2}{3}" \
|
||||
.format(self.PREFIX, seq, record.levelname, self.SUFFIX)
|
||||
return logging.Formatter.format(self, record)
|
||||
|
||||
|
||||
class BookLogger:
|
||||
def __init__(self, name, book_id, main_logger=None,
|
||||
filemode='w+', logging_level=logging.INFO,
|
||||
logging_format='%(asctime)s - %(levelname)s - %(message)s [%(filename)s:%(lineno)d in %(funcName)s]'):
|
||||
def __init__(self, name: str, book_id: Union[int, str], main_logger: logging.Logger = None,
|
||||
filemode: str = "w+", logging_level: int = logging.INFO,
|
||||
logging_format: str = "%(asctime)s - %(levelname)s - %(message)s [%(filename)s:%(lineno)d in %(funcName)s]"):
|
||||
"""
|
||||
Method for Logger configuration. Logger will write to file.
|
||||
:param name: name of the Logger.
|
||||
:param attr_name: name of attribute that will be added to self.
|
||||
:param filename: name of the log file.
|
||||
:param filemode: mode of opening log file.
|
||||
:param logging_level: logging level: 10 - debug, 20 - info, 30 - warning, 40 - error, 50 - critical.
|
||||
:param logging_format: format of record in log file.
|
||||
Parameters
|
||||
----------
|
||||
name: str
|
||||
name of the Logger
|
||||
book_id: Union[int, str]
|
||||
id of the book
|
||||
main_logger: Logger
|
||||
main logger of the converter
|
||||
filemode: str
|
||||
mode of opening log file.
|
||||
logging_level: int
|
||||
logging level: 10 - debug, 20 - info, 30 - warning, 40 - error, 50 - critical
|
||||
logging_format: str
|
||||
format of record in log file
|
||||
|
||||
"""
|
||||
self.main_logger = main_logger
|
||||
|
||||
self.logger = logging.getLogger(name)
|
||||
self.logger.propagate = False
|
||||
folder_path = os.path.dirname(
|
||||
os.path.dirname(os.path.abspath(__file__)))
|
||||
folder_path = os.path.dirname(folder_path)
|
||||
filename = f'logs/{book_id}.log'
|
||||
filename = f"logs/{book_id}.log"
|
||||
file_path = os.path.join(folder_path, filename)
|
||||
file_handler = logging.FileHandler(file_path, mode=filemode)
|
||||
file_format = logging.Formatter(logging_format)
|
||||
@@ -58,42 +67,46 @@ class BookLogger:
|
||||
self.logger.addHandler(stream_handler)
|
||||
self.logger.setLevel(logging_level)
|
||||
|
||||
def log(self, message, logging_level=20):
|
||||
def log(self, message: str, logging_level: int = 20):
|
||||
"""
|
||||
Method for logging.
|
||||
Parameters
|
||||
----------
|
||||
message: str
|
||||
body of the message
|
||||
logging_level: int
|
||||
level of logging
|
||||
|
||||
:param message: body of the message
|
||||
:param logging_level: level of logging
|
||||
"""
|
||||
self.logger.log(msg=message, level=logging_level, stacklevel=2)
|
||||
|
||||
def log_error_to_main_log(self, message=''):
|
||||
def log_error_to_main_log(self, message: str = ""):
|
||||
""" Method for logging error to main log file. """
|
||||
if self.main_logger:
|
||||
if not message:
|
||||
message = f'Error in book conversion. Check log file.'
|
||||
message = f"Error in book conversion. Check log file."
|
||||
self.main_logger.error(message)
|
||||
|
||||
|
||||
class BookStatusWrapper:
|
||||
"""Class sets/updates statuses of Converter on Platform"""
|
||||
|
||||
def __init__(self, access, logger_object, book_id=0):
|
||||
def __init__(self, access, logger_object: BookLogger, book_id: int = 0):
|
||||
self.access = access
|
||||
self.logger_object = logger_object
|
||||
self.book_id = book_id
|
||||
|
||||
def set_status(self, status: str):
|
||||
str_2_status = {
|
||||
'[PROCESS]': self.access.PROCESS,
|
||||
'[GENERATE]': self.access.GENERATE,
|
||||
'[ERROR]': self.access.ERROR
|
||||
"[PROCESS]": self.access.PROCESS,
|
||||
"[GENERATE]": self.access.GENERATE,
|
||||
"[ERROR]": self.access.ERROR
|
||||
}
|
||||
|
||||
try:
|
||||
if self.access:
|
||||
self.access.update_status(self.book_id, str_2_status[status])
|
||||
self.logger_object.log(f'Status has been updated to {status}.')
|
||||
self.logger_object.log(f"Status has been updated to {status}.")
|
||||
except Exception as exc:
|
||||
self.logger_object.log(
|
||||
f"Can't update status of the book {status}.", logging.ERROR)
|
||||
@@ -101,10 +114,10 @@ class BookStatusWrapper:
|
||||
raise exc
|
||||
|
||||
def set_processing(self):
|
||||
self.set_status('[PROCESS]')
|
||||
self.set_status("[PROCESS]")
|
||||
|
||||
def set_generating(self):
|
||||
self.set_status('[GENERATE]')
|
||||
self.set_status("[GENERATE]")
|
||||
|
||||
def set_error(self):
|
||||
self.set_status('[ERROR]')
|
||||
self.set_status("[ERROR]")
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from webcolors import html4_hex_to_names, hex_to_rgb
|
||||
from webcolors import hex_to_rgb
|
||||
|
||||
# 16 основных цветов, hex соответвуют hex цветам livecarta
|
||||
# названия другие
|
||||
@@ -42,18 +42,23 @@ for key, name in html4_hex_to_names.items():
|
||||
HTML_COLORS_HSV[name] = (h, s, v)
|
||||
|
||||
|
||||
def rgb2closest_html_color_name(color):
|
||||
def rgb2closest_html_color_name(color: str):
|
||||
"""
|
||||
|
||||
- get color in hsv (hue, saturation, value)
|
||||
- try to match with black, grey, silver (black, darkGray, lightGray) as this colors matches badly even in hsv model
|
||||
|
||||
- calc hue difference between color and all base colors
|
||||
- if for new base color hue diff same as for any other, try to measure saturation and value
|
||||
(it happens for similar colors like red - pink, blue - dark blue)
|
||||
Parameters
|
||||
----------
|
||||
color: str
|
||||
color in hex
|
||||
|
||||
Returns
|
||||
-------
|
||||
base color name that matches best to a given color
|
||||
|
||||
:param color: str, color in hex
|
||||
:return: base color name that matches best to a given color
|
||||
"""
|
||||
|
||||
if color == (255, 255, 255):
|
||||
|
||||
Reference in New Issue
Block a user