def inline(svg): """ Inline the CSS rules in an SVG. This is a very rough operation, and full css precedence rules won't be respected. May ignore sibling operators (``~``, ``+``), pseudo-selectors (e.g. ``:first-child``), and attribute selectors (e.g. ``.foo[name=bar]``). Works best with rules like: * ``.class`` * ``tag`` * ``tag.class`` * ``#layer .class`` * ``#layer tag`` Args: svg (string): An SVG document. style (string): CSS to use, instead of the CSS in the <defs> element of the SVG. """ try: doc = etree.fromstring(svg.encode('utf-8')) style_element = doc.find('.//style', namespaces=doc.nsmap) if style_element is None: return svg css = style_element.text rules = tinycss2.parse_stylesheet(css, skip_whitespace=True, skip_comments=True) dom.apply_rules(doc, rules) return etree.tostring(doc, encoding='utf-8').decode('utf-8') # Return plain old SVG. except (AttributeError, NameError) as e: logging.getLogger('svgis').warning("Unable to inline CSS: %s", e) return svg
def process_css_block(self, css_text): ss = tinycss2.parse_stylesheet(css_text, skip_whitespace=True, skip_comments=True) # print(ss) bad_classes = [] ssf = [tmp for tmp in ss if tmp.type == "qualified-rule"] for rule in ssf: prelude = rule.prelude content = rule.content prelude = [tmp for tmp in prelude if tmp.type != 'whitespace'] content = [tmp for tmp in content if tmp.type != 'whitespace'] if ( len(prelude) == 2 and prelude[0].type == "literal" and prelude[1].type == "ident" and prelude[0].value == "." and len(content) == 4 and content[0].type == "ident" and content[1].type == "literal" and content[2].type == "ident" and content[3].type == "literal" and content[0].lower_value == "display" and content[2].lower_value == "none" ): bad_class = prelude[1].value bad_classes.append(bad_class) return bad_classes
def test_skip(): source = ''' /* foo */ @media print { #foo { width: /* bar*/4px; color: green; } } ''' no_ws = parse_stylesheet(source, skip_whitespace=True) no_comment = parse_stylesheet(source, skip_comments=True) default = parse_component_value_list(source) assert serialize(no_ws) != source assert serialize(no_comment) != source assert serialize(default) == source
def test_font_face_bad_1(): stylesheet = tinycss2.parse_stylesheet('@font-face {' ' font-family: "Bad Font";' ' src: url(BadFont.woff);' ' font-stretch: expanded;' ' font-style: wrong;' ' font-weight: bolder;' ' font-stretch: wrong;' '}') at_rule, = stylesheet assert at_rule.at_keyword == 'font-face' with capture_logs() as logs: font_family, src, font_stretch = list( preprocess_descriptors( 'font-face', 'http://weasyprint.org/foo/', tinycss2.parse_declaration_list(at_rule.content))) assert font_family == ('font_family', 'Bad Font') assert src == ('src', (('external', 'http://weasyprint.org/foo/BadFont.woff'), )) assert font_stretch == ('font_stretch', 'expanded') assert logs == [ 'WARNING: Ignored `font-style: wrong` at 1:91, invalid value.', 'WARNING: Ignored `font-weight: bolder` at 1:111, invalid value.', 'WARNING: Ignored `font-stretch: wrong` at 1:133, invalid value.' ]
def test_font_face_bad_1(): stylesheet = tinycss2.parse_stylesheet( '@font-face {' ' font-family: "Bad Font";' ' src: url(BadFont.woff);' ' font-stretch: expanded;' ' font-style: wrong;' ' font-weight: bolder;' ' font-stretch: wrong;' '}') at_rule, = stylesheet assert at_rule.at_keyword == 'font-face' with capture_logs() as logs: font_family, src, font_stretch = list( preprocess_descriptors( 'http://weasyprint.org/foo/', tinycss2.parse_declaration_list(at_rule.content))) assert font_family == ('font_family', 'Bad Font') assert src == ( 'src', (('external', 'http://weasyprint.org/foo/BadFont.woff'),)) assert font_stretch == ('font_stretch', 'expanded') assert logs == [ 'WARNING: Ignored `font-style: wrong` at 1:91, invalid value.', 'WARNING: Ignored `font-weight: bolder` at 1:111, invalid value.', 'WARNING: Ignored `font-stretch: wrong` at 1:133, invalid value.']
def __init__(self, guess=None, filename=None, url=None, file_obj=None, string=None, encoding=None, base_url=None, url_fetcher=default_url_fetcher, _check_mime_type=False, media_type='print', font_config=None, matcher=None, page_rules=None): PROGRESS_LOGGER.info( 'Step 2 - Fetching and parsing CSS - %s', filename or url or getattr(file_obj, 'name', 'CSS string')) result = _select_source( guess, filename, url, file_obj, string, base_url=base_url, url_fetcher=url_fetcher, check_css_mime_type=_check_mime_type) with result as (source_type, source, base_url, protocol_encoding): if source_type == 'string' and not isinstance(source, bytes): # unicode, no encoding stylesheet = tinycss2.parse_stylesheet(source) else: if source_type == 'file_obj': source = source.read() stylesheet, encoding = tinycss2.parse_stylesheet_bytes( source, environment_encoding=encoding, protocol_encoding=protocol_encoding) self.base_url = base_url self.matcher = matcher or cssselect2.Matcher() self.page_rules = [] if page_rules is None else page_rules # TODO: fonts are stored here and should be cleaned after rendering self.fonts = [] preprocess_stylesheet( media_type, base_url, stylesheet, url_fetcher, self.matcher, self.page_rules, self.fonts, font_config)
def __init__(self, selector): self._path = os.path.join(GLib.get_user_config_dir(), "gtk-3.0", "gtk.css") self.selector = selector self.rule_separator = "/***** %s - cinnamon-settings-generated - do not edit *****/" % self.selector rules = [] file = Gio.File.new_for_path(self._path) try: success, content_bytes, tag = file.load_contents(None) self._contents = content_bytes.decode() stylesheet = tinycss2.parse_stylesheet(self._contents) for rs in stylesheet: if isinstance(rs, tinycss2.ast.ParseError): continue rules.append(rs) self.stylesheet = rules except GLib.Error as e: if e.code == Gio.IOErrorEnum.NOT_FOUND: self._contents = "" self.stylesheet = rules else: raise PermissionError( "Could not load ~/.config/gtk-3.0/gtk.css file, check permissions" )
def parse_rules_from_bootstrap_css(css_text): import tinycss2 tinycss_parsed = tinycss2.parse_stylesheet(css_text) # Build dict from css selectors to dict of css prop-values rule_props = {} for token in tinycss_parsed: if token.type != "qualified-rule": continue rule = token selector_str = "".join([t.serialize() for t in rule.prelude]) selectors = tuple(s.strip() for s in selector_str.split(",")) property_strings = [ entry for entry in "".join([c.serialize().strip() for c in rule.content]).split(";") if entry ] property_pairs = [prop_str.split(":") for prop_str in property_strings] for selector in selectors: for prop_pair in property_pairs: if len(prop_pair) != 2: continue rule_props.setdefault(selector, {}) prop_key = prop_pair[0] prop_value = prop_pair[1].replace("!important", "").strip() rule_props[selector][prop_key] = prop_value return rule_props
def load_fonts(css_url): with urllib.request.urlopen(css_url) as url: css = url.read().decode() rules = tinycss2.parse_stylesheet(css, skip_comments=True) font_solid = None font_regular = None for rule in rules: if rule.type == "at-rule" and rule.at_keyword == "font-face": for component in rule.content: if component.type == "url" and component.value.endswith( ".woff"): font_url = urllib.parse.urljoin(css_url, component.value) fd = urllib.request.urlopen(font_url) font = fd.read() if "fa-solid-900" in component.value: font_solid = font elif "fa-regular-400" in component.value: font_regular = font else: print('Warning font "{0}" found in import but unused.'. format(font_url)) if font_solid == None or font_regular == None: print("Error one of the required fonts was not found") sys.exit() return (font_solid, font_regular)
def parse_style_sheet( css, ) -> Generator[Union[Tuple[Tuple[Callable[[object], bool], Tuple[ int, int, int]], Dict[str, object]], Tuple[Literal["error"], Union[ tinycss2.ast.ParseError, SelectorError]], ], None, None, ]: rules = tinycss2.parse_stylesheet(css or "", skip_comments=True, skip_whitespace=True) for rule in rules: if rule.type == "error": yield ("error", rule) # type: ignore[misc] continue if rule.type != "qualified-rule": continue try: selectors = compile_selector_list(rule.prelude) except SelectorError as e: yield ("error", e) # type: ignore[misc] continue declaration = { prop: value for prop, value in parse_declarations(rule.content) if prop != "error" and value is not None } yield from ((selector, declaration) for selector in selectors)
def __init__(self, guess=None, filename=None, url=None, file_obj=None, string=None, encoding=None, base_url=None, url_fetcher=default_url_fetcher, _check_mime_type=False, media_type='print', font_config=None, counter_style=None, matcher=None, page_rules=None): PROGRESS_LOGGER.info( 'Step 2 - Fetching and parsing CSS - %s', filename or url or getattr(file_obj, 'name', 'CSS string')) result = _select_source( guess, filename, url, file_obj, string, base_url=base_url, url_fetcher=url_fetcher, check_css_mime_type=_check_mime_type) with result as (source_type, source, base_url, protocol_encoding): if source_type == 'string' and not isinstance(source, bytes): # unicode, no encoding stylesheet = tinycss2.parse_stylesheet(source) else: if source_type == 'file_obj': source = source.read() stylesheet, encoding = tinycss2.parse_stylesheet_bytes( source, environment_encoding=encoding, protocol_encoding=protocol_encoding) self.base_url = base_url self.matcher = matcher or cssselect2.Matcher() self.page_rules = [] if page_rules is None else page_rules self.fonts = [] preprocess_stylesheet( media_type, base_url, stylesheet, url_fetcher, self.matcher, self.page_rules, self.fonts, font_config, counter_style)
def parse_stylesheets(tree, url): """Find stylesheets and return rule matchers in given tree.""" normal_matcher = cssselect2.Matcher() important_matcher = cssselect2.Matcher() # Find stylesheets # TODO: support contentStyleType on <svg> stylesheets = [] for element in tree.etree_element.iter(): # http://www.w3.org/TR/SVG/styling.html#StyleElement if (element.tag == '{http://www.w3.org/2000/svg}style' and element.get('type', 'text/css') == 'text/css' and element.text): # TODO: pass href for relative URLs # TODO: support media types # TODO: what if <style> has children elements? stylesheets.append(tinycss2.parse_stylesheet( element.text, skip_comments=True, skip_whitespace=True)) # Parse rules and fill matchers for stylesheet in stylesheets: for rule in find_stylesheets_rules(tree, stylesheet, url): normal_declarations, important_declarations = parse_declarations( rule.content) for selector in cssselect2.compile_selector_list(rule.prelude): if (selector.pseudo_element is None and not selector.never_matches): if normal_declarations: normal_matcher.add_selector( selector, normal_declarations) if important_declarations: important_matcher.add_selector( selector, important_declarations) return normal_matcher, important_matcher
def get_pics_from_css(css_files): pics = {} file_size = {} for f in css_files: print 'processing:', f css_content = tinycss2.parse_stylesheet(open(f, 'r').read(), skip_whitespace=True, skip_comments=True) for rule in css_content: if rule.type != 'qualified-rule': continue for token in rule.content: if token.type != 'url' or '?sprite' not in token.value: continue pic_file = token.value.split("?sprite") if not pic_file[1]: sprite_file = u"sprite" else: sprite_file = pic_file[1].replace("=", "") if sprite_file not in pics: pics[sprite_file] = [] file_size[sprite_file] = [] if pic_file[0] not in pics[sprite_file]: pics[sprite_file].append(pic_file[0]) path = pic_file[0].split('/')[2:] image_path = os.path.join(static_root, *path) image = Image.open(image_path, 'r') file_size[sprite_file].append(image.size) image.close() return file_size, pics
def optimizeCss(self, css): """replaces classes and ids with new values in a css file Arguments: path -- string path to css file to optimize Returns: string """ def obsfucate_selector(token_list): begin_class = False for token in token_list: if token.type == "literal" and token.value == ".": begin_class = True else: if token.type == "ident" and begin_class: if token.value in self.class_map: token.value = self.class_map[token.value] elif token.type == "hash" and token.value in self.id_map: token.value = self.id_map[token.value] begin_class = False stylesheet = tinycss2.parse_stylesheet(css) for node in stylesheet: if node.type == 'qualified-rule': obsfucate_selector(node.prelude) elif node.type == 'at-rule': if node.content is not None: obsfucate_selector(node.content) return "".join(list(map(lambda x: x.serialize(), stylesheet)))
def parse_style_sheet(css: str) -> Iterator[Rule]: rules = tinycss2.parse_stylesheet(css or "", skip_comments=True, skip_whitespace=True) for rule in rules: if rule.type == "error": yield ("error", rule) # type: ignore[misc] continue if rule.type != "qualified-rule": continue try: selectors = compile_selector_list(rule.prelude) except SelectorError as e: yield ("error", e) # type: ignore[misc] continue declaration = { prop: value for prop, value in parse_declarations(rule.content) if prop != "error" and value is not None } yield from ((selector, declaration) for selector in selectors)
def consume(self, source): """ Parse source and consume tokens from tinycss2. Arguments: source (string): Source content to parse. Returns: dict: Retrieved rules. """ manifest = OrderedDict() rules = parse_stylesheet( source, skip_comments=True, skip_whitespace=True, ) for rule in rules: # Gather rule selector+properties name = self.digest_prelude(rule) # Ignore everything out of styleguide namespace if not name.startswith(RULE_BASE_PREFIX): continue properties = self.digest_content(rule) manifest[name] = properties return manifest
def testChildToken(self): css = "#foo > #baz { stroke: green }" rules = tinycss2.parse_stylesheet(css, skip_whitespace=True, skip_comments=True) dom.apply_rules(self.document, rules) polyline = self.document.find(".//*[@id='baz']") self.assertIn('stroke:green', polyline.attrib.get('style', ''))
def parse_css_file(filename): """ Parse a DSS file """ css = cssutils.parseFile(filename) rules = parse_rules(css) with open(filename) as f: css = tinycss2.parse_stylesheet(f.read()) keyframes = parse_keyframes(css) return CSS(rules=rules, keyframes=keyframes)
def urls_from_css(css_text: str) -> List[str]: """Given CSS text, parse it and return all URLs found""" urls = [] nodes = tinycss2.parse_stylesheet(css_text) for node in descendants(nodes): if getattr(node, 'type', '') == 'url': urls.append(node.value) return urls
def test_counter_style_invalid(rule): stylesheet = tinycss2.parse_stylesheet(rule) with capture_logs() as logs: descriptors = [] preprocess_stylesheet('print', 'http://wp.org/foo/', stylesheet, None, None, None, descriptors, None, {}) assert not descriptors assert len(logs) >= 1
def __create_tynicss_stylesheet(cls, data): if hasattr(data, "read"): # is file like object css_parser, _ = tinycss2.parse_stylesheet_bytes( data.read(), skip_comments=True, skip_whitespace=True) else: css_parser = tinycss2.parse_stylesheet(data, skip_comments=True, skip_whitespace=True) return css_parser
def _remove_unused_selectors(self, css, unused): """Remove all unused rules from CSS""" new_css = '' rules = tinycss2.parse_stylesheet(css) for rule in rules[:]: rule_css = self._remove_unused_selectors_from_rule(rule, unused) new_css += rule_css # new_css = new_css.encode('utf8') return new_css
def test_font_face_bad_4(): stylesheet = tinycss2.parse_stylesheet('@font-face{font-family: test}') with capture_logs() as logs: descriptors = [] preprocess_stylesheet( 'print', 'http://wp.org/foo/', stylesheet, None, None, None, descriptors, None) assert not descriptors assert logs == [ "WARNING: Missing src descriptor in '@font-face' rule at 1:1"]
def main(filepath): open_mode = 'r' try: with open(filepath, open_mode) as f: text = f.read() result_list = tinycss2.parse_stylesheet(text) process_result_list(result_list) except (IOError, UnicodeDecodeError)as ex: log.error('Error: reading file: %s %s' % (filepath, ex)) raise
def test_font_face_bad_4(): stylesheet = tinycss2.parse_stylesheet('@font-face{font-family: test}') with capture_logs() as logs: descriptors = [] preprocess_stylesheet('print', 'http://wp.org/foo/', stylesheet, None, None, None, descriptors, None, None) assert not descriptors assert logs == [ "WARNING: Missing src descriptor in '@font-face' rule at 1:1" ]
def main(filepath): open_mode = 'r' try: with open(filepath, open_mode) as f: text = f.read() result_list = tinycss2.parse_stylesheet(text) process_result_list(result_list) except (IOError, UnicodeDecodeError) as ex: log.error('Error: reading file: %s %s' % (filepath, ex)) raise
def keyframe_simple(): return tinycss2.parse_stylesheet(""" @keyframes redintensity { from { color: rgba(255, 0, 0, 1); } to { color: rgba(255, 0, 0, 0); } } """)[1]
def testApplyRule(self): rules = tinycss2.parse_stylesheet("polygon {fill: orange}", skip_whitespace=True, skip_comments=True) svg = etree.fromstring( '<svg baseProfile="full" height="1" version="1.1" xmlns="http://www.w3.org/2000/svg">' '<polygon class="test" points="3,2 -2,6 8,-1 8,2 4,1 3,2" />' '</svg>') dom.apply_rules(svg, rules) text = etree.tostring(svg).decode('ascii') self.assertIn('orange', text)
def keyframe_fromto(): return tinycss2.parse_stylesheet(""" @keyframes redintensity { from, to { color: rgba(255, 0, 0, 1); } 50% { color: rgba(255, 0, 0, 0); } } """)[1]
def keyframe_percentage(): return tinycss2.parse_stylesheet(""" @keyframes redintensity { 0%, 100% { color: rgba(255, 0, 0, 1); } 50% { color: rgba(255, 0, 0, 0); } } """)[1]
def test_font_face_bad_5(): stylesheet = tinycss2.parse_stylesheet( '@font-face { font-family: test; src: wrong }') with capture_logs() as logs: descriptors = [] preprocess_stylesheet('print', 'http://wp.org/foo/', stylesheet, None, None, None, descriptors, None, None) assert not descriptors assert logs == [ 'WARNING: Ignored `src: wrong ` at 1:33, invalid value.', "WARNING: Missing src descriptor in '@font-face' rule at 1:1" ]
def test_font_face_bad_6(): stylesheet = tinycss2.parse_stylesheet( '@font-face { font-family: good, bad; src: url(test.woff) }') with capture_logs() as logs: descriptors = [] preprocess_stylesheet('print', 'http://wp.org/foo/', stylesheet, None, None, None, descriptors, None, None) assert not descriptors assert logs == [ 'WARNING: Ignored `font-family: good, bad` at 1:14, invalid value.', "WARNING: Missing font-family descriptor in '@font-face' rule at 1:1" ]
def test_font_face_bad_5(): stylesheet = tinycss2.parse_stylesheet( '@font-face { font-family: test; src: wrong }') with capture_logs() as logs: descriptors = [] preprocess_stylesheet( 'print', 'http://wp.org/foo/', stylesheet, None, None, None, descriptors, None) assert not descriptors assert logs == [ 'WARNING: Ignored `src: wrong ` at 1:33, invalid value.', "WARNING: Missing src descriptor in '@font-face' rule at 1:1"]
def test_font_face_bad_6(): stylesheet = tinycss2.parse_stylesheet( '@font-face { font-family: good, bad; src: url(test.woff) }') with capture_logs() as logs: descriptors = [] preprocess_stylesheet( 'print', 'http://wp.org/foo/', stylesheet, None, None, None, descriptors, None) assert not descriptors assert logs == [ 'WARNING: Ignored `font-family: good, bad` at 1:14, invalid value.', "WARNING: Missing font-family descriptor in '@font-face' rule at 1:1"]
def parse_stylesheet(css): rules = tinycss2.parse_stylesheet(css, skip_comments=True, skip_whitespace=True) for rule in rules: if rule.type == "qualified-rule": yield from parse_rule(rule) elif rule.type == "at-rule": yield from parse_at_rule(rule) elif rule.type == "error": log.warning("Parse error: {!r}", rule) else: log.warning("Unrecognized rule type: {!r}", rule.type)
def process(text): result_list = tinycss2.parse_stylesheet(text) parser.process_result_list(result_list) rename_list = [] for css_class in parser.CSS_CLASSES: old = css_class.lstrip('.') new = ''.join([CSS_CLASS_PREFIX, old]) rename_list.append((old, new)) with open('rename_list.csv', 'wb') as f: wr = csv.writer(f, quoting=csv.QUOTE_ALL) wr.writerows(rename_list) return result_list
def process(text): result_list = tinycss2.parse_stylesheet(text) parser.process_result_list(result_list) rename_list = [] for css_class in parser.CSS_CLASSES: old = css_class.lstrip('.') new = ''.join([CSS_CLASS_PREFIX, old]) rename_list.append((old, new)) with open('rename_list.csv', 'wb') as f: wr=csv.writer(f, quoting=csv.QUOTE_ALL) wr.writerows(rename_list) return result_list
def get_css(self): stylesheet = tinycss2.parse_stylesheet(self.css, skip_whitespace=True) rules = {} prev = None for rule in stylesheet: selector_string = rule.prelude content_string = rule.content s_rules = {} for content in content_string: if type(content) in [ tinycss2.ast.WhitespaceToken, tinycss2.ast.LiteralToken ]: continue if type(content) == tinycss2.ast.IdentToken: if type(prev) == tinycss2.ast.IdentToken: s_rules[prev.value] = content.value prev = None continue elif type(content) == tinycss2.ast.DimensionToken: if type(prev) == tinycss2.ast.IdentToken: s_rules[prev.value] = content.value prev = None continue elif type(content) == tinycss2.ast.StringToken: if type(prev) == tinycss2.ast.IdentToken: s_rules[prev.value] = content.value prev = None continue elif type(content) == tinycss2.ast.FunctionBlock: if type(prev) == tinycss2.ast.IdentToken: n = [] values = content.arguments for value in values: if type(value) in [ tinycss2.ast.WhitespaceToken, tinycss2.ast.LiteralToken ]: continue n.append(value.value) s_rules[prev.value] = n prev = None continue prev = content rules[selector_string[0].value] = s_rules return rules
def test_font_face_3(): stylesheet = tinycss2.parse_stylesheet( '@font-face {' ' font-family: Gentium Hard;' ' src: local();' '}') at_rule, = stylesheet assert at_rule.at_keyword == 'font-face' font_family, src = list(preprocess_descriptors( 'http://weasyprint.org/foo/', tinycss2.parse_declaration_list(at_rule.content))) assert font_family == ('font_family', 'Gentium Hard') assert src == ('src', (('local', None),))
def extract_urls_from_css(css): urls = [] rules = tinycss2.parse_stylesheet(css) for rule in rules: if rule.type == 'at-rule' and rule.lower_at_keyword == 'import': for token in rule.prelude: if token.type in ['string', 'url']: urls.append(token.value) elif hasattr(rule, 'content'): for token in rule.content: if token.type == 'url': urls.append(token.value) return urls
def test_font_face_1(): stylesheet = tinycss2.parse_stylesheet( '@font-face {' ' font-family: Gentium Hard;' ' src: url(http://example.com/fonts/Gentium.woff);' '}') at_rule, = stylesheet assert at_rule.at_keyword == 'font-face' font_family, src = list(preprocess_descriptors( 'http://weasyprint.org/foo/', tinycss2.parse_declaration_list(at_rule.content))) assert font_family == ('font_family', 'Gentium Hard') assert src == ( 'src', (('external', 'http://example.com/fonts/Gentium.woff'),))
def find_stylesheets(tree): """Find the stylesheets included in ``tree``.""" # TODO: support contentStyleType on <svg> default_type = 'text/css' for element in tree.xml_tree.iter(): # http://www.w3.org/TR/SVG/styling.html#StyleElement if (element.tag == '{http://www.w3.org/2000/svg}style' and element.get('type', default_type) == 'text/css' and element.text): # TODO: pass href for relative URLs # TODO: support media types # TODO: what if <style> has children elements? yield tinycss2.parse_stylesheet( element.text, skip_comments=True, skip_whitespace=True)
def find_stylesheets_rules(tree, stylesheet_rules, url): """Find the rules in a stylesheet.""" for rule in stylesheet_rules: if rule.type == 'at-rule': if rule.lower_at_keyword == 'import' and rule.content is None: # TODO: support media types in @import url_token = tinycss2.parse_one_component_value(rule.prelude) if url_token.type not in ('string', 'url'): continue css_url = parse_url(url_token.value, url) stylesheet = tinycss2.parse_stylesheet( tree.fetch_url(css_url, 'text/css').decode('utf-8')) for rule in find_stylesheets_rules( tree, stylesheet, css_url.geturl()): yield rule # TODO: support media types # if rule.lower_at_keyword == 'media': if rule.type == 'qualified-rule': yield rule
def test_font_face_2(): stylesheet = tinycss2.parse_stylesheet( '@font-face {' ' font-family: "Fonty Smiley";' ' src: url(Fonty-Smiley.woff);' ' font-style: italic;' ' font-weight: 200;' ' font-stretch: condensed;' '}') at_rule, = stylesheet assert at_rule.at_keyword == 'font-face' font_family, src, font_style, font_weight, font_stretch = list( preprocess_descriptors( 'http://weasyprint.org/foo/', tinycss2.parse_declaration_list(at_rule.content))) assert font_family == ('font_family', 'Fonty Smiley') assert src == ( 'src', (('external', 'http://weasyprint.org/foo/Fonty-Smiley.woff'),)) assert font_style == ('font_style', 'italic') assert font_weight == ('font_weight', 200) assert font_stretch == ('font_stretch', 'condensed')
def parse_and_validate(self, stylesheet_source): if len(stylesheet_source) > (MAX_SIZE_KIB * 1024): return "", [ValidationError(0, "TOO_BIG", {"size": MAX_SIZE_KIB})] nodes = tinycss2.parse_stylesheet(stylesheet_source) source_lines = stylesheet_source.splitlines() backslash_errors = self.check_for_evil_codepoints(source_lines) validation_errors = self.validate_rule_list(nodes) errors = [] for error in itertools.chain(backslash_errors, validation_errors): error._source_lines = source_lines errors.append(error) errors.sort(key=lambda e: e.line) if not errors: serialized = rcssmin.cssmin(tinycss2.serialize(nodes)) else: serialized = "" return serialized.encode("utf-8"), errors
def test_page_selectors(style, selectors): at_rule, = tinycss2.parse_stylesheet(style) assert parse_page_selectors(at_rule) == selectors
from xml.etree import ElementTree import cssselect2 import tinycss2 # Parse CSS and add rules to the matcher matcher = cssselect2.Matcher() rules = tinycss2.parse_stylesheet(''' body { font-size: 2em } body p { background: red } p { color: blue } ''', skip_whitespace=True) for rule in rules: selectors = cssselect2.compile_selector_list(rule.prelude) selector_string = tinycss2.serialize(rule.prelude) content_string = tinycss2.serialize(rule.content) payload = (selector_string, content_string) for selector in selectors: matcher.add_selector(selector, payload) # Parse HTML and find CSS rules applying to each tag html_tree = ElementTree.fromstring(''' <html> <body> <p>Test</p>