Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(314)

Side by Side Diff: third_party/pyscss/scss/parser.py

Issue 9111023: Pyscss is obsolete with Dart CSS complier; remove all pyscss code. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Remove pyparsing from .gitignore Created 8 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « third_party/pyscss/scss/grammar.py ('k') | third_party/pyscss/scss/tests/__init__.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 import cPickle
2 import os.path
3 import sys
4 from collections import defaultdict
5
6 from pyparsing import ParseBaseException
7
8 from scss import SORTING
9 from scss.base import Node, Empty, ParseNode, ContentNode, IncludeNode
10 from scss.control import Variable, Expression, Function, Mixin, Include, MixinPa ram, Extend, Variables, Option, FunctionDefinition, FunctionReturn, If, For, Sep ValString, Stylet
11 from scss.function import warn, _nest
12 from scss.grammar import *
13 from scss.value import NumberValue, StringValue, ColorValue, QuotedStringValue, PointValue, RepeatValue
14
15
16 class Comment(Node):
17 """ Comment node.
18 """
19 delim = ''
20 def __str__(self):
21 """ Clean comments if option `comments` disabled
22 or enabled option `compress`
23 """
24 if self.root.get_opt('comments') and not self.root.get_opt('compress'):
25 return super(Comment, self).__str__()
26 return ''
27
28
29 class Warn(Empty):
30 """ Warning node @warn.
31 """
32 def parse(self, target):
33 """ Write message to stderr.
34 """
35 if self.root.get_opt('warn'):
36 warn(self.data[1])
37
38
39 class Import(Node):
40 """ Import node @import.
41 """
42 def __str__(self):
43 """ Write @import to outstring.
44 """
45 return "%s;\n" % super(Import, self).__str__()
46
47 # TODO(terry): Need to eliminate the { } as literal and consume with notion of
48 # DECLARATION_BODY, ANIMATION_BODY, AnimationDecls, etc. This will
49 # make the formatting code general and succinct.
50 class AnimationDecls(ContentNode):
51 def __str__(self):
52 nl, ws, ts = self.root.cache['delims']
53
54 # Formatting for animation declarations. Each declaration body is
55 # wrapped by curly braces with one level of indentation (2 spaces).
56 # Within a curly brace each declaration is indented 2 spaced and each
57 # declaration ends with a semi-colon.
58 declLen = len(self.data)
59 if (declLen > 0):
60 declLen -= 1
61 assert self.data[0] == '{' and self.data[declLen] == '}'
62 return ''.join(['%s{%s' % (ws, nl),
63 '%s%s' % (ws, ws),
64 '%s%s%s;' % (ws, ws,
65 ''.join(str(decl) for decl in self.data[1:declLen])),
66 '%s%s%s}%s%s%s' % (nl, ws, ws, nl, ws, ws)])
67
68 class AnimationBody(ContentNode):
69 def __str__(self):
70 nl, ws, ts = self.root.cache['delims']
71
72 # Formatting for the body of the animation. The body is surrounded by an
73 # open curly brace and newline followed by a repeated field selector
74 # (indented by 2 spaces) and the animation declaration. When all
75 # animation declarations are emitted add the end curly brace for the
76 # entire animation.
77 bodyLen = len(self.data)
78 if bodyLen > 0:
79 bodyLen -= 1
80 assert self.data[0] == '{' and self.data[bodyLen] == '}'
81 return ''.join(['%s{%s' % (ws, nl),
82 '%s%s' % (ws, ws),
83 ''.join(str(body) for body in self.data[1:bodyLen]),
84 '%s' % nl,
85 '}%s%s' % (nl, nl)])
86
87 class Ruleset(ContentNode):
88 """ Rule node.
89 """
90 def parse(self, target):
91 """ Parse nested rulesets
92 and save it in cache.
93 """
94 if isinstance(target, ContentNode):
95 if target.name:
96 self.parent = target
97 self.name.parse(self)
98 self.name += target.name
99 target.ruleset.append(self)
100 self.root.cache['rset'][str(self.name).split()[0]].add(self)
101 super(Ruleset, self).parse(target)
102
103
104 class Declaration(ParseNode):
105 """ Declaration node.
106 """
107 def __init__(self, s, n, t):
108 """ Add self.name and self.expr to object.
109 """
110 super(Declaration, self).__init__(s, n, t)
111 self.name = self.expr = ''
112
113 def parse(self, target):
114 """ Parse nested declaration.
115 """
116 if not isinstance(target, Node):
117 parent = ContentNode(None, None, [])
118 parent.parse(target)
119 target = parent
120
121 super(Declaration, self).parse(target)
122 self.name = str(self.data[0])
123 while isinstance(target, Declaration):
124 self.name = '-'.join(( str(target.data[0]), self.name))
125 target = target.parent
126
127 self.expr = ' '.join(str(n) for n in self.data[2:] if not isinstance(n, Declaration))
128 if self.expr:
129 target.declareset.append(self)
130
131 def __str__(self):
132 """ Warning on unknown declaration
133 and write current in outstring.
134 """
135 if ( not SORTING.has_key(self.name.strip('*_'))
136 and self.root.get_opt('warn') ):
137 warn("Unknown declaration: %s" % self.name)
138
139 return (":%s" % self.root.cache['delims'][1] ).join(
140 (self.name, self.expr))
141
142
143 class DeclarationName(ParseNode):
144 """ Name of declaration node.
145 For spliting it in one string.
146 """
147 delim = ''
148
149
150 class SelectorTree(ParseNode):
151 """ Tree of selectors in ruleset.
152 """
153 delim = ', '
154
155 def extend(self, target):
156 """ @extend selectors tree.
157 """
158 self_test = ', '.join(map(str, self.data))
159 target_test = ', '.join(map(str, target.data))
160 self.data = (self_test + ', ' + self_test.replace(str(self.data[0].data[ 0]), target_test)).split(', ')
161
162 def __add__(self, target):
163 """ Add selectors from parent nodes.
164 """
165 if isinstance(target, SelectorTree):
166 self_test = ', '.join(map(str, self.data))
167 target_test = ', '.join(map(str, target.data))
168 self.data = _nest(target_test, self_test).split(', ')
169 return self
170
171 def __str__(self):
172 selOut = ''
173 for entry in self.data:
174 if (isinstance(entry, str)):
175 # Combinator and commas are as raw strings.
176 selOut += ' %s ' % entry
177 else:
178 for selEntry in entry.data:
179 if (isinstance(selEntry, str)):
180 selOut += ' %s ' % selEntry
181 else:
182 # Construct the pseudo elements etc. multiple regex tokens as str.
183 selOut += ''.join(str(n) for n in selEntry.data);
184 selOut += ' '
185 return selOut
186
187
188 class Selector(ParseNode):
189 """ Simple selector node.
190 """
191 delim = ''
192
193 def __str__(self):
194 """ Write to output.
195 """
196 return ''.join(StringValue(n).value for n in self.data)
197
198
199 class VarDefinition(ParseNode, Empty):
200 """ Variable definition.
201 """
202 def __init__(self, s, n, t):
203 """ Save self.name, self.default, self.expression
204 """
205 super(VarDefinition, self).__init__(s, n, t)
206 self.name = t[0][1:]
207 self.default = len(t) > 2
208 self.expression = t[1]
209
210 def parse(self, target):
211 """ Update root and parent context.
212 """
213 super(VarDefinition, self).parse(target)
214 if isinstance(self.parent, ParseNode):
215 self.parent.ctx.update({ self.name: self.expression.value })
216 self.root.set_var(self)
217
218
219 class Media(ParseNode):
220 def __str__(self):
221 selOut = ''
222 # TODO(terry): Need to retain parenthesis in expression for the media
223 # selector. Parenthesis are important and need a better
224 # grammar. For now hack is to wrap the 'and' operator and
225 # comma operator to use emit parentheses around expressions.
226 anyOper = False
227 openParen = 0
228 for entry in self.data:
229 if isinstance(entry, str) and entry == 'and':
230 if openParen > 0:
231 selOut += ') and '
232 openParen -= 1
233 else:
234 selOut += ' and '
235 anyOper = True
236 elif isinstance(entry, str) and entry == '{':
237 selOut += ''.join([')' for n in xrange(openParen)])
238 selOut += ' {\n'
239 # Handle the expression.
240 elif isinstance(entry, StringValue):
241 if openParen > 0:
242 selOut += ') , (%s' % entry
243 elif anyOper:
244 selOut += '(%s' % entry
245 anyOper = False
246 openParen += 1
247 else:
248 selOut += ' %s ' % entry
249 else:
250 selOut += ' %s ' % entry
251
252 selOut += '}\n'
253 return selOut
254
255 class Stylesheet(object):
256 """ Root stylesheet node.
257 """
258
259 def_delims = '\n', ' ', '\t'
260
261 # Known stylet base classes.
262 styletClasses = []
263
264 # List of known CSS class names emitted. We only want to emit one constant
265 # per CSS class.
266 knownClassNames = []
267
268 # Dart class to output only class name selectors with style properties.
269 cssClass = []
270
271 # Dart class to output only class name selectors with no style properties.
272 cssStateSelectors = []
273
274 currentOptions = []
275 currentFile = ''
276
277 scssIncludes = []
278
279 exportedClassName = []
280 classNameAsState = []
281
282 def __init__(self, cache = None, options=None):
283 self.cache = cache or dict(
284
285 # Variables context
286 ctx = dict(),
287
288 # Mixin context
289 mix = dict(),
290
291 # Rules context
292 rset = defaultdict(set),
293
294 # Options context
295 opts = dict(
296 comments = True,
297 warn = True,
298 sort = True,
299 path = os.getcwd(),
300 ),
301
302 # CSS delimeters
303 delims = self.def_delims,
304
305 )
306
307 if options:
308 self.currentOptions = options
309 for option in options.items():
310 self.set_opt(*option)
311
312 self.setup()
313 Node.root = self
314
315 def setup(self):
316
317 # Values
318 OTHER_VALUE.setParseAction(NumberValue)
319 PERCENTAGE_VALUE.setParseAction(NumberValue)
320 IDENT.setParseAction(StringValue)
321 PATH.setParseAction(StringValue)
322 POINT.setParseAction(PointValue)
323 COLOR_VALUE.setParseAction(ColorValue)
324 REPEAT_VALUE.setParseAction(RepeatValue)
325 quotedString.setParseAction(QuotedStringValue)
326 EXPRESSION.setParseAction(Expression)
327 SEP_VAL_STRING.setParseAction(SepValString)
328
329 # Vars
330 VARIABLE.setParseAction(Variable)
331 VAR_DEFINITION.setParseAction(VarDefinition)
332 VARIABLES.setParseAction(Variables)
333 FUNCTION.setParseAction(Function)
334 FUNCTION_DEFINITION.setParseAction(FunctionDefinition)
335 FUNCTION_RETURN.setParseAction(FunctionReturn)
336
337 # Coments
338 SCSS_COMMENT.setParseAction(lambda x: '')
339 CSS_COMMENT.setParseAction(Comment)
340
341 # At rules
342 IMPORT.setParseAction(Import)
343 CHARSET.setParseAction(Import)
344 MEDIA.setParseAction(Media)
345 STYLET.setParseAction(Stylet)
346 ANIMATION_DECLARATIONS.setParseAction(AnimationDecls)
347 ANIMATION_BODY.setParseAction(AnimationBody)
348
349 # Rules
350 RULESET.setParseAction(Ruleset)
351 DECLARATION.setParseAction(Declaration)
352 DECLARATION_NAME.setParseAction(DeclarationName)
353 SELECTOR.setParseAction(Selector)
354 SELECTOR_GROUP.setParseAction(ParseNode)
355 SELECTOR_TREE.setParseAction(SelectorTree)
356 FONT_FACE.setParseAction(ContentNode)
357
358 # SCSS Directives
359 MIXIN.setParseAction(Mixin)
360 MIXIN_PARAM.setParseAction(MixinParam)
361 INCLUDE.setParseAction(Include)
362 EXTEND.setParseAction(Extend)
363 OPTION.setParseAction(Option)
364 IF.setParseAction(If)
365 IF_BODY.setParseAction(IncludeNode)
366 ELSE.setParseAction(IncludeNode)
367 FOR.setParseAction(For)
368 FOR_BODY.setParseAction(IncludeNode)
369 WARN.setParseAction(Warn)
370
371 @property
372 def ctx(self):
373 return self.cache['ctx']
374
375 def set_var(self, vardef):
376 """ Set variable to global stylesheet context.
377 """
378 if not(vardef.default and self.cache['ctx'].get(vardef.name)):
379 self.cache['ctx'][vardef.name] = vardef.expression.value
380
381 def set_opt(self, name, value):
382 """ Set option.
383 """
384 self.cache['opts'][name] = value
385
386 if name == 'compress':
387 self.cache['delims'] = self.def_delims if not value else ('', '', '' )
388
389 def get_opt(self, name):
390 """ Get option.
391 """
392 return self.cache['opts'].get(name)
393
394 def update(self, cache):
395 """ Update self cache from other.
396 """
397 self.cache['delims'] = cache.get('delims')
398 self.cache['opts'].update(cache.get('opts'))
399 self.cache['rset'].update(cache.get('rset'))
400 self.cache['mix'].update(cache.get('mix'))
401 map(self.set_var, cache['ctx'].values())
402
403 def scan(self, src):
404 """ Scan scss from string and return nodes.
405 """
406 assert isinstance(src, basestring)
407 try:
408 nodes = STYLESHEET.parseString(src, parseAll=True)
409 return nodes
410 except ParseBaseException:
411 err = sys.exc_info()[1]
412 print >> sys.stderr, err.line
413 print >> sys.stderr, " "*(err.column-1) + "^"
414 print >> sys.stderr, err
415 sys.exit(1)
416
417 def parse(self, nodes):
418 map(lambda n: n.parse(self) if isinstance(n, Node) else None, nodes)
419
420 def loads(self, src):
421 """ Compile css from scss string.
422 """
423 assert isinstance(src, basestring)
424 nodes = self.scan(src.strip())
425 self.parse(nodes)
426 return ''.join(map(str, nodes))
427
428 def load(self, f, precache=None):
429 """ Compile scss from file.
430 File is string path of file object.
431 """
432 precache = precache or self.get_opt('cache') or False
433 nodes = None
434 if isinstance(f, file):
435 path = os.path.abspath(f.name)
436
437 else:
438 path = os.path.abspath(f.name)
439 f = open(f)
440
441 cache_path = os.path.splitext(path)[0] + '.ccss'
442
443 if precache and os.path.exists(cache_path):
444 ptime = os.path.getmtime(cache_path)
445 ttime = os.path.getmtime(path)
446 if ptime > ttime:
447 dump = open(cache_path, 'rb').read()
448 nodes = cPickle.loads(dump)
449
450 if not nodes:
451 src = f.read()
452 nodes = self.scan(src.strip())
453
454 if precache:
455 f = open(cache_path, 'wb')
456 cPickle.dump(nodes, f)
457
458 self.parse(nodes)
459 return ''.join(map(str, nodes))
460
461 # TODO(terry): For now special function for returning nodes.
462 def loadReturnNodes(self, f, precache=None):
463 """ Compile scss from file.
464 File is string path of file object.
465 """
466 self.currentFile = f
467
468 precache = precache or self.get_opt('cache') or False
469 nodes = None
470 if isinstance(f, file):
471 path = os.path.abspath(f.name)
472
473 else:
474 path = os.path.abspath(f.name)
475 f = open(f)
476
477 cache_path = os.path.splitext(path)[0] + '.ccss'
478
479 if precache and os.path.exists(cache_path):
480 ptime = os.path.getmtime(cache_path)
481 ttime = os.path.getmtime(path)
482 if ptime > ttime:
483 dump = open(cache_path, 'rb').read()
484 nodes = cPickle.loads(dump)
485
486 if not nodes:
487 src = f.read()
488 nodes = self.scan(src.strip())
489
490 if precache:
491 f = open(cache_path, 'wb')
492 cPickle.dump(nodes, f)
493
494 self.parse(nodes)
495 return nodes
496
497 def __str__(self):
498 return 'media';
499
500 # Format of the Dart CSS class:
501 #
502 # class Layout1 {
503 # // selector, properties<propertyName, value>
504 # static final selectors = const {
505 # '#elemId' : const {
506 # 'left' : '20px'
507 # },
508 # '.className' : const {
509 # 'color' : 'red'
510 # }
511 # };
512 # }
513 #
514 # Emit pre-defined classes for Dart CSS.
515 #
516 def emitPreDefineDart(self, sourceFile):
517 return ['// File generated by SCSS from source file %s\n' % sourceFile,
518 '// Do not edit.\n\n'
519 ]
520
521 def emitCssClass(self, cssName):
522 self.cssClass.append('class {0} {{\n'.format(cssName))
523 self.cssClass.append(' // CSS class selectors:\n')
524
525 # Emit stylet instance:
526 #
527 # static final CssLayout layout = new CssLayout();
528 def emitStyletInstance(self, styletName):
529 styletClass = 'STYLET_{0}'.format(styletName)
530 return ' static final {0} {1} = new {0}();\n\n'.format(styletClass,
531 styletName)
532
533 # Emit each exported stylet.
534 #
535 # class {stylet name} {
536 # // selector, properties<propertyName, value>
537 # static final selectors = const {
538 def emitStyletClass(self, stylet):
539 self.styletClasses.append('class {0} {{\n'.
540 format(stylet.name))
541 self.styletClasses.append(' // selector, properties<propertyName, value>\ n')
542 self.styletClasses.append(' static final selectors = const {\n')
543 return stylet.name
544
545 def emitCloseCSSStyletSelector(self):
546 self.styletClasses.append("\n }")
547
548 # Emit the selector for this style:
549 # where selectorValue is valid selector (e.g., #elemId, .className, etc.)
550 #
551 # 'selectorValue' : const {
552 def emitCSSStyletSelector(self, selectorTree, anySelectors):
553 if anySelectors:
554 self.styletClasses.append(",\n");
555 self.styletClasses.append(" '%s' : const {\n" % selectorTree.data[0])
556
557 # Emit each property in the stylet property map:
558 # 'propName' : 'propValue'
559 def emitStyletProperty(self, decl, anyProps):
560 if anyProps:
561 self.styletClasses.append(',\n')
562 propValues = len(decl)
563 if propValues > 0:
564 values = []
565 first = True
566 for value in decl[-(propValues - 2):]:
567 values.append(('{0}' if first else ' {0}').format(value))
568 first = False
569 self.styletClasses.append(" '{0}' : \"{1}\"".
570 format(decl[0], ''.join(values)))
571 anyProps = True
572 return anyProps
573
574 def emitEndStyletClass(self):
575 self.styletClasses.append('\n };\n')
576 self.styletClasses.append('}\n\n')
577
578 # Emit each CSS class name as a constant string in the generated Dart class,
579 # but only once.
580 def emitDartCSSClassName(self, selectorTree):
581 # Only process selectors ignore declarations associated with the
582 # selectors.
583 for parseNode in selectorTree.data:
584 if isinstance(parseNode, ParseNode):
585 assert isinstance(parseNode.data[0], ParseNode)
586
587 if len(parseNode.data) == 1:
588 for selector in parseNode.data:
589 # Tree will contain selector and strings (e.g., commas, etc.).
590 if isinstance(selector, Selector):
591 if len(selector.data) == 1:
592 selectName = selector.data[0]
593 if selectName[0] == '.' and selectName.rfind('.') == 0:
594 # static final String ARTICLE = 'article';
595 className = selectName[1:]
596 if not(className in self.knownClassNames):
597 # Class name hasn't been emitted; emit now.
598
599 # TODO(terry): Better mechanism then replacing -
600 # with _. Possibly add export name
601 # attribute.
602 exportedName = className.upper().replace('-', '_')
603 self.cssClass.append(
604 " static final String {0} = '{1}';\n".
605 format(exportedName, className))
606 # Add to list of known class names emitted.
607 self.knownClassNames.append(className)
608
609 # Decide if class selector should be as exported class name (that has a
610 # a real CSS style) or as a class name used for state (no CSS style).
611 def addToKnownClassList(self, selectorTree):
612 for parseNode in selectorTree.data:
613 if isinstance(parseNode, ParseNode):
614 if len(parseNode.data) == 1:
615 name = parseNode.data[0].data[0]
616 if name[0] == '.':
617 cssName = name[1:]
618 if not(cssName in self.exportedClassName):
619 self.exportedClassName.append(cssName)
620 else:
621 for node in parseNode.data:
622 if isinstance(node, Selector):
623 for name in node.data:
624 if name[0] == '.':
625 cssName = name[1:]
626 if not(cssName in self.exportedClassName) and not(
627 cssName in self.classNameAsState):
628 self.classNameAsState.append(cssName)
629
630 def emitCssSelector(self, name):
631 exportedName = name.upper().replace('-', '_')
632 self.cssClass.append(" static final String {0} = '{1}';\n".
633 format(exportedName, name))
634
635 def emitCssStateSelectors(self):
636 self.cssStateSelectors.append('\n // CSS state class selectors:\n')
637
638 def emitCssStateSelector(self, name):
639 exportedName = name.upper().replace('-', '_')
640 self.cssStateSelectors.append(" static final String {0} = '{1}';\n".
641 format(exportedName, name))
642
643 #class cssTest {
644 # static final String FRONTVIEW = 'frontview';
645 # static final String QUERY = 'query';
646 #
647 # static final CssLayout layout = new CssLayout();
648 #}
649 def dartClass(self, sourceFile, cssName, cssFiles):
650 self.styletClasses = self.emitPreDefineDart(sourceFile)
651 self.knownClassNames = []
652 self.cssClass = []
653
654 # One class per CSS file.
655 self.emitCssClass(cssName)
656
657 # Iterate though all rulesets.
658 stylets = []
659 anyProps = False
660
661 for file in cssFiles:
662 nodes = file[1]
663 for node in nodes:
664 if isinstance(node, Ruleset):
665 ruleset = node
666 for selectorTree in ruleset.data:
667 if isinstance(selectorTree, SelectorTree):
668 # Process both class selectors with style properties and class
669 # selectors used as state.
670 self.addToKnownClassList(selectorTree)
671 elif isinstance(node, Stylet):
672 # We've hit a stylet emit the stylet class definition.
673 stylet = node
674 stylets.append(self.emitStyletClass(stylet))
675 styletRulesets = stylet.data[2:]
676 styletSelectorOpen = False;
677 anySelectors = False
678 for styletRuleset in styletRulesets:
679 assert isinstance(styletRuleset, Ruleset)
680 for selectorTree in styletRuleset.data:
681 if isinstance(selectorTree, SelectorTree):
682 if styletSelectorOpen:
683 self.emitCloseCSSStyletSelector();
684 styletSelectorOpen = False;
685 anyProps = False;
686 self.emitCSSStyletSelector(selectorTree, anySelectors);
687 anySelectors = True;
688 styletSelectorOpen = True;
689 elif isinstance(selectorTree, Declaration):
690 anyProps = self.emitStyletProperty(selectorTree.data, anyProps )
691
692 if styletSelectorOpen:
693 self.emitCloseCSSStyletSelector();
694 anySelectors = False;
695 anyProps = False;
696
697 # Close the CSSStylet properties array and the style class we've
698 # been emitting.
699 self.emitEndStyletClass()
700 anyProps = False
701
702 # Emit all CSS class selectors that have a real CSS properties.
703 for cssClassSelector in self.exportedClassName:
704 self.emitCssSelector(cssClassSelector)
705
706 # Emit the CSS_State class for CSS class selectors that have not CSS
707 # properties associated with the class name.
708 self.emitCssStateSelectors()
709 for cssStateName in self.classNameAsState:
710 if not(cssStateName in self.exportedClassName):
711 self.emitCssStateSelector(cssStateName)
712
713 # Emit CSS selectors that have no CSS style properties (used for state).
714 self.cssClass.extend(self.cssStateSelectors)
715
716 # Close the CSS class we're done.
717 self.cssClass.append('}\n')
718
719 self.styletClasses.extend(self.cssClass)
720 return "".join(self.styletClasses)
721
722 def addInclude(self, filename, nodes):
723 self.scssIncludes.append([filename, nodes])
724
725 def parse( src, cache=None ):
726 """ Parse from string.
727 """
728 parser = Stylesheet(cache)
729 return parser.loads(src)
730
731
732 def load(path, cache=None, precache=False):
733 """ Parse from file.
734 """
735 parser = Stylesheet(cache)
736 return parser.load(path, precache=precache)
OLDNEW
« no previous file with comments | « third_party/pyscss/scss/grammar.py ('k') | third_party/pyscss/scss/tests/__init__.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698