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

# Source Code for Module cssutils.css.cssstylesheet

      1  """
      2  CSSStyleSheet implements DOM Level 2 CSS CSSStyleSheet.
      3
      4  Partly also:
      5      - http://dev.w3.org/csswg/cssom/#the-cssstylesheet
      6      - http://www.w3.org/TR/2006/WD-css3-namespace-20060828/
      7
      8  TODO:
      9      - ownerRule and ownerNode
     10  """
     11  __all__ = ['CSSStyleSheet']
     12  __docformat__ = 'restructuredtext'
     13  __version__ = '$Id: cssstylesheet.py 1340 2008-07-09 20:05:20Z cthedot $'
     14
     15  import xml.dom
     16  import cssutils.stylesheets
     17  from cssutils.util import _Namespaces, _SimpleNamespaces, _readUrl
     18  from cssutils.helper import Deprecated
     19
     20 -class CSSStyleSheet(cssutils.stylesheets.StyleSheet):
     21      """
     22      The CSSStyleSheet interface represents a CSS style sheet.
     23
     24      Properties
     25      ==========
     26      CSSOM
     27      -----
     28      cssRules
     29          of type CSSRuleList, (DOM readonly)
     30      encoding
     31          reflects the encoding of an @charset rule or 'utf-8' (default)
     32          if set to ``None``
     33      ownerRule
     34          of type CSSRule, readonly. If this sheet is imported this is a ref
     35          to the @import rule that imports it.
     36
     37      Inherits properties from stylesheet.StyleSheet
     38
     39      cssutils
     40      --------
     41      cssText: string
     42          a textual representation of the stylesheet
     43      namespaces
     44          reflects set @namespace rules of this rule.
     45          A dict of {prefix: namespaceURI} mapping.
     46
     47      Format
     48      ======
     49      stylesheet
     50        : [ CHARSET_SYM S* STRING S* ';' ]?
     51          [S|CDO|CDC]* [ import [S|CDO|CDC]* ]*
     52          [ namespace [S|CDO|CDC]* ]* # according to @namespace WD
     53          [ [ ruleset | media | page ] [S|CDO|CDC]* ]*
     54      """
     55 -    def __init__(self, href=None, media=None, title=u'', disabled=None,
     56                   ownerNode=None, parentStyleSheet=None, readonly=False,
     57                   ownerRule=None):
     58          """
     59          init parameters are the same as for stylesheets.StyleSheet
     60          """
     61          super(CSSStyleSheet, self).__init__(
     62                  'text/css', href, media, title, disabled,
     63                  ownerNode, parentStyleSheet)
     64
     65          self._ownerRule = ownerRule
     66          self.cssRules = cssutils.css.CSSRuleList()
     67          self.cssRules.append = self.insertRule
     68          self.cssRules.extend = self.insertRule
     69          self._namespaces = _Namespaces(parentStyleSheet=self)
     70          self._readonly = readonly
     71
     72          # used only during setting cssText by parse*()
     73          self.__encodingOverride = None
     74          self._fetcher = None
     75
     76 -    def __iter__(self):
     77          "generator which iterates over cssRules."
     78          for rule in self.cssRules:
     79              yield rule
     80
     81 -    def _cleanNamespaces(self):
     82          "removes all namespace rules with same namespaceURI but last one set"
     83          rules = self.cssRules
     84          namespaceitems = self.namespaces.items()
     85          i = 0
     86          while i < len(rules):
     87              rule = rules[i]
     88              if rule.type == rule.NAMESPACE_RULE and \
     89                 (rule.prefix, rule.namespaceURI) not in namespaceitems:
     90                  self.deleteRule(i)
     91              else:
     92                  i += 1
     93
     94 -    def _getUsedURIs(self):
     95          "returns set of URIs used in the sheet"
     96          useduris = set()
     97          for r1 in self:
     98              if r1.STYLE_RULE == r1.type:
     99                  useduris.update(r1.selectorList._getUsedUris())
    100              elif r1.MEDIA_RULE == r1.type:
    101                  for r2 in r1:
    102                      if r2.type == r2.STYLE_RULE:
    103                          useduris.update(r2.selectorList._getUsedUris())
    104          return useduris
    105
    106 -    def _getCssText(self):
    107          return cssutils.ser.do_CSSStyleSheet(self)
    108
    109 -    def _setCssText(self, cssText):
    110          """
    111          (cssutils)
    112          Parses ``cssText`` and overwrites the whole stylesheet.
    113
    114          :param cssText:
    115              a parseable string or a tuple of (cssText, dict-of-namespaces)
    116          :Exceptions:
    117              - `NAMESPACE_ERR`:
    118                If a namespace prefix is found which is not declared.
    119              - `NO_MODIFICATION_ALLOWED_ERR`: (self)
    120                Raised if the rule is readonly.
    121              - `SYNTAX_ERR`:
    122                Raised if the specified CSS string value has a syntax error and
    123                is unparsable.
    124          """
    125          self._checkReadonly()
    126
    127          cssText, namespaces = self._splitNamespacesOff(cssText)
    128          if not namespaces:
    129              namespaces = _SimpleNamespaces()
    130
    131          tokenizer = self._tokenize2(cssText)
    132          newseq = [] #cssutils.css.CSSRuleList()
    133
    134          # for closures: must be a mutable
    135          new = {'encoding': None, # needed for setting encoding of @import rules
    136                 'namespaces': namespaces}
    137          def S(expected, seq, token, tokenizer=None):
    138              # @charset must be at absolute beginning of style sheet
    139              if expected == 0:
    140                  return 1
    141              else:
    142                  return expected
    143
    144          def COMMENT(expected, seq, token, tokenizer=None):
    145              "special: sets parent*"
    146              comment = cssutils.css.CSSComment([token],
    147                                  parentStyleSheet=self.parentStyleSheet)
    148              seq.append(comment)
    149              return expected
    150
    151          def charsetrule(expected, seq, token, tokenizer):
    152              rule = cssutils.css.CSSCharsetRule(parentStyleSheet=self)
    153              rule.cssText = self._tokensupto2(tokenizer, token)
    154              if expected > 0 or len(seq) > 0:
    155                  self._log.error(
    156                      u'CSSStylesheet: CSSCharsetRule only allowed at beginning of stylesheet.',
    157                      token, xml.dom.HierarchyRequestErr)
    158              else:
    159                  if rule.wellformed:
    160                      seq.append(rule)
    161                      new['encoding'] = rule.encoding
    162              return 1
    163
    164          def importrule(expected, seq, token, tokenizer):
    165              rule = cssutils.css.CSSImportRule(parentStyleSheet=self)
    166              #rule._parentEncoding = new['encoding'] # set temporarily
    167
    168              # set temporarily as used by _resolveImport
    169              self.__newEncoding = new['encoding']
    170
    171              rule.cssText = self._tokensupto2(tokenizer, token)
    172              if expected > 1:
    173                  self._log.error(
    174                      u'CSSStylesheet: CSSImportRule not allowed here.',
    175                      token, xml.dom.HierarchyRequestErr)
    176              else:
    177                  if rule.wellformed:
    178                      #del rule._parentEncoding # remove as later it is read from this sheet!
    179                      seq.append(rule)
    180
    181              # remove as only used temporarily
    182              del self.__newEncoding
    183
    184              return 1
    185
    186          def namespacerule(expected, seq, token, tokenizer):
    187              rule = cssutils.css.CSSNamespaceRule(
    188                                  cssText=self._tokensupto2(tokenizer, token),
    189                                  parentStyleSheet=self)
    190              if expected > 2:
    191                  self._log.error(
    192                      u'CSSStylesheet: CSSNamespaceRule not allowed here.',
    193                      token, xml.dom.HierarchyRequestErr)
    194              else:
    195                  if rule.wellformed:
    196                      seq.append(rule)
    197                      # temporary namespaces given to CSSStyleRule and @media
    198                      new['namespaces'][rule.prefix] = rule.namespaceURI
    199              return 2
    200
    201          def fontfacerule(expected, seq, token, tokenizer):
    202              rule = cssutils.css.CSSFontFaceRule(parentStyleSheet=self)
    203              rule.cssText = self._tokensupto2(tokenizer, token)
    204              if rule.wellformed:
    205                  seq.append(rule)
    206              return 3
    207
    208          def mediarule(expected, seq, token, tokenizer):
    209              rule = cssutils.css.CSSMediaRule()
    210              rule.cssText = (self._tokensupto2(tokenizer, token),
    211                              new['namespaces'])
    212              if rule.wellformed:
    213                  rule._parentStyleSheet=self
    214                  for r in rule:
    215                      r._parentStyleSheet=self
    216                  seq.append(rule)
    217              return 3
    218
    219          def pagerule(expected, seq, token, tokenizer):
    220              rule = cssutils.css.CSSPageRule(parentStyleSheet=self)
    221              rule.cssText = self._tokensupto2(tokenizer, token)
    222              if rule.wellformed:
    223                  seq.append(rule)
    224              return 3
    225
    226          def unknownrule(expected, seq, token, tokenizer):
    227              self._log.warn(
    228                      u'CSSStylesheet: Unknown @rule found.',
    229                      token, neverraise=True)
    230              rule = cssutils.css.CSSUnknownRule(parentStyleSheet=self)
    231              rule.cssText = self._tokensupto2(tokenizer, token)
    232              if rule.wellformed:
    233                  seq.append(rule)
    234              return expected
    235
    236          def ruleset(expected, seq, token, tokenizer):
    237              rule = cssutils.css.CSSStyleRule()
    238              rule.cssText = (self._tokensupto2(tokenizer, token),
    239                              new['namespaces'])
    240              if rule.wellformed:
    241                  rule._parentStyleSheet=self
    242                  seq.append(rule)
    243              return 3
    244
    245          # expected:
    246          # ['CHARSET', 'IMPORT', 'NAMESPACE', ('PAGE', 'MEDIA', ruleset)]
    247          wellformed, expected = self._parse(0, newseq, tokenizer,
    248              {'S': S,
    249               'COMMENT': COMMENT,
    250               'CDO': lambda *ignored: None,
    251               'CDC': lambda *ignored: None,
    252               'CHARSET_SYM': charsetrule,
    253               'FONT_FACE_SYM': fontfacerule,
    254               'IMPORT_SYM': importrule,
    255               'NAMESPACE_SYM': namespacerule,
    256               'PAGE_SYM': pagerule,
    257               'MEDIA_SYM': mediarule,
    258               'ATKEYWORD': unknownrule
    259               },
    260               default=ruleset)
    261
    262          if wellformed:
    263              del self.cssRules[:]
    264              for rule in newseq:
    265                  self.insertRule(rule, _clean=False)
    266              self._cleanNamespaces()
    267
    268      cssText = property(_getCssText, _setCssText,
    269              "(cssutils) a textual representation of the stylesheet")
    270
    271 -    def _setCssTextWithEncodingOverride(self, cssText, encodingOverride=None):
    272          """Set cssText but use __encodingOverride to overwrite detected
    273          encoding. This is only used by @import during setting of cssText.
    274          In all other cases __encodingOverride is None"""
    275          if encodingOverride:
    276              # encoding during @import resolve, is used again during parse!
    277              self.__encodingOverride = encodingOverride
    278
    279          self.cssText = cssText
    280
    281          if encodingOverride:
    282              # set explicit encodingOverride
    283              self.encoding = self.__encodingOverride
    284              self.__encodingOverride = None
    285
    286 -    def _resolveImport(self, url):
    287          """Read (encoding, cssText) from ``url`` for @import sheets"""
    288          try:
    289              # only available during parse of a complete sheet
    290              parentEncoding = self.__newEncoding
    291          except AttributeError:
    292              # or check if @charset explicitly set
    293              try:
    294                  # explicit cssRules[0] and not the default encoding UTF-8
    295                  # but in that case None
    296                  parentEncoding = self.cssRules[0].encoding
    297              except (IndexError, AttributeError):
    298                  parentEncoding = None
    299
    300          return _readUrl(url, fetcher=self._fetcher,
    301                          overrideEncoding=self.__encodingOverride,
    302                          parentEncoding=parentEncoding)
    303
    304 -    def _setFetcher(self, fetcher=None):
    305          """sets @import URL loader, if None the default is used"""
    306          self._fetcher = fetcher
    307
    308 -    def _setEncoding(self, encoding):
    309          """
    310          sets encoding of charset rule if present or inserts new charsetrule
    311          with given encoding. If encoding if None removes charsetrule if
    312          present.
    313          """
    314          try:
    315              rule = self.cssRules[0]
    316          except IndexError:
    317              rule = None
    318          if rule and rule.CHARSET_RULE == rule.type:
    319              if encoding:
    320                  rule.encoding = encoding
    321              else:
    322                  self.deleteRule(0)
    323          elif encoding:
    324              self.insertRule(cssutils.css.CSSCharsetRule(encoding=encoding), 0)
    325
    326 -    def _getEncoding(self):
    327          "return encoding if @charset rule if given or default of 'utf-8'"
    328          try:
    329              return self.cssRules[0].encoding
    330          except (IndexError, AttributeError):
    331              return 'utf-8'
    332
    333      encoding = property(_getEncoding, _setEncoding,
    334              "(cssutils) reflects the encoding of an @charset rule or 'UTF-8' (default) if set to ``None``")
    335
    336      namespaces = property(lambda self: self._namespaces,
    337                            doc="Namespaces used in this CSSStyleSheet.")
    338
    339 -    def add(self, rule):
    340          """
    341          Adds rule to stylesheet at appropriate position.
    342          Same as ``sheet.insertRule(rule, inOrder=True)``.
    343          """
    344          return self.insertRule(rule, index=None, inOrder=True)
    345
    346 -    def deleteRule(self, index):
    347          """
    348          Used to delete a rule from the style sheet.
    349
    350          :param index:
    351              of the rule to remove in the StyleSheet's rule list. For an
    352              index < 0 **no** INDEX_SIZE_ERR is raised but rules for
    353              normal Python lists are used. E.g. ``deleteRule(-1)`` removes
    354              the last rule in cssRules.
    355          :Exceptions:
    356              - `INDEX_SIZE_ERR`: (self)
    357                Raised if the specified index does not correspond to a rule in
    358                the style sheet's rule list.
    359              - `NAMESPACE_ERR`: (self)
    360                Raised if removing this rule would result in an invalid StyleSheet
    361              - `NO_MODIFICATION_ALLOWED_ERR`: (self)
    362                Raised if this style sheet is readonly.
    363          """
    364          self._checkReadonly()
    365
    366          try:
    367              rule = self.cssRules[index]
    368          except IndexError:
    369              raise xml.dom.IndexSizeErr(
    370                  u'CSSStyleSheet: %s is not a valid index in the rulelist of length %i' % (
    371                  index, self.cssRules.length))
    372          else:
    373              if rule.type == rule.NAMESPACE_RULE:
    374                  # check all namespacerules if used
    375                  uris = [r.namespaceURI for r in self if r.type == r.NAMESPACE_RULE]
    376                  useduris = self._getUsedURIs()
    377                  if rule.namespaceURI in useduris and\
    378                     uris.count(rule.namespaceURI) == 1:
    379                      raise xml.dom.NoModificationAllowedErr(
    380                          u'CSSStyleSheet: NamespaceURI defined in this rule is used, cannot remove.')
    381                      return
    382
    383              rule._parentStyleSheet = None # detach
    384              del self.cssRules[index] # delete from StyleSheet
    385
    386 -    def insertRule(self, rule, index=None, inOrder=False, _clean=True):
    387          """
    388          Used to insert a new rule into the style sheet. The new rule now
    389          becomes part of the cascade.
    390
    391          :Parameters:
    392              rule
    393                  a parsable DOMString, in cssutils also a CSSRule or a
    394                  CSSRuleList
    395              index
    396                  of the rule before the new rule will be inserted.
    397                  If the specified index is equal to the length of the
    398                  StyleSheet's rule collection, the rule will be added to the end
    399                  of the style sheet.
    400                  If index is not given or None rule will be appended to rule
    401                  list.
    402              inOrder
    403                  if True the rule will be put to a proper location while
    404                  ignoring index but without raising HIERARCHY_REQUEST_ERR.
    405                  The resulting index is returned nevertheless
    406          :returns: the index within the stylesheet's rule collection
    407          :Exceptions:
    408              - `HIERARCHY_REQUEST_ERR`: (self)
    409                Raised if the rule cannot be inserted at the specified index
    410                e.g. if an @import rule is inserted after a standard rule set
    411                or other at-rule.
    412              - `INDEX_SIZE_ERR`: (self)
    413                Raised if the specified index is not a valid insertion point.
    414              - `NO_MODIFICATION_ALLOWED_ERR`: (self)
    415                Raised if this style sheet is readonly.
    416              - `SYNTAX_ERR`: (rule)
    417                Raised if the specified rule has a syntax error and is
    418                unparsable.
    419          """
    420          self._checkReadonly()
    421
    422          # check position
    423          if index is None:
    424              index = len(self.cssRules)
    425          elif index < 0 or index > self.cssRules.length:
    426              raise xml.dom.IndexSizeErr(
    427                  u'CSSStyleSheet: Invalid index %s for CSSRuleList with a length of %s.' % (
    428                      index, self.cssRules.length))
    429              return
    430
    431          if isinstance(rule, basestring):
    432              # init a temp sheet which has the same properties as self
    433              tempsheet = CSSStyleSheet(href=self.href,
    434                                        media=self.media,
    435                                        title=self.title,
    436                                        parentStyleSheet=self.parentStyleSheet,
    437                                        ownerRule=self.ownerRule)
    438              tempsheet._ownerNode = self.ownerNode
    439              tempsheet._fetcher = self._fetcher
    440
    441              # prepend encoding if in this sheet to be able to use it in
    442              # @import rules encoding resolution
    443              # do not add if new rule startswith "@charset" (which is exact!)
    444              if not rule.startswith(u'@charset') and (self.cssRules and
    445                  self.cssRules[0].type == self.cssRules[0].CHARSET_RULE):
    446                  # rule 0 is @charset!
    447                  newrulescount, newruleindex = 2, 1
    448                  rule = self.cssRules[0].cssText + rule
    449              else:
    450                  newrulescount, newruleindex = 1, 0
    451
    452              # parse the new rule(s)
    453              tempsheet.cssText = (rule, self._namespaces)
    454
    455              if len(tempsheet.cssRules) != newrulescount or (not isinstance(
    456                 tempsheet.cssRules[newruleindex], cssutils.css.CSSRule)):
    457                  self._log.error(u'CSSStyleSheet: Not a CSSRule: %s' % rule)
    458                  return
    459              rule = tempsheet.cssRules[newruleindex]
    460              rule._parentStyleSheet = None # done later?
    461
    462              # TODO:
    463              #tempsheet._namespaces = self._namespaces
    464
    465
    466          elif isinstance(rule, cssutils.css.CSSRuleList):
    467              # insert all rules
    468              for i, r in enumerate(rule):
    469                  self.insertRule(r, index + i)
    470              return index
    471
    472          if not rule.wellformed:
    473              self._log.error(u'CSSStyleSheet: Invalid rules cannot be added.')
    474              return
    475
    476          # CHECK HIERARCHY
    477          # @charset
    478          if rule.type == rule.CHARSET_RULE:
    479              if inOrder:
    480                  index = 0
    481                  # always first and only
    482                  if (self.cssRules and self.cssRules[0].type == rule.CHARSET_RULE):
    483                      self.cssRules[0].encoding = rule.encoding
    484                  else:
    485                      self.cssRules.insert(0, rule)
    486              elif index != 0 or (self.cssRules and
    487                                self.cssRules[0].type == rule.CHARSET_RULE):
    488                  self._log.error(
    489                      u'CSSStylesheet: @charset only allowed once at the beginning of a stylesheet.',
    490                      error=xml.dom.HierarchyRequestErr)
    491                  return
    492              else:
    493                  self.cssRules.insert(index, rule)
    494
    495          # @unknown or comment
    496          elif rule.type in (rule.UNKNOWN_RULE, rule.COMMENT) and not inOrder:
    497              if index == 0 and self.cssRules and\
    498                 self.cssRules[0].type == rule.CHARSET_RULE:
    499                  self._log.error(
    500                      u'CSSStylesheet: @charset must be the first rule.',
    501                      error=xml.dom.HierarchyRequestErr)
    502                  return
    503              else:
    504                  self.cssRules.insert(index, rule)
    505
    506          # @import
    507          elif rule.type == rule.IMPORT_RULE:
    508              if inOrder:
    509                  # automatic order
    510                  if rule.type in (r.type for r in self):
    511                      # find last of this type
    512                      for i, r in enumerate(reversed(self.cssRules)):
    513                          if r.type == rule.type:
    514                              index = len(self.cssRules) - i
    515                              break
    516                  else:
    517                      # find first point to insert
    518                      if self.cssRules and self.cssRules[0].type in (rule.CHARSET_RULE,
    519                                                                     rule.COMMENT):
    520                          index = 1
    521                      else:
    522                          index = 0
    523              else:
    524                  # after @charset
    525                  if index == 0 and self.cssRules and\
    526                     self.cssRules[0].type == rule.CHARSET_RULE:
    527                      self._log.error(
    528                          u'CSSStylesheet: Found @charset at index 0.',
    529                          error=xml.dom.HierarchyRequestErr)
    530                      return
    531                  # before @namespace, @page, @font-face, @media and stylerule
    532                  for r in self.cssRules[:index]:
    533                      if r.type in (r.NAMESPACE_RULE, r.MEDIA_RULE, r.PAGE_RULE,
    534                                    r.STYLE_RULE, r.FONT_FACE_RULE):
    535                          self._log.error(
    536                              u'CSSStylesheet: Cannot insert @import here, found @namespace, @media, @page or CSSStyleRule before index %s.' %
    537                              index,
    538                              error=xml.dom.HierarchyRequestErr)
    539                          return
    540              self.cssRules.insert(index, rule)
    541
    542          # @namespace
    543          elif rule.type == rule.NAMESPACE_RULE:
    544              if inOrder:
    545                  if rule.type in (r.type for r in self):
    546                      # find last of this type
    547                      for i, r in enumerate(reversed(self.cssRules)):
    548                          if r.type == rule.type:
    549                              index = len(self.cssRules) - i
    550                              break
    551                  else:
    552                      # find first point to insert
    553                      for i, r in enumerate(self.cssRules):
    554                          if r.type in (r.MEDIA_RULE, r.PAGE_RULE, r.STYLE_RULE,
    555                                        r.FONT_FACE_RULE, r.UNKNOWN_RULE, r.COMMENT):
    556                              index = i # before these
    557                              break
    558              else:
    559                  # after @charset and @import
    560                  for r in self.cssRules[index:]:
    561                      if r.type in (r.CHARSET_RULE, r.IMPORT_RULE):
    562                          self._log.error(
    563                              u'CSSStylesheet: Cannot insert @namespace here, found @charset or @import after index %s.' %
    564                              index,
    565                              error=xml.dom.HierarchyRequestErr)
    566                          return
    567                  # before @media and stylerule
    568                  for r in self.cssRules[:index]:
    569                      if r.type in (r.MEDIA_RULE, r.PAGE_RULE, r.STYLE_RULE,
    570                                    r.FONT_FACE_RULE):
    571                          self._log.error(
    572                              u'CSSStylesheet: Cannot insert @namespace here, found @media, @page or CSSStyleRule before index %s.' %
    573                              index,
    574                              error=xml.dom.HierarchyRequestErr)
    575                          return
    576
    577              if not (rule.prefix in self.namespaces and
    578                 self.namespaces[rule.prefix] == rule.namespaceURI):
    579                  # no doublettes
    580                  self.cssRules.insert(index, rule)
    581                  if _clean:
    582                      self._cleanNamespaces()
    583
    584          # all other where order is not important
    585          else:
    586              if inOrder:
    587                  # simply add to end as no specific order
    588                  self.cssRules.append(rule)
    589                  index = len(self.cssRules) - 1
    590              else:
    591                  for r in self.cssRules[index:]:
    592                      if r.type in (r.CHARSET_RULE, r.IMPORT_RULE, r.NAMESPACE_RULE):
    593                          self._log.error(
    594                              u'CSSStylesheet: Cannot insert rule here, found @charset, @import or @namespace before index %s.' %
    595                              index,
    596                              error=xml.dom.HierarchyRequestErr)
    597                          return
    598                  self.cssRules.insert(index, rule)
    599
    600          # post settings, TODO: for other rules which contain @rules
    601          rule._parentStyleSheet = self
    602          if rule.MEDIA_RULE == rule.type:
    603              for r in rule:
    604                  r._parentStyleSheet = self
    605          # ?
    606          elif rule.IMPORT_RULE == rule.type:
    607              rule.href = rule.href # try to reload stylesheet
    608
    609          return index
    610
    611      ownerRule = property(lambda self: self._ownerRule,
    612                           doc="(DOM attribute) NOT IMPLEMENTED YET")
    613
    614      @Deprecated('Use cssutils.replaceUrls(sheet, replacer) instead.')
    615 -    def replaceUrls(self, replacer):
    616          """
    617          **EXPERIMENTAL**
    618
    619          Utility method to replace all ``url(urlstring)`` values in
    620          ``CSSImportRules`` and ``CSSStyleDeclaration`` objects (properties).
    621
    622          ``replacer`` must be a function which is called with a single
    623          argument ``urlstring`` which is the current value of url()
    624          excluding ``url(`` and ``)``. It still may have surrounding
    625          single or double quotes though.
    626          """
    627          cssutils.replaceUrls(self, replacer)
    628
    629 -    def setSerializer(self, cssserializer):
    630          """
    631          Sets the global Serializer used for output of all stylesheet
    632          output.
    633          """
    634          if isinstance(cssserializer, cssutils.CSSSerializer):
    635              cssutils.ser = cssserializer
    636          else:
    637              raise ValueError(u'Serializer must be an instance of cssutils.CSSSerializer.')
    638
    639 -    def setSerializerPref(self, pref, value):
    640          """
    641          Sets Preference of CSSSerializer used for output of this
    642          stylesheet. See cssutils.serialize.Preferences for possible
    643          preferences to be set.
    644          """
    645          cssutils.ser.prefs.__setattr__(pref, value)
    646
    647 -    def __repr__(self):
    648          if self.media:
    649              mediaText = self.media.mediaText
    650          else:
    651              mediaText = None
    652          return "cssutils.css.%s(href=%r, media=%r, title=%r)" % (
    653                  self.__class__.__name__,
    654                  self.href, mediaText, self.title)
    655
    656 -    def __str__(self):
    657          if self.media:
    658              mediaText = self.media.mediaText
    659          else:
    660              mediaText = None
    661          return "<cssutils.css.%s object encoding=%r href=%r "\
    662                 "media=%r title=%r namespaces=%r at 0x%x>" % (
    663                  self.__class__.__name__, self.encoding, self.href,
    664                  mediaText, self.title, self.namespaces.namespaces,
    665                  id(self))
    666