From 27e8fbd248a52c5546f801c483973439586d53e2 Mon Sep 17 00:00:00 2001 From: Ozzieisaacs Date: Sat, 6 Nov 2021 20:17:00 +0400 Subject: [PATCH 1/2] Show dependencies in about section from automatic dependency check Bugfix and refactored dependency check Added output of googledrive dependencies as fallback option --- cps/about.py | 88 +++++++++++++++++++------------- cps/dep_check.py | 122 ++++++++++++++++++++++++--------------------- cps/editbooks.py | 4 +- cps/gdriveutils.py | 14 ++++++ cps/uploader.py | 53 ++++++++++---------- 5 files changed, 162 insertions(+), 119 deletions(-) diff --git a/cps/about.py b/cps/about.py index f3c8b95f..54e29d55 100644 --- a/cps/about.py +++ b/cps/about.py @@ -33,8 +33,9 @@ try: except ImportError: flaskwtf_version = _(u'not installed') -from . import db, calibre_db, converter, uploader, server, isoLanguages, constants +from . import db, calibre_db, converter, uploader, server, isoLanguages, constants, gdriveutils, dep_check from .render_template import render_title_template + try: from flask_login import __version__ as flask_loginVersion except ImportError: @@ -67,38 +68,59 @@ from . import services about = flask.Blueprint('about', __name__) +ret = dict() +req = dep_check.load_dependencys(False) +opt = dep_check.load_dependencys(True) +for i in (req + opt): + ret[i[1]] = i[0] -_VERSIONS = OrderedDict( - Platform = '{0[0]} {0[2]} {0[3]} {0[4]} {0[5]}'.format(platform.uname()), - Python=sys.version, - Calibre_Web=constants.STABLE_VERSION['version'] + ' - ' - + constants.NIGHTLY_VERSION[0].replace('%','%%') + ' - ' - + constants.NIGHTLY_VERSION[1].replace('%','%%'), - WebServer=server.VERSION, - Flask=flask.__version__, - Flask_Login=flask_loginVersion, - Flask_Principal=flask_principal.__version__, - Flask_WTF=flaskwtf_version, - Werkzeug=werkzeug.__version__, - Babel=babel.__version__, - Jinja2=jinja2.__version__, - Requests=requests.__version__, - SqlAlchemy=sqlalchemy.__version__, - pySqlite=sqlite3.version, - SQLite=sqlite3.sqlite_version, - iso639=isoLanguages.__version__, - pytz=pytz.__version__, - Unidecode=unidecode_version, - Scholarly=scholarly_version, - Flask_SimpleLDAP=u'installed' if bool(services.ldap) else None, - python_LDAP=services.ldapVersion if bool(services.ldapVersion) else None, - Goodreads=u'installed' if bool(services.goodreads_support) else None, - jsonschema=services.SyncToken.__version__ if bool(services.SyncToken) else None, - flask_dance=flask_danceVersion, - greenlet=greenlet_Version -) -_VERSIONS.update(uploader.get_versions()) - +if not ret: + _VERSIONS = OrderedDict( + Platform = '{0[0]} {0[2]} {0[3]} {0[4]} {0[5]}'.format(platform.uname()), + Python=sys.version, + Calibre_Web=constants.STABLE_VERSION['version'] + ' - ' + + constants.NIGHTLY_VERSION[0].replace('%','%%') + ' - ' + + constants.NIGHTLY_VERSION[1].replace('%','%%'), + WebServer=server.VERSION, + Flask=flask.__version__, + Flask_Login=flask_loginVersion, + Flask_Principal=flask_principal.__version__, + Flask_WTF=flaskwtf_version, + Werkzeug=werkzeug.__version__, + Babel=babel.__version__, + Jinja2=jinja2.__version__, + Requests=requests.__version__, + SqlAlchemy=sqlalchemy.__version__, + pySqlite=sqlite3.version, + SQLite=sqlite3.sqlite_version, + iso639=isoLanguages.__version__, + pytz=pytz.__version__, + Unidecode=unidecode_version, + Scholarly=scholarly_version, + Flask_SimpleLDAP=u'installed' if bool(services.ldap) else None, + python_LDAP=services.ldapVersion if bool(services.ldapVersion) else None, + Goodreads=u'installed' if bool(services.goodreads_support) else None, + jsonschema=services.SyncToken.__version__ if bool(services.SyncToken) else None, + flask_dance=flask_danceVersion, + greenlet=greenlet_Version + ) + _VERSIONS.update(gdriveutils.get_versions()) + _VERSIONS.update(uploader.get_versions(True)) +else: + _VERSIONS = OrderedDict( + Platform = '{0[0]} {0[2]} {0[3]} {0[4]} {0[5]}'.format(platform.uname()), + Python = sys.version, + Calibre_Web = constants.STABLE_VERSION['version'] + ' - ' + + constants.NIGHTLY_VERSION[0].replace('%', '%%') + ' - ' + + constants.NIGHTLY_VERSION[1].replace('%', '%%'), + Werkzeug = werkzeug.__version__, + Jinja2=jinja2.__version__, + pySqlite = sqlite3.version, + SQLite = sqlite3.sqlite_version, + Unidecode=unidecode_version, + ) + _VERSIONS.update(ret) + _VERSIONS.update(uploader.get_versions(False)) def collect_stats(): _VERSIONS['ebook converter'] = _(converter.get_calibre_version()) @@ -115,5 +137,3 @@ def stats(): series = calibre_db.session.query(db.Series).count() return render_title_template('stats.html', bookcounter=counter, authorcounter=authors, versions=collect_stats(), categorycounter=categorys, seriecounter=series, title=_(u"Statistics"), page="stat") - - diff --git a/cps/dep_check.py b/cps/dep_check.py index 9a982fec..1877576a 100644 --- a/cps/dep_check.py +++ b/cps/dep_check.py @@ -18,66 +18,76 @@ if not importlib: except ImportError as e: pkgresources = False -def dependency_check(optional=False): - dep = list() +def load_dependencys(optional=False): + deps = list() if importlib or pkgresources: if optional: req_path = os.path.join(BASE_DIR, "optional-requirements.txt") else: req_path = os.path.join(BASE_DIR, "requirements.txt") if os.path.exists(req_path): - try: - with open(req_path, 'r') as f: - for line in f: - if not line.startswith('#') and not line == '\n' and not line.startswith('git'): - res = re.match(r'(.*?)([<=>\s]+)([\d\.]+),?\s?([<=>\s]+)?([\d\.]+)?', line.strip()) - try: - if importlib: - dep_version = version(res.group(1)) - else: - dep_version = pkg_resources.get_distribution(res.group(1)).version - except ImportNotFound: - if optional: - continue - else: - return [{'name':res.group(1), - 'target': "available", - 'found': "Not available" - }] + with open(req_path, 'r') as f: + for line in f: + if not line.startswith('#') and not line == '\n' and not line.startswith('git'): + res = re.match(r'(.*?)([<=>\s]+)([\d\.]+),?\s?([<=>\s]+)?([\d\.]+)?', line.strip()) + try: + if importlib: + dep_version = version(res.group(1)) + else: + dep_version = pkg_resources.get_distribution(res.group(1)).version + except ImportNotFound: + if optional: + continue + '''else: + return [{'name':res.group(1), + 'target': "available", + 'found': "Not available" + }]''' + deps.append([dep_version, res.group(1), res.group(2), res.group(3), res.group(4), res.group(5)]) + return deps - if res.group(2).strip() == "==": - if dep_version.split('.') != res.group(3).split('.'): - dep.append({'name': res.group(1), - 'found': dep_version, - "target": res.group(2) + res.group(3)}) - continue - elif res.group(2).strip() == ">=": - if dep_version.split('.') < res.group(3).split('.'): - dep.append({'name': res.group(1), - 'found': dep_version, - "target": res.group(2) + res.group(3)}) - continue - elif res.group(2).strip() == ">": - if dep_version.split('.') <= res.group(3).split('.'): - dep.append({'name': res.group(1), - 'found': dep_version, - "target": res.group(2) + res.group(3)}) - continue - if res.group(4) and res.group(5): - if res.group(4).strip() == "<": - if dep_version.split('.') >= res.group(5).split('.'): - dep.append( - {'name': res.group(1), - 'found': dep_version, - "target": res.group(4) + res.group(5)}) - continue - elif res.group(2).strip() == "<=": - if dep_version.split('.') > res.group(5).split('.'): - dep.append( - {'name': res.group(1), - 'found': dep_version, - "target": res.group(4) + res.group(5)}) - continue - except Exception as e: - print(e) - return dep + +def dependency_check(optional=False): + d = list() + deps = load_dependencys(optional) + for dep in deps: + dep_version_int = [int(x) for x in dep[0].split('.')] + low_check = [int(x) for x in dep[3].split('.')] + try: + high_check = [int(x) for x in dep[5].split('.')] + except AttributeError: + high_check = None + if dep[2].strip() == "==": + if dep_version_int != low_check: + d.append({'name': dep[1], + 'found': dep[0], + "target": dep[2] + dep[3]}) + continue + elif dep[2].strip() == ">=": + if dep_version_int < low_check: + d.append({'name': dep[1], + 'found': dep[0], + "target": dep[2] + dep[3]}) + continue + elif dep[2].strip() == ">": + if dep_version_int <= low_check: + d.append({'name': dep[1], + 'found': dep[0], + "target": dep[2] + dep[3]}) + continue + if dep[4] and dep[5]: + if dep[4].strip() == "<": + if dep_version_int >= high_check: + d.append( + {'name': dep[1], + 'found': dep[0], + "target": dep[4] + dep[5]}) + continue + elif dep[4].strip() == "<=": + if dep_version_int > high_check: + d.append( + {'name': dep[1], + 'found': dep[0], + "target": dep[4] + dep[5]}) + continue + return d diff --git a/cps/editbooks.py b/cps/editbooks.py index 263a69fb..3403f46f 100644 --- a/cps/editbooks.py +++ b/cps/editbooks.py @@ -114,7 +114,7 @@ def search_objects_add(db_book_object, db_type, input_elements): type_elements = c_elements.value else: type_elements = c_elements.name - if inp_element == type_elements: + if inp_element.lower() == type_elements.lower(): # Lowercase check found = True break if not found: @@ -503,7 +503,7 @@ def edit_book_languages(languages, book, upload=False, invalid=None): def edit_book_publisher(publishers, book): changed = False - if publishers: + if publishers: publisher = publishers.rstrip().strip() if len(book.publishers) == 0 or (len(book.publishers) > 0 and publisher != book.publishers[0].name): changed |= modify_database_object([publisher], book.publishers, db.Publishers, calibre_db.session, diff --git a/cps/gdriveutils.py b/cps/gdriveutils.py index d3277814..878c1f9f 100644 --- a/cps/gdriveutils.py +++ b/cps/gdriveutils.py @@ -35,6 +35,15 @@ except ImportError: from sqlalchemy.exc import OperationalError, InvalidRequestError from sqlalchemy.sql.expression import text +try: + from six import __version__ as six_version +except ImportError: + six_version = "not installed" +try: + from httplib2 import __version__ as httplib2_version +except ImportError: + httplib2_version = "not installed" + try: from apiclient import errors from httplib2 import ServerNotFoundError @@ -659,3 +668,8 @@ def get_error_text(client_secrets=None): return 'Callback url (redirect url) is missing in client_secrets.json' if client_secrets: client_secrets.update(filedata['web']) + + +def get_versions(): + return {'six': six_version, + 'httplib2': httplib2_version} diff --git a/cps/uploader.py b/cps/uploader.py index 92a73381..f238b89d 100644 --- a/cps/uploader.py +++ b/cps/uploader.py @@ -157,7 +157,7 @@ def parse_xmp(pdf_file): def parse_xmp(pdf_file): """ - Parse XMP Metadata and prepare for BookMeta object + Parse XMP Metadata and prepare for BookMeta object """ try: xmp_info = pdf_file.getXmpMetadata() @@ -170,8 +170,8 @@ def parse_xmp(pdf_file): xmp_author = xmp_info.dc_creator # list except AttributeError: xmp_author = ['Unknown'] - - if xmp_info.dc_title: + + if xmp_info.dc_title: xmp_title = xmp_info.dc_title['x-default'] else: xmp_title = '' @@ -187,7 +187,7 @@ def parse_xmp(pdf_file): languages.append(isoLanguages.get_lang3(i)) except AttributeError: languages.append('') - + xmp_tags = ', '.join(xmp_info.dc_subject) xmp_publisher = ', '.join(xmp_info.dc_publisher) @@ -274,31 +274,30 @@ def pdf_preview(tmp_file_path, tmp_dir): return None -def get_versions(): +def get_versions(all=True): + ret = dict() if not use_generic_pdf_cover: - IVersion = ImageVersion.MAGICK_VERSION - WVersion = ImageVersion.VERSION + ret['Image Magick'] = ImageVersion.MAGICK_VERSION else: - IVersion = u'not installed' - WVersion = u'not installed' - if use_pdf_meta: - PVersion='v'+PyPdfVersion - else: - PVersion=u'not installed' - if lxmlversion: - XVersion = 'v'+'.'.join(map(str, lxmlversion)) - else: - XVersion = u'not installed' - if comic.use_comic_meta: - ComicVersion = comic.comic_version or u'installed' - else: - ComicVersion = u'not installed' - return {'Image Magick': IVersion, - 'PyPdf': PVersion, - 'lxml':XVersion, - 'Wand': WVersion, - # 'Pillow': PILVersion, - 'Comic_API': ComicVersion} + ret['Image Magick'] = u'not installed' + if all: + if not use_generic_pdf_cover: + ret['Wand'] = ImageVersion.VERSION + else: + ret['Wand'] = u'not installed' + if use_pdf_meta: + ret['PyPdf'] = PyPdfVersion + else: + ret['PyPdf'] = u'not installed' + if lxmlversion: + ret['lxml'] = '.'.join(map(str, lxmlversion)) + else: + ret['lxml'] = u'not installed' + if comic.use_comic_meta: + ret['Comic_API'] = comic.comic_version or u'installed' + else: + ret['Comic_API'] = u'not installed' + return ret def upload(uploadfile, rarExcecutable): From 60aa016734970ef31cce784306f5cbac53bbbe22 Mon Sep 17 00:00:00 2001 From: Ozzieisaacs Date: Sat, 6 Nov 2021 21:17:48 +0400 Subject: [PATCH 2/2] Handling of missing required dependency during dependency check --- cps/__init__.py | 2 +- cps/about.py | 1 - cps/dep_check.py | 17 ++++++++++------- 3 files changed, 11 insertions(+), 9 deletions(-) diff --git a/cps/__init__.py b/cps/__init__.py index a1a721c7..118b46ff 100644 --- a/cps/__init__.py +++ b/cps/__init__.py @@ -129,7 +129,7 @@ def create_app(): web_server.stop(True) sys.exit(7) for res in dependency_check() + dependency_check(True): - log.info('*** "{}" version does not fit the requirements. Should: {}, Found: {}, please consider updating. ***' + log.info('*** "{}" version does not fit the requirements. Should: {}, Found: {}, please consider installing required version ***' .format(res['name'], res['target'], res['found'])) diff --git a/cps/about.py b/cps/about.py index 54e29d55..ba5a99af 100644 --- a/cps/about.py +++ b/cps/about.py @@ -117,7 +117,6 @@ else: Jinja2=jinja2.__version__, pySqlite = sqlite3.version, SQLite = sqlite3.sqlite_version, - Unidecode=unidecode_version, ) _VERSIONS.update(ret) _VERSIONS.update(uploader.get_versions(False)) diff --git a/cps/dep_check.py b/cps/dep_check.py index 1877576a..12436d1d 100644 --- a/cps/dep_check.py +++ b/cps/dep_check.py @@ -38,11 +38,7 @@ def load_dependencys(optional=False): except ImportNotFound: if optional: continue - '''else: - return [{'name':res.group(1), - 'target': "available", - 'found': "Not available" - }]''' + dep_version = "not installed" deps.append([dep_version, res.group(1), res.group(2), res.group(3), res.group(4), res.group(5)]) return deps @@ -51,12 +47,19 @@ def dependency_check(optional=False): d = list() deps = load_dependencys(optional) for dep in deps: - dep_version_int = [int(x) for x in dep[0].split('.')] - low_check = [int(x) for x in dep[3].split('.')] try: + dep_version_int = [int(x) for x in dep[0].split('.')] + low_check = [int(x) for x in dep[3].split('.')] high_check = [int(x) for x in dep[5].split('.')] except AttributeError: high_check = None + except ValueError: + d.append({'name': dep[1], + 'target': "available", + 'found': "Not available" + }) + continue + if dep[2].strip() == "==": if dep_version_int != low_check: d.append({'name': dep[1],