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:
Kovid Goyal 2019-01-02 21:49:02 +05:30
parent 3f57acc815
commit dd7d8ea3c4
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
33 changed files with 91 additions and 121 deletions

View File

@ -8,7 +8,7 @@ __copyright__ = '2014, Kovid Goyal <kovid at kovidgoyal.net>'
import re
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
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.ebooks.oeb.polish.container import OEB_DOCS, OEB_STYLES, serialize
class DemoTool(Tool):
#: 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
for name, media_type in container.mime_map.iteritems():
if media_type in OEB_STYLES:
# A stylesheet. Parsed stylesheets are cssutils CSSStylesheet
# A stylesheet. Parsed stylesheets are css_parser CSSStylesheet
# objects.
self.magnify_stylesheet(container.parsed(name), factor)
container.dirty(name) # Tell the container that we have changed the stylesheet

View File

@ -262,7 +262,7 @@ class OutputProfile(Plugin):
touchscreen = False
touchscreen_news_css = ''
#: 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 = []
#: If True, the date is appended to the title of downloaded news
periodical_date_in_title = True

View File

@ -2036,12 +2036,12 @@ class KOBOTOUCH(KOBO):
def get_extra_css(self):
extra_sheet = None
from cssutils.css import CSSRule
from css_parser.css import CSSRule
if self.modifying_css():
extra_css_path = os.path.join(self._main_prefix, self.KOBO_EXTRA_CSSFILE)
if os.path.exists(extra_css_path):
from cssutils import parseFile as cssparseFile
from css_parser import parseFile as cssparseFile
try:
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)))
@ -2068,7 +2068,7 @@ class KOBOTOUCH(KOBO):
return [r for r in sheet.cssRules.rulesOfType(css_rule)]
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)
if (r.style['widows'] or r.style['orphans'])]
@ -2158,7 +2158,7 @@ class KOBOTOUCH(KOBO):
return True
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):

View File

@ -497,7 +497,7 @@ class EPUBOutput(OutputFormatPlugin):
if stylesheet is not None:
# 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):
sel = '.'+lb.get('class')
for rule in stylesheet.data.cssRules.rulesOfType(CSSRule.STYLE_RULE):

View File

