mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Sync to trunk.
This commit is contained in:
commit
fff3cb147a
@ -20,7 +20,7 @@
|
|||||||
<script type="text/javascript"
|
<script type="text/javascript"
|
||||||
src="{prefix}/static/jquery.multiselect.min.js"></script>
|
src="{prefix}/static/jquery.multiselect.min.js"></script>
|
||||||
|
|
||||||
|
<script type="text/javascript" src="{prefix}/static/stacktrace.js"></script>
|
||||||
<script type="text/javascript" src="{prefix}/static/browse/browse.js"></script>
|
<script type="text/javascript" src="{prefix}/static/browse/browse.js"></script>
|
||||||
|
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
|
@ -129,7 +129,13 @@ function toplevel() {
|
|||||||
// }}}
|
// }}}
|
||||||
|
|
||||||
function render_error(msg) {
|
function render_error(msg) {
|
||||||
return '<div class="ui-widget"><div class="ui-state-error ui-corner-all" style="padding: 0pt 0.7em"><p><span class="ui-icon ui-icon-alert" style="float: left; margin-right: 0.3em"> </span><strong>Error: </strong>'+msg+"</p></div></div>"
|
var st = "";
|
||||||
|
try {
|
||||||
|
var st = printStackTrace();
|
||||||
|
st = st.join('\n\n');
|
||||||
|
} catch(e) {
|
||||||
|
}
|
||||||
|
return '<div class="ui-widget"><div class="ui-state-error ui-corner-all" style="padding: 0pt 0.7em"><p><span class="ui-icon ui-icon-alert" style="float: left; margin-right: 0.3em"> </span><strong>Error: </strong>'+msg+"<pre>"+st+"</pre></p></div></div>"
|
||||||
}
|
}
|
||||||
|
|
||||||
// Category feed {{{
|
// Category feed {{{
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<WixLocalization Culture="en-us" xmlns="http://schemas.microsoft.com/wix/2006/localization">
|
<WixLocalization Culture="en-us" xmlns="http://schemas.microsoft.com/wix/2006/localization">
|
||||||
<String Id="AdvancedWelcomeEulaDlgDescriptionPerUser">If you are upgrading from a {app} version older than 0.6.17, please uninstall {app} first. Click Advanced to change installation settings.</String>
|
<String Id="AdvancedWelcomeEulaDlgDescriptionPerUser">Click Advanced to change installation settings.</String>
|
||||||
<String Id="ProgressTextFileCost">Computing space requirements, this may take upto five minutes...</String>
|
<String Id="ProgressTextFileCost">Computing space requirements, this may take upto five minutes...</String>
|
||||||
<String Id="ProgressTextCostInitialize">Computing space requirements, this may take upto five minutes...</String>
|
<String Id="ProgressTextCostInitialize">Computing space requirements, this may take upto five minutes...</String>
|
||||||
<String Id="ProgressTextCostFinalize">Computing space requirements, this may take upto five minutes...</String>
|
<String Id="ProgressTextCostFinalize">Computing space requirements, this may take upto five minutes...</String>
|
||||||
|
@ -8,8 +8,8 @@ __docformat__ = 'restructuredtext en'
|
|||||||
|
|
||||||
import sys, os, shutil, glob, py_compile, subprocess, re, zipfile, time
|
import sys, os, shutil, glob, py_compile, subprocess, re, zipfile, time
|
||||||
|
|
||||||
from setup import Command, modules, functions, basenames, __version__, \
|
from setup import (Command, modules, functions, basenames, __version__,
|
||||||
__appname__
|
__appname__)
|
||||||
from setup.build_environment import msvc, MT, RC
|
from setup.build_environment import msvc, MT, RC
|
||||||
from setup.installer.windows.wix import WixMixIn
|
from setup.installer.windows.wix import WixMixIn
|
||||||
|
|
||||||
@ -20,6 +20,7 @@ LIBUNRAR = 'C:\\Program Files\\UnrarDLL\\unrar.dll'
|
|||||||
SW = r'C:\cygwin\home\kovid\sw'
|
SW = r'C:\cygwin\home\kovid\sw'
|
||||||
IMAGEMAGICK = os.path.join(SW, 'build', 'ImageMagick-6.6.6',
|
IMAGEMAGICK = os.path.join(SW, 'build', 'ImageMagick-6.6.6',
|
||||||
'VisualMagick', 'bin')
|
'VisualMagick', 'bin')
|
||||||
|
CRT = r'C:\Microsoft.VC90.CRT'
|
||||||
|
|
||||||
VERSION = re.sub('[a-z]\d+', '', __version__)
|
VERSION = re.sub('[a-z]\d+', '', __version__)
|
||||||
WINVER = VERSION+'.0'
|
WINVER = VERSION+'.0'
|
||||||
@ -72,7 +73,7 @@ class Win32Freeze(Command, WixMixIn):
|
|||||||
self.lib_dir = self.j(self.base, 'Lib')
|
self.lib_dir = self.j(self.base, 'Lib')
|
||||||
self.pylib = self.j(self.base, 'pylib.zip')
|
self.pylib = self.j(self.base, 'pylib.zip')
|
||||||
self.dll_dir = self.j(self.base, 'DLLs')
|
self.dll_dir = self.j(self.base, 'DLLs')
|
||||||
self.plugins_dir = os.path.join(self.base, 'plugins')
|
self.plugins_dir = os.path.join(self.base, 'plugins2')
|
||||||
|
|
||||||
self.initbase()
|
self.initbase()
|
||||||
self.build_launchers()
|
self.build_launchers()
|
||||||
@ -81,8 +82,33 @@ class Win32Freeze(Command, WixMixIn):
|
|||||||
self.embed_manifests()
|
self.embed_manifests()
|
||||||
self.install_site_py()
|
self.install_site_py()
|
||||||
self.archive_lib_dir()
|
self.archive_lib_dir()
|
||||||
|
self.remove_CRT_from_manifests()
|
||||||
self.create_installer()
|
self.create_installer()
|
||||||
|
|
||||||
|
def remove_CRT_from_manifests(self):
|
||||||
|
'''
|
||||||
|
The dependency on the CRT is removed from the manifests of all DLLs.
|
||||||
|
This allows the CRT loaded by the .exe files to be used instead.
|
||||||
|
'''
|
||||||
|
search_pat = re.compile(r'(?is)<dependency>.*Microsoft\.VC\d+\.CRT')
|
||||||
|
repl_pat = re.compile(
|
||||||
|
r'(?is)<dependency>.*?Microsoft\.VC\d+\.CRT.*?</dependency>')
|
||||||
|
|
||||||
|
for dll in glob.glob(self.j(self.dll_dir, '*.dll')):
|
||||||
|
bn = self.b(dll)
|
||||||
|
with open(dll, 'rb') as f:
|
||||||
|
raw = f.read()
|
||||||
|
match = search_pat.search(raw)
|
||||||
|
if match is None:
|
||||||
|
continue
|
||||||
|
self.info('Removing CRT dependency from manifest of: %s'%bn)
|
||||||
|
# Blank out the bytes corresponding to the dependency specification
|
||||||
|
nraw = repl_pat.sub(lambda m: b' '*len(m.group()), raw)
|
||||||
|
if len(nraw) != len(raw):
|
||||||
|
raise Exception('Something went wrong with %s'%bn)
|
||||||
|
with open(dll, 'wb') as f:
|
||||||
|
f.write(nraw)
|
||||||
|
|
||||||
def initbase(self):
|
def initbase(self):
|
||||||
if self.e(self.base):
|
if self.e(self.base):
|
||||||
shutil.rmtree(self.base)
|
shutil.rmtree(self.base)
|
||||||
@ -103,6 +129,9 @@ class Win32Freeze(Command, WixMixIn):
|
|||||||
def freeze(self):
|
def freeze(self):
|
||||||
shutil.copy2(self.j(self.src_root, 'LICENSE'), self.base)
|
shutil.copy2(self.j(self.src_root, 'LICENSE'), self.base)
|
||||||
|
|
||||||
|
self.info('Adding CRT')
|
||||||
|
shutil.copytree(CRT, self.j(self.base, os.path.basename(CRT)))
|
||||||
|
|
||||||
self.info('Adding resources...')
|
self.info('Adding resources...')
|
||||||
tgt = self.j(self.base, 'resources')
|
tgt = self.j(self.base, 'resources')
|
||||||
if os.path.exists(tgt):
|
if os.path.exists(tgt):
|
||||||
@ -197,6 +226,10 @@ class Win32Freeze(Command, WixMixIn):
|
|||||||
if os.path.exists(tg):
|
if os.path.exists(tg):
|
||||||
shutil.rmtree(tg)
|
shutil.rmtree(tg)
|
||||||
shutil.copytree(imfd, tg)
|
shutil.copytree(imfd, tg)
|
||||||
|
for dirpath, dirnames, filenames in os.walk(tdir):
|
||||||
|
for x in filenames:
|
||||||
|
if not x.endswith('.dll'):
|
||||||
|
os.remove(self.j(dirpath, x))
|
||||||
|
|
||||||
print
|
print
|
||||||
print 'Adding third party dependencies'
|
print 'Adding third party dependencies'
|
||||||
|
@ -92,7 +92,7 @@ def aliasmbcs():
|
|||||||
|
|
||||||
def add_calibre_vars():
|
def add_calibre_vars():
|
||||||
sys.resources_location = os.path.join(sys.app_dir, 'resources')
|
sys.resources_location = os.path.join(sys.app_dir, 'resources')
|
||||||
sys.extensions_location = os.path.join(sys.app_dir, 'plugins')
|
sys.extensions_location = os.path.join(sys.app_dir, 'plugins2')
|
||||||
|
|
||||||
dv = os.environ.get('CALIBRE_DEVELOP_FROM', None)
|
dv = os.environ.get('CALIBRE_DEVELOP_FROM', None)
|
||||||
if dv and os.path.exists(dv):
|
if dv and os.path.exists(dv):
|
||||||
|
@ -11,6 +11,10 @@
|
|||||||
SummaryCodepage='1252' />
|
SummaryCodepage='1252' />
|
||||||
|
|
||||||
<Media Id="1" Cabinet="{app}.cab" CompressionLevel="{compression}" EmbedCab="yes" />
|
<Media Id="1" Cabinet="{app}.cab" CompressionLevel="{compression}" EmbedCab="yes" />
|
||||||
|
<!-- The following line ensures that DLLs are replaced even if their version is the same as before. This
|
||||||
|
is necessary because of the manifest nuking that was part of making calibre isolated. But I think it
|
||||||
|
is more rigorous anyway. -->
|
||||||
|
<Property Id='REINSTALLMODE' Value='emus'/>
|
||||||
|
|
||||||
<Upgrade Id="{upgrade_code}">
|
<Upgrade Id="{upgrade_code}">
|
||||||
<UpgradeVersion Maximum="{version}"
|
<UpgradeVersion Maximum="{version}"
|
||||||
@ -33,7 +37,6 @@
|
|||||||
</Property>
|
</Property>
|
||||||
|
|
||||||
<Directory Id='TARGETDIR' Name='SourceDir'>
|
<Directory Id='TARGETDIR' Name='SourceDir'>
|
||||||
<Merge Id="VCRedist" SourceFile="{crt_msm}" DiskId="1" Language="0"/>
|
|
||||||
<Directory Id='ProgramFilesFolder' Name='PFiles'>
|
<Directory Id='ProgramFilesFolder' Name='PFiles'>
|
||||||
<Directory Id='APPLICATIONFOLDER' Name='{app}' />
|
<Directory Id='APPLICATIONFOLDER' Name='{app}' />
|
||||||
</Directory>
|
</Directory>
|
||||||
@ -100,10 +103,6 @@
|
|||||||
<ComponentRef Id="RememberInstallDir"/>
|
<ComponentRef Id="RememberInstallDir"/>
|
||||||
</Feature>
|
</Feature>
|
||||||
|
|
||||||
<Feature Id="VCRedist" Title="Visual C++ 8.0 Runtime" AllowAdvertise="no" Display="hidden" Level="1">
|
|
||||||
<MergeRef Id="VCRedist"/>
|
|
||||||
</Feature>
|
|
||||||
|
|
||||||
<Feature Id="FSMS" Title="Start menu shortcuts" Level="1"
|
<Feature Id="FSMS" Title="Start menu shortcuts" Level="1"
|
||||||
Description="Program shortcuts installed in the Start Menu">
|
Description="Program shortcuts installed in the Start Menu">
|
||||||
<ComponentRef Id="StartMenuShortcuts"/>
|
<ComponentRef Id="StartMenuShortcuts"/>
|
||||||
@ -149,12 +148,13 @@
|
|||||||
Set default folder name and allow only per machine installs.
|
Set default folder name and allow only per machine installs.
|
||||||
For a per-machine installation, the default installation location
|
For a per-machine installation, the default installation location
|
||||||
will be [ProgramFilesFolder][ApplicationFolderName] and the user
|
will be [ProgramFilesFolder][ApplicationFolderName] and the user
|
||||||
will be able to change it in the setup UI. This is because the installer
|
will be able to change it in the setup UI. This is no longer necessary
|
||||||
has to install the VC90 merge module into the system winsxs folder for python
|
(i.e. per user installs should work) but left this way as I
|
||||||
to work, so per user installs are impossible anyway.
|
dont want to deal with the complications
|
||||||
-->
|
-->
|
||||||
<Property Id="ApplicationFolderName" Value="Calibre2" />
|
<Property Id="ApplicationFolderName" Value="Calibre2" />
|
||||||
<Property Id="WixAppFolder" Value="WixPerMachineFolder" />
|
<Property Id="WixAppFolder" Value="WixPerMachineFolder" />
|
||||||
|
<Property Id="ALLUSERS" Value="1" />
|
||||||
<WixVariable Id="WixUISupportPerUser" Value="0" />
|
<WixVariable Id="WixUISupportPerUser" Value="0" />
|
||||||
|
|
||||||
<!-- Add option to launch calibre after install -->
|
<!-- Add option to launch calibre after install -->
|
||||||
|
@ -35,7 +35,6 @@ class WixMixIn:
|
|||||||
exe_map = self.smap,
|
exe_map = self.smap,
|
||||||
main_icon = self.j(self.src_root, 'icons', 'library.ico'),
|
main_icon = self.j(self.src_root, 'icons', 'library.ico'),
|
||||||
web_icon = self.j(self.src_root, 'icons', 'web.ico'),
|
web_icon = self.j(self.src_root, 'icons', 'web.ico'),
|
||||||
crt_msm = self.j(self.SW, 'Microsoft_VC90_CRT_x86.msm')
|
|
||||||
)
|
)
|
||||||
template = open(self.j(self.d(__file__), 'en-us.xml'),
|
template = open(self.j(self.d(__file__), 'en-us.xml'),
|
||||||
'rb').read()
|
'rb').read()
|
||||||
|
@ -11,7 +11,7 @@ import os, shutil, traceback, textwrap, time, codecs
|
|||||||
from Queue import Empty
|
from Queue import Empty
|
||||||
|
|
||||||
from calibre.customize.conversion import InputFormatPlugin, OptionRecommendation
|
from calibre.customize.conversion import InputFormatPlugin, OptionRecommendation
|
||||||
from calibre import extract, CurrentDir, prints
|
from calibre import extract, CurrentDir, prints, walk
|
||||||
from calibre.constants import filesystem_encoding
|
from calibre.constants import filesystem_encoding
|
||||||
from calibre.ptempfile import PersistentTemporaryDirectory
|
from calibre.ptempfile import PersistentTemporaryDirectory
|
||||||
from calibre.utils.ipc.server import Server
|
from calibre.utils.ipc.server import Server
|
||||||
@ -27,6 +27,11 @@ def extract_comic(path_to_comic_file):
|
|||||||
# names
|
# names
|
||||||
tdir = tdir.decode(filesystem_encoding)
|
tdir = tdir.decode(filesystem_encoding)
|
||||||
extract(path_to_comic_file, tdir)
|
extract(path_to_comic_file, tdir)
|
||||||
|
for x in walk(tdir):
|
||||||
|
bn = os.path.basename(x)
|
||||||
|
nbn = bn.replace('#', '_')
|
||||||
|
if nbn != bn:
|
||||||
|
os.rename(x, os.path.join(os.path.dirname(x), nbn))
|
||||||
return tdir
|
return tdir
|
||||||
|
|
||||||
def find_pages(dir, sort_on_mtime=False, verbose=False):
|
def find_pages(dir, sort_on_mtime=False, verbose=False):
|
||||||
@ -362,6 +367,7 @@ class ComicInput(InputFormatPlugin):
|
|||||||
if not line:
|
if not line:
|
||||||
continue
|
continue
|
||||||
fname, title = line.partition(':')[0], line.partition(':')[-1]
|
fname, title = line.partition(':')[0], line.partition(':')[-1]
|
||||||
|
fname = fname.replace('#', '_')
|
||||||
fname = os.path.join(tdir, *fname.split('/'))
|
fname = os.path.join(tdir, *fname.split('/'))
|
||||||
if not title:
|
if not title:
|
||||||
title = os.path.basename(fname).rpartition('.')[0]
|
title = os.path.basename(fname).rpartition('.')[0]
|
||||||
|
@ -154,13 +154,16 @@ _proceed_memory = []
|
|||||||
class ProceedNotification(MessageBox): # {{{
|
class ProceedNotification(MessageBox): # {{{
|
||||||
|
|
||||||
def __init__(self, callback, payload, html_log, log_viewer_title, title, msg,
|
def __init__(self, callback, payload, html_log, log_viewer_title, title, msg,
|
||||||
det_msg='', show_copy_button=False, parent=None):
|
det_msg='', show_copy_button=False, parent=None,
|
||||||
|
cancel_callback=None):
|
||||||
'''
|
'''
|
||||||
A non modal popup that notifies the user that a background task has
|
A non modal popup that notifies the user that a background task has
|
||||||
been completed.
|
been completed.
|
||||||
|
|
||||||
:param callback: A callable that is called with payload if the user
|
:param callback: A callable that is called with payload if the user
|
||||||
asks to proceed. Note that this is always called in the GUI thread
|
asks to proceed. Note that this is always called in the GUI thread.
|
||||||
|
:param cancel_callback: A callable that is called with the payload if
|
||||||
|
the users asks not to proceed.
|
||||||
:param payload: Arbitrary object, passed to callback
|
:param payload: Arbitrary object, passed to callback
|
||||||
:param html_log: An HTML or plain text log
|
:param html_log: An HTML or plain text log
|
||||||
:param log_viewer_title: The title for the log viewer window
|
:param log_viewer_title: The title for the log viewer window
|
||||||
@ -181,7 +184,7 @@ class ProceedNotification(MessageBox): # {{{
|
|||||||
self.vlb.clicked.connect(self.show_log)
|
self.vlb.clicked.connect(self.show_log)
|
||||||
self.det_msg_toggle.setVisible(bool(det_msg))
|
self.det_msg_toggle.setVisible(bool(det_msg))
|
||||||
self.setModal(False)
|
self.setModal(False)
|
||||||
self.callback = callback
|
self.callback, self.cancel_callback = callback, cancel_callback
|
||||||
_proceed_memory.append(self)
|
_proceed_memory.append(self)
|
||||||
|
|
||||||
def show_log(self):
|
def show_log(self):
|
||||||
@ -192,9 +195,11 @@ class ProceedNotification(MessageBox): # {{{
|
|||||||
try:
|
try:
|
||||||
if result == self.Accepted:
|
if result == self.Accepted:
|
||||||
self.callback(self.payload)
|
self.callback(self.payload)
|
||||||
|
elif self.cancel_callback is not None:
|
||||||
|
self.cancel_callback(self.payload)
|
||||||
finally:
|
finally:
|
||||||
# Ensure this notification is garbage collected
|
# Ensure this notification is garbage collected
|
||||||
self.callback = None
|
self.callback = self.cancel_callback = None
|
||||||
self.setParent(None)
|
self.setParent(None)
|
||||||
self.finished.disconnect()
|
self.finished.disconnect()
|
||||||
self.vlb.clicked.disconnect()
|
self.vlb.clicked.disconnect()
|
||||||
|
@ -197,9 +197,11 @@ class JobManager(QAbstractTableModel): # {{{
|
|||||||
def row_to_job(self, row):
|
def row_to_job(self, row):
|
||||||
return self.jobs[row]
|
return self.jobs[row]
|
||||||
|
|
||||||
def has_device_jobs(self):
|
def has_device_jobs(self, queued_also=False):
|
||||||
for job in self.jobs:
|
for job in self.jobs:
|
||||||
if job.is_running and isinstance(job, DeviceJob):
|
if isinstance(job, DeviceJob):
|
||||||
|
if job.duration is None: # Running or waiting
|
||||||
|
if (job.is_running or queued_also):
|
||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
@ -6,15 +6,15 @@
|
|||||||
<rect>
|
<rect>
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>584</width>
|
<width>872</width>
|
||||||
<height>533</height>
|
<height>610</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<property name="windowTitle">
|
<property name="windowTitle">
|
||||||
<string>Get Books</string>
|
<string>Get Books</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="windowIcon">
|
<property name="windowIcon">
|
||||||
<iconset>
|
<iconset resource="../../../../../resources/images.qrc">
|
||||||
<normaloff>:/images/store.png</normaloff>:/images/store.png</iconset>
|
<normaloff>:/images/store.png</normaloff>:/images/store.png</iconset>
|
||||||
</property>
|
</property>
|
||||||
<property name="sizeGripEnabled">
|
<property name="sizeGripEnabled">
|
||||||
@ -82,8 +82,8 @@
|
|||||||
<rect>
|
<rect>
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>125</width>
|
<width>173</width>
|
||||||
<height>127</height>
|
<height>106</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
@ -255,7 +255,7 @@
|
|||||||
</customwidget>
|
</customwidget>
|
||||||
</customwidgets>
|
</customwidgets>
|
||||||
<resources>
|
<resources>
|
||||||
<include location="../../../../resources/images.qrc"/>
|
<include location="../../../../../resources/images.qrc"/>
|
||||||
</resources>
|
</resources>
|
||||||
<connections>
|
<connections>
|
||||||
<connection>
|
<connection>
|
||||||
|
@ -770,7 +770,8 @@ class BrowseServer(object):
|
|||||||
summs.append(self.browse_summary_template.format(**args))
|
summs.append(self.browse_summary_template.format(**args))
|
||||||
|
|
||||||
|
|
||||||
return json.dumps('\n'.join(summs), ensure_ascii=False)
|
raw = json.dumps('\n'.join(summs), ensure_ascii=False)
|
||||||
|
return raw
|
||||||
|
|
||||||
def browse_render_details(self, id_):
|
def browse_render_details(self, id_):
|
||||||
try:
|
try:
|
||||||
|
@ -65,7 +65,8 @@ def test_sqlite():
|
|||||||
def test_qt():
|
def test_qt():
|
||||||
from PyQt4.Qt import (QWebView, QDialog, QImageReader, QNetworkAccessManager)
|
from PyQt4.Qt import (QWebView, QDialog, QImageReader, QNetworkAccessManager)
|
||||||
fmts = set(map(unicode, QImageReader.supportedImageFormats()))
|
fmts = set(map(unicode, QImageReader.supportedImageFormats()))
|
||||||
if 'jpg' not in fmts or 'png' not in fmts:
|
testf = set(['jpg', 'png', 'mng', 'svg', 'ico', 'gif'])
|
||||||
|
if testf.intersection(fmts) != testf:
|
||||||
raise RuntimeError(
|
raise RuntimeError(
|
||||||
"Qt doesn't seem to be able to load its image plugins")
|
"Qt doesn't seem to be able to load its image plugins")
|
||||||
QWebView, QDialog
|
QWebView, QDialog
|
||||||
@ -87,6 +88,12 @@ def test_imaging():
|
|||||||
raise RuntimeError('PIL choked!')
|
raise RuntimeError('PIL choked!')
|
||||||
print ('PIL OK!')
|
print ('PIL OK!')
|
||||||
|
|
||||||
|
def test_unrar():
|
||||||
|
from calibre.libunrar import _libunrar
|
||||||
|
if not _libunrar:
|
||||||
|
raise RuntimeError('Failed to load libunrar')
|
||||||
|
print ('Unrar OK!')
|
||||||
|
|
||||||
def test():
|
def test():
|
||||||
test_plugins()
|
test_plugins()
|
||||||
test_lxml()
|
test_lxml()
|
||||||
@ -97,6 +104,7 @@ def test():
|
|||||||
test_win32()
|
test_win32()
|
||||||
test_qt()
|
test_qt()
|
||||||
test_imaging()
|
test_imaging()
|
||||||
|
test_unrar()
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
test()
|
test()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user