mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Fix lack of thread saefty in template format system, that could lead to incorrect template evaluation in some cases. Fixes #801944 (Problem with metadata synch on Sony)
This commit is contained in:
commit
cde0352623
@ -14,7 +14,7 @@ from calibre.constants import preferred_encoding
|
|||||||
from calibre import isbytestring, force_unicode
|
from calibre import isbytestring, force_unicode
|
||||||
from calibre.utils.config import prefs, tweaks
|
from calibre.utils.config import prefs, tweaks
|
||||||
from calibre.utils.icu import strcmp
|
from calibre.utils.icu import strcmp
|
||||||
from calibre.utils.formatter import eval_formatter
|
from calibre.utils.formatter import EvalFormatter
|
||||||
|
|
||||||
class Book(Metadata):
|
class Book(Metadata):
|
||||||
def __init__(self, prefix, lpath, size=None, other=None):
|
def __init__(self, prefix, lpath, size=None, other=None):
|
||||||
@ -116,7 +116,7 @@ class CollectionsBookList(BookList):
|
|||||||
field_name = field_meta['name']
|
field_name = field_meta['name']
|
||||||
else:
|
else:
|
||||||
field_name = ''
|
field_name = ''
|
||||||
cat_name = eval_formatter.safe_format(
|
cat_name = EvalFormatter().safe_format(
|
||||||
fmt=tweaks['sony_collection_name_template'],
|
fmt=tweaks['sony_collection_name_template'],
|
||||||
kwargs={'category':field_name, 'value':field_value},
|
kwargs={'category':field_name, 'value':field_value},
|
||||||
error_value='GET_CATEGORY', book=None)
|
error_value='GET_CATEGORY', book=None)
|
||||||
|
@ -70,6 +70,7 @@ class SafeFormat(TemplateFormatter):
|
|||||||
return ''
|
return ''
|
||||||
return v
|
return v
|
||||||
|
|
||||||
|
# DEPRECATED. This is not thread safe. Do not use.
|
||||||
composite_formatter = SafeFormat()
|
composite_formatter = SafeFormat()
|
||||||
|
|
||||||
class Metadata(object):
|
class Metadata(object):
|
||||||
@ -110,6 +111,7 @@ class Metadata(object):
|
|||||||
# List of strings or []
|
# List of strings or []
|
||||||
self.author = list(authors) if authors else []# Needed for backward compatibility
|
self.author = list(authors) if authors else []# Needed for backward compatibility
|
||||||
self.authors = list(authors) if authors else []
|
self.authors = list(authors) if authors else []
|
||||||
|
self.formatter = SafeFormat()
|
||||||
|
|
||||||
def is_null(self, field):
|
def is_null(self, field):
|
||||||
'''
|
'''
|
||||||
@ -146,7 +148,7 @@ class Metadata(object):
|
|||||||
return val
|
return val
|
||||||
if val is None:
|
if val is None:
|
||||||
d['#value#'] = 'RECURSIVE_COMPOSITE FIELD (Metadata) ' + field
|
d['#value#'] = 'RECURSIVE_COMPOSITE FIELD (Metadata) ' + field
|
||||||
val = d['#value#'] = composite_formatter.safe_format(
|
val = d['#value#'] = self.formatter.safe_format(
|
||||||
d['display']['composite_template'],
|
d['display']['composite_template'],
|
||||||
self,
|
self,
|
||||||
_('TEMPLATE ERROR'),
|
_('TEMPLATE ERROR'),
|
||||||
@ -423,11 +425,12 @@ class Metadata(object):
|
|||||||
'''
|
'''
|
||||||
if not ops:
|
if not ops:
|
||||||
return
|
return
|
||||||
|
formatter = SafeFormat()
|
||||||
for op in ops:
|
for op in ops:
|
||||||
try:
|
try:
|
||||||
src = op[0]
|
src = op[0]
|
||||||
dest = op[1]
|
dest = op[1]
|
||||||
val = composite_formatter.safe_format\
|
val = formatter.safe_format\
|
||||||
(src, other, 'PLUGBOARD TEMPLATE ERROR', other)
|
(src, other, 'PLUGBOARD TEMPLATE ERROR', other)
|
||||||
if dest == 'tags':
|
if dest == 'tags':
|
||||||
self.set(dest, [f.strip() for f in val.split(',') if f.strip()])
|
self.set(dest, [f.strip() for f in val.split(',') if f.strip()])
|
||||||
|
@ -12,7 +12,7 @@ from PyQt4.Qt import Qt, QDialog, QGridLayout, QVBoxLayout, QFont, QLabel, \
|
|||||||
from calibre.gui2.dialogs.metadata_bulk_ui import Ui_MetadataBulkDialog
|
from calibre.gui2.dialogs.metadata_bulk_ui import Ui_MetadataBulkDialog
|
||||||
from calibre.gui2.dialogs.tag_editor import TagEditor
|
from calibre.gui2.dialogs.tag_editor import TagEditor
|
||||||
from calibre.ebooks.metadata import string_to_authors, authors_to_string, title_sort
|
from calibre.ebooks.metadata import string_to_authors, authors_to_string, title_sort
|
||||||
from calibre.ebooks.metadata.book.base import composite_formatter
|
from calibre.ebooks.metadata.book.base import SafeFormat
|
||||||
from calibre.gui2.custom_column_widgets import populate_metadata_page
|
from calibre.gui2.custom_column_widgets import populate_metadata_page
|
||||||
from calibre.gui2 import error_dialog, ResizableDialog, UNDEFINED_QDATE, \
|
from calibre.gui2 import error_dialog, ResizableDialog, UNDEFINED_QDATE, \
|
||||||
gprefs, question_dialog
|
gprefs, question_dialog
|
||||||
@ -499,7 +499,7 @@ class MetadataBulkDialog(ResizableDialog, Ui_MetadataBulkDialog):
|
|||||||
def s_r_get_field(self, mi, field):
|
def s_r_get_field(self, mi, field):
|
||||||
if field:
|
if field:
|
||||||
if field == '{template}':
|
if field == '{template}':
|
||||||
v = composite_formatter.safe_format\
|
v = SafeFormat().safe_format\
|
||||||
(unicode(self.s_r_template.text()), mi, _('S/R TEMPLATE ERROR'), mi)
|
(unicode(self.s_r_template.text()), mi, _('S/R TEMPLATE ERROR'), mi)
|
||||||
return [v]
|
return [v]
|
||||||
fm = self.db.metadata_for_field(field)
|
fm = self.db.metadata_for_field(field)
|
||||||
|
@ -11,7 +11,7 @@ from PyQt4.Qt import (Qt, QDialog, QDialogButtonBox, QSyntaxHighlighter, QFont,
|
|||||||
from calibre.gui2 import error_dialog
|
from calibre.gui2 import error_dialog
|
||||||
from calibre.gui2.dialogs.template_dialog_ui import Ui_TemplateDialog
|
from calibre.gui2.dialogs.template_dialog_ui import Ui_TemplateDialog
|
||||||
from calibre.utils.formatter_functions import formatter_functions
|
from calibre.utils.formatter_functions import formatter_functions
|
||||||
from calibre.ebooks.metadata.book.base import composite_formatter, Metadata
|
from calibre.ebooks.metadata.book.base import SafeFormat, Metadata
|
||||||
from calibre.library.coloring import (displayable_columns)
|
from calibre.library.coloring import (displayable_columns)
|
||||||
|
|
||||||
|
|
||||||
@ -270,7 +270,7 @@ class TemplateDialog(QDialog, Ui_TemplateDialog):
|
|||||||
self.highlighter.regenerate_paren_positions()
|
self.highlighter.regenerate_paren_positions()
|
||||||
self.text_cursor_changed()
|
self.text_cursor_changed()
|
||||||
self.template_value.setText(
|
self.template_value.setText(
|
||||||
composite_formatter.safe_format(cur_text, self.mi,
|
SafeFormat().safe_format(cur_text, self.mi,
|
||||||
_('EXCEPTION: '), self.mi))
|
_('EXCEPTION: '), self.mi))
|
||||||
|
|
||||||
def text_cursor_changed(self):
|
def text_cursor_changed(self):
|
||||||
|
@ -14,7 +14,7 @@ from PyQt4.Qt import (QAbstractTableModel, Qt, pyqtSignal, QIcon, QImage,
|
|||||||
from calibre.gui2 import NONE, UNDEFINED_QDATE
|
from calibre.gui2 import NONE, UNDEFINED_QDATE
|
||||||
from calibre.utils.pyparsing import ParseException
|
from calibre.utils.pyparsing import ParseException
|
||||||
from calibre.ebooks.metadata import fmt_sidx, authors_to_string, string_to_authors
|
from calibre.ebooks.metadata import fmt_sidx, authors_to_string, string_to_authors
|
||||||
from calibre.ebooks.metadata.book.base import composite_formatter
|
from calibre.ebooks.metadata.book.base import SafeFormat
|
||||||
from calibre.ptempfile import PersistentTemporaryFile
|
from calibre.ptempfile import PersistentTemporaryFile
|
||||||
from calibre.utils.config import tweaks, prefs
|
from calibre.utils.config import tweaks, prefs
|
||||||
from calibre.utils.date import dt_factory, qt_to_dt
|
from calibre.utils.date import dt_factory, qt_to_dt
|
||||||
@ -91,6 +91,7 @@ class BooksModel(QAbstractTableModel): # {{{
|
|||||||
self.current_highlighted_idx = None
|
self.current_highlighted_idx = None
|
||||||
self.highlight_only = False
|
self.highlight_only = False
|
||||||
self.colors = frozenset([unicode(c) for c in QColor.colorNames()])
|
self.colors = frozenset([unicode(c) for c in QColor.colorNames()])
|
||||||
|
self.formatter = SafeFormat()
|
||||||
self.read_config()
|
self.read_config()
|
||||||
|
|
||||||
def change_alignment(self, colname, alignment):
|
def change_alignment(self, colname, alignment):
|
||||||
@ -711,7 +712,7 @@ class BooksModel(QAbstractTableModel): # {{{
|
|||||||
try:
|
try:
|
||||||
if mi is None:
|
if mi is None:
|
||||||
mi = self.db.get_metadata(id_, index_is_id=True)
|
mi = self.db.get_metadata(id_, index_is_id=True)
|
||||||
color = composite_formatter.safe_format(fmt, mi, '', mi)
|
color = self.formatter.safe_format(fmt, mi, '', mi)
|
||||||
if color in self.colors:
|
if color in self.colors:
|
||||||
color = QColor(color)
|
color = QColor(color)
|
||||||
if color.isValid():
|
if color.isValid():
|
||||||
|
@ -20,7 +20,7 @@ from calibre.utils.config import tweaks
|
|||||||
from calibre.utils.icu import sort_key, lower, strcmp
|
from calibre.utils.icu import sort_key, lower, strcmp
|
||||||
from calibre.library.field_metadata import TagsIcons, category_icon_map
|
from calibre.library.field_metadata import TagsIcons, category_icon_map
|
||||||
from calibre.gui2.dialogs.confirm_delete import confirm
|
from calibre.gui2.dialogs.confirm_delete import confirm
|
||||||
from calibre.utils.formatter import eval_formatter
|
from calibre.utils.formatter import EvalFormatter
|
||||||
from calibre.utils.search_query_parser import saved_searches
|
from calibre.utils.search_query_parser import saved_searches
|
||||||
|
|
||||||
TAG_SEARCH_STATES = {'clear': 0, 'mark_plus': 1, 'mark_plusplus': 2,
|
TAG_SEARCH_STATES = {'clear': 0, 'mark_plus': 1, 'mark_plusplus': 2,
|
||||||
@ -341,6 +341,8 @@ class TagsModel(QAbstractItemModel): # {{{
|
|||||||
def _create_node_tree(self, data, state_map):
|
def _create_node_tree(self, data, state_map):
|
||||||
sort_by = config['sort_tags_by']
|
sort_by = config['sort_tags_by']
|
||||||
|
|
||||||
|
eval_formatter = EvalFormatter()
|
||||||
|
|
||||||
if data is None:
|
if data is None:
|
||||||
print ('_create_node_tree: no data!')
|
print ('_create_node_tree: no data!')
|
||||||
traceback.print_stack()
|
traceback.print_stack()
|
||||||
|
@ -347,5 +347,6 @@ class EvalFormatter(TemplateFormatter):
|
|||||||
key = key.lower()
|
key = key.lower()
|
||||||
return kwargs.get(key, _('No such variable ') + key)
|
return kwargs.get(key, _('No such variable ') + key)
|
||||||
|
|
||||||
|
# DEPRECATED. This is not thread safe. Do not use.
|
||||||
eval_formatter = EvalFormatter()
|
eval_formatter = EvalFormatter()
|
||||||
|
|
||||||
|
@ -202,9 +202,9 @@ class BuiltinEval(BuiltinFormatterFunction):
|
|||||||
'results from local variables.')
|
'results from local variables.')
|
||||||
|
|
||||||
def evaluate(self, formatter, kwargs, mi, locals, template):
|
def evaluate(self, formatter, kwargs, mi, locals, template):
|
||||||
from formatter import eval_formatter
|
from formatter import EvalFormatter
|
||||||
template = template.replace('[[', '{').replace(']]', '}')
|
template = template.replace('[[', '{').replace(']]', '}')
|
||||||
return eval_formatter.safe_format(template, locals, 'EVAL', None)
|
return EvalFormatter().safe_format(template, locals, 'EVAL', None)
|
||||||
|
|
||||||
class BuiltinAssign(BuiltinFormatterFunction):
|
class BuiltinAssign(BuiltinFormatterFunction):
|
||||||
name = 'assign'
|
name = 'assign'
|
||||||
|
Loading…
x
Reference in New Issue
Block a user