diff --git a/pyproject.toml b/pyproject.toml
index 27cec512a3..0606737fc6 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -24,7 +24,7 @@ quote-style = 'single'
explicit-preview-rules = true
ignore = [
'E402', 'E722', 'E741',
- 'UP012', 'UP030', 'UP032', 'UP038', 'C413', 'C420', 'PIE790', 'ISC003',
+ 'UP012', 'UP030', 'UP038', 'C413', 'C420', 'PIE790', 'ISC003',
'RUF001', 'RUF002', 'RUF003', 'RUF005', 'RUF012', 'RUF013', 'RUF015', 'RUF031', 'RUF100',
'F841', # because in preview, unused tuple unpacking variable that not use dummy syntax (prefix '_' underscore)
# raise error 'unused-variable', sigh (https://github.com/astral-sh/ruff/issues/8884)
@@ -32,7 +32,7 @@ ignore = [
select = [
'E', 'F', 'I', 'W', 'INT',
'Q', 'UP', 'YTT', 'TID', 'C4', 'COM818', 'PIE', 'RET501', 'ISC',
- 'RUF', # nota: RUF can flag many unsolicited errors
+ 'RUF', # note: RUF can flag many unsolicited errors
# preview rules
'RUF051', 'RUF056', # useless dict operation
'RUF055', # unnecessary regex
diff --git a/src/calibre/db/tests/legacy.py b/src/calibre/db/tests/legacy.py
index 793faf93f1..f22f1dcc61 100644
--- a/src/calibre/db/tests/legacy.py
+++ b/src/calibre/db/tests/legacy.py
@@ -32,7 +32,8 @@ class ET:
legacy = self.legacy or test.init_legacy(test.cloned_library)
oldres = getattr(old, self.func_name)(*self.args, **self.kwargs)
newres = getattr(legacy, self.func_name)(*self.args, **self.kwargs)
- test.assertEqual(oldres, newres, f'Equivalence test for {self.func_name} with args: {reprlib.repr(self.args)} and kwargs: {reprlib.repr(self.kwargs)} failed')
+ test.assertEqual(oldres, newres,
+ f'Equivalence test for {self.func_name} with args: {reprlib.repr(self.args)} and kwargs: {reprlib.repr(self.kwargs)} failed')
self.retval = newres
return newres
diff --git a/src/calibre/db/tests/writing.py b/src/calibre/db/tests/writing.py
index fe5b6b58aa..b66339558f 100644
--- a/src/calibre/db/tests/writing.py
+++ b/src/calibre/db/tests/writing.py
@@ -70,7 +70,7 @@ class WritingTest(BaseTest):
test.setter(db)(1, val)
old_cached_res = getter(1)
self.assertEqual(old_cached_res, cached_res,
- f'Failed setting for {test.name} with value {val!r}, cached value not the same. Old: {old_cached_res!r} != New: {cached_res!r}')
+ f'Failed setting for {test.name} with value {val!r}, cached value not the same. Old: {old_cached_res!r} != New: {cached_res!r}')
db.refresh()
old_sqlite_res = getter(1)
self.assertEqual(old_sqlite_res, sqlite_res,
diff --git a/src/calibre/devices/kobo/driver.py b/src/calibre/devices/kobo/driver.py
index 50632bb032..6cfda4774b 100644
--- a/src/calibre/devices/kobo/driver.py
+++ b/src/calibre/devices/kobo/driver.py
@@ -2701,7 +2701,8 @@ class KOBOTOUCH(KOBO):
debug_print(f'KoboTouch:update_device_database_collections - book.title={book.title}')
debug_print(
f'KoboTouch:update_device_database_collections - contentId={book.contentID},'
- f'update_core_metadata={update_core_metadata},update_purchased_kepubs={update_purchased_kepubs}, book.is_sideloaded={book.is_sideloaded}')
+ f'update_core_metadata={update_core_metadata},update_purchased_kepubs={update_purchased_kepubs}, '
+ f'book.is_sideloaded={book.is_sideloaded}')
if update_core_metadata and (update_purchased_kepubs or book.is_sideloaded):
if show_debug:
debug_print('KoboTouch:update_device_database_collections - calling set_core_metadata')
@@ -2939,7 +2940,8 @@ class KOBOTOUCH(KOBO):
if show_debug:
debug_print(
f'KoboTouch:_calculate_kobo_cover_size - expand_to={expand_to}'
- f' (vs. kobo_size={kobo_size}) & resize_to={resize_to}, keep_cover_aspect={keep_cover_aspect} & letterbox_fs_covers={letterbox_fs_covers}, png_covers={png_covers}')
+ f' (vs. kobo_size={kobo_size}) & resize_to={resize_to}, keep_cover_aspect={keep_cover_aspect} '
+ f'& letterbox_fs_covers={letterbox_fs_covers}, png_covers={png_covers}')
# NOTE: To speed things up, we enforce a lower
# compression level for png_covers, as the final
diff --git a/src/calibre/ebooks/conversion/plugins/pdb_input.py b/src/calibre/ebooks/conversion/plugins/pdb_input.py
index a20b43db55..99cb13794c 100644
--- a/src/calibre/ebooks/conversion/plugins/pdb_input.py
+++ b/src/calibre/ebooks/conversion/plugins/pdb_input.py
@@ -24,7 +24,8 @@ class PDBInput(InputFormatPlugin):
Reader = get_reader(header.ident)
if Reader is None:
- raise PDBError('No reader available for format within container.\n Identity is {}. Book type is {}'.format(header.ident, IDENTITY_TO_NAME.get(header.ident, _('Unknown'))))
+ raise PDBError('No reader available for format within container.\n Identity is {}. Book type is {}'.format(
+ header.ident, IDENTITY_TO_NAME.get(header.ident, _('Unknown'))))
log.debug(f'Detected ebook format as: {IDENTITY_TO_NAME[header.ident]} with identity: {header.ident}')
diff --git a/src/calibre/ebooks/htmlz/oeb2html.py b/src/calibre/ebooks/htmlz/oeb2html.py
index dd9e9891b8..abb8cf256c 100644
--- a/src/calibre/ebooks/htmlz/oeb2html.py
+++ b/src/calibre/ebooks/htmlz/oeb2html.py
@@ -55,7 +55,8 @@ class OEB2HTML:
def mlize_spine(self, oeb_book):
output = [
- f'
{prepare_string_for_xml(self.book_title)}'
+ ''
+ f'{prepare_string_for_xml(self.book_title)}'
]
for item in oeb_book.spine:
self.log.debug(f'Converting {item.href} to HTML...')
diff --git a/src/calibre/ebooks/lrf/objects.py b/src/calibre/ebooks/lrf/objects.py
index 32cde2a77f..f731c0becc 100644
--- a/src/calibre/ebooks/lrf/objects.py
+++ b/src/calibre/ebooks/lrf/objects.py
@@ -1182,7 +1182,8 @@ class BookAttr(StyleObject, LRFObject):
s = f'\n'
s += f'\n'
doc = self._document
- s += f'\n'
+ s += f'\n'
for font in self._document.font_map.values():
s += str(font)
s += '\n'
diff --git a/src/calibre/ebooks/pml/pmlconverter.py b/src/calibre/ebooks/pml/pmlconverter.py
index d72a6ef72d..6fea58bb78 100644
--- a/src/calibre/ebooks/pml/pmlconverter.py
+++ b/src/calibre/ebooks/pml/pmlconverter.py
@@ -157,8 +157,10 @@ class PML_HTMLizer:
def prepare_pml(self, pml):
# Give Chapters the form \\*='text'text\\*. This is used for generating
# the TOC later.
- pml = re.sub(r'(?msu)(?P\\x)(?P.*?)(?P=c)', lambda match: '{}="{}"{}{}'.format(match.group('c'), self.strip_pml(match.group('text')), match.group('text'), match.group('c')), pml)
- pml = re.sub(r'(?msu)(?P\\X[0-4])(?P.*?)(?P=c)', lambda match: '{}="{}"{}{}'.format(match.group('c'), self.strip_pml(match.group('text')), match.group('text'), match.group('c')), pml)
+ pml = re.sub(r'(?msu)(?P\\x)(?P.*?)(?P=c)', lambda match: '{}="{}"{}{}'.format(
+ match.group('c'), self.strip_pml(match.group('text')), match.group('text'), match.group('c')), pml)
+ pml = re.sub(r'(?msu)(?P\\X[0-4])(?P.*?)(?P=c)', lambda match: '{}="{}"{}{}'.format(
+ match.group('c'), self.strip_pml(match.group('text')), match.group('text'), match.group('c')), pml)
# Remove comments
pml = re.sub(r'(?mus)\\v(?P.*?)\\v', '', pml)
@@ -170,8 +172,10 @@ class PML_HTMLizer:
pml = re.sub(r'(?mus)^[ ]*$', '', pml)
# Footnotes and Sidebars.
- pml = re.sub(r'(?mus).+?)">\s*(?P.*?)\s*', lambda match: '\\FN="{}"{}\\FN'.format(match.group('target'), match.group('text')) if match.group('text') else '', pml)
- pml = re.sub(r'(?mus).+?)">\s*(?P.*?)\s*', lambda match: '\\SB="{}"{}\\SB'.format(match.group('target'), match.group('text')) if match.group('text') else '', pml)
+ pml = re.sub(r'(?mus).+?)">\s*(?P.*?)\s*', lambda match: '\\FN="{}"{}\\FN'.format(
+ match.group('target'), match.group('text')) if match.group('text') else '', pml)
+ pml = re.sub(r'(?mus).+?)">\s*(?P.*?)\s*', lambda match: '\\SB="{}"{}\\SB'.format(
+ match.group('target'), match.group('text')) if match.group('text') else '', pml)
# Convert &'s into entities so & in the text doesn't get turned into
# &. It will display as &
@@ -751,7 +755,9 @@ def pml_to_html(pml):
def footnote_sidebar_to_html(pre_id, id, pml):
id = id.strip('\x01')
if id.strip():
- html = f'
'
+ html = (
+ f'
{pml_to_html(pml)}'
+ f'
return ')
else:
html = f'
{pml_to_html(pml)}
'
return html
diff --git a/src/calibre/ebooks/rtf/rtfml.py b/src/calibre/ebooks/rtf/rtfml.py
index 3bc069758e..0aed5b31bc 100644
--- a/src/calibre/ebooks/rtf/rtfml.py
+++ b/src/calibre/ebooks/rtf/rtfml.py
@@ -150,7 +150,7 @@ class RTFMLizer:
return text
def header(self):
- header = f'{{\\rtf1{{\\info{{\\title {self.oeb_book.metadata.title[0].value}}}{{\\author {authors_to_string([x.value for x in self.oeb_book.metadata.creator])}}}}}\\ansi\\ansicpg1252\\deff0\\deflang1033\n'
+ header = f'{{\\rtf1{{\\info{{\\title {self.oeb_book.metadata.title[0].value}}}{{\\author {authors_to_string([x.value for x in self.oeb_book.metadata.creator])}}}}}\\ansi\\ansicpg1252\\deff0\\deflang1033\n' # noqa: E501
return header + (
'{\\fonttbl{\\f0\\froman\\fprq2\\fcharset128 Times New Roman;}{\\f1\\froman\\fprq2\\fcharset128 Times New Roman;}{\\f2\\fswiss\\fprq2\\fcharset128 Arial;}{\\f3\\fnil\\fprq2\\fcharset128 Arial;}{\\f4\\fnil\\fprq2\\fcharset128 MS Mincho;}{\\f5\\fnil\\fprq2\\fcharset128 Tahoma;}{\\f6\\fnil\\fprq0\\fcharset128 Tahoma;}}\n' # noqa: E501
'{\\stylesheet{\\ql \\li0\\ri0\\nowidctlpar\\wrapdefault\\faauto\\rin0\\lin0\\itap0 \\rtlch\\fcs1 \\af25\\afs24\\alang1033 \\ltrch\\fcs0 \\fs24\\lang1033\\langfe255\\cgrid\\langnp1033\\langfenp255 \\snext0 Normal;}\n' # noqa: E501
diff --git a/src/calibre/gui2/dialogs/message_box.py b/src/calibre/gui2/dialogs/message_box.py
index 0073dcb5fe..7dd810e59b 100644
--- a/src/calibre/gui2/dialogs/message_box.py
+++ b/src/calibre/gui2/dialogs/message_box.py
@@ -446,7 +446,8 @@ class JobError(QDialog): # {{{
d = QTextDocument()
d.setHtml(self.msg_label.text())
QApplication.clipboard().setText(
- f'calibre, version {__version__} ({sys.platform}, embedded-python: {isfrozen})\n{self.windowTitle()!s}: {d.toPlainText()!s}\n\n{self.det_msg.toPlainText()!s}')
+ f'calibre, version {__version__} ({sys.platform}, embedded-python: {isfrozen})\n'
+ f'{self.windowTitle()!s}: {d.toPlainText()!s}\n\n{self.det_msg.toPlainText()!s}')
if hasattr(self, 'ctc_button'):
self.ctc_button.setText(_('Copied'))
diff --git a/src/calibre/gui2/tweak_book/editor/smarts/html.py b/src/calibre/gui2/tweak_book/editor/smarts/html.py
index ad60d65c1c..da6a8bd741 100644
--- a/src/calibre/gui2/tweak_book/editor/smarts/html.py
+++ b/src/calibre/gui2/tweak_book/editor/smarts/html.py
@@ -50,7 +50,9 @@ class Tag:
self.self_closing = self_closing
def __repr__(self):
- return f'<{self.name} start_block={self.start_block.blockNumber()} start_offset={self.start_offset} end_block={self.end_block.blockNumber()} end_offset={self.end_offset} self_closing={self.self_closing}>'
+ return (
+ f'<{self.name} start_block={self.start_block.blockNumber()} start_offset={self.start_offset} '
+ f'end_block={self.end_block.blockNumber()} end_offset={self.end_offset} self_closing={self.self_closing}>')
__str__ = __repr__
diff --git a/src/calibre/gui2/tweak_book/editor/snippets.py b/src/calibre/gui2/tweak_book/editor/snippets.py
index 69ff49d758..0ccc39dca8 100644
--- a/src/calibre/gui2/tweak_book/editor/snippets.py
+++ b/src/calibre/gui2/tweak_book/editor/snippets.py
@@ -234,7 +234,9 @@ class EditorTabStop:
self.join_previous_edit = False
def __repr__(self):
- return f'EditorTabStop(num={self.num!r} text={self.text!r} left={self.left!r} right={self.right!r} is_deleted={self.is_deleted!r} mirrors={self.mirrors!r})'
+ return (
+ f'EditorTabStop(num={self.num!r} text={self.text!r} left={self.left!r} right={self.right!r} '
+ f'is_deleted={self.is_deleted!r} mirrors={self.mirrors!r})')
__str__ = __unicode__ = __repr__
def apply_selected_text(self, text):
diff --git a/src/calibre/gui2/tweak_book/live_css.py b/src/calibre/gui2/tweak_book/live_css.py
index 273e08b55c..dc255e77ec 100644
--- a/src/calibre/gui2/tweak_book/live_css.py
+++ b/src/calibre/gui2/tweak_book/live_css.py
@@ -394,7 +394,9 @@ class Property:
self.is_overriden = False
def __repr__(self):
- return f''
+ return (
+ f'')
class LiveCSS(QWidget):
diff --git a/src/calibre/gui2/tweak_book/preview.py b/src/calibre/gui2/tweak_book/preview.py
index 1f76bacbbf..b8687b4a9d 100644
--- a/src/calibre/gui2/tweak_book/preview.py
+++ b/src/calibre/gui2/tweak_book/preview.py
@@ -87,7 +87,9 @@ class ParseItem:
self.parsing_done = False
def __repr__(self):
- return f'ParsedItem(name={self.name!r}, length={self.length!r}, fingerprint={self.fingerprint!r}, parsing_done={self.parsing_done!r}, parsed_data_is_None={self.parsed_data is None!r})'
+ return (
+ f'ParsedItem(name={self.name!r}, length={self.length!r}, fingerprint={self.fingerprint!r}, '
+ f'parsing_done={self.parsing_done!r}, parsed_data_is_None={self.parsed_data is None!r})')
class ParseWorker(Thread):
diff --git a/src/calibre/gui2/tweak_book/save.py b/src/calibre/gui2/tweak_book/save.py
index d69bd0ea5e..469459983f 100644
--- a/src/calibre/gui2/tweak_book/save.py
+++ b/src/calibre/gui2/tweak_book/save.py
@@ -56,7 +56,8 @@ def save_container(container, path):
except OSError as err:
if err.errno != errno.EPERM:
raise
- raise OSError(f'Failed to change permissions of {temp.name} to {oct(st.st_mode)} ({format_permissions(st.st_mode)}), with error: {errno.errorcode[err.errno]}. Most likely the {os.path.dirname(temp.name)} directory has a restrictive umask')
+ raise OSError(f'Failed to change permissions of {temp.name} to {oct(st.st_mode)} ({format_permissions(st.st_mode)}), '
+ f'with error: {errno.errorcode[err.errno]}. Most likely the {os.path.dirname(temp.name)} directory has a restrictive umask')
try:
os.fchown(fno, st.st_uid, st.st_gid)
except OSError as err:
diff --git a/src/calibre/srv/content.py b/src/calibre/srv/content.py
index 9ec25c1782..20f5cb3b0d 100644
--- a/src/calibre/srv/content.py
+++ b/src/calibre/srv/content.py
@@ -222,7 +222,8 @@ def book_fmt(ctx, rd, library_id, db, book_id, fmt):
dest.seek(0)
cd = rd.query.get('content_disposition', 'attachment')
- rd.outheaders['Content-Disposition'] = f'''{cd}; filename="{book_filename(rd, book_id, mi, fmt)}"; filename*=utf-8''{book_filename(rd, book_id, mi, fmt, as_encoded_unicode=True)}'''
+ rd.outheaders['Content-Disposition'] = (
+ f'''{cd}; filename="{book_filename(rd, book_id, mi, fmt)}"; filename*=utf-8''{book_filename(rd, book_id, mi, fmt, as_encoded_unicode=True)}''')
return create_file_copy(ctx, rd, 'fmt', library_id, book_id, fmt, mtime, copy_func, extra_etag_data=extra_etag_data)
# }}}
@@ -465,7 +466,8 @@ def get_note_resource(ctx, rd, scheme, digest, library_id):
raise HTTPNotFound(f'Notes resource {scheme}:{digest} not found')
name = d['name']
rd.outheaders['Content-Type'] = guess_type(name)[0] or 'application/octet-stream'
- rd.outheaders['Content-Disposition'] = f'''inline; filename="{fname_for_content_disposition(name)}"; filename*=utf-8''{fname_for_content_disposition(name, as_encoded_unicode=True)}'''
+ rd.outheaders['Content-Disposition'] = (
+ f'''inline; filename="{fname_for_content_disposition(name)}"; filename*=utf-8''{fname_for_content_disposition(name, as_encoded_unicode=True)}''')
rd.outheaders['Last-Modified'] = http_date(d['mtime'])
return d['data']
@@ -522,7 +524,8 @@ def set_note(ctx, rd, field, item_id, library_id):
def data_file(rd, fname, path, stat_result):
cd = rd.query.get('content_disposition', 'attachment')
- rd.outheaders['Content-Disposition'] = f'''{cd}; filename="{fname_for_content_disposition(fname)}"; filename*=utf-8''{fname_for_content_disposition(fname, as_encoded_unicode=True)}'''
+ rd.outheaders['Content-Disposition'] = (
+ f'''{cd}; filename="{fname_for_content_disposition(fname)}"; filename*=utf-8''{fname_for_content_disposition(fname, as_encoded_unicode=True)}''')
return rd.filesystem_file_with_custom_etag(share_open(path, 'rb'), stat_result.st_dev, stat_result.st_ino, stat_result.st_size, stat_result.st_mtime)
diff --git a/src/calibre/utils/webengine.py b/src/calibre/utils/webengine.py
index a20d5c2cd8..e790012060 100644
--- a/src/calibre/utils/webengine.py
+++ b/src/calibre/utils/webengine.py
@@ -111,7 +111,9 @@ class to_js_bound(QObject):
self.name = name
def __call__(self, *args):
- self.parent().page.runJavaScript(f'if (window.python_comm) python_comm._from_python({json.dumps(self.name)}, {json.dumps(args)})', QWebEngineScript.ScriptWorldId.ApplicationWorld)
+ self.parent().page.runJavaScript(
+ f'if (window.python_comm) python_comm._from_python({json.dumps(self.name)}, {json.dumps(args)})',
+ QWebEngineScript.ScriptWorldId.ApplicationWorld)
emit = __call__
diff --git a/src/calibre/web/feeds/__init__.py b/src/calibre/web/feeds/__init__.py
index 34d970ea4e..89f9863357 100644
--- a/src/calibre/web/feeds/__init__.py
+++ b/src/calibre/web/feeds/__init__.py
@@ -232,7 +232,9 @@ class Feed:
self.articles.append(article)
else:
try:
- self.logger.debug('Skipping article {} ({}) from feed {} as it is too old.'.format(title, article.localtime.strftime('%a, %d %b, %Y %H:%M'), self.title))
+ self.logger.debug(
+ 'Skipping article {} ({}) from feed {} as it is too old.'.format(
+ title, article.localtime.strftime('%a, %d %b, %Y %H:%M'), self.title))
except UnicodeDecodeError:
if not isinstance(title, str):
title = title.decode('utf-8', 'replace')