コード例 #1
0
def test_comparison_stringerific():
    abc = String('abc')
    xyz = String('xyz')

    assert abc == abc
    assert abc != xyz
    assert not abc == xyz
    assert not abc != abc

    # Interaction with other types
    assert Number(123) != String('123')
    assert String('123') != Number(123)

    # Sass strings don't support ordering
    with pytest.raises(TypeError):
        abc < xyz

    with pytest.raises(TypeError):
        abc <= xyz

    with pytest.raises(TypeError):
        abc > xyz

    with pytest.raises(TypeError):
        abc >= xyz

    with pytest.raises(TypeError):
        Number(123) < String('123')
コード例 #2
0
 def kwatom(self):
     _token_ = self._peek(self.kwatom_rsts)
     if _token_ == '":"':
         pass
     elif _token_ == 'KWID':
         KWID = self._scan('KWID')
         return Literal(parse_bareword(KWID))
     elif _token_ == 'KWNUM':
         KWNUM = self._scan('KWNUM')
         UNITS = None
         if self._peek(self.kwatom_rsts_) == 'UNITS':
             UNITS = self._scan('UNITS')
         return Literal(Number(float(KWNUM), unit=UNITS))
     elif _token_ == 'KWSTR':
         KWSTR = self._scan('KWSTR')
         return Literal(String(KWSTR[1:-1], quotes="'"))
     elif _token_ == 'KWQSTR':
         KWQSTR = self._scan('KWQSTR')
         return Literal(String(KWQSTR[1:-1], quotes='"'))
     elif _token_ == 'KWCOLOR':
         KWCOLOR = self._scan('KWCOLOR')
         return Literal(Color.from_hex(COLOR, literal=True))
     else:  # == 'KWVAR'
         KWVAR = self._scan('KWVAR')
         return Variable(KWVAR)
コード例 #3
0
def quote(*args):
    arg = List.from_maybe_starargs(args).maybe()

    if isinstance(arg, String):
        return String(arg.value, quotes='"')
    else:
        return String(arg.render(), quotes='"')
コード例 #4
0
def test_quote():
    # Examples from the Ruby docs
    ret = calc('quote("foo")')
    assert ret == String('foo')
    assert ret.quotes == '"'
    ret = calc('quote(foo)')
    assert ret == String('foo')
    assert ret.quotes == '"'
コード例 #5
0
def test_parse(calc):
    # Tests for some general parsing.

    assert calc('foo !important bar') == List([
        String('foo'),
        String('!important'),
        String('bar'),
    ])
コード例 #6
0
def test_unquote():
    # Examples from the Ruby docs
    ret = calc('unquote("foo")')
    assert ret == String('foo')
    assert ret.quotes is None
    ret = calc('unquote(foo)')
    assert ret == String('foo')
    assert ret.quotes is None

    assert calc('unquote((one, two, three))') == String('one, two, three')
コード例 #7
0
ファイル: test_expression.py プロジェクト: ziotoie00/pyScss
def test_functions(calc):
    calc = Calculator(CoreExtension.namespace).calculate

    assert calc('grayscale(red)') == Color.from_rgb(0.5, 0.5, 0.5)
    assert calc('grayscale(1)') == String(
        'grayscale(1)',
        quotes=None)  # Misusing css built-in functions (with scss counterpart)
    assert calc('skew(1)') == String(
        'skew(1)', quotes=None)  # Missing css-only built-in functions
    with pytest.raises(SassEvaluationError):
        calc('unitless("X")')  # Misusing non-css built-in scss funtions
コード例 #8
0
def join_file_segments(*segments):
    """Join path parts into a single path, using the appropriate OS-specific
    delimiter.
    """
    parts = []
    for segment in segments:
        expect_type(segment, String)
        parts.append(segment.value)

    if parts:
        return String(os.path.join(*parts))
    else:
        return String('')
