add/remove blank-line (extra-edit)

ruff 'E302,E303,E304,E305,W391'
This commit is contained in:
un-pogaz 2025-01-24 11:14:21 +01:00
parent 5540126765
commit 8d28380515
307 changed files with 314 additions and 512 deletions

View File

@ -76,5 +76,3 @@ class InterfacePluginDemo(InterfaceActionBase):
ac = self.actual_plugin_ ac = self.actual_plugin_
if ac is not None: if ac is not None:
ac.apply_settings() ac.apply_settings()

View File

@ -89,5 +89,6 @@ def generate_template_language_help(language, log):
a(POSTAMBLE) a(POSTAMBLE)
return ''.join(output) return ''.join(output)
if __name__ == '__main__': if __name__ == '__main__':
generate_template_language_help() generate_template_language_help()

View File

@ -17,6 +17,7 @@ from calibre.web.feeds.news import BasicNewsRecipe
use_archive = True use_archive = True
def E(parent, name, text='', **attrs): def E(parent, name, text='', **attrs):
ans = parent.makeelement(name, **attrs) ans = parent.makeelement(name, **attrs)
ans.text = text ans.text = text
@ -341,7 +342,6 @@ class Economist(BasicNewsRecipe):
# }}} # }}}
def preprocess_raw_html(self, raw, url): def preprocess_raw_html(self, raw, url):
# open('/t/raw.html', 'wb').write(raw.encode('utf-8')) # open('/t/raw.html', 'wb').write(raw.encode('utf-8'))
if use_archive: if use_archive:

View File

@ -8,6 +8,7 @@ def absurl(url):
if url.startswith('/'): if url.startswith('/'):
return 'https://www.afr.com' + url return 'https://www.afr.com' + url
class afr(BasicNewsRecipe): class afr(BasicNewsRecipe):
title = 'Australian Financial Review' title = 'Australian Financial Review'
__author__ = 'unkn0wn' __author__ = 'unkn0wn'

View File

@ -28,4 +28,3 @@ class WwwAltomdata_dk(BasicNewsRecipe):
('Kommentarer til Alt om DATA, Datatid TechLife', 'http://www.altomdata.dk/comments/feed'), ('Kommentarer til Alt om DATA, Datatid TechLife', 'http://www.altomdata.dk/comments/feed'),
] ]

View File

@ -18,6 +18,7 @@ today = today.replace('/', '%2F')
index = 'https://epaper.andhrajyothy.com' index = 'https://epaper.andhrajyothy.com'
class andhra(BasicNewsRecipe): class andhra(BasicNewsRecipe):
title = 'ఆంధ్రజ్యోతి - ఆంధ్రప్రదేశ్' title = 'ఆంధ్రజ్యోతి - ఆంధ్రప్రదేశ్'
language = 'te' language = 'te'

View File

@ -18,6 +18,7 @@ today = today.replace('/', '%2F')
index = 'https://epaper.andhrajyothy.com' index = 'https://epaper.andhrajyothy.com'
class andhra(BasicNewsRecipe): class andhra(BasicNewsRecipe):
title = 'ఆంధ్రజ్యోతి - తెలంగాణ' title = 'ఆంధ్రజ్యోతి - తెలంగాణ'
language = 'te' language = 'te'

View File

@ -24,4 +24,3 @@ class WwwAvisen_dk(BasicNewsRecipe):
feeds = [ feeds = [
('Nyheder fra Avisen.dk', 'http://www.avisen.dk/rss.aspx'), ('Nyheder fra Avisen.dk', 'http://www.avisen.dk/rss.aspx'),
] ]

View File

@ -12,6 +12,7 @@ def class_as_string(x):
x = ' '.join(x) x = ' '.join(x)
return x return x
def class_startswith(*prefixes): def class_startswith(*prefixes):
def q(x): def q(x):
@ -24,6 +25,7 @@ def class_startswith(*prefixes):
return dict(attrs={'class': q}) return dict(attrs={'class': q})
def absolutize_url(url): def absolutize_url(url):
if url.startswith('//'): if url.startswith('//'):
return 'https:' + url return 'https:' + url

View File

@ -15,6 +15,7 @@ def absurl(x):
x = 'https://caravanmagazine.in' + x x = 'https://caravanmagazine.in' + x
return x return x
def safe_dict(data, *names): def safe_dict(data, *names):
ans = data ans = data
for x in names: for x in names:
@ -49,6 +50,7 @@ def parse_body(x):
yield from parse_body(p) yield from parse_body(p)
yield '</p>' yield '</p>'
def parse_p(p): def parse_p(p):
if p.get('type', '') == 'text': if p.get('type', '') == 'text':
if 'marks' in p: if 'marks' in p:

View File

@ -67,7 +67,6 @@ class ChicagoTribune(BasicNewsRecipe):
feeds.append({'title': title, 'url': url}) feeds.append({'title': title, 'url': url})
return [('Articles', feeds)] return [('Articles', feeds)]
def preprocess_html(self, soup): def preprocess_html(self, soup):
for img in soup.findAll('img', attrs={'data-src': True}): for img in soup.findAll('img', attrs={'data-src': True}):
img['src'] = img['data-src'] img['src'] = img['data-src']

View File

@ -51,4 +51,3 @@ class WwwComputerworld_dk(BasicNewsRecipe):
('IDG Kurser', 'http://job.idgkurser.dk/rss/'), ('IDG Kurser', 'http://job.idgkurser.dk/rss/'),
] ]

View File

@ -5,6 +5,7 @@ def absurl(url):
if url.startswith('/'): if url.startswith('/'):
return 'https://www.deccanherald.com' + url return 'https://www.deccanherald.com' + url
class herald(BasicNewsRecipe): class herald(BasicNewsRecipe):
title = 'Deccan Herald' title = 'Deccan Herald'
__author__ = 'unkn0wn' __author__ = 'unkn0wn'

View File

@ -54,7 +54,6 @@ class DeutscheWelle_es(BasicNewsRecipe):
('Conozca Alemania', 'http://rss.dw-world.de/rdf/rss-sp-con') ('Conozca Alemania', 'http://rss.dw-world.de/rdf/rss-sp-con')
] ]
def preprocess_html(self, soup): def preprocess_html(self, soup):
for img in soup.findAll('img', srcset=True): for img in soup.findAll('img', srcset=True):
img['src'] = img['srcset'].split()[6] img['src'] = img['srcset'].split()[6]

View File

@ -59,4 +59,3 @@ class DeutscheWelle_sr(BasicNewsRecipe):
(u'Nauka Tehnika Medicina', u'http://rss.dw-world.de/rdf/rss-ser-science'), (u'Nauka Tehnika Medicina', u'http://rss.dw-world.de/rdf/rss-ser-science'),
(u'Kultura', u'feed:http://rss.dw-world.de/rdf/rss-ser-cul') (u'Kultura', u'feed:http://rss.dw-world.de/rdf/rss-ser-cul')
] ]

View File

