This commit is contained in:
Kovid Goyal 2024-12-15 19:07:08 +05:30
commit 5c9d3386ee
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
118 changed files with 657 additions and 594 deletions

View File

@ -23,8 +23,9 @@ from setup import __appname__, __version__
sys.path.append(base) sys.path.append(base)
import calibre.utils.img as cimg
import custom import custom
import calibre.utils.img as cimg
from calibre.utils.localization import localize_website_link from calibre.utils.localization import localize_website_link
del sys.path[0] del sys.path[0]

View File

@ -299,7 +299,7 @@ def render_options(cmd, groups, options_header=True, add_program=True, header_le
def mark_options(raw): def mark_options(raw):
raw = re.sub(r'(\s+)--(\s+)', u'\\1``--``\\2', raw) raw = re.sub(r'(\s+)--(\s+)', r'\1``--``\2', raw)
def sub(m): def sub(m):
opt = m.group() opt = m.group()

View File

@ -8,13 +8,13 @@ __docformat__ = 'restructuredtext en'
import os import os
from sphinx.builders.epub3 import Epub3Builder as EpubBuilder
from calibre.ebooks.oeb.base import OPF from calibre.ebooks.oeb.base import OPF
from calibre.ebooks.oeb.polish.check.links import UnreferencedResource, check_links from calibre.ebooks.oeb.polish.check.links import UnreferencedResource, check_links
from calibre.ebooks.oeb.polish.container import OEB_DOCS, get_container from calibre.ebooks.oeb.polish.container import OEB_DOCS, get_container
from calibre.ebooks.oeb.polish.pretty import pretty_html_tree, pretty_opf from calibre.ebooks.oeb.polish.pretty import pretty_html_tree, pretty_opf
from calibre.utils.imghdr import identify from calibre.utils.imghdr import identify
from sphinx.builders.epub3 import Epub3Builder as EpubBuilder
from polyglot.builtins import iteritems from polyglot.builtins import iteritems

View File

@ -7,14 +7,15 @@ __copyright__ = '2014, Kovid Goyal <kovid at kovidgoyal.net>'
import re import re
from css_parser.css import CSSRule
from qt.core import QAction, QInputDialog
from calibre import force_unicode from calibre import force_unicode
from calibre.ebooks.oeb.polish.container import OEB_DOCS, OEB_STYLES, serialize from calibre.ebooks.oeb.polish.container import OEB_DOCS, OEB_STYLES, serialize
from calibre.gui2 import error_dialog from calibre.gui2 import error_dialog
# The base class that all tools must inherit from # The base class that all tools must inherit from
from calibre.gui2.tweak_book.plugin import Tool from calibre.gui2.tweak_book.plugin import Tool
from css_parser.css import CSSRule
from qt.core import QAction, QInputDialog
class DemoTool(Tool): class DemoTool(Tool):

View File

@ -6,9 +6,10 @@ __license__ = 'GPL v3'
__copyright__ = '2011, Kovid Goyal <kovid@kovidgoyal.net>' __copyright__ = '2011, Kovid Goyal <kovid@kovidgoyal.net>'
__docformat__ = 'restructuredtext en' __docformat__ = 'restructuredtext en'
from calibre.utils.config import JSONConfig
from qt.core import QHBoxLayout, QLabel, QLineEdit, QWidget from qt.core import QHBoxLayout, QLabel, QLineEdit, QWidget
from calibre.utils.config import JSONConfig
# This is where all preferences for this plugin will be stored # This is where all preferences for this plugin will be stored
# Remember that this name (i.e. plugins/interface_demo) is also # Remember that this name (i.e. plugins/interface_demo) is also
# in a global namespace, so make it as unique as possible. # in a global namespace, so make it as unique as possible.

View File

@ -12,9 +12,10 @@ if False:
# You do not need this code in your plugins # You do not need this code in your plugins
get_icons = get_resources = None get_icons = get_resources = None
from calibre_plugins.interface_demo.config import prefs
from qt.core import QDialog, QLabel, QMessageBox, QPushButton, QVBoxLayout from qt.core import QDialog, QLabel, QMessageBox, QPushButton, QVBoxLayout
from calibre_plugins.interface_demo.config import prefs
class DemoDialog(QDialog): class DemoDialog(QDialog):

View File

@ -4,24 +4,35 @@ requires-python = ">=3.8"
[tool.ruff] [tool.ruff]
line-length = 160 line-length = 160
target-version = 'py38' target-version = 'py38'
builtins = ['_'] builtins = ['_', 'I', 'P']
include = ['*.py', '*.recipe']
[tool.ruff.lint] exclude = [
ignore = ['E741', 'E402', 'E722', 'E401'] "*_ui.py",
select = ['E', 'F', 'I'] "bypy/*",
"setup/*",
[tool.ruff.lint.per-file-ignores] "src/css_selectors/*",
"src/calibre/ebooks/unihandecode/unicodepoints.py" = ["E501"] "src/polyglot/*",
"src/qt/__init__.py" = ["E501"] "src/templite/*",
"src/tinycss/*",
]
[tool.ruff.format] [tool.ruff.format]
quote-style = 'single' quote-style = 'single'
[tool.ruff.lint]
ignore = ['E402', 'E722', 'E741', 'E401']
select = ['E', 'F', 'I', 'W']
[tool.ruff.lint.per-file-ignores]
"src/calibre/ebooks/unihandecode/*codepoints.py" = ['E501', 'W191']
"src/qt/*.py" = ['I']
"src/qt/*.pyi" = ['I']
[tool.ruff.lint.isort] [tool.ruff.lint.isort]
detect-same-package = true detect-same-package = true
extra-standard-library = ['aes', 'elementmaker', 'encodings'] extra-standard-library = ["aes", "elementmaker", "encodings"]
known-first-party = ["calibre_extensions", 'polyglot'] known-first-party = ["calibre_extensions", "calibre_plugins", "polyglot"]
known-third-party = ["qt"] known-third-party = ["odf", "qt", "templite", "tinycss", "css_selectors"]
relative-imports-order = "closest-to-furthest" relative-imports-order = "closest-to-furthest"
split-on-trailing-comma = false split-on-trailing-comma = false
section-order = ['__python__', "future", "standard-library", "third-party", "first-party", "local-folder"] section-order = ['__python__', "future", "standard-library", "third-party", "first-party", "local-folder"]

View File

@ -7,12 +7,13 @@ from collections import defaultdict
from datetime import datetime, timedelta from datetime import datetime, timedelta
from urllib.parse import quote, urlencode from urllib.parse import quote, urlencode
from html5_parser import parse
from lxml import etree
from calibre import replace_entities from calibre import replace_entities
from calibre.ebooks.BeautifulSoup import NavigableString, Tag from calibre.ebooks.BeautifulSoup import NavigableString, Tag
from calibre.ptempfile import PersistentTemporaryFile from calibre.ptempfile import PersistentTemporaryFile
from calibre.web.feeds.news import BasicNewsRecipe from calibre.web.feeds.news import BasicNewsRecipe
from html5_parser import parse
from lxml import etree
use_archive = True use_archive = True

View File

@ -4,9 +4,10 @@ __copyright__ = '2010, Walt Anthony <workshop.northpole at gmail.com>'
www.americanthinker.com www.americanthinker.com
''' '''
import html5lib import html5lib
from lxml import etree
from calibre.utils.cleantext import clean_xml_chars from calibre.utils.cleantext import clean_xml_chars
from calibre.web.feeds.news import BasicNewsRecipe from calibre.web.feeds.news import BasicNewsRecipe
from lxml import etree
class AmericanThinker(BasicNewsRecipe): class AmericanThinker(BasicNewsRecipe):

View File

@ -4,9 +4,10 @@ __copyright__ = '2009-2010, Darko Miletic <darko.miletic at gmail.com>'
spectator.org spectator.org
''' '''
from calibre.web.feeds.news import BasicNewsRecipe
from css_selectors import Select from css_selectors import Select
from calibre.web.feeds.news import BasicNewsRecipe
class TheAmericanSpectator(BasicNewsRecipe): class TheAmericanSpectator(BasicNewsRecipe):
title = 'The American Spectator' title = 'The American Spectator'

View File

@ -3,9 +3,10 @@
import json import json
from datetime import datetime from datetime import datetime
from calibre.web.feeds.news import BasicNewsRecipe
from html5_parser import parse from html5_parser import parse
from calibre.web.feeds.news import BasicNewsRecipe
class BusinessStandard(BasicNewsRecipe): class BusinessStandard(BasicNewsRecipe):
title = 'Business Standard' title = 'Business Standard'

View File

@ -3,9 +3,10 @@
import json import json
from urllib.parse import quote, urlparse from urllib.parse import quote, urlparse
from calibre.web.feeds.news import BasicNewsRecipe
from mechanize import Request from mechanize import Request
from calibre.web.feeds.news import BasicNewsRecipe
def absurl(x): def absurl(x):
if x.startswith('//'): if x.startswith('//'):

View File

@ -18,7 +18,6 @@ class herald(BasicNewsRecipe):
keep_only_tags = [ keep_only_tags = [
classes('article-title article-author__name'), classes('article-title article-author__name'),
dict(name='div', attrs={'id':'main-content'}) dict(name='div', attrs={'id':'main-content'})
] ]
remove_tags = [ remove_tags = [

View File

@ -16,6 +16,7 @@ try:
except ImportError: except ImportError:
from cookielib import Cookie from cookielib import Cookie
import mechanize import mechanize
from calibre.web.feeds.news import BasicNewsRecipe from calibre.web.feeds.news import BasicNewsRecipe

View File

@ -5,9 +5,10 @@ www.esquire.com
''' '''
from collections import defaultdict from collections import defaultdict
from calibre.web.feeds.news import BasicNewsRecipe
from css_selectors import Select from css_selectors import Select
from calibre.web.feeds.news import BasicNewsRecipe
def absolutize(url): def absolutize(url):
if url.startswith('/'): if url.startswith('/'):

View File

@ -4,9 +4,10 @@ import json
import re import re
from urllib.parse import quote from urllib.parse import quote
from html5_parser import parse
from calibre import browser from calibre import browser
from calibre.web.feeds.news import BasicNewsRecipe, classes from calibre.web.feeds.news import BasicNewsRecipe, classes
from html5_parser import parse
class ft(BasicNewsRecipe): class ft(BasicNewsRecipe):

View File

@ -7,9 +7,10 @@ __copyright__ = '2017, John Hutson <jfhutson at gmail.com>'
firstthings.com firstthings.com
''' '''
import html5lib import html5lib
from calibre.web.feeds.news import BasicNewsRecipe
from lxml import html from lxml import html
from calibre.web.feeds.news import BasicNewsRecipe
class FirstThings(BasicNewsRecipe): class FirstThings(BasicNewsRecipe):

View File

@ -4,9 +4,10 @@ import re
import html5lib import html5lib
import mechanize import mechanize
from calibre.web.feeds.news import BasicNewsRecipe, classes
from lxml import html from lxml import html
from calibre.web.feeds.news import BasicNewsRecipe, classes
def as_article(source, log): def as_article(source, log):
url = source['url'] url = source['url']

View File

@ -8,9 +8,10 @@ __copyright__ = '2011, Piotr Kontek, piotr.kontek@gmail.com \
import re import re
import time import time
from calibre.web.feeds.news import BasicNewsRecipe
from lxml import html from lxml import html
from calibre.web.feeds.news import BasicNewsRecipe
class GN(BasicNewsRecipe): class GN(BasicNewsRecipe):
__author__ = 'Piotr Kontek, Tomasz Długosz' __author__ = 'Piotr Kontek, Tomasz Długosz'

View File

@ -7,9 +7,10 @@ __copyright__ = '2011, Piotr Kontek, piotr.kontek@gmail.com \
import re import re
from calibre.web.feeds.news import BasicNewsRecipe
from lxml import html from lxml import html
from calibre.web.feeds.news import BasicNewsRecipe
class GN(BasicNewsRecipe): class GN(BasicNewsRecipe):
__author__ = 'Piotr Kontek, Tomasz Długosz' __author__ = 'Piotr Kontek, Tomasz Długosz'

View File

@ -5,9 +5,10 @@ import re
from collections import OrderedDict from collections import OrderedDict
from urllib.parse import urlencode, urljoin from urllib.parse import urlencode, urljoin
from mechanize import Request
from calibre import browser, random_user_agent from calibre import browser, random_user_agent
from calibre.web.feeds.news import BasicNewsRecipe, classes from calibre.web.feeds.news import BasicNewsRecipe, classes
from mechanize import Request
class HBR(BasicNewsRecipe): class HBR(BasicNewsRecipe):

View File

@ -2,9 +2,10 @@
# vim:fileencoding=utf-8 # vim:fileencoding=utf-8
import json import json
from calibre.web.feeds.news import BasicNewsRecipe
from html5_parser import parse from html5_parser import parse
from calibre.web.feeds.news import BasicNewsRecipe
def get_story(story): def get_story(story):
str_type = story.get('type', '') str_type = story.get('type', '')

View File

@ -8,9 +8,10 @@ import json
from contextlib import closing from contextlib import closing
from time import sleep from time import sleep
from calibre.web.feeds.news import BasicNewsRecipe
from mechanize import Request from mechanize import Request
from calibre.web.feeds.news import BasicNewsRecipe
def absolutize(url): def absolutize(url):
if url.startswith('/'): if url.startswith('/'):

View File

@ -118,9 +118,10 @@ class Mediapart(BasicNewsRecipe):
''' '''
Create a generic cover for recipes that don't have a cover Create a generic cover for recipes that don't have a cover
''' '''
from calibre.gui2 import ensure_app, load_builtin_fonts, pixmap_to_data
from qt.core import QFont, QImage, QPainter, QPen, QRect, Qt from qt.core import QFont, QImage, QPainter, QPen, QRect, Qt
from calibre.gui2 import ensure_app, load_builtin_fonts, pixmap_to_data
def init_environment(): def init_environment():
ensure_app() ensure_app()
load_builtin_fonts() load_builtin_fonts()

View File

@ -4,9 +4,10 @@ import json
import re import re
from contextlib import closing from contextlib import closing
from calibre.web.feeds.recipes import BasicNewsRecipe
from mechanize import Request from mechanize import Request
from calibre.web.feeds.recipes import BasicNewsRecipe
class NRC(BasicNewsRecipe): class NRC(BasicNewsRecipe):
title = 'NRC' title = 'NRC'

View File

@ -1,9 +1,10 @@
import json import json
from datetime import datetime from datetime import datetime
from calibre.web.feeds.recipes import BasicNewsRecipe
from mechanize import Request from mechanize import Request
from calibre.web.feeds.recipes import BasicNewsRecipe
class Nzz(BasicNewsRecipe): class Nzz(BasicNewsRecipe):
title = 'NZZ' title = 'NZZ'

View File

@ -7,9 +7,10 @@ odb.org
import uuid import uuid
from calibre.web.feeds.news import BasicNewsRecipe
from lxml import html from lxml import html
from calibre.web.feeds.news import BasicNewsRecipe
class OurDailyBread(BasicNewsRecipe): class OurDailyBread(BasicNewsRecipe):
title = 'Our Daily Bread' title = 'Our Daily Bread'

View File

@ -3,9 +3,10 @@ import json
import uuid import uuid
from contextlib import closing from contextlib import closing
from calibre.web.feeds.recipes import BasicNewsRecipe
from mechanize import Request from mechanize import Request
from calibre.web.feeds.recipes import BasicNewsRecipe
class Parool(BasicNewsRecipe): class Parool(BasicNewsRecipe):
title = 'Het Parool' title = 'Het Parool'

View File

@ -9,7 +9,6 @@ publico.pt
''' '''
from calibre.web.feeds.news import BasicNewsRecipe from calibre.web.feeds.news import BasicNewsRecipe
from polyglot.urllib import urlencode from polyglot.urllib import urlencode

View File

@ -10,9 +10,10 @@ import re
# This imports the version bundled with Calibre # This imports the version bundled with Calibre
import lxml import lxml
from lxml.builder import E
from calibre.ebooks.BeautifulSoup import BeautifulSoup from calibre.ebooks.BeautifulSoup import BeautifulSoup
from calibre.web.feeds.recipes import BasicNewsRecipe from calibre.web.feeds.recipes import BasicNewsRecipe
from lxml.builder import E
respekt_url = 'https://www.respekt.cz' respekt_url = 'https://www.respekt.cz'

View File

@ -51,7 +51,7 @@ class PhilippineDailyInquirer(BasicNewsRecipe):
feeds = [ feeds = [
('Headlines' , 'http://newsinfo.inquirer.net/category/inquirer-headlines/feed'), ('Headlines', 'http://newsinfo.inquirer.net/category/inquirer-headlines/feed'),
('Latest Stories' , 'http://newsinfo.inquirer.net/category/latest-stories/feed'), ('Latest Stories' , 'http://newsinfo.inquirer.net/category/latest-stories/feed'),
('Nation' , 'http://newsinfo.inquirer.net/category/nation/feed'), ('Nation' , 'http://newsinfo.inquirer.net/category/nation/feed'),
('Nation - Latest Stories' , 'http://newsinfo.inquirer.net/category/latest-stories/nation-latest-stories/feed'), ('Nation - Latest Stories' , 'http://newsinfo.inquirer.net/category/latest-stories/nation-latest-stories/feed'),

View File

@ -15,10 +15,11 @@ except ImportError:
from urllib import urlencode from urllib import urlencode
import re import re
from mechanize import Request
from calibre import strftime from calibre import strftime
from calibre.ptempfile import PersistentTemporaryFile from calibre.ptempfile import PersistentTemporaryFile
from calibre.web.feeds.news import BasicNewsRecipe from calibre.web.feeds.news import BasicNewsRecipe
from mechanize import Request
class TheNewCriterion(BasicNewsRecipe): class TheNewCriterion(BasicNewsRecipe):

View File

@ -69,7 +69,7 @@ class PrivateEyeRecipe(BasicNewsRecipe):
article['author'] = author article['author'] = author
return article return article
edition_re = re.compile('(?:-front-cover-)(\d+)-') edition_re = re.compile(r'(?:-front-cover-)(\d+)-')
# Identify the cover image and extract the edition# from the url # Identify the cover image and extract the edition# from the url
def get_cover_url(self): def get_cover_url(self):
@ -242,8 +242,8 @@ class PrivateEyeRecipe(BasicNewsRecipe):
{'name': 'a', 'class': "view-full-screen"}, {'name': 'a', 'class': "view-full-screen"},
{'name': 'div', 'class': "image-counter"}, {'name': 'div', 'class': "image-counter"},
{'name': 'h2', 'string': "Find out more about The Oldie"}, {'name': 'h2', 'string': "Find out more about The Oldie"},
{'name': 'a', 'href': re.compile("^https?:\/\/issuu.com\/")}, {'name': 'a', 'href': re.compile(r"^https?:\/\/issuu.com\/")},
{'name': 'img', 'src': re.compile("\/assets\/images\/icons\/icon-")}, {'name': 'img', 'src': re.compile(r"\/assets\/images\/icons\/icon-")},
] ]
# The following extra css is to tweak the formatting of various elements of various article pages. # The following extra css is to tweak the formatting of various elements of various article pages.

View File

@ -16,7 +16,7 @@ def re_html(y):
def get_id(url): def get_id(url):
rq = browser().open(url) rq = browser().open(url)
return re.search('\?p=(\S+)>', str(rq.info())).group(1) return re.search(r'\?p=(\S+)>', str(rq.info())).group(1)
class TLS(BasicNewsRecipe): class TLS(BasicNewsRecipe):

View File

@ -34,4 +34,3 @@ class Ugeskriftet(BasicNewsRecipe):
feeds = [ feeds = [
('Ugeskriftet for læger', 'https://ugeskriftet.dk/rss/forside'), ('Ugeskriftet for læger', 'https://ugeskriftet.dk/rss/forside'),
] ]

View File

@ -88,7 +88,6 @@ class USAToday(BasicNewsRecipe):
feeds.append((section, articles)) feeds.append((section, articles))
return feeds return feeds
def preprocess_html(self, soup): def preprocess_html(self, soup):
for img in soup.findAll('img', src=True): for img in soup.findAll('img', src=True):
img['src'] = 'https://www.usatoday.com' + img['src'] img['src'] = 'https://www.usatoday.com' + img['src']

View File

@ -3,9 +3,10 @@ import json
import uuid import uuid
from contextlib import closing from contextlib import closing
from calibre.web.feeds.recipes import BasicNewsRecipe
from mechanize import Request from mechanize import Request
from calibre.web.feeds.recipes import BasicNewsRecipe
class Volkskrant(BasicNewsRecipe): class Volkskrant(BasicNewsRecipe):
title = 'Volkskrant' title = 'Volkskrant'

View File

@ -10,11 +10,12 @@ import time
from base64 import standard_b64encode from base64 import standard_b64encode
from datetime import date, timedelta from datetime import date, timedelta
from calibre.ptempfile import PersistentTemporaryFile
from calibre.web.feeds.news import BasicNewsRecipe
from css_selectors import Select from css_selectors import Select
from mechanize import Request from mechanize import Request
from calibre.ptempfile import PersistentTemporaryFile
from calibre.web.feeds.news import BasicNewsRecipe
try: try:
import urllib.parse as urlparse import urllib.parse as urlparse
except ImportError: except ImportError:

View File

@ -216,14 +216,14 @@ save_template_title_series_sorting = 'library_order'
# (present only for legacy reasons). # (present only for legacy reasons).
per_language_title_sort_articles = { per_language_title_sort_articles = {
# English # English
'eng' : (r'A\s+', r'The\s+', r'An\s+'), 'eng': (r'A\s+', r'The\s+', r'An\s+'),
# Esperanto # Esperanto
'epo': (r'La\s+', r"L'", 'L´'), 'epo': (r'La\s+', r"L'", 'L´'),
# Spanish # Spanish
'spa' : (r'El\s+', r'La\s+', r'Lo\s+', r'Los\s+', r'Las\s+', r'Un\s+', 'spa': (r'El\s+', r'La\s+', r'Lo\s+', r'Los\s+', r'Las\s+', r'Un\s+',
r'Una\s+', r'Unos\s+', r'Unas\s+'), r'Una\s+', r'Unos\s+', r'Unas\s+'),
# French # French
'fra' : (r'Le\s+', r'La\s+', r"L'", u'L´', u'L', r'Les\s+', r'Un\s+', r'Une\s+', 'fra': (r'Le\s+', r'La\s+', r"L'", r'L´', r'L', r'Les\s+', r'Un\s+', r'Une\s+',
r'Des\s+', r'De\s+La\s+', r'De\s+', r"D'", r'D´', r'D'), r'Des\s+', r'De\s+La\s+', r'De\s+', r"D'", r'D´', r'D'),
# Polish # Polish
'pol': (), 'pol': (),
@ -233,32 +233,32 @@ per_language_title_sort_articles = {
'Un´', 'Dei\\s+', 'Degli\\s+', 'Delle\\s+', 'Del\\s+', 'Un´', 'Dei\\s+', 'Degli\\s+', 'Delle\\s+', 'Del\\s+',
'Della\\s+', 'Dello\\s+', "Dell'", 'Dell´'), 'Della\\s+', 'Dello\\s+', "Dell'", 'Dell´'),
# Portuguese # Portuguese
'por' : (r'A\s+', r'O\s+', r'Os\s+', r'As\s+', r'Um\s+', r'Uns\s+', 'por': (r'A\s+', r'O\s+', r'Os\s+', r'As\s+', r'Um\s+', r'Uns\s+',
r'Uma\s+', r'Umas\s+', ), r'Uma\s+', r'Umas\s+', ),
# Romanian # Romanian
'ron' : (r'Un\s+', r'O\s+', r'Nişte\s+', ), 'ron': (r'Un\s+', r'O\s+', r'Nişte\s+', ),
# German # German
'deu' : (r'Der\s+', r'Die\s+', r'Das\s+', r'Den\s+', r'Ein\s+', 'deu': (r'Der\s+', r'Die\s+', r'Das\s+', r'Den\s+', r'Ein\s+',
r'Eine\s+', r'Einen\s+', r'Dem\s+', r'Des\s+', r'Einem\s+', r'Eine\s+', r'Einen\s+', r'Dem\s+', r'Des\s+', r'Einem\s+',
r'Eines\s+'), r'Eines\s+'),
# Dutch # Dutch
'nld' : (r'De\s+', r'Het\s+', r'Een\s+', r"'n\s+", r"'s\s+", r'Ene\s+', 'nld': (r'De\s+', r'Het\s+', r'Een\s+', r"'n\s+", r"'s\s+", r'Ene\s+',
r'Ener\s+', r'Enes\s+', r'Den\s+', r'Der\s+', r'Des\s+', r'Ener\s+', r'Enes\s+', r'Den\s+', r'Der\s+', r'Des\s+',
r"'t\s+"), r"'t\s+"),
# Swedish # Swedish
'swe' : (r'En\s+', r'Ett\s+', r'Det\s+', r'Den\s+', r'De\s+', ), 'swe': (r'En\s+', r'Ett\s+', r'Det\s+', r'Den\s+', r'De\s+', ),
# Turkish # Turkish
'tur' : (r'Bir\s+', ), 'tur': (r'Bir\s+', ),
# Afrikaans # Afrikaans
'afr' : (r"'n\s+", r'Die\s+', ), 'afr': (r"'n\s+", r'Die\s+', ),
# Greek # Greek
'ell' : (r'O\s+', r'I\s+', r'To\s+', r'Ta\s+', r'Tus\s+', r'Tis\s+', 'ell': (r'O\s+', r'I\s+', r'To\s+', r'Ta\s+', r'Tus\s+', r'Tis\s+',
r"'Enas\s+", r"'Mia\s+", r"'Ena\s+", r"'Enan\s+", ), r"'Enas\s+", r"'Mia\s+", r"'Ena\s+", r"'Enan\s+", ),
# Hungarian # Hungarian
'hun' : (r'A\s+', r'Az\s+', r'Egy\s+',), 'hun': (r'A\s+', r'Az\s+', r'Egy\s+',),
} }
default_language_for_title_sort = None default_language_for_title_sort = None
title_sort_articles=r'^(A|The|An)\s+' title_sort_articles = r'^(A|The|An)\s+'
#: Specify a folder calibre should connect to at startup #: Specify a folder calibre should connect to at startup
# Specify a folder that calibre should connect to at startup using # Specify a folder that calibre should connect to at startup using
@ -331,8 +331,8 @@ auto_connect_to_folder = ''
# The resulting two tweaks are: # The resulting two tweaks are:
# sony_collection_renaming_rules={'series':'Series', 'tags':'Tag'} # sony_collection_renaming_rules={'series':'Series', 'tags':'Tag'}
# sony_collection_name_template='{category:||: }{value}' # sony_collection_name_template='{category:||: }{value}'
sony_collection_renaming_rules={} sony_collection_renaming_rules = {}
sony_collection_name_template='{value}{category:| (|)}' sony_collection_name_template = '{value}{category:| (|)}'
#: Specify how SONY collections are sorted #: Specify how SONY collections are sorted
# Specify how SONY collections are sorted. This tweak is only applicable if # Specify how SONY collections are sorted. This tweak is only applicable if

View File

@ -41,6 +41,10 @@ class Check(Command):
CACHE = 'check.json' CACHE = 'check.json'
def add_options(self, parser):
parser.add_option('--fix', '--auto-fix', default=False, action='store_true',
help='Try to automatically fix some of the smallest errors')
def get_files(self): def get_files(self):
yield from checkable_python_files(self.SRC) yield from checkable_python_files(self.SRC)
@ -91,6 +95,10 @@ class Check(Command):
p = subprocess.Popen(['python', self.j(self.wn_path, 'whats_new.py'), f]) p = subprocess.Popen(['python', self.j(self.wn_path, 'whats_new.py'), f])
return p.wait() != 0 return p.wait() != 0
def perform_auto_fix(self):
p = subprocess.Popen(['ruff', 'check', '--fix-only'], text=True, stdout=subprocess.PIPE)
return p.stdout.read()
def run(self, opts): def run(self, opts):
self.fhash_cache = {} self.fhash_cache = {}
cache = {} cache = {}
@ -102,13 +110,20 @@ class Check(Command):
except OSError as err: except OSError as err:
if err.errno != errno.ENOENT: if err.errno != errno.ENOENT:
raise raise
if opts.fix:
self.info('\tAuto-fixing')
msg = self.perform_auto_fix()
self.info(msg)
dirty_files = tuple(f for f in self.get_files() if not self.is_cache_valid(f, cache)) dirty_files = tuple(f for f in self.get_files() if not self.is_cache_valid(f, cache))
try: try:
for i, f in enumerate(dirty_files): for i, f in enumerate(dirty_files):
self.info('\tChecking', f) self.info('\tChecking', f)
if self.file_has_errors(f): if self.file_has_errors(f):
self.info('%d files left to check' % (len(dirty_files) - i - 1)) self.info('%d files left to check' % (len(dirty_files) - i - 1))
try:
edit_file(f) edit_file(f)
except FileNotFoundError:
pass # continue if the configured editor fail to be open
if self.file_has_errors(f): if self.file_has_errors(f):
raise SystemExit(1) raise SystemExit(1)
cache[f] = self.file_hash(f) cache[f] = self.file_hash(f)

View File

@ -11,7 +11,7 @@ class PageGroup:
"""Simulate constructor overloading""" """Simulate constructor overloading"""
def __init__(self, page_locations: Union[int, List[int]], page_number_type: PageNumberTypes, first_value: int, def __init__(self, page_locations: Union[int, List[int]], page_number_type: PageNumberTypes, first_value: int,
page_labels: Union[str, List[str], None] = None): page_labels: Union[str, List[str], None] = None):
if page_locations.__class__ == int: if page_locations.__class__ is int:
self.page_locations: List[int] = [page_locations] self.page_locations: List[int] = [page_locations]
else: else:
self.page_locations: List[int] = page_locations self.page_locations: List[int] = page_locations
@ -19,7 +19,7 @@ class PageGroup:
self.__first_value = first_value self.__first_value = first_value
if page_number_type == PageNumberTypes.Custom: if page_number_type == PageNumberTypes.Custom:
assert page_labels is not None assert page_labels is not None
if page_labels.__class__ == str: if page_labels.__class__ is str:
assert 1 == len(self.page_locations) and len(page_labels) > 0 assert 1 == len(self.page_locations) and len(page_labels) > 0
self.__page_number_labels: List[str] = [page_labels] self.__page_number_labels: List[str] = [page_labels]
else: else:
@ -28,7 +28,7 @@ class PageGroup:
self.__page_number_labels: List[str] = page_labels self.__page_number_labels: List[str] = page_labels
def append(self, page_location: Union[int, Tuple[int, str]]) -> None: def append(self, page_location: Union[int, Tuple[int, str]]) -> None:
if page_location.__class__ == int: if page_location.__class__ is int:
assert self.__page_number_type != PageNumberTypes.Custom assert self.__page_number_type != PageNumberTypes.Custom
self.page_locations.append(page_location) self.page_locations.append(page_location)
else: else:

View File

@ -11,7 +11,7 @@ from calibre.devices.kindle.apnx_page_generator.page_number_type import PageNumb
class Pages: class Pages:
def __init__(self, page_locations: Optional[List[int]] = None): def __init__(self, page_locations: Optional[List[int]] = None):
if page_locations.__class__ == list: if page_locations.__class__ is list:
self.__pages_groups: List[PageGroup] = [PageGroup(page_locations, PageNumberTypes.Arabic, 1)] self.__pages_groups: List[PageGroup] = [PageGroup(page_locations, PageNumberTypes.Arabic, 1)]
else: else:
self.__pages_groups: List[PageGroup] = [] self.__pages_groups: List[PageGroup] = []

View File

@ -673,7 +673,7 @@ class Device(DeviceConfig, DevicePlugin):
hal = get_hal() hal = get_hal()
vols = hal.get_volumes(d) vols = hal.get_volumes(d)
if verbose: if verbose:
print("FBSD: ", vols) print("FBSD:\t", vols)
ok, mv = hal.mount_volumes(vols) ok, mv = hal.mount_volumes(vols)
if not ok: if not ok:

View File

@ -106,19 +106,19 @@ class HAL:
# Mount Point becomes Mount Path # Mount Point becomes Mount Path
mp += '/' mp += '/'
if DEBUG: if DEBUG:
print("FBSD: mounted", vol['label'], "on", mp) print("FBSD:\tmounted", vol['label'], "on", mp)
if mtd == 0: if mtd == 0:
ans['_main_prefix'], ans['_main_vol'] = mp, vol['vol'] ans['_main_prefix'], ans['_main_vol'] = mp, vol['vol']
if DEBUG: if DEBUG:
print("FBSD: main = ", mp) print("FBSD:\tmain = ", mp)
elif mtd == 1: elif mtd == 1:
ans['_card_a_prefix'], ans['_card_a_vol'] = mp, vol['vol'] ans['_card_a_prefix'], ans['_card_a_vol'] = mp, vol['vol']
if DEBUG: if DEBUG:
print("FBSD: card a = ", mp) print("FBSD:\tcard a = ", mp)
elif mtd == 2: elif mtd == 2:
ans['_card_b_prefix'], ans['_card_b_vol'] = mp, vol['vol'] ans['_card_b_prefix'], ans['_card_b_vol'] = mp, vol['vol']
if DEBUG: if DEBUG:
print("FBSD: card b = ", mp) print("FBSD:\tcard b = ", mp)
break break
mtd += 1 mtd += 1

View File

@ -5,13 +5,13 @@
import re import re
from functools import partial from functools import partial
from css_selectors.select import Select, get_parsed_selector
from html5_parser import parse from html5_parser import parse
from lxml import etree from lxml import etree
from calibre.ebooks.metadata.tag_mapper import uniq from calibre.ebooks.metadata.tag_mapper import uniq
from calibre.ebooks.oeb.base import OEB_DOCS, XPath from calibre.ebooks.oeb.base import OEB_DOCS, XPath
from calibre.ebooks.oeb.parse_utils import XHTML from calibre.ebooks.oeb.parse_utils import XHTML
from css_selectors.select import Select, get_parsed_selector
def non_empty_validator(label, val): def non_empty_validator(label, val):

View File

@ -11,6 +11,8 @@ import types
from collections import defaultdict, namedtuple from collections import defaultdict, namedtuple
from itertools import chain from itertools import chain
from css_selectors import Select, SelectorError
from calibre import force_unicode, prepare_string_for_xml from calibre import force_unicode, prepare_string_for_xml
from calibre.ebooks.oeb.base import XPath, xml2text from calibre.ebooks.oeb.base import XPath, xml2text
from calibre.ebooks.oeb.polish.container import OEB_DOCS, OEB_STYLES from calibre.ebooks.oeb.polish.container import OEB_DOCS, OEB_STYLES
@ -18,7 +20,6 @@ from calibre.ebooks.oeb.polish.spell import count_all_chars, get_all_words
from calibre.ebooks.oeb.polish.utils import OEB_FONTS from calibre.ebooks.oeb.polish.utils import OEB_FONTS
from calibre.utils.icu import numeric_sort_key, safe_chr from calibre.utils.icu import numeric_sort_key, safe_chr
from calibre.utils.imghdr import identify from calibre.utils.imghdr import identify
from css_selectors import Select, SelectorError
from polyglot.builtins import iteritems from polyglot.builtins import iteritems
File = namedtuple('File', 'name dir basename size category word_count') File = namedtuple('File', 'name dir basename size category word_count')

View File

@ -5,11 +5,11 @@ from contextlib import suppress
from typing import List, NamedTuple, Optional, Tuple from typing import List, NamedTuple, Optional, Tuple
from css_parser.css import CSSRule from css_parser.css import CSSRule
from css_selectors import Select, SelectorError
from calibre.ebooks.oeb.parse_utils import barename from calibre.ebooks.oeb.parse_utils import barename
from calibre.ebooks.oeb.polish.container import get_container from calibre.ebooks.oeb.polish.container import get_container
from calibre.ebooks.oeb.polish.parsing import parse from calibre.ebooks.oeb.polish.parsing import parse
from css_selectors import Select, SelectorError
class NoMatchingTagFound(KeyError): class NoMatchingTagFound(KeyError):

View File

@ -1,5 +1,19 @@
# autogenerated by __main__.py do not edit # autogenerated by __main__.py do not edit
top_level_module_names=('QtCore', 'QtGui', 'QtWidgets', 'QtNetwork', 'QtSvg', 'QtPrintSupport', 'QtOpenGL', 'QtOpenGLWidgets', 'QtQuick', 'QtMultimedia', 'QtMultimediaWidgets', 'QtTextToSpeech', 'QtWebEngineCore', 'QtWebEngineWidgets', 'QtDBus') top_level_module_names = ('QtCore',
'QtGui',
'QtWidgets',
'QtNetwork',
'QtSvg',
'QtPrintSupport',
'QtOpenGL',
'QtOpenGLWidgets',
'QtQuick',
'QtMultimedia',
'QtMultimediaWidgets',
'QtTextToSpeech',
'QtWebEngineCore',
'QtWebEngineWidgets',
'QtDBus')
def __getattr__(name): def __getattr__(name):
@ -7,4 +21,3 @@ def __getattr__(name):
import importlib import importlib
return importlib.import_module("PyQt6." + name) return importlib.import_module("PyQt6." + name)
raise AttributeError(name) raise AttributeError(name)

View File

@ -1,5 +1,4 @@
#!/usr/bin/env python #!/usr/bin/env python
# vim:fileencoding=utf-8
# License: GPL v3 Copyright: 2021, Kovid Goyal <kovid at kovidgoyal.net> # License: GPL v3 Copyright: 2021, Kovid Goyal <kovid at kovidgoyal.net>
import importlib import importlib
@ -56,10 +55,10 @@ qt_modules = {}
def __getattr__(name): def __getattr__(name):
return dynamic_load(name, name_map, already_imported, qt_modules, module_names) return dynamic_load(name, name_map, already_imported, qt_modules, module_names)
''', file=f) ''', end='', file=f)
with open(f'{base}/{name}.pyi', 'w') as f: with open(f'{base}/{name}.pyi', 'w') as f:
print('# autogenerated by __main__.py do not edit', file=f) print('# autogenerated by __main__.py do not edit', file=f)
f.write('\n'.join(types)) print('\n'.join(types), file=f)
if name == 'core': if name == 'core':
module_names += ('sip',) module_names += ('sip',)
mod = importlib.import_module(f'{QT_WRAPPER}.sip') mod = importlib.import_module(f'{QT_WRAPPER}.sip')
@ -79,7 +78,8 @@ for name in module_lists.keys():
scan(name) scan(name)
with open(f'{base}/__init__.py', 'w') as f: with open(f'{base}/__init__.py', 'w') as f:
print('# autogenerated by __main__.py do not edit', file=f) print('# autogenerated by __main__.py do not edit', file=f)
print(f'{top_level_module_names=}', file=f) print('top_level_module_names = ', end='', file=f)
pprint(top_level_module_names, stream=f)
print(f''' print(f'''
def __getattr__(name): def __getattr__(name):
@ -87,4 +87,4 @@ def __getattr__(name):
import importlib import importlib
return importlib.import_module("{QT_WRAPPER}." + name) return importlib.import_module("{QT_WRAPPER}." + name)
raise AttributeError(name) raise AttributeError(name)
''', file=f) ''', end='', file=f)

View File

@ -1,5 +1,4 @@
#!/usr/bin/env python #!/usr/bin/env python
# vim:fileencoding=utf-8
# License: GPL v3 Copyright: 2021, Kovid Goyal <kovid at kovidgoyal.net> # License: GPL v3 Copyright: 2021, Kovid Goyal <kovid at kovidgoyal.net>
import sys import sys