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)])
def stylesheet_url(path, only_path=False, cache_buster=True): """ Generates a path to an asset found relative to the project's css directory. Passing a true value as the second argument will cause the only the path to be returned instead of a `url()` function """ filepath = String.unquoted(path).value if callable(config.STATIC_ROOT): try: _file, _storage = list(config.STATIC_ROOT(filepath))[0] except IndexError: filetime = None else: filetime = getmtime(_file, _storage) if filetime is None: filetime = 'NA' else: _path = os.path.join(config.STATIC_ROOT, filepath.strip('/')) filetime = getmtime(_path) if filetime is None: filetime = 'NA' BASE_URL = config.STATIC_URL url = '%s%s' % (BASE_URL, filepath) if cache_buster: url = add_cache_buster(url, filetime) if only_path: return String.unquoted(url) else: return Url.unquoted(url)
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)
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=',')
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 + str(i))) else: ret.append(Number(i)) return List(ret, use_comma=True)
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=',')
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=',')
def stylesheet_url(path, only_path=False, cache_buster=True): """ Generates a path to an asset found relative to the project's css directory. Passing a true value as the second argument will cause the only the path to be returned instead of a `url()` function """ filepath = String.unquoted(path).value if callable(config.STATIC_ROOT): try: _file, _storage = list(config.STATIC_ROOT(filepath))[0] d_obj = _storage.modified_time(_file) filetime = int(time.mktime(d_obj.timetuple())) except: filetime = 'NA' else: _path = os.path.join(config.STATIC_ROOT, filepath.strip('/')) if os.path.exists(_path): filetime = int(os.path.getmtime(_path)) else: filetime = 'NA' BASE_URL = config.STATIC_URL url = '%s%s' % (BASE_URL, filepath) if cache_buster: url = add_cache_buster(url, filetime) if not only_path: url = 'url("%s")' % (url) return String.unquoted(url)
def _font_url(path, only_path=False, cache_buster=True, inline=False): filepath = String.unquoted(path).value path = None if callable(config.STATIC_ROOT): try: _file, _storage = list(config.STATIC_ROOT(filepath))[0] d_obj = _storage.modified_time(_file) filetime = int(time.mktime(d_obj.timetuple())) if inline: path = _storage.open(_file) except: filetime = 'NA' else: _path = os.path.join(config.STATIC_ROOT, filepath.strip('/')) if os.path.exists(_path): filetime = int(os.path.getmtime(_path)) if inline: path = open(_path, 'rb') else: filetime = 'NA' BASE_URL = config.STATIC_URL if path and inline: mime_type = mimetypes.guess_type(filepath)[0] url = 'data:' + mime_type + ';base64,' + base64.b64encode(path.read()) else: url = '%s%s' % (BASE_URL, filepath) if cache_buster: url = add_cache_buster(url, filetime) if not only_path: url = 'url("%s")' % escape(url) return String.unquoted(url)
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_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)])
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=',')
def append_selector(selector, to_append): if isinstance(selector, List): lst = selector.value else: lst = String.unquoted(selector).value.split(',') to_append = String.unquoted(to_append).value.strip() ret = sorted(set(s.strip() + to_append for s in lst if s.strip())) ret = dict(enumerate(ret)) ret['_'] = ',' return ret
def _font_url(path, only_path=False, cache_buster=True, inline=False): filepath = String.unquoted(path).value file = None FONTS_ROOT = _fonts_root() if callable(FONTS_ROOT): try: _file, _storage = list(FONTS_ROOT(filepath))[0] except IndexError: filetime = None else: filetime = getmtime(_file, _storage) if filetime is None: filetime = 'NA' elif inline: file = _storage.open(_file) else: _path = os.path.join(FONTS_ROOT, filepath.strip('/')) filetime = getmtime(_path) if filetime is None: filetime = 'NA' elif inline: file = open(_path, 'rb') BASE_URL = config.FONTS_URL or config.STATIC_URL if file and inline: font_type = None if re.match(r'^([^?]+)[.](.*)([?].*)?$', path.value): font_type = String.unquoted( re.match(r'^([^?]+)[.](.*)([?].*)?$', path.value).groups()[1]).value try: mime = FONT_TYPES[font_type] except KeyError: raise Exception('Could not determine font type for "%s"' % path.value) mime = FONT_TYPES.get(font_type) if font_type == 'woff': mime = 'application/font-woff' elif font_type == 'eot': mime = 'application/vnd.ms-fontobject' url = make_data_url((mime if '/' in mime else 'font/%s' % mime), file.read()) file.close() else: url = '%s/%s' % (BASE_URL.rstrip('/'), filepath.lstrip('/')) if cache_buster and filetime != 'NA': url = add_cache_buster(url, filetime) if only_path: return String.unquoted(url) else: return Url.unquoted(url)
def sprite_map_name(map): """ Returns the name of a sprite map The name is derived from the folder than contains the sprites. """ map = map.render() sprite_map = sprite_maps.get(map) if not sprite_map: log.error("No sprite map found: %s", map, extra={'stack': True}) if sprite_map: return String.unquoted(sprite_map['*n*']) return String.unquoted('')
def _font_url(path, only_path=False, cache_buster=True, inline=False): filepath = String.unquoted(path).value file = None FONTS_ROOT = _fonts_root() if callable(FONTS_ROOT): try: _file, _storage = list(FONTS_ROOT(filepath))[0] except IndexError: filetime = None else: filetime = getmtime(_file, _storage) if filetime is None: filetime = 'NA' elif inline: file = _storage.open(_file) else: _path = os.path.join(FONTS_ROOT, filepath.strip('/')) filetime = getmtime(_path) if filetime is None: filetime = 'NA' elif inline: file = open(_path, 'rb') BASE_URL = config.FONTS_URL or config.STATIC_URL if file and inline: font_type = None if re.match(r'^([^?]+)[.](.*)([?].*)?$', path.value): font_type = String.unquoted(re.match(r'^([^?]+)[.](.*)([?].*)?$', path.value).groups()[1]).value try: mime = FONT_TYPES[font_type] except KeyError: raise Exception('Could not determine font type for "%s"' % path.value) mime = FONT_TYPES.get(font_type) if font_type == 'woff': mime = 'application/font-woff' elif font_type == 'eot': mime = 'application/vnd.ms-fontobject' url = make_data_url( (mime if '/' in mime else 'font/%s' % mime), file.read()) file.close() else: url = '%s/%s' % (BASE_URL.rstrip('/'), filepath.lstrip('/')) if cache_buster and filetime != 'NA': url = add_cache_buster(url, filetime) if only_path: return String.unquoted(url) else: return Url.unquoted(url)
def _font_url(path, only_path=False, cache_buster=True, inline=False): filepath = String.unquoted(path).value file = None FONTS_ROOT = _fonts_root() if callable(FONTS_ROOT): try: _file, _storage = list(FONTS_ROOT(filepath))[0] d_obj = _storage.modified_time(_file) filetime = int(time.mktime(d_obj.timetuple())) if inline: file = _storage.open(_file) except: filetime = 'NA' else: _path = os.path.join(FONTS_ROOT, filepath.strip('/')) if os.path.exists(_path): filetime = int(os.path.getmtime(_path)) if inline: file = open(_path, 'rb') else: filetime = 'NA' BASE_URL = config.FONTS_URL or config.STATIC_URL if file and inline: font_type = None if re.match(r'^([^?]+)[.](.*)([?].*)?$', path.value): font_type = String.unquoted( re.match(r'^([^?]+)[.](.*)([?].*)?$', path.value).groups()[1]).value if not FONT_TYPES.get(font_type): raise Exception('Could not determine font type for "%s"' % path.value) mime = FONT_TYPES.get(font_type) if font_type == 'woff': mime = 'application/font-woff' elif font_type == 'eot': mime = 'application/vnd.ms-fontobject' url = 'data:' + (mime if '/' in mime else 'font/%s' % mime) + ';base64,' + base64.b64encode(file.read()) file.close() else: url = '%s/%s' % (BASE_URL.rstrip('/'), filepath.lstrip('/')) if cache_buster and filetime != 'NA': url = add_cache_buster(url, filetime) if not only_path: url = 'url(%s)' % escape(url) return String.unquoted(url)
def sprite_url(map, cache_buster=True): """ Returns a url to the sprite image. """ map = map.render() sprite_map = sprite_maps.get(map) if not sprite_map: log.error("No sprite map found: %s", map, extra={'stack': True}) if sprite_map: url = '%s%s' % (config.ASSETS_URL, sprite_map['*f*']) if cache_buster: url += '?_=%s' % sprite_map['*t*'] url = "url(%s)" % escape(url) return String.unquoted(url) return String.unquoted('')
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)
def sprite_does_not_have_parent(map, sprite): 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 there is no selector, the sprite does not have any parents return Boolean(not sprite[4])
def grayscale(color): if isinstance(color, Number) and color.is_unitless: # grayscale(n) is a CSS3 filter and should be left intact, but only # when using the "a" spelling return String.unquoted("grayscale(%d)" % (color.value,)) else: return greyscale(color)
def __init__( self, scss_vars=None, scss_opts=None, scss_files=None, super_selector='', live_errors=False, library=None, func_registry=None, search_paths=None): self.super_selector = super_selector self._scss_vars = {} if scss_vars: calculator = Calculator() for var_name, value in scss_vars.items(): if isinstance(value, six.string_types): scss_value = calculator.evaluate_expression(value) if scss_value is None: # TODO warning? scss_value = String.unquoted(value) else: scss_value = value self._scss_vars[var_name] = scss_value self._scss_opts = scss_opts or {} self._scss_files = scss_files self._library = func_registry or library self._search_paths = search_paths # If true, swallow compile errors and embed them in the output instead self.live_errors = live_errors
def image_width(image): """ Returns the width of the image found at the path supplied by `image` relative to your project's images directory. """ if not Image: raise Exception("Images manipulation require PIL") filepath = String.unquoted(image).value path = None try: width = _image_size_cache[filepath][0] except KeyError: width = 0 IMAGES_ROOT = _images_root() if callable(IMAGES_ROOT): try: _file, _storage = list(IMAGES_ROOT(filepath))[0] path = _storage.open(_file) except: pass else: _path = os.path.join(IMAGES_ROOT, filepath.strip("/")) if os.path.exists(_path): path = open(_path, "rb") if path: image = Image.open(path) size = image.size width = size[0] _image_size_cache[filepath] = size return Number(width, "px")
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)
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('*'))))
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() == '"•"'
def image_width(image): """ Returns the width of the image found at the path supplied by `image` relative to your project's images directory. """ if not Image: raise SassMissingDependency('PIL', 'image manipulation') image_size_cache = _get_cache('image_size_cache') filepath = String.unquoted(image).value path = None try: width = image_size_cache[filepath][0] except KeyError: width = 0 IMAGES_ROOT = _images_root() if callable(IMAGES_ROOT): try: _file, _storage = list(IMAGES_ROOT(filepath))[0] except IndexError: pass else: path = _storage.open(_file) else: _path = os.path.join(IMAGES_ROOT, filepath.strip(os.sep)) if os.path.exists(_path): path = open(_path, 'rb') if path: image = Image.open(path) size = image.size width = size[0] image_size_cache[filepath] = size return Number(width, 'px')
def grad_color_stops(*args): args = List.from_maybe_starargs(args) color_stops = __color_stops(True, *args) ret = ', '.join([ 'color-stop(%s, %s)' % (s.render(), c.render()) for s, c in color_stops ]) return String.unquoted(ret)
def evaluate(self, calculator, divide=False): left = self.left.evaluate(calculator, divide=True) right = self.right.evaluate(calculator, divide=True) # Determine whether to actually evaluate, or just print the operator # literally. literal = False # If either operand starts with an interpolation, treat the whole # shebang as literal. if any(isinstance(operand, Interpolation) and operand.parts[0] == '' for operand in (self.left, self.right)): literal = True # Special handling of division: treat it as a literal slash if both # operands are literals, there are no parentheses, and this isn't 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. elif ( self.op is operator.truediv and not divide and isinstance(self.left, Literal) and isinstance(self.right, Literal) ): literal = True if literal: # TODO we don't currently preserve the spacing, whereas Sass # remembers whether there was space on either side op = " {0} ".format(self.OPERATORS[self.op]) return String.unquoted(left.render() + op + right.render()) return self.op(left, right)
def calculate(self, expression, divide=False): expression = self.evaluate_expression(expression, divide=divide) if expression is None: return String.unquoted(self.apply_vars(expression)) return expression
def calculate(self, expression, divide=False): result = self.evaluate_expression(expression, divide=divide) if result is None: return String.unquoted(self.apply_vars(expression)) return result
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)])
def __init__(self, scss_vars=None, scss_opts=None, scss_files=None, super_selector='', live_errors=False, library=None, func_registry=None, search_paths=None): self.super_selector = super_selector self._scss_vars = {} if scss_vars: calculator = Calculator() for var_name, value in scss_vars.items(): if isinstance(value, six.string_types): scss_value = calculator.evaluate_expression(value) if scss_value is None: # TODO warning? scss_value = String.unquoted(value) else: scss_value = value self._scss_vars[var_name] = scss_value self._scss_opts = scss_opts or {} self._scss_files = scss_files self._library = func_registry or library self._search_paths = search_paths # If true, swallow compile errors and embed them in the output instead self.live_errors = live_errors
def grayscale(color): if isinstance(color, Number): # grayscale(n) and grayscale(n%) are CSS3 filters and should be left # intact, but only when using the "a" spelling return String.unquoted("grayscale(%s)" % (color.render(),)) else: return greyscale(color)
def __init__( self, scss_vars=None, scss_opts=None, scss_files=None, super_selector='', live_errors=False, library=ALL_BUILTINS_LIBRARY, func_registry=None, search_paths=None): self.super_selector = super_selector self._scss_vars = {} if scss_vars: calculator = Calculator() for var_name, value in scss_vars.items(): if isinstance(value, six.string_types): scss_value = calculator.evaluate_expression(value) if scss_value is None: # TODO warning? scss_value = String.unquoted(value) else: scss_value = value self._scss_vars[var_name] = scss_value self._scss_opts = scss_opts or {} self._scss_files = scss_files # NOTE: func_registry is backwards-compatibility for only one user and # has never existed in a real release self._library = func_registry or library self._search_paths = search_paths # If true, swallow compile errors and embed them in the output instead self.live_errors = live_errors
def grayscale(color): if isinstance(color, Number) and color.is_unitless: # grayscale(n) is a CSS3 filter and should be left intact, but only # when using the "a" spelling return String.unquoted("grayscale(%d)" % (color.value, )) else: return greyscale(color)
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), String.unquoted(format).value)) else: fonts.append(_font_url(font, inline=inline)) return List(fonts)
def image_height(image): """ Returns the height of the image found at the path supplied by `image` relative to your project's images directory. """ if not Image: raise Exception("Images manipulation require PIL") filepath = String.unquoted(image).value path = None try: height = _image_size_cache[filepath][1] except KeyError: height = 0 IMAGES_ROOT = _images_root() if callable(IMAGES_ROOT): try: _file, _storage = list(IMAGES_ROOT(filepath))[0] except IndexError: pass else: path = _storage.open(_file) else: _path = os.path.join(IMAGES_ROOT, filepath.strip('/')) if os.path.exists(_path): path = open(_path, 'rb') if path: image = Image.open(path) size = image.size height = size[1] _image_size_cache[filepath] = size return Number(height, 'px')
def image_height(image): """ Returns the height of the image found at the path supplied by `image` relative to your project's images directory. """ if not Image: raise Exception("Images manipulation require PIL") filepath = String.unquoted(image).value path = None try: height = _image_size_cache[filepath][1] except KeyError: height = 0 IMAGES_ROOT = _images_root() if callable(IMAGES_ROOT): try: _file, _storage = list(IMAGES_ROOT(filepath))[0] except IndexError: pass else: path = _storage.open(_file) else: _path = os.path.join(IMAGES_ROOT, filepath.strip(os.sep)) if os.path.exists(_path): path = open(_path, 'rb') if path: image = Image.open(path) size = image.size height = size[1] _image_size_cache[filepath] = size return Number(height, 'px')
def has_sprite(map, sprite): 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}) return Boolean(bool(sprite))
def has_glyph(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}) return Boolean(bool(glyph))
def sprite_file(map, sprite): """ Returns the relative path (from the images directory) to the original file used when construction the sprite. This is suitable for passing to the image_width and image_height helpers. """ 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: return String(sprite[1][0]) return String.unquoted('')
def _font_url(path, only_path=False, cache_buster=True, inline=False): filepath = String.unquoted(path).value file = None FONTS_ROOT = _fonts_root() if callable(FONTS_ROOT): try: _file, _storage = list(FONTS_ROOT(filepath))[0] d_obj = _storage.modified_time(_file) filetime = int(time.mktime(d_obj.timetuple())) if inline: file = _storage.open(_file) except: filetime = 'NA' else: _path = os.path.join(FONTS_ROOT, filepath.strip('/')) if os.path.exists(_path): filetime = int(os.path.getmtime(_path)) if inline: file = open(_path, 'rb') else: filetime = 'NA' BASE_URL = config.FONTS_URL or config.STATIC_URL if file and inline: font_type = None if re.match(r'^([^?]+)[.](.*)([?].*)?$', path.value): font_type = String.unquoted(re.match(r'^([^?]+)[.](.*)([?].*)?$', path.value).groups()[1]).value if not FONT_TYPES.get(font_type): raise Exception('Could not determine font type for "%s"' % path.value) mime = FONT_TYPES.get(font_type) if font_type == 'woff': mime = 'application/font-woff' elif font_type == 'eot': mime = 'application/vnd.ms-fontobject' url = 'data:' + (mime if '/' in mime else 'font/%s' % mime) + ';base64,' + base64.b64encode(file.read()) file.close() else: url = '%s/%s' % (BASE_URL.rstrip('/'), filepath.lstrip('/')) if cache_buster and filetime != 'NA': url = add_cache_buster(url, filetime) if not only_path: url = 'url(%s)' % escape(url) return String.unquoted(url)
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('*'))) ])
def linear_gradient(*args): args = List.from_maybe_starargs(args) position_and_angle = _get_gradient_position_and_angle(args) color_stops = _get_gradient_color_stops(args) if color_stops is None: raise Exception('No color stops provided to linear-gradient function') color_stops = __color_stops(False, *color_stops) args = [ position(position_and_angle) if position_and_angle is not None else None, ] args.extend(_render_standard_color_stops(color_stops)) to__s = 'linear-gradient(' + ', '.join(to_str(a) for a in args or [] if a is not None) + ')' ret = String.unquoted(to__s) def to__css2(): return String.unquoted('') ret.to__css2 = to__css2 def to__moz(): return String.unquoted('-moz-' + to__s) ret.to__moz = to__moz def to__pie(): return String.unquoted('-pie-' + to__s) ret.to__pie = to__pie def to__ms(): return String.unquoted('-ms-' + to__s) ret.to__ms = to__ms def to__o(): return String.unquoted('-o-' + to__s) ret.to__o = to__o def to__webkit(): return String.unquoted('-webkit-' + to__s) ret.to__webkit = to__webkit def to__owg(): args = [ 'linear', position(position_and_angle or None), opposite_position(position_and_angle or None), ] args.extend('color-stop(%s, %s)' % (s.render(), c.render()) for s, c in color_stops) ret = '-webkit-gradient(' + ', '.join(to_str(a) for a in args if a is not None) + ')' return String.unquoted(ret) ret.to__owg = to__owg def to__svg(): return linear_svg_gradient(color_stops, position_and_angle or 'top') ret.to__svg = to__svg return ret
def to__owg(): args = [ 'linear', position(position_and_angle or None), opposite_position(position_and_angle or None), ] args.extend('color-stop(%s, %s)' % (s.render(), c.render()) for s, c in color_stops) ret = '-webkit-gradient(' + ', '.join(to_str(a) for a in args if a is not None) + ')' return String.unquoted(ret)
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)'))