/usr/lib/python3/dist-packages/tinycss/page3.py is in python3-tinycss 0.4-1.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 | # coding: utf-8
"""
tinycss.page3
------------------
Support for CSS 3 Paged Media syntax:
http://dev.w3.org/csswg/css3-page/
Adds support for named page selectors and margin rules.
:copyright: (c) 2012 by Simon Sapin.
:license: BSD, see LICENSE for more details.
"""
from __future__ import division, unicode_literals
from .css21 import CSS21Parser, ParseError
class MarginRule(object):
"""A parsed at-rule for margin box.
.. attribute:: at_keyword
One of the 16 following strings:
* ``@top-left-corner``
* ``@top-left``
* ``@top-center``
* ``@top-right``
* ``@top-right-corner``
* ``@bottom-left-corner``
* ``@bottom-left``
* ``@bottom-center``
* ``@bottom-right``
* ``@bottom-right-corner``
* ``@left-top``
* ``@left-middle``
* ``@left-bottom``
* ``@right-top``
* ``@right-middle``
* ``@right-bottom``
.. attribute:: declarations
A list of :class:`~.css21.Declaration` objects.
.. attribute:: line
Source line where this was read.
.. attribute:: column
Source column where this was read.
"""
def __init__(self, at_keyword, declarations, line, column):
self.at_keyword = at_keyword
self.declarations = declarations
self.line = line
self.column = column
class CSSPage3Parser(CSS21Parser):
"""Extend :class:`~.css21.CSS21Parser` for `CSS 3 Paged Media`_ syntax.
.. _CSS 3 Paged Media: http://dev.w3.org/csswg/css3-page/
Compared to CSS 2.1, the ``at_rules`` and ``selector`` attributes of
:class:`~.css21.PageRule` objects are modified:
* ``at_rules`` is not always empty, it is a list of :class:`MarginRule`
objects.
* ``selector``, instead of a single string, is a tuple of the page name
and the pseudo class. Each of these may be a ``None`` or a string.
+--------------------------+------------------------+
| CSS | Parsed selectors |
+==========================+========================+
| .. code-block:: css | .. code-block:: python |
| | |
| @page {} | (None, None) |
| @page :first {} | (None, 'first') |
| @page chapter {} | ('chapter', None) |
| @page table:right {} | ('table', 'right') |
+--------------------------+------------------------+
"""
PAGE_MARGIN_AT_KEYWORDS = [
'@top-left-corner',
'@top-left',
'@top-center',
'@top-right',
'@top-right-corner',
'@bottom-left-corner',
'@bottom-left',
'@bottom-center',
'@bottom-right',
'@bottom-right-corner',
'@left-top',
'@left-middle',
'@left-bottom',
'@right-top',
'@right-middle',
'@right-bottom',
]
def parse_at_rule(self, rule, previous_rules, errors, context):
if rule.at_keyword in self.PAGE_MARGIN_AT_KEYWORDS:
if context != '@page':
raise ParseError(
rule, '{0} rule not allowed in {1}'.format(
rule.at_keyword, context))
if rule.head:
raise ParseError(
rule.head[0],
'unexpected {0} token in {1} rule header'.format(
rule.head[0].type, rule.at_keyword))
declarations, body_errors = self.parse_declaration_list(rule.body)
errors.extend(body_errors)
return MarginRule(
rule.at_keyword, declarations, rule.line, rule.column)
return super(CSSPage3Parser, self).parse_at_rule(
rule, previous_rules, errors, context)
def parse_page_selector(self, head):
"""Parse an @page selector.
:param head:
The ``head`` attribute of an unparsed :class:`AtRule`.
:returns:
A page selector. For CSS 2.1, this is 'first', 'left', 'right'
or None. 'blank' is added by GCPM.
:raises:
:class`~parsing.ParseError` on invalid selectors
"""
if not head:
return (None, None), (0, 0, 0)
if head[0].type == 'IDENT':
name = head.pop(0).value
while head and head[0].type == 'S':
head.pop(0)
if not head:
return (name, None), (1, 0, 0)
name_specificity = (1,)
else:
name = None
name_specificity = (0,)
if (len(head) == 2 and head[0].type == ':' and
head[1].type == 'IDENT'):
pseudo_class = head[1].value
specificity = {
'first': (1, 0), 'blank': (1, 0),
'left': (0, 1), 'right': (0, 1),
}.get(pseudo_class)
if specificity:
return (name, pseudo_class), (name_specificity + specificity)
raise ParseError(head[0], 'invalid @page selector')
|