def proxy(*args, **kwargs): """ Proxy function """ from tdi import c if c.load(test) is None: skip("c extension not found") for mod in module: reload(mod) return func(*args, **kwargs)
def proxy(*args, **kwargs): """ Proxy function """ from tdi import c if c.load(test) is None: raise SkipTest("c extension not found") for mod in module: reload(mod) return func(*args, **kwargs)
def test_load_none(imp, os): """ c.load() returns None if overridden """ imp.side_effect = [] os.environ.get.side_effect = ["1"] result = _c.load('foo') assert_equals(result, None) assert_equals(map(tuple, imp.mock_calls), []) assert_equals(map(tuple, os.mock_calls), [ ('environ.get', ('TDI_NO_C_OVERRIDE',), {}), ])
def test_load_tpl(imp, os, glob, loc): """ c.load() accepts different template """ imp.side_effect = ['lalala'] os.environ.get.side_effect = [None] glob.side_effect = [dict(a=1, b=2)] loc.side_effect = [dict(c=4, d=5)] result = _c.load('foo', tpl='_xx_%s_yy_') assert_equals(result, 'lalala') assert_equals(map(tuple, imp.mock_calls), [ ('', ('_xx_foo_yy_', {'a': 1, 'b': 2}, {'c': 4, 'd': 5}, ['*']), {}), ]) assert_equals(map(tuple, os.mock_calls), [ ('environ.get', ('TDI_NO_C_OVERRIDE',), {}), ]) assert_equals(map(tuple, glob.mock_calls), [('', (), {})]) assert_equals(map(tuple, loc.mock_calls), [('', (), {})])
def test_load_override(imp, os, glob, loc): """ c.load() accepts different override """ imp.side_effect = ['lalala'] os.environ.get.side_effect = [None] glob.side_effect = [dict(a=1, b=2)] loc.side_effect = [dict(c=4, d=5)] result = _c.load('foo', env_override='YO') assert_equals(result, 'lalala') assert_equals(map(tuple, imp.mock_calls), [ ('', ('tdi.c._tdi_foo', {'a': 1, 'b': 2}, {'c': 4, 'd': 5}, ['*']), {}), ]) assert_equals(map(tuple, os.mock_calls), [ ('environ.get', ('YO',), {}), ]) assert_equals(map(tuple, glob.mock_calls), [('', (), {})]) assert_equals(map(tuple, loc.mock_calls), [('', (), {})])
def test_load(imp, os, glob, loc): """ c.load() imports and returns a module """ imp.side_effect = ['lalala'] os.environ.get.side_effect = [None] glob.side_effect = [dict(a=1, b=2)] loc.side_effect = [dict(c=4, d=5)] result = _c.load('foo') assert_equals(result, 'lalala') assert_equals(map(tuple, imp.mock_calls), [ ('', ('tdi.c._tdi_foo', {'a': 1, 'b': 2}, {'c': 4, 'd': 5}, ['*']), {}), ]) assert_equals(map(tuple, os.mock_calls), [ ('environ.get', ('TDI_NO_C_OVERRIDE',), {}), ]) assert_equals(map(tuple, glob.mock_calls), [('', (), {})]) assert_equals(map(tuple, loc.mock_calls), [('', (), {})])
def test_load_space_delc(imp, os, glob, loc): """ c.load() modifies space and deletes 'c' """ mod = _test.Bunch(bar='BAZ', plop='blub') imp.side_effect = [mod] os.environ.get.side_effect = [None] glob.side_effect = [dict(a=1, b=2)] loc.side_effect = [dict(c=4, d=5)] space = dict(plop=42, c='something', d='else') result = _c.load('foo', space) assert_equals(space, {'plop': 'blub', 'd': 'else'}) assert_equals(result, mod) assert_equals(map(tuple, imp.mock_calls), [ ('', ('tdi.c._tdi_foo', {'a': 1, 'b': 2}, {'c': 4, 'd': 5}, ['*']), {}), ]) assert_equals(map(tuple, os.mock_calls), [ ('environ.get', ('TDI_NO_C_OVERRIDE',), {}), ]) assert_equals(map(tuple, glob.mock_calls), [('', (), {})]) assert_equals(map(tuple, loc.mock_calls), [('', (), {})])
flags = node.hiddenelement and '-' or '+' if noauto: flags += '*' if sep: flags += ':' node[tdi_attr] = flags + name node.hiddenelement = False def separate(node, ctx): """ Separator """ node.ctx = ctx return render(node, sep=True) node.repeat(repeat, (0, 1), node.ctx, separate=separate) if name is None: return setscope return render self.modelmethod = modelmethod self.new = new return self from tdi import c c = c.load('impl') if c is not None: RenderAdapter = c.RenderAdapter del c
def _make_decode(): """ Make decoder """ # pylint: disable = R0912 from tdi import c c = c.load('impl') if c is not None: return c.htmldecode sub = _re.compile(ur'&([^& \t\n\r\f;]*);').sub unicode_, unichr_, str_, int_ = unicode, unichr, str, int isinstance_ = isinstance default_entities = dict(_htmlentities.htmlentities) # pylint: disable = W0621 def decode(value, encoding='latin-1', errors='strict', entities=None): """ Decode HTML encoded text :Parameters: `value` : ``basestring`` HTML content to decode `encoding` : ``str`` Unicode encoding to be applied before value is being processed further. If value is already a unicode instance, the encoding is ignored. If omitted, 'latin-1' is applied (because it can't fail and maps bytes 1:1 to unicode codepoints). `errors` : ``str`` Error handling, passed to .decode() and evaluated for entities. If the entity name or character codepoint could not be found or not be parsed then the error handler has the following semantics: ``strict`` (or anything different from the other tokens below) A ``ValueError`` is raised. ``ignore`` The original entity is passed through ``replace`` The character is replaced by the replacement character (U+FFFD) `entities` : ``dict`` Entity name mapping (unicode(name) -> unicode(value)). If omitted or ``None``, the `HTML5 entity list`_ is applied. .. _HTML5 entity list: http://www.w3.org/TR/html5/ syntax.html#named-character-references :Return: The decoded content :Rtype: ``unicode`` """ # pylint: disable = E1101 # pylint: disable = R0912 if not isinstance_(value, unicode_): value = str_(value).decode(encoding, errors) if entities is None: entities = default_entities def subber(match): """ Substituter """ name = match.group(1) if not name.startswith(u'#'): try: return entities[name] except KeyError: pass else: if name.startswith(u'#x') or name.startswith(u'#X'): base = 16 name = name[2:] else: base = 10 name = name[1:] try: return unichr_(int_(name, base)) except (ValueError, TypeError, OverflowError): pass if errors == 'ignore': return match.group(0) elif errors == 'replace': return u'\ufffd' else: raise ValueError( "Unresolved entity %r" % (match.group(0),) ) return sub(subber, value) return decode
def _make_cssmin(python_only=False): """ Generate CSS minifier. :Parameters: `python_only` : ``bool`` Use only the python variant. If true, the c extension is not even tried to be loaded. (tdi.c._tdi_rcssmin) :Return: Minifier :Rtype: ``callable`` """ # pylint: disable = W0612 # ("unused" variables) # pylint: disable = R0911, R0912, R0914, R0915 # (too many anything) if not python_only: from tdi import c rcssmin = c.load('rcssmin') if rcssmin is not None: return rcssmin.cssmin nl = r'(?:[\n\f]|\r\n?)' # pylint: disable = C0103 spacechar = r'[\r\n\f\040\t]' unicoded = r'[0-9a-fA-F]{1,6}(?:[\040\n\t\f]|\r\n?)?' escaped = r'[^\n\r\f0-9a-fA-F]' escape = r'(?:\\(?:%(unicoded)s|%(escaped)s))' % locals() nmchar = r'[^\000-\054\056\057\072-\100\133-\136\140\173-\177]' #nmstart = r'[^\000-\100\133-\136\140\173-\177]' #ident = (r'(?:' # r'-?(?:%(nmstart)s|%(escape)s)%(nmchar)s*(?:%(escape)s%(nmchar)s*)*' #r')') % locals() comment = r'(?:/\*[^*]*\*+(?:[^/*][^*]*\*+)*/)' # only for specific purposes. The bang is grouped: _bang_comment = r'(?:/\*(!?)[^*]*\*+(?:[^/*][^*]*\*+)*/)' string1 = \ r'(?:\047[^\047\\\r\n\f]*(?:\\[^\r\n\f][^\047\\\r\n\f]*)*\047)' string2 = r'(?:"[^"\\\r\n\f]*(?:\\[^\r\n\f][^"\\\r\n\f]*)*")' strings = r'(?:%s|%s)' % (string1, string2) nl_string1 = \ r'(?:\047[^\047\\\r\n\f]*(?:\\(?:[^\r]|\r\n?)[^\047\\\r\n\f]*)*\047)' nl_string2 = r'(?:"[^"\\\r\n\f]*(?:\\(?:[^\r]|\r\n?)[^"\\\r\n\f]*)*")' nl_strings = r'(?:%s|%s)' % (nl_string1, nl_string2) uri_nl_string1 = r'(?:\047[^\047\\]*(?:\\(?:[^\r]|\r\n?)[^\047\\]*)*\047)' uri_nl_string2 = r'(?:"[^"\\]*(?:\\(?:[^\r]|\r\n?)[^"\\]*)*")' uri_nl_strings = r'(?:%s|%s)' % (uri_nl_string1, uri_nl_string2) nl_escaped = r'(?:\\%(nl)s)' % locals() space = r'(?:%(spacechar)s|%(comment)s)' % locals() ie7hack = r'(?:>/\*\*/)' uri = (r'(?:' r'(?:[^\000-\040"\047()\\\177]*' r'(?:%(escape)s[^\000-\040"\047()\\\177]*)*)' r'(?:' r'(?:%(spacechar)s+|%(nl_escaped)s+)' r'(?:' r'(?:[^\000-\040"\047()\\\177]|%(escape)s|%(nl_escaped)s)' r'[^\000-\040"\047()\\\177]*' r'(?:%(escape)s[^\000-\040"\047()\\\177]*)*' r')+' r')*' r')') % locals() nl_unesc_sub = _re.compile(nl_escaped).sub uri_space_sub = _re.compile(( r'(%(escape)s+)|%(spacechar)s+|%(nl_escaped)s+' ) % locals()).sub uri_space_subber = lambda m: m.groups()[0] or '' space_sub_simple = _re.compile(( r'[\r\n\f\040\t;]+|(%(comment)s+)' ) % locals()).sub space_sub_banged = _re.compile(( r'[\r\n\f\040\t;]+|(%(_bang_comment)s+)' ) % locals()).sub post_esc_sub = _re.compile(r'[\r\n\f\t]+').sub main_sub = _re.compile(( r'([^\\"\047u>@\r\n\f\040\t/;:{}]+)' r'|(?<=[{}(=:>+[,!])(%(space)s+)' r'|^(%(space)s+)' r'|(%(space)s+)(?=(([:{});=>+\],!])|$)?)' r'|;(%(space)s*(?:;%(space)s*)*)(?=(\})?)' r'|(\{)' r'|(\})' r'|(%(strings)s)' r'|(?<!%(nmchar)s)url\(%(spacechar)s*(' r'%(uri_nl_strings)s' r'|%(uri)s' r')%(spacechar)s*\)' r'|(@(?:' r'[mM][eE][dD][iI][aA]' r'|[sS][uU][pP][pP][oO][rR][tT][sS]' r'|[dD][oO][cC][uU][mM][eE][nN][tT]' r'|(?:-(?:' r'[wW][eE][bB][kK][iI][tT]|[mM][oO][zZ]|[oO]|[mM][sS]' r')-)?' r'[kK][eE][yY][fF][rR][aA][mM][eE][sS]' r'))(?!%(nmchar)s)' r'|(%(ie7hack)s)(%(space)s*)' r'|(:[fF][iI][rR][sS][tT]-[lL]' r'(?:[iI][nN][eE]|[eE][tT][tT][eE][rR]))' r'(%(space)s*)(?=[{,])' r'|(%(nl_strings)s)' r'|(%(escape)s[^\\"\047u>@\r\n\f\040\t/;:{}]*)' ) % locals()).sub #print main_sub.__self__.pattern def main_subber(keep_bang_comments): """ Make main subber """ in_macie5, in_rule, at_group = [0], [0], [0] if keep_bang_comments: space_sub = space_sub_banged def space_subber(match): """ Space|Comment subber """ if match.lastindex: group1, group2 = match.group(1, 2) if group2: if group1.endswith(r'\*/'): in_macie5[0] = 1 else: in_macie5[0] = 0 return group1 elif group1: if group1.endswith(r'\*/'): if in_macie5[0]: return '' in_macie5[0] = 1 return r'/*\*/' elif in_macie5[0]: in_macie5[0] = 0 return '/**/' return '' else: space_sub = space_sub_simple def space_subber(match): """ Space|Comment subber """ if match.lastindex: if match.group(1).endswith(r'\*/'): if in_macie5[0]: return '' in_macie5[0] = 1 return r'/*\*/' elif in_macie5[0]: in_macie5[0] = 0 return '/**/' return '' def fn_space_post(group): """ space with token after """ if group(5) is None or ( group(6) == ':' and not in_rule[0] and not at_group[0]): return ' ' + space_sub(space_subber, group(4)) return space_sub(space_subber, group(4)) def fn_semicolon(group): """ ; handler """ return ';' + space_sub(space_subber, group(7)) def fn_semicolon2(group): """ ; handler """ if in_rule[0]: return space_sub(space_subber, group(7)) return ';' + space_sub(space_subber, group(7)) def fn_open(group): """ { handler """ # pylint: disable = W0613 if at_group[0]: at_group[0] -= 1 else: in_rule[0] = 1 return '{' def fn_close(group): """ } handler """ # pylint: disable = W0613 in_rule[0] = 0 return '}' def fn_at_group(group): """ @xxx group handler """ at_group[0] += 1 return group(13) def fn_ie7hack(group): """ IE7 Hack handler """ if not in_rule[0] and not at_group[0]: in_macie5[0] = 0 return group(14) + space_sub(space_subber, group(15)) return '>' + space_sub(space_subber, group(15)) table = ( None, None, None, None, fn_space_post, # space with token after fn_space_post, # space with token after fn_space_post, # space with token after fn_semicolon, # semicolon fn_semicolon2, # semicolon fn_open, # { fn_close, # } lambda g: g(11), # string lambda g: 'url(%s)' % uri_space_sub(uri_space_subber, g(12)), # url(...) fn_at_group, # @xxx expecting {...} None, fn_ie7hack, # ie7hack None, lambda g: g(16) + ' ' + space_sub(space_subber, g(17)), # :first-line|letter followed # by [{,] (apparently space # needed for IE6) lambda g: nl_unesc_sub('', g(18)), # nl_string lambda g: post_esc_sub(' ', g(19)), # escape ) def func(match): """ Main subber """ idx, group = match.lastindex, match.group if idx > 3: return table[idx](group) # shortcuts for frequent operations below: elif idx == 1: # not interesting return group(1) #else: # space with token before or at the beginning return space_sub(space_subber, group(idx)) return func def cssmin(style, keep_bang_comments=False): # pylint: disable = W0621 """ Minify CSS. :Parameters: `style` : ``str`` CSS to minify `keep_bang_comments` : ``bool`` Keep comments starting with an exclamation mark? (``/*!...*/``) :Return: Minified style :Rtype: ``str`` """ return main_sub(main_subber(keep_bang_comments), style) return cssmin
def _make_jsmin(python_only=False): """ Generate JS minifier based on `jsmin.c by Douglas Crockford`_ .. _jsmin.c by Douglas Crockford: http://www.crockford.com/javascript/jsmin.c :Parameters: `python_only` : ``bool`` Use only the python variant. If true, the c extension is not even tried to be loaded. (tdi.c._tdi_rjsmin) :Return: Minifier :Rtype: ``callable`` """ # pylint: disable = R0912, R0914, W0612 if not python_only: from tdi import c rjsmin = c.load('rjsmin') if rjsmin is not None: return rjsmin.jsmin try: xrange except NameError: xrange = range # pylint: disable = W0622 space_chars = r'[\000-\011\013\014\016-\040]' line_comment = r'(?://[^\r\n]*)' space_comment = r'(?:/\*[^*]*\*+(?:[^/*][^*]*\*+)*/)' string1 = \ r'(?:\047[^\047\\\r\n]*(?:\\(?:[^\r\n]|\r?\n|\r)[^\047\\\r\n]*)*\047)' string2 = r'(?:"[^"\\\r\n]*(?:\\(?:[^\r\n]|\r?\n|\r)[^"\\\r\n]*)*")' strings = r'(?:%s|%s)' % (string1, string2) charclass = r'(?:\[[^\\\]\r\n]*(?:\\[^\r\n][^\\\]\r\n]*)*\])' nospecial = r'[^/\\\[\r\n]' regex = r'(?:/(?![\r\n/*])%s*(?:(?:\\[^\r\n]|%s)%s*)*/)' % ( nospecial, charclass, nospecial ) space = r'(?:%s|%s)' % (space_chars, space_comment) newline = r'(?:%s?[\r\n])' % line_comment def fix_charclass(result): """ Fixup string of chars to fit into a regex char class """ pos = result.find('-') if pos >= 0: result = r'%s%s-' % (result[:pos], result[pos + 1:]) def sequentize(string): """ Notate consecutive characters as sequence (1-4 instead of 1234) """ first, last, result = None, None, [] for char in map(ord, string): if last is None: first = last = char elif last + 1 == char: last = char else: result.append((first, last)) first = last = char if last is not None: result.append((first, last)) return ''.join(['%s%s%s' % ( chr(first), last > first + 1 and '-' or '', last != first and chr(last) or '' ) for first, last in result]) return _re.sub(r'([\000-\040\047])', # for better portability lambda m: '\\%03o' % ord(m.group(1)), (sequentize(result) .replace('\\', '\\\\') .replace('[', '\\[') .replace(']', '\\]') ) ) def id_literal_(what): """ Make id_literal like char class """ match = _re.compile(what).match result = ''.join([ chr(c) for c in xrange(127) if not match(chr(c)) ]) return '[^%s]' % fix_charclass(result) def not_id_literal_(keep): """ Make negated id_literal like char class """ match = _re.compile(id_literal_(keep)).match result = ''.join([ chr(c) for c in xrange(127) if not match(chr(c)) ]) return r'[%s]' % fix_charclass(result) not_id_literal = not_id_literal_(r'[a-zA-Z0-9_$]') preregex1 = r'[(,=:\[!&|?{};\r\n]' preregex2 = r'%(not_id_literal)sreturn' % locals() id_literal = id_literal_(r'[a-zA-Z0-9_$]') id_literal_open = id_literal_(r'[a-zA-Z0-9_${\[(!+-]') id_literal_close = id_literal_(r'[a-zA-Z0-9_$}\])"\047+-]') dull = r'[^\047"/\000-\040]' space_sub = _re.compile(( r'(%(dull)s+)' r'|(%(strings)s%(dull)s*)' r'|(?<=%(preregex1)s)' r'%(space)s*(?:%(newline)s%(space)s*)*' r'(%(regex)s%(dull)s*)' r'|(?<=%(preregex2)s)' r'%(space)s*(?:%(newline)s%(space)s)*' r'(%(regex)s%(dull)s*)' r'|(?<=%(id_literal_close)s)' r'%(space)s*(?:(%(newline)s)%(space)s*)+' r'(?=%(id_literal_open)s)' r'|(?<=%(id_literal)s)(%(space)s)+(?=%(id_literal)s)' r'|(?<=\+)(%(space)s)+(?=\+)' r'|(?<=-)(%(space)s)+(?=-)' r'|%(space)s+' r'|(?:%(newline)s%(space)s*)+' ) % locals()).sub #print space_sub.__self__.pattern def space_subber(match): """ Substitution callback """ # pylint: disable = C0321, R0911 groups = match.groups() if groups[0]: return groups[0] elif groups[1]: return groups[1] elif groups[2]: return groups[2] elif groups[3]: return groups[3] elif groups[4]: return '\n' elif groups[5] or groups[6] or groups[7]: return ' ' else: return '' def jsmin(script): # pylint: disable = W0621 r""" Minify javascript based on `jsmin.c by Douglas Crockford`_\. Instead of parsing the stream char by char, it uses a regular expression approach which minifies the whole script with one big substitution regex. .. _jsmin.c by Douglas Crockford: http://www.crockford.com/javascript/jsmin.c :Parameters: `script` : ``str`` Script to minify :Return: Minified script :Rtype: ``str`` """ return space_sub(space_subber, '\n%s\n' % script).strip() return jsmin