add codespell to pyproject.toml

calibre will probably never fully compliant with codespell
this setting is only to easily find common typo errors
by filtring a great range of false-positives, but not all
This commit is contained in:
un-pogaz 2025-03-23 13:59:14 +01:00
parent bc29562c0c
commit d176b3a7cf
30 changed files with 135 additions and 48 deletions

View File

@ -496,7 +496,7 @@
:: improved recipes
- Jot Down
- Various Russian and Ukranian news sources
- Various Russian and Ukrainian news sources
- Nautilus Magazine
- Süddeutsche Zeitung
- The India Forum
@ -974,7 +974,7 @@
- Fix a regression in 7.0 caused by a regression in Qt that would result in calibre hanging rarely when using the cover browser view
- [2049992] Fix custom template functions not useable in save to disk templates
- [2049992] Fix custom template functions not usable in save to disk templates
- Fix a regression in 7.2 that caused the popup used for editing fields in the book list to be mis-positioned on very wide monitors

View File

@ -402,7 +402,7 @@ V. General Format of a .ZIP file
13 - Acorn Risc 14 - VFAT
15 - alternate MVS 16 - BeOS
17 - Tandem 18 - OS/400
19 - OS/X (Darwin) 20 thru 255 - unused
19 - OS/X (Darwin) 20 through 255 - unused
The lower byte indicates the ZIP specification version
(the version of this document) supported by the software
@ -719,7 +719,7 @@ V. General Format of a .ZIP file
The Header ID field indicates the type of data that is in
the following data block.
Header ID's of 0 thru 31 are reserved for use by PKWARE.
Header ID's of 0 through 31 are reserved for use by PKWARE.
The remaining ID's can be used by third party vendors for
proprietary usage.
@ -1769,7 +1769,7 @@ Example: 0x02, 0x42, 0x01, 0x13
This would generate the original bit length array of:
(3, 3, 3, 3, 3, 2, 4, 4)
There are 8 codes in this table for the values 0 thru 7. Using
There are 8 codes in this table for the values 0 through 7. Using
the algorithm to obtain the Shannon-Fano codes produces:
Reversed Order Original
@ -1909,8 +1909,8 @@ The bit lengths for the literal tables are sent first with the number
of entries sent described by the 5 bits sent earlier. There are up
to 286 literal characters; the first 256 represent the respective 8
bit character, code 256 represents the End-Of-Block code, the remaining
29 codes represent copy lengths of 3 thru 258. There are up to 30
distance codes representing distances from 1 thru 32k as described
29 codes represent copy lengths of 3 through 258. There are up to 30
distance codes representing distances from 1 through 32k as described
below.
Length Codes
@ -2221,7 +2221,7 @@ keys, based on random data, to render a plaintext attack on the
data ineffective.
Read the 12-byte encryption header into Buffer, in locations
Buffer(0) thru Buffer(11).
Buffer(0) through Buffer(11).
loop for i <- 0 to 11
C <- buffer(i) ^ decrypt_byte()

View File