@ -14,6 +14,7 @@ Fetch Deutschlandfunk & Deutschlandfunk Kultur
## Version:1.6 ## Version:1.6
## New RSS source: https://www.deutschlandfunk.de/rss-angebot-102.html ## New RSS source: https://www.deutschlandfunk.de/rss-angebot-102.html
class AdvancedUserRecipe1432200863(BasicNewsRecipe): class AdvancedUserRecipe1432200863(BasicNewsRecipe):
title = 'Deutschlandfunk & Deutschlandfunk Kultur' title = 'Deutschlandfunk & Deutschlandfunk Kultur'
@ -34,8 +35,6 @@ class AdvancedUserRecipe1432200863(BasicNewsRecipe):
.b-image-figure, .caption-figure.is-left, .b-image-credits {font-size: .75em; font-weight: normal;margin-bottom: .75em} .b-image-figure, .caption-figure.is-left, .b-image-credits {font-size: .75em; font-weight: normal;margin-bottom: .75em}
''' '''
feeds = [ feeds = [
('DLF Nachrichten', 'https://www.deutschlandfunk.de/nachrichten-100.rss'), ('DLF Nachrichten', 'https://www.deutschlandfunk.de/nachrichten-100.rss'),
('DLF Politikportal', 'https://www.deutschlandfunk.de/politikportal-100.rss'), ('DLF Politikportal', 'https://www.deutschlandfunk.de/politikportal-100.rss'),

View File

@ -104,7 +104,6 @@ class DRNyheder(BasicNewsRecipe):
cover_url = cover_item['src'] cover_url = cover_item['src']
return cover_url return cover_url
keep_only_tags = [ keep_only_tags = [
dict(name='h1', attrs={'class': 'dre-article-title__heading'}), # Title dict(name='h1', attrs={'class': 'dre-article-title__heading'}), # Title

View File

@ -242,7 +242,6 @@ class Espresso(BasicNewsRecipe):
raw = etree.tostring(root, encoding='unicode') raw = etree.tostring(root, encoding='unicode')
return raw return raw
def eco_find_image_tables(self, soup): def eco_find_image_tables(self, soup):
for x in soup.findAll('table', align=['right', 'center']): for x in soup.findAll('table', align=['right', 'center']):
if len(x.findAll('font')) in (1, 2) and len(x.findAll('img')) == 1: if len(x.findAll('font')) in (1, 2) and len(x.findAll('img')) == 1:

View File

@ -78,6 +78,7 @@ def load_article_from_json(raw):
body += process_node(node) body += process_node(node)
return '<html><body><article>' + body + '</article></body></html>' return '<html><body><article>' + body + '</article></body></html>'
def cleanup_html_article(root): def cleanup_html_article(root):
main = root.xpath('//main')[0] main = root.xpath('//main')[0]
body = root.xpath('//body')[0] body = root.xpath('//body')[0]
@ -91,17 +92,20 @@ def cleanup_html_article(root):
for x in root.xpath('//button'): for x in root.xpath('//button'):
x.getparent().remove(x) x.getparent().remove(x)
def classes(classes): def classes(classes):
q = frozenset(classes.split(' ')) q = frozenset(classes.split(' '))
return dict(attrs={ return dict(attrs={
'class': lambda x: x and frozenset(x.split()).intersection(q)}) 'class': lambda x: x and frozenset(x.split()).intersection(q)})
def new_tag(soup, name, attrs=()): def new_tag(soup, name, attrs=()):
impl = getattr(soup, 'new_tag', None) impl = getattr(soup, 'new_tag', None)
if impl is not None: if impl is not None:
return impl(name, attrs=dict(attrs)) return impl(name, attrs=dict(attrs))
return Tag(soup, name, attrs=attrs or None) return Tag(soup, name, attrs=attrs or None)
def process_url(url): def process_url(url):
if url.startswith('/'): if url.startswith('/'):
url = 'https://www.economist.com' + url url = 'https://www.economist.com' + url

View File

@ -33,7 +33,6 @@ class Esensja(BasicNewsRecipe):
dict(attrs={'class': ['tekst_koniec', 'ref', 'wykop']}), dict(attrs={'class': ['tekst_koniec', 'ref', 'wykop']}),
dict(attrs={'itemprop': ['copyrightHolder', 'publisher']}), dict(attrs={'itemprop': ['copyrightHolder', 'publisher']}),
dict(id='komentarze') dict(id='komentarze')
] ]
extra_css = ''' extra_css = '''

View File

@ -18,7 +18,6 @@ def format_tickaroo_liveblog(soup):
for div in soup.findAll('div', attrs={'class':'tik4-content-block tik4-content-block--rich-text tik4-content-block--position-2'}): for div in soup.findAll('div', attrs={'class':'tik4-content-block tik4-content-block--rich-text tik4-content-block--position-2'}):
div.insert_before(soup.new_tag('br')) div.insert_before(soup.new_tag('br'))
#format liveblogs #format liveblogs
for tag in soup.findAll('time'): for tag in soup.findAll('time'):
ntag = soup.new_tag('br') ntag = soup.new_tag('br')
@ -33,6 +32,7 @@ def format_tickaroo_liveblog(soup):
if ntag and temp: if ntag and temp:
ntag.insert_after(temp) ntag.insert_after(temp)
# process run of images # process run of images
def bilderstrecke(soup,tag): def bilderstrecke(soup,tag):
flag = False flag = False
@ -76,10 +76,10 @@ def bilderstrecke(soup,tag):
collect.append(fig) collect.append(fig)
soup.find(class_='header-teaser').insert_after(collect) soup.find(class_='header-teaser').insert_after(collect)
for tag in soup.findAll(class_='header-teaser__image--default'): for tag in soup.findAll(class_='header-teaser__image--default'):
tag.extract() tag.extract()
def story(soup,tag): def story(soup,tag):
first_image = soup.find('img',attrs={'loading':'lazy'}) first_image = soup.find('img',attrs={'loading':'lazy'})
first_caption = soup.find('figcaption',attrs={'class':'caption'}) first_caption = soup.find('figcaption',attrs={'class':'caption'})
@ -136,7 +136,6 @@ class FazNet(BasicNewsRecipe):
dict(name = 'script', attrs = {'id':'__NUXT_DATA__'}), dict(name = 'script', attrs = {'id':'__NUXT_DATA__'}),
] ]
remove_tags = [ remove_tags = [
dict(name='div', attrs={'class':[ dict(name='div', attrs={'class':[
'related-articles','consent-placeholder', 'related-articles','consent-placeholder',
@ -153,7 +152,6 @@ class FazNet(BasicNewsRecipe):
remove_attributes = ['onclick'] remove_attributes = ['onclick']
test_article = False test_article = False
if not test_article: if not test_article:
feeds = [ feeds = [

View File

@ -7,6 +7,7 @@ from calibre.web.feeds.news import BasicNewsRecipe, classes
index = 'https://www.globaltimes.cn/' index = 'https://www.globaltimes.cn/'
class GlobalTimes(BasicNewsRecipe): class GlobalTimes(BasicNewsRecipe):
title = 'Global Times' title = 'Global Times'
__author__ = 'unkn0wn' __author__ = 'unkn0wn'

View File

@ -5,10 +5,12 @@ from calibre.web.feeds.news import BasicNewsRecipe, classes
Hamilton Spectator Calibre Recipe Hamilton Spectator Calibre Recipe
''' '''
def absurl(url): def absurl(url):
if url.startswith('/'): if url.startswith('/'):
return 'https://www.thespec.com' + url return 'https://www.thespec.com' + url
class HamiltonSpectator(BasicNewsRecipe): class HamiltonSpectator(BasicNewsRecipe):
title = u'Hamilton Spectator' title = u'Hamilton Spectator'
max_articles_per_feed = 50 max_articles_per_feed = 50

View File

@ -17,6 +17,7 @@ def get_story(story):
for x in story['story-elements']: for x in story['story-elements']:
yield from get_story(x) yield from get_story(x)
def img(img): def img(img):
yield '<p>' yield '<p>'
if 'image-s3-key' in img: if 'image-s3-key' in img:
@ -25,6 +26,7 @@ def img(img):
yield '<div class="cap">' + img['title'] + '</div>' yield '<div class="cap">' + img['title'] + '</div>'
yield '</p>' yield '</p>'
class himal(BasicNewsRecipe): class himal(BasicNewsRecipe):
title = 'Himal Southasian' title = 'Himal Southasian'
__author__ = 'unkn0wn' __author__ = 'unkn0wn'

View File

@ -74,7 +74,6 @@ class TheHindufeeds(BasicNewsRecipe):
src.extract() src.extract()
return soup return soup
def get_cover_url(self): def get_cover_url(self):
soup = self.index_to_soup('https://www.thehindu.com/todays-paper/') soup = self.index_to_soup('https://www.thehindu.com/todays-paper/')
if cover := soup.find(attrs={'class':'hindu-ad'}): if cover := soup.find(attrs={'class':'hindu-ad'}):

View File

@ -8,6 +8,7 @@ from calibre.web.feeds.news import BasicNewsRecipe
index = 'https://epaper.hindustantimes.com' index = 'https://epaper.hindustantimes.com'
class ht(BasicNewsRecipe): class ht(BasicNewsRecipe):
title = 'Hindustan Times Print Edition' title = 'Hindustan Times Print Edition'
language = 'en_IN' language = 'en_IN'
@ -100,7 +101,6 @@ class ht(BasicNewsRecipe):
feeds_dict[section].append({'title': title, 'description': desc, 'url': url}) feeds_dict[section].append({'title': title, 'description': desc, 'url': url})
return list(feeds_dict.items()) return list(feeds_dict.items())
def preprocess_raw_html(self, raw, *a): def preprocess_raw_html(self, raw, *a):
data = json.loads(raw) data = json.loads(raw)
body = '' body = ''

View File

@ -64,4 +64,3 @@ class Hurriyet(BasicNewsRecipe):
(u'Ankara', 'https://www.hurriyet.com.tr/rss/ankara'), (u'Ankara', 'https://www.hurriyet.com.tr/rss/ankara'),
(u'Ege', 'https://www.hurriyet.com.tr/rss/ege') (u'Ege', 'https://www.hurriyet.com.tr/rss/ege')
] ]

View File

@ -8,6 +8,7 @@ def absurl(url):
if url.startswith('/'): if url.startswith('/'):
return 'https://www.infzm.com' + url return 'https://www.infzm.com' + url
def json_to_html(raw, link): def json_to_html(raw, link):
data = json.loads(raw) data = json.loads(raw)
data = data['data']['content'] data = data['data']['content']
@ -51,7 +52,6 @@ class infzm(BasicNewsRecipe):
.cm_pic_caption, .cm_pic_author { font-size:small; text-align:center; } .cm_pic_caption, .cm_pic_author { font-size:small; text-align:center; }
''' '''
def parse_index(self): def parse_index(self):
index = 'https://www.infzm.com/' index = 'https://www.infzm.com/'
sections = [ sections = [

View File

@ -47,7 +47,6 @@ class inc42(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', attrs={'data-src':True}): for img in soup.findAll('img', attrs={'data-src':True}):
img['src'] = img['data-src'] img['src'] = img['data-src']

View File

@ -20,4 +20,3 @@ class IndiaSpeaksReddit(BasicNewsRecipe):
feeds = [ feeds = [
('India Speaks Reddit main feed', 'https://www.reddit.com/r/IndiaSpeaks.rss'), ('India Speaks Reddit main feed', 'https://www.reddit.com/r/IndiaSpeaks.rss'),
] ]

View File

@ -17,4 +17,3 @@ class Kosmonauta(BasicNewsRecipe):
remove_attributes = ['style'] remove_attributes = ['style']
max_articles_per_feed = 100 max_articles_per_feed = 100
feeds = [(u'Kosmonauta.net', u'http://www.kosmonauta.net/feed')] feeds = [(u'Kosmonauta.net', u'http://www.kosmonauta.net/feed')]

View File

@ -21,12 +21,14 @@ def resize(x):
if '_750' in k: if '_750' in k:
return v return v
m_fr = { m_fr = {
1: 'Janvier', 2: 'Février', 3: 'Mars', 4: 'Avril', 1: 'Janvier', 2: 'Février', 3: 'Mars', 4: 'Avril',
5: 'Mai', 6: 'Juin', 7: 'Juillet', 8: 'Août', 5: 'Mai', 6: 'Juin', 7: 'Juillet', 8: 'Août',
9: 'Septembre', 10: 'Octobre', 11: 'Novembre', 12: 'Décembre' 9: 'Septembre', 10: 'Octobre', 11: 'Novembre', 12: 'Décembre'
} }
def json_to_html(raw): def json_to_html(raw):
data = json.loads(raw) data = json.loads(raw)

View File

@ -6,6 +6,7 @@ def absurl(url):
if url.startswith('/'): if url.startswith('/'):
return 'https://www.livelaw.in' + url return 'https://www.livelaw.in' + url
class livelaw(BasicNewsRecipe): class livelaw(BasicNewsRecipe):
title = 'Live Law' title = 'Live Law'
__author__ = 'unkn0wn' __author__ = 'unkn0wn'

View File

@ -14,6 +14,7 @@ def absurl(x):
x = 'https://www.newyorker.com' + x x = 'https://www.newyorker.com' + x
return x return x
class NewYorker(BasicNewsRecipe): class NewYorker(BasicNewsRecipe):
title = 'The New Yorker Magazine' title = 'The New Yorker Magazine'
@ -129,7 +130,6 @@ class NewYorker(BasicNewsRecipe):
feeds_dict[section].append({'title': title, 'url': url, 'description': desc}) feeds_dict[section].append({'title': title, 'url': url, 'description': desc})
return feeds_dict.items() return feeds_dict.items()
# The New Yorker changes the content it delivers based on cookies, so the # The New Yorker changes the content it delivers based on cookies, so the
# following ensures that we send no cookies # following ensures that we send no cookies
def get_browser(self, *args, **kwargs): def get_browser(self, *args, **kwargs):

View File

@ -36,4 +36,3 @@ class ReutersJa(BasicNewsRecipe):
for img in soup.findAll('img', attrs={'data-src':True}): for img in soup.findAll('img', attrs={'data-src':True}):
img['src'] = img['data-src'] img['src'] = img['data-src']
return soup return soup

View File

@ -38,4 +38,3 @@ class Nordjyske_dk(BasicNewsRecipe):
('Aalborg', 'http://nordjyske.dk/rss/aalborg'), ('Aalborg', 'http://nordjyske.dk/rss/aalborg'),
] ]

View File

@ -97,7 +97,6 @@ class Nzz(BasicNewsRecipe):
return url return url
def get_browser(self, *args, **kwargs): def get_browser(self, *args, **kwargs):
kwargs['user_agent'] = 'Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)' kwargs['user_agent'] = 'Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)'
br = BasicNewsRecipe.get_browser(self, *args, **kwargs) br = BasicNewsRecipe.get_browser(self, *args, **kwargs)

View File

@ -18,4 +18,3 @@ class PajamasMedia(BasicNewsRecipe):
'http://feeds.feedburner.com/PajamasMedia'), 'http://feeds.feedburner.com/PajamasMedia'),
] ]

View File

@ -24,6 +24,7 @@ def classes(classes):
return dict(attrs={ return dict(attrs={
'class': lambda x: x and frozenset(x.split()).intersection(q)}) 'class': lambda x: x and frozenset(x.split()).intersection(q)})
class RadioCanada(BasicNewsRecipe): class RadioCanada(BasicNewsRecipe):
title = 'Radio Canada' title = 'Radio Canada'
__author__ = 'quatorze, pticrix' __author__ = 'quatorze, pticrix'

View File

@ -79,7 +79,6 @@ class RND(BasicNewsRecipe):
#('E-Mobility', 'https://www.rnd.de/arc/outboundfeeds/rss/category/e-mobility/') #('E-Mobility', 'https://www.rnd.de/arc/outboundfeeds/rss/category/e-mobility/')
] ]
def parse_feeds(self): def parse_feeds(self):
# Call parent's method. # Call parent's method.
feeds = BasicNewsRecipe.parse_feeds(self) feeds = BasicNewsRecipe.parse_feeds(self)

View File

@ -193,7 +193,6 @@ class Saechsische(BasicNewsRecipe):
#('Beruf & Bildung', 'https://www.saechsische.de/arc/outboundfeeds/rss/category/beruf-und-bildung') #('Beruf & Bildung', 'https://www.saechsische.de/arc/outboundfeeds/rss/category/beruf-und-bildung')
] ]
def parse_feeds(self): def parse_feeds(self):
# Call parent's method. # Call parent's method.
feeds = BasicNewsRecipe.parse_feeds(self) feeds = BasicNewsRecipe.parse_feeds(self)

View File

@ -10,6 +10,7 @@ def classes(classes):
return dict(attrs={ return dict(attrs={
'class': lambda x: x and frozenset(x.split()).intersection(q)}) 'class': lambda x: x and frozenset(x.split()).intersection(q)})
class Salon_com(BasicNewsRecipe): class Salon_com(BasicNewsRecipe):
title = 'Salon.com' title = 'Salon.com'

View File

@ -20,6 +20,7 @@ def E(parent, name, text='', **attrs):
parent.append(ans) parent.append(ans)
return ans return ans
def process_node(node, html_parent): def process_node(node, html_parent):
ntype = node.get('type') ntype = node.get('type')
@ -45,6 +46,7 @@ def ts_date(x):
dt = datetime.fromtimestamp(x/1000 + time.timezone) dt = datetime.fromtimestamp(x/1000 + time.timezone)
return dt.strftime('%b %d, %Y at %I:%M %p') return dt.strftime('%b %d, %Y at %I:%M %p')
def load_article_from_json(raw, root): def load_article_from_json(raw, root):
# open('/t/raw.json', 'w').write(raw) # open('/t/raw.json', 'w').write(raw)
data = json.loads(raw)['props']['pageProps']['payload']['data']['article'] data = json.loads(raw)['props']['pageProps']['payload']['data']['article']

View File

@ -25,5 +25,4 @@ class Ria_eng(BasicNewsRecipe):
'comment': description, 'tags': category, 'language': language 'comment': description, 'tags': category, 'language': language
} }
feeds = [(u'News', u'https://sputnikglobe.com/export/rss2/archive/index.xml')] feeds = [(u'News', u'https://sputnikglobe.com/export/rss2/archive/index.xml')]

