コード例 #1
0
ファイル: sprites.py プロジェクト: 571451370/devstack_mitaka
def sprite(map, sprite, offset_x=None, offset_y=None, cache_buster=True):
    """
    Returns the image and background position for use in a single shorthand
    property
    """
    map = map.render()
    sprite_maps = _get_cache('sprite_maps')
    sprite_map = sprite_maps.get(map)
    sprite_name = String.unquoted(sprite).value
    sprite = sprite_map and sprite_map.get(sprite_name)
    if not sprite_map:
        log.error("No sprite map found: %s", map, extra={'stack': True})
    elif not sprite:
        log.error("No sprite found: %s in %s",
                  sprite_name,
                  sprite_map['*n*'],
                  extra={'stack': True})
    if sprite:
        url = '%s%s' % (config.ASSETS_URL, sprite_map['*f*'])
        if cache_buster:
            url += '?_=%s' % sprite_map['*t*']
        x = Number(offset_x or 0, 'px')
        y = Number(offset_y or 0, 'px')
        if not x.value or (x.value <= -1
                           or x.value >= 1) and not x.is_simple_unit('%'):
            x -= Number(sprite[2], 'px')
        if not y.value or (y.value <= -1
                           or y.value >= 1) and not y.is_simple_unit('%'):
            y -= Number(sprite[3], 'px')
        url = "url(%s)" % escape(url)
        return List([String.unquoted(url), x, y])
    return List([Number(0), Number(0)])
コード例 #2
0
def sprite_position(map, sprite, offset_x=None, offset_y=None):
    """
    Returns the position for the original image in the sprite.
    This is suitable for use as a value to background-position.
    """
    map = map.render()
    sprite_map = sprite_maps.get(map)
    sprite_name = String.unquoted(sprite).value
    sprite = sprite_map and sprite_map.get(sprite_name)
    if not sprite_map:
        log.error("No sprite map found: %s", map, extra={'stack': True})
    elif not sprite:
        log.error("No sprite found: %s in %s", sprite_name, sprite_map['*n*'], extra={'stack': True})
    if sprite:
        x = None
        if offset_x is not None and not isinstance(offset_x, Number):
            x = offset_x
        if not x or x.value not in ('left', 'right', 'center'):
            if x:
                offset_x = None
            x = Number(offset_x or 0, 'px')
            if not x.value or (x.value <= -1 or x.value >= 1) and not x.is_simple_unit('%'):
                x -= Number(sprite[2], 'px')
        y = None
        if offset_y is not None and not isinstance(offset_y, Number):
            y = offset_y
        if not y or y.value not in ('top', 'bottom', 'center'):
            if y:
                offset_y = None
            y = Number(offset_y or 0, 'px')
            if not y.value or (y.value <= -1 or y.value >= 1) and not y.is_simple_unit('%'):
                y -= Number(sprite[3], 'px')
        return List([x, y])
    return List([Number(0), Number(0)])
コード例 #3
0
ファイル: helpers.py プロジェクト: return42/pyScss
def _font_files(args, inline):
    if args == ():
        return String.unquoted("")

    fonts = []
    args_len = len(args)
    skip_next = False
    for index, arg in enumerate(args):
        if not skip_next:
            font_type = args[index + 1] if args_len > (index + 1) else None
            if font_type and font_type.value in FONT_TYPES:
                skip_next = True
            else:
                if re.match(r'^([^?]+)[.](.*)([?].*)?$', arg.value):
                    font_type = String.unquoted(
                        re.match(r'^([^?]+)[.](.*)([?].*)?$',
                                 arg.value).groups()[1])

            if font_type.value in FONT_TYPES:
                fonts.append(
                    List([
                        _font_url(arg, inline=inline),
                        Function(FONT_TYPES[font_type.value], 'format'),
                    ],
                         use_comma=False))
            else:
                raise Exception('Could not determine font type for "%s"' %
                                arg.value)
        else:
            skip_next = False

    return List(fonts, separator=',')
コード例 #4
0
def _render_standard_color_stops(color_stops):
    pairs = []
    for i, (stop, color) in enumerate(color_stops):
        if ((i == 0 and stop == Number(0, '%')) or
                (i == len(color_stops) - 1 and stop == Number(100, '%'))):
            pairs.append(color)
        else:
            pairs.append(List([color, stop], use_comma=False))

    return List(pairs, use_comma=True)