@ -74,6 +74,93 @@ docstring-quotes = 'single'
inline-quotes = 'single'
multiline-quotes = 'single'
[tool.codespell]
# calibre will probably never fully compliant with codespell
# this setting is only to easily find common typo errors
# by filtring a great range of false-positives, but not all
# (if codespell could per-file-ignores words, its be nicer)
count = false
summary = false
quiet-level = 3
regex = '''\b(?<!&)(?<!&amp;)[\w\-']+(?!&(amp;)?)\b'''
builtin = [
'clear',
'rare',
'informal',
]
ignore-words-list = [
"alo",
"ans",
"clen",
"eto",
"fo",
"nam",
"nd",
"som",
"te",
"atLeast",
"Implementor",
"implementor",
"Implementors",
"implementors",
"missings",
"re-use",
"re-used",
"re-using",
"succeded",
]
uri-ignore-words-list = '*'
skip = [
"*.svg",
"*.rcc",
"*_ui.py",
"./src/calibre/ebooks/rtf2xml/char_set.py",
"./src/calibre/ebooks/unihandecode/*",
"./src/calibre/ebooks/html_entities.h",
"./src/calibre/ebooks/html_entities.py",
"./src/calibre/utils/icu_test.py",
"./src/calibre/utils/search_query_parser_test.py",
"./Changelog.old.txt",
"./COPYRIGHT",
"./LICENSE",
"./LICENSE.rtf",
"./pyproject.toml",
"./session.vim",
"./build/*",
"./docs/*",
"./nbproject/*",
"./recipes/*",
"./translations/*",
"./tags/*",
"./manual/generated/*",
"./manual/locale/*",
"./resources/dictionaries/*",
"./resources/localization/*",
"./resources/hyphenation/*",
"./resources/mathjax/*",
"./resources/builtin_recipes.xml",
"./resources/changelog.json",
"./resources/editor.js",
"./resources/editor-functions.json",
"./resources/mime.types",
"./resources/piper-voices.json",
"./resources/stylelint-bundle.min.js",
"./resources/user-manual-translation-stats.json",
"./resources/template-functions.json",
"./resources/viewer.js",
"./resources/viewer.html",
"./resources/content-server/index-generated.html",
"./setup/installer/*",
"./setup/pyqt_enums/*",
"./setup/lc_data.py",
"./setup/linux-installer.py",
"./src/css_selectors/*",
"./src/polyglot/*",
"./src/templite/*",
"./src/tinycss/*",
"./src/unicode_names/*",
]
[tool.flynt]
line-length = 400 # over value to catch every case
transform-format = false # don't transform already existing format call

View File

@ -61,7 +61,7 @@ class ESPN(BasicNewsRecipe):
def get_browser(self):
br = BasicNewsRecipe.get_browser(self)
if False and self.username and self.password:
# ESPN has changed to a JS based login system, cant be bothered
# ESPN has changed to a JS based login system, can't be bothered
# revering it
br.set_handle_refresh(False)
url = ('https://r.espn.go.com/members/v3_1/login')

View File

@ -71,7 +71,7 @@ class ft(BasicNewsRecipe):
# def get_browser(self, *args, **kw):
# br = super().get_browser(*args, **kw)
# if self.username and self.password:
# # ft.com uses a CAPTCHA on its login page so this sadly doesnt work
# # ft.com uses a CAPTCHA on its login page so this sadly doesn't work
# br.open('https://accounts.ft.com/login?location=https%3A%2F%2Fwww.ft.com')
# br.select_form(id='email-form')
# br['email'] = self.username

View File

@ -77,7 +77,7 @@ class IndependentAustralia(BasicNewsRecipe):
businessArticles = []
lifeArticles = []
australiaArticles = []
# Loop thru the articles in all feeds to find articles with base categories in it
# Loop through the articles in all feeds to find articles with base categories in it
for curfeed in feeds:
delList = []
for a, curarticle in enumerate(curfeed.articles):

View File

@ -107,7 +107,7 @@ class SatMagazine(BasicNewsRecipe):
title_number = 0
# Goes thru all the articles one by one and sort them out
# Goes through all the articles one by one and sort them out
for article in articles:
title = self.tag_to_string(article)

View File

@ -57,7 +57,7 @@ def get_dist(base, which, bitness):
def shutdown_allowed(which, bitness):
# The ARM64 VM is extremely flakey often booting up to a non-functional
# state so dont shut it down as it seems to be more stable once bootup is
# state so dont shut it down as it seems to be more stable once boot-up is
# done.
return bitness != 'arm64'

View File

@ -3474,7 +3474,7 @@ class Cache:
self._add_extra_files(dest_id, {q: BytesIO(cdata)}, replace=False, auto_rename=True)
break
for key in self.field_metadata: # loop thru all defined fields
for key in self.field_metadata: # loop through all defined fields
fm = self.field_metadata[key]
if not fm['is_custom']:
continue

View File

