Commits

cthedot committed fef89c7

improved CSSUnknown serializing and refactored CSSStyleDeclaration

Comments (0)

Files changed (12)

 
     - **BUGFIX**: Fixed parsing of values like ``background: url(x.gif)0 0;`` (missing space but still valid).
 
+    - BUGFIX: Serializing CSSUnknownRules is slightly improved, blocks are correctly indentet now.
+
     - **LICENSE**: cssutils is licensed under the **LGPL v3** now (before LGPL v2.1). This should not be a problem I guess but please be aware. So the former mix of LGPL 2.1 and 3 is resolved to a single LGPL 3 license for both cssutils and the included encutils.
 
     - INTERNAL: Moved tests out of cssutils main package into a tests package parallel to cssutils.

src/cssutils/css/cssfontfacerule.py

         if isinstance(style, basestring):
             self._style = CSSStyleDeclaration(parentRule=self, cssText=style)
         else:
-            self._style.seq = style.seq
+            self._style._seq = style.seq
 
     style = property(_getStyle, _setStyle,
         doc="(DOM) The declaration-block of this rule set.")

src/cssutils/css/csspagerule.py

         else:
             # cssText would be serialized with optional preferences
             # so use seq!
-            self._style.seq = style.seq 
+            self._style._seq = style.seq 
 
     style = property(_getStyle, _setStyle,
         doc="(DOM) The declaration-block of this rule set.")

src/cssutils/css/cssstyledeclaration.py

 from cssproperties import CSS2Properties
 from property import Property
 
-class CSSStyleDeclaration(CSS2Properties, cssutils.util.Base):
+class CSSStyleDeclaration(CSS2Properties, cssutils.util.Base2):
     """
     The CSSStyleDeclaration class represents a single CSS declaration
     block. This class may be used to determine the style properties
         """
         super(CSSStyleDeclaration, self).__init__()
         self._parentRule = parentRule
-        self.seq = []
+        #self._seq = self._tempSeq()
         self.cssText = cssText
         self._readonly = readonly
 
             name = self._normalize(nameOrProperty)
         return name in self.__nnames()
     
-    
     def __iter__(self):
         """
         iterator of set Property objects with different normalized names.
             implementation of known is not really nice, any alternative?
         """
         known = ['_tokenizer', '_log', '_ttypes',
-                 'seq', 'parentRule', '_parentRule', 'cssText',
+                 '_seq', 'seq', 'parentRule', '_parentRule', 'cssText',
                  'valid', 'wellformed',
                  '_readonly']
         known.extend(CSS2Properties._properties)
         if names are set twice the last one is used (double reverse!) 
         """
         names = []
-        for x in reversed(self.seq): 
-            if isinstance(x, Property) and not x.name in names:
-                names.append(x.name)
+        for item in reversed(self.seq):
+            val = item.value
+            if isinstance(val, Property) and not val.name in names:
+                names.append(val.name)
         return reversed(names)    
 
     def __getitem__(self, CSSName):
             property = Property()
             property.cssText = tokens
             if property.wellformed:
-                seq.append(property)
+                seq.append(property, 'Property')
             else:
                 self._log.error(u'CSSStyleDeclaration: Syntax Error in Property: %s'
                                 % self._valuestr(tokens))
 
         def unexpected(expected, seq, token, tokenizer=None):
             # error, find next ; or } to omit upto next property
-
-            # ignore until ; or }
-            tokens = self._tokensupto2(tokenizer, propertyvalueendonly=True)
-            ignored = self._tokenvalue(token) + self._valuestr(tokens)
-            self._log.error(u'CSSStyleDeclaration: Unexpected token, ignoring %r.' %
+            ignored = self._tokenvalue(token) + self._valuestr(
+                                self._tokensupto2(tokenizer, propertyvalueendonly=True))
+            self._log.error(u'CSSStyleDeclaration: Unexpected token, ignoring upto %r.' %
                             ignored,token)
             # does not matter in this case
             return expected
 
         # [Property: Value;]* Property: Value?
-        newseq = []
+        newseq = self._tempSeq()
         wellformed, expected = self._parse(expected=None,
             seq=newseq, tokenizer=tokenizer,
             productions={'IDENT': ident},#, 'CHAR': char},
         # wellformed set by parse
         # post conditions
 
-        # do not check wellformed as each property             
+        # do not check wellformed as invalid things are removed anyway            
         #if wellformed: 
-        self.seq = newseq
+        self._setSeq(newseq)
 
     cssText = property(_getCssText, _setCssText,
         doc="(DOM) A parsable textual representation of the declaration\
             # all properties or all with this name    
             nname = self._normalize(name)
             properties = []
-            for x in self.seq:
-                if isinstance(x, Property) and (
-                   (bool(nname) == False) or (x.name == nname)):
-                    properties.append(x)
+            for item in self.seq:
+                val = item.value
+                if isinstance(val, Property) and (
+                   (bool(nname) == False) or (val.name == nname)):
+                    properties.append(val)
             return properties
 
     def getProperty(self, name, normalize=True):
         """
         nname = self._normalize(name)
         found = None