コード例 #5
0
ファイル: helpers.py プロジェクト: return42/pyScss
def dash_compass_slice(lst, start_index, end_index=None):
    start_index = Number(start_index).value
    end_index = Number(end_index).value if end_index is not None else None
    ret = {}
    lst = List(lst)
    if end_index:
        # This function has an inclusive end, but Python slicing is exclusive
        end_index += 1
    ret = lst.value[start_index:end_index]
    return List(ret, use_comma=lst.use_comma)
コード例 #6
0
ファイル: sprites.py プロジェクト: Rehy0810/database
def sprites(map):
    map = map.render()
    sprite_map = sprite_maps.get(map, {})
    return List(
        list(
            String.unquoted(s)
            for s in sorted(s for s in sprite_map if not s.startswith('*'))))
コード例 #7
0
def join(lst1, lst2, separator=None):
    ret = []
    ret.extend(List.from_maybe(lst1))
    ret.extend(List.from_maybe(lst2))

    use_comma = __parse_separator(separator, default_from=lst1)
    return List(ret, use_comma=use_comma)
コード例 #8
0
def nest(*arguments):
    if isinstance(arguments[0], List):
        lst = arguments[0].value
    else:
        lst = StringValue(arguments[0]).value.split(',')
    ret = [unicode(s).strip() for s in lst if unicode(s).strip()]
    for arg in arguments[1:]:
        if isinstance(arg, List):
            lst = arg.value
        else:
            lst = StringValue(arg).value.split(',')
        new_ret = []
        for s in lst:
            s = unicode(s).strip()
            if s:
                for r in ret:
                    if '&' in s:
                        new_ret.append(s.replace('&', r))
                    else:
                        if r[-1] in ('.', ':', '#'):
                            new_ret.append(r + s)
                        else:
                            new_ret.append(r + ' ' + s)
        ret = new_ret

    return List(sorted(set(ret)), use_comma=True)
コード例 #9
0
def enumerate_(prefix, frm, through, separator='-'):
    separator = StringValue(separator).value
    try:
        frm = int(getattr(frm, 'value', frm))
    except ValueError:
        frm = 1
    try:
        through = int(getattr(through, 'value', through))
    except ValueError:
        through = frm
    if frm > through:
        frm, through = through, frm
        rev = reversed
    else:
        rev = lambda x: x

    ret = []
    for i in rev(range(frm, through + 1)):
        if prefix.value:
            ret.append(
                StringValue(prefix.value + separator + str(i), quotes=None))
        else:
            ret.append(NumberValue(i))

    return List(ret, use_comma=True)
コード例 #10
0
ファイル: helpers.py プロジェクト: lamby/31bananas
def _font_files(args, inline):
    if args == ():
        return String.unquoted("")

    fonts = []
    args_len = len(args)
    skip_next = False
    for index in range(len(args)):
        arg = args[index]
        if not skip_next:
            font_type = args[index + 1] if args_len > (index + 1) else None
            if font_type and font_type.value in FONT_TYPES:
                skip_next = True
            else:
                if re.match(r'^([^?]+)[.](.*)([?].*)?$', arg.value):
                    font_type = String.unquoted(
                        re.match(r'^([^?]+)[.](.*)([?].*)?$',
                                 arg.value).groups()[1])

            if font_type.value in FONT_TYPES:
                fonts.append(
                    String.unquoted(
                        '%s format("%s")' %
                        (_font_url(arg, inline=inline),
                         String.unquoted(FONT_TYPES[font_type.value]).value)))
            else:
                raise Exception('Could not determine font type for "%s"' %
                                arg.value)
        else:
            skip_next = False

    return List(fonts, separator=',')
コード例 #11
0
def _font_files(args, inline):
    args = List.from_maybe_starargs(args)
    n = 0
    params = [[], []]
    for arg in args:
        if isinstance(arg, List):
            if len(arg) == 2:
                if n % 2 == 1:
                    params[1].append(None)
                    n += 1
                params[0].append(arg[0])
                params[1].append(arg[1])
                n += 2
            else:
                for arg2 in arg:
                    params[n % 2].append(arg2)
                    n += 1
        else:
            params[n % 2].append(arg)
            n += 1
    len0 = len(params[0])
    len1 = len(params[1])
    if len1 < len0:
        params[1] += [None] * (len0 - len1)
    elif len0 < len1:
        params[0] += [None] * (len1 - len0)
    fonts = []
    for font, format in zip(params[0], params[1]):
        if format:
            fonts.append(
                '%s format("%s")' %
                (_font_url(font, inline=inline), StringValue(format).value))
        else:
            fonts.append(_font_url(font, inline=inline))
    return List(fonts)
