def parse(input, namespaces=None, forgiving=False): """Yield tinycss2 selectors found in given ``input``. :param input: A string, or an iterable of tinycss2 component values. """ if isinstance(input, str): input = parse_component_value_list(input) tokens = TokenStream(input) namespaces = namespaces or {} try: yield parse_selector(tokens, namespaces) except SelectorError as exception: if not forgiving: raise exception while 1: next = tokens.next() if next is None: return elif next == ',': try: yield parse_selector(tokens, namespaces) except SelectorError as exception: if not forgiving: raise exception else: if not forgiving: raise SelectorError(next, f'unexpected {next.type} token.')
def test_backslash_delim(): source = '\\\nfoo' tokens = parse_component_value_list(source) assert [t.type for t in tokens] == ['literal', 'whitespace', 'ident'] assert tokens[0].value == '\\' del tokens[1] assert [t.type for t in tokens] == ['literal', 'ident'] assert serialize(tokens) == source
def is_valid_css_component_value_list(css_component_value_list: str) -> bool: """Determines whether css component values are valid. :param css_component_value_list: css component value lists :type css_component_value_list: str :return: whether css component values is valid :rtype: bool """ values = parse_component_value_list(css_component_value_list) for value in values: if not isinstance(value, ParseError): continue return False return True
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 set_declaration(self, selector, decl_name, value_as_str): # Remove an existing declaration.. for some reason if they # get modified, they become invalid (or I'm doing something wrong) self.remove_declaration(selector, decl_name) rs, idx = self.get_ruleset(selector) # rs.content[0].value: the value of the WhitespaceToken is the actual indent prefix = "\n\t" if rs.content: prefix = rs.content[0].value component_values = tinycss2.parse_component_value_list(prefix + decl_name + ": " + value_as_str + ";") for component_value in component_values: self.stylesheet[idx].content.append(component_value)
def parse(input, namespaces=None): """ :param input: A :term:`string`, or an iterable of :term:`component values`. """ if isinstance(input, basestring): input = parse_component_value_list(input) tokens = TokenStream(input) namespaces = namespaces or {} yield parse_selector(tokens, namespaces) tokens.skip_whitespace_and_comment() while 1: next = tokens.next() if next is None: return elif next == ',': yield parse_selector(tokens, namespaces) else: raise SelectorError(next, 'unpexpected %s token.' % next.type)
def parse(input, namespaces=None): """Yield tinycss2 selectors found in given ``input``. :param input: A string, or an iterable of tinycss2 component values. """ if isinstance(input, str): input = parse_component_value_list(input) tokens = TokenStream(input) namespaces = namespaces or {} yield parse_selector(tokens, namespaces) tokens.skip_whitespace_and_comment() while 1: next = tokens.next() if next is None: return elif next == ",": yield parse_selector(tokens, namespaces) else: raise SelectorError(next, "unpexpected %s token." % next.type)
def test_comment_eof(): source = '/* foo ' parsed = parse_component_value_list(source) assert serialize(parsed) == '/* foo */'
def test_serialization(css): parsed = parse_component_value_list(css, skip_comments=True) return parse_component_value_list(serialize(parsed), skip_comments=True)
def test_component_value_list(input): return parse_component_value_list(input, skip_comments=True)
def beautify(cls, css, indent=2, encoding=None): """Prettifing `css` by reindending to width of `indent` per level. `css` is expected to be a valid Cascading Style Sheet :param css: a valid css as multiline string :param indent: width od indentation per level :param encoding: expected encoding of `css`. If None, it will be guesssed :returns: reindented css >>> # a single css rule >>> from html5print import CSSBeautifier >>> css = ".para { margin: 10px 20px; }" >>> print(CSSBeautifier.beautify(css)) .para { margin : 10px 20px; } >>> # multiple css rules >>> from html5print import CSSBeautifier >>> css = ".para { margin: 10px 20px; }" >>> css += os.linesep + "p { border: 5px solid red; }" >>> print(CSSBeautifier.beautify(css)) .para { margin : 10px 20px; } p { border : 5px solid red; } >>> # pseudo-class css rule >>> from html5print import CSSBeautifier >>> css = ' /* beginning of css*/\\n ::after { margin: 10px 20px; }' >>> print(CSSBeautifier.beautify(css)) /* beginning of css*/ ::after { margin : 10px 20px; } >>> # pseudo-class css rule with different indent >>> from html5print import CSSBeautifier >>> css = ' /* beginning of css*/\\n ::after { margin: 10px 20px; }' >>> print(CSSBeautifier.beautify(css, 4)) /* beginning of css*/ ::after { margin : 10px 20px; } >>> # pseudo-class css rules with comments in between >>> from html5print import CSSBeautifier >>> css = ' /* beginning of css*/\\n ::after { margin: 10px 20px; }' >>> css += os.linesep + ' /* another comment */p {' >>> css += 'h1 : color: #36CFFF; font-weight: normal;}' >>> print(CSSBeautifier.beautify(css, 4)) /* beginning of css*/ ::after { margin : 10px 20px; } /* another comment */ p { h1 : color: #36CFFF; font-weight : normal; } >>> # media query >>> from html5print import CSSBeautifier >>> css = '''@media (-webkit-min-device-pixel-ratio:0) { ... h2.collapse { margin: -22px 0 22px 18px; ... } ... ::i-block-chrome, h2.collapse { margin: 0 0 22px 0; } } ... ''' >>> print(CSSBeautifier.beautify(css, 4)) @media (-webkit-min-device-pixel-ratio:0) { h2.collapse { margin : -22px 0 22px 18px; } ::i-block-chrome, h2.collapse { margin : 0 0 22px 0; } } """ text = decodeText(css) extra = cls._tinycss2ParserFlag() ast = tinycss2.parse_component_value_list(text, **extra) parsed = [] for ast, isCSSRule in cls._getCSSObjects(ast): if isCSSRule: text = cls._serializeCSSRule(ast, indent) else: text = cls._serializeComments(ast) if text: parsed.append(text) return os.linesep.join(parsed)