예제 #1
0
 def unhandled_exception(self, exc_type, value, tb):
     if exc_type is KeyboardInterrupt:
         return
     import traceback
     try:
         sio = PolyglotStringIO(errors='replace')
         try:
             from calibre.debug import print_basic_debug_info
             print_basic_debug_info(out=sio)
         except:
             pass
         traceback.print_exception(exc_type, value, tb, file=sio)
         if getattr(value, 'locking_debug_msg', None):
             prints(value.locking_debug_msg, file=sio)
         fe = sio.getvalue()
         msg = '<b>%s</b>:' % exc_type.__name__ + as_unicode(value)
         error_dialog(self,
                      _('Unhandled exception'),
                      msg,
                      det_msg=fe,
                      show=True)
         prints(fe, file=sys.stderr)
     except BaseException:
         pass
     except:
         pass
예제 #2
0
 def test_email_settings(self, to):
     opts = smtp_prefs().parse()
     from calibre.utils.smtp import sendmail, create_mail
     buf = PolyglotStringIO()
     debug_out = partial(prints, file=buf)
     oout, oerr = sys.stdout, sys.stderr
     sys.stdout = sys.stderr = buf
     tb = None
     try:
         msg = create_mail(opts.from_, to, 'Test mail from calibre',
                           'Test mail from calibre')
         sendmail(msg,
                  from_=opts.from_,
                  to=[to],
                  verbose=3,
                  timeout=30,
                  relay=opts.relay_host,
                  username=opts.relay_username,
                  debug_output=debug_out,
                  password=from_hex_unicode(opts.relay_password),
                  encryption=opts.encryption,
                  port=opts.relay_port)
     except:
         import traceback
         tb = traceback.format_exc()
         tb += '\n\nLog:\n' + buf.getvalue()
     finally:
         sys.stdout, sys.stderr = oout, oerr
     return tb
예제 #3
0
 def settingsxml(self):
     """ Generates the settings.xml file """
     x = DocumentSettings()
     x.addElement(self.settings)
     xml=PolyglotStringIO()
     xml.write(_XMLPROLOGUE)
     x.toXml(0,xml)
     return xml.getvalue()
예제 #4
0
 def settingsxml(self):
     """ Generates the settings.xml file """
     x = DocumentSettings()
     x.addElement(self.settings)
     xml = PolyglotStringIO()
     xml.write(_XMLPROLOGUE)
     x.toXml(0, xml)
     return xml.getvalue()
예제 #5
0
 def metaxml(self):
     """ Generates the meta.xml file """
     self.__replaceGenerator()
     x = DocumentMeta()
     x.addElement(self.meta)
     xml=PolyglotStringIO()
     xml.write(_XMLPROLOGUE)
     x.toXml(0,xml)
     return xml.getvalue()
예제 #6
0
 def metaxml(self):
     """ Generates the meta.xml file """
     self.__replaceGenerator()
     x = DocumentMeta()
     x.addElement(self.meta)
     xml = PolyglotStringIO()
     xml.write(_XMLPROLOGUE)
     x.toXml(0, xml)
     return xml.getvalue()
