mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Switch from cssutils to css-parser
css-parser is a new fork of the unmaintained cssutils. See https://github.com/ebook-utils/css-parser
This commit is contained in:
parent
3f57acc815
commit
dd7d8ea3c4
@ -8,7 +8,7 @@ __copyright__ = '2014, Kovid Goyal <kovid at kovidgoyal.net>'
|
|||||||
|
|
||||||
import re
|
import re
|
||||||
from PyQt5.Qt import QAction, QInputDialog
|
from PyQt5.Qt import QAction, QInputDialog
|
||||||
from cssutils.css import CSSRule
|
from css_parser.css import CSSRule
|
||||||
|
|
||||||
# The base class that all tools must inherit from
|
# The base class that all tools must inherit from
|
||||||
from calibre.gui2.tweak_book.plugin import Tool
|
from calibre.gui2.tweak_book.plugin import Tool
|
||||||
@ -17,6 +17,7 @@ from calibre import force_unicode
|
|||||||
from calibre.gui2 import error_dialog
|
from calibre.gui2 import error_dialog
|
||||||
from calibre.ebooks.oeb.polish.container import OEB_DOCS, OEB_STYLES, serialize
|
from calibre.ebooks.oeb.polish.container import OEB_DOCS, OEB_STYLES, serialize
|
||||||
|
|
||||||
|
|
||||||
class DemoTool(Tool):
|
class DemoTool(Tool):
|
||||||
|
|
||||||
#: Set this to a unique name it will be used as a key
|
#: Set this to a unique name it will be used as a key
|
||||||
@ -79,7 +80,7 @@ class DemoTool(Tool):
|
|||||||
# stylesheets, <style> tags and style="" attributes
|
# stylesheets, <style> tags and style="" attributes
|
||||||
for name, media_type in container.mime_map.iteritems():
|
for name, media_type in container.mime_map.iteritems():
|
||||||
if media_type in OEB_STYLES:
|
if media_type in OEB_STYLES:
|
||||||
# A stylesheet. Parsed stylesheets are cssutils CSSStylesheet
|
# A stylesheet. Parsed stylesheets are css_parser CSSStylesheet
|
||||||
# objects.
|
# objects.
|
||||||
self.magnify_stylesheet(container.parsed(name), factor)
|
self.magnify_stylesheet(container.parsed(name), factor)
|
||||||
container.dirty(name) # Tell the container that we have changed the stylesheet
|
container.dirty(name) # Tell the container that we have changed the stylesheet
|
||||||
|
@ -262,7 +262,7 @@ class OutputProfile(Plugin):
|
|||||||
touchscreen = False
|
touchscreen = False
|
||||||
touchscreen_news_css = ''
|
touchscreen_news_css = ''
|
||||||
#: A list of extra (beyond CSS 2.1) modules supported by the device
|
#: A list of extra (beyond CSS 2.1) modules supported by the device
|
||||||
#: Format is a cssutils profile dictionary (see iPad for example)
|
#: Format is a css_parser profile dictionary (see iPad for example)
|
||||||
extra_css_modules = []
|
extra_css_modules = []
|
||||||
#: If True, the date is appended to the title of downloaded news
|
#: If True, the date is appended to the title of downloaded news
|
||||||
periodical_date_in_title = True
|
periodical_date_in_title = True
|
||||||
|
@ -2036,12 +2036,12 @@ class KOBOTOUCH(KOBO):
|
|||||||
|
|
||||||
def get_extra_css(self):
|
def get_extra_css(self):
|
||||||
extra_sheet = None
|
extra_sheet = None
|
||||||
from cssutils.css import CSSRule
|
from css_parser.css import CSSRule
|
||||||
|
|
||||||
if self.modifying_css():
|
if self.modifying_css():
|
||||||
extra_css_path = os.path.join(self._main_prefix, self.KOBO_EXTRA_CSSFILE)
|
extra_css_path = os.path.join(self._main_prefix, self.KOBO_EXTRA_CSSFILE)
|
||||||
if os.path.exists(extra_css_path):
|
if os.path.exists(extra_css_path):
|
||||||
from cssutils import parseFile as cssparseFile
|
from css_parser import parseFile as cssparseFile
|
||||||
try:
|
try:
|
||||||
extra_sheet = cssparseFile(extra_css_path)
|
extra_sheet = cssparseFile(extra_css_path)
|
||||||
debug_print("KoboTouch:get_extra_css: Using extra CSS in {0} ({1} rules)".format(extra_css_path, len(extra_sheet.cssRules)))
|
debug_print("KoboTouch:get_extra_css: Using extra CSS in {0} ({1} rules)".format(extra_css_path, len(extra_sheet.cssRules)))
|
||||||
@ -2068,7 +2068,7 @@ class KOBOTOUCH(KOBO):
|
|||||||
return [r for r in sheet.cssRules.rulesOfType(css_rule)]
|
return [r for r in sheet.cssRules.rulesOfType(css_rule)]
|
||||||
|
|
||||||
def get_extra_css_rules_widow_orphan(self, sheet):
|
def get_extra_css_rules_widow_orphan(self, sheet):
|
||||||
from cssutils.css import CSSRule
|
from css_parser.css import CSSRule
|
||||||
return [r for r in self.get_extra_css_rules(sheet, CSSRule.STYLE_RULE)
|
return [r for r in self.get_extra_css_rules(sheet, CSSRule.STYLE_RULE)
|
||||||
if (r.style['widows'] or r.style['orphans'])]
|
if (r.style['widows'] or r.style['orphans'])]
|
||||||
|
|
||||||
@ -2158,7 +2158,7 @@ class KOBOTOUCH(KOBO):
|
|||||||
return True
|
return True
|
||||||
|
|
||||||
def _modify_stylesheet(self, sheet, fileext, is_dirty=False):
|
def _modify_stylesheet(self, sheet, fileext, is_dirty=False):
|
||||||
from cssutils.css import CSSRule
|
from css_parser.css import CSSRule
|
||||||
|
|
||||||
# if fileext in (EPUB_EXT, KEPUB_EXT):
|
# if fileext in (EPUB_EXT, KEPUB_EXT):
|
||||||
|
|
||||||
|
@ -497,7 +497,7 @@ class EPUBOutput(OutputFormatPlugin):
|
|||||||
|
|
||||||
if stylesheet is not None:
|
if stylesheet is not None:
|
||||||
# ADE doesn't render lists correctly if they have left margins
|
# ADE doesn't render lists correctly if they have left margins
|
||||||
from cssutils.css import CSSRule
|
from css_parser.css import CSSRule
|
||||||
for lb in XPath('//h:ul[@class]|//h:ol[@class]')(root):
|
for lb in XPath('//h:ul[@class]|//h:ol[@class]')(root):
|
||||||
sel = '.'+lb.get('class')
|
sel = '.'+lb.get('class')
|
||||||
for rule in stylesheet.data.cssRules.rulesOfType(CSSRule.STYLE_RULE):
|
for rule in stylesheet.data.cssRules.rulesOfType(CSSRule.STYLE_RULE):
|
||||||
|
@ -73,8 +73,8 @@ class FB2Input(InputFormatPlugin):
|
|||||||
css += etree.tostring(s, encoding=unicode, method='text',
|
css += etree.tostring(s, encoding=unicode, method='text',
|
||||||
with_tail=False) + '\n\n'
|
with_tail=False) + '\n\n'
|
||||||
if css:
|
if css:
|
||||||
import cssutils, logging
|
import css_parser, logging
|
||||||
parser = cssutils.CSSParser(fetcher=None,
|
parser = css_parser.CSSParser(fetcher=None,
|
||||||
log=logging.getLogger('calibre.css'))
|
log=logging.getLogger('calibre.css'))
|
||||||
|
|
||||||
XHTML_CSS_NAMESPACE = '@namespace "%s";\n' % XHTML_NS
|
XHTML_CSS_NAMESPACE = '@namespace "%s";\n' % XHTML_NS
|
||||||
|
@ -109,8 +109,8 @@ class HTMLInput(InputFormatPlugin):
|
|||||||
from calibre.ebooks.html.input import get_filelist
|
from calibre.ebooks.html.input import get_filelist
|
||||||
from calibre.ebooks.metadata import string_to_authors
|
from calibre.ebooks.metadata import string_to_authors
|
||||||
from calibre.utils.localization import canonicalize_lang
|
from calibre.utils.localization import canonicalize_lang
|
||||||
import cssutils, logging
|
import css_parser, logging
|
||||||
cssutils.log.setLevel(logging.WARN)
|
css_parser.log.setLevel(logging.WARN)
|
||||||
self.OEB_STYLES = OEB_STYLES
|
self.OEB_STYLES = OEB_STYLES
|
||||||
oeb = create_oebbook(log, None, opts, self,
|
oeb = create_oebbook(log, None, opts, self,
|
||||||
encoding=opts.input_encoding, populate=False)
|
encoding=opts.input_encoding, populate=False)
|
||||||
@ -189,7 +189,7 @@ class HTMLInput(InputFormatPlugin):
|
|||||||
if href == item.href:
|
if href == item.href:
|
||||||
dpath = os.path.dirname(path)
|
dpath = os.path.dirname(path)
|
||||||
break
|
break
|
||||||
cssutils.replaceUrls(item.data,
|
css_parser.replaceUrls(item.data,
|
||||||
partial(self.resource_adder, base=dpath))
|
partial(self.resource_adder, base=dpath))
|
||||||
|
|
||||||
toc = self.oeb.toc
|
toc = self.oeb.toc
|
||||||
|
@ -1051,8 +1051,8 @@ OptionRecommendation(name='search_replace',
|
|||||||
if self.opts.embed_all_fonts or self.opts.embed_font_family:
|
if self.opts.embed_all_fonts or self.opts.embed_font_family:
|
||||||
# Start the threaded font scanner now, for performance
|
# Start the threaded font scanner now, for performance
|
||||||
from calibre.utils.fonts.scanner import font_scanner # noqa
|
from calibre.utils.fonts.scanner import font_scanner # noqa
|
||||||
import cssutils, logging
|
import css_parser, logging
|
||||||
cssutils.log.setLevel(logging.WARN)
|
css_parser.log.setLevel(logging.WARN)
|
||||||
get_types_map() # Ensure the mimetypes module is intialized
|
get_types_map() # Ensure the mimetypes module is intialized
|
||||||
|
|
||||||
if self.opts.debug_pipeline is not None:
|
if self.opts.debug_pipeline is not None:
|
||||||
|
@ -8,7 +8,7 @@ from functools import partial
|
|||||||
from collections import OrderedDict
|
from collections import OrderedDict
|
||||||
import operator
|
import operator
|
||||||
|
|
||||||
from cssutils.css import Property, CSSRule
|
from css_parser.css import Property, CSSRule
|
||||||
|
|
||||||
from calibre import force_unicode
|
from calibre import force_unicode
|
||||||
from calibre.ebooks import parse_css_length
|
from calibre.ebooks import parse_css_length
|
||||||
@ -345,7 +345,7 @@ def export_rules(serialized_rules):
|
|||||||
|
|
||||||
def import_rules(raw_data):
|
def import_rules(raw_data):
|
||||||
import regex
|
import regex
|
||||||
pat = regex.compile('\s*(\S+)\s*:\s*(.+)', flags=regex.VERSION1)
|
pat = regex.compile(r'\s*(\S+)\s*:\s*(.+)', flags=regex.VERSION1)
|
||||||
current_rule = {}
|
current_rule = {}
|
||||||
|
|
||||||
def sanitize(r):
|
def sanitize(r):
|
||||||
|
@ -327,28 +327,6 @@ def upshift_markup(parts):
|
|||||||
parts[i] = part
|
parts[i] = part
|
||||||
|
|
||||||
|
|
||||||
def handle_media_queries(raw):
|
|
||||||
# cssutils cannot handle CSS 3 media queries. We look for media queries
|
|
||||||
# that use amzn-mobi or amzn-kf8 and map them to a simple @media screen
|
|
||||||
# rule. See https://bugs.launchpad.net/bugs/1406708 for an example
|
|
||||||
import tinycss
|
|
||||||
parser = tinycss.make_full_parser()
|
|
||||||
|
|
||||||
def replace(m):
|
|
||||||
sheet = parser.parse_stylesheet(m.group() + '}')
|
|
||||||
if len(sheet.rules) > 0:
|
|
||||||
for mq in sheet.rules[0].media:
|
|
||||||
# Only accept KF8 media types
|
|
||||||
if (mq.media_type, mq.negated) in {('amzn-mobi', True), ('amzn-kf8', False)}:
|
|
||||||
return '@media screen {'
|
|
||||||
else:
|
|
||||||
# Empty sheet, doesn't matter what we use
|
|
||||||
return '@media screen {'
|
|
||||||
return m.group()
|
|
||||||
|
|
||||||
return re.sub(r'@media\s[^{;]*?[{;]', replace, raw)
|
|
||||||
|
|
||||||
|
|
||||||
def expand_mobi8_markup(mobi8_reader, resource_map, log):
|
def expand_mobi8_markup(mobi8_reader, resource_map, log):
|
||||||
# First update all internal links that are based on offsets
|
# First update all internal links that are based on offsets
|
||||||
parts = update_internal_links(mobi8_reader, log)
|
parts = update_internal_links(mobi8_reader, log)
|
||||||
@ -390,8 +368,6 @@ def expand_mobi8_markup(mobi8_reader, resource_map, log):
|
|||||||
if not os.path.exists(fi.dir):
|
if not os.path.exists(fi.dir):
|
||||||
os.mkdir(fi.dir)
|
os.mkdir(fi.dir)
|
||||||
with open(os.path.join(fi.dir, fi.fname), 'wb') as f:
|
with open(os.path.join(fi.dir, fi.fname), 'wb') as f:
|
||||||
if fi.fname.endswith('.css') and '@media' in flow:
|
|
||||||
flow = handle_media_queries(flow)
|
|
||||||
f.write(flow.encode('utf-8'))
|
f.write(flow.encode('utf-8'))
|
||||||
|
|
||||||
return spine
|
return spine
|
||||||
|
@ -13,8 +13,8 @@ from collections import defaultdict, namedtuple
|
|||||||
from io import BytesIO
|
from io import BytesIO
|
||||||
from struct import pack
|
from struct import pack
|
||||||
|
|
||||||
import cssutils
|
import css_parser
|
||||||
from cssutils.css import CSSRule
|
from css_parser.css import CSSRule
|
||||||
from lxml import etree
|
from lxml import etree
|
||||||
|
|
||||||
from calibre import isbytestring, force_unicode
|
from calibre import isbytestring, force_unicode
|
||||||
@ -77,9 +77,9 @@ class KF8Writer(object):
|
|||||||
''' Duplicate data so that any changes we make to markup/CSS only
|
''' Duplicate data so that any changes we make to markup/CSS only
|
||||||
affect KF8 output and not MOBI 6 output '''
|
affect KF8 output and not MOBI 6 output '''
|
||||||
self._data_cache = {}
|
self._data_cache = {}
|
||||||
# Suppress cssutils logging output as it is duplicated anyway earlier
|
# Suppress css_parser logging output as it is duplicated anyway earlier
|
||||||
# in the pipeline
|
# in the pipeline
|
||||||
cssutils.log.setLevel(logging.CRITICAL)
|
css_parser.log.setLevel(logging.CRITICAL)
|
||||||
for item in self.oeb.manifest:
|
for item in self.oeb.manifest:
|
||||||
if item.media_type in XML_DOCS:
|
if item.media_type in XML_DOCS:
|
||||||
self._data_cache[item.href] = copy.deepcopy(item.data)
|
self._data_cache[item.href] = copy.deepcopy(item.data)
|
||||||
@ -87,7 +87,7 @@ class KF8Writer(object):
|
|||||||
# I can't figure out how to make an efficient copy of the
|
# I can't figure out how to make an efficient copy of the
|
||||||
# in-memory CSSStylesheet, as deepcopy doesn't work (raises an
|
# in-memory CSSStylesheet, as deepcopy doesn't work (raises an
|
||||||
# exception)
|
# exception)
|
||||||
self._data_cache[item.href] = cssutils.parseString(
|
self._data_cache[item.href] = css_parser.parseString(
|
||||||
item.data.cssText, validate=False)
|
item.data.cssText, validate=False)
|
||||||
|
|
||||||
def data(self, item):
|
def data(self, item):
|
||||||
@ -138,9 +138,9 @@ class KF8Writer(object):
|
|||||||
|
|
||||||
for tag in XPath('//h:style')(root):
|
for tag in XPath('//h:style')(root):
|
||||||
if tag.text:
|
if tag.text:
|
||||||
sheet = cssutils.parseString(tag.text, validate=False)
|
sheet = css_parser.parseString(tag.text, validate=False)
|
||||||
replacer = partial(pointer, item)
|
replacer = partial(pointer, item)
|
||||||
cssutils.replaceUrls(sheet, replacer,
|
css_parser.replaceUrls(sheet, replacer,
|
||||||
ignoreImportRules=True)
|
ignoreImportRules=True)
|
||||||
repl = sheet.cssText
|
repl = sheet.cssText
|
||||||
if isbytestring(repl):
|
if isbytestring(repl):
|
||||||
@ -150,7 +150,7 @@ class KF8Writer(object):
|
|||||||
elif item.media_type in OEB_STYLES:
|
elif item.media_type in OEB_STYLES:
|
||||||
sheet = self.data(item)
|
sheet = self.data(item)
|
||||||
replacer = partial(pointer, item)
|
replacer = partial(pointer, item)
|
||||||
cssutils.replaceUrls(sheet, replacer, ignoreImportRules=True)
|
css_parser.replaceUrls(sheet, replacer, ignoreImportRules=True)
|
||||||
|
|
||||||
def extract_css_into_flows(self):
|
def extract_css_into_flows(self):
|
||||||
inlines = defaultdict(list) # Ensure identical <style>s not repeated
|
inlines = defaultdict(list) # Ensure identical <style>s not repeated
|
||||||
@ -194,7 +194,7 @@ class KF8Writer(object):
|
|||||||
if not raw or not raw.strip():
|
if not raw or not raw.strip():
|
||||||
extract(tag)
|
extract(tag)
|
||||||
continue
|
continue
|
||||||
sheet = cssutils.parseString(raw, validate=False)
|
sheet = css_parser.parseString(raw, validate=False)
|
||||||
if fix_import_rules(sheet):
|
if fix_import_rules(sheet):
|
||||||
raw = force_unicode(sheet.cssText, 'utf-8')
|
raw = force_unicode(sheet.cssText, 'utf-8')
|
||||||
|
|
||||||
|
@ -9,8 +9,8 @@ Convert an ODT file into a Open Ebook
|
|||||||
import os, logging
|
import os, logging
|
||||||
|
|
||||||
from lxml import etree
|
from lxml import etree
|
||||||
from cssutils import CSSParser
|
from css_parser import CSSParser
|
||||||
from cssutils.css import CSSRule
|
from css_parser.css import CSSRule
|
||||||
|
|
||||||
from odf.odf2xhtml import ODF2XHTML
|
from odf.odf2xhtml import ODF2XHTML
|
||||||
from odf.opendocument import load as odLoad
|
from odf.opendocument import load as odLoad
|
||||||
@ -184,8 +184,8 @@ class Extract(ODF2XHTML):
|
|||||||
x.set('class', orig + ' ' + ' '.join(extra))
|
x.set('class', orig + ' ' + ' '.join(extra))
|
||||||
|
|
||||||
def do_filter_css(self, css):
|
def do_filter_css(self, css):
|
||||||
from cssutils import parseString
|
from css_parser import parseString
|
||||||
from cssutils.css import CSSRule
|
from css_parser.css import CSSRule
|
||||||
sheet = parseString(css, validate=False)
|
sheet = parseString(css, validate=False)
|
||||||
rules = list(sheet.cssRules.rulesOfType(CSSRule.STYLE_RULE))
|
rules = list(sheet.cssRules.rulesOfType(CSSRule.STYLE_RULE))
|
||||||
sel_map = {}
|
sel_map = {}
|
||||||
@ -301,7 +301,3 @@ class Extract(ODF2XHTML):
|
|||||||
with open('metadata.opf', 'wb') as f:
|
with open('metadata.opf', 'wb') as f:
|
||||||
opf.render(f)
|
opf.render(f)
|
||||||
return os.path.abspath('metadata.opf')
|
return os.path.abspath('metadata.opf')
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -217,7 +217,7 @@ def rewrite_links(root, link_repl_func, resolve_base_href=False):
|
|||||||
If the ``link_repl_func`` returns None, the attribute or
|
If the ``link_repl_func`` returns None, the attribute or
|
||||||
tag text will be removed completely.
|
tag text will be removed completely.
|
||||||
'''
|
'''
|
||||||
from cssutils import replaceUrls, log, CSSParser
|
from css_parser import replaceUrls, log, CSSParser
|
||||||
log.setLevel(logging.WARN)
|
log.setLevel(logging.WARN)
|
||||||
log.raiseExceptions = False
|
log.raiseExceptions = False
|
||||||
|
|
||||||
@ -269,7 +269,7 @@ def rewrite_links(root, link_repl_func, resolve_base_href=False):
|
|||||||
try:
|
try:
|
||||||
stext = parser.parseStyle(text, validate=False)
|
stext = parser.parseStyle(text, validate=False)
|
||||||
except Exception:
|
except Exception:
|
||||||
# Parsing errors are raised by cssutils
|
# Parsing errors are raised by css_parser
|
||||||
continue
|
continue
|
||||||
replaceUrls(stext, link_repl_func)
|
replaceUrls(stext, link_repl_func)
|
||||||
repl = stext.cssText.replace('\n', ' ').replace('\r',
|
repl = stext.cssText.replace('\n', ' ').replace('\r',
|
||||||
@ -971,8 +971,8 @@ class Manifest(object):
|
|||||||
return self._parse_xhtml(convert_markdown(data, title=title))
|
return self._parse_xhtml(convert_markdown(data, title=title))
|
||||||
|
|
||||||
def _parse_css(self, data):
|
def _parse_css(self, data):
|
||||||
from cssutils import CSSParser, log, resolveImports
|
from css_parser import CSSParser, log, resolveImports
|
||||||
from cssutils.css import CSSRule
|
from css_parser.css import CSSRule
|
||||||
log.setLevel(logging.WARN)
|
log.setLevel(logging.WARN)
|
||||||
log.raiseExceptions = False
|
log.raiseExceptions = False
|
||||||
self.oeb.log.debug('Parsing', self.href, '...')
|
self.oeb.log.debug('Parsing', self.href, '...')
|
||||||
@ -1011,7 +1011,7 @@ class Manifest(object):
|
|||||||
convert and return as an lxml.etree element in the XHTML
|
convert and return as an lxml.etree element in the XHTML
|
||||||
namespace.
|
namespace.
|
||||||
- XML content is parsed and returned as an lxml.etree element.
|
- XML content is parsed and returned as an lxml.etree element.
|
||||||
- CSS and CSS-variant content is parsed and returned as a cssutils
|
- CSS and CSS-variant content is parsed and returned as a css_parser
|
||||||
CSS DOM stylesheet.
|
CSS DOM stylesheet.
|
||||||
- All other content is returned as a :class:`str` object with no
|
- All other content is returned as a :class:`str` object with no
|
||||||
special parsing.
|
special parsing.
|
||||||
|
@ -9,11 +9,8 @@ __copyright__ = '2013, Kovid Goyal <kovid at kovidgoyal.net>'
|
|||||||
from polyglot.builtins import zip
|
from polyglot.builtins import zip
|
||||||
from functools import wraps
|
from functools import wraps
|
||||||
|
|
||||||
try:
|
from css_parser.css import PropertyValue
|
||||||
from cssutils.css import PropertyValue
|
from css_parser import profile as cssprofiles, CSSParser
|
||||||
except ImportError:
|
|
||||||
raise RuntimeError('You need cssutils >= 0.9.9 for calibre')
|
|
||||||
from cssutils import profile as cssprofiles, CSSParser
|
|
||||||
from tinycss.fonts3 import parse_font, serialize_font_family
|
from tinycss.fonts3 import parse_font, serialize_font_family
|
||||||
|
|
||||||
DEFAULTS = {'azimuth': 'center', 'background-attachment': 'scroll', # {{{
|
DEFAULTS = {'azimuth': 'center', 'background-attachment': 'scroll', # {{{
|
||||||
@ -269,7 +266,7 @@ def condense_sheet(sheet):
|
|||||||
|
|
||||||
def test_normalization(return_tests=False): # {{{
|
def test_normalization(return_tests=False): # {{{
|
||||||
import unittest
|
import unittest
|
||||||
from cssutils import parseStyle
|
from css_parser import parseStyle
|
||||||
from itertools import product
|
from itertools import product
|
||||||
|
|
||||||
class TestNormalization(unittest.TestCase):
|
class TestNormalization(unittest.TestCase):
|
||||||
|
@ -10,7 +10,7 @@ from itertools import count
|
|||||||
from operator import itemgetter
|
from operator import itemgetter
|
||||||
import re
|
import re
|
||||||
|
|
||||||
from cssutils.css import CSSStyleSheet, CSSRule, Property
|
from css_parser.css import CSSStyleSheet, CSSRule, Property
|
||||||
|
|
||||||
from css_selectors import Select, INAPPROPRIATE_PSEUDO_CLASSES, SelectorError
|
from css_selectors import Select, INAPPROPRIATE_PSEUDO_CLASSES, SelectorError
|
||||||
from calibre import as_unicode
|
from calibre import as_unicode
|
||||||
@ -45,7 +45,8 @@ def iterrules(container, sheet_name, rules=None, media_rule_ok=media_allowed, ru
|
|||||||
:param sheet_name: The name of the sheet in the container (in case of inline style sheets, the name of the html file)
|
:param sheet_name: The name of the sheet in the container (in case of inline style sheets, the name of the html file)
|
||||||
:param media_rule_ok: A function to test if a @media rule is allowed
|
:param media_rule_ok: A function to test if a @media rule is allowed
|
||||||
:param rule_index_counter: A counter object, rule numbers will be calculated by incrementing the counter.
|
:param rule_index_counter: A counter object, rule numbers will be calculated by incrementing the counter.
|
||||||
:param rule_type: Only yield rules of this type, where type is a string type name, see cssutils.css.CSSRule for the names (by default all rules are yielded)
|
:param rule_type: Only yield rules of this type, where type is a string type name, see css_parser.css.CSSRule for the names (
|
||||||
|
by default all rules are yielded)
|
||||||
:return: (CSSRule object, the name of the sheet from which it comes, rule index - a monotonically increasing number)
|
:return: (CSSRule object, the name of the sheet from which it comes, rule index - a monotonically increasing number)
|
||||||
'''
|
'''
|
||||||
|
|
||||||
@ -104,7 +105,7 @@ def iterdeclaration(decl):
|
|||||||
|
|
||||||
class Values(tuple):
|
class Values(tuple):
|
||||||
|
|
||||||
''' A tuple of `cssutils.css.Value ` (and its subclasses) objects. Also has a
|
''' A tuple of `css_parser.css.Value ` (and its subclasses) objects. Also has a
|
||||||
`sheet_name` attribute that is the canonical name relative to which URLs
|
`sheet_name` attribute that is the canonical name relative to which URLs
|
||||||
for this property should be resolved. '''
|
for this property should be resolved. '''
|
||||||
|
|
||||||
|
@ -6,7 +6,7 @@ from __future__ import (unicode_literals, division, absolute_import,
|
|||||||
__license__ = 'GPL v3'
|
__license__ = 'GPL v3'
|
||||||
__copyright__ = '2013, Kovid Goyal <kovid at kovidgoyal.net>'
|
__copyright__ = '2013, Kovid Goyal <kovid at kovidgoyal.net>'
|
||||||
|
|
||||||
from cssutils.css import CSSRule
|
from css_parser.css import CSSRule
|
||||||
|
|
||||||
from calibre import force_unicode
|
from calibre import force_unicode
|
||||||
from calibre.ebooks.oeb.base import OEB_DOCS, OEB_STYLES
|
from calibre.ebooks.oeb.base import OEB_DOCS, OEB_STYLES
|
||||||
|
@ -50,7 +50,7 @@ def run_checks(container):
|
|||||||
if err.level > WARN:
|
if err.level > WARN:
|
||||||
return errors
|
return errors
|
||||||
|
|
||||||
# cssutils is not thread safe
|
# css_parser is not thread safe
|
||||||
for name, mt, raw in stylesheets:
|
for name, mt, raw in stylesheets:
|
||||||
if not raw:
|
if not raw:
|
||||||
errors.append(EmptyFile(name))
|
errors.append(EmptyFile(name))
|
||||||
@ -107,4 +107,3 @@ def fix_errors(container, errors):
|
|||||||
# better to have a false positive than a false negative)
|
# better to have a false positive than a false negative)
|
||||||
changed = True
|
changed = True
|
||||||
return changed
|
return changed
|
||||||
|
|
||||||
|
@ -9,7 +9,7 @@ __copyright__ = '2013, Kovid Goyal <kovid at kovidgoyal.net>'
|
|||||||
import re
|
import re
|
||||||
|
|
||||||
from lxml.etree import XMLParser, fromstring, XMLSyntaxError
|
from lxml.etree import XMLParser, fromstring, XMLSyntaxError
|
||||||
import cssutils
|
import css_parser
|
||||||
|
|
||||||
from calibre import force_unicode, human_readable, prepare_string_for_xml
|
from calibre import force_unicode, human_readable, prepare_string_for_xml
|
||||||
from calibre.ebooks.chardet import replace_encoding_declarations, find_declared_encoding
|
from calibre.ebooks.chardet import replace_encoding_declarations, find_declared_encoding
|
||||||
@ -432,7 +432,7 @@ class BareTextInBody(BaseError):
|
|||||||
|
|
||||||
class ErrorHandler(object):
|
class ErrorHandler(object):
|
||||||
|
|
||||||
' Replacement logger to get useful error/warning info out of cssutils during parsing '
|
' Replacement logger to get useful error/warning info out of css_parser during parsing '
|
||||||
|
|
||||||
def __init__(self, name):
|
def __init__(self, name):
|
||||||
# may be disabled during setting of known valid items
|
# may be disabled during setting of known valid items
|
||||||
@ -467,7 +467,7 @@ class ErrorHandler(object):
|
|||||||
|
|
||||||
def check_css_parsing(name, raw, line_offset=0, is_declaration=False):
|
def check_css_parsing(name, raw, line_offset=0, is_declaration=False):
|
||||||
log = ErrorHandler(name)
|
log = ErrorHandler(name)
|
||||||
parser = cssutils.CSSParser(fetcher=lambda x: (None, None), log=log)
|
parser = css_parser.CSSParser(fetcher=lambda x: (None, None), log=log)
|
||||||
if is_declaration:
|
if is_declaration:
|
||||||
parser.parseStyle(raw, validate=True)
|
parser.parseStyle(raw, validate=True)
|
||||||
else:
|
else:
|
||||||
|
@ -19,7 +19,7 @@ from io import BytesIO
|
|||||||
from itertools import count
|
from itertools import count
|
||||||
from urlparse import urlparse
|
from urlparse import urlparse
|
||||||
|
|
||||||
from cssutils import getUrls, replaceUrls
|
from css_parser import getUrls, replaceUrls
|
||||||
from lxml import etree
|
from lxml import etree
|
||||||
|
|
||||||
from calibre import CurrentDir, walk
|
from calibre import CurrentDir, walk
|
||||||
@ -589,7 +589,7 @@ class Container(ContainerBase): # {{{
|
|||||||
|
|
||||||
def parsed(self, name):
|
def parsed(self, name):
|
||||||
''' Return a parsed representation of the file specified by name. For
|
''' Return a parsed representation of the file specified by name. For
|
||||||
HTML and XML files an lxml tree is returned. For CSS files a cssutils
|
HTML and XML files an lxml tree is returned. For CSS files a css_parser
|
||||||
stylesheet is returned. Note that parsed objects are cached for
|
stylesheet is returned. Note that parsed objects are cached for
|
||||||
performance. If you make any changes to the parsed object, you must
|
performance. If you make any changes to the parsed object, you must
|
||||||
call :meth:`dirty` so that the container knows to update the cache. See also :meth:`replace`.'''
|
call :meth:`dirty` so that the container knows to update the cache. See also :meth:`replace`.'''
|
||||||
@ -605,7 +605,7 @@ class Container(ContainerBase): # {{{
|
|||||||
def replace(self, name, obj):
|
def replace(self, name, obj):
|
||||||
'''
|
'''
|
||||||
Replace the parsed object corresponding to name with obj, which must be
|
Replace the parsed object corresponding to name with obj, which must be
|
||||||
a similar object, i.e. an lxml tree for HTML/XML or a cssutils
|
a similar object, i.e. an lxml tree for HTML/XML or a css_parser
|
||||||
stylesheet for a CSS file.
|
stylesheet for a CSS file.
|
||||||
'''
|
'''
|
||||||
self.parsed_cache[name] = obj
|
self.parsed_cache[name] = obj
|
||||||
|
@ -9,7 +9,7 @@ __copyright__ = '2014, Kovid Goyal <kovid at kovidgoyal.net>'
|
|||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
from functools import partial
|
from functools import partial
|
||||||
|
|
||||||
from cssutils.css import CSSRule, CSSStyleDeclaration
|
from css_parser.css import CSSRule, CSSStyleDeclaration
|
||||||
from css_selectors import parse, SelectorSyntaxError
|
from css_selectors import parse, SelectorSyntaxError
|
||||||
|
|
||||||
from calibre import force_unicode
|
from calibre import force_unicode
|
||||||
@ -208,7 +208,7 @@ def filter_declaration(style, properties=()):
|
|||||||
|
|
||||||
|
|
||||||
def filter_sheet(sheet, properties=()):
|
def filter_sheet(sheet, properties=()):
|
||||||
from cssutils.css import CSSRule
|
from css_parser.css import CSSRule
|
||||||
changed = False
|
changed = False
|
||||||
remove = []
|
remove = []
|
||||||
for rule in sheet.cssRules.rulesOfType(CSSRule.STYLE_RULE):
|
for rule in sheet.cssRules.rulesOfType(CSSRule.STYLE_RULE):
|
||||||
|
@ -8,7 +8,7 @@ __copyright__ = '2016, Kovid Goyal <kovid at kovidgoyal.net>'
|
|||||||
|
|
||||||
from functools import partial
|
from functools import partial
|
||||||
|
|
||||||
from cssutils import parseStyle
|
from css_parser import parseStyle
|
||||||
|
|
||||||
from calibre.constants import iswindows
|
from calibre.constants import iswindows
|
||||||
from calibre.ebooks.oeb.base import OEB_STYLES, OEB_DOCS
|
from calibre.ebooks.oeb.base import OEB_STYLES, OEB_DOCS
|
||||||
|
@ -16,9 +16,9 @@ def guess_type(x):
|
|||||||
return _guess_type(x)[0] or 'application/octet-stream'
|
return _guess_type(x)[0] or 'application/octet-stream'
|
||||||
|
|
||||||
|
|
||||||
def setup_cssutils_serialization(tab_width=2):
|
def setup_css_parser_serialization(tab_width=2):
|
||||||
import cssutils
|
import css_parser
|
||||||
prefs = cssutils.ser.prefs
|
prefs = css_parser.ser.prefs
|
||||||
prefs.indent = tab_width * ' '
|
prefs.indent = tab_width * ' '
|
||||||
prefs.indentClosingBrace = False
|
prefs.indentClosingBrace = False
|
||||||
prefs.omitLastSemicolon = False
|
prefs.omitLastSemicolon = False
|
||||||
@ -163,7 +163,7 @@ def parse_css(data, fname='<string>', is_declaration=False, decode=None, log_lev
|
|||||||
if log_level is None:
|
if log_level is None:
|
||||||
import logging
|
import logging
|
||||||
log_level = logging.WARNING
|
log_level = logging.WARNING
|
||||||
from cssutils import CSSParser, log
|
from css_parser import CSSParser, log
|
||||||
from calibre.ebooks.oeb.base import _css_logger
|
from calibre.ebooks.oeb.base import _css_logger
|
||||||
log.setLevel(log_level)
|
log.setLevel(log_level)
|
||||||
log.raiseExceptions = False
|
log.raiseExceptions = False
|
||||||
|
@ -185,7 +185,7 @@ class OEBReader(object):
|
|||||||
return bad
|
return bad
|
||||||
|
|
||||||
def _manifest_add_missing(self, invalid):
|
def _manifest_add_missing(self, invalid):
|
||||||
import cssutils
|
import css_parser
|
||||||
manifest = self.oeb.manifest
|
manifest = self.oeb.manifest
|
||||||
known = set(manifest.hrefs)
|
known = set(manifest.hrefs)
|
||||||
unchecked = set(manifest.values())
|
unchecked = set(manifest.values())
|
||||||
@ -225,7 +225,7 @@ class OEBReader(object):
|
|||||||
new.add(href)
|
new.add(href)
|
||||||
elif item.media_type in OEB_STYLES:
|
elif item.media_type in OEB_STYLES:
|
||||||
try:
|
try:
|
||||||
urls = list(cssutils.getUrls(data))
|
urls = list(css_parser.getUrls(data))
|
||||||
except:
|
except:
|
||||||
urls = []
|
urls = []
|
||||||
for url in urls:
|
for url in urls:
|
||||||
|
@ -11,10 +11,10 @@ __copyright__ = '2008, Marshall T. Vandegrift <llasram@gmail.com>'
|
|||||||
import os, re, logging, copy, unicodedata
|
import os, re, logging, copy, unicodedata
|
||||||
from weakref import WeakKeyDictionary
|
from weakref import WeakKeyDictionary
|
||||||
from xml.dom import SyntaxErr as CSSSyntaxError
|
from xml.dom import SyntaxErr as CSSSyntaxError
|
||||||
from cssutils.css import (CSSStyleRule, CSSPageRule, CSSFontFaceRule,
|
from css_parser.css import (CSSStyleRule, CSSPageRule, CSSFontFaceRule,
|
||||||
cssproperties)
|
cssproperties)
|
||||||
from cssutils import (profile as cssprofiles, parseString, parseStyle, log as
|
from css_parser import (profile as cssprofiles, parseString, parseStyle, log as
|
||||||
cssutils_log, CSSParser, profiles, replaceUrls)
|
css_parser_log, CSSParser, profiles, replaceUrls)
|
||||||
from calibre import force_unicode, as_unicode
|
from calibre import force_unicode, as_unicode
|
||||||
from calibre.ebooks import unit_convert
|
from calibre.ebooks import unit_convert
|
||||||
from calibre.ebooks.oeb.base import XHTML, XHTML_NS, CSS_MIME, OEB_STYLES, xpath, urlnormalize
|
from calibre.ebooks.oeb.base import XHTML, XHTML_NS, CSS_MIME, OEB_STYLES, xpath, urlnormalize
|
||||||
@ -22,7 +22,7 @@ from calibre.ebooks.oeb.normalize_css import DEFAULTS, normalizers
|
|||||||
from css_selectors import Select, SelectorError, INAPPROPRIATE_PSEUDO_CLASSES
|
from css_selectors import Select, SelectorError, INAPPROPRIATE_PSEUDO_CLASSES
|
||||||
from tinycss.media3 import CSSMedia3Parser
|
from tinycss.media3 import CSSMedia3Parser
|
||||||
|
|
||||||
cssutils_log.setLevel(logging.WARN)
|
css_parser_log.setLevel(logging.WARN)
|
||||||
|
|
||||||
_html_css_stylesheet = None
|
_html_css_stylesheet = None
|
||||||
|
|
||||||
@ -123,7 +123,7 @@ class Stylizer(object):
|
|||||||
stylesheets.append(parseString(base_css, validate=False))
|
stylesheets.append(parseString(base_css, validate=False))
|
||||||
style_tags = xpath(tree, '//*[local-name()="style" or local-name()="link"]')
|
style_tags = xpath(tree, '//*[local-name()="style" or local-name()="link"]')
|
||||||
|
|
||||||
# Add cssutils parsing profiles from output_profile
|
# Add css_parser parsing profiles from output_profile
|
||||||
for profile in self.opts.output_profile.extra_css_modules:
|
for profile in self.opts.output_profile.extra_css_modules:
|
||||||
cssprofiles.addProfile(profile['name'],
|
cssprofiles.addProfile(profile['name'],
|
||||||
profile['props'],
|
profile['props'],
|
||||||
|
@ -9,7 +9,7 @@ __copyright__ = '2013, Kovid Goyal <kovid at kovidgoyal.net>'
|
|||||||
import logging
|
import logging
|
||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
|
|
||||||
import cssutils
|
import css_parser
|
||||||
from lxml import etree
|
from lxml import etree
|
||||||
|
|
||||||
from calibre import guess_type
|
from calibre import guess_type
|
||||||
@ -97,7 +97,7 @@ class EmbedFonts(object):
|
|||||||
self.sheet_cache = {}
|
self.sheet_cache = {}
|
||||||
self.find_style_rules()
|
self.find_style_rules()
|
||||||
self.find_embedded_fonts()
|
self.find_embedded_fonts()
|
||||||
self.parser = cssutils.CSSParser(loglevel=logging.CRITICAL, log=logging.getLogger('calibre.css'))
|
self.parser = css_parser.CSSParser(loglevel=logging.CRITICAL, log=logging.getLogger('calibre.css'))
|
||||||
self.warned = set()
|
self.warned = set()
|
||||||
self.warned2 = set()
|
self.warned2 = set()
|
||||||
self.newly_embedded_fonts = set()
|
self.newly_embedded_fonts = set()
|
||||||
|
@ -25,7 +25,7 @@ class RenameFiles(object): # {{{
|
|||||||
self.renamed_items_map = renamed_items_map
|
self.renamed_items_map = renamed_items_map
|
||||||
|
|
||||||
def __call__(self, oeb, opts):
|
def __call__(self, oeb, opts):
|
||||||
import cssutils
|
import css_parser
|
||||||
self.log = oeb.logger
|
self.log = oeb.logger
|
||||||
self.opts = opts
|
self.opts = opts
|
||||||
self.oeb = oeb
|
self.oeb = oeb
|
||||||
@ -35,7 +35,7 @@ class RenameFiles(object): # {{{
|
|||||||
if etree.iselement(item.data):
|
if etree.iselement(item.data):
|
||||||
rewrite_links(self.current_item.data, self.url_replacer)
|
rewrite_links(self.current_item.data, self.url_replacer)
|
||||||
elif hasattr(item.data, 'cssText'):
|
elif hasattr(item.data, 'cssText'):
|
||||||
cssutils.replaceUrls(item.data, self.url_replacer)
|
css_parser.replaceUrls(item.data, self.url_replacer)
|
||||||
|
|
||||||
if self.oeb.guide:
|
if self.oeb.guide:
|
||||||
for ref in self.oeb.guide.values():
|
for ref in self.oeb.guide.values():
|
||||||
@ -184,4 +184,3 @@ class FlatFilenames(object): # {{{
|
|||||||
renamer = RenameFiles(self.rename_map, self.renamed_items_map)
|
renamer = RenameFiles(self.rename_map, self.renamed_items_map)
|
||||||
renamer(oeb, opts)
|
renamer(oeb, opts)
|
||||||
# }}}
|
# }}}
|
||||||
|
|
||||||
|
@ -11,8 +11,8 @@ from collections import defaultdict
|
|||||||
from xml.dom import SyntaxErr
|
from xml.dom import SyntaxErr
|
||||||
|
|
||||||
from lxml import etree
|
from lxml import etree
|
||||||
import cssutils
|
import css_parser
|
||||||
from cssutils.css import Property
|
from css_parser.css import Property
|
||||||
|
|
||||||
from calibre import guess_type
|
from calibre import guess_type
|
||||||
from calibre.ebooks import unit_convert
|
from calibre.ebooks import unit_convert
|
||||||
@ -139,7 +139,7 @@ class EmbedFontsCSSRules(object):
|
|||||||
iid, href = oeb.manifest.generate(u'page_styles', u'page_styles.css')
|
iid, href = oeb.manifest.generate(u'page_styles', u'page_styles.css')
|
||||||
rules = [x.cssText for x in self.rules]
|
rules = [x.cssText for x in self.rules]
|
||||||
rules = u'\n\n'.join(rules)
|
rules = u'\n\n'.join(rules)
|
||||||
sheet = cssutils.parseString(rules, validate=False)
|
sheet = css_parser.parseString(rules, validate=False)
|
||||||
self.href = oeb.manifest.add(iid, href, guess_type(href)[0],
|
self.href = oeb.manifest.add(iid, href, guess_type(href)[0],
|
||||||
data=sheet).href
|
data=sheet).href
|
||||||
return self.href
|
return self.href
|
||||||
@ -203,7 +203,7 @@ class CSSFlattener(object):
|
|||||||
# Make all links to resources absolute, as these sheets will be
|
# Make all links to resources absolute, as these sheets will be
|
||||||
# consolidated into a single stylesheet at the root of the document
|
# consolidated into a single stylesheet at the root of the document
|
||||||
if item.media_type in OEB_STYLES:
|
if item.media_type in OEB_STYLES:
|
||||||
cssutils.replaceUrls(item.data, item.abshref,
|
css_parser.replaceUrls(item.data, item.abshref,
|
||||||
ignoreImportRules=True)
|
ignoreImportRules=True)
|
||||||
|
|
||||||
self.body_font_family, self.embed_font_rules = self.get_embed_font_info(
|
self.body_font_family, self.embed_font_rules = self.get_embed_font_info(
|
||||||
@ -278,7 +278,7 @@ class CSSFlattener(object):
|
|||||||
cfont[k] = font[k]
|
cfont[k] = font[k]
|
||||||
rule = '@font-face { %s }'%('; '.join(u'%s:%s'%(k, v) for k, v in
|
rule = '@font-face { %s }'%('; '.join(u'%s:%s'%(k, v) for k, v in
|
||||||
cfont.iteritems()))
|
cfont.iteritems()))
|
||||||
rule = cssutils.parseString(rule)
|
rule = css_parser.parseString(rule)
|
||||||
efi.append(rule)
|
efi.append(rule)
|
||||||
|
|
||||||
return body_font_family, efi
|
return body_font_family, efi
|
||||||
@ -615,7 +615,7 @@ class CSSFlattener(object):
|
|||||||
if item.media_type in OEB_STYLES:
|
if item.media_type in OEB_STYLES:
|
||||||
manifest.remove(item)
|
manifest.remove(item)
|
||||||
id, href = manifest.generate('css', 'stylesheet.css')
|
id, href = manifest.generate('css', 'stylesheet.css')
|
||||||
sheet = cssutils.parseString(css, validate=False)
|
sheet = css_parser.parseString(css, validate=False)
|
||||||
if self.transform_css_rules:
|
if self.transform_css_rules:
|
||||||
from calibre.ebooks.css_transform_rules import transform_sheet
|
from calibre.ebooks.css_transform_rules import transform_sheet
|
||||||
transform_sheet(self.transform_css_rules, sheet)
|
transform_sheet(self.transform_css_rules, sheet)
|
||||||
@ -647,7 +647,7 @@ class CSSFlattener(object):
|
|||||||
href = None
|
href = None
|
||||||
if css.strip():
|
if css.strip():
|
||||||
id_, href = manifest.generate('page_css', 'page_styles.css')
|
id_, href = manifest.generate('page_css', 'page_styles.css')
|
||||||
sheet = cssutils.parseString(css, validate=False)
|
sheet = css_parser.parseString(css, validate=False)
|
||||||
if self.transform_css_rules:
|
if self.transform_css_rules:
|
||||||
from calibre.ebooks.css_transform_rules import transform_sheet
|
from calibre.ebooks.css_transform_rules import transform_sheet
|
||||||
transform_sheet(self.transform_css_rules, sheet)
|
transform_sheet(self.transform_css_rules, sheet)
|
||||||
|
@ -65,7 +65,7 @@ class RemoveFakeMargins(object):
|
|||||||
|
|
||||||
stylesheet = stylesheet.data
|
stylesheet = stylesheet.data
|
||||||
|
|
||||||
from cssutils.css import CSSRule
|
from css_parser.css import CSSRule
|
||||||
for rule in stylesheet.cssRules.rulesOfType(CSSRule.STYLE_RULE):
|
for rule in stylesheet.cssRules.rulesOfType(CSSRule.STYLE_RULE):
|
||||||
self.selector_map[rule.selectorList.selectorText] = rule.style
|
self.selector_map[rule.selectorList.selectorText] = rule.style
|
||||||
|
|
||||||
|
@ -23,7 +23,7 @@ class ManifestTrimmer(object):
|
|||||||
return cls()
|
return cls()
|
||||||
|
|
||||||
def __call__(self, oeb, context):
|
def __call__(self, oeb, context):
|
||||||
import cssutils
|
import css_parser
|
||||||
oeb.logger.info('Trimming unused files from manifest...')
|
oeb.logger.info('Trimming unused files from manifest...')
|
||||||
self.opts = context
|
self.opts = context
|
||||||
used = set()
|
used = set()
|
||||||
@ -60,7 +60,7 @@ class ManifestTrimmer(object):
|
|||||||
if found not in used:
|
if found not in used:
|
||||||
new.add(found)
|
new.add(found)
|
||||||
elif item.media_type == CSS_MIME:
|
elif item.media_type == CSS_MIME:
|
||||||
for href in cssutils.getUrls(item.data):
|
for href in css_parser.getUrls(item.data):
|
||||||
href = item.abshref(urlnormalize(href))
|
href = item.abshref(urlnormalize(href))
|
||||||
if href in oeb.manifest.hrefs:
|
if href in oeb.manifest.hrefs:
|
||||||
found = oeb.manifest.hrefs[href]
|
found = oeb.manifest.hrefs[href]
|
||||||
|
@ -26,7 +26,7 @@ from calibre.ebooks.oeb.polish.pretty import fix_all_html, pretty_all
|
|||||||
from calibre.ebooks.oeb.polish.replace import rename_files, replace_file, get_recommended_folders, rationalize_folders
|
from calibre.ebooks.oeb.polish.replace import rename_files, replace_file, get_recommended_folders, rationalize_folders
|
||||||
from calibre.ebooks.oeb.polish.split import split, merge, AbortError, multisplit
|
from calibre.ebooks.oeb.polish.split import split, merge, AbortError, multisplit
|
||||||
from calibre.ebooks.oeb.polish.toc import remove_names_from_toc, create_inline_toc
|
from calibre.ebooks.oeb.polish.toc import remove_names_from_toc, create_inline_toc
|
||||||
from calibre.ebooks.oeb.polish.utils import link_stylesheets, setup_cssutils_serialization as scs
|
from calibre.ebooks.oeb.polish.utils import link_stylesheets, setup_css_parser_serialization as scs
|
||||||
from calibre.gui2 import error_dialog, choose_files, question_dialog, info_dialog, choose_save_file, open_url, choose_dir, add_to_recent_docs
|
from calibre.gui2 import error_dialog, choose_files, question_dialog, info_dialog, choose_save_file, open_url, choose_dir, add_to_recent_docs
|
||||||
from calibre.gui2.dialogs.confirm_delete import confirm
|
from calibre.gui2.dialogs.confirm_delete import confirm
|
||||||
from calibre.gui2.tweak_book import (
|
from calibre.gui2.tweak_book import (
|
||||||
@ -61,7 +61,7 @@ def get_container(*args, **kwargs):
|
|||||||
return container
|
return container
|
||||||
|
|
||||||
|
|
||||||
def setup_cssutils_serialization():
|
def setup_css_parser_serialization():
|
||||||
scs(tprefs['editor_tab_stop_width'])
|
scs(tprefs['editor_tab_stop_width'])
|
||||||
|
|
||||||
|
|
||||||
@ -91,7 +91,7 @@ class Boss(QObject):
|
|||||||
self.save_manager.check_for_completion.connect(self.check_terminal_save)
|
self.save_manager.check_for_completion.connect(self.check_terminal_save)
|
||||||
self.doing_terminal_save = False
|
self.doing_terminal_save = False
|
||||||
self.ignore_preview_to_editor_sync = False
|
self.ignore_preview_to_editor_sync = False
|
||||||
setup_cssutils_serialization()
|
setup_css_parser_serialization()
|
||||||
get_boss.boss = self
|
get_boss.boss = self
|
||||||
self.gui = parent
|
self.gui = parent
|
||||||
completion_worker().result_callback = self.handle_completion_result_signal.emit
|
completion_worker().result_callback = self.handle_completion_result_signal.emit
|
||||||
@ -172,7 +172,7 @@ class Boss(QObject):
|
|||||||
bar.setIconSize(QSize(tprefs['toolbar_icon_size'], tprefs['toolbar_icon_size']))
|
bar.setIconSize(QSize(tprefs['toolbar_icon_size'], tprefs['toolbar_icon_size']))
|
||||||
|
|
||||||
if ret == p.Accepted:
|
if ret == p.Accepted:
|
||||||
setup_cssutils_serialization()
|
setup_css_parser_serialization()
|
||||||
self.gui.apply_settings()
|
self.gui.apply_settings()
|
||||||
self.refresh_file_list()
|
self.refresh_file_list()
|
||||||
if ret == p.Accepted or p.dictionaries_changed:
|
if ret == p.Accepted or p.dictionaries_changed:
|
||||||
|
@ -53,9 +53,9 @@ def beautify_text(raw, syntax):
|
|||||||
elif syntax == 'css':
|
elif syntax == 'css':
|
||||||
import logging
|
import logging
|
||||||
from calibre.ebooks.oeb.base import serialize, _css_logger
|
from calibre.ebooks.oeb.base import serialize, _css_logger
|
||||||
from calibre.ebooks.oeb.polish.utils import setup_cssutils_serialization
|
from calibre.ebooks.oeb.polish.utils import setup_css_parser_serialization
|
||||||
from cssutils import CSSParser, log
|
from css_parser import CSSParser, log
|
||||||
setup_cssutils_serialization(tprefs['editor_tab_stop_width'])
|
setup_css_parser_serialization(tprefs['editor_tab_stop_width'])
|
||||||
log.setLevel(logging.WARN)
|
log.setLevel(logging.WARN)
|
||||||
log.raiseExceptions = False
|
log.raiseExceptions = False
|
||||||
parser = CSSParser(loglevel=logging.WARNING,
|
parser = CSSParser(loglevel=logging.WARNING,
|
||||||
|
@ -10,7 +10,7 @@ import sys, re
|
|||||||
from operator import itemgetter
|
from operator import itemgetter
|
||||||
from itertools import chain
|
from itertools import chain
|
||||||
|
|
||||||
from cssutils import parseStyle
|
from css_parser import parseStyle
|
||||||
from PyQt5.Qt import QTextEdit, Qt, QTextCursor
|
from PyQt5.Qt import QTextEdit, Qt, QTextCursor
|
||||||
|
|
||||||
from calibre import prepare_string_for_xml, xml_entity_to_unicode
|
from calibre import prepare_string_for_xml, xml_entity_to_unicode
|
||||||
|
@ -13,8 +13,8 @@ from polyglot.builtins import map
|
|||||||
from urlparse import urlparse
|
from urlparse import urlparse
|
||||||
from urllib import quote
|
from urllib import quote
|
||||||
|
|
||||||
from cssutils import replaceUrls
|
from css_parser import replaceUrls
|
||||||
from cssutils.css import CSSRule
|
from css_parser.css import CSSRule
|
||||||
|
|
||||||
from calibre import prepare_string_for_xml, force_unicode
|
from calibre import prepare_string_for_xml, force_unicode
|
||||||
from calibre.ebooks import parse_css_length
|
from calibre.ebooks import parse_css_length
|
||||||
|
@ -50,7 +50,7 @@ def serialize_single_font_family(x):
|
|||||||
xl = 'sans-serif'
|
xl = 'sans-serif'
|
||||||
return xl
|
return xl
|
||||||
if SIMPLE_NAME_PAT.match(x) is not None and not x.lower().startswith('and'):
|
if SIMPLE_NAME_PAT.match(x) is not None and not x.lower().startswith('and'):
|
||||||
# cssutils dies if a font name starts with and
|
# css_parser dies if a font name starts with and
|
||||||
return x
|
return x
|
||||||
return '"%s"' % x.replace('"', r'\"')
|
return '"%s"' % x.replace('"', r'\"')
|
||||||
|
|
||||||
@ -58,6 +58,7 @@ def serialize_single_font_family(x):
|
|||||||
def serialize_font_family(families):
|
def serialize_font_family(families):
|
||||||
return ', '.join(map(serialize_single_font_family, families))
|
return ', '.join(map(serialize_single_font_family, families))
|
||||||
|
|
||||||
|
|
||||||
GLOBAL_IDENTS = frozenset('inherit initial unset normal'.split())
|
GLOBAL_IDENTS = frozenset('inherit initial unset normal'.split())
|
||||||
STYLE_IDENTS = frozenset('italic oblique'.split())
|
STYLE_IDENTS = frozenset('italic oblique'.split())
|
||||||
VARIANT_IDENTS = frozenset(('small-caps',))
|
VARIANT_IDENTS = frozenset(('small-caps',))
|
||||||
|
Loading…
x
Reference in New Issue
Block a user