-        for x in reversed(self.seq):
-            if isinstance(x, Property):
-                if (normalize and nname == x.name) or name == x.literalname:
-                    if x.priority:
-                        return x 
+        for item in reversed(self.seq):
+            val = item.value
+            if isinstance(val, Property):
+                if (normalize and nname == val.name) or name == val.literalname:
+                    if val.priority:
+                        return val
                     elif not found:
-                        found = x
+                        found = val
         return found
 
     def getPropertyCSSValue(self, name, normalize=True):
         """
         self._checkReadonly()
         r = self.getPropertyValue(name, normalize=normalize)
+        newseq = self._tempSeq()
         if normalize:
             # remove all properties with name == nname
             nname = self._normalize(name)
-            newseq = [x for x in self.seq 
-                      if not(isinstance(x, Property) and x.name == nname)]
+            for item in self.seq:
+                if not (isinstance(item.value, Property) and item.value.name == nname):
+                    newseq.appendItem(item)
         else:
             # remove all properties with literalname == name
-            newseq = [x for x in self.seq 
-                      if not(isinstance(x, Property) and x.literalname == name)]
-        self.seq = newseq
+            for item in self.seq:
+                if not (isinstance(item.value, Property) and item.value.literalname == name):
+                    newseq.appendItem(item)
+        self._setSeq(newseq)
         return r
 
     def setProperty(self, name, value=None, priority=u'', normalize=True):
                     property.priority = newp.priority
                     break
             else:
-                self.seq.append(newp)
+                self.seq._readonly = False
+                self.seq.append(newp, 'Property')
+                self.seq._readonly = True
 
     def item(self, index):
         """

src/cssutils/css/cssstylerule.py

             self._style.cssText = style
         else:
             # cssText would be serialized with optional preferences
-            # so use seq!
-            self._style.seq = style.seq 
+            # so use _seq!
+            self._style._seq = style._seq 
 
     style = property(lambda self: self._style, _setStyle,
         doc="(DOM) The declaration-block of this rule set.")

src/cssutils/serialize.py

             # remove trailing S
             del self.out[-1]
     
-    def append(self, val, typ=None, space=True, keepS=False, indent=False):
+    def append(self, val, typ=None, space=True, keepS=False, indent=False, 
+               lineSeparator=False):
         """
         Appends val. Adds a single S after each token except as follows:
         
         - typ COMMENT
             uses cssText depending on self.ser.prefs.keepComments
-        - typ cssutils.css.CSSRule.UNKNOWN_RULE
+        - typ "Property", cssutils.css.CSSRule.UNKNOWN_RULE
             uses cssText
         - typ STRING
             escapes ser._string
                     val = val.cssText
                 else: 
                     return
-            elif cssutils.css.CSSRule.UNKNOWN_RULE == typ:
+            elif typ in ('Property', cssutils.css.CSSRule.UNKNOWN_RULE):
                 val = val.cssText
             elif 'S' == typ and not keepS:
                 return
                 self.out.append(self.ser._indentblock(val, self.ser._level+1))
             else:
                 self.out.append(val)
-
             # POST
-            if val in u'+>~': # enclose selector combinator
+            if lineSeparator:
+                # Property , ...
+                pass
+            elif val in u'+>~': # enclose selector combinator
                 self.out.insert(-1, self.ser.prefs.selectorCombinatorSpacer)
                 self.out.append(self.ser.prefs.selectorCombinatorSpacer)
             elif u',' == val: # list
         """
         serializes CSSComment which consists only of commentText
         """
-        # no need to use Out() as too simple
         if rule._cssText and self.prefs.keepComments:
             return rule._cssText
         else:
         always @charset "encoding";
         no comments or other things allowed!
         """
-        # no need to use Out() as too simple
         if rule.wellformed:
             return u'@charset %s;' % self._string(rule.encoding)
         else:
             stacks = []
             for item in rule.seq:
                 typ, val = item.type, item.value
-                
                 # PRE
                 if u'}' == val:
                     # close last open item on stack
                         val = self._indentblock(
                                stackblock + self.prefs.lineSeparator + val, 
                                min(1, len(stacks)+1))
+                    else:
+                        val = self._indentblock(val, min(1, len(stacks)+1))
                 # APPEND
                 if stacks:
                     stacks[-1].append(val, typ)
         """
         Style declaration of CSSStyleRule
         """
-        # TODO: use Out()
+#        # TODO: use Out()
         
-        # may be comments only
+        # may be comments only       
         if len(style.seq) > 0:
             if separator is None:
                 separator = self.prefs.lineSeparator
 
             if self.prefs.keepAllProperties:
                 # all
-                parts = style.seq
+                seq = style.seq
             else:
                 # only effective ones
                 _effective = style.getProperties()