예제 #7
0
def build_forms(srcdir, info=None, summary=False, check_for_migration=False):
    import re
    from qt.core import QT_VERSION_STR
    qt_major = QT_VERSION_STR.split('.')[0]
    m = importlib.import_module(f'PyQt{qt_major}.uic')

    from polyglot.io import PolyglotStringIO
    forms = find_forms(srcdir)
    if info is None:
        info = print
    pat = re.compile(r'''(['"]):/images/([^'"]+)\1''')

    def sub(match):
        ans = 'I(%s%s%s)' % (match.group(1), match.group(2), match.group(1))
        return ans

    num = 0
    transdef_pat = re.compile(
        r'^\s+_translate\s+=\s+QtCore.QCoreApplication.translate$', flags=re.M)
    transpat = re.compile(r'_translate\s*\(.+?,\s+"(.+?)(?<!\\)"\)', re.DOTALL)

    # Ensure that people running from source have all their forms rebuilt for
    # the qt5 migration
    force_compile = os.environ.get('CALIBRE_FORCE_BUILD_UI_FORMS',
                                   '') in ('1', 'yes', 'true')
    if check_for_migration:
        from calibre.gui2 import gprefs
        force_compile |= not gprefs.get(f'migrated_forms_to_qt{qt_major}',
                                        False)

    for form in forms:
        compiled_form = form_to_compiled_form(form)
        if force_compile or not os.path.exists(compiled_form) or os.stat(
                form).st_mtime > os.stat(compiled_form).st_mtime:
            if not summary:
                info('\tCompiling form', form)
            buf = PolyglotStringIO()
            m.compileUi(form, buf)
            dat = buf.getvalue()
            dat = dat.replace('import images_rc', '')
            dat = transdef_pat.sub('', dat)
            dat = transpat.sub(r'_("\1")', dat)
            dat = dat.replace('_("MMM yyyy")', '"MMM yyyy"')
            dat = dat.replace('_("d MMM yyyy")', '"d MMM yyyy"')
            dat = pat.sub(sub, dat)
            if not isinstance(dat, bytes):
                dat = dat.encode('utf-8')
            open(compiled_form, 'wb').write(dat)
            num += 1
    if num:
        info('Compiled %d forms' % num)
    if check_for_migration and force_compile:
        gprefs.set(f'migrated_forms_to_qt{qt_major}', True)
예제 #8
0
    def _tag_args(self, level, *args):
        now = time.localtime()
        buf = PolyglotStringIO()
        tagged_args = []
        for arg in args:
            prints(time.strftime("%Y-%m-%d %H:%M:%S", now), file=buf, end=" ")
            buf.write("[")
            prints(level, file=buf, end="")
            buf.write("] ")
            prints(arg, file=buf, end="")

            tagged_args.append(buf.getvalue())
            buf.truncate(0)

        return tagged_args
예제 #9
0
 def stylesxml(self):
     """ Generates the styles.xml file """
     xml=PolyglotStringIO()
     xml.write(_XMLPROLOGUE)
     x = DocumentStyles()
     x.write_open_tag(0, xml)
     if self.fontfacedecls.hasChildNodes():
         self.fontfacedecls.toXml(1, xml)
     self.styles.toXml(1, xml)
     a = AutomaticStyles()
     a.write_open_tag(1, xml)
     for s in self._used_auto_styles([self.masterstyles]):
         s.toXml(2, xml)
     a.write_close_tag(1, xml)
     if self.masterstyles.hasChildNodes():
         self.masterstyles.toXml(1, xml)
     x.write_close_tag(0, xml)
     return xml.getvalue()
예제 #10
0
 def stylesxml(self):
     """ Generates the styles.xml file """
     xml = PolyglotStringIO()
     xml.write(_XMLPROLOGUE)
     x = DocumentStyles()
     x.write_open_tag(0, xml)
     if self.fontfacedecls.hasChildNodes():
         self.fontfacedecls.toXml(1, xml)
     self.styles.toXml(1, xml)
     a = AutomaticStyles()
     a.write_open_tag(1, xml)
     for s in self._used_auto_styles([self.masterstyles]):
         s.toXml(2, xml)
     a.write_close_tag(1, xml)
     if self.masterstyles.hasChildNodes():
         self.masterstyles.toXml(1, xml)
     x.write_close_tag(0, xml)
     return xml.getvalue()