View File

@ -70,4 +70,3 @@ class TagesspiegelRss(BasicNewsRecipe):
(u'Medien', u'http://www.tagesspiegel.de/contentexport/feed/medien'), (u'Medien', u'http://www.tagesspiegel.de/contentexport/feed/medien'),
(u'Wissen', u'http://www.tagesspiegel.de/contentexport/feed/wissen') (u'Wissen', u'http://www.tagesspiegel.de/contentexport/feed/wissen')
] ]

View File

@ -27,7 +27,6 @@ class Tehelka(BasicNewsRecipe):
use_embedded_content = False use_embedded_content = False
ignore_duplicate_articles = {'title', 'url'} ignore_duplicate_articles = {'title', 'url'}
feeds = [ feeds = [
('Tehelka', 'http://tehelka.com/rss'), ('Tehelka', 'http://tehelka.com/rss'),
] ]

View File

@ -35,7 +35,6 @@ class SaturdayPaper(BasicNewsRecipe):
{'name': 'div', 'class': 'end-matter'}, {'name': 'div', 'class': 'end-matter'},
] ]
def get_cover_url(self): def get_cover_url(self):
soup = self.index_to_soup('https://www.thesaturdaypaper.com.au/editions/') soup = self.index_to_soup('https://www.thesaturdaypaper.com.au/editions/')
div = soup.find('div', attrs={'class':'article__image'}) div = soup.find('div', attrs={'class':'article__image'})