コード例 #9
0
def test_reference_operations():
    """Test the example expressions in the reference document:

    http://sass-lang.com/docs/yardoc/file.SASS_REFERENCE.html#operations
    """
    # TODO: break this into its own file and add the entire reference guide

    # Need to build the calculator manually to get at its namespace, and need
    # to use calculate() instead of evaluate_expression() so interpolation
    # works
    ns = CoreExtension.namespace.derive()
    calc = Calculator(ns).calculate

    # Simple example
    assert calc('1in + 8pt') == Number(1.1111111111111112, "in")

    # Division
    ns.set_variable('$width', Number(1000, "px"))
    ns.set_variable('$font-size', Number(12, "px"))
    ns.set_variable('$line-height', Number(30, "px"))
    assert calc('10px/8px') == String('10px / 8px')  # plain CSS; no division
    assert calc('$width/2') == Number(500,
                                      "px")  # uses a variable; does division
    assert calc('(500px/2)') == Number(250, "px")  # uses parens; does division
    assert calc('5px + 8px/2px') == Number(9, "px")  # uses +; does division
    # TODO, again: Ruby Sass correctly renders this without spaces
    assert calc('#{$font-size}/#{$line-height}') == String('12px / 30px')
    # uses #{}; does no division

    # Color operations
    ns.set_variable('$translucent-red', Color.from_rgb(1, 0, 0, 0.5))
    ns.set_variable('$green', Color.from_name('lime'))
    assert calc('#010203 + #040506') == Color.from_hex('#050709')
    assert calc('#010203 * 2') == Color.from_hex('#020406')
    assert calc(
        'rgba(255, 0, 0, 0.75) + rgba(0, 255, 0, 0.75)') == Color.from_rgb(
            1, 1, 0, 0.75)
    assert calc('opacify($translucent-red, 0.3)') == Color.from_rgb(
        1, 0, 0, 0.8)
    assert calc('transparentize($translucent-red, 0.25)') == Color.from_rgb(
        1, 0, 0, 0.25)
    assert calc(
        "progid:DXImageTransform.Microsoft.gradient(enabled='false', startColorstr='#{ie-hex-str($green)}', endColorstr='#{ie-hex-str($translucent-red)}')"
    ).render(
    ) == "progid:DXImageTransform.Microsoft.gradient(enabled='false', startColorstr='#FF00FF00', endColorstr='#80FF0000')"

    # String operations
    ns.set_variable('$value', Null())
    assert_strict_string_eq(calc('e + -resize'), String('e-resize',
                                                        quotes=None))
    assert_strict_string_eq(calc('"Foo " + Bar'), String('Foo Bar',
                                                         quotes='"'))
    assert_strict_string_eq(calc('sans- + "serif"'),
                            String('sans-serif', quotes=None))
    assert calc('3px + 4px auto') == List(
        [Number(7, "px"), String('auto', quotes=None)])
    assert_strict_string_eq(calc('"I ate #{5 + 10} pies!"'),
                            String('I ate 15 pies!', quotes='"'))
    assert_strict_string_eq(calc('"I ate #{$value} pies!"'),
                            String('I ate  pies!', quotes='"'))
コード例 #10
0
ファイル: test_expression.py プロジェクト: ziotoie00/pyScss
def test_parse_strings(calc):
    # Escapes in barewords are preserved.
    assert calc('auto\\9') == String.unquoted('auto\\9')

    # Escapes in quoted strings are expanded.
    assert calc('"\\2022"') == String("•", quotes='"')
    assert calc('"\\2022"').render() == '"•"'
コード例 #11
0
ファイル: webchat.py プロジェクト: tesla1856/LalkaChat
    def style_scss(self, *path):
        css_namespace = Namespace()
        for key, value in self.settings['keys'].items():
            if isinstance(value, LCText):
                css_value = String(value)
            elif isinstance(value, LCColour):
                css_value = Color.from_hex(value)
            elif isinstance(value, LCBool):
                css_value = Boolean(value.simple())
            elif isinstance(value, LCSpin):
                css_value = Number(value.simple())
            else:
                raise ValueError("Unable to find comparable values")
            css_namespace.set_variable('${}'.format(key), css_value)

        cherrypy.response.headers['Content-Type'] = 'text/css'
        with open(os.path.join(self.settings['location'], *path), 'r') as css:
            css_content = css.read()
            compiler = Compiler(namespace=css_namespace, output_style='nested')
            # Something wrong with PyScss,
            #  Syntax error: Found u'100%' but expected one of ADD.
            # Doesn't happen on next attempt, so we are doing bad thing
            attempts = 0
            while attempts < 100:
                try:
                    attempts += 1
                    ret_string = compiler.compile_string(css_content)
                    return ret_string
                except Exception as exc:
                    if attempts == 100:
                        log.debug(exc)
コード例 #12
0
ファイル: scss_filter.py プロジェクト: tomascribb10/horizon
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

        self.namespace = Namespace()

        # Add variables to the SCSS Global Namespace Here
        self.namespace.set_variable('$static_url', String(settings.STATIC_URL))
コード例 #13
0
ファイル: scss_filter.py プロジェクト: my-master-yang/xiong
    def __init__(self, *args, **kwargs):
        super(HorizonScssFilter, self).__init__(*args, **kwargs)

        self.namespace = Namespace()

        # Add variables to the SCSS Global Namespace Here
        self.namespace.set_variable('$static_url', String(six.text_type(getattr(settings, 'STATIC_URL', '/static/'))))
