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