View File

@ -196,7 +196,6 @@ class PrivateEyeRecipe(BasicNewsRecipe):
return soup return soup
# Remove features not wanted and tweak HTML # Remove features not wanted and tweak HTML
preprocess_regexps = [ preprocess_regexps = [
# Remove big blank spaces # Remove big blank spaces

View File

@ -11,11 +11,13 @@ def resize(x):
elif '?crop=' in x: elif '?crop=' in x:
return x + '&resize=600' return x + '&resize=600'
def absurl(url): def absurl(url):
if url.startswith('/'): if url.startswith('/'):
url = 'https://www.thetimes.com' + url url = 'https://www.thetimes.com' + url
return url return url
class times(BasicNewsRecipe): class times(BasicNewsRecipe):
title = 'The Times and Sunday Times' title = 'The Times and Sunday Times'
__author__ = 'unkn0wn' __author__ = 'unkn0wn'

View File

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

View File

@ -23,6 +23,7 @@ date_ = dt.strftime('%d_%m_%Y')
index = 'https://asset.harnscloud.com/PublicationData/TOI/' + le + '/' + date0 index = 'https://asset.harnscloud.com/PublicationData/TOI/' + le + '/' + date0
img_index = 'https://cmsimages.timesgroup.com/image-resizer?epaper_s3_path=PublicationData/TOI/' + le + '/' + date0 img_index = 'https://cmsimages.timesgroup.com/image-resizer?epaper_s3_path=PublicationData/TOI/' + le + '/' + date0
def handle_images(x, soup): def handle_images(x, soup):
img = soup.find('img') img = soup.find('img')
if img: if img:
@ -36,6 +37,7 @@ def handle_images(x, soup):
for lead in reversed(soup.findAll('div', attrs={'class':'lead'})): for lead in reversed(soup.findAll('div', attrs={'class':'lead'})):
x.insert_after(lead) x.insert_after(lead)
class toiprint(BasicNewsRecipe): class toiprint(BasicNewsRecipe):
title = 'TOI Print Edition' title = 'TOI Print Edition'
language = 'en_IN' language = 'en_IN'

View File

@ -14,10 +14,12 @@ def classes(classes):
return dict(attrs={ return dict(attrs={
'class': lambda x: x and frozenset(x.split()).intersection(q)}) 'class': lambda x: x and frozenset(x.split()).intersection(q)})
def absurl(url): def absurl(url):
if url.startswith('/'): if url.startswith('/'):
return 'https://www.usatoday.com' + url return 'https://www.usatoday.com' + url
class USAToday(BasicNewsRecipe): class USAToday(BasicNewsRecipe):
title = 'USA Today' title = 'USA Today'

View File

@ -28,6 +28,7 @@ except ImportError:
needs_subscription = False needs_subscription = False
class WSJ(BasicNewsRecipe): class WSJ(BasicNewsRecipe):
if needs_subscription: if needs_subscription:

View File

@ -36,6 +36,7 @@ select = [
'RUF055', # unnecessary regex 'RUF055', # unnecessary regex
'RUF039', # always use raw-string for regex 'RUF039', # always use raw-string for regex
'RUF047', # needless else 'RUF047', # needless else
'E302', 'E303', 'E304', 'E305', 'W391', # blank-line standard
] ]
[lint.per-file-ignores] [lint.per-file-ignores]
@ -49,7 +50,7 @@ select = [
"src/calibre/gui2/tts/manager.py" = ['UP037'] "src/calibre/gui2/tts/manager.py" = ['UP037']
"src/calibre/utils/copy_files.py" = ['UP037'] "src/calibre/utils/copy_files.py" = ['UP037']
"src/calibre/utils/smartypants.py" = ['RUF039', 'RUF055'] "src/calibre/utils/smartypants.py" = ['RUF039', 'RUF055']
"src/qt/*.py" = ['I'] "src/qt/*.py" = ['I', 'E302']
"src/qt/*.pyi" = ['I'] "src/qt/*.pyi" = ['I']
[lint.isort] [lint.isort]

View File

@ -29,7 +29,6 @@ def check_version_info():
exit(f'calibre requires Python {minver}. Current Python version: {".".join(map(str, sys.version_info[:3]))}') exit(f'calibre requires Python {minver}. Current Python version: {".".join(map(str, sys.version_info[:3]))}')
check_version_info() check_version_info()
sys.path.insert(0, src_base) sys.path.insert(0, src_base)

View File

@ -23,6 +23,7 @@ isunix = islinux or ismacos or isbsd or ishaiku
py_lib = os.path.join(sys.prefix, 'libs', 'python{}{}.lib'.format(*sys.version_info[:2])) py_lib = os.path.join(sys.prefix, 'libs', 'python{}{}.lib'.format(*sys.version_info[:2]))
class CompileCommand(NamedTuple): class CompileCommand(NamedTuple):
cmd: list[str] cmd: list[str]
src: str src: str
@ -145,7 +146,6 @@ def parse_extension(ext, compiling_for='native'):
if compiling_for == 'windows': if compiling_for == 'windows':
get_key = 'windows_' get_key = 'windows_'
def get(k, default=''): def get(k, default=''):
ans = ext.pop(k, default) ans = ext.pop(k, default)
ans = ext.pop(get_key + k, ans) ans = ext.pop(get_key + k, ans)
@ -242,7 +242,6 @@ class Environment(NamedTuple):
return list(map(map_name, libs)) return list(map(map_name, libs))
def init_env(debug=False, sanitize=False, compiling_for='native'): def init_env(debug=False, sanitize=False, compiling_for='native'):
from setup.build_environment import NMAKE, win_cc, win_inc, win_ld, win_lib from setup.build_environment import NMAKE, win_cc, win_inc, win_ld, win_lib
linker = None linker = None

View File

@ -10,6 +10,7 @@ import subprocess
BASE = '/srv/download/bw' BASE = '/srv/download/bw'
def main(): def main():
if not os.path.exists(BASE): if not os.path.exists(BASE):
os.makedirs(BASE) os.makedirs(BASE)
@ -52,5 +53,6 @@ def main():
with open('index.html', 'wb') as f: with open('index.html', 'wb') as f:
f.write(html.encode('utf-8')) f.write(html.encode('utf-8'))
if __name__ == '__main__': if __name__ == '__main__':
main() main()

View File

@ -69,7 +69,6 @@ class ReadFileWithProgressReporting: # {{{
) )
sys.stdout.flush() sys.stdout.flush()
# }}} # }}}
@ -93,7 +92,6 @@ class Base: # {{{
print('_' * 50) print('_' * 50)
sys.stdout.flush() sys.stdout.flush()
# }}} # }}}
@ -127,7 +125,6 @@ class SourceForge(Base): # {{{
break break
print('Uploaded in', int(time.time() - start), 'seconds\n\n') print('Uploaded in', int(time.time() - start), 'seconds\n\n')
# }}} # }}}
@ -259,7 +256,6 @@ class GitHub(Base): # {{{
self.fail(r, f'Failed to create release for version: {self.version}') self.fail(r, f'Failed to create release for version: {self.version}')
return r.json() return r.json()
# }}} # }}}
@ -388,10 +384,9 @@ def generate_index(): # {{{
f.write(index.encode('utf-8')) f.write(index.encode('utf-8'))
finally: finally:
os.chdir('..') os.chdir('..')
# }}} # }}}
SERVER_BASE = '/srv/download/' SERVER_BASE = '/srv/download/'
@ -432,9 +427,6 @@ def upload_to_servers(files, version): # {{{
# else: # else:
# break # break
# print('Uploaded in', int(time.time() - start), 'seconds\n\n') # print('Uploaded in', int(time.time() - start), 'seconds\n\n')
#
# }}} # }}}

