Inspecting CSS in Python with cssutils
For a new MyMart feature, we’re allowing our members to customise the look of parts of the site.They can choose custom colours with a palette widget. The values they give us are used to generate a CSS stylesheet which alters the rendering of certain page items.
I wanted to write test cases to ensure that the CSS is being generated correctly, so I used Christof Hoecke’s cssutils
module to parse and then inspect the CSS.
cssutils
parses a stylesheet into a hierarchy of DOM Level 2 objects. A stylesheet is typically made up of several CSSStyleRule
s which are broken down into a list of Selector
objects and a CSSStyleDeclaration
object which can be interrogated for the actual values we’re looking for.
First pull the CSS text into a variable, load it from file, enter it by hand, what ever is appropriate.
>>> pagecsstext = """div.data-key { color:#333333; }"""
Once we have the CSS in hand, parse it using cssutils
’
parseString
method.
>>> from cssutils import parseString
>>> pagecss = parseString(pagecsstext)
>>> pagecss.cssRules
[<cssutils.css.cssstylerule.CSSStyleRule object at 0x1480230>]
For the tests, I then need to search out and evaluate specific rules and values. cssutils
doesn’t make this as easy as we might like, my hope here was that I would be able to say something like pagecss.get_rule_for_selector("div.data-key")
or something similar. There are problems with this for the implementor, I might request .data-key
which should match in some situations. However, it would be nice to see a naive implementation added to the module. Here’s one I made earlier:
def get_rule_for_selector(stylesheet, selector):
for rule in stylesheet.cssRules:
if hasattr(rule, "selectorList") and selector in [s.selectorText for s in rule.selectorList]:
return rule
We can then write expressions to get to the values of the stylesheet as follows.
>>> div_data_key = get_rule_for_selector(pagecss, "div.data-key")
>>> div_data_key = div_data_key.style.getPropertyValue("color") u'#333333'
Bringing it all together, here is my first test case. The page is served by Django, so I use their Client
object to make a request.
class ShopTests(MyMartTestCase):
def test_shop_css(self):
c = Client()
r = c.get("/somebody/screen.css")
self.assertEqual(r.headers["Content-Type"], "text/css; charset=utf-8")
rcss = parseString(r.content)
tc_h2 = get_rule_for_selector(rcss, "table#content h2")
self.assertEqual(tc_h2.style.getPropertyValue("background-color"),
"#ff99cc")
self.assertEqual(tc_h2.style.getPropertyValue("color"),
"#000000")
tc_body = get_rule_for_selector(rcss, "table#content div.block-body")
self.assertEqual(tc_body.style.getPropertyValue("background-color"),
"#ffccdd")
self.assertEqual(tc_body.style.getPropertyValue("color"),
"#333333")