@ -119,7 +119,7 @@ class Notes:
def path_for_resource(self, resource_hash: str) -> str:
hashalg, digest = resource_hash.split(':', 1)
prefix = digest[:2]
# Cant use colons in filenames on windows safely
# Can't use colons in filenames on windows safely
return os.path.join(self.resources_dir, prefix, f'{hashalg}-{digest}')
def remove_resources(self, conn, note_id, resources_to_potentially_remove, delete_from_link_table=True):

View File

@ -299,7 +299,7 @@
DEVICE_FLAG_BROKEN_MTPGETOBJPROPLIST |
DEVICE_FLAG_PLAYLIST_SPL_V1 },
// YP-F3 is NOT MTP - USB mass storage
// From a rouge .INF file
// From a rogue .INF file
// this device ID seems to have been recycled for:
// the Samsung SGH-A707 Cingular cellphone
// the Samsung L760-V cellphone
@ -1183,7 +1183,7 @@
DEVICE_FLAG_BROKEN_MTPGETOBJPROPLIST_ALL },
// From: Willy Gardiol (web) <willy@gardiol.org>
// Spurious errors for getting all objects, lead me to believe
// this flag atleast is needed
// this flag at least is needed
{ "Nokia", 0x0421, "5800 XpressMusic v2", 0x0155,
DEVICE_FLAG_BROKEN_MTPGETOBJPROPLIST_ALL },
// Yet another version... I think

View File

@ -51,7 +51,7 @@ def read_variable_len_data(data, header):
header['tagx_block_size'] = 0
trailing_bytes = data[idxt_offset+idxt_size:]
if trailing_bytes.rstrip(b'\0'):
raise ValueError('Traling bytes after last IDXT entry: {!r}'.format(trailing_bytes.rstrip(b'\0')))
raise ValueError('Trailing bytes after last IDXT entry: {!r}'.format(trailing_bytes.rstrip(b'\0')))
header['indices'] = indices

View File

@ -101,7 +101,7 @@ div#book-inner {{ margin-top: 0; margin-bottom: 0; }}</style><script type="text/
# encoding quirks
'<p>A\xa0nbsp;&nbsp;':
'<p><span class="koboSpan" id="kobo.1.1">A&#160;nbsp;&#160;</span></p>',
'<div><script>1 < 2 & 3</script>': # escaping with cdata note that kepubify doesnt do this
'<div><script>1 < 2 & 3</script>': # escaping with cdata note that kepubify doesn't do this
'<div><script><![CDATA[1 < 2 & 3]]></script></div>',
# CSS filtering

View File

@ -732,21 +732,21 @@ class Region:
class Page:
def __init__(self, page, font_map, opts, log, idc):
def text_cmp(frst, secnd):
def text_cmp(first, second):
# Compare 2 text objects.
# Order by line (top/bottom) then left
if (frst.top <= secnd.top and frst.bottom >= secnd.bottom-BOTTOM_FACTOR) \
or (secnd.top <= frst.top and secnd.bottom >= frst.bottom-BOTTOM_FACTOR):
if (first.top <= second.top and first.bottom >= second.bottom-BOTTOM_FACTOR) \
or (second.top <= first.top and second.bottom >= first.bottom-BOTTOM_FACTOR):
# Overlap = same line
if frst.left < secnd.left:
if first.left < second.left:
return -1
elif frst.left == secnd.left:
elif first.left == second.left:
return 0
return 1
# Different line so sort into line number
if frst.bottom < secnd.bottom:
if first.bottom < second.bottom:
return -1
elif frst.bottom == secnd.bottom:
elif first.bottom == second.bottom:
return 0
return 1

View File

@ -121,7 +121,7 @@ class ListNumbers:
return 'ordered'
# sys.stderr.write('module is list_numbers\n')
# sys.stderr.write('method is __determine type\n')
# sys.stderr.write('Couldn\'t get type of list\n')
# sys.stderr.write("Couldn't get type of list\n")
# must be some type of ordered list -- just a guess!
return 'unordered'

