diff --git a/setup.cfg b/setup.cfg
index af4550aa0a..85743dbf49 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -1,6 +1,6 @@
[flake8]
max-line-length = 160
-builtins = _,dynamic_property,__,P,I,lopen,icu_lower,icu_upper,icu_title,ngettext,connect_lambda
+builtins = _,__,P,I,lopen,icu_lower,icu_upper,icu_title,ngettext,connect_lambda
ignore = E12,E203,E22,E231,E241,E401,E402,E731,W391,E722,E741,W504
[yapf]
diff --git a/src/calibre/__init__.py b/src/calibre/__init__.py
index 359a6b49e0..6aa14b8473 100644
--- a/src/calibre/__init__.py
+++ b/src/calibre/__init__.py
@@ -4,9 +4,8 @@
__docformat__ = 'restructuredtext en'
import sys, os, re, time, random, warnings
-from polyglot.builtins import (builtins, codepoint_to_chr, iteritems,
+from polyglot.builtins import (codepoint_to_chr, iteritems,
itervalues, unicode_type, range, filter, hasenv)
-builtins.__dict__['dynamic_property'] = lambda func: func(None)
from math import floor
from functools import partial
diff --git a/src/calibre/db/backend.py b/src/calibre/db/backend.py
index 72a61a6fe4..b3f26afb16 100644
--- a/src/calibre/db/backend.py
+++ b/src/calibre/db/backend.py
@@ -1145,17 +1145,14 @@ def dump_and_restore(self, callback=None, sql=None):
def vacuum(self):
self.execute('VACUUM')
- @dynamic_property
+ @property
def user_version(self):
- doc = 'The user version of this database'
+ '''The user version of this database'''
+ return self.conn.get('pragma user_version;', all=False)
- def fget(self):
- return self.conn.get('pragma user_version;', all=False)
-
- def fset(self, val):
- self.execute('pragma user_version=%d'%int(val))
-
- return property(doc=doc, fget=fget, fset=fset)
+ @user_version.setter
+ def user_version(self, val):
+ self.execute('pragma user_version=%d'%int(val))
def initialize_database(self):
metadata_sqlite = P('metadata_sqlite.sql', data=True,
@@ -1252,29 +1249,26 @@ def custom_tables(self):
def exists_at(cls, path):
return path and os.path.exists(os.path.join(path, 'metadata.db'))
- @dynamic_property
+ @property
def library_id(self):
- doc = ('The UUID for this library. As long as the user only operates'
- ' on libraries with calibre, it will be unique')
+ '''The UUID for this library. As long as the user only operates on libraries with calibre, it will be unique'''
- def fget(self):
- if getattr(self, '_library_id_', None) is None:
- ans = self.conn.get('SELECT uuid FROM library_id', all=False)
- if ans is None:
- ans = str(uuid.uuid4())
- self.library_id = ans
- else:
- self._library_id_ = ans
- return self._library_id_
+ if getattr(self, '_library_id_', None) is None:
+ ans = self.conn.get('SELECT uuid FROM library_id', all=False)
+ if ans is None:
+ ans = str(uuid.uuid4())
+ self.library_id = ans
+ else:
+ self._library_id_ = ans
+ return self._library_id_
- def fset(self, val):
- self._library_id_ = unicode_type(val)
- self.execute('''
- DELETE FROM library_id;
- INSERT INTO library_id (uuid) VALUES (?);
- ''', (self._library_id_,))
-
- return property(doc=doc, fget=fget, fset=fset)
+ @library_id.setter
+ def library_id(self, val):
+ self._library_id_ = unicode_type(val)
+ self.execute('''
+ DELETE FROM library_id;
+ INSERT INTO library_id (uuid) VALUES (?);
+ ''', (self._library_id_,))
def last_modified(self):
''' Return last modified time as a UTC datetime object '''
diff --git a/src/calibre/devices/cli.py b/src/calibre/devices/cli.py
index e90a88bce1..412fa985ed 100755
--- a/src/calibre/devices/cli.py
+++ b/src/calibre/devices/cli.py
@@ -31,73 +31,55 @@ def __init__(self, file):
self.name = file.name
self.path = file.path
- @dynamic_property
+ @property
def mode_string(self):
- doc=""" The mode string for this file. There are only two modes read-only and read-write """
+ """ The mode string for this file. There are only two modes read-only and read-write """
+ mode, x = "-", "-"
+ if self.is_dir:
+ mode, x = "d", "x"
+ if self.is_readonly:
+ mode += "r-"+x+"r-"+x+"r-"+x
+ else:
+ mode += "rw"+x+"rw"+x+"rw"+x
+ return mode
- def fget(self):
- mode, x = "-", "-"
- if self.is_dir:
- mode, x = "d", "x"
- if self.is_readonly:
- mode += "r-"+x+"r-"+x+"r-"+x
- else:
- mode += "rw"+x+"rw"+x+"rw"+x
- return mode
- return property(doc=doc, fget=fget)
-
- @dynamic_property
+ @property
def isdir_name(self):
- doc='''Return self.name + '/' if self is a directory'''
+ '''Return self.name + '/' if self is a directory'''
+ name = self.name
+ if self.is_dir:
+ name += '/'
+ return name
- def fget(self):
- name = self.name
- if self.is_dir:
- name += '/'
- return name
- return property(doc=doc, fget=fget)
-
- @dynamic_property
+ @property
def name_in_color(self):
- doc=""" The name in ANSI text. Directories are blue, ebooks are green """
+ """ The name in ANSI text. Directories are blue, ebooks are green """
+ cname = self.name
+ blue, green, normal = "", "", ""
+ if self.term:
+ blue, green, normal = self.term.BLUE, self.term.GREEN, self.term.NORMAL
+ if self.is_dir:
+ cname = blue + self.name + normal
+ else:
+ ext = self.name[self.name.rfind("."):]
+ if ext in (".pdf", ".rtf", ".lrf", ".lrx", ".txt"):
+ cname = green + self.name + normal
+ return cname
- def fget(self):
- cname = self.name
- blue, green, normal = "", "", ""
- if self.term:
- blue, green, normal = self.term.BLUE, self.term.GREEN, self.term.NORMAL
- if self.is_dir:
- cname = blue + self.name + normal
- else:
- ext = self.name[self.name.rfind("."):]
- if ext in (".pdf", ".rtf", ".lrf", ".lrx", ".txt"):
- cname = green + self.name + normal
- return cname
- return property(doc=doc, fget=fget)
-
- @dynamic_property
+ @property
def human_readable_size(self):
- doc=""" File size in human readable form """
+ """ File size in human readable form """
+ return human_readable(self.size)
- def fget(self):
- return human_readable(self.size)
- return property(doc=doc, fget=fget)
-
- @dynamic_property
+ @property
def modification_time(self):
- doc=""" Last modified time in the Linux ls -l format """
+ """ Last modified time in the Linux ls -l format """
+ return time.strftime("%Y-%m-%d %H:%M", time.localtime(self.wtime))
- def fget(self):
- return time.strftime("%Y-%m-%d %H:%M", time.localtime(self.wtime))
- return property(doc=doc, fget=fget)
-
- @dynamic_property
+ @property
def creation_time(self):
- doc=""" Last modified time in the Linux ls -l format """
-
- def fget(self):
- return time.strftime("%Y-%m-%d %H:%M", time.localtime(self.ctime))
- return property(doc=doc, fget=fget)
+ """ Last modified time in the Linux ls -l format """
+ return time.strftime("%Y-%m-%d %H:%M", time.localtime(self.ctime))
def info(dev):
diff --git a/src/calibre/devices/usbms/books.py b/src/calibre/devices/usbms/books.py
index 93fb4d8686..44ec03fdee 100644
--- a/src/calibre/devices/usbms/books.py
+++ b/src/calibre/devices/usbms/books.py
@@ -46,26 +46,21 @@ def __eq__(self, other):
# use lpath because the prefix can change, changing path
return self.lpath == getattr(other, 'lpath', None)
- @dynamic_property
+ @property
def db_id(self):
- doc = '''The database id in the application database that this file corresponds to'''
+ '''The database id in the application database that this file corresponds to'''
- def fget(self):
- match = re.search(r'_(\d+)$', self.lpath.rpartition('.')[0])
- if match:
- return int(match.group(1))
- return None
- return property(fget=fget, doc=doc)
+ match = re.search(r'_(\d+)$', self.lpath.rpartition('.')[0])
+ if match:
+ return int(match.group(1))
+ return None
- @dynamic_property
+ @property
def title_sorter(self):
- doc = '''String to sort the title. If absent, title is returned'''
+ '''String to sort the title. If absent, title is returned'''
+ return title_sort(self.title)
- def fget(self):
- return title_sort(self.title)
- return property(doc=doc, fget=fget)
-
- @dynamic_property
+ @property
def thumbnail(self):
return None
diff --git a/src/calibre/ebooks/covers.py b/src/calibre/ebooks/covers.py
index 14f9ac71f2..e0c948d1ae 100644
--- a/src/calibre/ebooks/covers.py
+++ b/src/calibre/ebooks/covers.py
@@ -169,24 +169,23 @@ def __init__(self, text='', width=0, font=None, img=None, max_height=100, align=
def height(self):
return int(ceil(sum(l if isinstance(l, numbers.Number) else l.boundingRect().height() for l in self.layouts)))
- @dynamic_property
+ @property
def position(self):
- def fget(self):
- return self._position
+ return self._position
- def fset(self, new_pos):
- (x, y) = new_pos
- self._position = Point(x, y)
- if self.layouts:
- self.layouts[0].setPosition(QPointF(x, y))
- y += self.layouts[0].boundingRect().height()
- for l in self.layouts[1:]:
- if isinstance(l, numbers.Number):
- y += l
- else:
- l.setPosition(QPointF(x, y))
- y += l.boundingRect().height()
- return property(fget=fget, fset=fset)
+ @position.setter
+ def position(self, new_pos):
+ (x, y) = new_pos
+ self._position = Point(x, y)
+ if self.layouts:
+ self.layouts[0].setPosition(QPointF(x, y))
+ y += self.layouts[0].boundingRect().height()
+ for l in self.layouts[1:]:
+ if isinstance(l, numbers.Number):
+ y += l
+ else:
+ l.setPosition(QPointF(x, y))
+ y += l.boundingRect().height()
def draw(self, painter):
for l in self.layouts:
diff --git a/src/calibre/ebooks/lrf/tags.py b/src/calibre/ebooks/lrf/tags.py
index ae71a6dc97..62de1a3a78 100644
--- a/src/calibre/ebooks/lrf/tags.py
+++ b/src/calibre/ebooks/lrf/tags.py
@@ -209,37 +209,29 @@ def __str__(self):
s += " at %08X, contents: %s" % (self.offset, repr(self.contents))
return s
- @dynamic_property
+ @property
def byte(self):
- def fget(self):
- if len(self.contents) != 1:
- raise LRFParseError("Bad parameter for tag ID: %04X" % self.id)
- return struct.unpack("'%(self.id, self.href(), self.media_type)
@@ -804,172 +803,155 @@ def get_href(item):
for item in self.iterguide():
item.set('href', get_href(item))
- @dynamic_property
+ @property
def title(self):
# TODO: Add support for EPUB 3 refinements
- def fget(self):
- for elem in self.title_path(self.metadata):
- title = self.get_text(elem)
- if title and title.strip():
- return re.sub(r'\s+', ' ', title.strip())
+ for elem in self.title_path(self.metadata):
+ title = self.get_text(elem)
+ if title and title.strip():
+ return re.sub(r'\s+', ' ', title.strip())
- def fset(self, val):
- val = (val or '').strip()
- titles = self.title_path(self.metadata)
- if self.package_version < 3:
- # EPUB 3 allows multiple title elements containing sub-titles,
- # series and other things. We all loooove EPUB 3.
- for title in titles:
- title.getparent().remove(title)
- titles = ()
- if val:
- title = titles[0] if titles else self.create_metadata_element('title')
- title.text = re.sub(r'\s+', ' ', unicode_type(val))
+ @title.setter
+ def title(self, val):
+ val = (val or '').strip()
+ titles = self.title_path(self.metadata)
+ if self.package_version < 3:
+ # EPUB 3 allows multiple title elements containing sub-titles,
+ # series and other things. We all loooove EPUB 3.
+ for title in titles:
+ title.getparent().remove(title)
+ titles = ()
+ if val:
+ title = titles[0] if titles else self.create_metadata_element('title')
+ title.text = re.sub(r'\s+', ' ', unicode_type(val))
- return property(fget=fget, fset=fset)
-
- @dynamic_property
+ @property
def authors(self):
+ ans = []
+ for elem in self.authors_path(self.metadata):
+ ans.extend(string_to_authors(self.get_text(elem)))
+ return ans
- def fget(self):
- ans = []
- for elem in self.authors_path(self.metadata):
- ans.extend(string_to_authors(self.get_text(elem)))
- return ans
+ @authors.setter
+ def authors(self, val):
+ remove = list(self.authors_path(self.metadata))
+ for elem in remove:
+ elem.getparent().remove(elem)
+ # Ensure new author element is at the top of the list
+ # for broken implementations that always use the first
+ # element with no attention to the role
+ for author in reversed(val):
+ elem = self.metadata.makeelement('{%s}creator'%
+ self.NAMESPACES['dc'], nsmap=self.NAMESPACES)
+ elem.tail = '\n'
+ self.metadata.insert(0, elem)
+ elem.set('{%s}role'%self.NAMESPACES['opf'], 'aut')
+ self.set_text(elem, author.strip())
- def fset(self, val):
- remove = list(self.authors_path(self.metadata))
- for elem in remove:
- elem.getparent().remove(elem)
- # Ensure new author element is at the top of the list
- # for broken implementations that always use the first
- # element with no attention to the role
- for author in reversed(val):
- elem = self.metadata.makeelement('{%s}creator'%
- self.NAMESPACES['dc'], nsmap=self.NAMESPACES)
- elem.tail = '\n'
- self.metadata.insert(0, elem)
- elem.set('{%s}role'%self.NAMESPACES['opf'], 'aut')
- self.set_text(elem, author.strip())
-
- return property(fget=fget, fset=fset)
-
- @dynamic_property
+ @property
def author_sort(self):
+ matches = self.authors_path(self.metadata)
+ if matches:
+ for match in matches:
+ ans = match.get('{%s}file-as'%self.NAMESPACES['opf'], None)
+ if not ans:
+ ans = match.get('file-as', None)
+ if ans:
+ return ans
- def fget(self):
- matches = self.authors_path(self.metadata)
- if matches:
- for match in matches:
- ans = match.get('{%s}file-as'%self.NAMESPACES['opf'], None)
- if not ans:
- ans = match.get('file-as', None)
- if ans:
- return ans
+ @author_sort.setter
+ def author_sort(self, val):
+ matches = self.authors_path(self.metadata)
+ if matches:
+ for key in matches[0].attrib:
+ if key.endswith('file-as'):
+ matches[0].attrib.pop(key)
+ matches[0].set('{%s}file-as'%self.NAMESPACES['opf'], unicode_type(val))
- def fset(self, val):
- matches = self.authors_path(self.metadata)
- if matches:
- for key in matches[0].attrib:
- if key.endswith('file-as'):
- matches[0].attrib.pop(key)
- matches[0].set('{%s}file-as'%self.NAMESPACES['opf'], unicode_type(val))
-
- return property(fget=fget, fset=fset)
-
- @dynamic_property
+ @property
def tags(self):
+ ans = []
+ for tag in self.tags_path(self.metadata):
+ text = self.get_text(tag)
+ if text and text.strip():
+ ans.extend([x.strip() for x in text.split(',')])
+ return ans
- def fget(self):
- ans = []
- for tag in self.tags_path(self.metadata):
- text = self.get_text(tag)
- if text and text.strip():
- ans.extend([x.strip() for x in text.split(',')])
- return ans
+ @tags.setter
+ def tags(self, val):
+ for tag in list(self.tags_path(self.metadata)):
+ tag.getparent().remove(tag)
+ for tag in val:
+ elem = self.create_metadata_element('subject')
+ self.set_text(elem, unicode_type(tag))
- def fset(self, val):
- for tag in list(self.tags_path(self.metadata)):
- tag.getparent().remove(tag)
- for tag in val:
- elem = self.create_metadata_element('subject')
- self.set_text(elem, unicode_type(tag))
-
- return property(fget=fget, fset=fset)
-
- @dynamic_property
+ @property
def pubdate(self):
+ ans = None
+ for match in self.pubdate_path(self.metadata):
+ try:
+ val = parse_date(etree.tostring(match, encoding=unicode_type,
+ method='text', with_tail=False).strip())
+ except:
+ continue
+ if ans is None or val < ans:
+ ans = val
+ return ans
- def fget(self):
- ans = None
- for match in self.pubdate_path(self.metadata):
- try:
- val = parse_date(etree.tostring(match, encoding=unicode_type,
- method='text', with_tail=False).strip())
- except:
- continue
- if ans is None or val < ans:
- ans = val
- return ans
-
- def fset(self, val):
- least_val = least_elem = None
- for match in self.pubdate_path(self.metadata):
- try:
- cval = parse_date(etree.tostring(match, encoding=unicode_type,
- method='text', with_tail=False).strip())
- except:
+ @pubdate.setter
+ def pubdate(self, val):
+ least_val = least_elem = None
+ for match in self.pubdate_path(self.metadata):
+ try:
+ cval = parse_date(etree.tostring(match, encoding=unicode_type,
+ method='text', with_tail=False).strip())
+ except:
+ match.getparent().remove(match)
+ else:
+ if not val:
match.getparent().remove(match)
- else:
- if not val:
- match.getparent().remove(match)
- if least_val is None or cval < least_val:
- least_val, least_elem = cval, match
+ if least_val is None or cval < least_val:
+ least_val, least_elem = cval, match
- if val:
- if least_val is None:
- least_elem = self.create_metadata_element('date')
+ if val:
+ if least_val is None:
+ least_elem = self.create_metadata_element('date')
- least_elem.attrib.clear()
- least_elem.text = isoformat(val)
+ least_elem.attrib.clear()
+ least_elem.text = isoformat(val)
- return property(fget=fget, fset=fset)
-
- @dynamic_property
+ @property
def isbn(self):
+ for match in self.isbn_path(self.metadata):
+ return self.get_text(match) or None
- def fget(self):
- for match in self.isbn_path(self.metadata):
- return self.get_text(match) or None
+ @isbn.setter
+ def isbn(self, val):
+ uuid_id = None
+ for attr in self.root.attrib:
+ if attr.endswith('unique-identifier'):
+ uuid_id = self.root.attrib[attr]
+ break
- def fset(self, val):
- uuid_id = None
- for attr in self.root.attrib:
- if attr.endswith('unique-identifier'):
- uuid_id = self.root.attrib[attr]
- break
-
- matches = self.isbn_path(self.metadata)
- if not val:
- for x in matches:
- xid = x.get('id', None)
- is_package_identifier = uuid_id is not None and uuid_id == xid
- if is_package_identifier:
- self.set_text(x, str(uuid.uuid4()))
- for attr in x.attrib:
- if attr.endswith('scheme'):
- x.attrib[attr] = 'uuid'
- else:
- x.getparent().remove(x)
- return
- if not matches:
- attrib = {'{%s}scheme'%self.NAMESPACES['opf']: 'ISBN'}
- matches = [self.create_metadata_element('identifier',
- attrib=attrib)]
- self.set_text(matches[0], unicode_type(val))
-
- return property(fget=fget, fset=fset)
+ matches = self.isbn_path(self.metadata)
+ if not val:
+ for x in matches:
+ xid = x.get('id', None)
+ is_package_identifier = uuid_id is not None and uuid_id == xid
+ if is_package_identifier:
+ self.set_text(x, str(uuid.uuid4()))
+ for attr in x.attrib:
+ if attr.endswith('scheme'):
+ x.attrib[attr] = 'uuid'
+ else:
+ x.getparent().remove(x)
+ return
+ if not matches:
+ attrib = {'{%s}scheme'%self.NAMESPACES['opf']: 'ISBN'}
+ matches = [self.create_metadata_element('identifier',
+ attrib=attrib)]
+ self.set_text(matches[0], unicode_type(val))
def get_identifiers(self):
identifiers = {}
@@ -1024,85 +1006,73 @@ def set_identifiers(self, identifiers):
self.set_text(self.create_metadata_element(
'identifier', attrib=attrib), unicode_type(val))
- @dynamic_property
+ @property
def application_id(self):
+ for match in self.application_id_path(self.metadata):
+ return self.get_text(match) or None
- def fget(self):
- for match in self.application_id_path(self.metadata):
- return self.get_text(match) or None
+ @application_id.setter
+ def application_id(self, val):
+ removed_ids = set()
+ for x in tuple(self.application_id_path(self.metadata)):
+ removed_ids.add(x.get('id', None))
+ x.getparent().remove(x)
- def fset(self, val):
- removed_ids = set()
- for x in tuple(self.application_id_path(self.metadata)):
- removed_ids.add(x.get('id', None))
- x.getparent().remove(x)
+ uuid_id = None
+ for attr in self.root.attrib:
+ if attr.endswith('unique-identifier'):
+ uuid_id = self.root.attrib[attr]
+ break
+ attrib = {'{%s}scheme'%self.NAMESPACES['opf']: 'calibre'}
+ if uuid_id and uuid_id in removed_ids:
+ attrib['id'] = uuid_id
+ self.set_text(self.create_metadata_element(
+ 'identifier', attrib=attrib), unicode_type(val))
- uuid_id = None
- for attr in self.root.attrib:
- if attr.endswith('unique-identifier'):
- uuid_id = self.root.attrib[attr]
- break
- attrib = {'{%s}scheme'%self.NAMESPACES['opf']: 'calibre'}
- if uuid_id and uuid_id in removed_ids:
- attrib['id'] = uuid_id
- self.set_text(self.create_metadata_element(
- 'identifier', attrib=attrib), unicode_type(val))
-
- return property(fget=fget, fset=fset)
-
- @dynamic_property
+ @property
def uuid(self):
+ for match in self.uuid_id_path(self.metadata):
+ return self.get_text(match) or None
- def fget(self):
- for match in self.uuid_id_path(self.metadata):
- return self.get_text(match) or None
+ @uuid.setter
+ def uuid(self, val):
+ matches = self.uuid_id_path(self.metadata)
+ if not matches:
+ attrib = {'{%s}scheme'%self.NAMESPACES['opf']: 'uuid'}
+ matches = [self.create_metadata_element('identifier',
+ attrib=attrib)]
+ self.set_text(matches[0], unicode_type(val))
- def fset(self, val):
- matches = self.uuid_id_path(self.metadata)
- if not matches:
- attrib = {'{%s}scheme'%self.NAMESPACES['opf']: 'uuid'}
- matches = [self.create_metadata_element('identifier',
- attrib=attrib)]
- self.set_text(matches[0], unicode_type(val))
-
- return property(fget=fget, fset=fset)
-
- @dynamic_property
+ @property
def language(self):
+ ans = self.languages
+ if ans:
+ return ans[0]
- def fget(self):
- ans = self.languages
- if ans:
- return ans[0]
+ @language.setter
+ def language(self, val):
+ self.languages = [val]
- def fset(self, val):
- self.languages = [val]
-
- return property(fget=fget, fset=fset)
-
- @dynamic_property
+ @property
def languages(self):
+ ans = []
+ for match in self.languages_path(self.metadata):
+ t = self.get_text(match)
+ if t and t.strip():
+ l = canonicalize_lang(t.strip())
+ if l:
+ ans.append(l)
+ return ans
- def fget(self):
- ans = []
- for match in self.languages_path(self.metadata):
- t = self.get_text(match)
- if t and t.strip():
- l = canonicalize_lang(t.strip())
- if l:
- ans.append(l)
- return ans
+ @languages.setter
+ def languages(self, val):
+ matches = self.languages_path(self.metadata)
+ for x in matches:
+ x.getparent().remove(x)
- def fset(self, val):
- matches = self.languages_path(self.metadata)
- for x in matches:
- x.getparent().remove(x)
-
- for lang in val:
- l = self.create_metadata_element('language')
- self.set_text(l, unicode_type(lang))
-
- return property(fget=fget, fset=fset)
+ for lang in val:
+ l = self.create_metadata_element('language')
+ self.set_text(l, unicode_type(lang))
@property
def raw_languages(self):
@@ -1111,20 +1081,18 @@ def raw_languages(self):
if t and t.strip():
yield t.strip()
- @dynamic_property
+ @property
def book_producer(self):
+ for match in self.bkp_path(self.metadata):
+ return self.get_text(match) or None
- def fget(self):
- for match in self.bkp_path(self.metadata):
- return self.get_text(match) or None
-
- def fset(self, val):
- matches = self.bkp_path(self.metadata)
- if not matches:
- matches = [self.create_metadata_element('contributor')]
- matches[0].set('{%s}role'%self.NAMESPACES['opf'], 'bkp')
- self.set_text(matches[0], unicode_type(val))
- return property(fget=fget, fset=fset)
+ @book_producer.setter
+ def book_producer(self, val):
+ matches = self.bkp_path(self.metadata)
+ if not matches:
+ matches = [self.create_metadata_element('contributor')]
+ matches[0].set('{%s}role'%self.NAMESPACES['opf'], 'bkp')
+ self.set_text(matches[0], unicode_type(val))
def identifier_iter(self):
for item in self.identifier_path(self.metadata):
@@ -1238,42 +1206,39 @@ def epub3_nav(self):
if path and os.path.exists(path):
return path
- @dynamic_property
+ @property
def cover(self):
+ if self.guide is not None:
+ for t in ('cover', 'other.ms-coverimage-standard', 'other.ms-coverimage'):
+ for item in self.guide:
+ if item.type and item.type.lower() == t:
+ return item.path
+ try:
+ if self.try_to_guess_cover:
+ return self.guess_cover()
+ except:
+ pass
- def fget(self):
- if self.guide is not None:
- for t in ('cover', 'other.ms-coverimage-standard', 'other.ms-coverimage'):
- for item in self.guide:
- if item.type and item.type.lower() == t:
- return item.path
- try:
- if self.try_to_guess_cover:
- return self.guess_cover()
- except:
- pass
+ @cover.setter
+ def cover(self, path):
+ if self.guide is not None:
+ self.guide.set_cover(path)
+ for item in list(self.iterguide()):
+ if 'cover' in item.get('type', ''):
+ item.getparent().remove(item)
- def fset(self, path):
- if self.guide is not None:
- self.guide.set_cover(path)
- for item in list(self.iterguide()):
- if 'cover' in item.get('type', ''):
- item.getparent().remove(item)
-
- else:
- g = self.create_guide_element()
- self.guide = Guide()
- self.guide.set_cover(path)
- etree.SubElement(g, 'opf:reference', nsmap=self.NAMESPACES,
- attrib={'type':'cover', 'href':self.guide[-1].href()})
- id = self.manifest.id_for_path(self.cover)
- if id is None:
- for t in ('cover', 'other.ms-coverimage-standard', 'other.ms-coverimage'):
- for item in self.guide:
- if item.type.lower() == t:
- self.create_manifest_item(item.href(), guess_type(path)[0])
-
- return property(fget=fget, fset=fset)
+ else:
+ g = self.create_guide_element()
+ self.guide = Guide()
+ self.guide.set_cover(path)
+ etree.SubElement(g, 'opf:reference', nsmap=self.NAMESPACES,
+ attrib={'type':'cover', 'href':self.guide[-1].href()})
+ id = self.manifest.id_for_path(self.cover)
+ if id is None:
+ for t in ('cover', 'other.ms-coverimage-standard', 'other.ms-coverimage'):
+ for item in self.guide:
+ if item.type.lower() == t:
+ self.create_manifest_item(item.href(), guess_type(path)[0])
def get_metadata_element(self, name):
matches = self.metadata_elem_path(self.metadata, name=name)
diff --git a/src/calibre/ebooks/metadata/toc.py b/src/calibre/ebooks/metadata/toc.py
index 7d4cc06dd8..2287d12aab 100644
--- a/src/calibre/ebooks/metadata/toc.py
+++ b/src/calibre/ebooks/metadata/toc.py
@@ -122,19 +122,16 @@ def flat(self):
for i in obj.flat():
yield i
- @dynamic_property
+ @property
def abspath(self):
- doc='Return the file this toc entry points to as a absolute path to a file on the system.'
+ 'Return the file this toc entry points to as a absolute path to a file on the system.'
- def fget(self):
- if self.href is None:
- return None
- path = self.href.replace('/', os.sep)
- if not os.path.isabs(path):
- path = os.path.join(self.base_path, path)
- return path
-
- return property(fget=fget, doc=doc)
+ if self.href is None:
+ return None
+ path = self.href.replace('/', os.sep)
+ if not os.path.isabs(path):
+ path = os.path.join(self.base_path, path)
+ return path
def read_from_opf(self, opfreader):
toc = opfreader.soup.find('spine', toc=True)
diff --git a/src/calibre/ebooks/mobi/writer2/indexer.py b/src/calibre/ebooks/mobi/writer2/indexer.py
index 2d415fcea4..a36e99b9ba 100644
--- a/src/calibre/ebooks/mobi/writer2/indexer.py
+++ b/src/calibre/ebooks/mobi/writer2/indexer.py
@@ -131,14 +131,13 @@ def __repr__(self):
' parent_index=%r)')%(self.offset, self.depth, self.length,
self.index, self.parent_index)
- @dynamic_property
+ @property
def size(self):
- def fget(self):
- return self.length
+ return self.length
- def fset(self, val):
- self.length = val
- return property(fget=fget, fset=fset, doc='Alias for length')
+ @size.setter
+ def size(self, val):
+ self.length = val
@property
def next_offset(self):
diff --git a/src/calibre/ebooks/oeb/base.py b/src/calibre/ebooks/oeb/base.py
index d0bd14ceb0..d17c73c6d6 100644
--- a/src/calibre/ebooks/oeb/base.py
+++ b/src/calibre/ebooks/oeb/base.py
@@ -704,20 +704,17 @@ def __init__(self, term, value, attrib={}, nsmap={}, **kwargs):
if attr != nsattr:
attrib[nsattr] = attrib.pop(attr)
- @dynamic_property
+ @property
def name(self):
- def fget(self):
- return self.term
- return property(fget=fget)
+ return self.term
- @dynamic_property
+ @property
def content(self):
- def fget(self):
- return self.value
+ return self.value
- def fset(self, value):
- self.value = value
- return property(fget=fget, fset=fset)
+ @content.setter
+ def content(self, value):
+ self.value = value
scheme = Attribute(lambda term: 'scheme' if
term == OPF('meta') else OPF('scheme'),
@@ -830,33 +827,27 @@ def __contains__(self, key):
def __getattr__(self, term):
return self.items[term]
- @dynamic_property
+ @property
def _nsmap(self):
- def fget(self):
- nsmap = {}
- for term in self.items:
- for item in self.items[term]:
- nsmap.update(item.nsmap)
- return nsmap
- return property(fget=fget)
+ nsmap = {}
+ for term in self.items:
+ for item in self.items[term]:
+ nsmap.update(item.nsmap)
+ return nsmap
- @dynamic_property
+ @property
def _opf1_nsmap(self):
- def fget(self):
- nsmap = self._nsmap
- for key, value in nsmap.items():
- if value in OPF_NSES or value in DC_NSES:
- del nsmap[key]
- return nsmap
- return property(fget=fget)
+ nsmap = self._nsmap
+ for key, value in nsmap.items():
+ if value in OPF_NSES or value in DC_NSES:
+ del nsmap[key]
+ return nsmap
- @dynamic_property
+ @property
def _opf2_nsmap(self):
- def fget(self):
- nsmap = self._nsmap
- nsmap.update(OPF2_NSMAP)
- return nsmap
- return property(fget=fget)
+ nsmap = self._nsmap
+ nsmap.update(OPF2_NSMAP)
+ return nsmap
def to_opf1(self, parent=None):
nsmap = self._opf1_nsmap
@@ -1011,9 +1002,9 @@ def _fetch_css(self, path):
# }}}
- @dynamic_property
+ @property
def data(self):
- doc = """Provides MIME type sensitive access to the manifest
+ """Provides MIME type sensitive access to the manifest
entry's associated content.
- XHTML, HTML, and variant content is parsed as necessary to
@@ -1025,40 +1016,39 @@ def data(self):
- All other content is returned as a :class:`str` object with no
special parsing.
"""
+ data = self._data
+ if data is None:
+ if self._loader is None:
+ return None
+ data = self._loader(getattr(self, 'html_input_href',
+ self.href))
+ try:
+ mt = self.media_type.lower()
+ except Exception:
+ mt = 'application/octet-stream'
+ if not isinstance(data, string_or_bytes):
+ pass # already parsed
+ elif mt in OEB_DOCS:
+ data = self._parse_xhtml(data)
+ elif mt[-4:] in ('+xml', '/xml'):
+ data = self._parse_xml(data)
+ elif mt in OEB_STYLES:
+ data = self._parse_css(data)
+ elif mt == 'text/plain':
+ self.oeb.log.warn('%s contains data in TXT format'%self.href,
+ 'converting to HTML')
+ data = self._parse_txt(data)
+ self.media_type = XHTML_MIME
+ self._data = data
+ return data
- def fget(self):
- data = self._data
- if data is None:
- if self._loader is None:
- return None
- data = self._loader(getattr(self, 'html_input_href',
- self.href))
- try:
- mt = self.media_type.lower()
- except Exception:
- mt = 'application/octet-stream'
- if not isinstance(data, string_or_bytes):
- pass # already parsed
- elif mt in OEB_DOCS:
- data = self._parse_xhtml(data)
- elif mt[-4:] in ('+xml', '/xml'):
- data = self._parse_xml(data)
- elif mt in OEB_STYLES:
- data = self._parse_css(data)
- elif mt == 'text/plain':
- self.oeb.log.warn('%s contains data in TXT format'%self.href,
- 'converting to HTML')
- data = self._parse_txt(data)
- self.media_type = XHTML_MIME
- self._data = data
- return data
+ @data.setter
+ def data(self, value):
+ self._data = value
- def fset(self, value):
- self._data = value
-
- def fdel(self):
- self._data = None
- return property(fget, fset, fdel, doc=doc)
+ @data.deleter
+ def data(self):
+ self._data = None
def unload_data_from_memory(self, memory=None):
if isinstance(self._data, bytes):
@@ -1266,20 +1256,19 @@ def to_opf2(self, parent=None):
element(elem, OPF('item'), attrib=attrib)
return elem
- @dynamic_property
+ @property
def main_stylesheet(self):
- def fget(self):
- ans = getattr(self, '_main_stylesheet', None)
- if ans is None:
- for item in self:
- if item.media_type.lower() in OEB_STYLES:
- ans = item
- break
- return ans
+ ans = getattr(self, '_main_stylesheet', None)
+ if ans is None:
+ for item in self:
+ if item.media_type.lower() in OEB_STYLES:
+ ans = item
+ break
+ return ans
- def fset(self, item):
- self._main_stylesheet = item
- return property(fget=fget, fset=fset)
+ @main_stylesheet.setter
+ def main_stylesheet(self, item):
+ self._main_stylesheet = item
class Spine(object):
@@ -1422,15 +1411,12 @@ def __repr__(self):
return 'Reference(type=%r, title=%r, href=%r)' \
% (self.type, self.title, self.href)
- @dynamic_property
+ @property
def item(self):
- doc = """The manifest item associated with this reference."""
-
- def fget(self):
- path = urldefrag(self.href)[0]
- hrefs = self.oeb.manifest.hrefs
- return hrefs.get(path, None)
- return property(fget=fget, doc=doc)
+ """The manifest item associated with this reference."""
+ path = urldefrag(self.href)[0]
+ hrefs = self.oeb.manifest.hrefs
+ return hrefs.get(path, None)
def __init__(self, oeb):
self.oeb = oeb
diff --git a/src/calibre/ebooks/oeb/polish/container.py b/src/calibre/ebooks/oeb/polish/container.py
index c889a9c5df..2a3175632f 100644
--- a/src/calibre/ebooks/oeb/polish/container.py
+++ b/src/calibre/ebooks/oeb/polish/container.py
@@ -1369,14 +1369,13 @@ def commit(self, outpath=None, keep_parsed=False):
with self.open(name, 'wb') as f:
f.write(data)
- @dynamic_property
+ @property
def path_to_ebook(self):
- def fget(self):
- return self.pathtoepub
+ return self.pathtoepub
- def fset(self, val):
- self.pathtoepub = val
- return property(fget=fget, fset=fset)
+ @path_to_ebook.setter
+ def path_to_ebook(self, val):
+ self.pathtoepub = val
# }}}
@@ -1496,14 +1495,13 @@ def commit(self, outpath=None, keep_parsed=False):
outpath = self.pathtoazw3
opf_to_azw3(self.name_path_map[self.opf_name], outpath, self)
- @dynamic_property
+ @property
def path_to_ebook(self):
- def fget(self):
- return self.pathtoazw3
+ return self.pathtoazw3
- def fset(self, val):
- self.pathtoazw3 = val
- return property(fget=fget, fset=fset)
+ @path_to_ebook.setter
+ def path_to_ebook(self, val):
+ self.pathtoazw3 = val
@property
def names_that_must_not_be_changed(self):
diff --git a/src/calibre/gui2/__init__.py b/src/calibre/gui2/__init__.py
index f9a9d252ab..a3cb32d8e0 100644
--- a/src/calibre/gui2/__init__.py
+++ b/src/calibre/gui2/__init__.py
@@ -1022,19 +1022,19 @@ def event(self, e):
else:
return QApplication.event(self, e)
- @dynamic_property
+ @property
def current_custom_colors(self):
- from PyQt5.Qt import QColorDialog, QColor
+ from PyQt5.Qt import QColorDialog
- def fget(self):
- return [col.getRgb() for col in
+ return [col.getRgb() for col in
(QColorDialog.customColor(i) for i in range(QColorDialog.customCount()))]
- def fset(self, colors):
- num = min(len(colors), QColorDialog.customCount())
- for i in range(num):
- QColorDialog.setCustomColor(i, QColor(*colors[i]))
- return property(fget=fget, fset=fset)
+ @current_custom_colors.setter
+ def current_custom_colors(self, colors):
+ from PyQt5.Qt import QColorDialog, QColor
+ num = min(len(colors), QColorDialog.customCount())
+ for i in range(num):
+ QColorDialog.setCustomColor(i, QColor(*colors[i]))
def read_custom_colors(self):
colors = self.color_prefs.get('custom_colors_for_color_dialog', None)
diff --git a/src/calibre/gui2/actions/toc_edit.py b/src/calibre/gui2/actions/toc_edit.py
index 25923733a6..8782f86aa4 100644
--- a/src/calibre/gui2/actions/toc_edit.py
+++ b/src/calibre/gui2/actions/toc_edit.py
@@ -51,18 +51,17 @@ def do_all(self):
b.setChecked(True)
self.accept()
- @dynamic_property
+ @property
def formats(self):
- def fget(self):
- for b in self.buttons:
- if b.isChecked():
- yield unicode_type(b.text())[1:]
+ for b in self.buttons:
+ if b.isChecked():
+ yield unicode_type(b.text())[1:]
- def fset(self, formats):
- formats = {x.upper() for x in formats}
- for b in self.buttons:
- b.setChecked(b.text()[1:] in formats)
- return property(fget=fget, fset=fset)
+ @formats.setter
+ def formats(self, formats):
+ formats = {x.upper() for x in formats}
+ for b in self.buttons:
+ b.setChecked(b.text()[1:] in formats)
# }}}
diff --git a/src/calibre/gui2/comments_editor.py b/src/calibre/gui2/comments_editor.py
index 546422014e..da9d790a43 100644
--- a/src/calibre/gui2/comments_editor.py
+++ b/src/calibre/gui2/comments_editor.py
@@ -336,55 +336,53 @@ def exec_command(self, cmd, arg=None):
def remove_format_cleanup(self):
self.html = self.html
- @dynamic_property
+ @property
def html(self):
+ ans = u''
+ try:
+ if not self.page().mainFrame().documentElement().findFirst('meta[name="calibre-dont-sanitize"]').isNull():
+ # Bypass cleanup if special meta tag exists
+ return unicode_type(self.page().mainFrame().toHtml())
+ check = unicode_type(self.page().mainFrame().toPlainText()).strip()
+ raw = unicode_type(self.page().mainFrame().toHtml())
+ raw = xml_to_unicode(raw, strip_encoding_pats=True,
+ resolve_entities=True)[0]
+ raw = self.comments_pat.sub('', raw)
+ if not check and '
1:
- ans = u'%s
'%(u''.join(elems))
- else:
- ans = u''.join(elems)
- if not ans.startswith('<'):
- ans = '%s
'%ans
- ans = xml_replace_entities(ans)
- except:
- import traceback
- traceback.print_exc()
-
- return ans
-
- def fset(self, val):
- if self.base_url is None:
- self.setHtml(val)
+ if len(elems) > 1:
+ ans = u'%s
'%(u''.join(elems))
else:
- self.setHtml(val, self.base_url)
- self.set_font_style()
- return property(fget=fget, fset=fset)
+ ans = u''.join(elems)
+ if not ans.startswith('<'):
+ ans = '%s
'%ans
+ ans = xml_replace_entities(ans)
+ except:
+ import traceback
+ traceback.print_exc()
+
+ return ans
+
+ @html.setter
+ def html(self, val):
+ if self.base_url is None:
+ self.setHtml(val)
+ else:
+ self.setHtml(val, self.base_url)
+ self.set_font_style()
def set_base_url(self, qurl):
self.base_url = qurl
@@ -763,15 +761,14 @@ def __init__(self, parent=None, one_line_toolbar=False, toolbar_prefs_name=None)
def set_minimum_height_for_editor(self, val):
self.editor.setMinimumHeight(val)
- @dynamic_property
+ @property
def html(self):
- def fset(self, v):
- self.editor.html = v
+ self.tabs.setCurrentIndex(0)
+ return self.editor.html
- def fget(self):
- self.tabs.setCurrentIndex(0)
- return self.editor.html
- return property(fget=fget, fset=fset)
+ @html.setter
+ def html(self, v):
+ self.editor.html = v
def change_tab(self, index):
# print 'reloading:', (index and self.wyswyg_dirty) or (not index and
@@ -785,14 +782,13 @@ def change_tab(self, index):
self.editor.html = unicode_type(self.code_edit.toPlainText())
self.source_dirty = False
- @dynamic_property
+ @property
def tab(self):
- def fget(self):
- return 'code' if self.tabs.currentWidget() is self.code_edit else 'wyswyg'
+ return 'code' if self.tabs.currentWidget() is self.code_edit else 'wyswyg'
- def fset(self, val):
- self.tabs.setCurrentWidget(self.code_edit if val == 'code' else self.wyswyg)
- return property(fget=fget, fset=fset)
+ @tab.setter
+ def tab(self, val):
+ self.tabs.setCurrentWidget(self.code_edit if val == 'code' else self.wyswyg)
def wyswyg_dirtied(self, *args):
self.wyswyg_dirty = True
@@ -816,14 +812,13 @@ def toggle_toolbars(self):
if self.toolbar_prefs_name is not None:
gprefs.set(self.toolbar_prefs_name, visible)
- @dynamic_property
+ @property
def toolbars_visible(self):
- def fget(self):
- return self.toolbar1.isVisible() or self.toolbar2.isVisible() or self.toolbar3.isVisible()
+ return self.toolbar1.isVisible() or self.toolbar2.isVisible() or self.toolbar3.isVisible()
- def fset(self, val):
- getattr(self, ('show' if val else 'hide') + '_toolbars')()
- return property(fget=fget, fset=fset)
+ @toolbars_visible.setter
+ def toolbars_visible(self, val):
+ getattr(self, ('show' if val else 'hide') + '_toolbars')()
def set_readonly(self, what):
self.editor.set_readonly(what)
diff --git a/src/calibre/gui2/complete2.py b/src/calibre/gui2/complete2.py
index d1f801cf84..8df266d0b4 100644
--- a/src/calibre/gui2/complete2.py
+++ b/src/calibre/gui2/complete2.py
@@ -333,23 +333,21 @@ def set_space_before_sep(self, space_before):
def set_add_separator(self, what):
self.add_separator = bool(what)
- @dynamic_property
+ @property
def all_items(self):
- def fget(self):
- return self.mcompleter.model().all_items
+ return self.mcompleter.model().all_items
- def fset(self, items):
- self.mcompleter.model().set_items(items)
- return property(fget=fget, fset=fset)
+ @all_items.setter
+ def all_items(self, items):
+ self.mcompleter.model().set_items(items)
- @dynamic_property
+ @property
def disable_popup(self):
- def fget(self):
- return self.mcompleter.disable_popup
+ return self.mcompleter.disable_popup
- def fset(self, val):
- self.mcompleter.disable_popup = bool(val)
- return property(fget=fget, fset=fset)
+ @disable_popup.setter
+ def disable_popup(self, val):
+ self.mcompleter.disable_popup = bool(val)
# }}}
def event(self, ev):
@@ -471,23 +469,21 @@ def show_initial_value(self, what):
self.setText(what)
self.lineEdit().selectAll()
- @dynamic_property
+ @property
def all_items(self):
- def fget(self):
- return self.lineEdit().all_items
+ return self.lineEdit().all_items
- def fset(self, val):
- self.lineEdit().all_items = val
- return property(fget=fget, fset=fset)
+ @all_items.setter
+ def all_items(self, val):
+ self.lineEdit().all_items = val
- @dynamic_property
+ @property
def disable_popup(self):
- def fget(self):
- return self.lineEdit().disable_popup
+ return self.lineEdit().disable_popup
- def fset(self, val):
- self.lineEdit().disable_popup = bool(val)
- return property(fget=fget, fset=fset)
+ @disable_popup.setter
+ def disable_popup(self, val):
+ self.lineEdit().disable_popup = bool(val)
# }}}
def text(self):
diff --git a/src/calibre/gui2/covers.py b/src/calibre/gui2/covers.py
index d6103c6072..c0cdde8ee2 100644
--- a/src/calibre/gui2/covers.py
+++ b/src/calibre/gui2/covers.py
@@ -43,14 +43,13 @@ def __init__(self, color, parent=None):
self.setIcon(QIcon(self.pix))
self.clicked.connect(self.choose_color)
- @dynamic_property
+ @property
def color(self):
- def fget(self):
- return self._color.name(QColor.HexRgb)[1:]
+ return self._color.name(QColor.HexRgb)[1:]
- def fset(self, val):
- self._color = QColor('#' + val)
- return property(fget=fget, fset=fset)
+ @color.setter
+ def color(self, val):
+ self._color = QColor('#' + val)
def update_display(self):
self.pix.fill(self._color)
diff --git a/src/calibre/gui2/custom_column_widgets.py b/src/calibre/gui2/custom_column_widgets.py
index c0bfef6bf0..1740271ce0 100644
--- a/src/calibre/gui2/custom_column_widgets.py
+++ b/src/calibre/gui2/custom_column_widgets.py
@@ -377,14 +377,13 @@ def getter(self):
val = None
return val
- @dynamic_property
+ @property
def tab(self):
- def fget(self):
- return self._tb.tab
+ return self._tb.tab
- def fset(self, val):
- self._tb.tab = val
- return property(fget=fget, fset=fset)
+ @tab.setter
+ def tab(self, val):
+ self._tb.tab = val
def connect_data_changed(self, slot):
self._tb.data_changed.connect(slot)
diff --git a/src/calibre/gui2/device.py b/src/calibre/gui2/device.py
index f918421e6d..c7f96e46c0 100644
--- a/src/calibre/gui2/device.py
+++ b/src/calibre/gui2/device.py
@@ -1367,29 +1367,26 @@ def sync_catalogs(self, send_ids=None, do_auto_convert=True):
memory=[files, remove])
self.status_bar.show_message(_('Sending catalogs to device.'), 5000)
- @dynamic_property
+ @property
def news_to_be_synced(self):
- doc = 'Set of ids to be sent to device'
+ 'Set of ids to be sent to device'
+ ans = []
+ try:
+ ans = self.library_view.model().db.prefs.get('news_to_be_synced',
+ [])
+ except:
+ import traceback
+ traceback.print_exc()
+ return set(ans)
- def fget(self):
- ans = []
- try:
- ans = self.library_view.model().db.prefs.get('news_to_be_synced',
- [])
- except:
- import traceback
- traceback.print_exc()
- return set(ans)
-
- def fset(self, ids):
- try:
- self.library_view.model().db.new_api.set_pref('news_to_be_synced',
- list(ids))
- except:
- import traceback
- traceback.print_exc()
-
- return property(fget=fget, fset=fset, doc=doc)
+ @news_to_be_synced.setter
+ def news_to_be_synced(self, ids):
+ try:
+ self.library_view.model().db.new_api.set_pref('news_to_be_synced',
+ list(ids))
+ except:
+ import traceback
+ traceback.print_exc()
def sync_news(self, send_ids=None, do_auto_convert=True):
if self.device_connected:
diff --git a/src/calibre/gui2/dialogs/custom_recipes.py b/src/calibre/gui2/dialogs/custom_recipes.py
index 7b33412c5c..116c7acd0b 100644
--- a/src/calibre/gui2/dialogs/custom_recipes.py
+++ b/src/calibre/gui2/dialogs/custom_recipes.py
@@ -378,32 +378,31 @@ def validate(self):
return False
return True
- @dynamic_property
+ @property
def recipe_source(self):
- def fget(self):
- title = self.title.text().strip()
- feeds = [self.feeds.item(i).data(Qt.UserRole) for i in range(self.feeds.count())]
- return options_to_recipe_source(title, self.oldest_article.value(), self.max_articles.value(), feeds)
+ title = self.title.text().strip()
+ feeds = [self.feeds.item(i).data(Qt.UserRole) for i in range(self.feeds.count())]
+ return options_to_recipe_source(title, self.oldest_article.value(), self.max_articles.value(), feeds)
- def fset(self, src):
- self.feeds.clear()
- self.feed_title.clear()
- self.feed_url.clear()
- if src is None:
- self.title.setText(_('My news source'))
- self.oldest_article.setValue(7)
- self.max_articles.setValue(100)
- else:
- recipe = compile_recipe(src)
- self.title.setText(recipe.title)
- self.oldest_article.setValue(recipe.oldest_article)
- self.max_articles.setValue(recipe.max_articles_per_feed)
- for x in (recipe.feeds or ()):
- title, url = ('', x) if len(x) == 1 else x
- QListWidgetItem('%s - %s' % (title, url), self.feeds).setData(Qt.UserRole, (title, url))
+ @recipe_source.setter
+ def recipe_source(self, src):
+ self.feeds.clear()
+ self.feed_title.clear()
+ self.feed_url.clear()
+ if src is None:
+ self.title.setText(_('My news source'))
+ self.oldest_article.setValue(7)
+ self.max_articles.setValue(100)
+ else:
+ recipe = compile_recipe(src)
+ self.title.setText(recipe.title)
+ self.oldest_article.setValue(recipe.oldest_article)
+ self.max_articles.setValue(recipe.max_articles_per_feed)
+ for x in (recipe.feeds or ()):
+ title, url = ('', x) if len(x) == 1 else x
+ QListWidgetItem('%s - %s' % (title, url), self.feeds).setData(Qt.UserRole, (title, url))
- return property(fget=fget, fset=fset)
# }}}
@@ -431,16 +430,13 @@ def validate(self):
return False
return True
- @dynamic_property
+ @property
def recipe_source(self):
+ return self.editor.toPlainText()
- def fget(self):
- return self.editor.toPlainText()
-
- def fset(self, src):
- self.editor.load_text(src, syntax='python', doc_name='')
-
- return property(fget=fget, fset=fset)
+ @recipe_source.setter
+ def recipe_source(self, src):
+ self.editor.load_text(src, syntax='python', doc_name='')
def sizeHint(self):
return QSize(800, 500)
diff --git a/src/calibre/gui2/dialogs/progress.py b/src/calibre/gui2/dialogs/progress.py
index 239f8d4c88..63a44a90d3 100644
--- a/src/calibre/gui2/dialogs/progress.py
+++ b/src/calibre/gui2/dialogs/progress.py
@@ -64,14 +64,13 @@ def set_msg(self, msg=''):
def set_value(self, val):
self.value = val
- @dynamic_property
+ @property
def value(self):
- def fset(self, val):
- return self.bar.setValue(val)
+ return self.bar.value()
- def fget(self):
- return self.bar.value()
- return property(fget=fget, fset=fset)
+ @value.setter
+ def value(self, val):
+ self.bar.setValue(val)
def set_min(self, min):
self.min = min
@@ -79,42 +78,38 @@ def set_min(self, min):
def set_max(self, max):
self.max = max
- @dynamic_property
+ @property
def max(self):
- def fget(self):
- return self.bar.maximum()
+ return self.bar.maximum()
- def fset(self, val):
- self.bar.setMaximum(val)
- return property(fget=fget, fset=fset)
+ @max.setter
+ def max(self, val):
+ self.bar.setMaximum(val)
- @dynamic_property
+ @property
def min(self):
- def fget(self):
- return self.bar.minimum()
+ return self.bar.minimum()
- def fset(self, val):
- self.bar.setMinimum(val)
- return property(fget=fget, fset=fset)
+ @min.setter
+ def min(self, val):
+ self.bar.setMinimum(val)
- @dynamic_property
+ @property
def title(self):
- def fget(self):
- return self.title_label.text()
+ return self.title_label.text()
- def fset(self, val):
- self.title_label.setText(unicode_type(val or ''))
- return property(fget=fget, fset=fset)
+ @title.setter
+ def title(self, val):
+ self.title_label.setText(unicode_type(val or ''))
- @dynamic_property
+ @property
def msg(self):
- def fget(self):
- return self.message.text()
+ return self.message.text()
- def fset(self, val):
- val = unicode_type(val or '')
- self.message.setText(elided_text(val, self.font(), self.message.minimumWidth()-10))
- return property(fget=fget, fset=fset)
+ @msg.setter
+ def msg(self, val):
+ val = unicode_type(val or '')
+ self.message.setText(elided_text(val, self.font(), self.message.minimumWidth()-10))
def _canceled(self, *args):
self.canceled = True
diff --git a/src/calibre/gui2/font_family_chooser.py b/src/calibre/gui2/font_family_chooser.py
index 8897ee1cbf..e35702b294 100644
--- a/src/calibre/gui2/font_family_chooser.py
+++ b/src/calibre/gui2/font_family_chooser.py
@@ -353,18 +353,17 @@ def __init__(self, parent=None):
def clear_family(self):
self.font_family = None
- @dynamic_property
+ @property
def font_family(self):
- def fget(self):
- return self._current_family
+ return self._current_family
- def fset(self, val):
- if not val:
- val = None
- self._current_family = val
- self.button.setText(val or self.default_text)
- self.family_changed.emit(val)
- return property(fget=fget, fset=fset)
+ @font_family.setter
+ def font_family(self, val):
+ if not val:
+ val = None
+ self._current_family = val
+ self.button.setText(val or self.default_text)
+ self.family_changed.emit(val)
def show_chooser(self):
d = FontFamilyDialog(self.font_family, self)
diff --git a/src/calibre/gui2/languages.py b/src/calibre/gui2/languages.py
index 70c4302a9d..d9a402c96b 100644
--- a/src/calibre/gui2/languages.py
+++ b/src/calibre/gui2/languages.py
@@ -60,23 +60,20 @@ def vals(self):
parts = [x.strip() for x in raw.split(',')]
return [self.comma_rmap.get(x, x) for x in parts]
- @dynamic_property
+ @property
def lang_codes(self):
+ vals = self.vals
+ ans = []
+ for name in vals:
+ if name:
+ code = self._rmap.get(lower(name), None)
+ if code is not None:
+ ans.append(code)
+ return ans
- def fget(self):
- vals = self.vals
- ans = []
- for name in vals:
- if name:
- code = self._rmap.get(lower(name), None)
- if code is not None:
- ans.append(code)
- return ans
-
- def fset(self, lang_codes):
- self.set_lang_codes(lang_codes, allow_undo=False)
-
- return property(fget=fget, fset=fset)
+ @lang_codes.setter
+ def lang_codes(self, lang_codes):
+ self.set_lang_codes(lang_codes, allow_undo=False)
def set_lang_codes(self, lang_codes, allow_undo=True):
ans = []
diff --git a/src/calibre/gui2/library/views.py b/src/calibre/gui2/library/views.py
index a5ce76815d..d122d58209 100644
--- a/src/calibre/gui2/library/views.py
+++ b/src/calibre/gui2/library/views.py
@@ -186,18 +186,17 @@ def __exit__(self, *args):
view.horizontalScrollBar().setValue(self.hscroll)
self.init_vals()
- @dynamic_property
+ @property
def state(self):
- def fget(self):
- self.__enter__()
- return {x:getattr(self, x) for x in ('selected_ids', 'current_id',
- 'vscroll', 'hscroll')}
+ self.__enter__()
+ return {x:getattr(self, x) for x in ('selected_ids', 'current_id',
+ 'vscroll', 'hscroll')}
- def fset(self, state):
- for k, v in iteritems(state):
- setattr(self, k, v)
- self.__exit__()
- return property(fget=fget, fset=fset)
+ @state.setter
+ def state(self, state):
+ for k, v in iteritems(state):
+ setattr(self, k, v)
+ self.__exit__()
# }}}
@@ -1161,24 +1160,23 @@ def get_selected_ids(self):
ans.append(i)
return ans
- @dynamic_property
+ @property
def current_id(self):
- def fget(self):
- try:
- return self.model().id(self.currentIndex())
- except:
- pass
- return None
+ try:
+ return self.model().id(self.currentIndex())
+ except:
+ pass
+ return None
- def fset(self, val):
- if val is None:
- return
- m = self.model()
- for row in range(m.rowCount(QModelIndex())):
- if m.id(row) == val:
- self.set_current_row(row, select=False)
- break
- return property(fget=fget, fset=fset)
+ @current_id.setter
+ def current_id(self, val):
+ if val is None:
+ return
+ m = self.model()
+ for row in range(m.rowCount(QModelIndex())):
+ if m.id(row) == val:
+ self.set_current_row(row, select=False)
+ break
@property
def next_id(self):
diff --git a/src/calibre/gui2/metadata/basic_widgets.py b/src/calibre/gui2/metadata/basic_widgets.py
index 1bf2148fd1..5eb16fe328 100644
--- a/src/calibre/gui2/metadata/basic_widgets.py
+++ b/src/calibre/gui2/metadata/basic_widgets.py
@@ -72,14 +72,13 @@ def initialize(self, db, id_):
def commit(self, db, id_):
return True
- @dynamic_property
+ @property
def current_val(self):
- # Present in most but not all basic metadata widgets
- def fget(self):
- return None
- def fset(self, val):
- pass
- return property(fget=fget, fset=fset)
+ return None
+
+ @current_val.setter
+ def current_val(self, val):
+ pass
'''
@@ -225,24 +224,22 @@ def commit(self, db, id_):
# to work even if some of the book files are opened in windows.
getattr(db, 'set_'+ self.TITLE_ATTR)(id_, title, notify=False)
- @dynamic_property
+ @property
def current_val(self):
- def fget(self):
- title = clean_text(unicode_type(self.text()))
- if not title:
- title = self.get_default()
- return title.strip()
+ title = clean_text(unicode_type(self.text()))
+ if not title:
+ title = self.get_default()
+ return title.strip()
- def fset(self, val):
- if hasattr(val, 'strip'):
- val = val.strip()
- if not val:
- val = self.get_default()
- self.set_text(val)
- self.setCursorPosition(0)
-
- return property(fget=fget, fset=fset)
+ @current_val.setter
+ def current_val(self, val):
+ if hasattr(val, 'strip'):
+ val = val.strip()
+ if not val:
+ val = self.get_default()
+ self.set_text(val)
+ self.setCursorPosition(0)
def break_cycles(self):
self.dialog = None
@@ -416,22 +413,20 @@ def commit(self, db, id_):
self.books_to_refresh |= db.set_authors(id_, authors, notify=False,
allow_case_change=True)
- @dynamic_property
+ @property
def current_val(self):
- def fget(self):
- au = clean_text(unicode_type(self.text()))
- if not au:
- au = self.get_default()
- return string_to_authors(au)
+ au = clean_text(unicode_type(self.text()))
+ if not au:
+ au = self.get_default()
+ return string_to_authors(au)
- def fset(self, val):
- if not val:
- val = [self.get_default()]
- self.set_edit_text(' & '.join([x.strip() for x in val]))
- self.lineEdit().setCursorPosition(0)
-
- return property(fget=fget, fset=fset)
+ @current_val.setter
+ def current_val(self, val):
+ if not val:
+ val = [self.get_default()]
+ self.set_edit_text(' & '.join([x.strip() for x in val]))
+ self.lineEdit().setCursorPosition(0)
def break_cycles(self):
self.db = self.dialog = None
@@ -485,19 +480,17 @@ def __init__(self, parent, authors_edit, autogen_button, db,
self.first_time = True
self.update_state()
- @dynamic_property
+ @property
def current_val(self):
- def fget(self):
- return clean_text(unicode_type(self.text()))
+ return clean_text(unicode_type(self.text()))
- def fset(self, val):
- if not val:
- val = ''
- self.set_text(val.strip())
- self.setCursorPosition(0)
-
- return property(fget=fget, fset=fset)
+ @current_val.setter
+ def current_val(self, val):
+ if not val:
+ val = ''
+ self.set_text(val.strip())
+ self.setCursorPosition(0)
def update_state_and_val(self):
# Handle case change if the authors box changed
@@ -613,19 +606,17 @@ def __init__(self, parent):
self.books_to_refresh = set([])
self.lineEdit().textChanged.connect(self.data_changed)
- @dynamic_property
+ @property
def current_val(self):
- def fget(self):
- return clean_text(unicode_type(self.currentText()))
+ return clean_text(unicode_type(self.currentText()))
- def fset(self, val):
- if not val:
- val = ''
- self.set_edit_text(val.strip())
- self.lineEdit().setCursorPosition(0)
-
- return property(fget=fget, fset=fset)
+ @current_val.setter
+ def current_val(self, val):
+ if not val:
+ val = ''
+ self.set_edit_text(val.strip())
+ self.lineEdit().setCursorPosition(0)
def initialize(self, db, id_):
self.books_to_refresh = set([])
@@ -672,19 +663,17 @@ def __init__(self, parent, series_edit):
def enable(self, *args):
self.setEnabled(bool(self.series_edit.current_val))
- @dynamic_property
+ @property
def current_val(self):
- def fget(self):
- return self.value()
+ return self.value()
- def fset(self, val):
- if val is None:
- val = 1.0
- val = float(val)
- self.set_spinbox_value(val)
-
- return property(fget=fget, fset=fset)
+ @current_val.setter
+ def current_val(self, val):
+ if val is None:
+ val = 1.0
+ val = float(val)
+ self.set_spinbox_value(val)
def initialize(self, db, id_):
self.db = db
@@ -1255,31 +1244,29 @@ def initialize(self, db, id_):
def changed(self):
return self.current_val != self.original_val
- @dynamic_property
+ @property
def current_val(self):
- def fget(self):
- return self._cdata
+ return self._cdata
- def fset(self, cdata):
- self._cdata = None
- self.cdata_before_trim = None
- pm = QPixmap()
- if cdata:
- pm.loadFromData(cdata)
- if pm.isNull():
- pm = QPixmap(I('default_cover.png'))
- else:
- self._cdata = cdata
- pm.setDevicePixelRatio(getattr(self, 'devicePixelRatioF', self.devicePixelRatio)())
- self.setPixmap(pm)
- tt = _('This book has no cover')
- if self._cdata:
- tt = _('Cover size: %(width)d x %(height)d pixels') % \
- dict(width=pm.width(), height=pm.height())
- self.setToolTip(tt)
- self.data_changed.emit()
-
- return property(fget=fget, fset=fset)
+ @current_val.setter
+ def current_val(self, cdata):
+ self._cdata = None
+ self.cdata_before_trim = None
+ pm = QPixmap()
+ if cdata:
+ pm.loadFromData(cdata)
+ if pm.isNull():
+ pm = QPixmap(I('default_cover.png'))
+ else:
+ self._cdata = cdata
+ pm.setDevicePixelRatio(getattr(self, 'devicePixelRatioF', self.devicePixelRatio)())
+ self.setPixmap(pm)
+ tt = _('This book has no cover')
+ if self._cdata:
+ tt = _('Cover size: %(width)d x %(height)d pixels') % \
+ dict(width=pm.width(), height=pm.height())
+ self.setToolTip(tt)
+ self.data_changed.emit()
def commit(self, db, id_):
if self.changed:
@@ -1309,20 +1296,19 @@ class CommentsEdit(Editor, ToMetadataMixin): # {{{
FIELD_NAME = 'comments'
toolbar_prefs_name = 'metadata-comments-editor-widget-hidden-toolbars'
- @dynamic_property
+ @property
def current_val(self):
- def fget(self):
- return self.html
+ return self.html
- def fset(self, val):
- if not val or not val.strip():
- val = ''
- else:
- val = comments_to_html(val)
- self.set_html(val, self.allow_undo)
- self.wyswyg_dirtied()
- self.data_changed.emit()
- return property(fget=fget, fset=fset)
+ @current_val.setter
+ def current_val(self, val):
+ if not val or not val.strip():
+ val = ''
+ else:
+ val = comments_to_html(val)
+ self.set_html(val, self.allow_undo)
+ self.wyswyg_dirtied()
+ self.data_changed.emit()
def initialize(self, db, id_):
path = db.abspath(id_, index_is_id=True)
@@ -1350,14 +1336,13 @@ def __init__(self, parent):
self.setWhatsThis(self.TOOLTIP)
self.currentTextChanged.connect(self.data_changed)
- @dynamic_property
+ @property
def current_val(self):
- def fget(self):
- return self.rating_value
+ return self.rating_value
- def fset(self, val):
- self.rating_value = val
- return property(fget=fget, fset=fset)
+ @current_val.setter
+ def current_val(self, val):
+ self.rating_value = val
def initialize(self, db, id_):
val = db.rating(id_, index_is_id=True)
@@ -1390,17 +1375,16 @@ def __init__(self, parent):
self.setToolTip(self.TOOLTIP)
self.setWhatsThis(self.TOOLTIP)
- @dynamic_property
+ @property
def current_val(self):
- def fget(self):
- return [clean_text(x) for x in unicode_type(self.text()).split(',')]
+ return [clean_text(x) for x in unicode_type(self.text()).split(',')]
- def fset(self, val):
- if not val:
- val = []
- self.set_edit_text(', '.join([x.strip() for x in val]))
- self.setCursorPosition(0)
- return property(fget=fget, fset=fset)
+ @current_val.setter
+ def current_val(self, val):
+ if not val:
+ val = []
+ self.set_edit_text(', '.join([x.strip() for x in val]))
+ self.setCursorPosition(0)
def initialize(self, db, id_):
self.books_to_refresh = set([])
@@ -1454,14 +1438,13 @@ def __init__(self, *args, **kwargs):
self.textChanged.connect(self.data_changed)
self.setToolTip(self.TOOLTIP)
- @dynamic_property
+ @property
def current_val(self):
- def fget(self):
- return self.lang_codes
+ return self.lang_codes
- def fset(self, val):
- self.set_lang_codes(val, self.allow_undo)
- return property(fget=fget, fset=fset)
+ @current_val.setter
+ def current_val(self, val):
+ self.set_lang_codes(val, self.allow_undo)
def initialize(self, db, id_):
self.init_langs(db)
@@ -1562,44 +1545,43 @@ def edit_identifiers(self):
if d.exec_() == d.Accepted:
self.current_val = d.get_identifiers()
- @dynamic_property
+ @property
def current_val(self):
- def fget(self):
- raw = unicode_type(self.text()).strip()
- parts = [clean_text(x) for x in raw.split(',')]
- ans = {}
- for x in parts:
- c = x.split(':')
- if len(c) > 1:
- itype = c[0].lower()
- c = ':'.join(c[1:])
- if itype == 'isbn':
- v = check_isbn(c)
- if v is not None:
- c = v
- ans[itype] = c
- return ans
-
- def fset(self, val):
- if not val:
- val = {}
-
- def keygen(x):
- x = x[0]
- if x == 'isbn':
- x = '00isbn'
- return x
- for k in list(val):
- if k == 'isbn':
- v = check_isbn(k)
+ raw = unicode_type(self.text()).strip()
+ parts = [clean_text(x) for x in raw.split(',')]
+ ans = {}
+ for x in parts:
+ c = x.split(':')
+ if len(c) > 1:
+ itype = c[0].lower()
+ c = ':'.join(c[1:])
+ if itype == 'isbn':
+ v = check_isbn(c)
if v is not None:
- val[k] = v
- ids = sorted(iteritems(val), key=keygen)
- txt = ', '.join(['%s:%s'%(k.lower(), vl) for k, vl in ids])
- # Use selectAll + insert instead of setText so that undo works
- self.selectAll(), self.insert(txt.strip())
- self.setCursorPosition(0)
- return property(fget=fget, fset=fset)
+ c = v
+ ans[itype] = c
+ return ans
+
+ @current_val.setter
+ def current_val(self, val):
+ if not val:
+ val = {}
+
+ def keygen(x):
+ x = x[0]
+ if x == 'isbn':
+ x = '00isbn'
+ return x
+ for k in list(val):
+ if k == 'isbn':
+ v = check_isbn(k)
+ if v is not None:
+ val[k] = v
+ ids = sorted(iteritems(val), key=keygen)
+ txt = ', '.join(['%s:%s'%(k.lower(), vl) for k, vl in ids])
+ # Use selectAll + insert instead of setText so that undo works
+ self.selectAll(), self.insert(txt.strip())
+ self.setCursorPosition(0)
def initialize(self, db, id_):
self.original_val = db.get_identifiers(id_, index_is_id=True)
@@ -1778,19 +1760,17 @@ def __init__(self, parent):
self.clear_button.setToolTip(_('Clear publisher'))
self.clear_button.clicked.connect(self.clearEditText)
- @dynamic_property
+ @property
def current_val(self):
- def fget(self):
- return clean_text(unicode_type(self.currentText()))
+ return clean_text(unicode_type(self.currentText()))
- def fset(self, val):
- if not val:
- val = ''
- self.set_edit_text(val.strip())
- self.lineEdit().setCursorPosition(0)
-
- return property(fget=fget, fset=fset)
+ @current_val.setter
+ def current_val(self, val):
+ if not val:
+ val = ''
+ self.set_edit_text(val.strip())
+ self.lineEdit().setCursorPosition(0)
def initialize(self, db, id_):
self.books_to_refresh = set([])
@@ -1857,18 +1837,17 @@ def __init__(self, parent, create_clear_button=True):
def reset_date(self, *args):
self.current_val = None
- @dynamic_property
+ @property
def current_val(self):
- def fget(self):
- return qt_to_dt(self.dateTime(), as_utc=False)
+ return qt_to_dt(self.dateTime(), as_utc=False)
- def fset(self, val):
- if val is None or is_date_undefined(val):
- val = UNDEFINED_DATE
- else:
- val = as_local_time(val)
- self.set_spinbox_value(val)
- return property(fget=fget, fset=fset)
+ @current_val.setter
+ def current_val(self, val):
+ if val is None or is_date_undefined(val):
+ val = UNDEFINED_DATE
+ else:
+ val = as_local_time(val)
+ self.set_spinbox_value(val)
def initialize(self, db, id_):
self.current_val = getattr(db, self.ATTR)(id_, index_is_id=True)
diff --git a/src/calibre/gui2/metadata/diff.py b/src/calibre/gui2/metadata/diff.py
index 9f5b1fe9b6..9fdc166282 100644
--- a/src/calibre/gui2/metadata/diff.py
+++ b/src/calibre/gui2/metadata/diff.py
@@ -49,29 +49,28 @@ def __init__(self, field, is_new, parent, metadata, extra):
self.set_separator(sep)
self.textChanged.connect(self.changed)
- @dynamic_property
+ @property
def value(self):
- def fget(self):
- val = unicode_type(self.text()).strip()
- ism = self.metadata['is_multiple']
- if ism:
- if not val:
- val = []
- else:
- val = val.strip(ism['list_to_ui'].strip())
- val = [x.strip() for x in val.split(ism['list_to_ui']) if x.strip()]
- return val
+ val = unicode_type(self.text()).strip()
+ ism = self.metadata['is_multiple']
+ if ism:
+ if not val:
+ val = []
+ else:
+ val = val.strip(ism['list_to_ui'].strip())
+ val = [x.strip() for x in val.split(ism['list_to_ui']) if x.strip()]
+ return val
- def fset(self, val):
- ism = self.metadata['is_multiple']
- if ism:
- if not val:
- val = ''
- else:
- val = ism['list_to_ui'].join(val)
- self.setText(val)
- self.setCursorPosition(0)
- return property(fget=fget, fset=fset)
+ @value.setter
+ def value(self, val):
+ ism = self.metadata['is_multiple']
+ if ism:
+ if not val:
+ val = ''
+ else:
+ val = ism['list_to_ui'].join(val)
+ self.setText(val)
+ self.setCursorPosition(0)
def from_mi(self, mi):
val = mi.get(self.field, default='') or ''
@@ -85,15 +84,14 @@ def to_mi(self, mi):
elif self.field == 'authors':
mi.set('author_sort', authors_to_sort_string(val))
- @dynamic_property
+ @property
def current_val(self):
- def fget(self):
- return unicode_type(self.text())
+ return unicode_type(self.text())
- def fset(self, val):
- self.setText(val)
- self.setCursorPosition(0)
- return property(fget=fget, fset=fset)
+ @current_val.setter
+ def current_val(self, val):
+ self.setText(val)
+ self.setCursorPosition(0)
@property
def is_blank(self):
@@ -119,14 +117,13 @@ def __init__(self, field, is_new, parent, metadata, extra):
if not is_new:
self.lineEdit().setReadOnly(True)
- @dynamic_property
+ @property
def current_val(self):
- def fget(self):
- return self.lang_codes
+ return self.lang_codes
- def fset(self, val):
- self.lang_codes = val
- return property(fget=fget, fset=fset)
+ @current_val.setter
+ def current_val(self, val):
+ self.lang_codes = val
def from_mi(self, mi):
self.lang_codes = mi.languages
@@ -241,17 +238,16 @@ def from_mi(self, mi):
def to_mi(self, mi):
mi.set_identifiers(self.as_dict)
- @dynamic_property
+ @property
def as_dict(self):
- def fget(self):
- parts = (x.strip() for x in self.current_val.split(',') if x.strip())
- return {k:v for k, v in iteritems({x.partition(':')[0].strip():x.partition(':')[-1].strip() for x in parts}) if k and v}
+ parts = (x.strip() for x in self.current_val.split(',') if x.strip())
+ return {k:v for k, v in iteritems({x.partition(':')[0].strip():x.partition(':')[-1].strip() for x in parts}) if k and v}
- def fset(self, val):
- val = ('%s:%s' % (k, v) for k, v in iteritems(val))
- self.setText(', '.join(val))
- self.setCursorPosition(0)
- return property(fget=fget, fset=fset)
+ @as_dict.setter
+ def as_dict(self, val):
+ val = ('%s:%s' % (k, v) for k, v in iteritems(val))
+ self.setText(', '.join(val))
+ self.setCursorPosition(0)
class CommentsEdit(Editor):
@@ -269,15 +265,14 @@ def __init__(self, field, is_new, parent, metadata, extra):
self.hide_toolbars()
self.set_readonly(True)
- @dynamic_property
+ @property
def current_val(self):
- def fget(self):
- return self.html
+ return self.html
- def fset(self, val):
- self.html = val or ''
- self.changed.emit()
- return property(fget=fget, fset=fset)
+ @current_val.setter
+ def current_val(self, val):
+ self.html = val or ''
+ self.changed.emit()
def from_mi(self, mi):
val = mi.get(self.field, default='')
@@ -315,16 +310,15 @@ def __init__(self, field, is_new, parent, metadata, extra):
def is_blank(self):
return self.pixmap is None
- @dynamic_property
+ @property
def current_val(self):
- def fget(self):
- return self.pixmap
+ return self.pixmap
- def fset(self, val):
- self.pixmap = val
- self.changed.emit()
- self.update()
- return property(fget=fget, fset=fset)
+ @current_val.setter
+ def current_val(self, val):
+ self.pixmap = val
+ self.changed.emit()
+ self.update()
def from_mi(self, mi):
p = getattr(mi, 'cover', None)
diff --git a/src/calibre/gui2/preferences/coloring.py b/src/calibre/gui2/preferences/coloring.py
index a3383a7b1a..60ae95b98f 100644
--- a/src/calibre/gui2/preferences/coloring.py
+++ b/src/calibre/gui2/preferences/coloring.py
@@ -138,35 +138,33 @@ def __init__(self, fm, parent=None):
b.setSizeAdjustPolicy(b.AdjustToMinimumContentsLengthWithIcon)
b.setMinimumContentsLength(20)
- @dynamic_property
+ @property
def current_col(self):
- def fget(self):
- idx = self.column_box.currentIndex()
- return unicode_type(self.column_box.itemData(idx) or '')
+ idx = self.column_box.currentIndex()
+ return unicode_type(self.column_box.itemData(idx) or '')
- def fset(self, val):
- for idx in range(self.column_box.count()):
- c = unicode_type(self.column_box.itemData(idx) or '')
- if c == val:
- self.column_box.setCurrentIndex(idx)
- return
- raise ValueError('Column %r not found'%val)
- return property(fget=fget, fset=fset)
+ @current_col.setter
+ def current_col(self, val):
+ for idx in range(self.column_box.count()):
+ c = unicode_type(self.column_box.itemData(idx) or '')
+ if c == val:
+ self.column_box.setCurrentIndex(idx)
+ return
+ raise ValueError('Column %r not found'%val)
- @dynamic_property
+ @property
def current_action(self):
- def fget(self):
- idx = self.action_box.currentIndex()
- return unicode_type(self.action_box.itemData(idx) or '')
+ idx = self.action_box.currentIndex()
+ return unicode_type(self.action_box.itemData(idx) or '')
- def fset(self, val):
- for idx in range(self.action_box.count()):
- c = unicode_type(self.action_box.itemData(idx) or '')
- if c == val:
- self.action_box.setCurrentIndex(idx)
- return
- raise ValueError('Action %r not valid for current column'%val)
- return property(fget=fget, fset=fset)
+ @current_action.setter
+ def current_action(self, val):
+ for idx in range(self.action_box.count()):
+ c = unicode_type(self.action_box.itemData(idx) or '')
+ if c == val:
+ self.action_box.setCurrentIndex(idx)
+ return
+ raise ValueError('Action %r not valid for current column'%val)
@property
def current_val(self):
@@ -176,26 +174,24 @@ def current_val(self):
ans = rmap.get(lower(ans), ans)
return ans
- @dynamic_property
+ @property
def condition(self):
- def fget(self):
- c, a, v = (self.current_col, self.current_action,
- self.current_val)
- if not c or not a:
- return None
- return (c, a, v)
+ c, a, v = (self.current_col, self.current_action,
+ self.current_val)
+ if not c or not a:
+ return None
+ return (c, a, v)
- def fset(self, condition):
- c, a, v = condition
- if not v:
- v = ''
- v = v.strip()
- self.current_col = c
- self.current_action = a
- self.value_box.setText(v)
-
- return property(fget=fget, fset=fset)
+ @condition.setter
+ def condition(self, condition):
+ c, a, v = condition
+ if not v:
+ v = ''
+ v = v.strip()
+ self.current_col = c
+ self.current_action = a
+ self.value_box.setText(v)
def init_action_box(self):
self.action_box.blockSignals(True)
diff --git a/src/calibre/gui2/tweak_book/editor/image.py b/src/calibre/gui2/tweak_book/editor/image.py
index 2c1b72aa5c..580b0d02db 100644
--- a/src/calibre/gui2/tweak_book/editor/image.py
+++ b/src/calibre/gui2/tweak_book/editor/image.py
@@ -62,23 +62,21 @@ def keep_ar(self, which):
other.setValue(oval)
other.blockSignals(False)
- @dynamic_property
+ @property
def width(self):
- def fget(self):
- return self._width.value()
+ return self._width.value()
- def fset(self, val):
- self._width.setValue(val)
- return property(fget=fget, fset=fset)
+ @width.setter
+ def width(self, val):
+ self._width.setValue(val)
- @dynamic_property
+ @property
def height(self):
- def fget(self):
- return self._height.value()
+ return self._height.value()
- def fset(self, val):
- self._height.setValue(val)
- return property(fget=fget, fset=fset)
+ @height.setter
+ def height(self, val):
+ self._height.setValue(val)
# }}}
@@ -111,24 +109,22 @@ def __init__(self, syntax, parent=None):
self.canvas.undo_redo_state_changed.connect(self.undo_redo_state_changed)
self.canvas.selection_state_changed.connect(self.update_clipboard_actions)
- @dynamic_property
+ @property
def is_modified(self):
- def fget(self):
- return self._is_modified
+ return self._is_modified
- def fset(self, val):
- self._is_modified = val
- self.modification_state_changed.emit(val)
- return property(fget=fget, fset=fset)
+ @is_modified.setter
+ def is_modified(self, val):
+ self._is_modified = val
+ self.modification_state_changed.emit(val)
- @dynamic_property
+ @property
def current_editing_state(self):
- def fget(self):
- return {}
+ return {}
- def fset(self, val):
- pass
- return property(fget=fget, fset=fset)
+ @current_editing_state.setter
+ def current_editing_state(self, val):
+ pass
@property
def undo_available(self):
@@ -138,14 +134,13 @@ def undo_available(self):
def redo_available(self):
return self.canvas.redo_action.isEnabled()
- @dynamic_property
+ @property
def current_line(self):
- def fget(self):
- return 0
+ return 0
- def fset(self, val):
- pass
- return property(fget=fget, fset=fset)
+ @current_line.setter
+ def current_line(self, val):
+ pass
@property
def number_of_lines(self):
@@ -160,15 +155,14 @@ def change_document_name(self, newname):
def get_raw_data(self):
return self.canvas.get_image_data(quality=self.quality)
- @dynamic_property
+ @property
def data(self):
- def fget(self):
- return self.get_raw_data()
+ return self.get_raw_data()
- def fset(self, val):
- self.canvas.load_image(val)
- self._is_modified = False # The image_changed signal will have been triggered causing this editor to be incorrectly marked as modified
- return property(fget=fget, fset=fset)
+ @data.setter
+ def data(self, val):
+ self.canvas.load_image(val)
+ self._is_modified = False # The image_changed signal will have been triggered causing this editor to be incorrectly marked as modified
def replace_data(self, raw, only_if_different=True):
# We ignore only_if_different as it is useless in our case, and
diff --git a/src/calibre/gui2/tweak_book/editor/snippets.py b/src/calibre/gui2/tweak_book/editor/snippets.py
index 23512db75b..fd78baab4f 100644
--- a/src/calibre/gui2/tweak_book/editor/snippets.py
+++ b/src/calibre/gui2/tweak_book/editor/snippets.py
@@ -221,26 +221,25 @@ def apply_selected_text(self, text):
with m:
m.text = text
- @dynamic_property
+ @property
def text(self):
- def fget(self):
- editor = self.editor()
- if editor is None or self.is_deleted:
- return ''
- c = editor.textCursor()
- c.setPosition(self.left), c.setPosition(self.right, c.KeepAnchor)
- return editor.selected_text_from_cursor(c)
+ editor = self.editor()
+ if editor is None or self.is_deleted:
+ return ''
+ c = editor.textCursor()
+ c.setPosition(self.left), c.setPosition(self.right, c.KeepAnchor)
+ return editor.selected_text_from_cursor(c)
- def fset(self, text):
- editor = self.editor()
- if editor is None or self.is_deleted:
- return
- c = editor.textCursor()
- c.joinPreviousEditBlock() if self.join_previous_edit else c.beginEditBlock()
- c.setPosition(self.left), c.setPosition(self.right, c.KeepAnchor)
- c.insertText(text)
- c.endEditBlock()
- return property(fget=fget, fset=fset)
+ @text.setter
+ def text(self, text):
+ editor = self.editor()
+ if editor is None or self.is_deleted:
+ return
+ c = editor.textCursor()
+ c.joinPreviousEditBlock() if self.join_previous_edit else c.beginEditBlock()
+ c.setPosition(self.left), c.setPosition(self.right, c.KeepAnchor)
+ c.insertText(text)
+ c.endEditBlock()
def set_editor_cursor(self, editor):
if not self.is_deleted:
@@ -537,20 +536,18 @@ def apply_snip(self, snip, creating_snippet=None):
self.types.item(0).setCheckState(Qt.Checked)
(self.name if self.creating_snippet else self.template).setFocus(Qt.OtherFocusReason)
- @dynamic_property
+ @property
def snip(self):
- def fset(self, snip):
- self.apply_snip(snip)
+ ftypes = []
+ for i in range(self.types.count()):
+ i = self.types.item(i)
+ if i.checkState() == Qt.Checked:
+ ftypes.append(i.data(Qt.UserRole))
+ return {'description':self.name.text().strip(), 'trigger':self.trig.text(), 'template':self.template.toPlainText(), 'syntaxes':ftypes}
- def fget(self):
- ftypes = []
- for i in range(self.types.count()):
- i = self.types.item(i)
- if i.checkState() == Qt.Checked:
- ftypes.append(i.data(Qt.UserRole))
- return {'description':self.name.text().strip(), 'trigger':self.trig.text(), 'template':self.template.toPlainText(), 'syntaxes':ftypes}
-
- return property(fget=fget, fset=fset)
+ @snip.setter
+ def snip(self, snip):
+ self.apply_snip(snip)
def validate(self):
snip = self.snip
diff --git a/src/calibre/gui2/tweak_book/editor/text.py b/src/calibre/gui2/tweak_book/editor/text.py
index 55fc517013..e8eed6d278 100644
--- a/src/calibre/gui2/tweak_book/editor/text.py
+++ b/src/calibre/gui2/tweak_book/editor/text.py
@@ -206,17 +206,15 @@ def add_file(name, data, mt=None):
insert_text(md.html())
return
- @dynamic_property
+ @property
def is_modified(self):
''' True if the document has been modified since it was loaded or since
the last time is_modified was set to False. '''
+ return self.document().isModified()
- def fget(self):
- return self.document().isModified()
-
- def fset(self, val):
- self.document().setModified(bool(val))
- return property(fget=fget, fset=fset)
+ @is_modified.setter
+ def is_modified(self, val):
+ self.document().setModified(bool(val))
def sizeHint(self):
return self.size_hint
diff --git a/src/calibre/gui2/tweak_book/editor/widget.py b/src/calibre/gui2/tweak_book/editor/widget.py
index 6b31933c5f..21c62f0516 100644
--- a/src/calibre/gui2/tweak_book/editor/widget.py
+++ b/src/calibre/gui2/tweak_book/editor/widget.py
@@ -159,28 +159,26 @@ def __init__(self, syntax, parent=None):
self.editor.link_clicked.connect(self.link_clicked)
self.editor.smart_highlighting_updated.connect(self.smart_highlighting_updated)
- @dynamic_property
+ @property
def current_line(self):
- def fget(self):
- return self.editor.textCursor().blockNumber()
+ return self.editor.textCursor().blockNumber()
- def fset(self, val):
- self.editor.go_to_line(val)
- return property(fget=fget, fset=fset)
+ @current_line.setter
+ def current_line(self, val):
+ self.editor.go_to_line(val)
- @dynamic_property
+ @property
def current_editing_state(self):
- def fget(self):
- c = self.editor.textCursor()
- return {'cursor':(c.anchor(), c.position())}
+ c = self.editor.textCursor()
+ return {'cursor':(c.anchor(), c.position())}
- def fset(self, val):
- anchor, position = val.get('cursor', (None, None))
- if anchor is not None and position is not None:
- c = self.editor.textCursor()
- c.setPosition(anchor), c.setPosition(position, c.KeepAnchor)
- self.editor.setTextCursor(c)
- return property(fget=fget, fset=fset)
+ @current_editing_state.setter
+ def current_editing_state(self, val):
+ anchor, position = val.get('cursor', (None, None))
+ if anchor is not None and position is not None:
+ c = self.editor.textCursor()
+ c.setPosition(anchor), c.setPosition(position, c.KeepAnchor)
+ self.editor.setTextCursor(c)
def current_tag(self, for_position_sync=True):
return self.editor.current_tag(for_position_sync=for_position_sync)
@@ -189,18 +187,17 @@ def current_tag(self, for_position_sync=True):
def number_of_lines(self):
return self.editor.blockCount()
- @dynamic_property
+ @property
def data(self):
- def fget(self):
- ans = self.get_raw_data()
- ans, changed = replace_encoding_declarations(ans, enc='utf-8', limit=4*1024)
- if changed:
- self.data = ans
- return ans.encode('utf-8')
+ ans = self.get_raw_data()
+ ans, changed = replace_encoding_declarations(ans, enc='utf-8', limit=4*1024)
+ if changed:
+ self.data = ans
+ return ans.encode('utf-8')
- def fset(self, val):
- self.editor.load_text(val, syntax=self.syntax, doc_name=editor_name(self))
- return property(fget=fget, fset=fset)
+ @data.setter
+ def data(self, val):
+ self.editor.load_text(val, syntax=self.syntax, doc_name=editor_name(self))
def init_from_template(self, template):
self.editor.load_text(template, syntax=self.syntax, process_template=True, doc_name=editor_name(self))
@@ -317,14 +314,13 @@ def go_to_anchor(self, *args, **kwargs):
def has_marked_text(self):
return self.editor.current_search_mark is not None
- @dynamic_property
+ @property
def is_modified(self):
- def fget(self):
- return self.editor.is_modified
+ return self.editor.is_modified
- def fset(self, val):
- self.editor.is_modified = val
- return property(fget=fget, fset=fset)
+ @is_modified.setter
+ def is_modified(self, val):
+ self.editor.is_modified = val
def create_toolbars(self):
self.action_bar = b = self.addToolBar(_('Edit actions tool bar'))
diff --git a/src/calibre/gui2/tweak_book/preview.py b/src/calibre/gui2/tweak_book/preview.py
index 61b443c443..5a325713fa 100644
--- a/src/calibre/gui2/tweak_book/preview.py
+++ b/src/calibre/gui2/tweak_book/preview.py
@@ -370,17 +370,16 @@ def sizeHint(self):
def refresh(self):
self.pageAction(self.page().Reload).trigger()
- @dynamic_property
+ @property
def scroll_pos(self):
- def fget(self):
- mf = self.page().mainFrame()
- return (mf.scrollBarValue(Qt.Horizontal), mf.scrollBarValue(Qt.Vertical))
+ mf = self.page().mainFrame()
+ return (mf.scrollBarValue(Qt.Horizontal), mf.scrollBarValue(Qt.Vertical))
- def fset(self, val):
- mf = self.page().mainFrame()
- mf.setScrollBarValue(Qt.Horizontal, val[0])
- mf.setScrollBarValue(Qt.Vertical, val[1])
- return property(fget=fget, fset=fset)
+ @scroll_pos.setter
+ def scroll_pos(self, val):
+ mf = self.page().mainFrame()
+ mf.setScrollBarValue(Qt.Horizontal, val[0])
+ mf.setScrollBarValue(Qt.Vertical, val[1])
def clear(self):
self.setHtml(_(
diff --git a/src/calibre/gui2/tweak_book/reports.py b/src/calibre/gui2/tweak_book/reports.py
index 948356121d..64b943085e 100644
--- a/src/calibre/gui2/tweak_book/reports.py
+++ b/src/calibre/gui2/tweak_book/reports.py
@@ -1061,14 +1061,13 @@ def __init__(self, parent=None):
self.summary = la = QLabel('\xa0')
h.addWidget(la)
- @dynamic_property
+ @property
def sort_order(self):
- def fget(self):
- return [Qt.AscendingOrder, Qt.DescendingOrder][self._sort_order.currentIndex()]
+ return [Qt.AscendingOrder, Qt.DescendingOrder][self._sort_order.currentIndex()]
- def fset(self, val):
- self._sort_order.setCurrentIndex({Qt.AscendingOrder:0}.get(val, 1))
- return property(fget=fget, fset=fset)
+ @sort_order.setter
+ def sort_order(self, val):
+ self._sort_order.setCurrentIndex({Qt.AscendingOrder:0}.get(val, 1))
def update_summary(self):
self.summary.setText(_('{0} rules, {1} unused').format(self.model.rowCount(), self.model.num_unused))
diff --git a/src/calibre/gui2/tweak_book/search.py b/src/calibre/gui2/tweak_book/search.py
index bb4598b4ac..d83997b051 100644
--- a/src/calibre/gui2/tweak_book/search.py
+++ b/src/calibre/gui2/tweak_book/search.py
@@ -152,16 +152,15 @@ def __init__(self, parent, emphasize=False):
f.setBold(True), f.setItalic(True)
self.setFont(f)
- @dynamic_property
+ @property
def where(self):
wm = {0:'current', 1:'text', 2:'styles', 3:'selected', 4:'open', 5:'selected-text'}
+ return wm[self.currentIndex()]
- def fget(self):
- return wm[self.currentIndex()]
-
- def fset(self, val):
- self.setCurrentIndex({v:k for k, v in iteritems(wm)}[val])
- return property(fget=fget, fset=fset)
+ @where.setter
+ def where(self, val):
+ wm = {0:'current', 1:'text', 2:'styles', 3:'selected', 4:'open', 5:'selected-text'}
+ self.setCurrentIndex({v:k for k, v in iteritems(wm)}[val])
def showPopup(self):
# We do it like this so that the popup uses a normal font
@@ -190,14 +189,13 @@ def __init__(self, parent):
Search for the previous match from your current position
'''))
- @dynamic_property
+ @property
def direction(self):
- def fget(self):
- return 'down' if self.currentIndex() == 0 else 'up'
+ return 'down' if self.currentIndex() == 0 else 'up'
- def fset(self, val):
- self.setCurrentIndex(1 if val == 'up' else 0)
- return property(fget=fget, fset=fset)
+ @direction.setter
+ def direction(self, val):
+ self.setCurrentIndex(1 if val == 'up' else 0)
class ModeBox(QComboBox):
@@ -216,14 +214,13 @@ def __init__(self, parent):
The search expression is interpreted as a regular expression. The replace expression is an arbitrarily powerful Python function.
'''))
- @dynamic_property
+ @property
def mode(self):
- def fget(self):
- return ('normal', 'regex', 'function')[self.currentIndex()]
+ return ('normal', 'regex', 'function')[self.currentIndex()]
- def fset(self, val):
- self.setCurrentIndex({'regex':1, 'function':2}.get(val, 0))
- return property(fget=fget, fset=fset)
+ @mode.setter
+ def mode(self, val):
+ self.setCurrentIndex({'regex':1, 'function':2}.get(val, 0))
class SearchWidget(QWidget):
@@ -353,91 +350,82 @@ def mode_changed(self, idx):
self.replace_text.setVisible(not function_mode)
self.functions_container.setVisible(function_mode)
- @dynamic_property
+ @property
def mode(self):
- def fget(self):
- return self.mode_box.mode
+ return self.mode_box.mode
- def fset(self, val):
- self.mode_box.mode = val
- self.da.setVisible(self.mode in ('regex', 'function'))
- return property(fget=fget, fset=fset)
+ @mode.setter
+ def mode(self, val):
+ self.mode_box.mode = val
+ self.da.setVisible(self.mode in ('regex', 'function'))
- @dynamic_property
+ @property
def find(self):
- def fget(self):
- return unicode_type(self.find_text.text())
+ return unicode_type(self.find_text.text())
- def fset(self, val):
- self.find_text.setText(val)
- return property(fget=fget, fset=fset)
+ @find.setter
+ def find(self, val):
+ self.find_text.setText(val)
- @dynamic_property
+ @property
def replace(self):
- def fget(self):
- if self.mode == 'function':
- return self.functions.text()
- return unicode_type(self.replace_text.text())
+ if self.mode == 'function':
+ return self.functions.text()
+ return unicode_type(self.replace_text.text())
- def fset(self, val):
- self.replace_text.setText(val)
- return property(fget=fget, fset=fset)
+ @replace.setter
+ def replace(self, val):
+ self.replace_text.setText(val)
- @dynamic_property
+ @property
def where(self):
- def fget(self):
- return self.where_box.where
+ return self.where_box.where
- def fset(self, val):
- self.where_box.where = val
- return property(fget=fget, fset=fset)
+ @where.setter
+ def where(self, val):
+ self.where_box.where = val
- @dynamic_property
+ @property
def case_sensitive(self):
- def fget(self):
- return self.cs.isChecked()
+ return self.cs.isChecked()
- def fset(self, val):
- self.cs.setChecked(bool(val))
- return property(fget=fget, fset=fset)
+ @case_sensitive.setter
+ def case_sensitive(self, val):
+ self.cs.setChecked(bool(val))
- @dynamic_property
+ @property
def direction(self):
- def fget(self):
- return self.direction_box.direction
+ return self.direction_box.direction
- def fset(self, val):
- self.direction_box.direction = val
- return property(fget=fget, fset=fset)
+ @direction.setter
+ def direction(self, val):
+ self.direction_box.direction = val
- @dynamic_property
+ @property
def wrap(self):
- def fget(self):
- return self.wr.isChecked()
+ return self.wr.isChecked()
- def fset(self, val):
- self.wr.setChecked(bool(val))
- return property(fget=fget, fset=fset)
+ @wrap.setter
+ def wrap(self, val):
+ self.wr.setChecked(bool(val))
- @dynamic_property
+ @property
def dot_all(self):
- def fget(self):
- return self.da.isChecked()
+ return self.da.isChecked()
- def fset(self, val):
- self.da.setChecked(bool(val))
- return property(fget=fget, fset=fset)
+ @dot_all.setter
+ def dot_all(self, val):
+ self.da.setChecked(bool(val))
- @dynamic_property
+ @property
def state(self):
- def fget(self):
- return {x:getattr(self, x) for x in self.DEFAULT_STATE}
+ return {x:getattr(self, x) for x in self.DEFAULT_STATE}
- def fset(self, val):
- for x in self.DEFAULT_STATE:
- if x in val:
- setattr(self, x, val[x])
- return property(fget=fget, fset=fset)
+ @state.setter
+ def state(self, val):
+ for x in self.DEFAULT_STATE:
+ if x in val:
+ setattr(self, x, val[x])
def restore_state(self):
self.state = tprefs.get('find-widget-state', self.DEFAULT_STATE)
@@ -1008,14 +996,13 @@ def pb(text, tooltip=None, action=None):
self.searches.setFocus(Qt.OtherFocusReason)
- @dynamic_property
+ @property
def state(self):
- def fget(self):
- return {'wrap':self.wrap, 'direction':self.direction, 'where':self.where}
+ return {'wrap':self.wrap, 'direction':self.direction, 'where':self.where}
- def fset(self, val):
- self.wrap, self.where, self.direction = val['wrap'], val['where'], val['direction']
- return property(fget=fget, fset=fset)
+ @state.setter
+ def state(self, val):
+ self.wrap, self.where, self.direction = val['wrap'], val['where'], val['direction']
def save_state(self):
tprefs['saved_seaches_state'] = self.state
@@ -1042,32 +1029,29 @@ def stack_current_changed(self, index):
for x in ('eb', 'ab', 'rb', 'upb', 'dnb', 'd2', 'filter_text', 'cft', 'd3', 'ib', 'eb2'):
getattr(self, x).setVisible(visible)
- @dynamic_property
+ @property
def where(self):
- def fget(self):
- return self.where_box.where
+ return self.where_box.where
- def fset(self, val):
- self.where_box.where = val
- return property(fget=fget, fset=fset)
+ @where.setter
+ def where(self, val):
+ self.where_box.where = val
- @dynamic_property
+ @property
def direction(self):
- def fget(self):
- return self.direction_box.direction
+ return self.direction_box.direction
- def fset(self, val):
- self.direction_box.direction = val
- return property(fget=fget, fset=fset)
+ @direction.setter
+ def direction(self, val):
+ self.direction_box.direction = val
- @dynamic_property
+ @property
def wrap(self):
- def fget(self):
- return self.wr.isChecked()
+ return self.wr.isChecked()
- def fset(self, val):
- self.wr.setChecked(bool(val))
- return property(fget=fget, fset=fset)
+ @wrap.setter
+ def wrap(self, val):
+ self.wr.setChecked(bool(val))
def do_filter(self, text):
self.model.do_filter(text)
diff --git a/src/calibre/gui2/tweak_book/text_search.py b/src/calibre/gui2/tweak_book/text_search.py
index 23794a6577..b44967c444 100644
--- a/src/calibre/gui2/tweak_book/text_search.py
+++ b/src/calibre/gui2/tweak_book/text_search.py
@@ -36,14 +36,13 @@ def __init__(self, parent):
The search expression is interpreted as a regular expression. See the User Manual for more help on using regular expressions.
'''))
- @dynamic_property
+ @property
def mode(self):
- def fget(self):
- return ('normal', 'regex')[self.currentIndex()]
+ return ('normal', 'regex')[self.currentIndex()]
- def fset(self, val):
- self.setCurrentIndex({'regex':1}.get(val, 0))
- return property(fget=fget, fset=fset)
+ @mode.setter
+ def mode(self, val):
+ self.setCurrentIndex({'regex':1}.get(val, 0))
class WhereBox(QComboBox):
@@ -71,16 +70,15 @@ def __init__(self, parent, emphasize=False):
f.setBold(True), f.setItalic(True)
self.setFont(f)
- @dynamic_property
+ @property
def where(self):
wm = {0:'current', 1:'text', 2:'selected', 3:'open'}
+ return wm[self.currentIndex()]
- def fget(self):
- return wm[self.currentIndex()]
-
- def fset(self, val):
- self.setCurrentIndex({v:k for k, v in iteritems(wm)}[val])
- return property(fget=fget, fset=fset)
+ @where.setter
+ def where(self, val):
+ wm = {0:'current', 1:'text', 2:'selected', 3:'open'}
+ self.setCurrentIndex({v:k for k, v in iteritems(wm)}[val])
def showPopup(self):
# We do it like this so that the popup uses a normal font
@@ -137,17 +135,16 @@ def __init__(self, ui):
state = tprefs.get('text_search_widget_state')
self.state = state or {}
- @dynamic_property
+ @property
def state(self):
- def fget(self):
- return {'mode': self.mode.mode, 'where':self.where_box.where, 'case_sensitive':self.cs.isChecked(), 'dot_all':self.da.isChecked()}
+ return {'mode': self.mode.mode, 'where':self.where_box.where, 'case_sensitive':self.cs.isChecked(), 'dot_all':self.da.isChecked()}
- def fset(self, val):
- self.mode.mode = val.get('mode', 'normal')
- self.where_box.where = val.get('where', 'current')
- self.cs.setChecked(bool(val.get('case_sensitive')))
- self.da.setChecked(bool(val.get('dot_all', True)))
- return property(fget=fget, fset=fset)
+ @state.setter
+ def state(self, val):
+ self.mode.mode = val.get('mode', 'normal')
+ self.where_box.where = val.get('where', 'current')
+ self.cs.setChecked(bool(val.get('case_sensitive')))
+ self.da.setChecked(bool(val.get('dot_all', True)))
def save_state(self):
tprefs['text_search_widget_state'] = self.state
diff --git a/src/calibre/gui2/viewer/config.py b/src/calibre/gui2/viewer/config.py
index 8f310d53e8..4e1f2f6d00 100644
--- a/src/calibre/gui2/viewer/config.py
+++ b/src/calibre/gui2/viewer/config.py
@@ -236,17 +236,16 @@ def init_dictionaries(self):
from calibre.gui2.viewer.main import dprefs
self.word_lookups = dprefs['word_lookups']
- @dynamic_property
+ @property
def word_lookups(self):
- def fget(self):
- return dict(self.dictionary_list.item(i).data(Qt.UserRole) for i in range(self.dictionary_list.count()))
+ return dict(self.dictionary_list.item(i).data(Qt.UserRole) for i in range(self.dictionary_list.count()))
- def fset(self, wl):
- self.dictionary_list.clear()
- for langcode, url in sorted(iteritems(wl), key=lambda lc_url:sort_key(calibre_langcode_to_name(lc_url[0]))):
- i = QListWidgetItem('%s: %s' % (calibre_langcode_to_name(langcode), url), self.dictionary_list)
- i.setData(Qt.UserRole, (langcode, url))
- return property(fget=fget, fset=fset)
+ @word_lookups.setter
+ def word_lookups(self, wl):
+ self.dictionary_list.clear()
+ for langcode, url in sorted(iteritems(wl), key=lambda lc_url:sort_key(calibre_langcode_to_name(lc_url[0]))):
+ i = QListWidgetItem('%s: %s' % (calibre_langcode_to_name(langcode), url), self.dictionary_list)
+ i.setData(Qt.UserRole, (langcode, url))
def add_dictionary_website(self):
class AD(QDialog):
diff --git a/src/calibre/gui2/viewer/documentview.py b/src/calibre/gui2/viewer/documentview.py
index 91232c0cd7..b8c210ef7f 100644
--- a/src/calibre/gui2/viewer/documentview.py
+++ b/src/calibre/gui2/viewer/documentview.py
@@ -430,46 +430,43 @@ def is_portrait(self):
def xpos(self):
return self.mainFrame().scrollPosition().x()
- @dynamic_property
+ @property
def scroll_fraction(self):
- def fget(self):
- if self.in_paged_mode:
- return self.javascript('''
- ans = 0.0;
- if (window.paged_display) {
- ans = window.paged_display.current_pos();
- }
- ans;''', typ='float')
- else:
- try:
- return abs(float(self.ypos)/(self.height-self.window_height))
- except ZeroDivisionError:
- return 0.
+ if self.in_paged_mode:
+ return self.javascript('''
+ ans = 0.0;
+ if (window.paged_display) {
+ ans = window.paged_display.current_pos();
+ }
+ ans;''', typ='float')
+ else:
+ try:
+ return abs(float(self.ypos)/(self.height-self.window_height))
+ except ZeroDivisionError:
+ return 0.
- def fset(self, val):
- if self.in_paged_mode and self.loaded_javascript:
- self.javascript('paged_display.scroll_to_pos(%f)'%val)
- else:
- npos = val * (self.height - self.window_height)
- if npos < 0:
- npos = 0
- self.scroll_to(x=self.xpos, y=npos)
- return property(fget=fget, fset=fset)
+ @scroll_fraction.setter
+ def scroll_fraction(self, val):
+ if self.in_paged_mode and self.loaded_javascript:
+ self.javascript('paged_display.scroll_to_pos(%f)'%val)
+ else:
+ npos = val * (self.height - self.window_height)
+ if npos < 0:
+ npos = 0
+ self.scroll_to(x=self.xpos, y=npos)
- @dynamic_property
+ @property
def page_number(self):
' The page number is the number of the page at the left most edge of the screen (starting from 0) '
+ if self.in_paged_mode:
+ return self.javascript(
+ 'ans = 0; if (window.paged_display) ans = window.paged_display.column_boundaries()[0]; ans;', typ='int')
- def fget(self):
- if self.in_paged_mode:
- return self.javascript(
- 'ans = 0; if (window.paged_display) ans = window.paged_display.column_boundaries()[0]; ans;', typ='int')
-
- def fset(self, val):
- if self.in_paged_mode and self.loaded_javascript:
- self.javascript('if (window.paged_display) window.paged_display.scroll_to_column(%d)' % int(val))
- return True
- return property(fget=fget, fset=fset)
+ @page_number.setter
+ def page_number(self, val):
+ if self.in_paged_mode and self.loaded_javascript:
+ self.javascript('if (window.paged_display) window.paged_display.scroll_to_column(%d)' % int(val))
+ return True
@property
def page_dimensions(self):
@@ -862,14 +859,13 @@ def footnote_link_clicked(self, qurl):
def sizeHint(self):
return self._size_hint
- @dynamic_property
+ @property
def scroll_fraction(self):
- def fget(self):
- return self.document.scroll_fraction
+ return self.document.scroll_fraction
- def fset(self, val):
- self.document.scroll_fraction = float(val)
- return property(fget=fget, fset=fset)
+ @scroll_fraction.setter
+ def scroll_fraction(self, val):
+ self.document.scroll_fraction = float(val)
@property
def hscroll_fraction(self):
@@ -879,14 +875,13 @@ def hscroll_fraction(self):
def content_size(self):
return self.document.width, self.document.height
- @dynamic_property
+ @property
def current_language(self):
- def fget(self):
- return self.document.current_language
+ return self.document.current_language
- def fset(self, val):
- self.document.current_language = val
- return property(fget=fget, fset=fset)
+ @current_language.setter
+ def current_language(self, val):
+ self.document.current_language = val
def search(self, text, backwards=False):
flags = self.document.FindBackward if backwards else self.document.FindFlags(0)
@@ -1189,19 +1184,18 @@ def scroll_to(self, pos, notify=True):
if notify and self.manager is not None and new_pos != old_pos:
self.manager.scrolled(self.scroll_fraction)
- @dynamic_property
+ @property
def multiplier(self):
- def fget(self):
- return self.zoomFactor()
+ return self.zoomFactor()
- def fset(self, val):
- oval = self.zoomFactor()
- self.setZoomFactor(val)
- if val != oval:
- if self.document.in_paged_mode:
- self.document.update_contents_size_for_paged_mode()
- self.magnification_changed.emit(val)
- return property(fget=fget, fset=fset)
+ @multiplier.setter
+ def multiplier(self, val):
+ oval = self.zoomFactor()
+ self.setZoomFactor(val)
+ if val != oval:
+ if self.document.in_paged_mode:
+ self.document.update_contents_size_for_paged_mode()
+ self.magnification_changed.emit(val)
def magnify_fonts(self, amount=None):
if amount is None:
diff --git a/src/calibre/gui2/widgets.py b/src/calibre/gui2/widgets.py
index ff02851f8b..9eb9861a18 100644
--- a/src/calibre/gui2/widgets.py
+++ b/src/calibre/gui2/widgets.py
@@ -1131,30 +1131,28 @@ def print_sizes(self):
print(self.save_name, 'side:', self.side_index_size, 'other:', end=' ')
print(list(self.sizes())[self.other_index])
- @dynamic_property
+ @property
def side_index_size(self):
- def fget(self):
- if self.count() < 2:
- return 0
- return self.sizes()[self.side_index]
+ if self.count() < 2:
+ return 0
+ return self.sizes()[self.side_index]
- def fset(self, val):
- if self.count() < 2:
- return
- if val == 0 and not self.is_side_index_hidden:
- self.save_state()
- sizes = list(self.sizes())
- for i in range(len(sizes)):
- sizes[i] = val if i == self.side_index else 10
- self.setSizes(sizes)
- total = sum(self.sizes())
- sizes = list(self.sizes())
- for i in range(len(sizes)):
- sizes[i] = val if i == self.side_index else total-val
- self.setSizes(sizes)
- self.initialize()
-
- return property(fget=fget, fset=fset)
+ @side_index_size.setter
+ def side_index_size(self, val):
+ if self.count() < 2:
+ return
+ if val == 0 and not self.is_side_index_hidden:
+ self.save_state()
+ sizes = list(self.sizes())
+ for i in range(len(sizes)):
+ sizes[i] = val if i == self.side_index else 10
+ self.setSizes(sizes)
+ total = sum(self.sizes())
+ sizes = list(self.sizes())
+ for i in range(len(sizes)):
+ sizes[i] = val if i == self.side_index else total-val
+ self.setSizes(sizes)
+ self.initialize()
def do_resize(self, *args):
orig = self.desired_side_size
diff --git a/src/calibre/gui2/widgets2.py b/src/calibre/gui2/widgets2.py
index 76db5fc928..135405f044 100644
--- a/src/calibre/gui2/widgets2.py
+++ b/src/calibre/gui2/widgets2.py
@@ -86,28 +86,27 @@ def __init__(self, initial_color=None, parent=None, choose_text=None):
self.color = initial_color
self.clicked.connect(self.choose_color)
- @dynamic_property
+ @property
def color(self):
- def fget(self):
- return self._color
+ return self._color
- def fset(self, val):
- val = unicode_type(val or '')
- col = QColor(val)
- orig = self._color
- if col.isValid():
- self._color = val
- self.setText(val)
- p = QPixmap(self.iconSize())
- p.fill(col)
- self.setIcon(QIcon(p))
- else:
- self._color = None
- self.setText(self.choose_text)
- self.setIcon(QIcon())
- if orig != col:
- self.color_changed.emit(self._color)
- return property(fget=fget, fset=fset)
+ @color.setter
+ def color(self, val):
+ val = unicode_type(val or '')
+ col = QColor(val)
+ orig = self._color
+ if col.isValid():
+ self._color = val
+ self.setText(val)
+ p = QPixmap(self.iconSize())
+ p.fill(col)
+ self.setIcon(QIcon(p))
+ else:
+ self._color = None
+ self.setText(self.choose_text)
+ self.setIcon(QIcon())
+ if orig != col:
+ self.color_changed.emit(self._color)
def choose_color(self):
col = QColorDialog.getColor(QColor(self._color or Qt.white), self, _('Choose a color'))
diff --git a/src/calibre/library/database.py b/src/calibre/library/database.py
index c47c932639..7a898d566c 100644
--- a/src/calibre/library/database.py
+++ b/src/calibre/library/database.py
@@ -827,13 +827,10 @@ def close(self):
# _lock_file = None
self.conn.close()
- @dynamic_property
+ @property
def user_version(self):
- doc = 'The user version of this database'
-
- def fget(self):
- return self.conn.get('pragma user_version;', all=False)
- return property(doc=doc, fget=fget)
+ 'The user version of this database'
+ return self.conn.get('pragma user_version;', all=False)
def is_empty(self):
return not self.conn.get('SELECT id FROM books LIMIT 1', all=False)
diff --git a/src/calibre/library/database2.py b/src/calibre/library/database2.py
index e73f76bf5b..a5a7ce4b49 100644
--- a/src/calibre/library/database2.py
+++ b/src/calibre/library/database2.py
@@ -75,43 +75,36 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
PATH_LIMIT = 40 if 'win32' in sys.platform else 100
WINDOWS_LIBRARY_PATH_LIMIT = 75
- @dynamic_property
+ @property
def user_version(self):
- doc = 'The user version of this database'
+ 'The user version of this database'
+ return self.conn.get('pragma user_version;', all=False)
- def fget(self):
- return self.conn.get('pragma user_version;', all=False)
+ @user_version.setter
+ def user_version(self, val):
+ self.conn.execute('pragma user_version=%d'%int(val))
+ self.conn.commit()
- def fset(self, val):
- self.conn.execute('pragma user_version=%d'%int(val))
- self.conn.commit()
-
- return property(doc=doc, fget=fget, fset=fset)
-
- @dynamic_property
+ @property
def library_id(self):
- doc = ('The UUID for this library. As long as the user only operates'
- ' on libraries with calibre, it will be unique')
+ '''The UUID for this library. As long as the user only operates on libraries with calibre, it will be unique'''
+ if self._library_id_ is None:
+ ans = self.conn.get('SELECT uuid FROM library_id', all=False)
+ if ans is None:
+ ans = str(uuid.uuid4())
+ self.library_id = ans
+ else:
+ self._library_id_ = ans
+ return self._library_id_
- def fget(self):
- if self._library_id_ is None:
- ans = self.conn.get('SELECT uuid FROM library_id', all=False)
- if ans is None:
- ans = str(uuid.uuid4())
- self.library_id = ans
- else:
- self._library_id_ = ans
- return self._library_id_
-
- def fset(self, val):
- self._library_id_ = unicode_type(val)
- self.conn.executescript('''
- DELETE FROM library_id;
- INSERT INTO library_id (uuid) VALUES ("%s");
- '''%self._library_id_)
- self.conn.commit()
-
- return property(doc=doc, fget=fget, fset=fset)
+ @library_id.setter
+ def library_id(self, val):
+ self._library_id_ = unicode_type(val)
+ self.conn.executescript('''
+ DELETE FROM library_id;
+ INSERT INTO library_id (uuid) VALUES ("%s");
+ '''%self._library_id_)
+ self.conn.commit()
def connect(self):
if iswindows and len(self.library_path) + 4*self.PATH_LIMIT + 10 > 259:
diff --git a/src/calibre/utils/magick/legacy.py b/src/calibre/utils/magick/legacy.py
index 388f7ee9e1..b144e32235 100644
--- a/src/calibre/utils/magick/legacy.py
+++ b/src/calibre/utils/magick/legacy.py
@@ -57,47 +57,43 @@ def from_qimage(self, img):
def to_qimage(self):
return clone_image(self.img)
- @dynamic_property
+ @property
def type(self):
- def fget(self):
- if len(self.img.colorTable()) > 0:
- return 'PaletteType'
- return 'TrueColorType'
+ if len(self.img.colorTable()) > 0:
+ return 'PaletteType'
+ return 'TrueColorType'
- def fset(self, t):
- if t == 'GrayscaleType':
- self.img = grayscale_image(self.img)
- elif t == 'PaletteType':
- self.img = quantize_image(self.img)
- return property(fget=fget, fset=fset)
+ @type.setter
+ def type(self, t):
+ if t == 'GrayscaleType':
+ self.img = grayscale_image(self.img)
+ elif t == 'PaletteType':
+ self.img = quantize_image(self.img)
- @dynamic_property
+ @property
def format(self):
- def fget(self):
- return self.write_format or self.read_format
+ return self.write_format or self.read_format
- def fset(self, val):
- self.write_format = val
- return property(fget=fget, fset=fset)
+ @format.setter
+ def format(self, val):
+ self.write_format = val
- @dynamic_property
+ @property
def colorspace(self):
- def fget(self):
- return 'RGBColorspace'
+ return 'RGBColorspace'
- def fset(self, val):
- raise NotImplementedError('Changing image colorspace is not supported')
- return property(fget=fget, fset=fset)
+ @colorspace.setter
+ def colorspace(self, val):
+ raise NotImplementedError('Changing image colorspace is not supported')
- @dynamic_property
+ @property
def size(self):
- def fget(self):
- return self.img.width(), self.img.height()
+ return self.img.width(), self.img.height()
- def fset(self, val):
- w, h = val[:2]
- self.img = resize_image(self.img, w, h)
- return property(fget=fget, fset=fset)
+ @size.setter
+ def size(self, val):
+ w, h = val[:2]
+ self.img = resize_image(self.img, w, h)
def save(self, path, format=None):
if format is None:
diff --git a/src/calibre/web/feeds/__init__.py b/src/calibre/web/feeds/__init__.py
index 3b42ec7f18..db9e8bc572 100644
--- a/src/calibre/web/feeds/__init__.py
+++ b/src/calibre/web/feeds/__init__.py
@@ -57,32 +57,29 @@ def __init__(self, id, title, url, author, summary, published, content):
self.localtime = self.utctime.astimezone(local_tz)
self._formatted_date = None
- @dynamic_property
+ @property
def formatted_date(self):
- def fget(self):
- if self._formatted_date is None:
- self._formatted_date = strftime(" [%a, %d %b %H:%M]",
- t=self.localtime.timetuple())
- return self._formatted_date
+ if self._formatted_date is None:
+ self._formatted_date = strftime(" [%a, %d %b %H:%M]",
+ t=self.localtime.timetuple())
+ return self._formatted_date
- def fset(self, val):
- if isinstance(val, unicode_type):
- self._formatted_date = val
+ @formatted_date.setter
+ def formatted_date(self, val):
+ if isinstance(val, unicode_type):
+ self._formatted_date = val
- return property(fget=fget, fset=fset)
-
- @dynamic_property
+ @property
def title(self):
- def fget(self):
- t = self._title
- if not isinstance(t, unicode_type) and hasattr(t, 'decode'):
- t = t.decode('utf-8', 'replace')
- return t
+ t = self._title
+ if not isinstance(t, unicode_type) and hasattr(t, 'decode'):
+ t = t.decode('utf-8', 'replace')
+ return t
- def fset(self, val):
- self._title = clean_ascii_chars(val)
- return property(fget=fget, fset=fset)
+ @title.setter
+ def title(self, val):
+ self._title = clean_ascii_chars(val)
def __repr__(self):
return \