View File

@ -25,6 +25,7 @@ def generate_data():
ans.append((x, nl(getattr(locale, x.upper())))) ans.append((x, nl(getattr(locale, x.upper()))))
return ans return ans
def main(): def main():
if sys.version_info[0] < 3: # noqa: UP036 if sys.version_info[0] < 3: # noqa: UP036
raise RuntimeError('Must be run using python 3.x') raise RuntimeError('Must be run using python 3.x')

View File

@ -1,7 +1,6 @@
#!/usr/bin/env python #!/usr/bin/env python
# License: GPLv3 Copyright: 2013, Kovid Goyal <kovid at kovidgoyal.net> # License: GPLv3 Copyright: 2013, Kovid Goyal <kovid at kovidgoyal.net>
# Imports {{{ # Imports {{{
import argparse import argparse
import ast import ast
@ -151,8 +150,8 @@ def load_plugins_index():
raise raise
return json.loads(bz2.decompress(raw)) return json.loads(bz2.decompress(raw))
# Get metadata from plugin zip file {{{
# Get metadata from plugin zip file {{{
def convert_node(fields, x, names={}, import_data=None): def convert_node(fields, x, names={}, import_data=None):
name = x.__class__.__name__ name = x.__class__.__name__
@ -357,9 +356,9 @@ def get_plugin_info(raw_zip):
return json.loads(res.stdout) return json.loads(res.stdout)
raise raise
# }}} # }}}
def update_plugin_from_entry(plugin, entry): def update_plugin_from_entry(plugin, entry):
plugin['index_name'] = entry.name plugin['index_name'] = entry.name
plugin['thread_url'] = entry.url plugin['thread_url'] = entry.url
@ -706,7 +705,6 @@ def test_parse(): # {{{
if new_url != full_url: if new_url != full_url:
print(f'new url ({aname}): {new_url} != {full_url} for plugin at: {url}') print(f'new url ({aname}): {new_url} != {full_url} for plugin at: {url}')
raise SystemExit(1) raise SystemExit(1)
# }}} # }}}
@ -740,7 +738,6 @@ class HelloWorld(FileTypePlugin):
zf.writestr('very/ver.py', b'MV = (0, 7, 53)') zf.writestr('very/ver.py', b'MV = (0, 7, 53)')
zf.writestr('__init__.py', b'from xxx import yyy\nfrom very.lovely import HelloWorld') zf.writestr('__init__.py', b'from xxx import yyy\nfrom very.lovely import HelloWorld')
assert get_plugin_info(buf.getvalue()) == vals assert get_plugin_info(buf.getvalue()) == vals
# }}} # }}}

View File

@ -65,7 +65,6 @@ class Test(BaseTest):
ffmpeg_dll_dir = os.path.join(SW, 'ffmpeg', 'bin') ffmpeg_dll_dir = os.path.join(SW, 'ffmpeg', 'bin')
os.add_dll_directory(ffmpeg_dll_dir) os.add_dll_directory(ffmpeg_dll_dir)
from calibre.utils.run_tests import filter_tests_by_name, find_tests, remove_tests_by_name, run_cli from calibre.utils.run_tests import filter_tests_by_name, find_tests, remove_tests_by_name, run_cli
tests = find_tests(which_tests=frozenset(opts.test_module), exclude_tests=frozenset(opts.exclude_test_module)) tests = find_tests(which_tests=frozenset(opts.test_module), exclude_tests=frozenset(opts.exclude_test_module))
if opts.test_name: if opts.test_name:

View File

@ -607,7 +607,6 @@ class Translations(POT): # {{{
if os.path.exists(destbase): if os.path.exists(destbase):
shutil.rmtree(destbase) shutil.rmtree(destbase)
shutil.rmtree(self.cache_dir) shutil.rmtree(self.cache_dir)
# }}} # }}}
@ -756,7 +755,6 @@ class GetTranslations(Translations): # {{{
cc('git add */*.po'.split()) cc('git add */*.po'.split())
cc('git commit -am'.split() + [msg or 'Updated translations']) cc('git commit -am'.split() + [msg or 'Updated translations'])
cc('git push'.split()) cc('git push'.split())
# }}} # }}}
@ -817,7 +815,6 @@ class ISO639(Command): # {{{
def clean(self): def clean(self):
if os.path.exists(self.DEST): if os.path.exists(self.DEST):
os.remove(self.DEST) os.remove(self.DEST)
# }}} # }}}

View File

@ -98,7 +98,6 @@ class ReUpload(Command): # {{{
if os.path.exists(x): if os.path.exists(x):
os.remove(x) os.remove(x)
# }}} # }}}
@ -159,7 +158,6 @@ def run_remote_upload(args):
'python', 'hosting.py' 'python', 'hosting.py'
] + args) ] + args)
# }}} # }}}
@ -313,7 +311,6 @@ class UploadInstallers(Command): # {{{
def upload_to_calibre(self): def upload_to_calibre(self):
run_remote_upload(calibre_cmdline(__version__)) run_remote_upload(calibre_cmdline(__version__))
# }}} # }}}
@ -355,7 +352,6 @@ class UploadUserManual(Command): # {{{
) )
check_call('ssh main chown -R http:http /srv/manual'.split()) check_call('ssh main chown -R http:http /srv/manual'.split())
# }}} # }}}
@ -382,7 +378,6 @@ class UploadDemo(Command): # {{{
check_call(f'scp /tmp/html-demo.zip main:{DOWNLOADS}/', shell=True) check_call(f'scp /tmp/html-demo.zip main:{DOWNLOADS}/', shell=True)
# }}} # }}}
@ -410,5 +405,4 @@ class UploadToServer(Command): # {{{
f'ssh main /usr/local/bin/update-calibre-version.py {__version__} && /usr/local/bin/update-calibre-code.py && /apps/static/generate.py' f'ssh main /usr/local/bin/update-calibre-version.py {__version__} && /usr/local/bin/update-calibre-code.py && /apps/static/generate.py'
).split()) ).split())
# }}} # }}}

View File

@ -128,7 +128,6 @@ def query_vcvarsall(is64bit=True):
comn_tools[k] = int(m.group(1)) comn_tools[k] = int(m.group(1))
comntools = sorted(comn_tools, key=comn_tools.__getitem__)[-1] comntools = sorted(comn_tools, key=comn_tools.__getitem__)[-1]
def g(k): def g(k):
try: try:
return env[k] return env[k]

View File

@ -176,6 +176,7 @@ def download_item(dest_dir: str, file: File):
raise SystemExit(f'The hash for {file.filename} does not match.' raise SystemExit(f'The hash for {file.filename} does not match.'
f' {m.hexdigest()} != {file.sha256}') f' {m.hexdigest()} != {file.sha256}')
def cabinets_in_msi(path): def cabinets_in_msi(path):
raw = subprocess.check_output(['msiinfo', 'export', path, 'Media']).decode('utf-8') raw = subprocess.check_output(['msiinfo', 'export', path, 'Media']).decode('utf-8')
return re.findall(r'\S+\.cab', raw) return re.findall(r'\S+\.cab', raw)

View File

