diff --git a/ebook_converter/__init__.py b/ebook_converter/__init__.py index b6f80e7..328d81b 100644 --- a/ebook_converter/__init__.py +++ b/ebook_converter/__init__.py @@ -3,7 +3,6 @@ import os import pkg_resources import re import sys -import time import mimetypes from functools import partial @@ -13,10 +12,11 @@ try: except EnvironmentError: os.chdir(os.path.expanduser('~')) -from ebook_converter.constants_old import iswindows, islinux, isfrozen, \ - isbsd, preferred_encoding, __appname__, __version__, __author__, \ +from ebook_converter import constants_old +from ebook_converter.constants_old import islinux, isfrozen, \ + isbsd, __appname__, __version__, __author__, \ win32event, win32api, winerror, fcntl, \ - filesystem_encoding, plugins, config_dir + config_dir from ebook_converter.startup import winutil, winutilerror from ebook_converter.utils.icu import safe_chr @@ -41,7 +41,7 @@ def guess_extension(*args, **kwargs): def unicode_path(path, abs=False): if isinstance(path, bytes): - path = path.decode(filesystem_encoding) + path = path.decode(constants_old.filesystem_encoding) if abs: path = os.path.abspath(path) return path @@ -68,9 +68,10 @@ def sanitize_file_name(name, substitute='_'): """ if isinstance(name, bytes): - name = name.decode(filesystem_encoding, 'replace') + name = name.decode(constants_old.filesystem_encoding, 'replace') if isinstance(substitute, bytes): - substitute = substitute.decode(filesystem_encoding, 'replace') + substitute = substitute.decode(constants_old.filesystem_encoding, + 'replace') chars = (substitute if c in _filename_sanitize_unicode else c for c in name) one = ''.join(chars) @@ -99,7 +100,8 @@ def prints(*args, **kwargs): """ file = kwargs.get('file', sys.stdout) file = getattr(file, 'buffer', file) - enc = 'utf-8' if os.getenv('CALIBRE_WORKER') else preferred_encoding + enc = ('utf-8' if os.getenv('CALIBRE_WORKER') + else constants_old.preferred_encoding) sep = kwargs.get('sep', ' ') if not isinstance(sep, bytes): sep = sep.encode(enc) @@ -110,7 +112,7 @@ def prints(*args, **kwargs): count = 0 for i, arg in enumerate(args): if isinstance(arg, str): - if iswindows: + if constants_old.iswindows: from ebook_converter.utils.terminal import Detect cs = Detect(file) if cs.is_console: @@ -257,40 +259,6 @@ def walk(dir): yield os.path.join(record[0], f) -def strftime(fmt, t=None): - """ - A version of strftime that returns unicode strings and tries to handle - dates before 1900 - """ - if not fmt: - return '' - if t is None: - t = time.localtime() - if hasattr(t, 'timetuple'): - t = t.timetuple() - early_year = t[0] < 1900 - if early_year: - replacement = 1900 if t[0] % 4 == 0 else 1901 - fmt = fmt.replace('%Y', '_early year hack##') - t = list(t) - orig_year = t[0] - t[0] = replacement - t = time.struct_time(t) - ans = None - if iswindows: - if isinstance(fmt, bytes): - fmt = fmt.decode('mbcs', 'replace') - fmt = fmt.replace('%e', '%#d') - ans = plugins['winutil'][0].strftime(fmt, t) - else: - ans = time.strftime(fmt, t) - if isinstance(ans, bytes): - ans = ans.decode(preferred_encoding, 'replace') - if early_year: - ans = ans.replace('_early year hack##', str(orig_year)) - return ans - - def my_unichr(num): try: return safe_chr(num) @@ -380,14 +348,15 @@ def prepare_string_for_xml(raw, attribute=False): return raw -def force_unicode(obj, enc=preferred_encoding): +def force_unicode(obj, enc=constants_old.preferred_encoding): if isinstance(obj, bytes): try: obj = obj.decode(enc) except Exception: try: - obj = obj.decode(filesystem_encoding if enc == - preferred_encoding else preferred_encoding) + obj = obj.decode(constants_old.filesystem_encoding + if enc == constants_old.preferred_encoding + else constants_old.preferred_encoding) except Exception: try: obj = obj.decode('utf-8') diff --git a/ebook_converter/ebooks/conversion/plumber.py b/ebook_converter/ebooks/conversion/plumber.py index 3b39790..bfe0dcb 100644 --- a/ebook_converter/ebooks/conversion/plumber.py +++ b/ebook_converter/ebooks/conversion/plumber.py @@ -14,8 +14,8 @@ from ebook_converter.ebooks.conversion.preprocess import HTMLPreProcessor from ebook_converter.ptempfile import PersistentTemporaryDirectory from ebook_converter.utils.date import parse_date from ebook_converter.utils.zipfile import ZipFile -from ebook_converter import extract, walk, filesystem_encoding -from ebook_converter.constants_old import __version__ +from ebook_converter import extract, walk +from ebook_converter.constants_old import __version__, filesystem_encoding DEBUG_README=b''' diff --git a/ebook_converter/ebooks/lrf/html/convert_from.py b/ebook_converter/ebooks/lrf/html/convert_from.py index 7b35760..20d0d93 100644 --- a/ebook_converter/ebooks/lrf/html/convert_from.py +++ b/ebook_converter/ebooks/lrf/html/convert_from.py @@ -20,10 +20,10 @@ from math import ceil, floor import bs4 -from ebook_converter import ( - __appname__, entity_to_unicode, fit_image, force_unicode, preferred_encoding -) -from ebook_converter.constants_old import filesystem_encoding +from ebook_converter import __appname__, entity_to_unicode, fit_image, \ + force_unicode +from ebook_converter.constants_old import filesystem_encoding, \ + preferred_encoding from ebook_converter.devices.interface import DevicePlugin as Device from ebook_converter.ebooks import ConversionError from ebook_converter.ebooks.BeautifulSoup import html5_parser diff --git a/ebook_converter/ebooks/oeb/transforms/jacket.py b/ebook_converter/ebooks/oeb/transforms/jacket.py index 716e138..6781c3b 100644 --- a/ebook_converter/ebooks/oeb/transforms/jacket.py +++ b/ebook_converter/ebooks/oeb/transforms/jacket.py @@ -8,12 +8,11 @@ import urllib.parse from xml.sax import saxutils from ebook_converter import constants as const -from ebook_converter import strftime +from ebook_converter.utils import date from ebook_converter.constants_old import iswindows from ebook_converter.ebooks.oeb import base from ebook_converter.ebooks.oeb.base import XPath, xml2text, urlnormalize from ebook_converter.library.comments import comments_to_html, markdown -from ebook_converter.utils.date import is_date_undefined, as_local_time from ebook_converter.ebooks.chardet import strip_encoding_declarations from ebook_converter.ebooks.metadata import fmt_sidx, rating_to_stars @@ -272,11 +271,11 @@ def render_jacket(mi, output_profile, alt_title='Unknown', alt_tags=[], publisher = saxutils.escape(publisher) try: - if is_date_undefined(mi.pubdate): + if date.is_date_undefined(mi.pubdate): pubdate = '' else: - dt = as_local_time(mi.pubdate) - pubdate = strftime('%Y', dt.timetuple()) + dt = date.as_local_time(mi.pubdate) + pubdate = date.strftime('%Y', dt.timetuple()) except Exception: pubdate = '' diff --git a/ebook_converter/library/catalogs/bibtex.py b/ebook_converter/library/catalogs/bibtex.py index 5a3e477..ea5568b 100644 --- a/ebook_converter/library/catalogs/bibtex.py +++ b/ebook_converter/library/catalogs/bibtex.py @@ -1,7 +1,7 @@ import re, codecs, os, numbers from collections import namedtuple -from ebook_converter import strftime +from ebook_converter.utils import date from ebook_converter.customize import CatalogPlugin from ebook_converter.library.catalogs import FIELDS, TEMPLATE_ALLOWED_FIELDS from ebook_converter.customize.conversion import DummyReporter @@ -206,7 +206,7 @@ class BIBTEX(CatalogPlugin): elif field == 'pubdate' : bibtex_entry.append('year = "%s"' % item.year) - bibtex_entry.append('month = "%s"' % bibtexdict.utf8ToBibtex(strftime("%b", item))) + bibtex_entry.append('month = "%s"' % bibtexdict.utf8ToBibtex(date.strftime("%b", item))) elif field.startswith('#') and isinstance(item, (str, bytes)): bibtex_entry.append('custom_%s = "%s"' % (field[1:], @@ -392,7 +392,7 @@ class BIBTEX(CatalogPlugin): outfile.write('%%%Calibre catalog\n%%%{0} entries in catalog\n\n'.format(nb_entries)) outfile.write('@preamble{"This catalog of %d entries was generated by calibre on %s"}\n\n' - % (nb_entries, strftime("%A, %d. %B %Y %H:%M"))) + % (nb_entries, date.strftime("%A, %d. %B %Y %H:%M"))) for entry in data: outfile.write(create_bibtex_entry(entry, fields, bib_entry, template_citation, diff --git a/ebook_converter/library/catalogs/epub_mobi.py b/ebook_converter/library/catalogs/epub_mobi.py index 8eb7d3d..2dae664 100644 --- a/ebook_converter/library/catalogs/epub_mobi.py +++ b/ebook_converter/library/catalogs/epub_mobi.py @@ -1,7 +1,7 @@ import datetime, os, time from collections import namedtuple -from ebook_converter import strftime +from ebook_converter.utils import date from ebook_converter.customize import CatalogPlugin from ebook_converter.customize.conversion import OptionRecommendation, DummyReporter from ebook_converter.library import current_library_name @@ -254,8 +254,8 @@ class EPUB_MOBI(CatalogPlugin): opts.fmt = self.fmt = path_to_output.rpartition('.')[2] # Add local options - opts.creator = '%s, %s %s, %s' % (strftime('%A'), strftime('%B'), strftime('%d').lstrip('0'), strftime('%Y')) - opts.creator_sort_as = '%s %s' % ('calibre', strftime('%Y-%m-%d')) + opts.creator = '%s, %s %s, %s' % (date.strftime('%A'), date.strftime('%B'), date.strftime('%d').lstrip('0'), date.strftime('%Y')) + opts.creator_sort_as = '%s %s' % ('calibre', date.strftime('%Y-%m-%d')) opts.connected_kindle = False # Finalize output_profile diff --git a/ebook_converter/utils/date.py b/ebook_converter/utils/date.py index db53b0d..34ba4dc 100644 --- a/ebook_converter/utils/date.py +++ b/ebook_converter/utils/date.py @@ -1,8 +1,8 @@ import re -from datetime import datetime, time as dtime, timedelta, MINYEAR, MAXYEAR -from functools import partial +import datetime +import time +import functools -from ebook_converter import strftime from ebook_converter.constants_old import iswindows, isosx, plugins, preferred_encoding from ebook_converter.utils.iso8601 import utc_tz, local_tz, UNDEFINED_DATE from ebook_converter.utils.localization import lcdata @@ -46,8 +46,8 @@ else: except: parse_date_day_first = False -DEFAULT_DATE = datetime(2000,1,1, tzinfo=utc_tz) -EPOCH = datetime(1970, 1, 1, tzinfo=_utc_tz) +DEFAULT_DATE = datetime.datetime(2000,1,1, tzinfo=utc_tz) +EPOCH = datetime.datetime(1970, 1, 1, tzinfo=_utc_tz) def is_date_undefined(qt_or_dt): @@ -58,7 +58,7 @@ def is_date_undefined(qt_or_dt): if hasattr(d, 'date'): d = d.date() try: - d = datetime(d.year(), d.month(), d.day(), tzinfo=utc_tz) + d = datetime.datetime(d.year(), d.month(), d.day(), tzinfo=utc_tz) except ValueError: return True # Undefined QDate return d.year < UNDEFINED_DATE.year or ( @@ -96,7 +96,8 @@ def parse_date(date_string, assume_utc=False, as_utc=True, default=None): if isinstance(date_string, bytes): date_string = date_string.decode(preferred_encoding, 'replace') if default is None: - func = datetime.utcnow if assume_utc else datetime.now + func = (datetime.datetime.utcnow if assume_utc + else datetime.datetime.now) default = func().replace(day=15, hour=0, minute=0, second=0, microsecond=0, tzinfo=_utc_tz if assume_utc else _local_tz) if iso_pat().match(date_string) is not None: @@ -109,7 +110,7 @@ def parse_date(date_string, assume_utc=False, as_utc=True, default=None): def fix_only_date(val): - n = val + timedelta(days=1) + n = val + datetime.timedelta(days=1) if n.month > val.month: val = val.replace(day=val.day-1) if val.day == 1: @@ -130,20 +131,20 @@ def parse_only_date(raw, assume_utc=True, as_utc=True): def strptime(val, fmt, assume_utc=False, as_utc=True): - dt = datetime.strptime(val, fmt) + dt = datetime.datetime.strptime(val, fmt) if dt.tzinfo is None: dt = dt.replace(tzinfo=_utc_tz if assume_utc else _local_tz) return dt.astimezone(_utc_tz if as_utc else _local_tz) def dt_factory(time_t, assume_utc=False, as_utc=True): - dt = datetime(*(time_t[0:6])) + dt = datetime.datetime(*(time_t[0:6])) if dt.tzinfo is None: dt = dt.replace(tzinfo=_utc_tz if assume_utc else _local_tz) return dt.astimezone(_utc_tz if as_utc else _local_tz) -safeyear = lambda x: min(max(x, MINYEAR), MAXYEAR) +safeyear = lambda x: min(max(x, datetime.MINYEAR), datetime.MAXYEAR) def qt_to_dt(qdate_or_qdatetime, as_utc=True): @@ -153,29 +154,29 @@ def qt_to_dt(qdate_or_qdatetime, as_utc=True): o = o.toUTC() d, t = o.date(), o.time() try: - ans = datetime(safeyear(d.year()), d.month(), d.day(), t.hour(), t.minute(), t.second(), t.msec()*1000, utc_tz) + ans = datetime.datetime(safeyear(d.year()), d.month(), d.day(), t.hour(), t.minute(), t.second(), t.msec()*1000, utc_tz) except ValueError: - ans = datetime(safeyear(d.year()), d.month(), 1, t.hour(), t.minute(), t.second(), t.msec()*1000, utc_tz) + ans = datetime.datetime(safeyear(d.year()), d.month(), 1, t.hour(), t.minute(), t.second(), t.msec()*1000, utc_tz) if not as_utc: ans = ans.astimezone(local_tz) return ans try: - dt = datetime(safeyear(o.year()), o.month(), o.day()).replace(tzinfo=_local_tz) + dt = datetime.datetime(safeyear(o.year()), o.month(), o.day()).replace(tzinfo=_local_tz) except ValueError: - dt = datetime(safeyear(o.year()), o.month(), 1).replace(tzinfo=_local_tz) + dt = datetime.datetime(safeyear(o.year()), o.month(), 1).replace(tzinfo=_local_tz) return dt.astimezone(_utc_tz if as_utc else _local_tz) def fromtimestamp(ctime, as_utc=True): - dt = datetime.utcfromtimestamp(ctime).replace(tzinfo=_utc_tz) + dt = datetime.datetime.utcfromtimestamp(ctime).replace(tzinfo=_utc_tz) if not as_utc: dt = dt.astimezone(_local_tz) return dt def fromordinal(day, as_utc=True): - return datetime.fromordinal(day).replace( + return datetime.datetime.fromordinal(day).replace( tzinfo=_utc_tz if as_utc else _local_tz) @@ -193,6 +194,40 @@ def internal_iso_format_string(): return 'yyyy-MM-ddThh:mm:ss' +def strftime(fmt, t=None): + """ + A version of strftime that returns unicode strings and tries to handle + dates before 1900 + """ + if not fmt: + return '' + if t is None: + t = time.localtime() + if hasattr(t, 'timetuple'): + t = t.timetuple() + early_year = t[0] < 1900 + if early_year: + replacement = 1900 if t[0] % 4 == 0 else 1901 + fmt = fmt.replace('%Y', '_early year hack##') + t = list(t) + orig_year = t[0] + t[0] = replacement + t = time.struct_time(t) + ans = None + if iswindows: + if isinstance(fmt, bytes): + fmt = fmt.decode('mbcs', 'replace') + fmt = fmt.replace('%e', '%#d') + ans = plugins['winutil'][0].strftime(fmt, t) + else: + ans = time.strftime(fmt, t) + if isinstance(ans, bytes): + ans = ans.decode(preferred_encoding, 'replace') + if early_year: + ans = ans.replace('_early year hack##', str(orig_year)) + return ans + + def w3cdtf(date_time, assume_utc=False): if hasattr(date_time, 'tzinfo'): if date_time.tzinfo is None: @@ -227,21 +262,21 @@ def as_utc(date_time, assume_utc=True): def now(): - return datetime.now().replace(tzinfo=_local_tz) + return datetime.datetime.now().replace(tzinfo=_local_tz) def utcnow(): - return datetime.utcnow().replace(tzinfo=_utc_tz) + return datetime.datetime.utcnow().replace(tzinfo=_utc_tz) def utcfromtimestamp(stamp): try: - return datetime.utcfromtimestamp(stamp).replace(tzinfo=_utc_tz) + return datetime.datetime.utcfromtimestamp(stamp).replace(tzinfo=_utc_tz) except ValueError: # Raised if stamp is out of range for the platforms gmtime function # For example, this happens with negative values on windows try: - return EPOCH + timedelta(seconds=stamp) + return EPOCH + datetime.timedelta(seconds=stamp) except (ValueError, OverflowError): # datetime can only represent years between 1 and 9999 import traceback @@ -334,8 +369,8 @@ def format_date(dt, format, assume_utc=False, as_utc=False): if not format: format = 'dd MMM yyyy' - if not isinstance(dt, datetime): - dt = datetime.combine(dt, dtime()) + if not isinstance(dt, datetime.datetime): + dt = datetime.datetime.combine(dt, datetime.time()) if hasattr(dt, 'tzinfo'): if dt.tzinfo is None: @@ -349,7 +384,7 @@ def format_date(dt, format, assume_utc=False, as_utc=False): if dt == UNDEFINED_DATE: return '' - repl_func = partial(fd_repl_func, dt, 'ap' in format.lower()) + repl_func = functools.partial(fd_repl_func, dt, 'ap' in format.lower()) return re.sub( '(s{1,2})|(m{1,2})|(h{1,2})|(ap)|(AP)|(d{1,4}|M{1,4}|(?:yyyy|yy))', repl_func, format) @@ -411,8 +446,8 @@ def clean_date_for_sort(dt, fmt=None): if not fmt: fmt = 'yyMd' - if not isinstance(dt, datetime): - dt = datetime.combine(dt, dtime()) + if not isinstance(dt, datetime.datetime): + dt = datetime.datetime.combine(dt, datetime.time()) if hasattr(dt, 'tzinfo'): if dt.tzinfo is None: @@ -426,7 +461,7 @@ def clean_date_for_sort(dt, fmt=None): 'day':UNDEFINED_DATE.day, 'hour':UNDEFINED_DATE.hour, 'min':UNDEFINED_DATE.minute, 'sec':UNDEFINED_DATE.second} - repl_func = partial(cd_repl_func, tt, dt) + repl_func = functools.partial(cd_repl_func, tt, dt) re.sub('(s{1,2})|(m{1,2})|(h{1,2})|(d{1,4}|M{1,4}|(?:yyyy|yy))', repl_func, fmt) return dt.replace(year=tt['year'], month=tt['mon'], day=tt['day'], hour=tt['hour'], minute=tt['min'], second=tt['sec'], microsecond=0)