コード例 #12
0
def set_nth(list, n, value):
    expect_type(n, Number, unit=None)

    py_n = n.to_python_index(len(list))
    return List(
        tuple(list[:py_n]) + (value,) + tuple(list[py_n + 1:]),
        use_comma=list.use_comma)
コード例 #13
0
def join(lst1, lst2, separator=String.unquoted('auto')):
    expect_type(separator, String)

    ret = []
    ret.extend(List.from_maybe(lst1))
    ret.extend(List.from_maybe(lst2))

    if separator.value == 'comma':
        use_comma = True
    elif separator.value == 'space':
        use_comma = False
    elif separator.value == 'auto':
        # The Sass docs are slightly misleading here, but the algorithm is: use
        # the delimiter from the first list that has at least 2 items, or
        # default to spaces.
        if len(lst1) > 1:
            use_comma = lst1.use_comma
        elif len(lst2) > 1:
            use_comma = lst2.use_comma
        else:
            use_comma = False
    else:
        raise ValueError("separator for join() must be comma, space, or auto")

    return List(ret, use_comma=use_comma)
コード例 #14
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='"'))
コード例 #15
0
def append(lst, val, separator=None):
    ret = []
    ret.extend(List.from_maybe(lst))
    ret.append(val)

    use_comma = __parse_separator(separator, default_from=lst)
    return List(ret, use_comma=use_comma)
コード例 #16
0
ファイル: helpers.py プロジェクト: return42/pyScss
def enumerate_(prefix, frm, through, separator='-'):
    separator = String.unquoted(separator).value
    try:
        frm = int(getattr(frm, 'value', frm))
    except ValueError:
        frm = 1
    try:
        through = int(getattr(through, 'value', through))
    except ValueError:
        through = frm
    if frm > through:
        # DEVIATION: allow reversed enumerations (and ranges as range() uses enumerate, like '@for .. from .. through')
        frm, through = through, frm
        rev = reversed
    else:
        rev = lambda x: x

    ret = []
    for i in rev(range(frm, through + 1)):
        if prefix and prefix.value:
            ret.append(
                String.unquoted(prefix.value + separator + six.text_type(i)))
        else:
            ret.append(Number(i))

    return List(ret, use_comma=True)
コード例 #17
0
def test_parse(calc):
    # Tests for some general parsing.

    assert calc('foo !important bar') == List([
        String('foo'),
        String('!important'),
        String('bar'),
    ])
コード例 #18
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)
コード例 #19
0
def sprites(map, remove_suffix=False):
    map = map.render()
    sprite_map = sprite_maps.get(map, {})
    return List([
        String.unquoted(s) for s in sorted(
            set(
                s.rsplit('-', 1)[0] if remove_suffix else s for s in sprite_map
                if not s.startswith('*')))
    ])
コード例 #20
0
ファイル: fonts.py プロジェクト: coinpayee/pyScss
def glyphs(sheet, remove_suffix=False):
    sheet = sheet.render()
    font_sheet = font_sheets.get(sheet, {})
    return List([
        String.unquoted(f) for f in sorted(
            set(
                f.rsplit('-', 1)[0] if remove_suffix else f for f in font_sheet
                if not f.startswith('*')))
    ])
コード例 #21
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)'))
コード例 #22
0
ファイル: helpers.py プロジェクト: return42/pyScss
def nest(*arguments):
    if isinstance(arguments[0], List):
        lst = arguments[0]
    elif isinstance(arguments[0], String):
        lst = arguments[0].value.split(',')
    else:
        raise TypeError("Expected list or string, got %r" % (arguments[0], ))

    ret = []
    for s in lst:
        if isinstance(s, String):
            s = s.value
        elif isinstance(s, six.string_types):
            s = s
        else:
            raise TypeError("Expected string, got %r" % (s, ))

        s = s.strip()
        if not s:
            continue

        ret.append(s)

    for arg in arguments[1:]:
        if isinstance(arg, List):
            lst = arg
        elif isinstance(arg, String):
            lst = arg.value.split(',')
        else:
            raise TypeError("Expected list or string, got %r" % (arg, ))

        new_ret = []
        for s in lst:
            if isinstance(s, String):
                s = s.value
            elif isinstance(s, six.string_types):
                s = s
            else:
                raise TypeError("Expected string, got %r" % (s, ))

            s = s.strip()
            if not s:
                continue

            for r in ret:
                if '&' in s:
                    new_ret.append(s.replace('&', r))
                else:
                    if not r or r[-1] in ('.', ':', '#'):
                        new_ret.append(r + s)
                    else:
                        new_ret.append(r + ' ' + s)
        ret = new_ret

    ret = [String.unquoted(s) for s in sorted(set(ret))]
    return List(ret, use_comma=True)
