Package cssutils :: Package css :: Module cssimportrule
[hide private]
[frames] | no frames]

Source Code for Module cssutils.css.cssimportrule

  1  """CSSImportRule implements DOM Level 2 CSS CSSImportRule. 
  2   
  3  plus: 
  4   
  5  ``name`` property 
  6      http://www.w3.org/TR/css3-cascade/#cascading 
  7   
  8  """ 
  9  __all__ = ['CSSImportRule'] 
 10  __docformat__ = 'restructuredtext' 
 11  __version__ = '$Id: cssimportrule.py 1401 2008-07-29 21:07:54Z cthedot $' 
 12   
 13  import os 
 14  import urllib 
 15  import urlparse 
 16  import xml.dom 
 17  import cssrule 
 18  import cssutils 
 19   
20 -class CSSImportRule(cssrule.CSSRule):
21 """ 22 Represents an @import rule within a CSS style sheet. The @import rule 23 is used to import style rules from other style sheets. 24 25 Properties 26 ========== 27 atkeyword: (cssutils only) 28 the literal keyword used 29 cssText: of type DOMString 30 The parsable textual representation of this rule 31 href: of type DOMString, (DOM readonly, cssutils also writable) 32 The location of the style sheet to be imported. The attribute will 33 not contain the url(...) specifier around the URI. 34 hreftype: 'uri' (serializer default) or 'string' (cssutils only) 35 The original type of href, not really relevant as it may be 36 reconfigured in the serializer but it is kept anyway 37 media: of type stylesheets::MediaList (DOM readonly) 38 A list of media types for this rule of type MediaList. 39 name: 40 An optional name used for cascading 41 styleSheet: of type CSSStyleSheet (DOM readonly) 42 The style sheet referred to by this rule. The value of this 43 attribute is None if the style sheet has not yet been loaded or if 44 it will not be loaded (e.g. if the stylesheet is for a media type 45 not supported by the user agent). 46 47 Inherits properties from CSSRule 48 49 Format 50 ====== 51 import 52 : IMPORT_SYM S* 53 [STRING|URI] S* [ medium [ COMMA S* medium]* ]? S* STRING? S* ';' S* 54 ; 55 """ 56 type = property(lambda self: cssrule.CSSRule.IMPORT_RULE) 57
58 - def __init__(self, href=None, mediaText=u'all', name=None, 59 parentRule=None, parentStyleSheet=None, readonly=False):
60 """ 61 if readonly allows setting of properties in constructor only 62 63 Do not use as positional but as keyword attributes only! 64 65 href 66 location of the style sheet to be imported. 67 mediaText 68 A list of media types for which this style sheet may be used 69 as a string 70 """ 71 super(CSSImportRule, self).__init__(parentRule=parentRule, 72 parentStyleSheet=parentStyleSheet) 73 self._atkeyword = u'@import' 74 self.hreftype = None 75 self._styleSheet = None 76 77 self._href = None 78 self.href = href 79 80 self._media = cssutils.stylesheets.MediaList() 81 if mediaText: 82 self._media.mediaText = mediaText 83 84 self._name = name 85 86 seq = self._tempSeq() 87 seq.append(self.href, 'href') 88 seq.append(self.media, 'media') 89 seq.append(self.name, 'name') 90 self._setSeq(seq) 91 self._readonly = readonly
92 93 _usemedia = property(lambda self: self.media.mediaText not in (u'', u'all'), 94 doc="if self._media is used (or simply empty)") 95
96 - def _getCssText(self):
97 """ 98 returns serialized property cssText 99 """ 100 return cssutils.ser.do_CSSImportRule(self)
101
102 - def _setCssText(self, cssText):
103 """ 104 DOMException on setting 105 106 - HIERARCHY_REQUEST_ERR: (CSSStylesheet) 107 Raised if the rule cannot be inserted at this point in the 108 style sheet. 109 - INVALID_MODIFICATION_ERR: (self) 110 Raised if the specified CSS string value represents a different 111 type of rule than the current one. 112 - NO_MODIFICATION_ALLOWED_ERR: (CSSRule) 113 Raised if the rule is readonly. 114 - SYNTAX_ERR: (self) 115 Raised if the specified CSS string value has a syntax error and 116 is unparsable. 117 """ 118 super(CSSImportRule, self)._setCssText(cssText) 119 tokenizer = self._tokenize2(cssText) 120 attoken = self._nexttoken(tokenizer, None) 121 if self._type(attoken) != self._prods.IMPORT_SYM: 122 self._log.error(u'CSSImportRule: No CSSImportRule found: %s' % 123 self._valuestr(cssText), 124 error=xml.dom.InvalidModificationErr) 125 else: 126 # for closures: must be a mutable 127 new = {'keyword': self._tokenvalue(attoken), 128 'href': None, 129 'hreftype': None, 130 'media': None, 131 'name': None, 132 'wellformed': True 133 } 134 135 def __doname(seq, token): 136 # called by _string or _ident 137 new['name'] = self._stringtokenvalue(token) 138 seq.append(new['name'], 'name') 139 return ';'
140 141 def _string(expected, seq, token, tokenizer=None): 142 if 'href' == expected: 143 # href 144 new['href'] = self._stringtokenvalue(token) 145 new['hreftype'] = 'string' 146 seq.append(new['href'], 'href') 147 return 'media name ;' 148 elif 'name' in expected: 149 # name 150 return __doname(seq, token) 151 else: 152 new['wellformed'] = False 153 self._log.error( 154 u'CSSImportRule: Unexpected string.', token) 155 return expected
156 157 def _uri(expected, seq, token, tokenizer=None): 158 # href 159 if 'href' == expected: 160 uri = self._uritokenvalue(token) 161 new['hreftype'] = 'uri' 162 new['href'] = uri 163 seq.append(new['href'], 'href') 164 return 'media name ;' 165 else: 166 new['wellformed'] = False 167 self._log.error( 168 u'CSSImportRule: Unexpected URI.', token) 169 return expected 170 171 def _ident(expected, seq, token, tokenizer=None): 172 # medialist ending with ; which is checked upon too 173 if expected.startswith('media'): 174 mediatokens = self._tokensupto2( 175 tokenizer, importmediaqueryendonly=True) 176 mediatokens.insert(0, token) # push found token 177 178 last = mediatokens.pop() # retrieve ; 179 lastval, lasttyp = self._tokenvalue(last), self._type(last) 180 if lastval != u';' and lasttyp not in ('EOF', self._prods.STRING): 181 new['wellformed'] = False 182 self._log.error(u'CSSImportRule: No ";" found: %s' % 183 self._valuestr(cssText), token=token) 184 185 media = cssutils.stylesheets.MediaList() 186 media.mediaText = mediatokens 187 if media.wellformed: 188 new['media'] = media 189 seq.append(media, 'media') 190 else: 191 new['wellformed'] = False 192 self._log.error(u'CSSImportRule: Invalid MediaList: %s' % 193 self._valuestr(cssText), token=token) 194 195 if lasttyp == self._prods.STRING: 196 # name 197 return __doname(seq, last) 198 else: 199 return 'EOF' # ';' is token "last" 200 else: 201 new['wellformed'] = False 202 self._log.error( 203 u'CSSImportRule: Unexpected ident.', token) 204 return expected 205 206 def _char(expected, seq, token, tokenizer=None): 207 # final ; 208 val = self._tokenvalue(token) 209 if expected.endswith(';') and u';' == val: 210 return 'EOF' 211 else: 212 new['wellformed'] = False 213 self._log.error( 214 u'CSSImportRule: Unexpected char.', token) 215 return expected 216 217 # import : IMPORT_SYM S* [STRING|URI] 218 # S* [ medium [ ',' S* medium]* ]? ';' S* 219 # STRING? # see http://www.w3.org/TR/css3-cascade/#cascading 220 # ; 221 newseq = self._tempSeq() 222 wellformed, expected = self._parse(expected='href', 223 seq=newseq, tokenizer=tokenizer, 224 productions={'STRING': _string, 225 'URI': _uri, 226 'IDENT': _ident, 227 'CHAR': _char}, 228 new=new) 229 230 # wellformed set by parse 231 wellformed = wellformed and new['wellformed'] 232 233 # post conditions 234 if not new['href']: 235 wellformed = False 236 self._log.error(u'CSSImportRule: No href found: %s' % 237 self._valuestr(cssText)) 238 239 if expected != 'EOF': 240 wellformed = False 241 self._log.error(u'CSSImportRule: No ";" found: %s' % 242 self._valuestr(cssText)) 243 244 # set all 245 if wellformed: 246 self.atkeyword = new['keyword'] 247 self.hreftype = new['hreftype'] 248 if new['media']: 249 # use same object 250 self.media.mediaText = new['media'].mediaText 251 # put it in newseq too 252 for index, x in enumerate(newseq): 253 if x.type == 'media': 254 newseq.replace(index, self.media, 255 x.type, x.line, x.col) 256 break 257 else: 258 # reset media 259 self.media.mediaText = u'all' 260 newseq.append(self.media, 'media') 261 self.name = new['name'] 262 self._setSeq(newseq) 263 self.href = new['href'] 264 265 if self.styleSheet: 266 # title is set by href 267 #self.styleSheet._href = self.href 268 self.styleSheet._parentStyleSheet = self.parentStyleSheet 269 270 cssText = property(fget=_getCssText, fset=_setCssText, 271 doc="(DOM attribute) The parsable textual representation.") 272
273 - def _setHref(self, href):
274 # update seq 275 for i, item in enumerate(self.seq): 276 val, typ = item.value, item.type 277 if 'href' == typ: 278 self._seq[i] = (href, typ, item.line, item.col) 279 break 280 else: 281 seq = self._tempSeq() 282 seq.append(self.href, 'href') 283 self._setSeq(seq) 284 # set new href 285 self._href = href 286 if not self.styleSheet: 287 # set only if not set before 288 self.__setStyleSheet()
289 290 href = property(lambda self: self._href, _setHref, 291 doc="Location of the style sheet to be imported.") 292 293 media = property(lambda self: self._media, 294 doc=u"(DOM readonly) A list of media types for this rule" 295 " of type MediaList") 296
297 - def _setName(self, name):
298 """raises xml.dom.SyntaxErr if name is not a string""" 299 if isinstance(name, basestring) or name is None: 300 # "" or '' 301 if not name: 302 name = None 303 # update seq 304 for i, item in enumerate(self.seq): 305 val, typ = item.value, item.type 306 if 'name' == typ: 307 self._seq[i] = (name, typ, item.line, item.col) 308 break 309 else: 310 # append 311 seq = self._tempSeq() 312 for item in self.seq: 313 # copy current seq 314 seq.append(item.value, item.type, item.line, item.col) 315 seq.append(name, 'name') 316 self._setSeq(seq) 317 self._name = name 318 # set title of referred sheet 319 if self.styleSheet: 320 self.styleSheet.title = name 321 else: 322 self._log.error(u'CSSImportRule: Not a valid name: %s' % name)
323 324 name = property(lambda self: self._name, _setName, 325 doc=u"An optional name for the imported sheet") 326
327 - def __setStyleSheet(self):
328 """Read new CSSStyleSheet cssText from href using parentStyleSheet.href 329 330 Indirectly called if setting ``href``. In case of any error styleSheet 331 is set to ``None``. 332 """ 333 # should simply fail so all errors are catched! 334 if self.parentStyleSheet and self.href: 335 # relative href 336 parentHref = self.parentStyleSheet.href 337 if parentHref is None: 338 # use cwd instead 339 parentHref = u'file:' + urllib.pathname2url(os.getcwd()) + '/' 340 href = urlparse.urljoin(parentHref, self.href) 341 342 # all possible exceptions are ignored (styleSheet is None then) 343 try: 344 usedEncoding, enctype, cssText = self.parentStyleSheet._resolveImport(href) 345 if cssText is None: 346 # catched in next except below! 347 raise IOError('Cannot read Stylesheet.') 348 styleSheet = cssutils.css.CSSStyleSheet(href=href, 349 media=self.media, 350 ownerRule=self, 351 title=self.name) 352 # inherit fetcher for @imports in styleSheet 353 styleSheet._setFetcher(self.parentStyleSheet._fetcher) 354 # contentEncoding with parentStyleSheet.overrideEncoding, 355 # HTTP or parent 356 encodingOverride, encoding = None, None 357 if enctype == 0: 358 encodingOverride = usedEncoding 359 elif 5 > enctype > 0: 360 encoding = usedEncoding 361 362 styleSheet._setCssTextWithEncodingOverride(cssText, 363 encodingOverride=encodingOverride, 364 encoding=encoding) 365 366 except (OSError, IOError, ValueError), e: 367 self._log.warn(u'CSSImportRule: While processing imported style sheet href=%r: %r' 368 % (self.href, e), neverraise=True) 369 else: 370 self._styleSheet = styleSheet
371 372 styleSheet = property(lambda self: self._styleSheet, 373 doc="(readonly) The style sheet referred to by this rule.") 374
375 - def _getWellformed(self):
376 "depending if media is used at all" 377 if self._usemedia: 378 return bool(self.href and self.media.wellformed) 379 else: 380 return bool(self.href)
381 382 wellformed = property(_getWellformed) 383
384 - def __repr__(self):
385 if self._usemedia: 386 mediaText = self.media.mediaText 387 else: 388 mediaText = None 389 return "cssutils.css.%s(href=%r, mediaText=%r, name=%r)" % ( 390 self.__class__.__name__, 391 self.href, self.media.mediaText, self.name)
392
393 - def __str__(self):
394 if self._usemedia: 395 mediaText = self.media.mediaText 396 else: 397 mediaText = None 398 return "<cssutils.css.%s object href=%r mediaText=%r name=%r at 0x%x>" % ( 399 self.__class__.__name__, self.href, mediaText, self.name, id(self))
400