The css module#
This modules provides StyleSheet, Style, Element and a some utility functions that help write css properties.
StyleSheet
represents a list of rules and conditions (nested @-rules)
from a CSS file or string source. (The CSS format is parsed by the Css language
definition in parce.lang.css
and transformed to a CSS structure by the
CssTransform
transform class.)
Style
represents a resulting list of rules, sorted on specificity, so
that by selecting rules the properties that apply in a certain situation can be
determined and read.
Element
and AbstractElement
describe elements in a HTML or
XML document, and can be used to select matching rules in a stylesheet. Element
provides a list-based helper, and AbstractElement can be inherited from to wrap
any tree structure to use with stylesheet rule selectors.
This module is used by the theme
module to provide
syntax highlighting themes based on CSS files.
Workflow:
Instantiate a StyleSheet from a file or other source. If needed, combine multiple StyleSheets using the + operator.
Filter conditions out using
filter_conditions()
, like media, supports or document.Get a Style object through the
style
property of the StyleSheet.Use a
select
method to select rules based on their selectors.Use
properties()
to combine the properties of the selected rules to get a dictionary of the CSS properties that apply.
Example:
>>> from parce.css import Element, StyleSheet
>>> style = StyleSheet.from_file("parce/themes/default.css").style
>>> e = Element(class_="comment", parent=Element(class_="parce"))
>>> style.select_element(e).properties()
{'color': [<Value text='dimgray', color=Color(r=105, g=105, b=105, a=1.0)>],
'font-family': [<Value text='serif'>], 'font-style': [<Value text='italic'>]}
- class Atrule(keyword, contents, block)#
Bases:
tuple
An at-rule. For nested atrules the nested stylesheet is in a list
block
, for other at-rules that end with a rule with properties, the properties dict is inblock
; when there is no block,block
is None.- block#
The block between
{
…}
.
- contents#
The tokens between de keyword and the block.
- keyword#
The identifier directly after the
@
.
- class Rule(prelude, properties)#
Bases:
tuple
A normal rule
- prelude#
The list of selector lists, see
Css.prelude()
.
- properties#
The dictionary of Css properties.
- class Condition(keyword, node, style)#
Bases:
tuple
A conditional at-rule
- keyword#
The keyword after the
@
.
- node#
The contents after the keyword and before the block, or the query after the filename of an
@import
rule.
- class Color(r, g, b, a)#
Bases:
tuple
A named tuple holding the (r, g, b, a) value of a color.
- a#
The opacity, float in the range 0..1.
- b#
The blue value, integer in the range 0..255.
- g#
The green value, integer in the range 0..255.
- r#
The red value, integer in the range 0..255.
- class StyleSheet(rules=None, filename='')[source]#
Bases:
object
Represents a list of style rules and conditions.
Normal CSS rules are translated into a Rule tuple, nested rules such as @media, @document and @supports are translated into Condition tuples, and other @-rules are put in Atrule tuples.
A Rule consists of
selectors
andproperties
. Theselectors
are the tokens in a rule before the {. Theproperties
is a dict mapping css property names to the list of tokens representing their value.A Condition consists of
keyword
,node
andstyle
; thenode
is Css.atrule context containing all text from the @ upto the opening {. Thestyle
is another StyleSheet object representing the nested style sheet.An Atrule tuple consists of
keyword
andnode
, where the node is the Css.atrule context.You can combine stylesheets from different files or sources using the + operator.
The
style
property returns the Style object representing all combined rules, and allowing further queries. Theat
property returns an Atrules instance containing the atrules that do not belong to the nested at-rules.- filename = ''#
our filename, if we were loaded from a file
- classmethod load_from_file(filename)[source]#
Return a CSS structure from filename, handling the encoding.
- classmethod from_file(filename, path=None, allow_import=True)[source]#
Return a new StyleSheet adding Rules and Conditions from a local filename.
The
path
argument is currently unused. Ifallow_import
is False, the @import atrule is ignored.
- classmethod from_text(text, filename='', path=None, allow_import=True)[source]#
Return a new StyleSheet adding Rules and Conditions from a string.
The
filename
argument is used to handle @import rules correctly. Thepath
argument is currently unused. Ifallow_import
is False, the @import atrule is ignored.
- classmethod from_data(data, filename='', path=None, allow_import=True)[source]#
Return a new StyleSheet adding Rules and Conditions from a bytes string.
The
filename
argument is used to handle @import rules correctly. Thepath
argument is currently unused. Ifallow_import
is False, the @import atrule is ignored.
- classmethod from_css(css, filename='', path=None, allow_import=True)[source]#
Return a new StyleSheet adding Rules and Conditions from a CSS structure.
The
filename
argument is used to handle @import rules correctly. Thepath
argument is currently unused. Ifallow_import
is False, the @import atrule is ignored.
- filter_conditions(keyword, predicate)[source]#
Return a new StyleSheet object where conditions are filtered out.
For Condition instances with the specified keyword, the predicate is called with the contents of the
rule
(the full Atrule) of each Condition, and if the return value doesn’t evaluate to True, the Condition is removed from the resulting set. Conditions with other keywords are kept.Currently (CSS3), Conditions have the “media”, “supports” or “document” keyword. @import rules that have a media query after the filename are also stored as a Condition.
For example, this is a crude way to only get the @media rules for “screen”:
filter_conditions("media", lambda rule: "screen" in rule.contents)
Of course, a better parser for @media expressions could be written :-)
- filenames()[source]#
Return a list of filenames the currently selected rules depend on.
Our own filename will be the first in the list, and filenames of
@import
-ed rules that are still selected are appended to the list.
- property style#
Return a Style object with the remaining rules.
All rules that still are behind a condition, are let through. The rules are sorted on specificity.
- property at#
Return an Atrules object containing the remaining at-rules.
All rules that still are behind a condition, are let through.
- class Style(rules)[source]#
Bases:
object
Represents the list of rules created by the StyleSheet object.
All
select
-methods/properties return a new Style object with the narrowed-down selection of rules.Use
properties()
to get the dictionary of combined properties that apply to the selected rules.
- class Atrules(rules)[source]#
Bases:
object
Represents the @rules that are not nested, e.g. @page etc.
- class AbstractElement[source]#
Bases:
object
Base implementation for an Element object that Style uses for matching.
You may reimplement this to wrap any tree structure you want to use with the css module. You should then implement:
__init__()
get_name()
get_parent()
get_attributes()
get_pseudo_classes()
(if needed)get_pseudo_elements()
(if needed)children()
get_child_count()
previous_siblings()
next_siblings()
If you wrap other objects, be sure to reimplement
__eq__
and__ne__
, to compare those objects and not the wrappers, which may be recreated each time.
- class Element(name='', parent=None, pseudo_classes=None, pseudo_elements=None, **attrs)[source]#
Bases:
AbstractElement
,list
Mimic an Element CSS selector rules are matched with.
Use “class_” when specifying the class with a keyword argument. You can also manipulate the attributes after instantiating.
- class LxmlElement(element)[source]#
Bases:
AbstractElement
An Element wrapping an element from a lxml.etree tree.
- class CssTransform[source]#
Bases:
Transform
Transform a CSS stylesheet into a simpler data structure.
The data structure created by this Transform only contains plain Python strings, lists, (named) tuples, dictionaries and
Value
objects.Value
represents any item from a property value list. Most notably, a CSS color (hexadecimal, named or via the CSSrgb()
/rgba()
functions) is converted to a namedColor
four-tuple.A tree created by the Css.root lexicon becomes a list of tuples that are either a Rule or an Atrule named tuple.
An
Atrule
named tuple corresponds to an @-rule and consists of three items, thekeyword
which contains the name, thecontents
, which contains all items after the name, and theblock
which contains the part between { and }.There are three at-rule types:
Nested at-rule: the
keyword
is either"media"
,"supports"
or"document"
, thecontents
contains the query strings and Value instances; theblock
contains the list of nested Rule/Atrule tuples.At-rules with a properties block, like
@page:left { ... }
: the keyword can be anything, the block is a dictionary of properties like theproperties
dictionary of a normal Rule (see below). Thecontents
contains the stuff between the block and the initial keyword.At-rules without a block; like
@import url("filename.css");
, theblock
is None for these at-rules.
A
Rule
named tuple corresponds to a normal CSS rule and consists of two items, theprelude
, which contains the selectors, and theproperties
dictionary.The prelude is a list of selector groups. Each selector group is also a list, containing at least one selector dictionary and optionally operator strings and more selector dictionaries. See the
prelude()
method.The properties is a dictionary mapping property names to lists of
Value
instances. A Value can express any CSS property value, like a quoted string, unquoted name, number with or without unit, url, etc. It also recognizes named, rgb/rgba and hexadecimal colors, which can be found as aColor
tuple in theValue.color
attribute. It does not yet parsecalc()
function calls.For example:
>>> from parce import root >>> from parce.transform import transform_tree >>> from parce.lang.css import Css >>> from parce.css import CssTransform >>> transform_tree(root(Css.root, 'h1 { color: red; }'), CssTransform()) [Rule(prelude=[[{'element_selector': ['h1']}]], properties={'color': [<Value text='red', color=Color(r=255, g=0, b=0, a=1.0)>]})]
- prelude(items)[source]#
Return a Css prelude.
A prelude is a list of selector lists. A Css prelude that contains a comma has more than one selector lists.
A selector list is a list of selector dictionaries with possible combinator operators in between. The operators can be:
" "
(space),">"
,"~"
,"+"
, or"||"
.Every selector is a dictionary, and inbetween are operator strings. A comma in the selector causes the prelude to contain more than one list. Every selector list consists of selector dicts with an operator or whitespace in between.
- selector(items)[source]#
Return a dictionary object.
The possible keys are: “element_selector”, “id_selector”, “class_selector”, “pseudo_class”, “pseudo_element”, “attribute_selector”.
If present, the value is a list of objects created by that context. Most objects are simple strings, but for pseudo_class it is a (name, selector_list) tuple, and for attribute_selector it is a four-tuple of the contents between the
[
and]
.“*” is ignored, ‘|’ is not yet handled.
- declaration(items)[source]#
Return a two-tuple(property, value).
The value is a list of Value instances from
common()
.
- attribute_selector(items)[source]#
Return a four-tuple representing the contents between [ and ].
The tuple: (attribute, operator, value, flag).
- pseudo_class(items)[source]#
Return a tuple(name, selector_list).
The
name
is the name of the pseudo class, the selector_list is a list of selectors like theprelude
of a rule. For pseudo classes without arguments, the selector_list is None.
- atrule_nested(items)[source]#
Return a two-tuple: the stuff before the nested block and the nested block.
- identifier(items)[source]#
Return a Value.
For a color name, returns a Value with a color, otherwise a Value with the text.
If the identifier also has a function sub-context, a Value representing a function call is returned (this is done by the
get_css_function_call()
function, which is capable of interpretingurl
,rgb
andrgba
function calls).
- comment = None#
- common(items)[source]#
Yield any values, see Css.common().
Every item is either a Value instance or a delimiting token. If an
identifier
context is followed by afunction
context, they are combined into a Value with funcname and arguments by theget_css_function_call()
method.
- get_css_function_call(name, arguments)[source]#
Return a Value for a CSS function call. Handles rgb/rgba.
- get_string(items)[source]#
Yield the parts of a string.
Called by
sqstring()
anddqstring()
.
- get_ident_token(items)[source]#
Return a two-tuple(name, action).
Combines tokens in an identifier context, (see
Css.identifier_common()
).
- get_hex_color(text)[source]#
Return a named four-tuple Color(r, g, b, a) describing color and alpha.
The
text
is a hexadecimal color without the hash, like “FA0042”. The r, g, b values are in the range 0..255, a in 0..1; 1.0 is fully opaque.
- class Value(text=None, number=None, unit=None, url=None, color=None, funcname=None, quoted=None, arguments=())[source]#
Bases:
object
Any value that can occur in a CSS property declaration.
The value of a CSS property is always a list of Value instances.
For a numerial value, the
number
attribute contains the numeric value, and thetext
attribute the textual representation as present in the CSS file. A unit (or “%
”) that was specified, is in theunit
attribute.For a color value, the color is in the
color
attribute as aColor
four-tuple. When a CSS3 named color was specified, the name of the color is in thetext
attribute, or when a hexadecimal color was specified, the hexadecimal notation is also in thetext
attribute.For a value that can either be a quoted string or an ident_token, the value is in the
text
attribute. If it originally was a quoted string, thequoted
attribute is set to True.If the value represents a URL specified via the
url()
function, the URL is in theurl
attribute.If the value represents a function call, the name of the function is in the
funcname
attribute, and the argument list in thearguments
attribute. Except for theurl()
, thergb()
andrgba()
functions, which are handled by the CssTransform class.
- calculate_specificity(prelude)[source]#
Calculate the specificity of the Css rule prelude.
Returns a three-tuple (ids, clss, elts), where ids is the number of ID selectors, clss the number of class, attribute or pseudo-class selectors, and elts the number of element or pseudo-elements.
Currently, does not handle functions like :not(), :is(), although that would not be difficult to implement.