コード例 #14
0
def absolute_path(relative_path):
    """Return an absolute path for the given relative path, relative to the
    calling file.
    """
    expect_type(relative_path, String)
    # TODO i can't get the calling file until "rule" or something else helpful
    # is actually passed in!
    return String(os.path.abspath(relative_path.value))
コード例 #15
0
def ie_hex_str(color):
    c = Color(color).value
    return String("#{3:02X}{0:02X}{1:02X}{2:02X}".format(
        int(round(c[0])),
        int(round(c[1])),
        int(round(c[2])),
        int(round(c[3] * 255)),
    ))
コード例 #16
0
ファイル: views.py プロジェクト: funkybob/dumpling
def styles(request, name):
    src = ''
    namespace = Namespace()
    for tv in ThemeValue.objects.all():
        namespace.set_variable('${}-{}'.format(tv.group, tv.name),
                               String(tv.value))
    compiler = Compiler(namespace=namespace)
    return HttpResponse(compiler.compile_string(src), content_type='text/css')
コード例 #17
0
    def evaluate(self, calculator, divide=False):
        # TODO bake this into the context and options "dicts", plus library
        func_name = normalize_var(self.func_name)

        argspec_node = self.argspec

        # Turn the pairs of arg tuples into *args and **kwargs
        # TODO unclear whether this is correct -- how does arg, kwarg, arg
        # work?
        args, kwargs = argspec_node.evaluate_call_args(calculator)
        argspec_len = len(args) + len(kwargs)

        # Translate variable names to Python identifiers
        # TODO what about duplicate kw names?  should this happen in argspec?
        # how does that affect mixins?
        kwargs = dict((key.lstrip('$').replace('-', '_'), value)
                      for key, value in kwargs.items())

        # TODO merge this with the library
        funct = None
        try:
            funct = calculator.namespace.function(func_name, argspec_len)
            # @functions take a ns as first arg.  TODO: Python functions possibly
            # should too
            if getattr(funct, '__name__', None) == '__call':
                funct = partial(funct, calculator.namespace)
        except KeyError:
            try:
                # DEVIATION: Fall back to single parameter
                funct = calculator.namespace.function(func_name, 1)
                args = [List(args, use_comma=True)]
            except KeyError:
                if not is_builtin_css_function(func_name):
                    log.error("Function not found: %s:%s",
                              func_name,
                              argspec_len,
                              extra={'stack': True})

        if funct:
            ret = funct(*args, **kwargs)
            if not isinstance(ret, Value):
                raise TypeError("Expected Sass type as return value, got %r" %
                                (ret, ))
            return ret

        # No matching function found, so render the computed values as a CSS
        # function call.  Slurpy arguments are expanded and named arguments are
        # unsupported.
        if kwargs:
            raise TypeError(
                "The CSS function %s doesn't support keyword arguments." %
                (func_name, ))

        # TODO another candidate for a "function call" sass type
        rendered_args = [arg.render() for arg in args]

        return String(u"%s(%s)" % (func_name, u", ".join(rendered_args)),
                      quotes=None)
コード例 #18
0
ファイル: test_gradients.py プロジェクト: ziotoie00/pyScss
def test_linear_gradient():
    # Set up some values
    to = String.unquoted('to')
    bottom = String.unquoted('bottom')
    left = String.unquoted('left')

    red = Color.from_name('red')
    blue = Color.from_name('blue')

    start = Number(0, "%")
    middle = Number(50, "%")
    end = Number(100, "%")

    assert (linear_gradient(left, List((red, start)), List(
        (blue, middle))) == String('linear-gradient(left, red, blue 50%)'))

    assert (linear_gradient(List((to, bottom)), blue, List(
        (red, end))) == String('linear-gradient(to bottom, blue, red)'))
コード例 #19
0
def str_insert(string, insert, index):
    expect_type(string, String)
    expect_type(insert, String)
    expect_type(index, Number, unit=None)

    py_index = index.to_python_index(len(string.value), check_bounds=False)
    return String(
        string.value[:py_index] + insert.value + string.value[py_index:],
        quotes=string.quotes)
