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
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
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()
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()
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()
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()
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)
def init_env(self, name=''): from calibre.gui2.tweak_book.boss import get_boss self.context_name = name or '' self.match_index = 0 self.boss = get_boss() self.data = {} self.debug_buf = PolyglotStringIO() self.functions = {name:func.mod for name, func in iteritems(functions()) if func.mod is not None}
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()
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()
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
def file_has_errors(self, f): from polyglot.io import PolyglotStringIO oo, oe = sys.stdout, sys.stderr sys.stdout = sys.stderr = buf = PolyglotStringIO() try: ret = run_2to3(f) finally: sys.stdout, sys.stderr = oo, oe if ret: raise SystemExit('Could not parse: ' + f) output = buf.getvalue() return re.search(r'^RefactoringTool: No changes to ' + f, output, flags=re.M) is None
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
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
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)