View File

@ -1776,7 +1776,7 @@ def raise_and_focus(self: QWidget) -> None:
def raise_without_focus(self: QWidget) -> None:
if QApplication.instance().platformName() == 'wayland':
# On fucking Wayland, we cant raise a dialog without also giving it
# On fucking Wayland, we can't raise a dialog without also giving it
# keyboard focus. What a joke.
self.raise_and_focus()
else:

View File

@ -288,10 +288,10 @@ class AutoAdder(QObject):
if duplicates:
paths, formats, metadata = [], [], []
for p, f, mis in duplicates:
for p, f, mi in duplicates:
paths.extend(p)
formats.extend(f)
metadata.extend(mis)
metadata.extend(mi)
dups = [(mic, mic.cover, [p]) for mic, p in zip(metadata, paths)]
d = DuplicatesQuestion(m.db, dups, parent=gui)
dups = tuple(d.duplicates)

View File

@ -485,7 +485,7 @@ class CentralContainer(QWidget):
def read_settings(self):
before = self.serialized_settings()
# sadly self.size() doesnt always return sensible values so look at
# sadly self.size() doesn't always return sensible values so look at
# the size of the main window which works perfectly for width, not so
# perfectly for height
sz = self.size()

View File

@ -287,7 +287,7 @@ class NoteEditorWidget(EditorWidget):
def do_insert_image(self):
# See https://bugreports.qt.io/browse/QTBUG-118537
# for why we cant have a nice margin for floating images
# for why we can't have a nice margin for floating images
d = AskImage(self.images, self.db)
if d.exec() == QDialog.DialogCode.Accepted and d.current_digest:
ir = self.images[d.current_digest]

View File

@ -153,14 +153,14 @@ def send_mails(jobnames, callback, attachments, to_s, subjects,
attachments, to_s, subjects, texts, attachment_names):
description = _('Email %(name)s to %(to)s') % dict(name=name, to=to)
if isinstance(to, str) and (is_for_kindle(to) or '@pbsync.com' in to):
# The PocketBook service is a total joke. It cant handle
# The PocketBook service is a total joke. It can't handle
# non-ascii, filenames that are long enough to be split up, commas, and
# the good lord alone knows what else. So use a random filename
# containing only 22 English letters and numbers
#
# And since this email is only going to be processed by automated
# services, make the subject+text random too as at least the amazon
# service cant handle non-ascii text. I dont know what baboons
# service can't handle non-ascii text. I dont know what baboons
# these companies employ to write their code. It's the height of
# irony that they are called "tech" companies.
# https://bugs.launchpad.net/calibre/+bug/1989282

View File

@ -36,7 +36,7 @@ class FTSDialog(Dialog):
l = QVBoxLayout(self)
self.fat_warning = fw = QLabel(
f'<span style="color:red; font-weight: bold">{_("WARNING")}:</span> ' +
_('The calibre library is on a FAT drive, indexing more than a few hundred books wont work.') +
_("The calibre library is on a FAT drive, indexing more than a few hundred books won't work.") +
f' <a href="xxx" style="text-decoration: none">{_("Learn more")}</a>')
# fw.setVisible(False)
fw.linkActivated.connect(self.show_fat_details)

View File

@ -359,7 +359,7 @@ class VLTabs(QTabBar): # {{{
def lock_tab(self):
gprefs['vl_tabs_closable'] = False
self.setTabsClosable(False)
# Workaround for Qt bug where it doesnt recalculate the tab size after locking
# Workaround for Qt bug where it doesn't recalculate the tab size after locking
for idx in range(self.count()):
self.setTabButton(idx, QTabBar.ButtonPosition.RightSide, None)
self.setTabButton(idx, QTabBar.ButtonPosition.LeftSide, None)

View File

