Documentation
This commit is contained in:
parent
b050925ba0
commit
ba4fe2ea62
lesscpy
@ -0,0 +1,4 @@
|
||||
"""
|
||||
Main lesscss parse library. Contains lexer and parser, along with
|
||||
utility classes
|
||||
"""
|
@ -1,9 +1,11 @@
|
||||
# -*- coding: utf8 -*-
|
||||
"""
|
||||
LESSCPY Color functions
|
||||
.. module:: lesscpy.lessc.color
|
||||
:synopsis: Lesscpy Color functions
|
||||
|
||||
Copyright (c)
|
||||
See LICENSE for details.
|
||||
<jtm@robot.is>
|
||||
.. moduleauthor:: Jóhann T. Maríusson <jtm@robot.is>
|
||||
"""
|
||||
import colorsys
|
||||
from . import utility
|
||||
@ -11,8 +13,10 @@ from . import utility
|
||||
class Color():
|
||||
def process(self, expression):
|
||||
""" Process color expression
|
||||
@param tuple: color expression
|
||||
@return: string
|
||||
args:
|
||||
expression (tuple): color expression
|
||||
returns:
|
||||
str
|
||||
"""
|
||||
a, o, b = expression
|
||||
c1 = self._hextorgb(a)
|
||||
@ -25,23 +29,29 @@ class Color():
|
||||
r.append("%02x" % v)
|
||||
return ''.join(r)
|
||||
|
||||
def operate(self, a, b, o):
|
||||
def operate(self, left, right, operation):
|
||||
""" Do operation on colors
|
||||
@param string: color
|
||||
@param string: color
|
||||
@param string: operator
|
||||
args:
|
||||
left (str): left side
|
||||
right (str): right side
|
||||
operation (str): Operation
|
||||
returns:
|
||||
str
|
||||
"""
|
||||
operation = {
|
||||
'+': '__add__',
|
||||
'-': '__sub__',
|
||||
'*': '__mul__',
|
||||
'/': '__truediv__'
|
||||
}.get(o)
|
||||
v = getattr(a, operation)(b)
|
||||
return v
|
||||
}.get(operation)
|
||||
return getattr(left, operation)(right)
|
||||
|
||||
def rgb(self, *args):
|
||||
"""
|
||||
""" Translate rgb(...) to color string
|
||||
raises:
|
||||
ValueError
|
||||
returns:
|
||||
str
|
||||
"""
|
||||
if len(args) == 4:
|
||||
return self.rgba(*args)
|
||||
@ -57,7 +67,11 @@ class Color():
|
||||
raise ValueError('Illegal color values')
|
||||
|
||||
def rgba(self, *args):
|
||||
"""
|
||||
""" Translate rgba(...) to color string
|
||||
raises:
|
||||
ValueError
|
||||
returns:
|
||||
str
|
||||
"""
|
||||
if len(args) == 4:
|
||||
try:
|
||||
@ -71,7 +85,11 @@ class Color():
|
||||
raise ValueError('Illegal color values')
|
||||
|
||||
def hsl(self, *args):
|
||||
"""
|
||||
""" Translate hsl(...) to color string
|
||||
raises:
|
||||
ValueError
|
||||
returns:
|
||||
str
|
||||
"""
|
||||
if len(args) == 4:
|
||||
return self.hsla(*args)
|
||||
@ -85,7 +103,11 @@ class Color():
|
||||
raise ValueError('Illegal color values')
|
||||
|
||||
def hsla(self, *args):
|
||||
"""
|
||||
""" Translate hsla(...) to color string
|
||||
raises:
|
||||
ValueError
|
||||
returns:
|
||||
str
|
||||
"""
|
||||
if len(args) == 4:
|
||||
h, s, l, a = args
|
||||
@ -97,28 +119,46 @@ class Color():
|
||||
return "rgba(%s,%s,%s,%s)" % tuple(color)
|
||||
raise ValueError('Illegal color values')
|
||||
|
||||
def hue(self, *args):
|
||||
def hue(self, color, *args):
|
||||
""" Return the hue value of a color
|
||||
args:
|
||||
color (str): color
|
||||
raises:
|
||||
ValueError
|
||||
returns:
|
||||
float
|
||||
"""
|
||||
"""
|
||||
if args:
|
||||
h, l, s = self._hextohls(args[0])
|
||||
return round(h * 360, 3)
|
||||
if color:
|
||||
h, l, s = self._hextohls(color)
|
||||
return round(h * 360.0, 3)
|
||||
raise ValueError('Illegal color values')
|
||||
|
||||
def saturation(self, *args):
|
||||
def saturation(self, color, *args):
|
||||
""" Return the saturation value of a color
|
||||
args:
|
||||
color (str): color
|
||||
raises:
|
||||
ValueError
|
||||
returns:
|
||||
float
|
||||
"""
|
||||
"""
|
||||
if args:
|
||||
h, l, s = self._hextohls(args[0])
|
||||
return s * 100
|
||||
if color:
|
||||
h, l, s = self._hextohls(color)
|
||||
return s * 100.0
|
||||
raise ValueError('Illegal color values')
|
||||
|
||||
def lightness(self, *args):
|
||||
def lightness(self, color, *args):
|
||||
""" Return the lightness value of a color
|
||||
args:
|
||||
color (str): color
|
||||
raises:
|
||||
ValueError
|
||||
returns:
|
||||
float
|
||||
"""
|
||||
"""
|
||||
if args:
|
||||
h, l, s = self._hextohls(args[0])
|
||||
return l * 100
|
||||
if color:
|
||||
h, l, s = self._hextohls(color)
|
||||
return l * 100.0
|
||||
raise ValueError('Illegal color values')
|
||||
|
||||
def opacity(self, *args):
|
||||
@ -126,74 +166,97 @@ class Color():
|
||||
"""
|
||||
pass
|
||||
|
||||
def lighten(self, *args):
|
||||
def lighten(self, color, diff, *args):
|
||||
""" Lighten a color
|
||||
args:
|
||||
color (str): color
|
||||
diff (str): percentage
|
||||
returns:
|
||||
str
|
||||
"""
|
||||
"""
|
||||
if len(args) == 2:
|
||||
color, diff = args
|
||||
if color and diff:
|
||||
return self._ophsl(color, diff, 1, '__add__')
|
||||
raise ValueError('Illegal color values')
|
||||
|
||||
def darken(self, *args):
|
||||
def darken(self, color, diff, *args):
|
||||
""" Darken a color
|
||||
args:
|
||||
color (str): color
|
||||
diff (str): percentage
|
||||
returns:
|
||||
str
|
||||
"""
|
||||
"""
|
||||
if len(args) == 2:
|
||||
color, diff = args
|
||||
if color and diff:
|
||||
return self._ophsl(color, diff, 1, '__sub__')
|
||||
raise ValueError('Illegal color values')
|
||||
|
||||
def saturate(self, *args):
|
||||
def saturate(self, color, diff, *args):
|
||||
""" Saturate a color
|
||||
args:
|
||||
color (str): color
|
||||
diff (str): percentage
|
||||
returns:
|
||||
str
|
||||
"""
|
||||
"""
|
||||
if len(args) == 2:
|
||||
color, diff = args
|
||||
if color and diff:
|
||||
return self._ophsl(color, diff, 2, '__add__')
|
||||
raise ValueError('Illegal color values')
|
||||
|
||||
def desaturate(self, *args):
|
||||
def desaturate(self, color, diff, *args):
|
||||
""" Desaturate a color
|
||||
args:
|
||||
color (str): color
|
||||
diff (str): percentage
|
||||
returns:
|
||||
str
|
||||
"""
|
||||
"""
|
||||
if len(args) == 2:
|
||||
color, diff = args
|
||||
if color and diff:
|
||||
return self._ophsl(color, diff, 2, '__sub__')
|
||||
raise ValueError('Illegal color values')
|
||||
|
||||
def clamp(self, v):
|
||||
"""
|
||||
"""
|
||||
return min(1, max(0, v))
|
||||
def _clamp(self, value):
|
||||
# Clamp value
|
||||
return min(1, max(0, value))
|
||||
|
||||
def grayscale(self, *args):
|
||||
def grayscale(self, color, *args):
|
||||
""" Simply 100% desaturate.
|
||||
args:
|
||||
color (str): color
|
||||
returns:
|
||||
str
|
||||
"""
|
||||
Simply 100% desaturate.
|
||||
"""
|
||||
if len(args) == 2:
|
||||
return self.desaturate(args[0], 100)
|
||||
if color:
|
||||
return self.desaturate(color, 100.0)
|
||||
raise ValueError('Illegal color values')
|
||||
|
||||
def greyscale(self, *args):
|
||||
def greyscale(self, color, *args):
|
||||
"""Wrapper for grayscale, other spelling
|
||||
"""
|
||||
Wrapper for grayscale
|
||||
"""
|
||||
return self.grayscale(*args)
|
||||
return self.grayscale(color, *args)
|
||||
|
||||
def spin(self, *args):
|
||||
def spin(self, color, degree, *args):
|
||||
""" Spin color by degree. (Increase / decrease hue)
|
||||
args:
|
||||
color (str): color
|
||||
degree (str): percentage
|
||||
raises:
|
||||
ValueError
|
||||
returns:
|
||||
str
|
||||
"""
|
||||
"""
|
||||
if len(args) == 2:
|
||||
color, deg = args
|
||||
if type(deg) == str: deg = int(deg.strip('%'))
|
||||
if color and degree:
|
||||
if type(degree) == str:
|
||||
degree = int(degree.strip('%'))
|
||||
h, l, s = self._hextohls(color)
|
||||
h = ((h * 360) + deg) % 360
|
||||
h = 360 + h if h < 0 else h
|
||||
rgb = colorsys.hls_to_rgb(h / 360, l, s)
|
||||
h = ((h * 360.0) + degree) % 360.0
|
||||
h = 360.0 + h if h < 0 else h
|
||||
rgb = colorsys.hls_to_rgb(h / 360.0, l, s)
|
||||
color = (round(c * 255) for c in rgb)
|
||||
return self._rgbatohex(color)
|
||||
raise ValueError('Illegal color values')
|
||||
|
||||
def mix(self, *args):
|
||||
"""
|
||||
This algorithm factors in both the user-provided weight
|
||||
def mix(self, color1, color2, weight=50, *args):
|
||||
"""This algorithm factors in both the user-provided weight
|
||||
and the difference between the alpha values of the two colors
|
||||
to decide how to perform the weighted average of the two RGB values.
|
||||
|
||||
@ -216,19 +279,24 @@ class Color():
|
||||
|
||||
Copyright (c) 2006-2009 Hampton Catlin, Nathan Weizenbaum, and Chris Eppstein
|
||||
http://sass-lang.com
|
||||
args:
|
||||
color1 (str): first color
|
||||
color2 (str): second color
|
||||
weight (int/str): weight
|
||||
raises:
|
||||
ValueError
|
||||
returns:
|
||||
str
|
||||
"""
|
||||
if len(args) >= 2:
|
||||
try:
|
||||
c1, c2, w = args
|
||||
except ValueError:
|
||||
c1, c2 = args
|
||||
w = 50
|
||||
if type(w) == str: w = int(w.strip('%'))
|
||||
w = ((w / 100.0) * 2) - 1
|
||||
rgb1 = self._hextorgb(c1)
|
||||
rgb2 = self._hextorgb(c2)
|
||||
a = 0
|
||||
w1 = (((w if w * a == -1 else w + a) / (1 + w * a)) + 1)
|
||||
if color1 and color2:
|
||||
if type(weight) == str:
|
||||
weight = int(weight.strip('%'))
|
||||
weight = ((weight / 100.0) * 2) - 1
|
||||
rgb1 = self._hextorgb(color1)
|
||||
rgb2 = self._hextorgb(color2)
|
||||
alpha = 0
|
||||
w1 = (((weight if weight * alpha == -1
|
||||
else weight + alpha) / (1 + weight * alpha)) + 1)
|
||||
w1 = w1 / 2.0
|
||||
w2 = 1 - w1
|
||||
rgb = [
|
||||
@ -240,10 +308,14 @@ class Color():
|
||||
raise ValueError('Illegal color values')
|
||||
|
||||
def fmt(self, color):
|
||||
"""
|
||||
Format CSS Hex color code.
|
||||
""" Format CSS Hex color code.
|
||||
uppercase becomes lowercase, 3 digit codes expand to 6 digit.
|
||||
@param string: color
|
||||
args:
|
||||
color (str): color
|
||||
raises:
|
||||
ValueError
|
||||
returns:
|
||||
str
|
||||
"""
|
||||
if utility.is_color(color):
|
||||
color = color.lower().strip('#')
|
||||
@ -253,8 +325,6 @@ class Color():
|
||||
raise ValueError('Cannot format non-color')
|
||||
|
||||
def _rgbatohex(self, rgba):
|
||||
"""
|
||||
"""
|
||||
return '#%s' % ''.join(["%02x" % v for v in
|
||||
[0xff
|
||||
if h > 0xff else
|
||||
@ -262,8 +332,6 @@ class Color():
|
||||
for h in rgba]
|
||||
])
|
||||
def _hextorgb(self, hex):
|
||||
"""
|
||||
"""
|
||||
hex = hex.strip()
|
||||
if hex[0] == '#':
|
||||
hex = hex.strip('#').strip(';')
|
||||
@ -275,17 +343,13 @@ class Color():
|
||||
return [int(hex, 16)] * 3
|
||||
|
||||
def _hextohls(self, hex):
|
||||
"""
|
||||
"""
|
||||
rgb = self._hextorgb(hex)
|
||||
return colorsys.rgb_to_hls(*[c / 255.0 for c in rgb])
|
||||
|
||||
def _ophsl(self, color, diff, idx, op):
|
||||
"""
|
||||
"""
|
||||
if type(diff) == str: diff = int(diff.strip('%'))
|
||||
hls = list(self._hextohls(color))
|
||||
hls[idx] = self.clamp(getattr(hls[idx], op)(diff / 100))
|
||||
hls[idx] = self._clamp(getattr(hls[idx], op)(diff / 100))
|
||||
rgb = colorsys.hls_to_rgb(*hls)
|
||||
color = (round(c * 255) for c in rgb)
|
||||
return self._rgbatohex(color)
|
||||
|
@ -1,6 +1,6 @@
|
||||
# -*- coding: utf8 -*-
|
||||
"""
|
||||
.. module:: parser
|
||||
.. module:: lesscpy.lessc.parser
|
||||
:synopsis: Lesscss parser.
|
||||
|
||||
http://www.dabeaz.com/ply/ply.html
|
||||
@ -33,7 +33,8 @@ class LessParser(object):
|
||||
scope=None,
|
||||
outputdir='/tmp',
|
||||
importlvl=0,
|
||||
verbose=False):
|
||||
verbose=False
|
||||
):
|
||||
""" Parser object
|
||||
|
||||
Kwargs:
|
||||
|
@ -1,16 +1,29 @@
|
||||
"""
|
||||
.. module:: lesscpy.lessc.scope
|
||||
:synopsis: Scope class.
|
||||
|
||||
|
||||
Copyright (c)
|
||||
See LICENSE for details.
|
||||
.. moduleauthor:: Jóhann T. Maríusson <jtm@robot.is>
|
||||
"""
|
||||
from . import utility
|
||||
|
||||
class Scope(list):
|
||||
""" Scope class. A stack implementation.
|
||||
"""
|
||||
def __init__(self, init=False):
|
||||
"""Scope
|
||||
Args:
|
||||
init (bool): Initiate scope
|
||||
"""
|
||||
super().__init__()
|
||||
self._mixins = {}
|
||||
if init: self.push()
|
||||
self.in_mixin = False
|
||||
|
||||
def push(self):
|
||||
"""
|
||||
"""Push level on scope
|
||||
"""
|
||||
self.append({
|
||||
'__variables__' : {},
|
||||
@ -29,7 +42,9 @@ class Scope(list):
|
||||
|
||||
@property
|
||||
def scopename(self):
|
||||
"""
|
||||
"""Current scope name as list
|
||||
Returns:
|
||||
list
|
||||
"""
|
||||
return [r['__current__']
|
||||
for r in self
|
||||
@ -37,13 +52,17 @@ class Scope(list):
|
||||
|
||||
|
||||
def add_block(self, block):
|
||||
"""
|
||||
"""Add block element to scope
|
||||
Args:
|
||||
block (Block): Block object
|
||||
"""
|
||||
self[-1]['__blocks__'].append(block)
|
||||
self[-1]['__names__'].append(block.raw())
|
||||
|
||||
def add_mixin(self, mixin):
|
||||
"""
|
||||
"""Add mixin to scope
|
||||
Args:
|
||||
mixin (Mixin): Mixin object
|
||||
"""
|
||||
raw = mixin.name.raw()
|
||||
if raw in self._mixins:
|
||||
@ -52,13 +71,18 @@ class Scope(list):
|
||||
self._mixins[raw] = [mixin]
|
||||
|
||||
def add_variable(self, variable):
|
||||
"""
|
||||
"""Add variable to scope
|
||||
Args:
|
||||
variable (Variable): Variable object
|
||||
"""
|
||||
self[-1]['__variables__'][variable.name] = variable
|
||||
|
||||
def variables(self, name):
|
||||
"""
|
||||
Search for variable by name
|
||||
"""Search for variable by name. Searches scope top down
|
||||
Args:
|
||||
name (string): Search term
|
||||
Returns:
|
||||
Variable object OR False
|
||||
"""
|
||||
if type(name) is tuple:
|
||||
name = name[0]
|
||||
@ -70,17 +94,19 @@ class Scope(list):
|
||||
return False
|
||||
|
||||
def mixins(self, name):
|
||||
"""
|
||||
Search mixins for name.
|
||||
Allow '>' to be ignored.
|
||||
""" Search mixins for name.
|
||||
Allow '>' to be ignored. '.a .b()' == '.a > .b()'
|
||||
Args:
|
||||
name (string): Search term
|
||||
Returns:
|
||||
Mixin object list OR False
|
||||
"""
|
||||
m = self._smixins(name)
|
||||
if m: return m
|
||||
return self._smixins(name.replace('?>?', ' '))
|
||||
|
||||
def _smixins(self, name):
|
||||
"""
|
||||
Inner wrapper to search for mixins by name.
|
||||
"""Inner wrapper to search for mixins by name.
|
||||
"""
|
||||
return (self._mixins[name]
|
||||
if name in self._mixins
|
||||
@ -89,15 +115,18 @@ class Scope(list):
|
||||
def blocks(self, name):
|
||||
"""
|
||||
Search for defined blocks recursively.
|
||||
Allow '>' to be ignored.
|
||||
Allow '>' to be ignored. '.a .b' == '.a > .b'
|
||||
Args:
|
||||
name (string): Search term
|
||||
Returns:
|
||||
Block object OR False
|
||||
"""
|
||||
b = self._blocks(name)
|
||||
if b: return b
|
||||
return self._blocks(name.replace('?>?', ' '))
|
||||
|
||||
def _blocks(self, name):
|
||||
"""
|
||||
Inner wrapper to search for blocks by name.
|
||||
"""Inner wrapper to search for blocks by name.
|
||||
"""
|
||||
i = len(self)
|
||||
while i >= 0:
|
||||
@ -116,7 +145,11 @@ class Scope(list):
|
||||
return False
|
||||
|
||||
def update(self, scope, at=0):
|
||||
"""
|
||||
"""Update scope. Add another scope to this one.
|
||||
Args:
|
||||
scope (Scope): Scope object
|
||||
Kwargs:
|
||||
at (int): Level to update
|
||||
"""
|
||||
if hasattr(scope, '_mixins') and not at:
|
||||
self._mixins.update(scope._mixins)
|
||||
@ -125,13 +158,19 @@ class Scope(list):
|
||||
self[at]['__names__'].extend(scope[at]['__names__'])
|
||||
|
||||
def swap(self, name):
|
||||
"""
|
||||
""" Swap variable name for variable value
|
||||
Args:
|
||||
name (str): Variable name
|
||||
Returns:
|
||||
Variable value (Mixed)
|
||||
"""
|
||||
if name.startswith('@@'):
|
||||
var = self.variables(name[1:])
|
||||
if var is False: raise SyntaxError('Unknown variable %s' % name)
|
||||
if var is False:
|
||||
raise SyntaxError('Unknown variable %s' % name)
|
||||
name = '@' + utility.destring(var.value[0])
|
||||
var = self.variables(name)
|
||||
if var is False: raise SyntaxError('Unknown variable %s' % name)
|
||||
if var is False:
|
||||
raise SyntaxError('Unknown variable %s' % name)
|
||||
return var.value
|
||||
|
@ -1,41 +1,52 @@
|
||||
# -*- coding: utf8 -*-
|
||||
"""
|
||||
Utility functions
|
||||
.. module:: lesscpy.lessc.utility
|
||||
:synopsis: various utility functions
|
||||
|
||||
Copyright (c)
|
||||
See LICENSE for details.
|
||||
<jtm@robot.is>
|
||||
.. moduleauthor:: Jóhann T. Maríusson <jtm@robot.is>
|
||||
"""
|
||||
import collections
|
||||
import re
|
||||
|
||||
def flatten(ll):
|
||||
def flatten(lst):
|
||||
"""Flatten list.
|
||||
Args:
|
||||
lst (list): List to flatten
|
||||
Returns:
|
||||
generator
|
||||
"""
|
||||
Flatten list.
|
||||
@param ll: list
|
||||
@return: generator
|
||||
"""
|
||||
for el in ll:
|
||||
if isinstance(el, collections.Iterable) and not isinstance(el, str):
|
||||
for sub in flatten(el):
|
||||
for elm in lst:
|
||||
if isinstance(elm, collections.Iterable) and not isinstance(elm, str):
|
||||
for sub in flatten(elm):
|
||||
yield sub
|
||||
else:
|
||||
yield el
|
||||
yield elm
|
||||
|
||||
def pairwise(lst):
|
||||
""" yield item i and item i+1 in lst. e.g.
|
||||
(lst[0], lst[1]), (lst[1], lst[2]), ..., (lst[-1], None)
|
||||
Args:
|
||||
lst (list): List to process
|
||||
Returns:
|
||||
list
|
||||
"""
|
||||
if not lst: return
|
||||
l = len(lst)
|
||||
for i in range(l-1):
|
||||
if not lst:
|
||||
return
|
||||
length = len(lst)
|
||||
for i in range(length-1):
|
||||
yield lst[i], lst[i+1]
|
||||
yield lst[-1], None
|
||||
|
||||
def rename(ll, scope):
|
||||
def rename(blocks, scope):
|
||||
""" Rename all sub-blocks moved under another
|
||||
block. (mixins)
|
||||
Args:
|
||||
lst (list): block list
|
||||
scope (object): Scope object
|
||||
"""
|
||||
for p in ll:
|
||||
for p in blocks:
|
||||
if hasattr(p, 'inner'):
|
||||
p.name.parse(scope)
|
||||
if p.inner:
|
||||
@ -45,7 +56,11 @@ def rename(ll, scope):
|
||||
scope.pop()
|
||||
|
||||
def blocksearch(block, name):
|
||||
""" Recursive search for name in block
|
||||
""" Recursive search for name in block (inner blocks)
|
||||
Args:
|
||||
name (str): search term
|
||||
Returns:
|
||||
Block OR False
|
||||
"""
|
||||
for b in block.inner:
|
||||
b = (b if b.raw() == name
|
||||
@ -53,43 +68,59 @@ def blocksearch(block, name):
|
||||
if b: return b
|
||||
return False
|
||||
|
||||
def reverse_guard(ll):
|
||||
"""
|
||||
def reverse_guard(lst):
|
||||
""" Reverse guard expression. not
|
||||
(@a > 5) -> (@a <= 5)
|
||||
Args:
|
||||
lst (list): Expression
|
||||
returns:
|
||||
list
|
||||
"""
|
||||
rev = {
|
||||
'<': '>',
|
||||
'>': '<',
|
||||
'<': '>=',
|
||||
'>': '<=',
|
||||
'=': '!=',
|
||||
'!=': '=',
|
||||
'>=': '<=',
|
||||
'<=': '>='
|
||||
'>=': '<',
|
||||
'<=': '>'
|
||||
}
|
||||
return [rev[l] if l in rev else l for l in ll]
|
||||
return [rev[l] if l in rev else l for l in lst]
|
||||
|
||||
def debug_print(ll, lvl=0):
|
||||
"""
|
||||
def debug_print(lst, lvl=0):
|
||||
""" Print scope tree
|
||||
args:
|
||||
lst (list): parse result
|
||||
lvl (int): current nesting level
|
||||
"""
|
||||
pad = ''.join(['\t.'] * lvl)
|
||||
t = type(ll)
|
||||
t = type(lst)
|
||||
if t is list:
|
||||
for p in ll:
|
||||
for p in lst:
|
||||
debug_print(p, lvl)
|
||||
elif hasattr(ll, 'tokens'):
|
||||
elif hasattr(lst, 'tokens'):
|
||||
print(pad, t)
|
||||
debug_print(list(flatten(ll.tokens)), lvl+1)
|
||||
debug_print(list(flatten(lst.tokens)), lvl+1)
|
||||
|
||||
def destring(v):
|
||||
""" Strip quotes
|
||||
@param string: value
|
||||
@return: string
|
||||
def destring(value):
|
||||
""" Strip quotes from string
|
||||
args:
|
||||
value (str)
|
||||
returns:
|
||||
str
|
||||
"""
|
||||
return v.strip('"\'')
|
||||
return value.strip('"\'')
|
||||
|
||||
def analyze_number(var, err=''):
|
||||
""" Analyse number for type and split from unit
|
||||
@param str: value
|
||||
@raises: SyntaxError
|
||||
@return: tuple (number, unit)
|
||||
1px -> (q, 'px')
|
||||
args:
|
||||
var (str): number string
|
||||
kwargs:
|
||||
err (str): Error message
|
||||
raises:
|
||||
SyntaxError
|
||||
returns:
|
||||
tuple
|
||||
"""
|
||||
n, u = split_unit(var)
|
||||
if type(var) is not str:
|
||||
@ -104,74 +135,94 @@ def analyze_number(var, err=''):
|
||||
raise SyntaxError('%s ´%s´' % (err, var))
|
||||
return (n, u)
|
||||
|
||||
def with_unit(n, u=None):
|
||||
def with_unit(number, unit=None):
|
||||
""" Return number with unit
|
||||
@param int/float: value
|
||||
@param str: unit
|
||||
@return: mixed
|
||||
args:
|
||||
number (mixed): Number
|
||||
unit (str): Unit
|
||||
returns:
|
||||
str
|
||||
"""
|
||||
if type(n) is tuple:
|
||||
n, u = n
|
||||
if n == 0: return 0
|
||||
if u:
|
||||
n = str(n)
|
||||
if n.startswith('.'):
|
||||
n = '0' + n
|
||||
return "%s%s" % (n, u)
|
||||
return n
|
||||
if type(number) is tuple:
|
||||
number, unit = number
|
||||
if number == 0:
|
||||
return '0'
|
||||
if unit:
|
||||
number = str(number)
|
||||
if number.startswith('.'):
|
||||
number = '0' + number
|
||||
return "%s%s" % (number, unit)
|
||||
return number if type(number) is str else str(number)
|
||||
|
||||
def is_color(v):
|
||||
""" Is CSS color
|
||||
@param mixed: value
|
||||
@return: bool
|
||||
def is_color(value):
|
||||
""" Is string CSS color
|
||||
args:
|
||||
value (str): string
|
||||
returns:
|
||||
bool
|
||||
"""
|
||||
if not v or type(v) is not str:
|
||||
if not value or type(value) is not str:
|
||||
return False
|
||||
if v[0] == '#' and len(v) in [4, 5, 7, 9]:
|
||||
if value[0] == '#' and len(value) in [4, 5, 7, 9]:
|
||||
try:
|
||||
int(v[1:], 16)
|
||||
int(value[1:], 16)
|
||||
return True
|
||||
except Exception:
|
||||
except ValueError:
|
||||
pass
|
||||
return False
|
||||
|
||||
def is_variable(v):
|
||||
def is_variable(value):
|
||||
""" Check if string is LESS variable
|
||||
@param string: check
|
||||
@return: bool
|
||||
args:
|
||||
value (str): string
|
||||
returns:
|
||||
bool
|
||||
"""
|
||||
if type(v) is str:
|
||||
return (v.startswith('@') or v.startswith('-@'))
|
||||
elif type(v) is tuple:
|
||||
v = ''.join(v)
|
||||
return (v.startswith('@') or v.startswith('-@'))
|
||||
if type(value) is str:
|
||||
return (value.startswith('@') or value.startswith('-@'))
|
||||
elif type(value) is tuple:
|
||||
value = ''.join(value)
|
||||
return (value.startswith('@') or value.startswith('-@'))
|
||||
return False
|
||||
|
||||
def is_int(v):
|
||||
def is_int(value):
|
||||
""" Is value integer
|
||||
args:
|
||||
value (str): string
|
||||
returns:
|
||||
bool
|
||||
"""
|
||||
try:
|
||||
int(str(v))
|
||||
int(str(value))
|
||||
return True
|
||||
except (ValueError, TypeError):
|
||||
pass
|
||||
return False
|
||||
|
||||
def is_float(v):
|
||||
def is_float(value):
|
||||
""" Is value float
|
||||
args:
|
||||
value (str): string
|
||||
returns:
|
||||
bool
|
||||
"""
|
||||
if not is_int(v):
|
||||
if not is_int(value):
|
||||
try:
|
||||
float(str(v))
|
||||
float(str(value))
|
||||
return True
|
||||
except (ValueError, TypeError):
|
||||
pass
|
||||
return False
|
||||
|
||||
def split_unit(v):
|
||||
def split_unit(value):
|
||||
""" Split a number from its unit
|
||||
1px -> (q, 'px')
|
||||
Args:
|
||||
value (str): input
|
||||
returns:
|
||||
tuple
|
||||
"""
|
||||
r = re.search('^(\-?[\d\.]+)(.*)$', str(v))
|
||||
r = re.search('^(\-?[\d\.]+)(.*)$', str(value))
|
||||
return r.groups() if r else ('','')
|
||||
|
||||
|
||||
|
@ -86,9 +86,9 @@ class TestUtility(unittest.TestCase):
|
||||
self.assertEqual('1.0px', test(1.0, 'px'))
|
||||
self.assertEqual('0.0px', test('.0', 'px'))
|
||||
self.assertEqual('0.6px', test(.6, 'px'))
|
||||
self.assertEqual(1, test(1))
|
||||
self.assertEqual(1, test(1, None))
|
||||
self.assertEqual(1, test(1,))
|
||||
self.assertEqual('1', test(1))
|
||||
self.assertEqual('1', test(1, None))
|
||||
self.assertEqual('1', test(1,))
|
||||
|
||||
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user