@ -73,8 +73,8 @@ class FB2Input(InputFormatPlugin):
css += etree.tostring(s, encoding=unicode, method='text',
with_tail=False) + '\n\n'
if css:
import cssutils, logging
parser = cssutils.CSSParser(fetcher=None,
import css_parser, logging
parser = css_parser.CSSParser(fetcher=None,
log=logging.getLogger('calibre.css'))
XHTML_CSS_NAMESPACE = '@namespace "%s";\n' % XHTML_NS

View File

@ -109,8 +109,8 @@ class HTMLInput(InputFormatPlugin):
from calibre.ebooks.html.input import get_filelist
from calibre.ebooks.metadata import string_to_authors
from calibre.utils.localization import canonicalize_lang
import cssutils, logging
cssutils.log.setLevel(logging.WARN)
import css_parser, logging
css_parser.log.setLevel(logging.WARN)
self.OEB_STYLES = OEB_STYLES
oeb = create_oebbook(log, None, opts, self,
encoding=opts.input_encoding, populate=False)
@ -189,7 +189,7 @@ class HTMLInput(InputFormatPlugin):
if href == item.href:
dpath = os.path.dirname(path)
break
cssutils.replaceUrls(item.data,
css_parser.replaceUrls(item.data,
partial(self.resource_adder, base=dpath))
toc = self.oeb.toc

View File

@ -1051,8 +1051,8 @@ OptionRecommendation(name='search_replace',
if self.opts.embed_all_fonts or self.opts.embed_font_family:
# Start the threaded font scanner now, for performance
from calibre.utils.fonts.scanner import font_scanner # noqa
import cssutils, logging
cssutils.log.setLevel(logging.WARN)
import css_parser, logging
css_parser.log.setLevel(logging.WARN)
get_types_map() # Ensure the mimetypes module is intialized
if self.opts.debug_pipeline is not None:

View File

@ -8,7 +8,7 @@ from functools import partial
from collections import OrderedDict
import operator
from cssutils.css import Property, CSSRule
from css_parser.css import Property, CSSRule
from calibre import force_unicode
from calibre.ebooks import parse_css_length
@ -345,7 +345,7 @@ def export_rules(serialized_rules):
def import_rules(raw_data):
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 = {}
def sanitize(r):

View File

@ -327,28 +327,6 @@ def upshift_markup(parts):
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):
# First update all internal links that are based on offsets
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):
os.mkdir(fi.dir)
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'))
return spine

View File

@ -13,8 +13,8 @@ from collections import defaultdict, namedtuple
from io import BytesIO
from struct import pack
import cssutils
from cssutils.css import CSSRule
import css_parser
from css_parser.css import CSSRule
from lxml import etree
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
affect KF8 output and not MOBI 6 output '''
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
cssutils.log.setLevel(logging.CRITICAL)
css_parser.log.setLevel(logging.CRITICAL)
for item in self.oeb.manifest:
if item.media_type in XML_DOCS:
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
# in-memory CSSStylesheet, as deepcopy doesn't work (raises an
# exception)
self._data_cache[item.href] = cssutils.parseString(
self._data_cache[item.href] = css_parser.parseString(
item.data.cssText, validate=False)
def data(self, item):
@ -138,9 +138,9 @@ class KF8Writer(object):
for tag in XPath('//h:style')(root):
if tag.text:
sheet = cssutils.parseString(tag.text, validate=False)
sheet = css_parser.parseString(tag.text, validate=False)
replacer = partial(pointer, item)
cssutils.replaceUrls(sheet, replacer,
css_parser.replaceUrls(sheet, replacer,
ignoreImportRules=True)
repl = sheet.cssText
if isbytestring(repl):
@ -150,7 +150,7 @@ class KF8Writer(object):
elif item.media_type in OEB_STYLES:
sheet = self.data(item)
replacer = partial(pointer, item)
cssutils.replaceUrls(sheet, replacer, ignoreImportRules=True)
css_parser.replaceUrls(sheet, replacer, ignoreImportRules=True)
def extract_css_into_flows(self):
inlines = defaultdict(list) # Ensure identical <style>s not repeated
@ -194,7 +194,7 @@ class KF8Writer(object):
if not raw or not raw.strip():
extract(tag)
continue
sheet = cssutils.parseString(raw, validate=False)
sheet = css_parser.parseString(raw, validate=False)
if fix_import_rules(sheet):
raw = force_unicode(sheet.cssText, 'utf-8')

View File

@ -9,8 +9,8 @@ Convert an ODT file into a Open Ebook
import os, logging
from lxml import etree
from cssutils import CSSParser
from cssutils.css import CSSRule
from css_parser import CSSParser
from css_parser.css import CSSRule
from odf.odf2xhtml import ODF2XHTML
from odf.opendocument import load as odLoad
@ -184,8 +184,8 @@ class Extract(ODF2XHTML):
x.set('class', orig + ' ' + ' '.join(extra))
def do_filter_css(self, css):
from cssutils import parseString
from cssutils.css import CSSRule
from css_parser import parseString
from css_parser.css import CSSRule
sheet = parseString(css, validate=False)
rules = list(sheet.cssRules.rulesOfType(CSSRule.STYLE_RULE))
sel_map = {}
@ -301,7 +301,3 @@ class Extract(ODF2XHTML):
with open('metadata.opf', 'wb') as f:
opf.render(f)
return os.path.abspath('metadata.opf')

View File

@ -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
tag text will be removed completely.
'''
from cssutils import replaceUrls, log, CSSParser
from css_parser import replaceUrls, log, CSSParser
log.setLevel(logging.WARN)
log.raiseExceptions = False
@ -269,7 +269,7 @@ def rewrite_links(root, link_repl_func, resolve_base_href=False):
try:
stext = parser.parseStyle(text, validate=False)
except Exception:
# Parsing errors are raised by cssutils
# Parsing errors are raised by css_parser
continue
replaceUrls(stext, link_repl_func)
repl = stext.cssText.replace('\n', ' ').replace('\r',
@ -971,8 +971,8 @@ class Manifest(object):
return self._parse_xhtml(convert_markdown(data, title=title))
def _parse_css(self, data):
from cssutils import CSSParser, log, resolveImports
from cssutils.css import CSSRule
from css_parser import CSSParser, log, resolveImports
from css_parser.css import CSSRule
log.setLevel(logging.WARN)
log.raiseExceptions = False
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
namespace.
- 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.
- All other content is returned as a :class:`str` object with no
special parsing.

View File

@ -9,11 +9,8 @@ __copyright__ = '2013, Kovid Goyal <kovid at kovidgoyal.net>'
from polyglot.builtins import zip
from functools import wraps
try:
from cssutils.css import PropertyValue
except ImportError:
raise RuntimeError('You need cssutils >= 0.9.9 for calibre')
from cssutils import profile as cssprofiles, CSSParser
from css_parser.css import PropertyValue
from css_parser import profile as cssprofiles, CSSParser
from tinycss.fonts3 import parse_font, serialize_font_family
DEFAULTS = {'azimuth': 'center', 'background-attachment': 'scroll', # {{{
@ -269,7 +266,7 @@ def condense_sheet(sheet):
def test_normalization(return_tests=False): # {{{
import unittest
from cssutils import parseStyle
from css_parser import parseStyle
from itertools import product
class TestNormalization(unittest.TestCase):

View File

@ -10,7 +10,7 @@ from itertools import count
from operator import itemgetter
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 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 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_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)
'''
@ -104,7 +105,7 @@ def iterdeclaration(decl):
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
for this property should be resolved. '''

View File

@ -6,7 +6,7 @@ from __future__ import (unicode_literals, division, absolute_import,
__license__ = 'GPL v3'
__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.ebooks.oeb.base import OEB_DOCS, OEB_STYLES

View File

@ -50,7 +50,7 @@ def run_checks(container):
if err.level > WARN:
return errors
# cssutils is not thread safe
# css_parser is not thread safe
for name, mt, raw in stylesheets:
if not raw:
errors.append(EmptyFile(name))
@ -107,4 +107,3 @@ def fix_errors(container, errors):
# better to have a false positive than a false negative)
changed = True
return changed

View File

@ -9,7 +9,7 @@ __copyright__ = '2013, Kovid Goyal <kovid at kovidgoyal.net>'
import re
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.ebooks.chardet import replace_encoding_declarations, find_declared_encoding
@ -432,7 +432,7 @@ class BareTextInBody(BaseError):
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):
# 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):
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:
parser.parseStyle(raw, validate=True)
else:

View File

@ -19,7 +19,7 @@ from io import BytesIO
from itertools import count
from urlparse import urlparse
from cssutils import getUrls, replaceUrls
from css_parser import getUrls, replaceUrls
from lxml import etree
from calibre import CurrentDir, walk
@ -589,7 +589,7 @@ class Container(ContainerBase): # {{{
def parsed(self, name):
''' 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
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`.'''
@ -605,7 +605,7 @@ class Container(ContainerBase): # {{{
def replace(self, name, obj):
'''
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.
'''
self.parsed_cache[name] = obj

View File

@ -9,7 +9,7 @@ __copyright__ = '2014, Kovid Goyal <kovid at kovidgoyal.net>'
from collections import defaultdict
from functools import partial
from cssutils.css import CSSRule, CSSStyleDeclaration
from css_parser.css import CSSRule, CSSStyleDeclaration
from css_selectors import parse, SelectorSyntaxError
from calibre import force_unicode
@ -208,7 +208,7 @@ def filter_declaration(style, properties=()):
def filter_sheet(sheet, properties=()):
from cssutils.css import CSSRule
from css_parser.css import CSSRule
changed = False
remove = []
for rule in sheet.cssRules.rulesOfType(CSSRule.STYLE_RULE):

View File

@ -8,7 +8,7 @@ __copyright__ = '2016, Kovid Goyal <kovid at kovidgoyal.net>'
from functools import partial
from cssutils import parseStyle
from css_parser import parseStyle
from calibre.constants import iswindows
from calibre.ebooks.oeb.base import OEB_STYLES, OEB_DOCS

View File

@ -16,9 +16,9 @@ def guess_type(x):
return _guess_type(x)[0] or 'application/octet-stream'
def setup_cssutils_serialization(tab_width=2):
import cssutils
prefs = cssutils.ser.prefs
def setup_css_parser_serialization(tab_width=2):
import css_parser
prefs = css_parser.ser.prefs
prefs.indent = tab_width * ' '
prefs.indentClosingBrace = 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:
import logging
log_level = logging.WARNING
from cssutils import CSSParser, log
from css_parser import CSSParser, log
from calibre.ebooks.oeb.base import _css_logger
log.setLevel(log_level)
log.raiseExceptions = False

View File

@ -185,7 +185,7 @@ class OEBReader(object):
return bad
def _manifest_add_missing(self, invalid):
import cssutils
import css_parser
manifest = self.oeb.manifest
known = set(manifest.hrefs)
unchecked = set(manifest.values())
@ -225,7 +225,7 @@ class OEBReader(object):
new.add(href)
elif item.media_type in OEB_STYLES:
try:
urls = list(cssutils.getUrls(data))
urls = list(css_parser.getUrls(data))
except:
urls = []
for url in urls:

View File

@ -11,10 +11,10 @@ __copyright__ = '2008, Marshall T. Vandegrift <llasram@gmail.com>'
import os, re, logging, copy, unicodedata
from weakref import WeakKeyDictionary
from xml.dom import SyntaxErr as CSSSyntaxError
from cssutils.css import (CSSStyleRule, CSSPageRule, CSSFontFaceRule,
from css_parser.css import (CSSStyleRule, CSSPageRule, CSSFontFaceRule,
cssproperties)
from cssutils import (profile as cssprofiles, parseString, parseStyle, log as
cssutils_log, CSSParser, profiles, replaceUrls)
from css_parser import (profile as cssprofiles, parseString, parseStyle, log as
css_parser_log, CSSParser, profiles, replaceUrls)
from calibre import force_unicode, as_unicode
from calibre.ebooks import unit_convert
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 tinycss.media3 import CSSMedia3Parser
cssutils_log.setLevel(logging.WARN)
css_parser_log.setLevel(logging.WARN)
_html_css_stylesheet = None
@ -123,7 +123,7 @@ class Stylizer(object):
stylesheets.append(parseString(base_css, validate=False))
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:
cssprofiles.addProfile(profile['name'],
profile['props'],

View File

@ -9,7 +9,7 @@ __copyright__ = '2013, Kovid Goyal <kovid at kovidgoyal.net>'
import logging
from collections import defaultdict
import cssutils
import css_parser
from lxml import etree
from calibre import guess_type
@ -97,7 +97,7 @@ class EmbedFonts(object):
self.sheet_cache = {}
self.find_style_rules()
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.warned2 = set()
self.newly_embedded_fonts = set()

View File

@ -25,7 +25,7 @@ class RenameFiles(object): # {{{
self.renamed_items_map = renamed_items_map
def __call__(self, oeb, opts):
import cssutils
import css_parser
self.log = oeb.logger
self.opts = opts
self.oeb = oeb
@ -35,7 +35,7 @@ class RenameFiles(object): # {{{
if etree.iselement(item.data):
rewrite_links(self.current_item.data, self.url_replacer)
elif hasattr(item.data, 'cssText'):
cssutils.replaceUrls(item.data, self.url_replacer)
css_parser.replaceUrls(item.data, self.url_replacer)
if self.oeb.guide:
for ref in self.oeb.guide.values():
@ -184,4 +184,3 @@ class FlatFilenames(object): # {{{
renamer = RenameFiles(self.rename_map, self.renamed_items_map)
renamer(oeb, opts)
# }}}

View File

@ -11,8 +11,8 @@ from collections import defaultdict
from xml.dom import SyntaxErr
from lxml import etree
import cssutils
from cssutils.css import Property
import css_parser
from css_parser.css import Property
from calibre import guess_type
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')
rules = [x.cssText for x in self.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],
data=sheet).href
return self.href
@ -203,7 +203,7 @@ class CSSFlattener(object):
# Make all links to resources absolute, as these sheets will be
# consolidated into a single stylesheet at the root of the document
if item.media_type in OEB_STYLES:
cssutils.replaceUrls(item.data, item.abshref,
css_parser.replaceUrls(item.data, item.abshref,
ignoreImportRules=True)
self.body_font_family, self.embed_font_rules = self.get_embed_font_info(
@ -278,7 +278,7 @@ class CSSFlattener(object):
cfont[k] = font[k]
rule = '@font-face { %s }'%('; '.join(u'%s:%s'%(k, v) for k, v in
cfont.iteritems()))
rule = cssutils.parseString(rule)
rule = css_parser.parseString(rule)
efi.append(rule)
return body_font_family, efi
@ -615,7 +615,7 @@ class CSSFlattener(object):
if item.media_type in OEB_STYLES:
manifest.remove(item)
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:
from calibre.ebooks.css_transform_rules import transform_sheet
transform_sheet(self.transform_css_rules, sheet)
@ -647,7 +647,7 @@ class CSSFlattener(object):
href = None
if css.strip():
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:
from calibre.ebooks.css_transform_rules import transform_sheet
transform_sheet(self.transform_css_rules, sheet)

View File

@ -65,7 +65,7 @@ class RemoveFakeMargins(object):
stylesheet = stylesheet.data
from cssutils.css import CSSRule
from css_parser.css import CSSRule
for rule in stylesheet.cssRules.rulesOfType(CSSRule.STYLE_RULE):
self.selector_map[rule.selectorList.selectorText] = rule.style

View File

@ -23,7 +23,7 @@ class ManifestTrimmer(object):
return cls()
def __call__(self, oeb, context):
import cssutils
import css_parser
oeb.logger.info('Trimming unused files from manifest...')
self.opts = context
used = set()
@ -60,7 +60,7 @@ class ManifestTrimmer(object):
if found not in used:
new.add(found)
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))
if href in oeb.manifest.hrefs:
found = oeb.manifest.hrefs[href]

View File

@ -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.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.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.dialogs.confirm_delete import confirm
from calibre.gui2.tweak_book import (
@ -61,7 +61,7 @@ def get_container(*args, **kwargs):
return container
def setup_cssutils_serialization():
def setup_css_parser_serialization():
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.doing_terminal_save = False
self.ignore_preview_to_editor_sync = False
setup_cssutils_serialization()
setup_css_parser_serialization()
get_boss.boss = self
self.gui = parent
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']))
if ret == p.Accepted:
setup_cssutils_serialization()
setup_css_parser_serialization()
self.gui.apply_settings()
self.refresh_file_list()
if ret == p.Accepted or p.dictionaries_changed:

View File

@ -53,9 +53,9 @@ def beautify_text(raw, syntax):
elif syntax == 'css':
import logging
from calibre.ebooks.oeb.base import serialize, _css_logger
from calibre.ebooks.oeb.polish.utils import setup_cssutils_serialization
from cssutils import CSSParser, log
setup_cssutils_serialization(tprefs['editor_tab_stop_width'])
from calibre.ebooks.oeb.polish.utils import setup_css_parser_serialization
from css_parser import CSSParser, log
setup_css_parser_serialization(tprefs['editor_tab_stop_width'])
log.setLevel(logging.WARN)
log.raiseExceptions = False
parser = CSSParser(loglevel=logging.WARNING,

View File

@ -10,7 +10,7 @@ import sys, re
from operator import itemgetter
from itertools import chain
from cssutils import parseStyle
from css_parser import parseStyle
from PyQt5.Qt import QTextEdit, Qt, QTextCursor
from calibre import prepare_string_for_xml, xml_entity_to_unicode

View File

@ -13,8 +13,8 @@ from polyglot.builtins import map
from urlparse import urlparse
from urllib import quote
from cssutils import replaceUrls
from cssutils.css import CSSRule
from css_parser import replaceUrls
from css_parser.css import CSSRule
from calibre import prepare_string_for_xml, force_unicode
from calibre.ebooks import parse_css_length

View File

@ -50,7 +50,7 @@ def serialize_single_font_family(x):
xl = 'sans-serif'
return xl
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 '"%s"' % x.replace('"', r'\"')
@ -58,6 +58,7 @@ def serialize_single_font_family(x):
def serialize_font_family(families):
return ', '.join(map(serialize_single_font_family, families))
GLOBAL_IDENTS = frozenset('inherit initial unset normal'.split())
STYLE_IDENTS = frozenset('italic oblique'.split())
VARIANT_IDENTS = frozenset(('small-caps',))