コード例 #23
0
ファイル: helpers.py プロジェクト: return42/pyScss
def reject(lst, *values):
    """Removes the given values from the list"""
    lst = List.from_maybe(lst)
    values = frozenset(List.from_maybe_starargs(values))

    ret = []
    for item in lst:
        if item not in values:
            ret.append(item)
    return List(ret, use_comma=lst.use_comma)
コード例 #24
0
ファイル: helpers.py プロジェクト: return42/pyScss
def compact(*args):
    """Returns a new list after removing any non-true values"""
    use_comma = True
    if len(args) == 1 and isinstance(args[0], List):
        use_comma = args[0].use_comma
        args = args[0]

    return List(
        [arg for arg in args if arg],
        use_comma=use_comma,
    )
コード例 #25
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)
コード例 #26
0
    def evaluate(self, calculator, divide=False):
        items = [item.evaluate(calculator, divide=divide) for item in self.items]

        # Whether this is a "plain" literal matters for null removal: nulls are
        # left alone if this is a completely vanilla CSS property
        literal = True
        if divide:
            # TODO sort of overloading "divide" here...  rename i think
            literal = False
        elif not all(isinstance(item, Literal) for item in self.items):
            literal = False

        return List(items, use_comma=self.comma, literal=literal)
コード例 #27
0
def grad_point(*p):
    pos = set()
    hrz = vrt = Number(0.5, '%')
    for _p in p:
        pos.update(String.unquoted(_p).value.split())
    if 'left' in pos:
        hrz = Number(0, '%')
    elif 'right' in pos:
        hrz = Number(1, '%')
    if 'top' in pos:
        vrt = Number(0, '%')
    elif 'bottom' in pos:
        vrt = Number(1, '%')
    return List([v for v in (hrz, vrt) if v is not None])
コード例 #28
0
ファイル: helpers.py プロジェクト: return42/pyScss
def prefix(prefix, *args):
    to_fnct_str = 'to_' + to_str(prefix).replace('-', '_')
    args = list(args)
    for i, arg in enumerate(args):
        if isinstance(arg, List):
            _value = []
            for iarg in arg:
                to_fnct = getattr(iarg, to_fnct_str, None)
                if to_fnct:
                    _value.append(to_fnct())
                else:
                    _value.append(iarg)
            args[i] = List(_value)
        else:
            to_fnct = getattr(arg, to_fnct_str, None)
            if to_fnct:
                args[i] = to_fnct()

    return List.maybe_new(args, use_comma=True)
コード例 #29
0
ファイル: helpers.py プロジェクト: return42/pyScss
def _position(opposite, positions):
    if positions is None:
        positions = DEFAULT_POSITION
    else:
        positions = List.from_maybe(positions)

    ret = []
    for pos in positions:
        if isinstance(pos, (String, six.string_types)):
            pos_value = getattr(pos, 'value', pos)
            if pos_value in OPPOSITE_POSITIONS:
                if opposite:
                    ret.append(OPPOSITE_POSITIONS[pos_value])
                else:
                    ret.append(pos)
                continue
            elif pos_value == 'to':
                # Gradient syntax keyword; leave alone
                ret.append(pos)
                continue

        elif isinstance(pos, Number):
            if pos.is_simple_unit('%'):
                if opposite:
                    ret.append(Number(100 - pos.value, '%'))
                else:
                    ret.append(pos)
                continue
            elif pos.is_simple_unit('deg'):
                # TODO support other angle types?
                if opposite:
                    ret.append(Number((pos.value + 180) % 360, 'deg'))
                else:
                    ret.append(pos)
                continue

        if opposite:
            log.warn("Can't find opposite for position %r" % (pos, ))
        ret.append(pos)

    return List(ret, use_comma=False).maybe()
コード例 #30
0
def append(lst, val, separator=String.unquoted('auto')):
    expect_type(separator, String)

    ret = []
    ret.extend(List.from_maybe(lst))
    ret.append(val)

    separator = separator.value
    if separator == 'comma':
        use_comma = True
    elif separator == 'space':
        use_comma = False
    elif separator == 'auto':
        if len(lst) < 2:
            use_comma = False
        else:
            use_comma = lst.use_comma
    else:
        raise ValueError('Separator must be auto, comma, or space')

    return List(ret, use_comma=use_comma)