예제 #11
0
def debug(ioreg_to_tmp=False, buf=None, plugins=None, disabled_plugins=None):
    '''
    If plugins is None, then this method calls startup and shutdown on the
    device plugins. So if you are using it in a context where startup could
    already have been called (for example in the main GUI), pass in the list of
    device plugins as the plugins parameter.
    '''
    import textwrap
    from calibre.customize.ui import device_plugins, disabled_device_plugins
    from calibre.debug import print_basic_debug_info
    from calibre.devices.scanner import DeviceScanner
    from calibre.constants import iswindows, ismacos
    from calibre import prints
    from polyglot.io import PolyglotStringIO
    oldo, olde = sys.stdout, sys.stderr

    if buf is None:
        buf = PolyglotStringIO()
    sys.stdout = sys.stderr = buf
    out = partial(prints, file=buf)

    devplugins = device_plugins() if plugins is None else plugins
    devplugins = list(sorted(devplugins, key=lambda x: x.__class__.__name__))
    if plugins is None:
        for d in devplugins:
            try:
                d.startup()
            except:
                out('Startup failed for device plugin: %s' % d)

    if disabled_plugins is None:
        disabled_plugins = list(disabled_device_plugins())

    try:
        print_basic_debug_info(out=buf)
        s = DeviceScanner()
        s.scan()
        devices = (s.devices)
        if not iswindows:
            devices = [list(x) for x in devices]
            for d in devices:
                for i in range(3):
                    d[i] = hex(d[i])
        out('USB devices on system:')
        out(pprint.pformat(devices))

        ioreg = None
        if ismacos:
            from calibre.devices.usbms.device import Device
            mount = '\n'.join(
                repr(x) for x in Device.osx_run_mount().splitlines())
            drives = pprint.pformat(Device.osx_get_usb_drives())
            ioreg = 'Output from mount:\n' + mount + '\n\n'
            ioreg += 'Output from osx_get_usb_drives:\n' + drives + '\n\n'
            ioreg += Device.run_ioreg().decode('utf-8')
        connected_devices = []
        if disabled_plugins:
            out(
                '\nDisabled plugins:',
                textwrap.fill(' '.join(
                    [x.__class__.__name__ for x in disabled_plugins])))
            out(' ')
        else:
            out('\nNo disabled plugins')
        found_dev = False
        for dev in devplugins:
            if not dev.MANAGES_DEVICE_PRESENCE:
                continue
            out('Looking for devices of type:', dev.__class__.__name__)
            if dev.debug_managed_device_detection(s.devices, buf):
                found_dev = True
                break
            out(' ')

        if not found_dev:
            out('Looking for devices...')
            for dev in devplugins:
                if dev.MANAGES_DEVICE_PRESENCE:
                    continue
                connected, det = s.is_device_connected(dev, debug=True)
                if connected:
                    out('\t\tDetected possible device', dev.__class__.__name__)
                    connected_devices.append((dev, det))

            out(' ')
            errors = {}
            success = False
            out('Devices possibly connected:', end=' ')
            for dev, det in connected_devices:
                out(dev.name, end=', ')
            if not connected_devices:
                out('None', end='')
            out(' ')
            for dev, det in connected_devices:
                out('Trying to open', dev.name, '...', end=' ')
                dev.do_device_debug = True
                try:
                    dev.reset(detected_device=det)
                    dev.open(det, None)
                    out('OK')
                except:
                    import traceback
                    errors[dev] = traceback.format_exc()
                    out('failed')
                    continue
                dev.do_device_debug = False
                success = True
                if hasattr(dev, '_main_prefix'):
                    out('Main memory:', repr(dev._main_prefix))
                out('Total space:', dev.total_space())
                break
            if not success and errors:
                out('Opening of the following devices failed')
                for dev, msg in errors.items():
                    out(dev)
                    out(msg)
                    out(' ')

            if ioreg is not None:
                ioreg = 'IOREG Output\n' + ioreg
                out(' ')
                if ioreg_to_tmp:
                    lopen('/tmp/ioreg.txt', 'w').write(ioreg)
                    out('Dont forget to send the contents of /tmp/ioreg.txt')
                    out('You can open it with the command: open /tmp/ioreg.txt'
                        )
                else:
                    out(ioreg)

        if hasattr(buf, 'getvalue'):
            return buf.getvalue()
    finally:
        sys.stdout = oldo
        sys.stderr = olde
        if plugins is None:
            for d in devplugins:
                try:
                    d.shutdown()
                except:
                    pass