コード例 #20
0
 def atom(self):
     _token_ = self._peek(self.u_expr_chks)
     if _token_ == 'LPAR':
         LPAR = self._scan('LPAR')
         _token_ = self._peek(self.atom_rsts)
         if _token_ not in self.argspec_item_chks:
             expr_map = self.expr_map()
             v = expr_map
         else:  # in self.argspec_item_chks
             expr_lst = self.expr_lst()
             v = expr_lst
         RPAR = self._scan('RPAR')
         return Parentheses(v)
     elif _token_ == 'FNCT':
         FNCT = self._scan('FNCT')
         LPAR = self._scan('LPAR')
         argspec = self.argspec()
         RPAR = self._scan('RPAR')
         return CallOp(FNCT, argspec)
     elif _token_ == 'BANG_IMPORTANT':
         BANG_IMPORTANT = self._scan('BANG_IMPORTANT')
         return Literal(String(BANG_IMPORTANT, quotes=None))
     elif _token_ == 'ID':
         ID = self._scan('ID')
         return Literal(parse_bareword(ID))
     elif _token_ == 'NUM':
         NUM = self._scan('NUM')
         UNITS = None
         if self._peek(self.atom_rsts_) == 'UNITS':
             UNITS = self._scan('UNITS')
         return Literal(Number(float(NUM), unit=UNITS))
     elif _token_ == 'STR':
         STR = self._scan('STR')
         return Literal(String(STR[1:-1], quotes="'"))
     elif _token_ == 'QSTR':
         QSTR = self._scan('QSTR')
         return Literal(String(QSTR[1:-1], quotes='"'))
     elif _token_ == 'COLOR':
         COLOR = self._scan('COLOR')
         return Literal(Color.from_hex(COLOR, literal=True))
     else:  # == 'VAR'
         VAR = self._scan('VAR')
         return Variable(VAR)
コード例 #21
0
def _get_gradient_shape_and_size(args):
    for arg in args:
        for seek in (
            'circle', 'ellipse',
            'closest-side', 'closest-corner',
            'farthest-side', 'farthest-corner',
            'contain', 'cover',
        ):
            if String(seek) in arg:
                return arg
    return None
コード例 #22
0
ファイル: expression.py プロジェクト: magical/pyScss
 def atom(self):
     _token_ = self._peek(self.u_expr_chks)
     if _token_ == 'LPAR':
         LPAR = self._scan('LPAR')
         expr_lst = self.expr_lst()
         RPAR = self._scan('RPAR')
         return Parentheses(expr_lst)
     elif _token_ == 'ID':
         ID = self._scan('ID')
         return Literal(parse_bareword(ID))
     elif _token_ == 'BANG_IMPORTANT':
         BANG_IMPORTANT = self._scan('BANG_IMPORTANT')
         return Literal(String(BANG_IMPORTANT, quotes=None))
     elif _token_ == 'FNCT':
         FNCT = self._scan('FNCT')
         v = ArgspecLiteral([])
         LPAR = self._scan('LPAR')
         if self._peek(self.atom_rsts) != 'RPAR':
             argspec = self.argspec()
             v = argspec
         RPAR = self._scan('RPAR')
         return CallOp(FNCT, v)
     elif _token_ == 'NUM':
         NUM = self._scan('NUM')
         if self._peek(self.atom_rsts_) == 'UNITS':
             UNITS = self._scan('UNITS')
             return Literal(NumberValue(float(NUM), unit=UNITS.lower()))
         return Literal(NumberValue(float(NUM)))
     elif _token_ == 'STR':
         STR = self._scan('STR')
         return Literal(String(STR[1:-1], quotes="'"))
     elif _token_ == 'QSTR':
         QSTR = self._scan('QSTR')
         return Literal(String(QSTR[1:-1], quotes='"'))
     elif _token_ == 'COLOR':
         COLOR = self._scan('COLOR')
         return Literal(ColorValue(ParserValue(COLOR)))
     else:  # == 'VAR'
         VAR = self._scan('VAR')
         return Variable(VAR)
コード例 #23
0
ファイル: test_expression.py プロジェクト: ziotoie00/pyScss
def test_parse_bang_important(calc):
    # The !important flag is treated as part of a spaced list.
    assert calc('40px !important') == List([
        Number(40, 'px'),
        String.unquoted('!important'),
    ],
                                           use_comma=False)

    # And is allowed anywhere in the string.
    assert calc('foo !important bar') == List([
        String('foo'),
        String('!important'),
        String('bar'),
    ],
                                              use_comma=False)

    # And may have space before the !.
    assert calc('40px ! important') == List([
        Number(40, 'px'),
        String.unquoted('!important'),
    ],
                                            use_comma=False)
コード例 #24
0
def parse_bareword(word):
    if word in COLOR_NAMES:
        return Color.from_name(word)
    elif word == 'null':
        return Null()
    elif word == 'undefined':
        return Undefined()
    elif word == 'true':
        return Boolean(True)
    elif word == 'false':
        return Boolean(False)
    else:
        return String(word, quotes=None)