-                parts = [x for x in style.seq 
-                         if (isinstance(x, cssutils.css.Property) 
-                             and x in _effective)
-                         or not isinstance(x, cssutils.css.Property)]
+                seq = [item for item in style.seq 
+                         if (isinstance(item.value, cssutils.css.Property) 
+                             and item.value in _effective)
+                         or not isinstance(item.value, cssutils.css.Property)]
 
             out = []
-            for i, part in enumerate(parts):
-                if isinstance(part, cssutils.css.CSSComment):
+            for i, item in enumerate(seq):
+                typ, val = item.type, item.value
+                if isinstance(val, cssutils.css.CSSComment):
                     # CSSComment
                     if self.prefs.keepComments:
-                        out.append(part.cssText)
+                        out.append(val.cssText)
                         out.append(separator)
-                elif isinstance(part, cssutils.css.Property):
+                elif isinstance(val, cssutils.css.Property):
                     # PropertySimilarNameList
-                    out.append(self.do_Property(part))
-                    if not (self.prefs.omitLastSemicolon and i==len(parts)-1):
+                    out.append(self.do_Property(val))
+                    if not (self.prefs.omitLastSemicolon and i==len(seq)-1):
                         out.append(u';')
                     out.append(separator)
-                elif isinstance(part, cssutils.css.CSSUnknownRule):
+                elif isinstance(val, cssutils.css.CSSUnknownRule):
                     # @rule
-                    out.append(part.cssText)
+                    out.append(val.cssText)
                     out.append(separator)
                 else:
                     # ?
-                    out.append(part)
+                    out.append(val)
                     out.append(separator)
 
             if out and out[-1] == separator:

src/cssutils/stylesheets/stylesheet.py

 import urlparse
 import cssutils
 
-class StyleSheet(cssutils.util.Base):
+class StyleSheet(cssutils.util.Base2):
     """
     The StyleSheet interface is the abstract base interface
     for any type of style sheet. It represents a single style

src/cssutils/util.py

         else:
             self._seq.append(Item(val, typ, line, col))
 
+    def appendItem(self, item):
+        "if not readonly add item which must be an Item"
+        if self._readonly:
+            raise AttributeError('Seq is readonly.')
+        else:
+            self._seq.append(item)
+
     def replace(self, index=-1, val=None, typ=None, line=None, col=None):
         """
         if not readonly replace Item at index with new Item or

src/tests/test_cssmediarule.py

         color: green
         }
     }''',
-            u'@media all { @x{}}': u'@media all {\n    @x {\n    }\n    }',
+            u'@media all { @x{}}': u'@media all {\n    @x {\n        }\n    }',
             u'@media all "n" /**/ { @x{}}': 
-                u'@media all "n" /**/ {\n    @x {\n    }\n    }',
+                u'@media all "n" /**/ {\n    @x {\n        }\n    }',
             u'@mediaall"n"/**/{@x{}}': 
-                u'@media all "n" /**/ {\n    @x {\n    }\n    }',
+                u'@media all "n" /**/ {\n    @x {\n        }\n    }',
             # comments
             u'@media/*1*//*2*/all/*3*//*4*/{/*5*/a{x:1}}': 
                 u'@media /*1*/ /*2*/ all /*3*/ /*4*/ {\n    /*5*/\n    a {\n        x: 1\n        }\n    }',

src/tests/test_cssstyledeclaration.py

             ur'$: 0': u'', # really invalid!
             # unknown rule but valid
             u'@x;\ncolor: red': None, 
-            u'@x {\n}\ncolor: red': None,
+            u'@x {\n    }\ncolor: red': None,
             u'/**/\ncolor: red': None, 
             u'/**/\ncolor: red;\n/**/': None, 
             }

src/tests/test_cssunknownrule.py

         "CSSUnknownRule.cssText"
         tests = {
             '@x;': None,
-            '@x {}': u'@x {\n}',
-            '@x{ \n \t \f\r}': u'@x {\n}',
-            '@x {\n    [()]([ {\n    }]) {\n    }\n    }': None,
+            '@x {}': u'@x {\n    }',
+            '@x{ \n \t \f\r}': u'@x {\n    }',
+            '@x {\n    [()]([ {\n        }]) {\n        }\n    }': None,
             '@x {\n    @b;\n    }': None,
             '''@x {
     @b {
     sys.exit(0)
 
 if 1:
-    st = cssutils.css.CSSStyleDeclaration()
-    st.color = 'red'
-    st['item'] = "123", "important"
-    for p in st.getProperties():
-        print st.__getattribute__(p.name)
-    print 
-    for p in st:
-        print repr(p)
-        
-    print st['notset']
+    st = cssutils.css.CSSStyleDeclaration(cssText="left: 0;left:1")
+    cssutils.ser.prefs.keepAllProperties = False
+    print st.cssText
     sys.exit(0)
 
 
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.