mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
automated upgrade of python code using ruff and ./setup.py upgrade_source_code
This commit is contained in:
parent
dd71135591
commit
3e58252176
@ -3,7 +3,6 @@ requires-python = ">=3.10"
|
|||||||
|
|
||||||
[tool.ruff]
|
[tool.ruff]
|
||||||
line-length = 160
|
line-length = 160
|
||||||
target-version = 'py310'
|
|
||||||
builtins = ['_', 'I', 'P']
|
builtins = ['_', 'I', 'P']
|
||||||
include = ['*.py', '*.recipe']
|
include = ['*.py', '*.recipe']
|
||||||
exclude = [
|
exclude = [
|
||||||
|
@ -5,7 +5,6 @@ afriquexxi.info
|
|||||||
'''
|
'''
|
||||||
|
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|
||||||
from zoneinfo import ZoneInfo
|
from zoneinfo import ZoneInfo
|
||||||
|
|
||||||
from calibre import browser
|
from calibre import browser
|
||||||
|
@ -3,9 +3,9 @@
|
|||||||
|
|
||||||
import json
|
import json
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
from zoneinfo import ZoneInfo
|
||||||
|
|
||||||
import mechanize
|
import mechanize
|
||||||
from zoneinfo import ZoneInfo
|
|
||||||
|
|
||||||
from calibre import browser
|
from calibre import browser
|
||||||
from calibre.web.feeds.news import BasicNewsRecipe
|
from calibre.web.feeds.news import BasicNewsRecipe
|
||||||
|
@ -5,7 +5,6 @@ contretemps.eu
|
|||||||
'''
|
'''
|
||||||
|
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|
||||||
from zoneinfo import ZoneInfo
|
from zoneinfo import ZoneInfo
|
||||||
|
|
||||||
from calibre.web.feeds.news import BasicNewsRecipe
|
from calibre.web.feeds.news import BasicNewsRecipe
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
''' orientxxi.info '''
|
''' orientxxi.info '''
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|
||||||
from zoneinfo import ZoneInfo
|
from zoneinfo import ZoneInfo
|
||||||
|
|
||||||
from calibre import browser
|
from calibre import browser
|
||||||
|
@ -15,7 +15,7 @@ import sys
|
|||||||
import sysconfig
|
import sysconfig
|
||||||
import textwrap
|
import textwrap
|
||||||
from functools import partial
|
from functools import partial
|
||||||
from typing import List, NamedTuple
|
from typing import NamedTuple
|
||||||
|
|
||||||
from setup import SRC, Command, isbsd, isfreebsd, ishaiku, islinux, ismacos, iswindows
|
from setup import SRC, Command, isbsd, isfreebsd, ishaiku, islinux, ismacos, iswindows
|
||||||
|
|
||||||
@ -24,14 +24,14 @@ isunix = islinux or ismacos or isbsd or ishaiku
|
|||||||
py_lib = os.path.join(sys.prefix, 'libs', 'python%d%d.lib' % sys.version_info[:2])
|
py_lib = os.path.join(sys.prefix, 'libs', 'python%d%d.lib' % sys.version_info[:2])
|
||||||
|
|
||||||
class CompileCommand(NamedTuple):
|
class CompileCommand(NamedTuple):
|
||||||
cmd: List[str]
|
cmd: list[str]
|
||||||
src: str
|
src: str
|
||||||
dest: str
|
dest: str
|
||||||
|
|
||||||
|
|
||||||
class LinkCommand(NamedTuple):
|
class LinkCommand(NamedTuple):
|
||||||
cmd: List[str]
|
cmd: list[str]
|
||||||
objects: List[str]
|
objects: list[str]
|
||||||
dest: str
|
dest: str
|
||||||
|
|
||||||
|
|
||||||
@ -209,11 +209,11 @@ class Environment(NamedTuple):
|
|||||||
cc: str
|
cc: str
|
||||||
cxx: str
|
cxx: str
|
||||||
linker: str
|
linker: str
|
||||||
base_cflags: List[str]
|
base_cflags: list[str]
|
||||||
base_cxxflags: List[str]
|
base_cxxflags: list[str]
|
||||||
base_ldflags: List[str]
|
base_ldflags: list[str]
|
||||||
cflags: List[str]
|
cflags: list[str]
|
||||||
ldflags: List[str]
|
ldflags: list[str]
|
||||||
make: str
|
make: str
|
||||||
internal_inc_prefix: str
|
internal_inc_prefix: str
|
||||||
external_inc_prefix: str
|
external_inc_prefix: str
|
||||||
@ -228,10 +228,10 @@ class Environment(NamedTuple):
|
|||||||
dest_ext: str
|
dest_ext: str
|
||||||
std_prefix: str
|
std_prefix: str
|
||||||
|
|
||||||
def inc_dirs_to_cflags(self, dirs) -> List[str]:
|
def inc_dirs_to_cflags(self, dirs) -> list[str]:
|
||||||
return [self.external_inc_prefix+x for x in dirs]
|
return [self.external_inc_prefix+x for x in dirs]
|
||||||
|
|
||||||
def lib_dirs_to_ldflags(self, dirs) -> List[str]:
|
def lib_dirs_to_ldflags(self, dirs) -> list[str]:
|
||||||
return [self.libdir_prefix+x for x in dirs if x]
|
return [self.libdir_prefix+x for x in dirs if x]
|
||||||
|
|
||||||
def libraries_to_ldflags(self, libs):
|
def libraries_to_ldflags(self, libs):
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
# -* coding: utf-8 -*-
|
|
||||||
#
|
#
|
||||||
# License: MIT (see LICENSE file provided)
|
# License: MIT (see LICENSE file provided)
|
||||||
# vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4:
|
# vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4:
|
||||||
@ -34,22 +33,11 @@ default_encoding = 'utf-8'
|
|||||||
# python 2/3 compatibility helpers {{{
|
# python 2/3 compatibility helpers {{{
|
||||||
|
|
||||||
|
|
||||||
if sys.version_info < (3,):
|
|
||||||
PY3 = False
|
|
||||||
text_type = unicode
|
|
||||||
|
|
||||||
def b(s):
|
|
||||||
return s
|
|
||||||
|
|
||||||
def u(s):
|
|
||||||
return unicode(s, "unicode_escape")
|
|
||||||
|
|
||||||
else:
|
|
||||||
PY3 = True
|
PY3 = True
|
||||||
text_type = str
|
text_type = str
|
||||||
|
|
||||||
def b(s):
|
def b(s):
|
||||||
return s.encode("latin-1")
|
return s.encode()
|
||||||
|
|
||||||
def u(s):
|
def u(s):
|
||||||
return s
|
return s
|
||||||
@ -390,7 +378,7 @@ class _BaseFile(list):
|
|||||||
# But if pickling, we never want to check for duplicates anyway.
|
# But if pickling, we never want to check for duplicates anyway.
|
||||||
if getattr(self, 'check_for_duplicates', False) and entry in self:
|
if getattr(self, 'check_for_duplicates', False) and entry in self:
|
||||||
raise ValueError('Entry "%s" already exists' % entry.msgid)
|
raise ValueError('Entry "%s" already exists' % entry.msgid)
|
||||||
super(_BaseFile, self).append(entry)
|
super().append(entry)
|
||||||
|
|
||||||
def insert(self, index, entry):
|
def insert(self, index, entry):
|
||||||
"""
|
"""
|
||||||
@ -408,7 +396,7 @@ class _BaseFile(list):
|
|||||||
"""
|
"""
|
||||||
if self.check_for_duplicates and entry in self:
|
if self.check_for_duplicates and entry in self:
|
||||||
raise ValueError('Entry "%s" already exists' % entry.msgid)
|
raise ValueError('Entry "%s" already exists' % entry.msgid)
|
||||||
super(_BaseFile, self).insert(index, entry)
|
super().insert(index, entry)
|
||||||
|
|
||||||
def metadata_as_entry(self):
|
def metadata_as_entry(self):
|
||||||
"""
|
"""
|
||||||
@ -420,7 +408,7 @@ class _BaseFile(list):
|
|||||||
strs = []
|
strs = []
|
||||||
for name, value in mdata:
|
for name, value in mdata:
|
||||||
# Strip whitespace off each line in a multi-line entry
|
# Strip whitespace off each line in a multi-line entry
|
||||||
strs.append('%s: %s' % (name, value))
|
strs.append(f'{name}: {value}')
|
||||||
e.msgstr = '\n'.join(strs) + '\n'
|
e.msgstr = '\n'.join(strs) + '\n'
|
||||||
if self.metadata_is_fuzzy:
|
if self.metadata_is_fuzzy:
|
||||||
e.flags.append('fuzzy')
|
e.flags.append('fuzzy')
|
||||||
@ -444,7 +432,7 @@ class _BaseFile(list):
|
|||||||
string, controls how universal newlines works
|
string, controls how universal newlines works
|
||||||
"""
|
"""
|
||||||
if self.fpath is None and fpath is None:
|
if self.fpath is None and fpath is None:
|
||||||
raise IOError('You must provide a file path to save() method')
|
raise OSError('You must provide a file path to save() method')
|
||||||
contents = getattr(self, repr_method)()
|
contents = getattr(self, repr_method)()
|
||||||
if fpath is None:
|
if fpath is None:
|
||||||
fpath = self.fpath
|
fpath = self.fpath
|
||||||
@ -452,7 +440,7 @@ class _BaseFile(list):
|
|||||||
with open(fpath, 'wb') as fhandle:
|
with open(fpath, 'wb') as fhandle:
|
||||||
fhandle.write(contents)
|
fhandle.write(contents)
|
||||||
else:
|
else:
|
||||||
with io.open(
|
with open(
|
||||||
fpath,
|
fpath,
|
||||||
'w',
|
'w',
|
||||||
encoding=self.encoding,
|
encoding=self.encoding,
|
||||||
@ -730,10 +718,10 @@ class POFile(_BaseFile):
|
|||||||
object POFile, the reference catalog.
|
object POFile, the reference catalog.
|
||||||
"""
|
"""
|
||||||
# Store entries in dict/set for faster access
|
# Store entries in dict/set for faster access
|
||||||
self_entries = dict(
|
self_entries = {
|
||||||
(entry.msgid_with_context, entry) for entry in self
|
entry.msgid_with_context: entry for entry in self
|
||||||
)
|
}
|
||||||
refpot_msgids = set(entry.msgid_with_context for entry in refpot)
|
refpot_msgids = {entry.msgid_with_context for entry in refpot}
|
||||||
# Merge entries that are in the refpot
|
# Merge entries that are in the refpot
|
||||||
for entry in refpot:
|
for entry in refpot:
|
||||||
e = self_entries.get(entry.msgid_with_context)
|
e = self_entries.get(entry.msgid_with_context)
|
||||||
@ -822,7 +810,7 @@ class MOFile(_BaseFile):
|
|||||||
# class _BaseEntry {{{
|
# class _BaseEntry {{{
|
||||||
|
|
||||||
|
|
||||||
class _BaseEntry(object):
|
class _BaseEntry:
|
||||||
"""
|
"""
|
||||||
Base class for :class:`~polib.POEntry` and :class:`~polib.MOEntry` classes.
|
Base class for :class:`~polib.POEntry` and :class:`~polib.MOEntry` classes.
|
||||||
This class should **not** be instantiated directly.
|
This class should **not** be instantiated directly.
|
||||||
@ -942,16 +930,16 @@ class _BaseEntry(object):
|
|||||||
# quick and dirty trick to get the real field name
|
# quick and dirty trick to get the real field name
|
||||||
fieldname = fieldname[9:]
|
fieldname = fieldname[9:]
|
||||||
|
|
||||||
ret = ['%s%s%s "%s"' % (delflag, fieldname, plural_index,
|
ret = ['{}{}{} "{}"'.format(delflag, fieldname, plural_index,
|
||||||
escape(lines.pop(0)))]
|
escape(lines.pop(0)))]
|
||||||
for line in lines:
|
for line in lines:
|
||||||
ret.append('%s"%s"' % (delflag, escape(line)))
|
ret.append(f'{delflag}"{escape(line)}"')
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def msgid_with_context(self):
|
def msgid_with_context(self):
|
||||||
if self.msgctxt:
|
if self.msgctxt:
|
||||||
return '%s%s%s' % (self.msgctxt, "\x04", self.msgid)
|
return '{}{}{}'.format(self.msgctxt, "\x04", self.msgid)
|
||||||
return self.msgid
|
return self.msgid
|
||||||
# }}}
|
# }}}
|
||||||
# class POEntry {{{
|
# class POEntry {{{
|
||||||
@ -1023,14 +1011,14 @@ class POEntry(_BaseEntry):
|
|||||||
break_long_words=False
|
break_long_words=False
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
ret.append('%s%s' % (c[1], comment))
|
ret.append(f'{c[1]}{comment}')
|
||||||
|
|
||||||
# occurrences (with text wrapping as xgettext does)
|
# occurrences (with text wrapping as xgettext does)
|
||||||
if not self.obsolete and self.occurrences:
|
if not self.obsolete and self.occurrences:
|
||||||
filelist = []
|
filelist = []
|
||||||
for fpath, lineno in self.occurrences:
|
for fpath, lineno in self.occurrences:
|
||||||
if lineno:
|
if lineno:
|
||||||
filelist.append('%s:%s' % (fpath, lineno))
|
filelist.append(f'{fpath}:{lineno}')
|
||||||
else:
|
else:
|
||||||
filelist.append(fpath)
|
filelist.append(fpath)
|
||||||
filestr = ' '.join(filelist)
|
filestr = ' '.join(filelist)
|
||||||
@ -1238,7 +1226,7 @@ class MOEntry(_BaseEntry):
|
|||||||
# class _POFileParser {{{
|
# class _POFileParser {{{
|
||||||
|
|
||||||
|
|
||||||
class _POFileParser(object):
|
class _POFileParser:
|
||||||
"""
|
"""
|
||||||
A finite state machine to efficiently and correctly parse po
|
A finite state machine to efficiently and correctly parse po
|
||||||
file format.
|
file format.
|
||||||
@ -1264,10 +1252,10 @@ class _POFileParser(object):
|
|||||||
enc = kwargs.get('encoding', default_encoding)
|
enc = kwargs.get('encoding', default_encoding)
|
||||||
if _is_file(pofile):
|
if _is_file(pofile):
|
||||||
try:
|
try:
|
||||||
self.fhandle = io.open(pofile, 'rt', encoding=enc)
|
self.fhandle = open(pofile, encoding=enc)
|
||||||
except LookupError:
|
except LookupError:
|
||||||
enc = default_encoding
|
enc = default_encoding
|
||||||
self.fhandle = io.open(pofile, 'rt', encoding=enc)
|
self.fhandle = open(pofile, encoding=enc)
|
||||||
else:
|
else:
|
||||||
self.fhandle = pofile.splitlines()
|
self.fhandle = pofile.splitlines()
|
||||||
|
|
||||||
@ -1373,7 +1361,7 @@ class _POFileParser(object):
|
|||||||
if tokens[0] in keywords and nb_tokens > 1:
|
if tokens[0] in keywords and nb_tokens > 1:
|
||||||
line = line[len(tokens[0]):].lstrip()
|
line = line[len(tokens[0]):].lstrip()
|
||||||
if re.search(r'([^\\]|^)"', line[1:-1]):
|
if re.search(r'([^\\]|^)"', line[1:-1]):
|
||||||
raise IOError('Syntax error in po file %s(line %s): '
|
raise OSError('Syntax error in po file %s(line %s): '
|
||||||
'unescaped double quote found' %
|
'unescaped double quote found' %
|
||||||
(fpath, self.current_line))
|
(fpath, self.current_line))
|
||||||
self.current_token = line
|
self.current_token = line
|
||||||
@ -1391,7 +1379,7 @@ class _POFileParser(object):
|
|||||||
elif line[:1] == '"':
|
elif line[:1] == '"':
|
||||||
# we are on a continuation line
|
# we are on a continuation line
|
||||||
if re.search(r'([^\\]|^)"', line[1:-1]):
|
if re.search(r'([^\\]|^)"', line[1:-1]):
|
||||||
raise IOError('Syntax error in po file %s(line %s): '
|
raise OSError('Syntax error in po file %s(line %s): '
|
||||||
'unescaped double quote found' %
|
'unescaped double quote found' %
|
||||||
(fpath, self.current_line))
|
(fpath, self.current_line))
|
||||||
self.process('mc')
|
self.process('mc')
|
||||||
@ -1420,7 +1408,7 @@ class _POFileParser(object):
|
|||||||
|
|
||||||
elif tokens[0] == '#|':
|
elif tokens[0] == '#|':
|
||||||
if nb_tokens <= 1:
|
if nb_tokens <= 1:
|
||||||
raise IOError('Syntax error in po file %s(line %s)' %
|
raise OSError('Syntax error in po file %s(line %s)' %
|
||||||
(fpath, self.current_line))
|
(fpath, self.current_line))
|
||||||
|
|
||||||
# Remove the marker and any whitespace right after that.
|
# Remove the marker and any whitespace right after that.
|
||||||
@ -1434,14 +1422,14 @@ class _POFileParser(object):
|
|||||||
|
|
||||||
if nb_tokens == 2:
|
if nb_tokens == 2:
|
||||||
# Invalid continuation line.
|
# Invalid continuation line.
|
||||||
raise IOError('Syntax error in po file %s(line %s): '
|
raise OSError('Syntax error in po file %s(line %s): '
|
||||||
'invalid continuation line' %
|
'invalid continuation line' %
|
||||||
(fpath, self.current_line))
|
(fpath, self.current_line))
|
||||||
|
|
||||||
# we are on a "previous translation" comment line,
|
# we are on a "previous translation" comment line,
|
||||||
if tokens[1] not in prev_keywords:
|
if tokens[1] not in prev_keywords:
|
||||||
# Unknown keyword in previous translation comment.
|
# Unknown keyword in previous translation comment.
|
||||||
raise IOError('Syntax error in po file %s(line %s): '
|
raise OSError('Syntax error in po file %s(line %s): '
|
||||||
'unknown keyword %s' %
|
'unknown keyword %s' %
|
||||||
(fpath, self.current_line,
|
(fpath, self.current_line,
|
||||||
tokens[1]))
|
tokens[1]))
|
||||||
@ -1453,7 +1441,7 @@ class _POFileParser(object):
|
|||||||
self.process(prev_keywords[tokens[1]])
|
self.process(prev_keywords[tokens[1]])
|
||||||
|
|
||||||
else:
|
else:
|
||||||
raise IOError('Syntax error in po file %s(line %s)' %
|
raise OSError('Syntax error in po file %s(line %s)' %
|
||||||
(fpath, self.current_line))
|
(fpath, self.current_line))
|
||||||
|
|
||||||
if self.current_entry and len(tokens) > 0 and \
|
if self.current_entry and len(tokens) > 0 and \
|
||||||
@ -1524,7 +1512,7 @@ class _POFileParser(object):
|
|||||||
fpath = '%s ' % self.instance.fpath if self.instance.fpath else ''
|
fpath = '%s ' % self.instance.fpath if self.instance.fpath else ''
|
||||||
if hasattr(self.fhandle, 'close'):
|
if hasattr(self.fhandle, 'close'):
|
||||||
self.fhandle.close()
|
self.fhandle.close()
|
||||||
raise IOError('Syntax error in po file %s(line %s)' %
|
raise OSError('Syntax error in po file %s(line %s)' %
|
||||||
(fpath, self.current_line))
|
(fpath, self.current_line))
|
||||||
|
|
||||||
# state handlers
|
# state handlers
|
||||||
@ -1673,7 +1661,7 @@ class _POFileParser(object):
|
|||||||
# class _MOFileParser {{{
|
# class _MOFileParser {{{
|
||||||
|
|
||||||
|
|
||||||
class _MOFileParser(object):
|
class _MOFileParser:
|
||||||
"""
|
"""
|
||||||
A class to parse binary mo files.
|
A class to parse binary mo files.
|
||||||
"""
|
"""
|
||||||
@ -1729,14 +1717,14 @@ class _MOFileParser(object):
|
|||||||
elif magic_number == MOFile.MAGIC_SWAPPED:
|
elif magic_number == MOFile.MAGIC_SWAPPED:
|
||||||
ii = '>II'
|
ii = '>II'
|
||||||
else:
|
else:
|
||||||
raise IOError('Invalid mo file, magic number is incorrect !')
|
raise OSError('Invalid mo file, magic number is incorrect !')
|
||||||
self.instance.magic_number = magic_number
|
self.instance.magic_number = magic_number
|
||||||
# parse the version number and the number of strings
|
# parse the version number and the number of strings
|
||||||
version, numofstrings = self._readbinary(ii, 8)
|
version, numofstrings = self._readbinary(ii, 8)
|
||||||
# from MO file format specs: "A program seeing an unexpected major
|
# from MO file format specs: "A program seeing an unexpected major
|
||||||
# revision number should stop reading the MO file entirely"
|
# revision number should stop reading the MO file entirely"
|
||||||
if version >> 16 not in (0, 1):
|
if version >> 16 not in (0, 1):
|
||||||
raise IOError('Invalid mo file, unexpected major revision number')
|
raise OSError('Invalid mo file, unexpected major revision number')
|
||||||
self.instance.version = version
|
self.instance.version = version
|
||||||
# original strings and translation strings hash table offset
|
# original strings and translation strings hash table offset
|
||||||
msgids_hash_offset, msgstrs_hash_offset = self._readbinary(ii, 8)
|
msgids_hash_offset, msgstrs_hash_offset = self._readbinary(ii, 8)
|
||||||
@ -1777,8 +1765,8 @@ class _MOFileParser(object):
|
|||||||
entry = self._build_entry(
|
entry = self._build_entry(
|
||||||
msgid=msgid_tokens[0],
|
msgid=msgid_tokens[0],
|
||||||
msgid_plural=msgid_tokens[1],
|
msgid_plural=msgid_tokens[1],
|
||||||
msgstr_plural=dict((k, v) for k, v in
|
msgstr_plural={k: v for k, v in
|
||||||
enumerate(msgstr.split(b('\0'))))
|
enumerate(msgstr.split(b('\0')))}
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
entry = self._build_entry(msgid=msgid, msgstr=msgstr)
|
entry = self._build_entry(msgid=msgid, msgstr=msgstr)
|
||||||
|
@ -17,7 +17,6 @@ import time
|
|||||||
import uuid
|
import uuid
|
||||||
from contextlib import closing, suppress
|
from contextlib import closing, suppress
|
||||||
from functools import partial
|
from functools import partial
|
||||||
from typing import Optional
|
|
||||||
|
|
||||||
import apsw
|
import apsw
|
||||||
|
|
||||||
@ -1007,7 +1006,7 @@ class DB:
|
|||||||
def add_notes_resource(self, path_or_stream, name, mtime=None) -> int:
|
def add_notes_resource(self, path_or_stream, name, mtime=None) -> int:
|
||||||
return self.notes.add_resource(self.conn, path_or_stream, name, mtime=mtime)
|
return self.notes.add_resource(self.conn, path_or_stream, name, mtime=mtime)
|
||||||
|
|
||||||
def get_notes_resource(self, resource_hash) -> Optional[dict]:
|
def get_notes_resource(self, resource_hash) -> dict | None:
|
||||||
return self.notes.get_resource_data(self.conn, resource_hash)
|
return self.notes.get_resource_data(self.conn, resource_hash)
|
||||||
|
|
||||||
def notes_resources_used_by(self, field, item_id):
|
def notes_resources_used_by(self, field, item_id):
|
||||||
|
@ -14,13 +14,13 @@ import sys
|
|||||||
import traceback
|
import traceback
|
||||||
import weakref
|
import weakref
|
||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
from collections.abc import MutableSet, Set
|
from collections.abc import Iterable, MutableSet, Set
|
||||||
from functools import partial, wraps
|
from functools import partial, wraps
|
||||||
from io import DEFAULT_BUFFER_SIZE, BytesIO
|
from io import DEFAULT_BUFFER_SIZE, BytesIO
|
||||||
from queue import Queue
|
from queue import Queue
|
||||||
from threading import Lock
|
from threading import Lock
|
||||||
from time import mktime, monotonic, sleep, time
|
from time import mktime, monotonic, sleep, time
|
||||||
from typing import Iterable, NamedTuple, Optional, Tuple
|
from typing import NamedTuple
|
||||||
|
|
||||||
from calibre import as_unicode, detect_ncpus, isbytestring
|
from calibre import as_unicode, detect_ncpus, isbytestring
|
||||||
from calibre.constants import iswindows, preferred_encoding
|
from calibre.constants import iswindows, preferred_encoding
|
||||||
@ -725,7 +725,7 @@ class Cache:
|
|||||||
return self.backend.add_notes_resource(path_or_stream_or_data, name, mtime)
|
return self.backend.add_notes_resource(path_or_stream_or_data, name, mtime)
|
||||||
|
|
||||||
@read_api
|
@read_api
|
||||||
def get_notes_resource(self, resource_hash) -> Optional[dict]:
|
def get_notes_resource(self, resource_hash) -> dict | None:
|
||||||
' Return a dict containing the resource data and name or None if no resource with the specified hash is found '
|
' Return a dict containing the resource data and name or None if no resource with the specified hash is found '
|
||||||
return self.backend.get_notes_resource(resource_hash)
|
return self.backend.get_notes_resource(resource_hash)
|
||||||
|
|
||||||
@ -3370,7 +3370,7 @@ class Cache:
|
|||||||
return dict.fromkeys(relpaths)
|
return dict.fromkeys(relpaths)
|
||||||
|
|
||||||
@read_api
|
@read_api
|
||||||
def list_extra_files(self, book_id, use_cache=False, pattern='') -> Tuple[ExtraFile, ...]:
|
def list_extra_files(self, book_id, use_cache=False, pattern='') -> tuple[ExtraFile, ...]:
|
||||||
'''
|
'''
|
||||||
Get information about extra files in the book's directory.
|
Get information about extra files in the book's directory.
|
||||||
|
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
# License: GPLv3 Copyright: 2023, Kovid Goyal <kovid at kovidgoyal.net>
|
# License: GPLv3 Copyright: 2023, Kovid Goyal <kovid at kovidgoyal.net>
|
||||||
|
|
||||||
|
from collections.abc import Sequence
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
from typing import Sequence
|
|
||||||
|
|
||||||
COVER_FILE_NAME = 'cover.jpg'
|
COVER_FILE_NAME = 'cover.jpg'
|
||||||
METADATA_FILE_NAME = 'metadata.opf'
|
METADATA_FILE_NAME = 'metadata.opf'
|
||||||
|
@ -7,9 +7,9 @@ __docformat__ = 'restructuredtext en'
|
|||||||
|
|
||||||
import sys
|
import sys
|
||||||
from collections import Counter, defaultdict
|
from collections import Counter, defaultdict
|
||||||
|
from collections.abc import Iterable
|
||||||
from functools import partial
|
from functools import partial
|
||||||
from threading import Lock
|
from threading import Lock
|
||||||
from typing import Iterable
|
|
||||||
|
|
||||||
from calibre.db.tables import MANY_MANY, MANY_ONE, ONE_ONE, null
|
from calibre.db.tables import MANY_MANY, MANY_ONE, ONE_ONE, null
|
||||||
from calibre.db.utils import atof, force_to_bool
|
from calibre.db.utils import atof, force_to_bool
|
||||||
|
@ -8,7 +8,6 @@ import time
|
|||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
from contextlib import suppress
|
from contextlib import suppress
|
||||||
from itertools import count, repeat
|
from itertools import count, repeat
|
||||||
from typing import Optional
|
|
||||||
|
|
||||||
import apsw
|
import apsw
|
||||||
import xxhash
|
import xxhash
|
||||||
@ -368,7 +367,7 @@ class Notes:
|
|||||||
name = f'{base_name}-{c}{ext}'
|
name = f'{base_name}-{c}{ext}'
|
||||||
return resource_hash
|
return resource_hash
|
||||||
|
|
||||||
def get_resource_data(self, conn, resource_hash) -> Optional[dict]:
|
def get_resource_data(self, conn, resource_hash) -> dict | None:
|
||||||
ans = None
|
ans = None
|
||||||
for (name,) in conn.execute('SELECT name FROM notes_db.resources WHERE hash=?', (resource_hash,)):
|
for (name,) in conn.execute('SELECT name FROM notes_db.resources WHERE hash=?', (resource_hash,)):
|
||||||
path = self.path_for_resource(resource_hash)
|
path = self.path_for_resource(resource_hash)
|
||||||
|
@ -7,8 +7,8 @@ __docformat__ = 'restructuredtext en'
|
|||||||
|
|
||||||
import numbers
|
import numbers
|
||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
|
from collections.abc import Iterable
|
||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta
|
||||||
from typing import Iterable
|
|
||||||
|
|
||||||
from calibre.ebooks.metadata import author_to_author_sort
|
from calibre.ebooks.metadata import author_to_author_sort
|
||||||
from calibre.utils.date import UNDEFINED_DATE, parse_date, utc_tz
|
from calibre.utils.date import UNDEFINED_DATE, parse_date, utc_tz
|
||||||
|
@ -2,7 +2,6 @@ __license__ = 'GPL v3'
|
|||||||
__copyright__ = '2011, John Schember <john at nachtimwald.com>, refactored: 2022, Vaso Peras-Likodric <vaso at vipl.in.rs>'
|
__copyright__ = '2011, John Schember <john at nachtimwald.com>, refactored: 2022, Vaso Peras-Likodric <vaso at vipl.in.rs>'
|
||||||
__docformat__ = 'restructuredtext en'
|
__docformat__ = 'restructuredtext en'
|
||||||
|
|
||||||
from typing import Dict, Optional
|
|
||||||
|
|
||||||
'''
|
'''
|
||||||
Generates and writes an APNX page mapping file.
|
Generates and writes an APNX page mapping file.
|
||||||
@ -29,14 +28,14 @@ class APNXBuilder:
|
|||||||
Create an APNX file using a pseudo page mapping.
|
Create an APNX file using a pseudo page mapping.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
generators: Dict[str, IPageGenerator] = {
|
generators: dict[str, IPageGenerator] = {
|
||||||
FastPageGenerator.instance.name(): FastPageGenerator.instance,
|
FastPageGenerator.instance.name(): FastPageGenerator.instance,
|
||||||
AccuratePageGenerator.instance.name(): AccuratePageGenerator.instance,
|
AccuratePageGenerator.instance.name(): AccuratePageGenerator.instance,
|
||||||
PagebreakPageGenerator.instance.name(): PagebreakPageGenerator.instance,
|
PagebreakPageGenerator.instance.name(): PagebreakPageGenerator.instance,
|
||||||
# ExactPageGenerator.instance.name(): ExactPageGenerator.instance,
|
# ExactPageGenerator.instance.name(): ExactPageGenerator.instance,
|
||||||
}
|
}
|
||||||
|
|
||||||
def write_apnx(self, mobi_file_path: str, apnx_path: str, method: Optional[str] = None, page_count: int = 0):
|
def write_apnx(self, mobi_file_path: str, apnx_path: str, method: str | None = None, page_count: int = 0):
|
||||||
"""
|
"""
|
||||||
If you want a fixed number of pages (such as from a custom column) then
|
If you want a fixed number of pages (such as from a custom column) then
|
||||||
pass in a value to page_count, otherwise a count will be estimated
|
pass in a value to page_count, otherwise a count will be estimated
|
||||||
@ -61,7 +60,7 @@ class APNXBuilder:
|
|||||||
fsync(apnxf)
|
fsync(apnxf)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_apnx_meta(mobi_file_path) -> Dict[str, str]:
|
def get_apnx_meta(mobi_file_path) -> dict[str, str]:
|
||||||
import uuid
|
import uuid
|
||||||
apnx_meta = {
|
apnx_meta = {
|
||||||
'guid': str(uuid.uuid4()).replace('-', '')[:8],
|
'guid': str(uuid.uuid4()).replace('-', '')[:8],
|
||||||
|
@ -2,7 +2,6 @@ __license__ = 'GPL v3'
|
|||||||
__copyright__ = '2022, Vaso Peras-Likodric <vaso at vipl.in.rs>'
|
__copyright__ = '2022, Vaso Peras-Likodric <vaso at vipl.in.rs>'
|
||||||
__docformat__ = 'restructuredtext en'
|
__docformat__ = 'restructuredtext en'
|
||||||
|
|
||||||
from typing import Optional
|
|
||||||
|
|
||||||
from calibre.devices.kindle.apnx_page_generator.generators.fast_page_generator import FastPageGenerator
|
from calibre.devices.kindle.apnx_page_generator.generators.fast_page_generator import FastPageGenerator
|
||||||
from calibre.devices.kindle.apnx_page_generator.i_page_generator import IPageGenerator, mobi_html
|
from calibre.devices.kindle.apnx_page_generator.i_page_generator import IPageGenerator, mobi_html
|
||||||
@ -16,10 +15,10 @@ class AccuratePageGenerator(IPageGenerator):
|
|||||||
def name(self) -> str:
|
def name(self) -> str:
|
||||||
return "accurate"
|
return "accurate"
|
||||||
|
|
||||||
def _generate_fallback(self, mobi_file_path: str, real_count: Optional[int]) -> Pages:
|
def _generate_fallback(self, mobi_file_path: str, real_count: int | None) -> Pages:
|
||||||
return FastPageGenerator.instance.generate(mobi_file_path, real_count)
|
return FastPageGenerator.instance.generate(mobi_file_path, real_count)
|
||||||
|
|
||||||
def _generate(self, mobi_file_path: str, real_count: Optional[int]) -> Pages:
|
def _generate(self, mobi_file_path: str, real_count: int | None) -> Pages:
|
||||||
"""
|
"""
|
||||||
A more accurate but much more resource intensive and slower
|
A more accurate but much more resource intensive and slower
|
||||||
method to calculate the page length.
|
method to calculate the page length.
|
||||||
|
@ -2,7 +2,6 @@ __license__ = 'GPL v3'
|
|||||||
__copyright__ = '2022, Vaso Peras-Likodric <vaso at vipl.in.rs>'
|
__copyright__ = '2022, Vaso Peras-Likodric <vaso at vipl.in.rs>'
|
||||||
__docformat__ = 'restructuredtext en'
|
__docformat__ = 'restructuredtext en'
|
||||||
|
|
||||||
from typing import Optional
|
|
||||||
|
|
||||||
from calibre.devices.kindle.apnx_page_generator.generators.fast_page_generator import FastPageGenerator
|
from calibre.devices.kindle.apnx_page_generator.generators.fast_page_generator import FastPageGenerator
|
||||||
from calibre.devices.kindle.apnx_page_generator.i_page_generator import IPageGenerator, mobi_html_length
|
from calibre.devices.kindle.apnx_page_generator.i_page_generator import IPageGenerator, mobi_html_length
|
||||||
@ -16,10 +15,10 @@ class ExactPageGenerator(IPageGenerator):
|
|||||||
def name(self) -> str:
|
def name(self) -> str:
|
||||||
return "exact"
|
return "exact"
|
||||||
|
|
||||||
def _generate_fallback(self, mobi_file_path: str, real_count: Optional[int]) -> Pages:
|
def _generate_fallback(self, mobi_file_path: str, real_count: int | None) -> Pages:
|
||||||
return FastPageGenerator.instance.generate(mobi_file_path, real_count)
|
return FastPageGenerator.instance.generate(mobi_file_path, real_count)
|
||||||
|
|
||||||
def _generate(self, mobi_file_path: str, real_count: Optional[int]) -> Pages:
|
def _generate(self, mobi_file_path: str, real_count: int | None) -> Pages:
|
||||||
"""
|
"""
|
||||||
Given a specified page count (such as from a custom column),
|
Given a specified page count (such as from a custom column),
|
||||||
create our array of pages for the apnx file by dividing by
|
create our array of pages for the apnx file by dividing by
|
||||||
|
@ -2,7 +2,6 @@ __license__ = 'GPL v3'
|
|||||||
__copyright__ = '2022, Vaso Peras-Likodric <vaso at vipl.in.rs>'
|
__copyright__ = '2022, Vaso Peras-Likodric <vaso at vipl.in.rs>'
|
||||||
__docformat__ = 'restructuredtext en'
|
__docformat__ = 'restructuredtext en'
|
||||||
|
|
||||||
from typing import Optional
|
|
||||||
|
|
||||||
from calibre.devices.kindle.apnx_page_generator.i_page_generator import IPageGenerator, mobi_html_length
|
from calibre.devices.kindle.apnx_page_generator.i_page_generator import IPageGenerator, mobi_html_length
|
||||||
from calibre.devices.kindle.apnx_page_generator.pages import Pages
|
from calibre.devices.kindle.apnx_page_generator.pages import Pages
|
||||||
@ -13,10 +12,10 @@ class FastPageGenerator(IPageGenerator):
|
|||||||
def name(self) -> str:
|
def name(self) -> str:
|
||||||
return "fast"
|
return "fast"
|
||||||
|
|
||||||
def _generate_fallback(self, mobi_file_path: str, real_count: Optional[int]) -> Pages:
|
def _generate_fallback(self, mobi_file_path: str, real_count: int | None) -> Pages:
|
||||||
raise Exception("Fast calculation impossible.")
|
raise Exception("Fast calculation impossible.")
|
||||||
|
|
||||||
def _generate(self, mobi_file_path: str, real_count: Optional[int]) -> Pages:
|
def _generate(self, mobi_file_path: str, real_count: int | None) -> Pages:
|
||||||
"""
|
"""
|
||||||
2300 characters of uncompressed text per page. This is
|
2300 characters of uncompressed text per page. This is
|
||||||
not meant to map 1 to 1 to a print book but to be a
|
not meant to map 1 to 1 to a print book but to be a
|
||||||
|
@ -3,7 +3,6 @@ __copyright__ = '2022, Vaso Peras-Likodric <vaso at vipl.in.rs>'
|
|||||||
__docformat__ = 'restructuredtext en'
|
__docformat__ = 'restructuredtext en'
|
||||||
|
|
||||||
import re
|
import re
|
||||||
from typing import Optional
|
|
||||||
|
|
||||||
from calibre.devices.kindle.apnx_page_generator.generators.fast_page_generator import FastPageGenerator
|
from calibre.devices.kindle.apnx_page_generator.generators.fast_page_generator import FastPageGenerator
|
||||||
from calibre.devices.kindle.apnx_page_generator.i_page_generator import IPageGenerator, mobi_html
|
from calibre.devices.kindle.apnx_page_generator.i_page_generator import IPageGenerator, mobi_html
|
||||||
@ -15,10 +14,10 @@ class PagebreakPageGenerator(IPageGenerator):
|
|||||||
def name(self) -> str:
|
def name(self) -> str:
|
||||||
return "pagebreak"
|
return "pagebreak"
|
||||||
|
|
||||||
def _generate_fallback(self, mobi_file_path: str, real_count: Optional[int]) -> Pages:
|
def _generate_fallback(self, mobi_file_path: str, real_count: int | None) -> Pages:
|
||||||
return FastPageGenerator.instance.generate(mobi_file_path, real_count)
|
return FastPageGenerator.instance.generate(mobi_file_path, real_count)
|
||||||
|
|
||||||
def _generate(self, mobi_file_path: str, real_count: Optional[int]) -> Pages:
|
def _generate(self, mobi_file_path: str, real_count: int | None) -> Pages:
|
||||||
""" Determine pages based on the presence of <*pagebreak*/>. """
|
""" Determine pages based on the presence of <*pagebreak*/>. """
|
||||||
html = mobi_html(mobi_file_path)
|
html = mobi_html(mobi_file_path)
|
||||||
pages = []
|
pages = []
|
||||||
|
@ -4,7 +4,6 @@ __docformat__ = 'restructuredtext en'
|
|||||||
|
|
||||||
import struct
|
import struct
|
||||||
from abc import ABCMeta, abstractmethod
|
from abc import ABCMeta, abstractmethod
|
||||||
from typing import Optional
|
|
||||||
|
|
||||||
from calibre.devices.kindle.apnx_page_generator.pages import Pages
|
from calibre.devices.kindle.apnx_page_generator.pages import Pages
|
||||||
from calibre.ebooks.pdb.header import PdbHeaderReader
|
from calibre.ebooks.pdb.header import PdbHeaderReader
|
||||||
@ -15,14 +14,14 @@ from polyglot.builtins import as_bytes
|
|||||||
class IPageGenerator(metaclass=ABCMeta):
|
class IPageGenerator(metaclass=ABCMeta):
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def _generate(self, mobi_file_path: str, real_count: Optional[int]) -> Pages:
|
def _generate(self, mobi_file_path: str, real_count: int | None) -> Pages:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def _generate_fallback(self, mobi_file_path: str, real_count: Optional[int]) -> Pages:
|
def _generate_fallback(self, mobi_file_path: str, real_count: int | None) -> Pages:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def generate(self, mobi_file_path: str, real_count: Optional[int]) -> Pages:
|
def generate(self, mobi_file_path: str, real_count: int | None) -> Pages:
|
||||||
try:
|
try:
|
||||||
result = self._generate(mobi_file_path, real_count)
|
result = self._generate(mobi_file_path, real_count)
|
||||||
if result.number_of_pages > 0:
|
if result.number_of_pages > 0:
|
||||||
|
@ -2,32 +2,31 @@ __license__ = 'GPL v3'
|
|||||||
__copyright__ = '2022, Vaso Peras-Likodric <vaso at vipl.in.rs>'
|
__copyright__ = '2022, Vaso Peras-Likodric <vaso at vipl.in.rs>'
|
||||||
__docformat__ = 'restructuredtext en'
|
__docformat__ = 'restructuredtext en'
|
||||||
|
|
||||||
from typing import List, Tuple, Union
|
|
||||||
|
|
||||||
from calibre.devices.kindle.apnx_page_generator.page_number_type import PageNumberTypes
|
from calibre.devices.kindle.apnx_page_generator.page_number_type import PageNumberTypes
|
||||||
|
|
||||||
|
|
||||||
class PageGroup:
|
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: int | list[int], page_number_type: PageNumberTypes, first_value: int,
|
||||||
page_labels: Union[str, List[str], None] = None):
|
page_labels: str | list[str] | None = None):
|
||||||
if page_locations.__class__ is 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
|
||||||
self.__page_number_type: PageNumberTypes = page_number_type
|
self.__page_number_type: PageNumberTypes = page_number_type
|
||||||
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__ is 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:
|
||||||
assert len(page_labels) == len(self.page_locations)
|
assert len(page_labels) == len(self.page_locations)
|
||||||
assert all(len(label) > 0 for label in page_labels)
|
assert all(len(label) > 0 for label in page_labels)
|
||||||
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: int | tuple[int, str]) -> None:
|
||||||
if page_location.__class__ is 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)
|
||||||
@ -54,4 +53,4 @@ class PageGroup:
|
|||||||
values = str(self.__first_value)
|
values = str(self.__first_value)
|
||||||
else:
|
else:
|
||||||
values = "|".join(self.__page_number_labels)
|
values = "|".join(self.__page_number_labels)
|
||||||
return "({},{},{})".format(starting_location, self.__page_number_type.value, values)
|
return f"({starting_location},{self.__page_number_type.value},{values})"
|
||||||
|
@ -3,18 +3,17 @@ __copyright__ = '2022, Vaso Peras-Likodric <vaso at vipl.in.rs>'
|
|||||||
__docformat__ = 'restructuredtext en'
|
__docformat__ = 'restructuredtext en'
|
||||||
|
|
||||||
import itertools
|
import itertools
|
||||||
from typing import List, Optional
|
|
||||||
|
|
||||||
from calibre.devices.kindle.apnx_page_generator.page_group import PageGroup
|
from calibre.devices.kindle.apnx_page_generator.page_group import PageGroup
|
||||||
from calibre.devices.kindle.apnx_page_generator.page_number_type import PageNumberTypes
|
from calibre.devices.kindle.apnx_page_generator.page_number_type import PageNumberTypes
|
||||||
|
|
||||||
|
|
||||||
class Pages:
|
class Pages:
|
||||||
def __init__(self, page_locations: Optional[List[int]] = None):
|
def __init__(self, page_locations: list[int] | None = None):
|
||||||
if page_locations.__class__ is 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] = []
|
||||||
|
|
||||||
def append(self, page_location: PageGroup) -> None:
|
def append(self, page_location: PageGroup) -> None:
|
||||||
self.__pages_groups.append(page_location)
|
self.__pages_groups.append(page_location)
|
||||||
@ -34,7 +33,7 @@ class Pages:
|
|||||||
return ",".join(result)
|
return ",".join(result)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def page_locations(self) -> List[int]:
|
def page_locations(self) -> list[int]:
|
||||||
return list(itertools.chain.from_iterable(list(map(lambda pg: pg.page_locations, self.__pages_groups))))
|
return list(itertools.chain.from_iterable(list(map(lambda pg: pg.page_locations, self.__pages_groups))))
|
||||||
|
|
||||||
@property
|
@property
|
||||||
|
@ -12,8 +12,9 @@ import os
|
|||||||
import posixpath
|
import posixpath
|
||||||
import sys
|
import sys
|
||||||
import traceback
|
import traceback
|
||||||
|
from collections.abc import Sequence
|
||||||
from io import BytesIO
|
from io import BytesIO
|
||||||
from typing import NamedTuple, Sequence
|
from typing import NamedTuple
|
||||||
|
|
||||||
from calibre import prints
|
from calibre import prints
|
||||||
from calibre.constants import iswindows, numeric_version
|
from calibre.constants import iswindows, numeric_version
|
||||||
|
@ -13,7 +13,6 @@ from collections import defaultdict, deque
|
|||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from itertools import chain
|
from itertools import chain
|
||||||
from operator import attrgetter
|
from operator import attrgetter
|
||||||
from typing import Dict, Tuple
|
|
||||||
|
|
||||||
from calibre import force_unicode, human_readable, prints
|
from calibre import force_unicode, human_readable, prints
|
||||||
from calibre.constants import iswindows
|
from calibre.constants import iswindows
|
||||||
@ -121,7 +120,7 @@ class FileOrFolder:
|
|||||||
return not self.files and not self.folders
|
return not self.files and not self.folders
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def id_map(self) -> Dict[int, 'FileOrFolder']:
|
def id_map(self) -> dict[int, 'FileOrFolder']:
|
||||||
return self.fs_cache().id_maps[self.storage_id]
|
return self.fs_cache().id_maps[self.storage_id]
|
||||||
|
|
||||||
@property
|
@property
|
||||||
@ -141,7 +140,7 @@ class FileOrFolder:
|
|||||||
return self.fs_cache().storage(self.storage_id)
|
return self.fs_cache().storage(self.storage_id)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def full_path(self) -> Tuple[str, ...]:
|
def full_path(self) -> tuple[str, ...]:
|
||||||
parts = deque()
|
parts = deque()
|
||||||
parts.append(self.name)
|
parts.append(self.name)
|
||||||
p = self.parent
|
p = self.parent
|
||||||
|
@ -159,7 +159,7 @@ class ConnectionListener(Thread):
|
|||||||
device_socket = None
|
device_socket = None
|
||||||
self.driver._debug('driver is not answering')
|
self.driver._debug('driver is not answering')
|
||||||
|
|
||||||
except socket.timeout:
|
except TimeoutError:
|
||||||
pass
|
pass
|
||||||
except OSError:
|
except OSError:
|
||||||
x = sys.exc_info()[1]
|
x = sys.exc_info()[1]
|
||||||
@ -648,7 +648,7 @@ class SMART_DEVICE_APP(DeviceConfig, DevicePlugin):
|
|||||||
if not wait_for_response:
|
if not wait_for_response:
|
||||||
return None, None
|
return None, None
|
||||||
return self._receive_from_client(print_debug_info=print_debug_info)
|
return self._receive_from_client(print_debug_info=print_debug_info)
|
||||||
except socket.timeout:
|
except TimeoutError:
|
||||||
self._debug('timeout communicating with device')
|
self._debug('timeout communicating with device')
|
||||||
self._close_device_socket()
|
self._close_device_socket()
|
||||||
raise TimeoutError('Device did not respond in reasonable time')
|
raise TimeoutError('Device did not respond in reasonable time')
|
||||||
@ -676,7 +676,7 @@ class SMART_DEVICE_APP(DeviceConfig, DevicePlugin):
|
|||||||
self._debug('receive after decode') # , v)
|
self._debug('receive after decode') # , v)
|
||||||
return (self.reverse_opcodes[v[0]], v[1])
|
return (self.reverse_opcodes[v[0]], v[1])
|
||||||
self._debug('protocol error -- empty json string')
|
self._debug('protocol error -- empty json string')
|
||||||
except socket.timeout:
|
except TimeoutError:
|
||||||
self._debug('timeout communicating with device')
|
self._debug('timeout communicating with device')
|
||||||
self._close_device_socket()
|
self._close_device_socket()
|
||||||
raise TimeoutError('Device did not respond in reasonable time')
|
raise TimeoutError('Device did not respond in reasonable time')
|
||||||
@ -1202,7 +1202,7 @@ class SMART_DEVICE_APP(DeviceConfig, DevicePlugin):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
return True
|
return True
|
||||||
except socket.timeout:
|
except TimeoutError:
|
||||||
self._close_device_socket()
|
self._close_device_socket()
|
||||||
except OSError:
|
except OSError:
|
||||||
x = sys.exc_info()[1]
|
x = sys.exc_info()[1]
|
||||||
|
@ -61,7 +61,7 @@ class PDFInput(InputFormatPlugin):
|
|||||||
from calibre.ebooks.pdf.reflow import PDFDocument
|
from calibre.ebooks.pdf.reflow import PDFDocument
|
||||||
from calibre.utils.cleantext import clean_ascii_chars
|
from calibre.utils.cleantext import clean_ascii_chars
|
||||||
pdftohtml(os.getcwd(), stream.name, self.opts.no_images, as_xml=True)
|
pdftohtml(os.getcwd(), stream.name, self.opts.no_images, as_xml=True)
|
||||||
with open(u'index.xml', 'rb') as f:
|
with open('index.xml', 'rb') as f:
|
||||||
xml = clean_ascii_chars(f.read())
|
xml = clean_ascii_chars(f.read())
|
||||||
PDFDocument(xml, self.opts, self.log)
|
PDFDocument(xml, self.opts, self.log)
|
||||||
else:
|
else:
|
||||||
|
@ -40,7 +40,7 @@ class FDST:
|
|||||||
def __str__(self):
|
def __str__(self):
|
||||||
ans = ['FDST record']
|
ans = ['FDST record']
|
||||||
def a(k, v):
|
def a(k, v):
|
||||||
return ans.append('{}: {}'.format(k, v))
|
return ans.append(f'{k}: {v}')
|
||||||
a('Offset to sections', self.sec_off)
|
a('Offset to sections', self.sec_off)
|
||||||
a('Number of section records', self.num_sections)
|
a('Number of section records', self.num_sections)
|
||||||
ans.append('**** %d Sections ****'% len(self.sections))
|
ans.append('**** %d Sections ****'% len(self.sections))
|
||||||
|
@ -14,7 +14,6 @@ import sys
|
|||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
from itertools import count
|
from itertools import count
|
||||||
from operator import attrgetter
|
from operator import attrgetter
|
||||||
from typing import Optional
|
|
||||||
|
|
||||||
from lxml import etree, html
|
from lxml import etree, html
|
||||||
|
|
||||||
@ -1027,7 +1026,7 @@ class Manifest:
|
|||||||
# }}}
|
# }}}
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def data_as_bytes_or_none(self) -> Optional[bytes]:
|
def data_as_bytes_or_none(self) -> bytes | None:
|
||||||
if self._loader is None:
|
if self._loader is None:
|
||||||
return None
|
return None
|
||||||
return self._loader(getattr(self, 'html_input_href', self.href))
|
return self._loader(getattr(self, 'html_input_href', self.href))
|
||||||
|
@ -385,7 +385,7 @@ class Text(Element):
|
|||||||
return self.raw
|
return self.raw
|
||||||
|
|
||||||
def dump(self, f):
|
def dump(self, f):
|
||||||
f.write('T top={}, left={}, width={}, height={}: '.format(self.top, self.left, self.width, self.height))
|
f.write(f'T top={self.top}, left={self.left}, width={self.width}, height={self.height}: ')
|
||||||
f.write(self.to_html().encode('utf-8'))
|
f.write(self.to_html().encode('utf-8'))
|
||||||
f.write('\n')
|
f.write('\n')
|
||||||
|
|
||||||
@ -422,7 +422,7 @@ class Paragraph(Text):
|
|||||||
return self.raw
|
return self.raw
|
||||||
|
|
||||||
def dump(self, f):
|
def dump(self, f):
|
||||||
f.write('P top={}, left={}, width={}, height={}: '.format(self.top, self.left, self.width, self.height))
|
f.write(f'P top={self.top}, left={self.left}, width={self.width}, height={self.height}: ')
|
||||||
f.write(self.to_html().encode('utf-8'))
|
f.write(self.to_html().encode('utf-8'))
|
||||||
f.write('\n')
|
f.write('\n')
|
||||||
|
|
||||||
|
@ -1,6 +1,3 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
|
|
||||||
__license__ = 'GPL 3'
|
__license__ = 'GPL 3'
|
||||||
__copyright__ = '2010 Hiroshi Miura <miurahr@linux.com>'
|
__copyright__ = '2010 Hiroshi Miura <miurahr@linux.com>'
|
||||||
__docformat__ = 'restructuredtext en'
|
__docformat__ = 'restructuredtext en'
|
||||||
|
@ -1,6 +1,3 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
|
|
||||||
__license__ = 'GPL 3'
|
__license__ = 'GPL 3'
|
||||||
__copyright__ = '2010 Hiroshi Miura <miurahr@linux.com>'
|
__copyright__ = '2010 Hiroshi Miura <miurahr@linux.com>'
|
||||||
__docformat__ = 'restructuredtext en'
|
__docformat__ = 'restructuredtext en'
|
||||||
|
@ -1,6 +1,3 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
|
|
||||||
__license__ = 'GPL 3'
|
__license__ = 'GPL 3'
|
||||||
__copyright__ = '2009, John Schember <john@nachtimwald.com>'
|
__copyright__ = '2009, John Schember <john@nachtimwald.com>'
|
||||||
__docformat__ = 'restructuredtext en'
|
__docformat__ = 'restructuredtext en'
|
||||||
|
@ -1,6 +1,3 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
|
|
||||||
__license__ = 'GPL 3'
|
__license__ = 'GPL 3'
|
||||||
__copyright__ = '2010 Hiroshi Miura <miurahr@linux.com>'
|
__copyright__ = '2010 Hiroshi Miura <miurahr@linux.com>'
|
||||||
__docformat__ = 'restructuredtext en'
|
__docformat__ = 'restructuredtext en'
|
||||||
|
@ -1,6 +1,3 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
|
|
||||||
__license__ = 'GPL 3'
|
__license__ = 'GPL 3'
|
||||||
__copyright__ = '2010 Hiroshi Miura <miurahr@linux.com>'
|
__copyright__ = '2010 Hiroshi Miura <miurahr@linux.com>'
|
||||||
__docformat__ = 'restructuredtext en'
|
__docformat__ = 'restructuredtext en'
|
||||||
|
@ -106,7 +106,7 @@ class AllGUIActions(InterfaceAction):
|
|||||||
for n,v in kbd.keys_map.items():
|
for n,v in kbd.keys_map.items():
|
||||||
act_name = kbd.shortcuts[n]['name'].lower()
|
act_name = kbd.shortcuts[n]['name'].lower()
|
||||||
if act_name in lower_names:
|
if act_name in lower_names:
|
||||||
shortcuts = list((sc.toString() for sc in v))
|
shortcuts = list(sc.toString() for sc in v)
|
||||||
shortcut_map[act_name] = f'\t{", ".join(shortcuts)}'
|
shortcut_map[act_name] = f'\t{", ".join(shortcuts)}'
|
||||||
|
|
||||||
# This function constructs a menu action, dealing with the action being
|
# This function constructs a menu action, dealing with the action being
|
||||||
|
@ -97,12 +97,12 @@ class DocViewer(Dialog):
|
|||||||
|
|
||||||
b = self.back_button = self.bb.addButton(_('&Back'), QDialogButtonBox.ButtonRole.ActionRole)
|
b = self.back_button = self.bb.addButton(_('&Back'), QDialogButtonBox.ButtonRole.ActionRole)
|
||||||
b.clicked.connect(self.back)
|
b.clicked.connect(self.back)
|
||||||
b.setToolTip((_('Displays the previously viewed function')))
|
b.setToolTip(_('Displays the previously viewed function'))
|
||||||
b.setEnabled(False)
|
b.setEnabled(False)
|
||||||
|
|
||||||
b = self.bb.addButton(_('Show &all functions'), QDialogButtonBox.ButtonRole.ActionRole)
|
b = self.bb.addButton(_('Show &all functions'), QDialogButtonBox.ButtonRole.ActionRole)
|
||||||
b.clicked.connect(self.show_all_functions_button_clicked)
|
b.clicked.connect(self.show_all_functions_button_clicked)
|
||||||
b.setToolTip((_('Shows a list of all built-in functions in alphabetic order')))
|
b.setToolTip(_('Shows a list of all built-in functions in alphabetic order'))
|
||||||
|
|
||||||
def back(self):
|
def back(self):
|
||||||
if not self.back_stack:
|
if not self.back_stack:
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
|
|
||||||
from time import monotonic
|
from time import monotonic
|
||||||
from typing import NamedTuple, Tuple
|
from typing import NamedTuple
|
||||||
|
|
||||||
from qt.core import QObject, QTimer, pyqtSignal
|
from qt.core import QObject, QTimer, pyqtSignal
|
||||||
|
|
||||||
@ -18,7 +18,7 @@ class ExtraFile(NamedTuple):
|
|||||||
|
|
||||||
class ExtraFiles(NamedTuple):
|
class ExtraFiles(NamedTuple):
|
||||||
last_changed_at: float
|
last_changed_at: float
|
||||||
files: Tuple[ExtraFile, ...]
|
files: tuple[ExtraFile, ...]
|
||||||
|
|
||||||
|
|
||||||
class ExtraFilesWatcher(QObject):
|
class ExtraFilesWatcher(QObject):
|
||||||
|
@ -3,8 +3,8 @@
|
|||||||
|
|
||||||
import time
|
import time
|
||||||
import traceback
|
import traceback
|
||||||
|
from collections.abc import Iterator
|
||||||
from operator import attrgetter
|
from operator import attrgetter
|
||||||
from typing import Iterator, List
|
|
||||||
|
|
||||||
from qt.core import (
|
from qt.core import (
|
||||||
QAbstractItemView,
|
QAbstractItemView,
|
||||||
@ -102,7 +102,7 @@ class TrashList(QListWidget):
|
|||||||
|
|
||||||
restore_item = pyqtSignal(object, object)
|
restore_item = pyqtSignal(object, object)
|
||||||
|
|
||||||
def __init__(self, entries: List[TrashEntry], parent: 'TrashView', is_books: bool):
|
def __init__(self, entries: list[TrashEntry], parent: 'TrashView', is_books: bool):
|
||||||
super().__init__(parent)
|
super().__init__(parent)
|
||||||
self.is_books = is_books
|
self.is_books = is_books
|
||||||
self.db = parent.db
|
self.db = parent.db
|
||||||
|
@ -8,12 +8,13 @@ import os
|
|||||||
import re
|
import re
|
||||||
import sys
|
import sys
|
||||||
from collections import deque
|
from collections import deque
|
||||||
|
from collections.abc import Iterable, Iterator
|
||||||
from contextlib import suppress
|
from contextlib import suppress
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
from functools import lru_cache
|
from functools import lru_cache
|
||||||
from itertools import count
|
from itertools import count
|
||||||
from time import monotonic
|
from time import monotonic
|
||||||
from typing import BinaryIO, Iterable, Iterator
|
from typing import BinaryIO
|
||||||
|
|
||||||
from qt.core import (
|
from qt.core import (
|
||||||
QAudio,
|
QAudio,
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
# License: GPL v3 Copyright: 2021, Kovid Goyal <kovid at kovidgoyal.net>
|
# License: GPL v3 Copyright: 2021, Kovid Goyal <kovid at kovidgoyal.net>
|
||||||
|
|
||||||
from contextlib import suppress
|
from contextlib import suppress
|
||||||
from typing import List, NamedTuple, Optional, Tuple
|
from typing import NamedTuple
|
||||||
|
|
||||||
from css_parser.css import CSSRule
|
from css_parser.css import CSSRule
|
||||||
from css_selectors import Select, SelectorError
|
from css_selectors import Select, SelectorError
|
||||||
@ -21,9 +21,9 @@ class NoMatchingRuleFound(KeyError):
|
|||||||
|
|
||||||
|
|
||||||
class RuleLocation(NamedTuple):
|
class RuleLocation(NamedTuple):
|
||||||
rule_address: List[int]
|
rule_address: list[int]
|
||||||
file_name: str
|
file_name: str
|
||||||
style_tag_address: Optional[Tuple[int, List[int]]] = None
|
style_tag_address: tuple[int, list[int]] | None = None
|
||||||
|
|
||||||
|
|
||||||
def rule_matches_elem(rule, elem, select, class_name):
|
def rule_matches_elem(rule, elem, select, class_name):
|
||||||
|
@ -13,7 +13,6 @@ import traceback
|
|||||||
from contextlib import suppress
|
from contextlib import suppress
|
||||||
from functools import lru_cache, partial
|
from functools import lru_cache, partial
|
||||||
from io import BytesIO
|
from io import BytesIO
|
||||||
from typing import Union
|
|
||||||
|
|
||||||
from calibre import as_unicode
|
from calibre import as_unicode
|
||||||
from calibre.constants import iswindows
|
from calibre.constants import iswindows
|
||||||
@ -162,7 +161,7 @@ def is_ip_trusted(remote_addr, trusted_ips):
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
def is_local_address(addr: Union[ipaddress.IPv4Address, ipaddress.IPv6Address, None]):
|
def is_local_address(addr: ipaddress.IPv4Address | ipaddress.IPv6Address | None):
|
||||||
if addr is None:
|
if addr is None:
|
||||||
return False
|
return False
|
||||||
if addr.is_loopback:
|
if addr.is_loopback:
|
||||||
|
@ -92,7 +92,7 @@ class LoopTest(BaseTest):
|
|||||||
with self.assertRaises(socket.timeout):
|
with self.assertRaises(socket.timeout):
|
||||||
res = conn.getresponse()
|
res = conn.getresponse()
|
||||||
if int(res.status) == int(http_client.REQUEST_TIMEOUT):
|
if int(res.status) == int(http_client.REQUEST_TIMEOUT):
|
||||||
raise socket.timeout('Timeout')
|
raise TimeoutError('Timeout')
|
||||||
raise Exception('Got unexpected response: code: {} {} headers: {!r} data: {!r}'.format(
|
raise Exception('Got unexpected response: code: {} {} headers: {!r} data: {!r}'.format(
|
||||||
res.status, res.reason, res.getheaders(), res.read()))
|
res.status, res.reason, res.getheaders(), res.read()))
|
||||||
self.ae(pool.busy, 1)
|
self.ae(pool.busy, 1)
|
||||||
|
@ -6,8 +6,8 @@ import shutil
|
|||||||
import stat
|
import stat
|
||||||
import time
|
import time
|
||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
|
from collections.abc import Callable
|
||||||
from contextlib import suppress
|
from contextlib import suppress
|
||||||
from typing import Callable, Dict, List, Set, Tuple, Union
|
|
||||||
|
|
||||||
from calibre.constants import filesystem_encoding, iswindows
|
from calibre.constants import filesystem_encoding, iswindows
|
||||||
from calibre.utils.filenames import make_long_path_useable, samefile, windows_hardlink
|
from calibre.utils.filenames import make_long_path_useable, samefile, windows_hardlink
|
||||||
@ -16,14 +16,14 @@ if iswindows:
|
|||||||
from calibre_extensions import winutil
|
from calibre_extensions import winutil
|
||||||
|
|
||||||
WINDOWS_SLEEP_FOR_RETRY_TIME = 2 # seconds
|
WINDOWS_SLEEP_FOR_RETRY_TIME = 2 # seconds
|
||||||
WindowsFileId = Tuple[int, int, int]
|
WindowsFileId = tuple[int, int, int]
|
||||||
|
|
||||||
class UnixFileCopier:
|
class UnixFileCopier:
|
||||||
|
|
||||||
def __init__(self, delete_all=False, allow_move=False):
|
def __init__(self, delete_all=False, allow_move=False):
|
||||||
self.delete_all = delete_all
|
self.delete_all = delete_all
|
||||||
self.allow_move = allow_move
|
self.allow_move = allow_move
|
||||||
self.copy_map: Dict[str, str] = {}
|
self.copy_map: dict[str, str] = {}
|
||||||
|
|
||||||
def register(self, path: str, dest: str) -> None:
|
def register(self, path: str, dest: str) -> None:
|
||||||
self.copy_map[path] = dest
|
self.copy_map[path] = dest
|
||||||
@ -81,12 +81,12 @@ class WindowsFileCopier:
|
|||||||
def __init__(self, delete_all=False, allow_move=False):
|
def __init__(self, delete_all=False, allow_move=False):
|
||||||
self.delete_all = delete_all
|
self.delete_all = delete_all
|
||||||
self.allow_move = allow_move
|
self.allow_move = allow_move
|
||||||
self.path_to_fileid_map : Dict[str, WindowsFileId] = {}
|
self.path_to_fileid_map : dict[str, WindowsFileId] = {}
|
||||||
self.fileid_to_paths_map: Dict[WindowsFileId, Set[str]] = defaultdict(set)
|
self.fileid_to_paths_map: dict[WindowsFileId, set[str]] = defaultdict(set)
|
||||||
self.path_to_handle_map: Dict[str, 'winutil.Handle'] = {}
|
self.path_to_handle_map: dict[str, 'winutil.Handle'] = {}
|
||||||
self.folder_to_handle_map: Dict[str, 'winutil.Handle'] = {}
|
self.folder_to_handle_map: dict[str, 'winutil.Handle'] = {}
|
||||||
self.folders: List[str] = []
|
self.folders: list[str] = []
|
||||||
self.copy_map: Dict[str, str] = {}
|
self.copy_map: dict[str, str] = {}
|
||||||
|
|
||||||
def register(self, path: str, dest: str) -> None:
|
def register(self, path: str, dest: str) -> None:
|
||||||
with suppress(OSError):
|
with suppress(OSError):
|
||||||
@ -184,11 +184,11 @@ class WindowsFileCopier:
|
|||||||
winutil.move_file(make_long_path_useable(src_path), make_long_path_useable(dest_path))
|
winutil.move_file(make_long_path_useable(src_path), make_long_path_useable(dest_path))
|
||||||
|
|
||||||
|
|
||||||
def get_copier(delete_all=False, allow_move=False) -> Union[UnixFileCopier, WindowsFileCopier]:
|
def get_copier(delete_all=False, allow_move=False) -> UnixFileCopier | WindowsFileCopier:
|
||||||
return (WindowsFileCopier if iswindows else UnixFileCopier)(delete_all, allow_move)
|
return (WindowsFileCopier if iswindows else UnixFileCopier)(delete_all, allow_move)
|
||||||
|
|
||||||
|
|
||||||
def rename_files(src_to_dest_map: Dict[str, str]) -> None:
|
def rename_files(src_to_dest_map: dict[str, str]) -> None:
|
||||||
' Rename a bunch of files. On Windows all files are locked before renaming so no other process can interfere. '
|
' Rename a bunch of files. On Windows all files are locked before renaming so no other process can interfere. '
|
||||||
copier = get_copier(allow_move=True)
|
copier = get_copier(allow_move=True)
|
||||||
for s, d in src_to_dest_map.items():
|
for s, d in src_to_dest_map.items():
|
||||||
@ -197,7 +197,7 @@ def rename_files(src_to_dest_map: Dict[str, str]) -> None:
|
|||||||
copier.rename_all()
|
copier.rename_all()
|
||||||
|
|
||||||
|
|
||||||
def copy_files(src_to_dest_map: Dict[str, str], delete_source: bool = False) -> None:
|
def copy_files(src_to_dest_map: dict[str, str], delete_source: bool = False) -> None:
|
||||||
copier = get_copier(delete_source)
|
copier = get_copier(delete_source)
|
||||||
for s, d in src_to_dest_map.items():
|
for s, d in src_to_dest_map.items():
|
||||||
if not samefile(s, d):
|
if not samefile(s, d):
|
||||||
@ -211,7 +211,7 @@ def identity_transform(src_path: str, dest_path: str) -> str:
|
|||||||
|
|
||||||
|
|
||||||
def register_folder_recursively(
|
def register_folder_recursively(
|
||||||
src: str, copier: Union[UnixFileCopier, WindowsFileCopier], dest_dir: str,
|
src: str, copier: UnixFileCopier | WindowsFileCopier, dest_dir: str,
|
||||||
transform_destination_filename: Callable[[str, str], str] = identity_transform,
|
transform_destination_filename: Callable[[str, str], str] = identity_transform,
|
||||||
read_only: bool = False
|
read_only: bool = False
|
||||||
) -> None:
|
) -> None:
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
# vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:fdm=marker:ai
|
|
||||||
|
|
||||||
|
|
||||||
__license__ = 'GPL v3'
|
__license__ = 'GPL v3'
|
||||||
|
@ -8,7 +8,6 @@ import os
|
|||||||
import secrets
|
import secrets
|
||||||
import stat
|
import stat
|
||||||
import struct
|
import struct
|
||||||
from typing import Optional, Union
|
|
||||||
|
|
||||||
from calibre.constants import ismacos, iswindows
|
from calibre.constants import ismacos, iswindows
|
||||||
|
|
||||||
@ -44,7 +43,7 @@ class SharedMemory:
|
|||||||
'''
|
'''
|
||||||
_fd: int = -1
|
_fd: int = -1
|
||||||
_name: str = ''
|
_name: str = ''
|
||||||
_mmap: Optional[mmap.mmap] = None
|
_mmap: mmap.mmap | None = None
|
||||||
_size: int = 0
|
_size: int = 0
|
||||||
size_fmt = '!I'
|
size_fmt = '!I'
|
||||||
num_bytes_for_size = struct.calcsize(size_fmt)
|
num_bytes_for_size = struct.calcsize(size_fmt)
|
||||||
@ -158,7 +157,7 @@ class SharedMemory:
|
|||||||
def flush(self) -> None:
|
def flush(self) -> None:
|
||||||
self.mmap.flush()
|
self.mmap.flush()
|
||||||
|
|
||||||
def write_data_with_size(self, data: Union[str, bytes]) -> None:
|
def write_data_with_size(self, data: str | bytes) -> None:
|
||||||
if isinstance(data, str):
|
if isinstance(data, str):
|
||||||
data = data.encode('utf-8')
|
data = data.encode('utf-8')
|
||||||
sz = struct.pack(self.size_fmt, len(data))
|
sz = struct.pack(self.size_fmt, len(data))
|
||||||
|
@ -9,9 +9,10 @@ import calendar
|
|||||||
import json
|
import json
|
||||||
import os
|
import os
|
||||||
import zipfile
|
import zipfile
|
||||||
|
from collections.abc import Sequence
|
||||||
from datetime import timedelta
|
from datetime import timedelta
|
||||||
from threading import RLock
|
from threading import RLock
|
||||||
from typing import Dict, NamedTuple, Optional, Sequence
|
from typing import NamedTuple
|
||||||
|
|
||||||
from lxml import etree
|
from lxml import etree
|
||||||
from lxml.builder import ElementMaker
|
from lxml.builder import ElementMaker
|
||||||
@ -298,7 +299,7 @@ class RecipeCustomization(NamedTuple):
|
|||||||
add_title_tag: bool = False
|
add_title_tag: bool = False
|
||||||
custom_tags: Sequence[str] = ()
|
custom_tags: Sequence[str] = ()
|
||||||
keep_issues: int = 0
|
keep_issues: int = 0
|
||||||
recipe_specific_options: Optional[Dict[str, str]] = None
|
recipe_specific_options: dict[str, str] | None = None
|
||||||
|
|
||||||
|
|
||||||
class SchedulerConfig:
|
class SchedulerConfig:
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
|
|
||||||
from __future__ import absolute_import, division, print_function, unicode_literals
|
|
||||||
|
|
||||||
import json
|
import json
|
||||||
from pprint import pprint
|
from pprint import pprint
|
||||||
|
Loading…
x
Reference in New Issue
Block a user