コード例 #25
0
def str_slice(string, start_at, end_at=None):
    expect_type(string, String)
    expect_type(start_at, Number, unit=None)
    py_start_at = start_at.to_python_index(len(string.value))

    if end_at is None:
        py_end_at = None
    else:
        expect_type(end_at, Number, unit=None)
        # Endpoint is inclusive, unlike Python
        py_end_at = end_at.to_python_index(len(string.value)) + 1

    return String(string.value[py_start_at:py_end_at], quotes=string.quotes)
コード例 #26
0
ファイル: fonts.py プロジェクト: coinpayee/pyScss
def glyph_code(sheet, glyph):
    sheet = sheet.render()
    font_sheet = font_sheets.get(sheet)
    glyph_name = String.unquoted(glyph).value
    glyph = font_sheet and font_sheet.get(glyph_name)
    if not font_sheet:
        log.error("No font sheet found: %s", sheet, extra={'stack': True})
    elif not glyph:
        log.error("No glyph found: %s in %s",
                  glyph_name,
                  font_sheet['*n*'],
                  extra={'stack': True})
    return String('\\%x' % glyph[1])
コード例 #27
0
    def from_bareword(cls, word):
        if word in COLOR_NAMES:
            value = Color.from_name(word)
        elif word == 'null':
            value = Null()
        elif word == 'undefined':
            value = Undefined()
        elif word == 'true':
            value = Boolean(True)
        elif word == 'false':
            value = Boolean(False)
        else:
            value = String(word, quotes=None)

        return cls(value)
コード例 #28
0
ファイル: test_gradients.py プロジェクト: ziotoie00/pyScss
def test_linear_gradient_idempotent(calc):
    # linear-gradient should leave valid syntax alone.
    # Examples graciously stolen from MDN:
    # https://developer.mozilla.org/en-US/docs/Web/CSS/linear-gradient
    trials = [
        'linear-gradient(45deg, blue, red)',
        'linear-gradient(to left top, blue, red)',
        'linear-gradient(0deg, blue, green 40%, red)',
        'linear-gradient(to right, red, orange, yellow, green, blue, indigo, violet)',
        'linear-gradient(to bottom right, red, rgba(255,0,0,0))',
        'linear-gradient(to bottom, hsl(0, 80%, 70%), #bada55)',
    ]

    for trial in trials:
        assert calc(trial) == String(trial)
コード例 #29
0
    def evaluate(self, calculator, divide=False):
        left = self.left.evaluate(calculator, divide=True)
        right = self.right.evaluate(calculator, divide=True)

        # Special handling of division: treat it as a literal slash if both
        # operands are literals, there are parentheses, or this is part of a
        # bigger expression.
        # The first condition is covered by the type check.  The other two are
        # covered by the `divide` argument: other nodes that perform arithmetic
        # will pass in True, indicating that this should always be a division.
        if (self.op is operator.truediv and not divide
                and isinstance(self.left, Literal)
                and isinstance(self.right, Literal)):
            return String(left.render() + ' / ' + right.render(), quotes=None)

        return self.op(left, right)
コード例 #30
0
ファイル: expression.py プロジェクト: magical/pyScss
    def evaluate(self, calculator, divide=False):
        # TODO bake this into the context and options "dicts", plus library
        func_name = normalize_var(self.func_name)

        # Turn the pairs of arg tuples into *args and **kwargs
        # TODO unclear whether this is correct -- how does arg, kwarg, arg
        # work?
        args = []
        kwargs = {}
        evald_argpairs = []
        for var, expr in self.argspec.argpairs:
            value = expr.evaluate(calculator, divide=True)
            evald_argpairs.append((var, value))

            if var is None:
                args.append(value)
            else:
                kwargs[var.lstrip('$').replace('-', '_')] = value

        num_args = len(self.argspec.argpairs)

        # TODO merge this with the library
        try:
            func = calculator.namespace.function(func_name, num_args)
            # @functions take a ns as first arg.  TODO: Python functions possibly
            # should too
            if getattr(func, '__name__', None) == '__call':
                func = partial(func, calculator.namespace)
        except KeyError:
            if not is_builtin_css_function(func_name):
                log.error("Function not found: %s:%s",
                          func_name,
                          num_args,
                          extra={'stack': True})

            rendered_args = []
            for var, value in evald_argpairs:
                rendered_value = value.render()
                if var is None:
                    rendered_args.append(rendered_value)
                else:
                    rendered_args.append("%s: %s" % (var, rendered_value))

            return String(u"%s(%s)" % (func_name, u", ".join(rendered_args)),
                          quotes=None)
        else:
            return func(*args, **kwargs)