mirror of
https://github.com/gryf/ebook-converter.git
synced 2025-12-30 14:02:27 +01:00
302 lines
9.8 KiB
Python
302 lines
9.8 KiB
Python
from __future__ import print_function, unicode_literals
|
|
__license__ = 'GPL v3'
|
|
__copyright__ = '2008, Kovid Goyal kovid@kovidgoyal.net'
|
|
__docformat__ = 'restructuredtext en'
|
|
|
|
'''
|
|
Perform various initialization tasks.
|
|
'''
|
|
|
|
import locale, sys, os
|
|
|
|
# Default translation is NOOP
|
|
from polyglot.builtins import builtins, is_py3, unicode_type
|
|
builtins.__dict__['_'] = lambda s: s
|
|
|
|
# For strings which belong in the translation tables, but which shouldn't be
|
|
# immediately translated to the environment language
|
|
builtins.__dict__['__'] = lambda s: s
|
|
|
|
# For backwards compat with some third party plugins
|
|
builtins.__dict__['dynamic_property'] = lambda func: func(None)
|
|
|
|
|
|
from calibre.constants import iswindows, preferred_encoding, plugins, isosx, islinux, isfrozen, DEBUG, isfreebsd, ispy3
|
|
|
|
_run_once = False
|
|
winutil = winutilerror = None
|
|
|
|
if not _run_once:
|
|
_run_once = True
|
|
from importlib import import_module
|
|
|
|
if not isfrozen and not ispy3:
|
|
# Prevent PyQt4 from being loaded
|
|
class PyQt4Ban(object):
|
|
|
|
def find_module(self, fullname, path=None):
|
|
if fullname.startswith('PyQt4'):
|
|
return self
|
|
|
|
def load_module(self, fullname):
|
|
raise ImportError('Importing PyQt4 is not allowed as calibre uses PyQt5')
|
|
|
|
sys.meta_path.insert(0, PyQt4Ban())
|
|
|
|
class DeVendor(object):
|
|
|
|
if ispy3:
|
|
|
|
def find_spec(self, fullname, path, target=None):
|
|
spec = None
|
|
if fullname == 'calibre.web.feeds.feedparser':
|
|
m = import_module('feedparser')
|
|
spec = m.__spec__
|
|
elif fullname.startswith('calibre.ebooks.markdown'):
|
|
m = import_module(fullname[len('calibre.ebooks.'):])
|
|
spec = m.__spec__
|
|
return spec
|
|
|
|
else:
|
|
|
|
def find_module(self, fullname, path=None):
|
|
if fullname == 'calibre.web.feeds.feedparser' or fullname.startswith('calibre.ebooks.markdown'):
|
|
return self
|
|
|
|
def load_module(self, fullname):
|
|
if fullname == 'calibre.web.feeds.feedparser':
|
|
return import_module('feedparser')
|
|
return import_module(fullname[len('calibre.ebooks.'):])
|
|
|
|
sys.meta_path.insert(0, DeVendor())
|
|
|
|
#
|
|
# Platform specific modules
|
|
if iswindows:
|
|
winutil, winutilerror = plugins['winutil']
|
|
if not winutil:
|
|
raise RuntimeError('Failed to load the winutil plugin: %s'%winutilerror)
|
|
if len(sys.argv) > 1 and not isinstance(sys.argv[1], unicode_type):
|
|
sys.argv[1:] = winutil.argv()[1-len(sys.argv):]
|
|
|
|
if not ispy3:
|
|
# Python2's expanduser is broken for non-ASCII usernames
|
|
# and unicode paths
|
|
|
|
def expanduser(path):
|
|
if isinstance(path, bytes):
|
|
path = path.decode('mbcs')
|
|
if path[:1] != '~':
|
|
return path
|
|
i, n = 1, len(path)
|
|
while i < n and path[i] not in '/\\':
|
|
i += 1
|
|
userhome = winutil.special_folder_path(winutil.CSIDL_PROFILE)
|
|
if i != 1: # ~user
|
|
userhome = os.path.join(os.path.dirname(userhome), path[1:i])
|
|
|
|
return userhome + path[i:]
|
|
os.path.expanduser = expanduser
|
|
|
|
# Ensure that all temp files/dirs are created under a calibre tmp dir
|
|
from calibre.ptempfile import base_dir
|
|
try:
|
|
base_dir()
|
|
except EnvironmentError:
|
|
pass # Ignore this error during startup, so we can show a better error message to the user later.
|
|
|
|
#
|
|
# Convert command line arguments to unicode
|
|
enc = preferred_encoding
|
|
if isosx:
|
|
enc = 'utf-8'
|
|
for i in range(1, len(sys.argv)):
|
|
if not isinstance(sys.argv[i], unicode_type):
|
|
sys.argv[i] = sys.argv[i].decode(enc, 'replace')
|
|
|
|
#
|
|
# Ensure that the max number of open files is at least 1024
|
|
if iswindows:
|
|
# See https://msdn.microsoft.com/en-us/library/6e3b887c.aspx
|
|
if hasattr(winutil, 'setmaxstdio'):
|
|
winutil.setmaxstdio(max(1024, winutil.getmaxstdio()))
|
|
else:
|
|
import resource
|
|
soft, hard = resource.getrlimit(resource.RLIMIT_NOFILE)
|
|
if soft < 1024:
|
|
try:
|
|
resource.setrlimit(resource.RLIMIT_NOFILE, (min(1024, hard), hard))
|
|
except Exception:
|
|
if DEBUG:
|
|
import traceback
|
|
traceback.print_exc()
|
|
|
|
#
|
|
# Setup resources
|
|
import calibre.utils.resources as resources
|
|
resources
|
|
|
|
#
|
|
# Setup translations
|
|
from calibre.utils.localization import set_translators
|
|
|
|
set_translators()
|
|
|
|
#
|
|
# Initialize locale
|
|
# Import string as we do not want locale specific
|
|
# string.whitespace/printable, on windows especially, this causes problems.
|
|
# Before the delay load optimizations, string was loaded before this point
|
|
# anyway, so we preserve the old behavior explicitly.
|
|
import string
|
|
string
|
|
try:
|
|
locale.setlocale(locale.LC_ALL, '') # set the locale to the user's default locale
|
|
except:
|
|
dl = locale.getdefaultlocale()
|
|
try:
|
|
if dl:
|
|
locale.setlocale(locale.LC_ALL, dl[0])
|
|
except:
|
|
pass
|
|
|
|
# local_open() opens a file that wont be inherited by child processes
|
|
if is_py3:
|
|
local_open = open # PEP 446
|
|
elif iswindows:
|
|
def local_open(name, mode='r', bufsize=-1):
|
|
mode += 'N'
|
|
return open(name, mode, bufsize)
|
|
elif isosx:
|
|
import fcntl
|
|
FIOCLEX = 0x20006601
|
|
|
|
def local_open(name, mode='r', bufsize=-1):
|
|
ans = open(name, mode, bufsize)
|
|
try:
|
|
fcntl.ioctl(ans.fileno(), FIOCLEX)
|
|
except EnvironmentError:
|
|
fcntl.fcntl(ans, fcntl.F_SETFD, fcntl.fcntl(ans, fcntl.F_GETFD) | fcntl.FD_CLOEXEC)
|
|
return ans
|
|
else:
|
|
import fcntl
|
|
try:
|
|
cloexec_flag = fcntl.FD_CLOEXEC
|
|
except AttributeError:
|
|
cloexec_flag = 1
|
|
supports_mode_e = False
|
|
|
|
def local_open(name, mode='r', bufsize=-1):
|
|
global supports_mode_e
|
|
mode += 'e'
|
|
ans = open(name, mode, bufsize)
|
|
if supports_mode_e:
|
|
return ans
|
|
old = fcntl.fcntl(ans, fcntl.F_GETFD)
|
|
if not (old & cloexec_flag):
|
|
fcntl.fcntl(ans, fcntl.F_SETFD, old | cloexec_flag)
|
|
else:
|
|
supports_mode_e = True
|
|
return ans
|
|
|
|
builtins.__dict__['lopen'] = local_open
|
|
|
|
from calibre.utils.icu import title_case, lower as icu_lower, upper as icu_upper
|
|
builtins.__dict__['icu_lower'] = icu_lower
|
|
builtins.__dict__['icu_upper'] = icu_upper
|
|
builtins.__dict__['icu_title'] = title_case
|
|
|
|
def connect_lambda(bound_signal, self, func, **kw):
|
|
import weakref
|
|
r = weakref.ref(self)
|
|
del self
|
|
num_args = func.__code__.co_argcount - 1
|
|
if num_args < 0:
|
|
raise TypeError('lambda must take at least one argument')
|
|
|
|
def slot(*args):
|
|
ctx = r()
|
|
if ctx is not None:
|
|
if len(args) != num_args:
|
|
args = args[:num_args]
|
|
func(ctx, *args)
|
|
|
|
bound_signal.connect(slot, **kw)
|
|
builtins.__dict__['connect_lambda'] = connect_lambda
|
|
|
|
if islinux or isosx or isfreebsd:
|
|
# Name all threads at the OS level created using the threading module, see
|
|
# http://bugs.python.org/issue15500
|
|
import threading
|
|
|
|
orig_start = threading.Thread.start
|
|
|
|
def new_start(self):
|
|
orig_start(self)
|
|
try:
|
|
name = self.name
|
|
if not name or name.startswith('Thread-'):
|
|
name = self.__class__.__name__
|
|
if name == 'Thread':
|
|
name = self.name
|
|
if name:
|
|
if isinstance(name, unicode_type):
|
|
name = name.encode('ascii', 'replace').decode('ascii')
|
|
plugins['speedup'][0].set_thread_name(name[:15])
|
|
except Exception:
|
|
pass # Don't care about failure to set name
|
|
threading.Thread.start = new_start
|
|
|
|
|
|
def test_lopen():
|
|
from calibre.ptempfile import TemporaryDirectory
|
|
from calibre import CurrentDir
|
|
n = 'f\xe4llen'
|
|
print('testing lopen()')
|
|
|
|
if iswindows:
|
|
import msvcrt, win32api
|
|
|
|
def assert_not_inheritable(f):
|
|
if win32api.GetHandleInformation(msvcrt.get_osfhandle(f.fileno())) & 0b1:
|
|
raise SystemExit('File handle is inheritable!')
|
|
else:
|
|
import fcntl
|
|
|
|
def assert_not_inheritable(f):
|
|
if not fcntl.fcntl(f, fcntl.F_GETFD) & fcntl.FD_CLOEXEC:
|
|
raise SystemExit('File handle is inheritable!')
|
|
|
|
def copen(*args):
|
|
ans = lopen(*args)
|
|
assert_not_inheritable(ans)
|
|
return ans
|
|
|
|
with TemporaryDirectory() as tdir, CurrentDir(tdir):
|
|
with copen(n, 'w') as f:
|
|
f.write('one')
|
|
|
|
print('O_CREAT tested')
|
|
with copen(n, 'w+b') as f:
|
|
f.write(b'two')
|
|
with copen(n, 'r') as f:
|
|
if f.read() == 'two':
|
|
print('O_TRUNC tested')
|
|
else:
|
|
raise Exception('O_TRUNC failed')
|
|
with copen(n, 'ab') as f:
|
|
f.write(b'three')
|
|
with copen(n, 'r+') as f:
|
|
if f.read() == 'twothree':
|
|
print('O_APPEND tested')
|
|
else:
|
|
raise Exception('O_APPEND failed')
|
|
with copen(n, 'r+') as f:
|
|
f.seek(3)
|
|
f.write('xxxxx')
|
|
f.seek(0)
|
|
if f.read() == 'twoxxxxx':
|
|
print('O_RANDOM tested')
|
|
else:
|
|
raise Exception('O_RANDOM failed')
|