@ -268,7 +268,7 @@ class MarkdownHighlighter(QSyntaxHighlighter):
elif emphasis:
self.setFormat(self.offset+offset+ match.start(), match.end() - match.start(), self.MARKDOWN_KWS_FORMAT['Italic'])
def recusive(match, extra_offset, bold, emphasis):
def recursive(match, extra_offset, bold, emphasis):
apply(match, bold, emphasis)
if bold and emphasis:
return # max deep => return, do not process extra Bold/Italic
@ -278,17 +278,17 @@ class MarkdownHighlighter(QSyntaxHighlighter):
self._highlightBoldEmphasis(sub_txt, cursor, bf, sub_offset, bold, emphasis)
for mo in re.finditer(self.MARKDOWN_KEYS_REGEX['Italic'],text):
recusive(mo, 1, bold, True)
recursive(mo, 1, bold, True)
found = True
for mo in re.finditer(self.MARKDOWN_KEYS_REGEX['uItalic'],text):
recusive(mo, 1, bold, True)
recursive(mo, 1, bold, True)
found = True
for mo in re.finditer(self.MARKDOWN_KEYS_REGEX['Bold'],text):
recusive(mo, 2, True, emphasis)
recursive(mo, 2, True, emphasis)
found = True
for mo in re.finditer(self.MARKDOWN_KEYS_REGEX['uBold'],text):
recusive(mo, 2, True, emphasis)
recursive(mo, 2, True, emphasis)
found = True
for mo in re.finditer(self.MARKDOWN_KEYS_REGEX['BoldItalic'],text):

View File

@ -25,7 +25,7 @@ JS_IDENT = JS_IDENT_START + '(?:' + JS_IDENT_PART + ')*'
class JavascriptLexer(RegexLexer):
'''
For JavaScript source code. This is based on the pygments JS highlighter,
bu that does not handle multi-line comments in streaming mode, so we had to
but that does not handle multi-line comments in streaming mode, so we had to
modify it.
'''

View File

@ -83,7 +83,7 @@ def parse_uri(uri, parse_query=True, unquote_func=unquote):
try:
query = MultiDict.create_from_query_string(qs)
except Exception:
raise HTTPSimpleResponse(http_client.BAD_REQUEST, 'Unparseable query string')
raise HTTPSimpleResponse(http_client.BAD_REQUEST, 'Unparsable query string')
else:
query = None

View File

@ -192,7 +192,7 @@ class SetGlobalsNode(Node):
class StringCompareNode(Node):
def __init__(self, line_number, operator, left, right):
Node.__init__(self, line_number, 'comparision: ' + operator)
Node.__init__(self, line_number, 'comparison: ' + operator)
self.node_type = self.NODE_COMPARE_STRING
self.operator = operator
self.left = left

View File

@ -743,7 +743,7 @@ class SMTP:
>>> tolist=["one@one.org","two@two.org","three@three.org","four@four.org"]
>>> msg = '''\\
... From: Me@my.org
... Subject: testin'...
... Subject: testing...
...
... This is a test '''
>>> s.sendmail("me@my.org",tolist,msg)

View File

@ -446,7 +446,7 @@ def next_screen_location():
current_pos = Math.ceil(current_scroll_offset())
ans = limit if current_pos < limit else -1
if cols_per_screen is 1 and ans is not -1 and ans - current_pos < col_size:
ans = -1 # cant scroll partial columns
ans = -1 # can't scroll partial columns
return ans

View File

@ -145,7 +145,7 @@ class ReadUI:
try:
result = JSON.parse(xhr.responseText)
except Exception:
return self.show_error(_('Failed to parse profiles'), _('Unparseable data received for profiles'))
return self.show_error(_('Failed to parse profiles'), _('Unparsable data received for profiles'))
proceed(result)
).send()

View File

@ -134,7 +134,7 @@ def range_extents(q, in_flow_mode):
rect = boundary_node.getBoundingClientRect()
if not is_start:
ans.selected_prev = True
# we cant use getBoundingClientRect as the node might be split
# we can't use getBoundingClientRect as the node might be split
# among multiple columns
else if node.getClientRects:
rects = node.getClientRects()