Exemple #1
0
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
Exemple #2
0
	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
Exemple #3
0
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
Exemple #4
0
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.']
Exemple #6
0
 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)
Exemple #7
0
    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"
                )
Exemple #8
0
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
Exemple #9
0
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)
Exemple #10
0
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)
Exemple #11
0
 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)
Exemple #12
0
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
Exemple #13
0
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)))
Exemple #15
0
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)
Exemple #16
0
    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
Exemple #17
0
 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', ''))
Exemple #18
0
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)
Exemple #19
0
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
Exemple #20
0
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
Exemple #21
0
 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
Exemple #25
0
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
Exemple #27
0
def keyframe_simple():
    return tinycss2.parse_stylesheet("""
        @keyframes redintensity {
            from {
                color: rgba(255, 0, 0, 1);
            }
            to {
                color: rgba(255, 0, 0, 0);
            }
        }
    """)[1]
Exemple #28
0
 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)
Exemple #29
0
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]
Exemple #30
0
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]
Exemple #31
0
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"
    ]
Exemple #32
0
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"]
Exemple #35
0
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)
Exemple #36
0
 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
Exemple #38
0
    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),))
Exemple #40
0
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'),))
Exemple #42
0
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)
Exemple #43
0
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')
Exemple #45
0
    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
Exemple #46
0
def test_page_selectors(style, selectors):
    at_rule, = tinycss2.parse_stylesheet(style)
    assert parse_page_selectors(at_rule) == selectors
Exemple #47
0
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>