def csscombine(path=None, url=None, cssText=None, href=None, sourceencoding=None, targetencoding=None, minify=True, resolveVariables=True): """Combine sheets referred to by @import rules in given CSS proxy sheet into a single new sheet. :returns: combined cssText, normal or minified :Parameters: `path` or `url` or `cssText` + `href` path or URL to a CSSStyleSheet or a cssText of a sheet which imports other sheets which are then combined into one sheet. `cssText` normally needs `href` to be able to resolve relative imports. `sourceencoding` = 'utf-8' explicit encoding of the source proxysheet `targetencoding` encoding of the combined stylesheet `minify` = True defines if the combined sheet should be minified, in this case comments are not parsed at all! `resolveVariables` = True defines if variables in combined sheet should be resolved """ css_parser.log.info('Combining files from %r' % url, neverraise=True) if sourceencoding is not None: css_parser.log.info('Using source encoding %r' % sourceencoding, neverraise=True) parser = css_parser.CSSParser(parseComments=not minify) if path and not cssText: src = parser.parseFile(path, encoding=sourceencoding) elif url: src = parser.parseUrl(url, encoding=sourceencoding) elif cssText: src = parser.parseString(cssText, href=href, encoding=sourceencoding) else: sys.exit('Path or URL must be given') result = css_parser.resolveImports(src) result.encoding = targetencoding css_parser.log.info('Using target encoding: %r' % targetencoding, neverraise=True) oldser = css_parser.ser css_parser.setSerializer(css_parser.serialize.CSSSerializer()) if minify: css_parser.ser.prefs.useMinified() css_parser.ser.prefs.resolveVariables = resolveVariables cssText = result.cssText css_parser.setSerializer(oldser) return cssText
def do(): with self.patch_default_fetcher(fetcher): s = css_parser.parseString(a) r = css_parser.resolveImports(s) return s, r
def test_resolveImports(self): "css_parser.resolveImports(sheet)" self._tempSer() css_parser.ser.prefs.useMinified() a = '@charset "iso-8859-1";@import"b.css";\xe4{color:green}'.encode( 'iso-8859-1') b = '@charset "ascii";\\E4 {color:red}'.encode('ascii') # normal with self.patch_default_fetcher((None, b)): s = css_parser.parseString(a) # py3 TODO self.assertEqual(a, s.cssText) self.assertEqual(b, s.cssRules[1].styleSheet.cssText) c = css_parser.resolveImports(s) # py3 TODO self.assertEqual( '\xc3\xa4{color:red}\xc3\xa4{color:green}'.encode( 'iso-8859-1'), c.cssText) c.encoding = 'ascii' self.assertEqual( r'@charset "ascii";\E4 {color:red}\E4 {color:green}'.encode(), c.cssText) # b cannot be found with self.patch_default_fetcher((None, None)): s = css_parser.parseString(a) # py3 TODO self.assertEqual(a, s.cssText) self.assertEqual(css_parser.css.CSSStyleSheet, type(s.cssRules[1].styleSheet)) c = css_parser.resolveImports(s) # py3 TODO self.assertEqual( '@import"b.css";\xc3\xa4{color:green}'.encode('iso-8859-1'), c.cssText) # @import with media a = '@import"b.css";@import"b.css" print, tv ;@import"b.css" all;' b = 'a {color: red}' with self.patch_default_fetcher((None, b)): s = css_parser.parseString(a) c = css_parser.resolveImports(s) self.assertEqual( 'a{color:red}@media print,tv{a{color:red}}a{color:red}'.encode( ), c.cssText) # cannot resolve with media => keep original a = '@import"b.css"print;' b = '@namespace "http://example.com";' with self.patch_default_fetcher((None, b)): s = css_parser.parseString(a) c = css_parser.resolveImports(s) self.assertEqual(a.encode(), c.cssText) # urls are adjusted too, layout: # a.css # c.css # img/img.gif # b/ # b.css # subimg/subimg.gif a = ''' @import"b/b.css"; a { x: url(/img/abs.gif); y: url(img/img.gif); z: url(b/subimg/subimg.gif); }''' def fetcher(url): c = { 'b.css': ''' @import"../c.css"; b { x: url(/img/abs.gif); y: url(../img/img.gif); z: url(subimg/subimg.gif); }''', 'c.css': ''' c { x: url(/img/abs.gif); y: url(./img/img.gif); z: url(./b/subimg/subimg.gif); }''' } return 'utf-8', c[os.path.split(url)[1]] def do(): with self.patch_default_fetcher(fetcher): s = css_parser.parseString(a) r = css_parser.resolveImports(s) return s, r s, r = do() css_parser.ser.prefs.useDefaults() css_parser.ser.prefs.keepComments = False self.assertEqual( '''c { x: url(/img/abs.gif); y: url(img/img.gif); z: url(b/subimg/subimg.gif) } b { x: url(/img/abs.gif); y: url(img/img.gif); z: url(b/subimg/subimg.gif) } a { x: url(/img/abs.gif); y: url(img/img.gif); z: url(b/subimg/subimg.gif) }'''.encode(), r.cssText)
def test_imports(self): "CSSVariables imports" def fetcher(url): url = url.replace('\\', '/') url = url[url.rfind('/') + 1:] return (None, { '3.css': ''' @variables { over3-2-1-0: 3; over3-2-1: 3; over3-2: 3; over3-2-0: 3; over3-1: 3; over3-1-0: 3; over3-0: 3; local3: 3; } ''', '2.css': ''' @variables { over3-2-1-0: 2; over3-2-1: 2; over3-2-0: 2; over3-2: 2; over2-1: 2; over2-1-0: 2; over2-0: 2; local2: 2; } ''', '1.css': ''' @import "3.css"; @import "2.css"; @variables { over3-2-1-0: 1; over3-2-1: 1; over3-1: 1; over3-1-0: 1; over2-1: 1; over2-1-0: 1; over1-0: 1; local1: 1; } ''' }[url]) css = ''' @import "1.css"; @variables { over3-2-1-0: 0; over3-2-0: 0; over3-1-0: 0; over2-1-0: 0; over3-0: 0; over2-0: 0; over1-0: 0; local0: 0; } a { local0: var(local0); local1: var(local1); local2: var(local2); local3: var(local3); over1-0: var(over1-0); over2-0: var(over2-0); over3-0: var(over3-0); over2-1: var(over2-1); over3-1: var(over3-1); over3-2: var(over3-2); over2-1-0: var(over2-1-0); over3-2-0: var(over3-2-0); over3-2-1: var(over3-2-1); over3-2-1-0: var(over3-2-1-0); } ''' p = css_parser.CSSParser(fetcher=fetcher) s = p.parseString(css) # only these in rule of this sheet self.assertEqual(s.cssRules[1].variables.length, 8) # but all vars in s available! self.assertEqual(s.variables.length, 15) self.assertEqual([ 'local0', 'local1', 'local2', 'local3', 'over1-0', 'over2-0', 'over2-1', 'over2-1-0', 'over3-0', 'over3-1', 'over3-1-0', 'over3-2', 'over3-2-0', 'over3-2-1', 'over3-2-1-0' ], sorted(s.variables.keys())) # test with variables rule css_parser.ser.prefs.resolveVariables = False self.assertEqual( s.cssText, '''@import "1.css"; @variables { over3-2-1-0: 0; over3-2-0: 0; over3-1-0: 0; over2-1-0: 0; over3-0: 0; over2-0: 0; over1-0: 0; local0: 0 } a { local0: var(local0); local1: var(local1); local2: var(local2); local3: var(local3); over1-0: var(over1-0); over2-0: var(over2-0); over3-0: var(over3-0); over2-1: var(over2-1); over3-1: var(over3-1); over3-2: var(over3-2); over2-1-0: var(over2-1-0); over3-2-0: var(over3-2-0); over3-2-1: var(over3-2-1); over3-2-1-0: var(over3-2-1-0) }'''.encode()) # test with resolved vars css_parser.ser.prefs.resolveVariables = True self.assertEqual( s.cssText, '''@import "1.css"; a { local0: 0; local1: 1; local2: 2; local3: 3; over1-0: 0; over2-0: 0; over3-0: 0; over2-1: 1; over3-1: 1; over3-2: 2; over2-1-0: 0; over3-2-0: 0; over3-2-1: 1; over3-2-1-0: 0 }'''.encode()) s = css_parser.resolveImports(s) self.assertEqual( s.cssText, '''/* START @import "1.css" */ /* START @import "3.css" */ /* START @import "2.css" */ a { local0: 0; local1: 1; local2: 2; local3: 3; over1-0: 0; over2-0: 0; over3-0: 0; over2-1: 1; over3-1: 1; over3-2: 2; over2-1-0: 0; over3-2-0: 0; over3-2-1: 1; over3-2-1-0: 0 }'''.encode())