예제 #12
0
def ls(dev, path, recurse=False, human_readable_size=False, ll=False, cols=0):
    def col_split(l, cols):  # split list l into columns
        rows = len(l) // cols
        if len(l) % cols:
            rows += 1
        m = []
        for i in range(rows):
            m.append(l[i::rows])
        return m

    def row_widths(
            table):  # Calculate widths for each column in the row-wise table
        tcols = len(table[0])
        rowwidths = [0 for i in range(tcols)]
        for row in table:
            c = 0
            for item in row:
                rowwidths[c] = len(
                    item) if len(item) > rowwidths[c] else rowwidths[c]
                c += 1
        return rowwidths

    output = PolyglotStringIO()
    if path.endswith("/") and len(path) > 1:
        path = path[:-1]
    dirs = dev.list(path, recurse)
    for dir in dirs:
        if recurse:
            prints(dir[0] + ":", file=output)
        lsoutput, lscoloutput = [], []
        files = dir[1]
        maxlen = 0
        if ll:  # Calculate column width for size column
            for file in files:
                size = len(unicode_type(file.size))
                if human_readable_size:
                    file = FileFormatter(file)
                    size = len(file.human_readable_size)
                if size > maxlen:
                    maxlen = size
        for file in files:
            file = FileFormatter(file)
            name = file.name if ll else file.isdir_name
            lsoutput.append(name)
            lscoloutput.append(name)
            if ll:
                size = unicode_type(file.size)
                if human_readable_size:
                    size = file.human_readable_size
                prints(file.mode_string,
                       ("%" + unicode_type(maxlen) + "s") % size,
                       file.modification_time,
                       name,
                       file=output)
        if not ll and len(lsoutput) > 0:
            trytable = []
            for colwidth in range(MINIMUM_COL_WIDTH, cols):
                trycols = int(cols // colwidth)
                trytable = col_split(lsoutput, trycols)
                works = True
                for row in trytable:
                    row_break = False
                    for item in row:
                        if len(item) > colwidth - 1:
                            works, row_break = False, True
                            break
                    if row_break:
                        break
                if works:
                    break
            rowwidths = row_widths(trytable)
            trytablecol = col_split(lscoloutput, len(trytable[0]))
            for r in range(len(trytable)):
                for c in range(len(trytable[r])):
                    padding = rowwidths[c] - len(trytable[r][c])
                    prints(trytablecol[r][c],
                           "".ljust(padding),
                           end=' ',
                           file=output)
                prints(file=output)
        prints(file=output)
    listing = output.getvalue().rstrip() + "\n"
    output.close()
    return listing
예제 #13
0
    def __init__(self, parent, dbspec, ids, db):
        import re
        from PyQt5.uic import compileUi

        from calibre import prints as info

        QDialog.__init__(self, parent)
        self.setupUi(self)
        self.dbspec, self.ids = dbspec, ids

        # Display the number of books we've been passed
        self.count.setText(unicode_type(self.count.text()).format(len(ids)))

        # Display the last-used title
        self.title.setText(
            dynamic.get('catalog_last_used_title', _('My books')))

        self.fmts, self.widgets = [], []

        for plugin in catalog_plugins():
            if plugin.name in config['disabled_plugins']:
                continue

            name = plugin.name.lower().replace(' ', '_')
            if getattr(plugin, 'installation_type',
                       None) is PluginInstallationType.BUILTIN:
                try:
                    catalog_widget = importlib.import_module(
                        'calibre.gui2.catalog.' + name)
                    pw = catalog_widget.PluginWidget()
                    pw.parent_ref = weakref.ref(self)
                    pw.initialize(name, db)
                    pw.ICON = I('forward.png')
                    self.widgets.append(pw)
                    [
                        self.fmts.append(
                            [file_type.upper(), pw.sync_enabled, pw])
                        for file_type in plugin.file_types
                    ]
                except ImportError:
                    info("ImportError initializing %s" % name)
                    continue
            else:
                # Load dynamic tab
                form = os.path.join(plugin.resources_path, '%s.ui' % name)
                klass = os.path.join(plugin.resources_path, '%s.py' % name)
                compiled_form = os.path.join(plugin.resources_path,
                                             '%s_ui.py' % name)

                if os.path.exists(form) and os.path.exists(klass):
                    # info("Adding widget for user-installed Catalog plugin %s" % plugin.name)

                    # Compile the .ui form provided in plugin.zip
                    if not os.path.exists(compiled_form):
                        from polyglot.io import PolyglotStringIO

                        # info('\tCompiling form', form)
                        buf = PolyglotStringIO()
                        compileUi(form, buf)
                        dat = buf.getvalue()
                        dat = re.compile(
                            r'QtGui.QApplication.translate\(.+?,\s+"(.+?)(?<!\\)",.+?\)',
                            re.DOTALL).sub(r'_("\1")', dat)
                        open(compiled_form, 'wb').write(dat.encode('utf-8'))

                    # Import the dynamic PluginWidget() from .py file provided in plugin.zip
                    try:
                        sys.path.insert(0, plugin.resources_path)
                        catalog_widget = importlib.import_module(name)
                        pw = catalog_widget.PluginWidget()
                        pw.initialize(name)
                        pw.ICON = I('forward.png')
                        self.widgets.append(pw)
                        [
                            self.fmts.append(
                                [file_type.upper(), pw.sync_enabled, pw])
                            for file_type in plugin.file_types
                        ]
                    except ImportError:
                        info("ImportError with %s" % name)
                        continue
                    finally:
                        sys.path.remove(plugin.resources_path)

                else:
                    info("No dynamic tab resources found for %s" % name)

        self.widgets = sorted(self.widgets, key=lambda x: x.TITLE)

        # Generate a sorted list of installed catalog formats/sync_enabled pairs
        fmts = sorted((x[0] for x in self.fmts))

        self.sync_enabled_formats = []
        for fmt in self.fmts:
            if fmt[1]:
                self.sync_enabled_formats.append(fmt[0])

        # Callbacks when format, title changes
        self.format.currentIndexChanged.connect(self.format_changed)
        self.format.currentIndexChanged.connect(self.settings_changed)
        self.title.editingFinished.connect(self.settings_changed)

        # Add the installed catalog format list to the format QComboBox
        self.format.blockSignals(True)
        self.format.addItems(fmts)

        pref = dynamic.get('catalog_preferred_format', 'CSV')
        idx = self.format.findText(pref)
        if idx > -1:
            self.format.setCurrentIndex(idx)
        self.format.blockSignals(False)

        if self.sync.isEnabled():
            self.sync.setChecked(dynamic.get('catalog_sync_to_device', True))
        self.add_to_library.setChecked(
            dynamic.get('catalog_add_to_library', True))

        self.format.currentIndexChanged.connect(self.show_plugin_tab)
        self.buttonBox.button(
            QDialogButtonBox.StandardButton.Apply).clicked.connect(self.apply)
        self.buttonBox.button(
            QDialogButtonBox.StandardButton.Help).clicked.connect(self.help)
        self.show_plugin_tab(None)

        geom = dynamic.get('catalog_window_geom', None)
        if geom is not None:
            QApplication.instance().safe_restore_geometry(self, bytes(geom))
        else:
            self.resize(self.sizeHint())
        d = QCoreApplication.instance().desktop()
        g = d.availableGeometry(d.screenNumber(self))
        self.setMaximumWidth(g.width() - 50)
        self.setMaximumHeight(g.height() - 50)