def __init__(self, app, static_dir=None, asset_dir=None, load_paths=None): ''' See :ref:`scss_discovery_rules` and :ref:`static_discovery_rules` for more information about the impact of ``static_dir`` and ``asset_dir`` parameters. Parameters here has preedence over Parameters found in the application config. :param app: Your Flask Application :param static_dir: The path to the ``static`` directory of your application (optional) :param asset_dir: The path to the ``assets`` directory where Flask-Scss will search ``.scss`` files (optional) :param load_paths: A list of folders to add to pyScss load_paths (for ex., the path to a library like Compass) ''' if not load_paths: load_paths = [] self.app = app self.asset_dir = self.set_asset_dir(asset_dir) self.static_dir = self.set_static_dir(static_dir) self.assets = {} self.partials = {} load_path_list = ([self.asset_dir] if self.asset_dir else []) \ + (load_paths or app.config.get('SCSS_LOAD_PATHS', [])) # pyScss.log = app.logger self.compiler = Compiler(search_path=load_path_list) if self.app.testing or self.app.debug: self.set_hooks()
def clean(self): compiler = Compiler(search_path=getattr(settings, 'SASS_SEARCH_PATHS', []), output_style='compressed' if self.minify else 'nested') try: self.output = compiler.compile_string(self.source) except (ValueError, SassSyntaxError) as e: import traceback ; traceback.print_exc() raise ValidationError({'source': str(e)})
def _compile(self, files, debug=False): compiler = Compiler( search_path=self._get_search_path_for_files(files), output_style=debug and 'expanded' or 'compressed', generate_source_map=True, namespace=self.namespace) compiler.extensions.append(ThemingExtensions()) css = compiler.compile_sources(*files) return css.encode('utf-8')
def __init__(self, is_sass=False): # TODO it would be lovely to get these out of here, somehow self.namespace = Namespace(variables=_default_scss_vars) self.compiler = Compiler(namespace=self.namespace) self.compilation = self.compiler.make_compilation() self.legacy_compiler_options = {} self.source_file = SourceFile.from_string('', '<shell>', is_sass=is_sass) self.calculator = Calculator(self.namespace)
def clean(self): compiler = Compiler( search_path=getattr(settings, 'SASS_SEARCH_PATHS', []), output_style='compressed' if self.minify else 'nested') try: self.output = compiler.compile_string(self.source) except (ValueError, SassSyntaxError) as e: import traceback traceback.print_exc() raise ValidationError({'source': str(e)})
def setup(self): try: from scss.compiler import Compiler except ImportError: raise EnvironmentError('The "pyScss" package is not installed.') else: search_path = [ path.join(path.abspath(path.dirname(__file__)), 'static', 'scss') ] self.compiler = Compiler(search_path=search_path)
def customise_css(): colour = colours.get_from_qs(flask.request.args) namespace = Namespace() namespace.set_variable('$fg', Color.from_hex(colour.fg)) namespace.set_variable('$bg', Color.from_hex(colour.bg)) namespace.set_variable('$highFg', Color.from_hex(colour.highFg)) namespace.set_variable('$highBg', Color.from_hex(colour.highBg)) compiler = Compiler(namespace=namespace) res = make_response(compiler.compile('style/index.scss')) res.mimetype = 'text/css' return res
def compile_file(self, path: str): """Compiles SCSS into CSS.""" # don't compile non-scss files if os.path.splitext(path)[1] != ".scss": return # the name of the compiled file without extensions name = Path(path).stem output_path = os.path.join(SCSSAutoCompiler.OUTPUT_DIR, name + ".css") try: # ensure these folders exist os.makedirs(os.path.dirname(output_path)) except FileExistsError: pass try: print(f"compiling SCSS at {path} => {output_path}") with open(output_path, "w") as f: f.write(Compiler(search_path=("style/", )).compile(path)) self.octogon.on_compile(name, "scss", output_path) except Exception as e: print("failed to compile scss: ") print(e)
def parse_import_path(self, path): url_base = self.url_base url_map = self.url_map path = normalize_path(path) if path.find('!') >= 0 : path = path.split('!') prefix = path[0] if prefix in url_map: path = normalize_path(url_base + url_map[prefix] + path[1]) else: raise Exception('prefix not found ! (' + prefix + ')') else: path = url_base + path if os.path.isfile(path): fileext = os.path.splitext(path)[1] if fileext == '.js' and jsx: with open(path) as handler: content = handler.read().decode('utf-8') if self._match_jsx_notation(content): temp = tempfile.mkstemp(fileext) self._tempfile.append(temp) jsx.transform(path, temp[1]) path = temp[1] if fileext == '.scss' and SCSSCompiler: compiler = SCSSCompiler(search_path=(self.scss_root,)) temp = tempfile.mkstemp('.css') self._tempfile.append(temp) with open(path) as handler: content = handler.read().decode('utf-8') content = compiler.compile_string(content) os.write(temp[0], content.encode('utf-8')) path = temp[1] return path
def parse_import_path(self, path): url_base = self.url_base url_map = self.url_map path = normalize_path(path) if path.find('!') >= 0: path = path.split('!') prefix = path[0] if prefix in url_map: path = normalize_path(url_base + url_map[prefix] + path[1]) else: raise Exception('prefix not found ! (' + prefix + ')') else: path = url_base + path if os.path.isfile(path): fileext = os.path.splitext(path)[1] if fileext == '.js' and jsx: with open(path) as handler: content = handler.read() if self._match_jsx_notation(content): temp = tempfile.mkstemp(fileext) self._tempfile.append(temp) jsx.transform(path, temp[1]) path = temp[1] if fileext == '.scss' and SCSSCompiler: compiler = SCSSCompiler(search_path=(self.scss_root, )) temp = tempfile.mkstemp('.css') self._tempfile.append(temp) with open(path) as handler: content = handler.read() content = compiler.compile_string(content) os.write(temp[0], content.encode('utf-8')) path = temp[1] return path
class ScssMangler(Mangler): ''' Mangle SASS/SCSS. ''' def __init__(self, target, extensions=None, include_paths=None): super().__init__(target) self.extensions = extensions or ['.sass', '.scss'] self.include_paths = include_paths or [] self.compiler = Compiler(search_path=self.include_paths) def can_process(self, file_obj): return file_obj.current_name.suffix in self.extensions def process_file(self, file_obj): content = self.compiler.compile_string(file_obj.str) self.target.delete(file_obj.current_name) file_obj.str = content file_obj.current_name = file_obj.current_name.with_suffix('.css') yield file_obj
class PySCSSFilter(Filter): """Compiles `Scss <http://sass-lang.org/>`_ markup to real CSS. Requires the ``pyScss`` package (http://pypi.python.org/pypi/pyScss/). Run: $ pip install pyScss """ name = 'apyscss' def setup(self): try: from scss.compiler import Compiler except ImportError: raise EnvironmentError('The "pyScss" package is not installed.') else: search_path = [ path.join(path.abspath(path.dirname(__file__)), 'static', 'scss') ] self.compiler = Compiler(search_path=search_path) def input(self, _in, out, **kw): out.write(self.compiler.compile_string(_in.read()))
def compile(self, scss_string=None, scss_file=None, source_files=None, super_selector=None, filename=None, is_sass=None, line_numbers=True, import_static_css=False): """Compile Sass to CSS. Returns a single CSS string. This method is DEPRECATED; see :mod:`scss.compiler` instead. """ # Derive our root namespace self.scss_vars = _default_scss_vars.copy() if self._scss_vars is not None: self.scss_vars.update(self._scss_vars) root_namespace = Namespace( variables=self.scss_vars, functions=self._library, ) # Figure out search paths. Fall back from provided explicitly to # defined globally to just searching the current directory search_paths = ['.'] if self._search_paths is not None: assert not isinstance(self._search_paths, six.string_types), \ "`search_paths` should be an iterable, not a string" search_paths.extend(self._search_paths) else: if config.LOAD_PATHS: if isinstance(config.LOAD_PATHS, six.string_types): # Back-compat: allow comma-delimited search_paths.extend(config.LOAD_PATHS.split(',')) else: search_paths.extend(config.LOAD_PATHS) search_paths.extend(self._scss_opts.get('load_paths', [])) # Normalize a few old styles of options output_style = self._scss_opts.get('style', config.STYLE) if output_style is True: output_style = 'compressed' elif output_style is False: output_style = 'legacy' fixed_search_path = [] for path in search_paths: if isinstance(path, six.string_types): fixed_search_path.append(Path(path)) else: fixed_search_path.append(path) # Build the compiler compiler = Compiler( namespace=root_namespace, extensions=[ CoreExtension, ExtraExtension, FontsExtension, CompassExtension, BootstrapExtension, ], search_path=fixed_search_path, import_static_css=import_static_css, live_errors=self.live_errors, generate_source_map=self._scss_opts.get('debug_info', False), output_style=output_style, warn_unused_imports=self._scss_opts.get('warn_unused', False), ignore_parse_errors=config.DEBUG, loops_have_own_scopes=config.CONTROL_SCOPING, undefined_variables_fatal=config.FATAL_UNDEFINED, super_selector=super_selector or self.super_selector, ) # Gonna add the source files manually compilation = compiler.make_compilation() # Inject the files we know about # TODO how does this work with the expectation of absoluteness if source_files is not None: for source in source_files: compilation.add_source(source) elif scss_string is not None: source = SourceFile.from_string( scss_string, relpath=filename, is_sass=is_sass, ) compilation.add_source(source) elif scss_file is not None: # This is now the only way to allow forcibly overriding the # filename a source "thinks" it is with open(scss_file, 'rb') as f: source = SourceFile.from_file( f, relpath=filename or scss_file, is_sass=is_sass, ) compilation.add_source(source) # Plus the ones from the constructor if self._scss_files: for name, contents in list(self._scss_files.items()): source = SourceFile.from_string(contents, relpath=name) compilation.add_source(source) return compiler.call_and_catch_errors(compilation.run)
class SassRepl(object): def __init__(self, is_sass=False): # TODO it would be lovely to get these out of here, somehow self.namespace = Namespace(variables=_default_scss_vars) self.compiler = Compiler(namespace=self.namespace) self.compilation = self.compiler.make_compilation() self.legacy_compiler_options = {} self.source_file = SourceFile.from_string('', '<shell>', is_sass=is_sass) self.calculator = Calculator(self.namespace) def __call__(self, s): # TODO this is kind of invasive; surely it's possible to do this # without calling only private methods from pprint import pformat if s in ('exit', 'quit'): raise KeyboardInterrupt for s in s.split(';'): s = self.source_file.prepare_source(s.strip()) if not s: continue elif s.startswith('@'): scope = None properties = [] children = deque() rule = SassRule(self.source_file, namespace=self.namespace, legacy_compiler_options=self.legacy_compiler_options, properties=properties) block = UnparsedBlock(rule, 1, s, None) code, name = (s.split(None, 1) + [''])[:2] if code == '@option': self.compilation._at_options(self.calculator, rule, scope, block) continue elif code == '@import': self.compilation._at_import(self.calculator, rule, scope, block) continue elif code == '@include': final_cont = '' self.compilation._at_include(self.calculator, rule, scope, block) code = self.compilation._print_properties(properties).rstrip('\n') if code: final_cont += code if children: self.compilation.children.extendleft(children) self.compilation.parse_children() code = self.compilation._create_css(self.compilation.rules).rstrip('\n') if code: final_cont += code yield final_cont continue elif s == 'ls' or s.startswith('show(') or s.startswith('show ') or s.startswith('ls(') or s.startswith('ls '): m = re.match(r'(?:show|ls)(\()?\s*([^,/\\) ]*)(?:[,/\\ ]([^,/\\ )]+))*(?(1)\))', s, re.IGNORECASE) if m: name = m.group(2) code = m.group(3) name = name and name.strip().rstrip('s') # remove last 's' as in functions code = code and code.strip() ns = self.namespace if not name: yield pformat(list(sorted(['vars', 'options', 'mixins', 'functions']))) elif name in ('v', 'var', 'variable'): variables = dict(ns._variables) if code == '*': pass elif code: variables = dict((k, v) for k, v in variables.items() if code in k) else: variables = dict((k, v) for k, v in variables.items() if not k.startswith('$--')) yield pformat(variables) elif name in ('o', 'opt', 'option'): opts = self.legacy_compiler_options if code == '*': pass elif code: opts = dict((k, v) for k, v in opts.items() if code in k) else: opts = dict((k, v) for k, v in opts.items()) yield pformat(opts) elif name in ('m', 'mix', 'mixin', 'f', 'func', 'funct', 'function'): if name.startswith('m'): funcs = dict(ns._mixins) elif name.startswith('f'): funcs = dict(ns._functions) if code == '*': pass elif code: funcs = dict((k, v) for k, v in funcs.items() if code in k[0]) else: pass # TODO print source when possible yield pformat(funcs) continue elif s.startswith('$') and (':' in s or '=' in s): prop, value = [a.strip() for a in _prop_split_re.split(s, 1)] prop = self.calculator.do_glob_math(prop) value = self.calculator.calculate(value) self.namespace.set_variable(prop, value) continue # TODO respect compress? try: yield(self.calculator.calculate(s).render()) except (SyntaxError, SassEvaluationError) as e: print("%s" % e, file=sys.stderr)
class Scss(object): ''' Main and only class for Flask-Scss. It is in charge on the discovery of .scss files and compiles them every time they are modified. Any application that wants to use Flask-Scss must create a instance of this class ''' def __init__(self, app, static_dir=None, asset_dir=None, load_paths=None): ''' See :ref:`scss_discovery_rules` and :ref:`static_discovery_rules` for more information about the impact of ``static_dir`` and ``asset_dir`` parameters. Parameters here has preedence over Parameters found in the application config. :param app: Your Flask Application :param static_dir: The path to the ``static`` directory of your application (optional) :param asset_dir: The path to the ``assets`` directory where Flask-Scss will search ``.scss`` files (optional) :param load_paths: A list of folders to add to pyScss load_paths (for ex., the path to a library like Compass) ''' if not load_paths: load_paths = [] self.app = app self.asset_dir = self.set_asset_dir(asset_dir) self.static_dir = self.set_static_dir(static_dir) self.assets = {} self.partials = {} load_path_list = ([self.asset_dir] if self.asset_dir else []) \ + (load_paths or app.config.get('SCSS_LOAD_PATHS', [])) # pyScss.log = app.logger self.compiler = Compiler(search_path=load_path_list) if self.app.testing or self.app.debug: self.set_hooks() def set_asset_dir(self, asset_dir): asset_dir = asset_dir \ or self.app.config.get('SCSS_ASSET_DIR', None) \ or op.join(self.app.root_path, 'assets') if op.exists(op.join(asset_dir, 'scss')): return op.join(asset_dir, 'scss') if op.exists(asset_dir): return asset_dir return None def set_static_dir(self, static_dir): static_dir = static_dir \ or self.app.config.get('SCSS_STATIC_DIR', None) \ or op.join(self.app.root_path, self.app.static_folder) if op.exists(op.join(static_dir, 'css')): return op.join(static_dir, 'css') if op.exists(static_dir): return static_dir return None def set_hooks(self): if self.asset_dir is None: self.app.logger.warning("The asset directory cannot be found." "Flask-Scss extension has been disabled") return if self.static_dir is None: self.app.logger.warning("The static directory cannot be found." "Flask-Scss extension has been disabled") return self.app.logger.info("Pyscss loaded!") self.app.before_request(self.update_scss) def discover_scss(self): for folder, _, files in os.walk(self.asset_dir): for filename in fnmatch.filter(files, '*.scss'): src_path = op.join(folder, filename) if filename.startswith('_') and src_path not in self.partials: self.partials[src_path] = op.getmtime(src_path) elif src_path not in self.partials and src_path not in self.assets: dest_path = src_path.replace(self.asset_dir, self.static_dir).replace( '.scss', '.css') self.assets[src_path] = dest_path def partials_have_changed(self): res = False for partial, old_mtime in self.partials.items(): cur_mtime = op.getmtime(partial) if cur_mtime > old_mtime: res = True self.partials[partial] = cur_mtime return res def update_scss(self): self.discover_scss() if self.partials_have_changed(): for asset, dest_path in self.assets.items(): self.compile_scss(asset, dest_path) return for asset, dest_path in self.assets.items(): dest_mtime = op.getmtime(dest_path) \ if op.exists(dest_path) \ else -1 if op.getmtime(asset) > dest_mtime: self.compile_scss(asset, dest_path) def compile_scss(self, asset, dest_path): self.app.logger.info("[flask-pyscss] refreshing %s" % (dest_path, )) if not os.path.exists(op.dirname(dest_path)): os.makedirs(op.dirname(dest_path)) with codecs.open(dest_path, 'w', 'utf-8') as file_out: with open(asset) as file_in: file_out.write(self.compiler.compile_string(file_in.read()))
class Scss(object): ''' Main and only class for Flask-Scss. It is in charge on the discovery of .scss files and compiles them every time they are modified. Any application that wants to use Flask-Scss must create a instance of this class ''' def __init__(self, app, static_dir=None, asset_dir=None, load_paths=None): ''' See :ref:`scss_discovery_rules` and :ref:`static_discovery_rules` for more information about the impact of ``static_dir`` and ``asset_dir`` parameters. Parameters here has preedence over Parameters found in the application config. :param app: Your Flask Application :param static_dir: The path to the ``static`` directory of your application (optional) :param asset_dir: The path to the ``assets`` directory where Flask-Scss will search ``.scss`` files (optional) :param load_paths: A list of folders to add to pyScss load_paths (for ex., the path to a library like Compass) ''' if not load_paths: load_paths = [] self.app = app self.asset_dir = self.set_asset_dir(asset_dir) self.static_dir = self.set_static_dir(static_dir) self.assets = {} self.partials = {} load_path_list = ([self.asset_dir] if self.asset_dir else []) \ + (load_paths or app.config.get('SCSS_LOAD_PATHS', [])) # pyScss.log = app.logger self.compiler = Compiler(search_path=load_path_list) if self.app.testing or self.app.debug: self.set_hooks() def set_asset_dir(self, asset_dir): asset_dir = asset_dir \ or self.app.config.get('SCSS_ASSET_DIR', None) \ or op.join(self.app.root_path, 'assets') if op.exists(op.join(asset_dir, 'scss')): return op.join(asset_dir, 'scss') if op.exists(asset_dir): return asset_dir return None def set_static_dir(self, static_dir): static_dir = static_dir \ or self.app.config.get('SCSS_STATIC_DIR', None) \ or op.join(self.app.root_path, self.app.static_folder) if op.exists(op.join(static_dir, 'css')): return op.join(static_dir, 'css') if op.exists(static_dir): return static_dir return None def set_hooks(self): if self.asset_dir is None: self.app.logger.warning("The asset directory cannot be found." "Flask-Scss extension has been disabled") return if self.static_dir is None: self.app.logger.warning("The static directory cannot be found." "Flask-Scss extension has been disabled") return self.app.logger.info("Pyscss loaded!") self.app.before_request(self.update_scss) def discover_scss(self): for folder, _, files in os.walk(self.asset_dir): for filename in fnmatch.filter(files, '*.scss'): src_path = op.join(folder, filename) if filename.startswith('_') and src_path not in self.partials: self.partials[src_path] = op.getmtime(src_path) elif src_path not in self.partials and src_path not in self.assets: dest_path = src_path.replace( self.asset_dir, self.static_dir ).replace('.scss', '.css') self.assets[src_path] = dest_path def partials_have_changed(self): res = False for partial, old_mtime in self.partials.items(): cur_mtime = op.getmtime(partial) if cur_mtime > old_mtime: res = True self.partials[partial] = cur_mtime return res def update_scss(self): self.discover_scss() if self.partials_have_changed(): for asset, dest_path in self.assets.items(): self.compile_scss(asset, dest_path) return for asset, dest_path in self.assets.items(): dest_mtime = op.getmtime(dest_path) \ if op.exists(dest_path) \ else -1 if op.getmtime(asset) > dest_mtime: self.compile_scss(asset, dest_path) def compile_scss(self, asset, dest_path): self.app.logger.info("[flask-pyscss] refreshing %s" % (dest_path,)) if not os.path.exists(op.dirname(dest_path)): os.makedirs(op.dirname(dest_path)) with codecs.open(dest_path, 'w', 'utf-8') as file_out: with open(asset) as file_in: file_out.write(self.compiler.compile_string(file_in.read()))
def __init__(self, target, extensions=None, include_paths=None): super().__init__(target) self.extensions = extensions or ['.sass', '.scss'] self.include_paths = include_paths or [] self.compiler = Compiler(search_path=self.include_paths)
class SassRepl(object): def __init__(self, is_sass=False): # TODO it would be lovely to get these out of here, somehow self.namespace = Namespace(variables=_default_scss_vars) self.compiler = Compiler(namespace=self.namespace) self.compilation = self.compiler.make_compilation() self.legacy_compiler_options = {} self.source_file = SourceFile.from_string('', '<shell>', is_sass=is_sass) self.calculator = Calculator(self.namespace) def __call__(self, s): # TODO this is kind of invasive; surely it's possible to do this # without calling only private methods from pprint import pformat if s in ('exit', 'quit'): raise KeyboardInterrupt for s in s.split(';'): s = self.source_file.prepare_source(s.strip()) if not s: continue elif s.startswith('@'): scope = None properties = [] children = deque() rule = SassRule( self.source_file, namespace=self.namespace, legacy_compiler_options=self.legacy_compiler_options, properties=properties) block = UnparsedBlock(rule, 1, s, None) code, name = (s.split(None, 1) + [''])[:2] if code == '@option': self.compilation._at_options(self.calculator, rule, scope, block) continue elif code == '@import': self.compilation._at_import(self.calculator, rule, scope, block) continue elif code == '@include': final_cont = '' self.compilation._at_include(self.calculator, rule, scope, block) code = self.compilation._print_properties( properties).rstrip('\n') if code: final_cont += code if children: self.compilation.children.extendleft(children) self.compilation.parse_children() code = self.compilation._create_css( self.compilation.rules).rstrip('\n') if code: final_cont += code yield final_cont continue elif s == 'ls' or s.startswith('show(') or s.startswith( 'show ') or s.startswith('ls(') or s.startswith('ls '): m = re.match( r'(?:show|ls)(\()?\s*([^,/\\) ]*)(?:[,/\\ ]([^,/\\ )]+))*(?(1)\))', s, re.IGNORECASE) if m: name = m.group(2) code = m.group(3) name = name and name.strip().rstrip( 's') # remove last 's' as in functions code = code and code.strip() ns = self.namespace if not name: yield pformat( list( sorted( ['vars', 'options', 'mixins', 'functions']))) elif name in ('v', 'var', 'variable'): variables = dict(ns._variables) if code == '*': pass elif code: variables = dict((k, v) for k, v in variables.items() if code in k) else: variables = dict((k, v) for k, v in variables.items() if not k.startswith('$--')) yield pformat(variables) elif name in ('o', 'opt', 'option'): opts = self.legacy_compiler_options if code == '*': pass elif code: opts = dict( (k, v) for k, v in opts.items() if code in k) else: opts = dict((k, v) for k, v in opts.items()) yield pformat(opts) elif name in ('m', 'mix', 'mixin', 'f', 'func', 'funct', 'function'): if name.startswith('m'): funcs = dict(ns._mixins) elif name.startswith('f'): funcs = dict(ns._functions) if code == '*': pass elif code: funcs = dict((k, v) for k, v in funcs.items() if code in k[0]) else: pass # TODO print source when possible yield pformat(funcs) continue elif s.startswith('$') and (':' in s or '=' in s): prop, value = [a.strip() for a in _prop_split_re.split(s, 1)] prop = self.calculator.do_glob_math(prop) value = self.calculator.calculate(value) self.namespace.set_variable(prop, value) continue # TODO respect compress? try: yield (self.calculator.calculate(s).render()) except (SyntaxError, SassEvaluationError) as e: print("%s" % e, file=sys.stderr)
def compile( self, scss_string=None, scss_file=None, source_files=None, super_selector=None, filename=None, is_sass=None, line_numbers=True, import_static_css=False): """Compile Sass to CSS. Returns a single CSS string. This method is DEPRECATED; see :mod:`scss.compiler` instead. """ # Derive our root namespace self.scss_vars = _default_scss_vars.copy() if self._scss_vars is not None: self.scss_vars.update(self._scss_vars) root_namespace = Namespace( variables=self.scss_vars, functions=self._library, ) # Figure out search paths. Fall back from provided explicitly to # defined globally to just searching the current directory search_paths = ['.'] if self._search_paths is not None: assert not isinstance(self._search_paths, six.string_types), \ "`search_paths` should be an iterable, not a string" search_paths.extend(self._search_paths) else: if config.LOAD_PATHS: if isinstance(config.LOAD_PATHS, six.string_types): # Back-compat: allow comma-delimited search_paths.extend(config.LOAD_PATHS.split(',')) else: search_paths.extend(config.LOAD_PATHS) search_paths.extend(self._scss_opts.get('load_paths', [])) # Normalize a few old styles of options output_style = self._scss_opts.get('style', config.STYLE) if output_style is True: output_style = 'compressed' elif output_style is False: output_style = 'legacy' fixed_search_path = [] for path in search_paths: if isinstance(path, six.string_types): fixed_search_path.append(Path(path)) else: fixed_search_path.append(path) # Build the compiler compiler = Compiler( namespace=root_namespace, extensions=[ CoreExtension, ExtraExtension, FontsExtension, CompassExtension, BootstrapExtension, ], search_path=fixed_search_path, import_static_css=import_static_css, live_errors=self.live_errors, generate_source_map=self._scss_opts.get('debug_info', False), output_style=output_style, warn_unused_imports=self._scss_opts.get('warn_unused', False), ignore_parse_errors=config.DEBUG, loops_have_own_scopes=config.CONTROL_SCOPING, undefined_variables_fatal=config.FATAL_UNDEFINED, super_selector=super_selector or self.super_selector, ) # Gonna add the source files manually compilation = compiler.make_compilation() # Inject the files we know about # TODO how does this work with the expectation of absoluteness if source_files is not None: for source in source_files: compilation.add_source(source) elif scss_string is not None: source = SourceFile.from_string( scss_string, relpath=filename, is_sass=is_sass, ) compilation.add_source(source) elif scss_file is not None: # This is now the only way to allow forcibly overriding the # filename a source "thinks" it is with open(scss_file, 'rb') as f: source = SourceFile.from_file( f, relpath=filename or scss_file, is_sass=is_sass, ) compilation.add_source(source) # Plus the ones from the constructor if self._scss_files: for name, contents in list(self._scss_files.items()): source = SourceFile.from_string(contents, relpath=name) compilation.add_source(source) return compiler.call_and_catch_errors(compilation.run)
def compile( self, scss_string=None, scss_file=None, source_files=None, super_selector=None, filename=None, is_sass=None, line_numbers=True): """Compile Sass to CSS. Returns a single CSS string. This method is DEPRECATED; see :mod:`scss.compiler` instead. """ # Derive our root namespace self.scss_vars = _default_scss_vars.copy() if self._scss_vars is not None: self.scss_vars.update(self._scss_vars) root_namespace = Namespace( variables=self.scss_vars, functions=self._library, ) # Figure out search paths. Fall back from provided explicitly to # defined globally to just searching the current directory search_paths = ['.'] if self._search_paths is not None: assert not isinstance(self._search_paths, six.string_types), \ "`search_paths` should be an iterable, not a string" search_paths.extend(self._search_paths) else: if config.LOAD_PATHS: if isinstance(config.LOAD_PATHS, six.string_types): # Back-compat: allow comma-delimited search_paths.extend(config.LOAD_PATHS.split(',')) else: search_paths.extend(config.LOAD_PATHS) search_paths.extend(self._scss_opts.get('load_paths', [])) # Normalize a few old styles of options output_style = self._scss_opts.get('style', config.STYLE) if output_style is True: output_style = 'compressed' elif output_style is False: output_style = 'legacy' # Build the compiler compiler = Compiler( namespace=root_namespace, search_path=search_paths, live_errors=self.live_errors, generate_source_map=self._scss_opts.get('debug_info', False), output_style=output_style, warn_unused_imports=self._scss_opts.get('warn_unused', False), super_selector=super_selector or self.super_selector, ) # Gonna add the source files manually compilation = compiler.make_compilation() # Inject the files we know about # TODO how does this work with the expectation of absoluteness if source_files is not None: for source in source_files: compilation.add_source(source) elif scss_string is not None: source = SourceFile.from_string( scss_string, path=filename, is_sass=is_sass, ) compilation.add_source(source) elif scss_file is not None: source = SourceFile.from_filename( scss_file, path=filename, is_sass=is_sass, ) compilation.add_source(source) # Plus the ones from the constructor if self._scss_files: for name, contents in list(self._scss_files.items()): source = SourceFile.from_string(contents, path=name) compilation.add_source(source) return compiler.call_and_catch_errors(compilation.run)