def _ColorProd(parent, nextSor=False): return Prod( name='ColorValue', match=lambda t, v: t == 'HASH' or (t == 'FUNCTION' and normalize(v) in (u'rgb(', u'rgba(', u'hsl(', u'hsla(')) or (t == 'IDENT' and normalize(v) in ColorValue.COLORS.keys()), nextSor=nextSor, toSeq=lambda t, tokens: ('ColorValue', ColorValue(pushtoken(t, tokens), parent=parent)))
def setVariable(self, variableName, value): """Used to set a variable value within this variable declaration block. :param variableName: The name of the CSS variable. :param value: The new value of the variable, may also be a PropertyValue object. :exceptions: - :exc:`~xml.dom.SyntaxErr`: Raised if the specified value has a syntax error and is unparsable. - :exc:`~xml.dom.NoModificationAllowedErr`: Raised if this declaration is readonly or the property is readonly. """ self._checkReadonly() # check name wellformed, seq, store, unused = \ ProdParser().parse(normalize(variableName), u'variableName', Sequence(PreDef.ident())) if not wellformed: self._log.error(u'Invalid variableName: %r: %r' % (variableName, value)) else: # check value if isinstance(value, PropertyValue): v = value else: v = PropertyValue(cssText=value, parent=self) if not v.wellformed: self._log.error(u'Invalid variable value: %r: %r' % (variableName, value)) else: # update seq self.seq._readonly = False variableName = normalize(variableName) if variableName in self._vars: for i, x in enumerate(self.seq): if x.value[0] == variableName: self.seq.replace(i, [variableName, v], x.type, x.line, x.col) break else: self.seq.append([variableName, v], 'var') self.seq._readonly = True self._vars[variableName] = v
def _ColorProd(parent, nextSor=False, toStore=None): return Prod( name='ColorValue', match=lambda t, v: (t == 'HASH' and reHexcolor.match(v)) or (t == 'FUNCTION' and normalize(v) in ('rgb(', 'rgba(', 'hsl(', 'hsla(')) or (t == 'IDENT' and normalize(v) in list(ColorValue.COLORS.keys())), nextSor=nextSor, toStore=toStore, toSeq=lambda t, tokens: ('ColorValue', ColorValue(pushtoken(t, tokens), parent=parent)))
def appendMedium(self, newMedium): """Add the `newMedium` to the end of the list. If the `newMedium` is already used, it is first removed. :param newMedium: a string or a :class:`~cssutils.stylesheets.MediaQuery` :returns: Wellformedness of `newMedium`. :exceptions: - :exc:`~xml.dom.InvalidCharacterErr`: If the medium contains characters that are invalid in the underlying style language. - :exc:`~xml.dom.InvalidModificationErr`: If mediaText is "all" and a new medium is tried to be added. Exception is "handheld" which is set in any case (Opera does handle "all, handheld" special, this special case might be removed in the future). - :exc:`~xml.dom.NoModificationAllowedErr`: Raised if this list is readonly. """ newMedium = self.__prepareset(newMedium) if newMedium: mts = [normalize(item.value.mediaType) for item in self] newmt = normalize(newMedium.mediaType) self._seq._readonly = False if 'all' in mts: self._log.info( 'MediaList: Ignoring new medium %r as already specified ' '"all" (set ``mediaText`` instead).' % newMedium, error=xml.dom.InvalidModificationErr, ) elif newmt and newmt in mts: # might be empty self.deleteMedium(newmt) self._seq.append(newMedium, 'MediaQuery') else: if 'all' == newmt: self._clearSeq() self._seq.append(newMedium, 'MediaQuery') self._seq._readonly = True return True else: return False
def test_normalize(self): "helper._normalize()" tests = { 'abcdefg ABCDEFG äöü߀ AÖÜ': r'abcdefg abcdefg äöü߀ aöü', r'\ga\Ga\\\ ': r'gaga\ ', r'0123456789': r'0123456789', r'"\x"': r'"x"', # unicode escape seqs should have been done by # the tokenizer... } for test, exp in list(tests.items()): self.assertEqual(normalize(test), exp) # static too self.assertEqual(normalize(test), exp)
def _setCssText(self, cssText): self._checkReadonly() types = self._prods # rename! prods = Sequence( Prod(name='var', match=lambda t, v: t == types.FUNCTION and normalize(v) == 'var('), PreDef.ident(toStore='ident'), Sequence(PreDef.comma(), Choice(_ColorProd(self, toStore='fallback'), _DimensionProd(self, toStore='fallback'), _URIProd(self, toStore='fallback'), _ValueProd(self, toStore='fallback'), _CalcValueProd(self, toStore='fallback'), _CSSVariableProd(self, toStore='fallback'), _CSSFunctionProd(self, toStore='fallback')), minmax=lambda: (0, 1)), PreDef.funcEnd(stop=True)) # store: name of variable store = {'ident': None, 'fallback': None} ok, seq, store, unused = ProdParser().parse(cssText, 'CSSVariable', prods) self.wellformed = ok if ok: self._name = store['ident'].value try: self._fallback = store['fallback'].value except KeyError: self._fallback = None self._setSeq(seq)
def do_css_CSSVariablesDeclaration(self, variables): """Variables of CSSVariableRule.""" if len(variables.seq) > 0: out = Out(self) lastitem = len(variables.seq) - 1 for i, item in enumerate(variables.seq): type_, val = item.type, item.value if u'var' == type_: name, cssvalue = val if self.prefs.normalizedVarNames: name = normalize(name) out.append(name) out.append(u':') out.append(cssvalue.cssText) if i < lastitem or not self.prefs.omitLastSemicolon: out.append(u';') elif isinstance(val, cssutils.css.CSSComment): # CSSComment out.append(val, 'COMMENT') out.append(self.prefs.lineSeparator) else: out.append(val.cssText, type_) out.append(self.prefs.lineSeparator) return out.value().strip() else: return u''
def _setCssText(self, cssText): self._checkReadonly() prods = Sequence( # PreDef.unary(), Choice( PreDef.dimension(stop=True), PreDef.number(stop=True), PreDef.percentage(stop=True), )) ok, seq, store, unused = ProdParser().parse(cssText, 'DimensionValue', prods) self.wellformed = ok if ok: item = seq[0] sign, v, d = self.__reUnNumDim.findall(normalize(item.value))[0] if '.' in v: val = float(sign + v) else: val = int(sign + v) dim = None if d: dim = d self._sign = sign self._value = val self._dimension = dim self._type = item.type self._setSeq(seq)
def __contains__(self, variableName): """Check if a variable is in variable declaration block. :param variableName: a string """ return normalize(variableName) in self.keys()
def __contains__(self, variableName): """Check if a variable is in variable declaration block. :param variableName: a string """ return normalize(variableName) in list(self.keys())
def _setCssText(self, cssText): self._checkReadonly() prods = Sequence(#PreDef.unary(), Choice(PreDef.dimension(stop=True), PreDef.number(stop=True), PreDef.percentage(stop=True) ) ) ok, seq, store, unused = ProdParser().parse(cssText, u'DimensionValue', prods) self.wellformed = ok if ok: item = seq[0] sign, v, d = self.__reUnNumDim.findall( normalize(item.value))[0] if u'.' in v: val = float(sign + v) else: val = int(sign + v) dim = None if d: dim = d self._sign = sign self._value = val self._dimension = dim self._type = item.type self._setSeq(seq)
def _MSValueProd(parent, nextSor=False): return Prod(name=MSValue._functionName, match=lambda t, v: (#t == self._prods.FUNCTION and ( normalize(v) in (u'expression(', u'alpha(', u'blur(', u'chroma(', u'dropshadow(', u'fliph(', u'flipv(', u'glow(', u'gray(', u'invert(', u'mask(', u'shadow(', u'wave(', u'xray(') or v.startswith(u'progid:DXImageTransform.Microsoft.') ), nextSor=nextSor, toSeq=lambda t, tokens: (MSValue._functionName, MSValue(pushtoken(t, tokens ), parent=parent ) ) )
def _MSValueProd(parent, nextSor=False): return Prod( name=MSValue._functionName, match=lambda t, v: ( # t == self._prods.FUNCTION and ( normalize(v) in ( 'expression(', 'alpha(', 'blur(', 'chroma(', 'dropshadow(', 'fliph(', 'flipv(', 'glow(', 'gray(', 'invert(', 'mask(', 'shadow(', 'wave(', 'xray(', ) or v.startswith('progid:DXImageTransform.Microsoft.')), nextSor=nextSor, toSeq=lambda t, tokens: ( MSValue._functionName, MSValue(pushtoken(t, tokens), parent=parent), ), )
def _productions(self): """Return definition used for parsing.""" types = self._prods # rename! itemProd = Choice( _ColorProd(self), _DimensionProd(self), _URIProd(self), _ValueProd(self), _CalcValueProd(self), _CSSVariableProd(self), _CSSFunctionProd(self), ) funcProds = Sequence( Prod( name='FUNCTION', match=lambda t, v: t == types.FUNCTION, toSeq=lambda t, tokens: (t[0], normalize(t[1])), ), Choice( Sequence( itemProd, Sequence(PreDef.comma(optional=True), itemProd, minmax=lambda: (0, None)), PreDef.funcEnd(stop=True), ), PreDef.funcEnd(stop=True), ), ) return funcProds
def appendMedium(self, newMedium): """Add the `newMedium` to the end of the list. If the `newMedium` is already used, it is first removed. :param newMedium: a string or a :class:`~cssutils.stylesheets.MediaQuery` :returns: Wellformedness of `newMedium`. :exceptions: - :exc:`~xml.dom.InvalidCharacterErr`: If the medium contains characters that are invalid in the underlying style language. - :exc:`~xml.dom.InvalidModificationErr`: If mediaText is "all" and a new medium is tried to be added. Exception is "handheld" which is set in any case (Opera does handle "all, handheld" special, this special case might be removed in the future). - :exc:`~xml.dom.NoModificationAllowedErr`: Raised if this list is readonly. """ newMedium = self.__prepareset(newMedium) if newMedium: mts = [normalize(item.value.mediaType) for item in self] newmt = normalize(newMedium.mediaType) self._seq._readonly = False if u'all' in mts: self._log.info(u'MediaList: Ignoring new medium %r as already specified "all" (set ``mediaText`` instead).' % newMedium, error=xml.dom.InvalidModificationErr) elif newmt and newmt in mts: # might be empty self.deleteMedium(newmt) self._seq.append(newMedium, 'MediaQuery') else: if u'all' == newmt: self._clearSeq() self._seq.append(newMedium, 'MediaQuery') self._seq._readonly = True return True else: return False
def _setCssText(self, cssText): self._checkReadonly() types = self._prods # rename! _operator = Choice( Prod( name='Operator */', match=lambda t, v: v in '*/', toSeq=lambda t, tokens: (t[0], t[1]), ), Sequence( PreDef.S(), Choice( Sequence( Prod( name='Operator */', match=lambda t, v: v in '*/', toSeq=lambda t, tokens: (t[0], t[1]), ), PreDef.S(optional=True), ), Sequence( Prod( name='Operator +-', match=lambda t, v: v in '+-', toSeq=lambda t, tokens: (t[0], t[1]), ), PreDef.S(), ), PreDef.funcEnd(stop=True, mayEnd=True), ), ), ) _operant = lambda: Choice( # noqa:E731 _DimensionProd(self), _CalcValueProd(self), _CSSVariableProd(self)) prods = Sequence( Prod( name='CALC', match=lambda t, v: t == types.FUNCTION and normalize(v) == 'calc(', ), PreDef.S(optional=True), _operant(), Sequence(_operator, _operant(), minmax=lambda: (0, None)), PreDef.funcEnd(stop=True), ) # store: name of variable ok, seq, store, unused = ProdParser().parse(cssText, 'CSSCalc', prods, checkS=True) self.wellformed = ok if ok: self._setSeq(seq)
def _ColorProd(parent, nextSor=False): return Prod(name='ColorValue', match=lambda t, v: t == 'HASH' or (t == 'FUNCTION' and normalize(v) in (u'rgb(', u'rgba(', u'hsl(', u'hsla(')) or (t == 'IDENT' and normalize(v) in ColorValue.COLORS.keys() ), nextSor = nextSor, toSeq=lambda t, tokens: ('ColorValue', ColorValue( pushtoken(t, tokens), parent=parent) ) )
def _CalcValueProd(parent, nextSor=False, toStore=None): return Prod( name=CSSCalc._functionName, match=lambda t, v: t == PreDef.types.FUNCTION and normalize( v) == 'calc(', toStore=toStore, toSeq=lambda t, tokens: (CSSCalc._functionName, CSSCalc(pushtoken(t, tokens), parent=parent)), nextSor=nextSor)
def _setCssText(self, cssText): self._checkReadonly() types = self._prods # rename! _operator = Choice(Prod(name='Operator */', match=lambda t, v: v in u'*/', toSeq=lambda t, tokens: (t[0], t[1]) ), Sequence( PreDef.S(), Choice( Sequence( Prod(name='Operator */', match=lambda t, v: v in u'*/', toSeq=lambda t, tokens: (t[0], t[1]) ), PreDef.S(optional=True) ), Sequence( Prod(name='Operator +-', match=lambda t, v: v in u'+-', toSeq=lambda t, tokens: (t[0], t[1]) ), PreDef.S() ), PreDef.funcEnd(stop=True, mayEnd=True) ) ) ) _operant = lambda: Choice(_DimensionProd(self), _CSSVariableProd(self)) prods = Sequence(Prod(name='CALC', match=lambda t, v: t == types.FUNCTION and normalize(v) == u'calc(' ), PreDef.S(optional=True), _operant(), Sequence(_operator, _operant(), minmax=lambda: (0, None) ), PreDef.funcEnd(stop=True) ) # store: name of variable ok, seq, store, unused = ProdParser().parse(cssText, u'CSSCalc', prods, checkS=True) self.wellformed = ok if ok: self._setSeq(seq)
def _CalcValueProd(parent, nextSor=False, toStore=None): return Prod(name=CSSCalc._functionName, match=lambda t, v: t == PreDef.types.FUNCTION and normalize(v) == u'calc(', toStore=toStore, toSeq=lambda t, tokens: (CSSCalc._functionName, CSSCalc( pushtoken(t, tokens), parent=parent) ), nextSor=nextSor)
def deleteMedium(self, oldMedium): """Delete a medium from the list. :param oldMedium: delete this medium from the list. :exceptions: - :exc:`~xml.dom.NotFoundErr`: Raised if `oldMedium` is not in the list. - :exc:`~xml.dom.NoModificationAllowedErr`: Raised if this list is readonly. """ self._checkReadonly() oldMedium = normalize(oldMedium) for i, mq in enumerate(self): if normalize(mq.value.mediaType) == oldMedium: del self[i] break else: self._log.error(u'"%s" not in this MediaList' % oldMedium, error=xml.dom.NotFoundErr)
def deleteMedium(self, oldMedium): """Delete a medium from the list. :param oldMedium: delete this medium from the list. :exceptions: - :exc:`~xml.dom.NotFoundErr`: Raised if `oldMedium` is not in the list. - :exc:`~xml.dom.NoModificationAllowedErr`: Raised if this list is readonly. """ self._checkReadonly() oldMedium = normalize(oldMedium) for i, mq in enumerate(self): if normalize(mq.value.mediaType) == oldMedium: del self[i] break else: self._log.error('"%s" not in this MediaList' % oldMedium, error=xml.dom.NotFoundErr)
def _setMediaType(self, mediaType): """ :param mediaType: one of :attr:`MEDIA_TYPES` :exceptions: - :exc:`~xml.dom.SyntaxErr`: Raised if the specified string value has a syntax error and is unparsable. - :exc:`~xml.dom.InvalidCharacterErr`: Raised if the given mediaType is unknown. - :exc:`~xml.dom.NoModificationAllowedErr`: Raised if this media query is readonly. """ self._checkReadonly() nmediaType = normalize(mediaType) if nmediaType not in self.MEDIA_TYPES: self._log.error( 'MediaQuery: Syntax Error in media type "%s".' % mediaType, error=xml.dom.SyntaxErr, ) else: # set self._mediaType = mediaType # update seq for i, x in enumerate(self._seq): if isinstance(x.value, str): if normalize(x.value) in ('only', 'not'): continue else: # TODO: simplify! self._seq[i] = (mediaType, 'IDENT', None, None) break else: self._seq.insert(0, mediaType, 'IDENT')
def getVariableValue(self, variableName): """Used to retrieve the value of a variable if it has been explicitly set within this variable declaration block. :param variableName: The name of the variable. :returns: the value of the variable if it has been explicitly set in this variable declaration block. Returns the empty string if the variable has not been set. """ try: return self._vars[normalize(variableName)].cssText except KeyError, e: return u''
def getVariableValue(self, variableName): """Used to retrieve the value of a variable if it has been explicitly set within this variable declaration block. :param variableName: The name of the variable. :returns: the value of the variable if it has been explicitly set in this variable declaration block. Returns the empty string if the variable has not been set. """ try: return self._vars[normalize(variableName)].cssText except KeyError as e: return ''
def _setMediaType(self, mediaType): """ :param mediaType: one of :attr:`MEDIA_TYPES` :exceptions: - :exc:`~xml.dom.SyntaxErr`: Raised if the specified string value has a syntax error and is unparsable. - :exc:`~xml.dom.InvalidCharacterErr`: Raised if the given mediaType is unknown. - :exc:`~xml.dom.NoModificationAllowedErr`: Raised if this media query is readonly. """ self._checkReadonly() nmediaType = normalize(mediaType) if nmediaType not in self.MEDIA_TYPES: self._log.error( u'MediaQuery: Syntax Error in media type "%s".' % mediaType, error=xml.dom.SyntaxErr) else: # set self._mediaType = mediaType # update seq for i, x in enumerate(self._seq): if isinstance(x.value, basestring): if normalize(x.value) in (u'only', u'not'): continue else: # TODO: simplify! self._seq[i] = (mediaType, 'IDENT', None, None) break else: self._seq.insert(0, mediaType, 'IDENT')
def _setCssText(self, cssText): self._checkReadonly() types = self._prods # rename! prods = Sequence( Prod(name='var', match=lambda t, v: t == types.FUNCTION and normalize(v) == u'var('), PreDef.ident(toStore='ident'), PreDef.funcEnd(stop=True)) # store: name of variable store = {'ident': None} ok, seq, store, unused = ProdParser().parse(cssText, u'CSSVariable', prods) if ok: self._name = store['ident'].value self._setSeq(seq) self.wellformed = ok
def removeVariable(self, variableName): """Used to remove a variable if it has been explicitly set within this variable declaration block. :param variableName: The name of the variable. :returns: the value of the variable if it has been explicitly set for this variable declaration block. Returns the empty string if the variable has not been set. :exceptions: - :exc:`~xml.dom.NoModificationAllowedErr`: Raised if this declaration is readonly is readonly. """ try: r = self._vars[normalize(variableName)] except KeyError, e: return u''
def _setCssText(self, cssText): self._checkReadonly() types = self._prods # rename! prods = Sequence(Prod(name='var', match=lambda t, v: t == types.FUNCTION and normalize(v) == u'var(' ), PreDef.ident(toStore='ident'), PreDef.funcEnd(stop=True)) # store: name of variable store = {'ident': None} ok, seq, store, unused = ProdParser().parse(cssText, u'CSSVariable', prods) if ok: self._name = store['ident'].value self._setSeq(seq) self.wellformed = ok
def _setCssText(self, cssText): self._checkReadonly() prods = Sequence(PreDef.unary(), Choice(PreDef.dimension(stop=True), PreDef.number(stop=True), PreDef.percentage(stop=True) ) ) ok, seq, store, unused = ProdParser().parse(cssText, u'DimensionValue', prods) if ok: sign = val = u'' dim = type_ = None # find for item in seq: if item.value in u'+-': sign = item.value else: type_ = item.type # number + optional dim v, d = self.__reNumDim.findall( normalize(item.value))[0] if u'.' in v: val = float(sign + v) else: val = int(sign + v) if d: dim = d self._sign = sign self._value = val self._dimension = dim self._type = type_ self._setSeq(seq) self.wellformed = ok
def _setCssText(self, cssText): self._checkReadonly() types = self._prods # rename! prods = Sequence(Prod(name='var', match=lambda t, v: t == types.FUNCTION and normalize(v) == u'var(' ), PreDef.ident(toStore='ident'), Sequence(PreDef.comma(), Choice(_ColorProd(self, toStore='fallback'), _DimensionProd(self, toStore='fallback'), _URIProd(self, toStore='fallback'), _ValueProd(self, toStore='fallback'), _CalcValueProd(self, toStore='fallback'), _CSSVariableProd(self, toStore='fallback'), _CSSFunctionProd(self, toStore='fallback') ), minmax=lambda: (0, 1) ), PreDef.funcEnd(stop=True)) # store: name of variable store = {'ident': None, 'fallback': None} ok, seq, store, unused = ProdParser().parse(cssText, u'CSSVariable', prods) self.wellformed = ok if ok: self._name = store['ident'].value try: self._fallback = store['fallback'].value except KeyError: self._fallback = None self._setSeq(seq)
def _setCssText(self, cssText): self._checkReadonly() prods = Sequence( PreDef.unary(), Choice(PreDef.dimension(stop=True), PreDef.number(stop=True), PreDef.percentage(stop=True))) ok, seq, store, unused = ProdParser().parse(cssText, u'DimensionValue', prods) if ok: sign = val = u'' dim = type_ = None # find for item in seq: if item.value in u'+-': sign = item.value else: type_ = item.type # number + optional dim v, d = self.__reNumDim.findall(normalize(item.value))[0] if u'.' in v: val = float(sign + v) else: val = int(sign + v) if d: dim = d self._sign = sign self._value = val self._dimension = dim self._type = type_ self._setSeq(seq) self.wellformed = ok
def _productions(self): """Return definition used for parsing.""" types = self._prods # rename! itemProd = Choice(_ColorProd(self), _DimensionProd(self), _URIProd(self), _ValueProd(self), #_CalcValueProd(self), _CSSVariableProd(self), _CSSFunctionProd(self) ) funcProds = Sequence(Prod(name='FUNCTION', match=lambda t, v: t == types.FUNCTION, toSeq=lambda t, tokens: (t[0], normalize(t[1]))), Choice(Sequence(itemProd, Sequence(PreDef.comma(), itemProd, minmax=lambda: (0, None)), PreDef.funcEnd(stop=True)), PreDef.funcEnd(stop=True)) ) return funcProds
def _setMediaText(self, mediaText): """ :param mediaText: a single media query string, e.g. ``print and (min-width: 25cm)`` :exceptions: - :exc:`~xml.dom.SyntaxErr`: Raised if the specified string value has a syntax error and is unparsable. - :exc:`~xml.dom.InvalidCharacterErr`: Raised if the given mediaType is unknown. - :exc:`~xml.dom.NoModificationAllowedErr`: Raised if this media query is readonly. media_query : [ONLY | NOT]? S* media_type S* [ AND S* expression ]* | expression [ AND S* expression ]* ; media_type : IDENT ; expression : '(' S* media_feature S* [ ':' S* expr ]? ')' S* ; media_feature : IDENT ; """ self._checkReadonly() expression = lambda: Sequence(PreDef.char(name='expression', char=u'('), Prod(name=u'media_feature', match=lambda t, v: t == PreDef.types.IDENT ), Sequence(PreDef.char(name='colon', char=u':'), cssutils.css.value.MediaQueryValueProd(self), minmax=lambda: (0, 1) # optional ), PreDef.char(name='expression END', char=u')', stopIfNoMoreMatch=self._partof ) ) prods = Choice(Sequence(Prod(name=u'ONLY|NOT', # media_query match=lambda t, v: t == PreDef.types.IDENT and normalize(v) in (u'only', u'not'), optional=True, toStore='not simple' ), Prod(name=u'media_type', match=lambda t, v: t == PreDef.types.IDENT and normalize(v) in self.MEDIA_TYPES, stopIfNoMoreMatch=True, toStore='media_type' ), Sequence(Prod(name=u'AND', match=lambda t, v: t == PreDef.types.IDENT and normalize(v) == 'and', toStore='not simple' ), expression(), minmax=lambda: (0, None) ) ), Sequence(expression(), Sequence(Prod(name=u'AND', match=lambda t, v: t == PreDef.types.IDENT and normalize(v) == 'and' ), expression(), minmax=lambda: (0, None) ) ) ) # parse ok, seq, store, unused = ProdParser().parse(mediaText, u'MediaQuery', prods) self._wellformed = ok if ok: try: media_type = store['media_type'] except KeyError, e: pass else: if 'not simple' not in store: self.mediaType = media_type.value # TODO: filter doubles! self._setSeq(seq)
def _setCssText(self, cssText): """Setting this attribute will result in the parsing of the new value and resetting of all the properties in the declaration block including the removal or addition of properties. :exceptions: - :exc:`~xml.dom.NoModificationAllowedErr`: Raised if this declaration is readonly or a property is readonly. - :exc:`~xml.dom.SyntaxErr`: Raised if the specified CSS string value has a syntax error and is unparsable. Format:: variableset : vardeclaration [ ';' S* vardeclaration ]* ; vardeclaration : varname ':' S* term ; varname : IDENT S* ; expr : [ VARCALL | term ] [ operator [ VARCALL | term ] ]* ; """ self._checkReadonly() vardeclaration = Sequence( PreDef.ident(), PreDef.char(':', ':', toSeq=False, optional=True), #PreDef.S(toSeq=False, optional=True), Prod(name='term', match=lambda t, v: True, toSeq=lambda t, tokens: ('value', PropertyValue(itertools.chain([t], tokens), parent=self)))) prods = Sequence( vardeclaration, Sequence(PreDef.S(optional=True), PreDef.char(';', ';', toSeq=False, optional=True), PreDef.S(optional=True), vardeclaration, minmax=lambda: (0, None)), PreDef.S(optional=True), PreDef.char(';', ';', toSeq=False, optional=True)) # parse wellformed, seq, store, notused = \ ProdParser().parse(cssText, 'CSSVariableDeclaration', prods, emptyOk=True) if wellformed: newseq = self._tempSeq() newvars = {} # seq contains only name: value pairs plus comments etc nameitem = None for item in seq: if 'IDENT' == item.type: nameitem = item elif 'value' == item.type: nname = normalize(nameitem.value) if nname in newvars: # replace var with same name for i, it in enumerate(newseq): if normalize(it.value[0]) == nname: newseq.replace(i, (nameitem.value, item.value), 'var', nameitem.line, nameitem.col) else: # saved non normalized name for reserialization newseq.append((nameitem.value, item.value), 'var', nameitem.line, nameitem.col) # newseq.append((nameitem.value, item.value), # 'var', # nameitem.line, nameitem.col) newvars[nname] = item.value else: newseq.appendItem(item) self._setSeq(newseq) self._vars = newvars self.wellformed = True
:exceptions: - :exc:`~xml.dom.NoModificationAllowedErr`: Raised if this declaration is readonly is readonly. """ try: r = self._vars[normalize(variableName)] except KeyError, e: return u'' else: self.seq._readonly = False if variableName in self._vars: for i, x in enumerate(self.seq): if x.value[0] == variableName: del self.seq[i] self.seq._readonly = True del self._vars[normalize(variableName)] return r.cssText def setVariable(self, variableName, value): """Used to set a variable value within this variable declaration block. :param variableName: The name of the CSS variable. :param value: The new value of the variable, may also be a CSSValue object. :exceptions: - :exc:`~xml.dom.SyntaxErr`: Raised if the specified value has a syntax error and is unparsable.
def __setitem__(self, variableName, value): self.setVariable(normalize(variableName), value)
def __getitem__(self, variableName): """Retrieve the value of variable ``variableName`` from this declaration. """ return self.getVariableValue(normalize(variableName))
def _setCssText(self, cssText): # noqa: C901 self._checkReadonly() types = self._prods # rename! component = Choice( PreDef.unary(toSeq=lambda t, tokens: ( t[0], DimensionValue(pushtoken(t, tokens), parent=self), )), PreDef.number(toSeq=lambda t, tokens: ( t[0], DimensionValue(pushtoken(t, tokens), parent=self), )), PreDef.percentage(toSeq=lambda t, tokens: ( t[0], DimensionValue(pushtoken(t, tokens), parent=self), )), ) noalp = Sequence( Prod( name='FUNCTION', match=lambda t, v: t == types.FUNCTION and v in ('rgb(', 'hsl('), toSeq=lambda t, tokens: (t[0], normalize(t[1])), ), component, Sequence(PreDef.comma(optional=True), component, minmax=lambda: (2, 2)), PreDef.funcEnd(stop=True), ) witha = Sequence( Prod( name='FUNCTION', match=lambda t, v: t == types.FUNCTION and v in ('rgba(', 'hsla('), toSeq=lambda t, tokens: (t[0], normalize(t[1])), ), component, Sequence(PreDef.comma(optional=True), component, minmax=lambda: (3, 3)), PreDef.funcEnd(stop=True), ) namedcolor = Prod( name='Named Color', match=lambda t, v: t == 'IDENT' and (normalize(v) in list(self.COLORS.keys())), stop=True, ) prods = Choice(PreDef.hexcolor(stop=True), namedcolor, noalp, witha) ok, seq, store, unused = ProdParser().parse(cssText, self.type, prods) self.wellformed = ok if ok: t, v = seq[0].type, seq[0].value if 'IDENT' == t: rgba = self.COLORS[normalize(v)] if 'HASH' == t: if len(v) == 4: # HASH #rgb rgba = ( int(2 * v[1], 16), int(2 * v[2], 16), int(2 * v[3], 16), 1.0, ) else: # HASH #rrggbb rgba = (int(v[1:3], 16), int(v[3:5], 16), int(v[5:7], 16), 1.0) elif 'FUNCTION' == t: functiontype, raw, check = None, [], '' HSL = False for item in seq: try: type_ = item.value.type except AttributeError: # type of function, e.g. rgb( if item.type == 'FUNCTION': functiontype = item.value HSL = functiontype in ('hsl(', 'hsla(') continue # save components if type_ == Value.NUMBER: raw.append(item.value.value) check += 'N' elif type_ == Value.PERCENTAGE: if HSL: # save as percentage fraction raw.append(item.value.value / 100.0) else: # save as real value of percentage of 255 raw.append(int(255 * item.value.value / 100)) check += 'P' if HSL: # convert to rgb # h is 360 based (circle) h, s, l_ = raw[0] / 360.0, raw[1], raw[2] # ORDER h l s !!! r, g, b = colorsys.hls_to_rgb(h, l_, s) # back to 255 based rgba = [ int(round(r * 255)), int(round(g * 255)), int(round(b * 255)), ] if len(raw) > 3: rgba.append(raw[3]) else: # rgb, rgba rgba = raw if len(rgba) < 4: rgba.append(1.0) # validate checks = { 'rgb(': ('NNN', 'PPP'), 'rgba(': ('NNNN', 'PPPN'), 'hsl(': ('NPP', ), 'hsla(': ('NPPN', ), } if check not in checks[functiontype]: self._log.error('ColorValue has invalid %s) parameters: ' '%s (N=Number, P=Percentage)' % (functiontype, check)) self._colorType = t self._red, self._green, self._blue, self._alpha = tuple(rgba) self._setSeq(seq)
def __delitem__(self, variableName): return self.removeVariable(normalize(variableName))
def _setCssText(self, cssText): self._checkReadonly() types = self._prods # rename! component = Choice( PreDef.unary(toSeq=lambda t, tokens: (t[ 0], DimensionValue(pushtoken(t, tokens), parent=self))), PreDef.number(toSeq=lambda t, tokens: (t[ 0], DimensionValue(pushtoken(t, tokens), parent=self))), PreDef.percentage(toSeq=lambda t, tokens: (t[ 0], DimensionValue(pushtoken(t, tokens), parent=self)))) noalp = Sequence( Prod(name='FUNCTION', match=lambda t, v: t == types.FUNCTION and v in (u'rgb(', u'hsl('), toSeq=lambda t, tokens: (t[0], normalize(t[1]))), component, Sequence(PreDef.comma(), component, minmax=lambda: (2, 2)), PreDef.funcEnd(stop=True)) witha = Sequence( Prod(name='FUNCTION', match=lambda t, v: t == types.FUNCTION and v in (u'rgba(', u'hsla('), toSeq=lambda t, tokens: (t[0], normalize(t[1]))), component, Sequence(PreDef.comma(), component, minmax=lambda: (3, 3)), PreDef.funcEnd(stop=True)) namedcolor = Prod(name='Named Color', match=lambda t, v: t == 'IDENT' and (normalize(v) in self.COLORS.keys()), stop=True) prods = Choice(PreDef.hexcolor(stop=True), namedcolor, noalp, witha) ok, seq, store, unused = ProdParser().parse(cssText, self.type, prods) if ok: t, v = seq[0].type, seq[0].value if u'IDENT' == t: rgba = self.COLORS[normalize(v)] if u'HASH' == t: if len(v) == 4: # HASH #rgb rgba = (int(2 * v[1], 16), int(2 * v[1], 16), int(2 * v[1], 16), 1.0) else: # HASH #rrggbb rgba = (int(v[1:3], 16), int(v[3:5], 16), int(v[5:7], 16), 1.0) elif u'FUNCTION' == t: functiontype, rgba, check = None, [], u'' for item in seq: try: type_ = item.value.type except AttributeError, e: # type of function, e.g. rgb( if item.type == 'FUNCTION': functiontype = item.value continue # save components if type_ == Value.NUMBER: rgba.append(item.value.value) check += u'N' elif type_ == Value.PERCENTAGE: rgba.append(int(255 * item.value.value / 100)) check += u'P' # validate checks = { u'rgb(': ('NNN', 'PPP'), u'rgba(': ('NNNN', 'PPPN'), u'hsl(': ('NPP', ), u'hsla(': ('NPPN', ) } if check not in checks[functiontype]: self._log.error(u'ColorValue has invalid %s) parameters: ' u'%s (N=Number, P=Percentage)' % (functiontype, check)) if len(rgba) < 4: rgba.append(1.0) self._colorType = t self._red, self._green, self._blue, self._alpha = tuple(rgba) self._setSeq(seq) self.wellformed = ok
def _setCssText(self, cssText): self._checkReadonly() types = self._prods # rename! component = Choice(PreDef.unary(toSeq=lambda t, tokens: (t[0], DimensionValue(pushtoken(t, tokens), parent=self) )), PreDef.number(toSeq=lambda t, tokens: (t[0], DimensionValue(pushtoken(t, tokens), parent=self) )), PreDef.percentage(toSeq=lambda t, tokens: (t[0], DimensionValue(pushtoken(t, tokens), parent=self) )) ) noalp = Sequence(Prod(name='FUNCTION', match=lambda t, v: t == types.FUNCTION and v in (u'rgb(', u'hsl('), toSeq=lambda t, tokens: (t[0], normalize(t[1]))), component, Sequence(PreDef.comma(optional=True), component, minmax=lambda: (2, 2) ), PreDef.funcEnd(stop=True) ) witha = Sequence(Prod(name='FUNCTION', match=lambda t, v: t == types.FUNCTION and v in (u'rgba(', u'hsla('), toSeq=lambda t, tokens: (t[0], normalize(t[1])) ), component, Sequence(PreDef.comma(optional=True), component, minmax=lambda: (3, 3) ), PreDef.funcEnd(stop=True) ) namedcolor = Prod(name='Named Color', match=lambda t, v: t == 'IDENT' and ( normalize(v) in self.COLORS.keys() ), stop=True) prods = Choice(PreDef.hexcolor(stop=True), namedcolor, noalp, witha) ok, seq, store, unused = ProdParser().parse(cssText, self.type, prods) self.wellformed = ok if ok: t, v = seq[0].type, seq[0].value if u'IDENT' == t: rgba = self.COLORS[normalize(v)] if u'HASH' == t: if len(v) == 4: # HASH #rgb rgba = (int(2*v[1], 16), int(2*v[2], 16), int(2*v[3], 16), 1.0) else: # HASH #rrggbb rgba = (int(v[1:3], 16), int(v[3:5], 16), int(v[5:7], 16), 1.0) elif u'FUNCTION' == t: functiontype, raw, check = None, [], u'' HSL = False for item in seq: try: type_ = item.value.type except AttributeError, e: # type of function, e.g. rgb( if item.type == 'FUNCTION': functiontype = item.value HSL = functiontype in (u'hsl(', u'hsla(') continue # save components if type_ == Value.NUMBER: raw.append(item.value.value) check += u'N' elif type_ == Value.PERCENTAGE: if HSL: # save as percentage fraction raw.append(item.value.value / 100.0) else: # save as real value of percentage of 255 raw.append(int(255 * item.value.value / 100)) check += u'P' if HSL: # convert to rgb # h is 360 based (circle) h, s, l = raw[0] / 360.0, raw[1], raw[2] # ORDER h l s !!! r, g, b = colorsys.hls_to_rgb(h, l, s) # back to 255 based rgba = [int(round(r*255)), int(round(g*255)), int(round(b*255))] if len(raw) > 3: rgba.append(raw[3]) else: # rgb, rgba rgba = raw if len(rgba) < 4: rgba.append(1.0) # validate checks = {u'rgb(': ('NNN', 'PPP'), u'rgba(': ('NNNN', 'PPPN'), u'hsl(': ('NPP',), u'hsla(': ('NPPN',) } if check not in checks[functiontype]: self._log.error(u'ColorValue has invalid %s) parameters: ' u'%s (N=Number, P=Percentage)' % (functiontype, check)) self._colorType = t self._red, self._green, self._blue, self._alpha = tuple(rgba) self._setSeq(seq)
def _setCssText(self, cssText): """Setting this attribute will result in the parsing of the new value and resetting of all the properties in the declaration block including the removal or addition of properties. :exceptions: - :exc:`~xml.dom.NoModificationAllowedErr`: Raised if this declaration is readonly or a property is readonly. - :exc:`~xml.dom.SyntaxErr`: Raised if the specified CSS string value has a syntax error and is unparsable. Format:: variableset : vardeclaration [ ';' S* vardeclaration ]* ; vardeclaration : varname ':' S* term ; varname : IDENT S* ; expr : [ VARCALL | term ] [ operator [ VARCALL | term ] ]* ; """ self._checkReadonly() vardeclaration = Sequence( PreDef.ident(), PreDef.char(u':', u':', toSeq=False), #PreDef.S(toSeq=False, optional=True), Prod(name=u'term', match=lambda t, v: True, toSeq=lambda t, tokens: (u'value', PropertyValue(itertools.chain([t], tokens), parent=self) ) ) ) prods = Sequence(vardeclaration, Sequence(PreDef.S(optional=True), PreDef.char(u';', u';', toSeq=False), PreDef.S(optional=True), vardeclaration, minmax=lambda: (0, None)), PreDef.S(optional=True), PreDef.char(u';', u';', toSeq=False, optional=True) ) # parse wellformed, seq, store, notused = \ ProdParser().parse(cssText, u'CSSVariableDeclaration', prods) if wellformed: newseq = self._tempSeq() newvars = {} # seq contains only name: value pairs plus comments etc nameitem = None for item in seq: if u'IDENT' == item.type: nameitem = item elif u'value' == item.type: nname = normalize(nameitem.value) if nname in newvars: # replace var with same name for i, it in enumerate(newseq): if normalize(it.value[0]) == nname: newseq.replace(i, (nameitem.value, item.value), 'var', nameitem.line, nameitem.col) else: # saved non normalized name for reserialization newseq.append((nameitem.value, item.value), 'var', nameitem.line, nameitem.col) # newseq.append((nameitem.value, item.value), # 'var', # nameitem.line, nameitem.col) newvars[nname] = item.value else: newseq.appendItem(item) self._setSeq(newseq) self._vars = newvars self.wellformed = True
def _setMediaText(self, mediaText): """ :param mediaText: a single media query string, e.g. ``print and (min-width: 25cm)`` :exceptions: - :exc:`~xml.dom.SyntaxErr`: Raised if the specified string value has a syntax error and is unparsable. - :exc:`~xml.dom.InvalidCharacterErr`: Raised if the given mediaType is unknown. - :exc:`~xml.dom.NoModificationAllowedErr`: Raised if this media query is readonly. media_query : [ONLY | NOT]? S* media_type S* [ AND S* expression ]* | expression [ AND S* expression ]* ; media_type : IDENT ; expression : '(' S* media_feature S* [ ':' S* expr ]? ')' S* ; media_feature : IDENT ; """ self._checkReadonly() expression = lambda: Sequence( PreDef.char(name='expression', char='('), Prod(name='media_feature', match=lambda t, v: t == PreDef.types.IDENT), Sequence( PreDef.char(name='colon', char=':'), cssutils.css.value.MediaQueryValueProd(self), minmax=lambda: (0, 1) # optional ), PreDef.char(name='expression END', char=')', stopIfNoMoreMatch=self._partof)) prods = Choice( Sequence( Prod( name='ONLY|NOT', # media_query match=lambda t, v: t == PreDef.types.IDENT and normalize(v) in ('only', 'not'), optional=True, toStore='not simple'), Prod(name='media_type', match=lambda t, v: t == PreDef.types.IDENT and normalize( v) in self.MEDIA_TYPES, stopIfNoMoreMatch=True, toStore='media_type'), Sequence(Prod(name='AND', match=lambda t, v: t == PreDef.types.IDENT and normalize(v) == 'and', toStore='not simple'), expression(), minmax=lambda: (0, None))), Sequence( expression(), Sequence(Prod(name='AND', match=lambda t, v: t == PreDef.types.IDENT and normalize(v) == 'and'), expression(), minmax=lambda: (0, None)))) # parse ok, seq, store, unused = ProdParser().parse(mediaText, 'MediaQuery', prods) self._wellformed = ok if ok: try: media_type = store['media_type'] except KeyError as e: pass else: if 'not simple' not in store: self.mediaType = media_type.value # TODO: filter doubles! self._setSeq(seq)
def _setCssText(self, cssText): self._checkReadonly() types = self._prods # rename! component = Choice(PreDef.unary(toSeq=lambda t, tokens: (t[0], DimensionValue(pushtoken(t, tokens), parent=self) )), PreDef.number(toSeq=lambda t, tokens: (t[0], DimensionValue(pushtoken(t, tokens), parent=self) )), PreDef.percentage(toSeq=lambda t, tokens: (t[0], DimensionValue(pushtoken(t, tokens), parent=self) )) ) noalp = Sequence(Prod(name='FUNCTION', match=lambda t, v: t == types.FUNCTION and v in (u'rgb(', u'hsl('), toSeq=lambda t, tokens: (t[0], normalize(t[1]))), component, Sequence(PreDef.comma(), component, minmax=lambda: (2, 2) ), PreDef.funcEnd(stop=True) ) witha = Sequence(Prod(name='FUNCTION', match=lambda t, v: t == types.FUNCTION and v in (u'rgba(', u'hsla('), toSeq=lambda t, tokens: (t[0], normalize(t[1])) ), component, Sequence(PreDef.comma(), component, minmax=lambda: (3, 3) ), PreDef.funcEnd(stop=True) ) namedcolor = Prod(name='Named Color', match=lambda t, v: t == 'IDENT' and ( normalize(v) in self.COLORS.keys() ), stop=True) prods = Choice(PreDef.hexcolor(stop=True), namedcolor, noalp, witha) ok, seq, store, unused = ProdParser().parse(cssText, self.type, prods) if ok: t, v = seq[0].type, seq[0].value if u'IDENT' == t: rgba = self.COLORS[normalize(v)] if u'HASH' == t: if len(v) == 4: # HASH #rgb rgba = (int(2*v[1], 16), int(2*v[1], 16), int(2*v[1], 16), 1.0) else: # HASH #rrggbb rgba = (int(v[1:3], 16), int(v[3:5], 16), int(v[5:7], 16), 1.0) elif u'FUNCTION' == t: functiontype, rgba, check = None, [], u'' for item in seq: try: type_ = item.value.type except AttributeError, e: # type of function, e.g. rgb( if item.type == 'FUNCTION': functiontype = item.value continue # save components if type_ == Value.NUMBER: rgba.append(item.value.value) check += u'N' elif type_ == Value.PERCENTAGE: rgba.append(int(255 * item.value.value / 100)) check += u'P' # validate checks = {u'rgb(': ('NNN', 'PPP'), u'rgba(': ('NNNN', 'PPPN'), u'hsl(': ('NPP',), u'hsla(': ('NPPN',) } if check not in checks[functiontype]: self._log.error(u'ColorValue has invalid %s) parameters: ' u'%s (N=Number, P=Percentage)' % (functiontype, check)) if len(rgba) < 4: rgba.append(1.0) self._colorType = t self._red, self._green, self._blue, self._alpha = tuple(rgba) self._setSeq(seq) self.wellformed = ok