Get rid of @dynamic_property

This commit is contained in:
Kovid Goyal 2019-05-15 20:39:48 +05:30
parent 846a1a5e9f
commit f51e63718c
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
43 changed files with 1269 additions and 1487 deletions

View File

@ -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]

View File

@ -4,9 +4,8 @@ __copyright__ = '2008, Kovid Goyal <kovid@kovidgoyal.net>'
__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

View File

@ -1145,17 +1145,14 @@ class DB(object):
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 @@ class DB(object):
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 '''

View File

@ -31,73 +31,55 @@ class FileFormatter(object):
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):

View File

@ -46,26 +46,21 @@ class Book(Metadata):
# 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

View File

@ -169,24 +169,23 @@ class Block(object):
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:

View File

@ -209,37 +209,29 @@ class Tag(object):
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("<B", self.contents)[0]
return property(fget=fget)
if len(self.contents) != 1:
raise LRFParseError("Bad parameter for tag ID: %04X" % self.id)
return struct.unpack("<B", self.contents)[0]
@dynamic_property
@property
def word(self):
def fget(self):
if len(self.contents) != 2:
raise LRFParseError("Bad parameter for tag ID: %04X" % self.id)
return struct.unpack("<H", self.contents)[0]
return property(fget=fget)
if len(self.contents) != 2:
raise LRFParseError("Bad parameter for tag ID: %04X" % self.id)
return struct.unpack("<H", self.contents)[0]
@dynamic_property
@property
def sword(self):
def fget(self):
if len(self.contents) != 2:
raise LRFParseError("Bad parameter for tag ID: %04X" % self.id)
return struct.unpack("<h", self.contents)[0]
return property(fget=fget)
if len(self.contents) != 2:
raise LRFParseError("Bad parameter for tag ID: %04X" % self.id)
return struct.unpack("<h", self.contents)[0]
@dynamic_property
@property
def dword(self):
def fget(self):
if len(self.contents) != 4:
raise LRFParseError("Bad parameter for tag ID: %04X" % self.id)
return struct.unpack("<I", self.contents)[0]
return property(fget=fget)
if len(self.contents) != 4:
raise LRFParseError("Bad parameter for tag ID: %04X" % self.id)
return struct.unpack("<I", self.contents)[0]
def dummy_parser(self, stream):
raise LRFParseError("Unknown tag at %08X" % stream.tell())

View File

@ -193,14 +193,13 @@ class ManifestItem(Resource): # {{{
res.mime_type = mt
return res
@dynamic_property
@property
def media_type(self):
def fget(self):
return self.mime_type
return self.mime_type
def fset(self, val):
self.mime_type = val
return property(fget=fget, fset=fset)
@media_type.setter
def media_type(self, val):
self.mime_type = val
def __unicode__representation__(self):
return u'<item id="%s" href="%s" media-type="%s" />'%(self.id, self.href(), self.media_type)
@ -804,172 +803,155 @@ class OPF(object): # {{{
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
# <dc:creator> 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
# <dc:creator> 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 @@ class OPF(object): # {{{
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 @@ class OPF(object): # {{{
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 @@ class OPF(object): # {{{
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)

View File

@ -122,19 +122,16 @@ class TOC(list):
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)

View File

@ -131,14 +131,13 @@ class IndexEntry(object):
' 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):

View File

@ -704,20 +704,17 @@ class Metadata(object):
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 @@ class Metadata(object):
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 @@ class Manifest(object):
# }}}
@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 @@ class Manifest(object):
- 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 @@ class Manifest(object):
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 @@ class Guide(object):
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

View File

@ -1369,14 +1369,13 @@ class EpubContainer(Container):
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 @@ class AZW3Container(Container):
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):

View File

@ -1022,19 +1022,19 @@ class Application(QApplication):
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)

View File

@ -51,18 +51,17 @@ class ChooseFormat(QDialog): # {{{
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)
# }}}

View File

@ -336,55 +336,53 @@ class EditorWidget(QWebView, LineEditECM): # {{{
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 '<img' not in raw.lower():
return ans
def fget(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 '<img' not in raw.lower():
return ans
root = html.fromstring(raw)
except Exception:
root = parse(raw, maybe_xhtml=False, sanitize_names=True)
try:
root = html.fromstring(raw)
except Exception:
root = parse(raw, maybe_xhtml=False, sanitize_names=True)
elems = []
for body in root.xpath('//body'):
if body.text:
elems.append(body.text)
elems += [html.tostring(x, encoding=unicode_type) for x in body if
x.tag not in ('script', 'style')]
elems = []
for body in root.xpath('//body'):
if body.text:
elems.append(body.text)
elems += [html.tostring(x, encoding=unicode_type) for x in body if
x.tag not in ('script', 'style')]
if len(elems) > 1:
ans = u'<div>%s</div>'%(u''.join(elems))
else:
ans = u''.join(elems)
if not ans.startswith('<'):
ans = '<p>%s</p>'%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'<div>%s</div>'%(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 = '<p>%s</p>'%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 @@ class Editor(QWidget): # {{{
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 @@ class Editor(QWidget): # {{{
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 @@ class Editor(QWidget): # {{{
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)

View File

@ -333,23 +333,21 @@ class LineEdit(QLineEdit, LineEditECM):
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 @@ class EditWithComplete(EnComboBox):
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):

View File

@ -43,14 +43,13 @@ class ColorButton(QToolButton):
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)

View File

@ -377,14 +377,13 @@ class Comments(Base):
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)

View File

@ -1367,29 +1367,26 @@ class DeviceMixin(object): # {{{
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:

View File

@ -378,32 +378,31 @@ class BasicRecipe(QWidget): # {{{
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 @@ class AdvancedRecipe(QWidget): # {{{
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='<recipe>')
return property(fget=fget, fset=fset)
@recipe_source.setter
def recipe_source(self, src):
self.editor.load_text(src, syntax='python', doc_name='<recipe>')
def sizeHint(self):
return QSize(800, 500)

View File

@ -64,14 +64,13 @@ class ProgressDialog(QDialog):
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 @@ class ProgressDialog(QDialog):
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

View File

@ -353,18 +353,17 @@ class FontFamilyChooser(QWidget):
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)

View File

@ -60,23 +60,20 @@ class LanguagesEdit(EditWithComplete):
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 = []

View File

@ -186,18 +186,17 @@ class PreserveViewState(object): # {{{
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 @@ class BooksView(QTableView): # {{{
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):

View File

@ -72,14 +72,13 @@ class BasicMetadataWidget(object):
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 @@ class TitleEdit(EnLineEdit, ToMetadataMixin):
# 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 @@ class AuthorsEdit(EditWithComplete, ToMetadataMixin):
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 @@ class AuthorSortEdit(EnLineEdit, ToMetadataMixin):
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 @@ class SeriesEdit(EditWithComplete, ToMetadataMixin):
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 @@ class SeriesIndexEdit(make_undoable(QDoubleSpinBox), ToMetadataMixin):
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 @@ class Cover(ImageView): # {{{
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 @@ class RatingEdit(RatingEditor, ToMetadataMixin): # {{{
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 @@ class TagsEdit(EditWithComplete, ToMetadataMixin): # {{{
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 @@ class LanguagesEdit(LE, ToMetadataMixin): # {{{
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 @@ class IdentifiersEdit(QLineEdit, ToMetadataMixin):
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 @@ class PublisherEdit(EditWithComplete, ToMetadataMixin): # {{{
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 @@ class DateEdit(make_undoable(QDateTimeEdit), ToMetadataMixin):
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)

View File

@ -49,29 +49,28 @@ class LineEdit(EditWithComplete):
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 @@ class LineEdit(EditWithComplete):
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 @@ class LanguagesEdit(LE):
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 @@ class IdentifiersEdit(LineEdit):
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 @@ class CommentsEdit(Editor):
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 @@ class CoverView(QWidget):
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)

View File

@ -138,35 +138,33 @@ class ConditionEditor(QWidget): # {{{
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 @@ class ConditionEditor(QWidget): # {{{
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)

View File

@ -62,23 +62,21 @@ class ResizeDialog(QDialog): # {{{
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 @@ class Editor(QMainWindow):
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 @@ class Editor(QMainWindow):
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 @@ class Editor(QMainWindow):
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

View File

@ -221,26 +221,25 @@ class EditorTabStop(object):
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 @@ class EditSnippet(QWidget):
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

View File

@ -206,17 +206,15 @@ class TextEdit(PlainTextEdit):
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

View File

@ -159,28 +159,26 @@ class Editor(QMainWindow):
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 @@ class Editor(QMainWindow):
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 @@ class Editor(QMainWindow):
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'))

View File

@ -370,17 +370,16 @@ class WebView(QWebView):
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(_(

View File

@ -1061,14 +1061,13 @@ class CSSWidget(QWidget):
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))

View File

@ -152,16 +152,15 @@ class WhereBox(QComboBox):
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 @@ class DirectionBox(QComboBox):
<dd>Search for the previous match from your current position</dd>
</dl>'''))
@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 @@ class ModeBox(QComboBox):
<dd>The search expression is interpreted as a regular expression. The replace expression is an arbitrarily powerful Python function.</dd>
</dl>'''))
@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 @@ class SearchWidget(QWidget):
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 @@ class SavedSearches(QWidget):
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 @@ class SavedSearches(QWidget):
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)

View File

@ -36,14 +36,13 @@ class ModeBox(QComboBox):
<dd>The search expression is interpreted as a regular expression. See the User Manual for more help on using regular expressions.</dd>
</dl>'''))
@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 @@ class WhereBox(QComboBox):
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 @@ class TextSearch(QWidget):
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

View File

@ -236,17 +236,16 @@ class ConfigDialog(QDialog, Ui_Dialog):
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):

View File

@ -430,46 +430,43 @@ class Document(QWebPage): # {{{
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 @@ class DocumentView(QWebView): # {{{
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 @@ class DocumentView(QWebView): # {{{
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 @@ class DocumentView(QWebView): # {{{
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:

View File

@ -1131,30 +1131,28 @@ class Splitter(QSplitter):
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

View File

@ -86,28 +86,27 @@ class ColorButton(QPushButton):
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'))

View File

@ -827,13 +827,10 @@ ALTER TABLE books ADD COLUMN isbn TEXT DEFAULT "" COLLATE NOCASE;
# _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)

View File

@ -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:

View File

@ -57,47 +57,43 @@ class Image(object):
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:

View File

@ -57,32 +57,29 @@ class Article(object):
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 \