@ -450,6 +450,7 @@ def my_unichr(num):
except (ValueError, OverflowError): except (ValueError, OverflowError):
return '?' return '?'
XML_ENTITIES = { XML_ENTITIES = {
'"' : '&quot;', '"' : '&quot;',
"'" : '&apos;', "'" : '&apos;',
@ -458,6 +459,7 @@ XML_ENTITIES = {
'&' : '&amp;' '&' : '&amp;'
} }
def entity_to_unicode(match, exceptions=(), encoding=None, result_exceptions={}): def entity_to_unicode(match, exceptions=(), encoding=None, result_exceptions={}):
''' '''
:param match: A match object such that '&'+match.group(1)';' is the entity. :param match: A match object such that '&'+match.group(1)';' is the entity.

View File

@ -410,7 +410,6 @@ else:
atexit.register(cleanup_cdir) atexit.register(cleanup_cdir)
# }}} # }}}
is_running_from_develop = False is_running_from_develop = False
if getattr(sys, 'frozen', False): if getattr(sys, 'frozen', False):
try: try:

View File

@ -475,6 +475,7 @@ class MetadataReaderPlugin(Plugin): # {{{
:return: A :class:`calibre.ebooks.metadata.book.Metadata` object :return: A :class:`calibre.ebooks.metadata.book.Metadata` object
''' '''
return None return None
# }}} # }}}

View File

@ -11,8 +11,8 @@ from calibre.ebooks.metadata.archive import ArchiveExtract, KPFExtract, get_comi
plugins = [] plugins = []
# To archive plugins {{{
# To archive plugins {{{
class PML2PMLZ(FileTypePlugin): class PML2PMLZ(FileTypePlugin):
name = 'PML to PMLZ' name = 'PML to PMLZ'
@ -96,8 +96,8 @@ class TXT2TXTZ(FileTypePlugin):
plugins += [HTML2ZIP, PML2PMLZ, TXT2TXTZ, ArchiveExtract, KPFExtract] plugins += [HTML2ZIP, PML2PMLZ, TXT2TXTZ, ArchiveExtract, KPFExtract]
# }}} # }}}
# Metadata reader plugins {{{
# Metadata reader plugins {{{
class ComicMetadataReader(MetadataReaderPlugin): class ComicMetadataReader(MetadataReaderPlugin):
@ -434,8 +434,8 @@ plugins += [x for x in list(locals().values()) if isinstance(x, type) and
# }}} # }}}
# Metadata writer plugins {{{
# Metadata writer plugins {{{
class EPUBMetadataWriter(MetadataWriterPlugin): class EPUBMetadataWriter(MetadataWriterPlugin):
@ -835,7 +835,6 @@ plugins += [
USER_DEFINED, USER_DEFINED,
] ]
# }}} # }}}
# New metadata download plugins {{{ # New metadata download plugins {{{
@ -850,8 +849,8 @@ plugins += [GoogleBooks, GoogleImages, Amazon, Edelweiss, OpenLibrary, BigBookSe
# }}} # }}}
# Interface Actions {{{
# Interface Actions {{{
class ActionAdd(InterfaceActionBase): class ActionAdd(InterfaceActionBase):
name = 'Add Books' name = 'Add Books'
@ -1137,6 +1136,7 @@ class ActionAllActions(InterfaceActionBase):
actual_plugin = 'calibre.gui2.actions.all_actions:AllGUIActions' actual_plugin = 'calibre.gui2.actions.all_actions:AllGUIActions'
description = _('Open a menu showing all installed GUI actions') description = _('Open a menu showing all installed GUI actions')
class ActionVirtualLibrary(InterfaceActionBase): class ActionVirtualLibrary(InterfaceActionBase):
name = 'Virtual Library' name = 'Virtual Library'
actual_plugin = 'calibre.gui2.actions.virtual_library:VirtualLibraryAction' actual_plugin = 'calibre.gui2.actions.virtual_library:VirtualLibraryAction'
@ -1183,8 +1183,8 @@ plugins += [ActionAdd, ActionAllActions, ActionFetchAnnotations, ActionGenerateC
# }}} # }}}
# Preferences Plugins {{{
# Preferences Plugins {{{
class LookAndFeel(PreferencesPlugin): class LookAndFeel(PreferencesPlugin):
name = 'Look & Feel' name = 'Look & Feel'
@ -1460,8 +1460,8 @@ plugins += [LookAndFeel, Behavior, Columns, Toolbar, Search, InputOptions,
# }}} # }}}
# Store plugins {{{
# Store plugins {{{
class StoreAmazonKindleStore(StoreBase): class StoreAmazonKindleStore(StoreBase):
name = 'Amazon Kindle' name = 'Amazon Kindle'

View File

@ -11,7 +11,6 @@ from calibre.customize import Plugin
class ConversionOption: class ConversionOption:
''' '''
Class representing conversion options Class representing conversion options
''' '''
@ -127,7 +126,6 @@ def gui_configuration_widget(name, parent, get_option_by_name,
class InputFormatPlugin(Plugin): class InputFormatPlugin(Plugin):
''' '''
InputFormatPlugins are responsible for converting a document into InputFormatPlugins are responsible for converting a document into
HTML+OPF+CSS+etc. HTML+OPF+CSS+etc.
@ -275,7 +273,6 @@ class InputFormatPlugin(Plugin):
class OutputFormatPlugin(Plugin): class OutputFormatPlugin(Plugin):
''' '''
OutputFormatPlugins are responsible for converting an OEB document OutputFormatPlugins are responsible for converting an OEB document
(OPF+HTML) into an output e-book. (OPF+HTML) into an output e-book.

View File

@ -34,8 +34,8 @@ class Plugin(_Plugin):
self.width_pts = self.width * 72./self.dpi self.width_pts = self.width * 72./self.dpi
self.height_pts = self.height * 72./self.dpi self.height_pts = self.height * 72./self.dpi
# Input profiles {{{
# Input profiles {{{
class InputProfile(Plugin): class InputProfile(Plugin):

View File

@ -74,11 +74,10 @@ def load_plugin(path_to_zip_file): # {{{
:return: A :class:`Plugin` instance. :return: A :class:`Plugin` instance.
''' '''
return loader.load(path_to_zip_file) return loader.load(path_to_zip_file)
# }}} # }}}
# Enable/disable plugins {{{
# Enable/disable plugins {{{
def disable_plugin(plugin_or_name): def disable_plugin(plugin_or_name):
x = getattr(plugin_or_name, 'name', plugin_or_name) x = getattr(plugin_or_name, 'name', plugin_or_name)
@ -131,8 +130,8 @@ def is_disabled(plugin):
plugin.name in default_disabled_plugins plugin.name in default_disabled_plugins
# }}} # }}}
# File type plugins {{{
# File type plugins {{{
_on_import = {} _on_import = {}
_on_postimport = {} _on_postimport = {}
@ -270,8 +269,8 @@ def run_plugins_on_postadd(db, book_id, fmt_map):
# }}} # }}}
# Plugin customization {{{
# Plugin customization {{{
def customize_plugin(plugin, custom): def customize_plugin(plugin, custom):
d = config['plugin_customization'] d = config['plugin_customization']
@ -284,8 +283,8 @@ def plugin_customization(plugin):
# }}} # }}}
# Input/Output profiles {{{
# Input/Output profiles {{{
def input_profiles(): def input_profiles():
for plugin in _initialized_plugins: for plugin in _initialized_plugins:
@ -299,8 +298,8 @@ def output_profiles():
yield plugin yield plugin
# }}} # }}}
# Interface Actions # {{{
# Interface Actions # {{{
def interface_actions(): def interface_actions():
customization = config['plugin_customization'] customization = config['plugin_customization']
@ -311,8 +310,8 @@ def interface_actions():
yield plugin yield plugin
# }}} # }}}
# Preferences Plugins # {{{
# Preferences Plugins # {{{
def preferences_plugins(): def preferences_plugins():
customization = config['plugin_customization'] customization = config['plugin_customization']
@ -323,8 +322,8 @@ def preferences_plugins():
yield plugin yield plugin
# }}} # }}}
# Library Closed Plugins # {{{
# Library Closed Plugins # {{{
def available_library_closed_plugins(): def available_library_closed_plugins():
customization = config['plugin_customization'] customization = config['plugin_customization']
@ -343,8 +342,8 @@ def has_library_closed_plugins():
return False return False
# }}} # }}}
# Store Plugins # {{{
# Store Plugins # {{{
def store_plugins(): def store_plugins():
customization = config['plugin_customization'] customization = config['plugin_customization']
@ -375,8 +374,8 @@ def available_stores():
# }}} # }}}
# Metadata read/write {{{
# Metadata read/write {{{
_metadata_readers = {} _metadata_readers = {}
_metadata_writers = {} _metadata_writers = {}
@ -519,8 +518,8 @@ def can_set_metadata(ftype):
# }}} # }}}
# Add/remove plugins {{{
# Add/remove plugins {{{
def add_plugin(path_to_zip_file): def add_plugin(path_to_zip_file):
make_config_dir() make_config_dir()
@ -565,8 +564,8 @@ def remove_plugin(plugin_or_name):
# }}} # }}}
# Input/Output format plugins {{{
# Input/Output format plugins {{{
def input_format_plugins(): def input_format_plugins():
for plugin in _initialized_plugins: for plugin in _initialized_plugins:
@ -623,8 +622,8 @@ def available_output_formats():
# }}} # }}}
# Catalog plugins {{{
# Catalog plugins {{{
def catalog_plugins(): def catalog_plugins():
for plugin in _initialized_plugins: for plugin in _initialized_plugins:
@ -648,8 +647,8 @@ def plugin_for_catalog_format(fmt):
# }}} # }}}
# Device plugins {{{
# Device plugins {{{
def device_plugins(include_disabled=False): def device_plugins(include_disabled=False):
for plugin in _initialized_plugins: for plugin in _initialized_plugins:
@ -670,8 +669,8 @@ def disabled_device_plugins():
yield plugin yield plugin
# }}} # }}}
# Metadata sources2 {{{
# Metadata sources2 {{{
def metadata_plugins(capabilities): def metadata_plugins(capabilities):
capabilities = frozenset(capabilities) capabilities = frozenset(capabilities)
@ -702,8 +701,8 @@ def patch_metadata_plugins(possibly_updated_plugins):
_initialized_plugins[i] = pup _initialized_plugins[i] = pup
# }}} # }}}
# Editor plugins {{{
# Editor plugins {{{
def all_edit_book_tool_plugins(): def all_edit_book_tool_plugins():
for plugin in _initialized_plugins: for plugin in _initialized_plugins:
@ -711,8 +710,8 @@ def all_edit_book_tool_plugins():
yield plugin yield plugin
# }}} # }}}
# Initialize plugins {{{
# Initialize plugins {{{
_initialized_plugins = [] _initialized_plugins = []
@ -823,8 +822,8 @@ def initialized_plugins():
# }}} # }}}
# CLI {{{
# CLI {{{
def build_plugin(path): def build_plugin(path):
from calibre import prints from calibre import prints

View File

@ -197,8 +197,8 @@ class DBPrefs(dict): # {{{
return json.load(f, object_hook=from_json) return json.load(f, object_hook=from_json)
# }}} # }}}
# Extra collators {{{
# Extra collators {{{
def pynocase(one, two, encoding='utf-8'): def pynocase(one, two, encoding='utf-8'):
if isbytestring(one): if isbytestring(one):
@ -226,8 +226,8 @@ def icu_collator(s1, s2):
# }}} # }}}
# Unused aggregators {{{
# Unused aggregators {{{
def Concatenate(sep=','): def Concatenate(sep=','):
'''String concatenation aggregator for sqlite''' '''String concatenation aggregator for sqlite'''

View File

@ -135,7 +135,6 @@ dynamic_category_preferences = frozenset({'grouped_search_make_user_categories',
class Cache: class Cache:
''' '''
An in-memory cache of the metadata.db file from a calibre library. An in-memory cache of the metadata.db file from a calibre library.
This class also serves as a threadsafe API for accessing the database. This class also serves as a threadsafe API for accessing the database.

View File

@ -189,6 +189,7 @@ def sort_key_for_name_and_first_letter(x, hierarchical_categories=()):
return (c if numeric_collation and c.isdigit() else '9999999999', return (c if numeric_collation and c.isdigit() else '9999999999',
collation_order(v2), sort_key(v1)) collation_order(v2), sort_key(v1))
def sort_key_for_name(x, hierarchical_categories=()): def sort_key_for_name(x, hierarchical_categories=()):
v = x.sort or x.name v = x.sort or x.name
if x.category not in hierarchical_categories: if x.category not in hierarchical_categories:

View File

@ -96,8 +96,6 @@ see the different options, specify the name of the output file and then the
add_plugin_parser_options(fmt, parser) add_plugin_parser_options(fmt, parser)
return parser return parser
# }}} # }}}

View File

@ -16,6 +16,7 @@ BOOK_ID_PATH_TEMPLATE = ' ({})'
RESOURCE_URL_SCHEME = 'calres' RESOURCE_URL_SCHEME = 'calres'
TEMPLATE_ICON_INDICATOR = ' template ' # Item values cannot start or end with space TEMPLATE_ICON_INDICATOR = ' template ' # Item values cannot start or end with space
@dataclass @dataclass
class TrashEntry: class TrashEntry:
book_id: int book_id: int

View File

@ -164,7 +164,6 @@ class ThreadSafePrefs(MutableMapping):
class LibraryDatabase: class LibraryDatabase:
''' Emulate the old LibraryDatabase2 interface ''' ''' Emulate the old LibraryDatabase2 interface '''
PATH_LIMIT = DB.PATH_LIMIT PATH_LIMIT = DB.PATH_LIMIT

View File

@ -25,6 +25,7 @@ from calibre.utils.icu import lower as icu_lower
if iswindows: if iswindows:
from calibre_extensions import winutil from calibre_extensions import winutil
class cmt(str): class cmt(str):
pass pass

View File

@ -28,8 +28,8 @@ EQUALS_MATCH = 1
REGEXP_MATCH = 2 REGEXP_MATCH = 2
ACCENT_MATCH = 3 ACCENT_MATCH = 3
# Utils {{{
# Utils {{{
def _matchkind(query, case_sensitive=False): def _matchkind(query, case_sensitive=False):
matchkind = CONTAINS_MATCH matchkind = CONTAINS_MATCH

View File

@ -20,6 +20,7 @@ from polyglot.builtins import iteritems, itervalues
def identity(x): def identity(x):
return x return x
def c_parse(val): def c_parse(val):
try: try:
year, month, day, hour, minutes, seconds, tzsecs = _c_speedup(val) year, month, day, hour, minutes, seconds, tzsecs = _c_speedup(val)
@ -90,7 +91,6 @@ class Table:
class VirtualTable(Table): class VirtualTable(Table):
''' '''
A dummy table used for fields that only exist in memory like ondevice A dummy table used for fields that only exist in memory like ondevice
''' '''
@ -102,7 +102,6 @@ class VirtualTable(Table):
class OneToOneTable(Table): class OneToOneTable(Table):
''' '''
Represents data that is unique per book (it may not actually be unique) but Represents data that is unique per book (it may not actually be unique) but
each item is assigned to a book in a one-to-one mapping. For example: uuid, each item is assigned to a book in a one-to-one mapping. For example: uuid,
@ -197,7 +196,6 @@ class CompositeTable(OneToOneTable):
class ManyToOneTable(Table): class ManyToOneTable(Table):
''' '''
Represents data where one data item can map to many books, for example: Represents data where one data item can map to many books, for example:
series or publisher. series or publisher.
@ -409,7 +407,6 @@ class RatingTable(ManyToOneTable):
class ManyToManyTable(ManyToOneTable): class ManyToManyTable(ManyToOneTable):
''' '''
Represents data that has a many-to-many mapping with books. i.e. each book Represents data that has a many-to-many mapping with books. i.e. each book
can have more than one value and each value can be mapped to more than one can have more than one value and each value can be mapped to more than one

View File

@ -4,6 +4,3 @@
__license__ = 'GPL v3' __license__ = 'GPL v3'
__copyright__ = '2011, Kovid Goyal <kovid@kovidgoyal.net>' __copyright__ = '2011, Kovid Goyal <kovid@kovidgoyal.net>'
__docformat__ = 'restructuredtext en' __docformat__ = 'restructuredtext en'

View File

@ -160,7 +160,6 @@ class FilesystemTest(BaseTest):
self.assertEqual(cache.rename_extra_files(1, {'B': 'data/c'}), set()) self.assertEqual(cache.rename_extra_files(1, {'B': 'data/c'}), set())
self.assertEqual(cache.rename_extra_files(1, {'B': 'data/c'}, replace=True), {'B'}) self.assertEqual(cache.rename_extra_files(1, {'B': 'data/c'}, replace=True), {'B'})
@unittest.skipUnless(iswindows, 'Windows only') @unittest.skipUnless(iswindows, 'Windows only')
def test_windows_atomic_move(self): def test_windows_atomic_move(self):
'Test book file open in another process when changing metadata' 'Test book file open in another process when changing metadata'

View File

@ -78,7 +78,6 @@ def run_funcs(self, db, ndb, funcs):
class LegacyTest(BaseTest): class LegacyTest(BaseTest):
''' Test the emulation of the legacy interface. ''' ''' Test the emulation of the legacy interface. '''
def test_library_wide_properties(self): # {{{ def test_library_wide_properties(self): # {{{

View File

@ -22,6 +22,7 @@ def test_notes_restore(self: 'NotesTest'):
doc2 = 'simple notes for an author2' doc2 = 'simple notes for an author2'
cache.set_notes_for('authors', authors[1], doc2, resource_hashes=(h2,)) cache.set_notes_for('authors', authors[1], doc2, resource_hashes=(h2,))
def test_notes_api(self: 'NotesTest'): def test_notes_api(self: 'NotesTest'):
cache, notes = self.create_notes_db() cache, notes = self.create_notes_db()
authors = sorted(cache.all_field_ids('authors')) authors = sorted(cache.all_field_ids('authors'))
@ -81,6 +82,7 @@ def test_notes_api(self: 'NotesTest'):
cache.set_notes_for('authors', authors[0], '', resource_hashes=()) cache.set_notes_for('authors', authors[0], '', resource_hashes=())
self.ae(len(os.listdir(notes.retired_dir)), 1) self.ae(len(os.listdir(notes.retired_dir)), 1)
def test_cache_api(self: 'NotesTest'): def test_cache_api(self: 'NotesTest'):
cache, notes = self.create_notes_db() cache, notes = self.create_notes_db()
authors = cache.field_for('authors', 1) authors = cache.field_for('authors', 1)

View File

@ -712,7 +712,6 @@ class ReadingTest(BaseTest):
self.assertRaises(NotImplementedError, pmi.template_to_attribute, {}, {}) self.assertRaises(NotImplementedError, pmi.template_to_attribute, {}, {})
self.assertRaises(NotImplementedError, pmi.smart_update, {}) self.assertRaises(NotImplementedError, pmi.smart_update, {})
# }}} # }}}
def test_marked_field(self): # {{{ def test_marked_field(self): # {{{

View File

@ -920,7 +920,6 @@ class WritingTest(BaseTest):
cache.restore_annotations(1, list(opf.read_annotations())) cache.restore_annotations(1, list(opf.read_annotations()))
amap = cache.annotations_map_for_book(1, 'moo') amap = cache.annotations_map_for_book(1, 'moo')
self.assertEqual([x[0] for x in annot_list], map_as_list(amap)) self.assertEqual([x[0] for x in annot_list], map_as_list(amap))
# }}} # }}}
def test_changed_events(self): # {{{ def test_changed_events(self): # {{{
@ -1043,7 +1042,6 @@ class WritingTest(BaseTest):
self.assertDictEqual({'publisher': {'random': 'url2'}, 'tags': {'foobar': 'url'}}, self.assertDictEqual({'publisher': {'random': 'url2'}, 'tags': {'foobar': 'url'}},
mi.link_maps, "ProxyMetadata didn't return the right link map") mi.link_maps, "ProxyMetadata didn't return the right link map")
# Now test deleting the links. # Now test deleting the links.
links = cache.get_link_map('tags') links = cache.get_link_map('tags')
to_del = {l:'' for l in links.keys()} to_del = {l:'' for l in links.keys()}
@ -1054,6 +1052,4 @@ class WritingTest(BaseTest):
cache.set_link_map('publisher', to_del) cache.set_link_map('publisher', to_del)
self.assertEqual({}, cache.get_link_map('publisher'), 'links on publisher were not deleted') self.assertEqual({}, cache.get_link_map('publisher'), 'links on publisher were not deleted')
self.assertEqual({}, cache.get_all_link_maps_for_book(1), 'Not all links for book were deleted') self.assertEqual({}, cache.get_all_link_maps_for_book(1), 'Not all links for book were deleted')
# }}} # }}}

View File

@ -107,7 +107,6 @@ class CacheError(Exception):
class ThumbnailCache: class ThumbnailCache:
' This is a persistent disk cache to speed up loading and resizing of covers ' ' This is a persistent disk cache to speed up loading and resizing of covers '
def __init__(self, def __init__(self,

View File

@ -99,7 +99,6 @@ def format_identifiers(x):
class View: class View:
''' A table view of the database, with rows and columns. Also supports ''' A table view of the database, with rows and columns. Also supports
filtering and sorting. ''' filtering and sorting. '''

View File

@ -19,8 +19,8 @@ from polyglot.builtins import iteritems, itervalues
missing = object() missing = object()
# Convert data into values suitable for the db {{{
# Convert data into values suitable for the db {{{
def sqlite_datetime(x): def sqlite_datetime(x):
return isoformat(x, sep=' ') if isinstance(x, datetime) else x return isoformat(x, sep=' ') if isinstance(x, datetime) else x
@ -190,8 +190,8 @@ def get_adapter(name, metadata):
return ans return ans
# }}} # }}}
# One-One fields {{{
# One-One fields {{{
def one_one_in_books(book_id_val_map, db, field, *args): def one_one_in_books(book_id_val_map, db, field, *args):
'Set a one-one field in the books table' 'Set a one-one field in the books table'
@ -265,8 +265,8 @@ def custom_series_index(book_id_val_map, db, field, *args):
return {s[1] for s in sequence} return {s[1] for s in sequence}
# }}} # }}}
# Many-One fields {{{
# Many-One fields {{{
def safe_lower(x): def safe_lower(x):
try: try:
@ -392,8 +392,8 @@ def many_one(book_id_val_map, db, field, allow_case_change, *args):
return dirtied return dirtied
# }}} # }}}
# Many-Many fields {{{
# Many-Many fields {{{
def uniq(vals, kmap=lambda x:x): def uniq(vals, kmap=lambda x:x):
''' Remove all duplicates from vals, while preserving order. kmap must be a ''' Remove all duplicates from vals, while preserving order. kmap must be a

View File

@ -99,7 +99,6 @@ class MIBUK(USBMS):
class JETBOOK_MINI(USBMS): class JETBOOK_MINI(USBMS):
''' '''
['0x4b8', ['0x4b8',
'0x507', '0x507',
@ -126,7 +125,6 @@ class JETBOOK_MINI(USBMS):
class JETBOOK_COLOR(USBMS): class JETBOOK_COLOR(USBMS):
''' '''
set([('0x951', set([('0x951',
'0x160b', '0x160b',

View File

@ -39,5 +39,3 @@ class Pages:
@property @property
def number_of_pages(self) -> int: def number_of_pages(self) -> int:
return sum(len(pg.page_locations) for pg in self.__pages_groups) return sum(len(pg.page_locations) for pg in self.__pages_groups)

View File

@ -185,5 +185,4 @@ class Bookmark: # {{{
return ans return ans
# }}} # }}}

View File

@ -4,6 +4,3 @@
__license__ = 'GPL v3' __license__ = 'GPL v3'
__copyright__ = '2012, Kovid Goyal <kovid@kovidgoyal.net>' __copyright__ = '2012, Kovid Goyal <kovid@kovidgoyal.net>'
__docformat__ = 'restructuredtext en' __docformat__ = 'restructuredtext en'

View File

@ -22,6 +22,7 @@ from calibre.utils.icu import lower, sort_key
bexts = frozenset(BOOK_EXTENSIONS) - {'mbp', 'tan', 'rar', 'zip', 'xml'} bexts = frozenset(BOOK_EXTENSIONS) - {'mbp', 'tan', 'rar', 'zip', 'xml'}
def convert_timestamp(md): def convert_timestamp(md):
try: try:
if isinstance(md, tuple): if isinstance(md, tuple):

View File

@ -9,4 +9,3 @@ __docformat__ = 'restructuredtext en'
''' '''
libmtp based drivers for MTP devices on Unix like platforms. libmtp based drivers for MTP devices on Unix like platforms.
''' '''

View File

@ -4,6 +4,3 @@
__license__ = 'GPL v3' __license__ = 'GPL v3'
__copyright__ = '2012, Kovid Goyal <kovid at kovidgoyal.net>' __copyright__ = '2012, Kovid Goyal <kovid at kovidgoyal.net>'
__docformat__ = 'restructuredtext en' __docformat__ = 'restructuredtext en'

View File

@ -73,7 +73,6 @@ class USBDevice:
class Device(DeviceConfig, DevicePlugin): class Device(DeviceConfig, DevicePlugin):
''' '''
This class provides logic common to all drivers for devices that export themselves This class provides logic common to all drivers for devices that export themselves
as USB Mass Storage devices. Provides implementations for mounting/ejecting as USB Mass Storage devices. Provides implementations for mounting/ejecting

View File

@ -67,7 +67,6 @@ def safe_walk(top, topdown=True, onerror=None, followlinks=False, maxdepth=128):
# CLI must come before Device as it implements the CLI functions that # CLI must come before Device as it implements the CLI functions that
# are inherited from the device interface in Device. # are inherited from the device interface in Device.
class USBMS(CLI, Device): class USBMS(CLI, Device):
''' '''
The base class for all USBMS devices. Implements the logic for The base class for all USBMS devices. Implements the logic for
sending/getting/updating metadata/caching metadata/etc. sending/getting/updating metadata/caching metadata/etc.

View File

@ -44,7 +44,6 @@ except ImportError:
# Data and function type definitions {{{ # Data and function type definitions {{{
class GUID(Structure): class GUID(Structure):
_fields_ = [ _fields_ = [
('data1', DWORD), ('data1', DWORD),
@ -701,8 +700,8 @@ def get_volume_pathnames(volume_id, buf=None):
# }}} # }}}
# def scan_usb_devices(): {{{
# def scan_usb_devices(): {{{
_USBDevice = namedtuple('USBDevice', 'vendor_id product_id bcd devid devinst') _USBDevice = namedtuple('USBDevice', 'vendor_id product_id bcd devid devinst')

Some files were not shown because too many files have changed in this diff Show More