class Compiler(object):
    """A Sass compiler.  Stores settings and knows how to fire off a
    compilation.  Main entry point into compiling Sass.
    """
    def __init__(
            self, root=Path(), search_path=(),
            namespace=None, extensions=(CoreExtension,),
            import_static_css=False,
            output_style='nested', generate_source_map=False,
            live_errors=False, warn_unused_imports=False,
            ignore_parse_errors=False,
            loops_have_own_scopes=True,
            undefined_variables_fatal=True,
            super_selector='',
            ):
        """Configure a compiler.

        :param root: Directory to treat as the "project root".  Search paths
            and some custom extensions (e.g. Compass) are relative to this
            directory.  Defaults to the current directory.
        :type root: :class:`pathlib.Path`
        :param search_path: List of paths to search for ``@import``s, relative
            to ``root``.  Absolute and parent paths are allowed here, but
            ``@import`` will refuse to load files that aren't in one of the
            directories here.  Defaults to only the root.
        :type search_path: list of strings, :class:`pathlib.Path` objects, or
            something that implements a similar interface (useful for custom
            pseudo filesystems)
        """
        # TODO perhaps polite to automatically cast any string paths to Path?
        # but have to be careful since the api explicitly allows dummy objects.
        if root is None:
            self.root = None
        else:
            self.root = root.resolve()

        self.search_path = tuple(
            self.normalize_path(path)
            for path in search_path
        )

        self.extensions = []
        if namespace is not None:
            self.extensions.append(NamespaceAdapterExtension(namespace))
        for extension in extensions:
            if isinstance(extension, Extension):
                self.extensions.append(extension)
            elif (isinstance(extension, type) and
                    issubclass(extension, Extension)):
                self.extensions.append(extension())
            elif isinstance(extension, Namespace):
                self.extensions.append(
                    NamespaceAdapterExtension(extension))
            else:
                raise TypeError(
                    "Expected an Extension or Namespace, got: {0!r}"
                    .format(extension)
                )

        if import_static_css:
            self.dynamic_extensions = ('.scss', '.sass', '.css')
            self.static_extensions = ()
        else:
            self.dynamic_extensions = ('.scss', '.sass')
            self.static_extensions = ('.css',)

        self.output_style = output_style
        self.generate_source_map = generate_source_map
        self.live_errors = live_errors
        self.warn_unused_imports = warn_unused_imports
        self.ignore_parse_errors = ignore_parse_errors
        self.loops_have_own_scopes = loops_have_own_scopes
        self.undefined_variables_fatal = undefined_variables_fatal
        self.super_selector = super_selector

    def normalize_path(self, path):
        if isinstance(path, six.string_types):
            path = Path(path)
        if path.is_absolute():
            return path
        if self.root is None:
            raise IOError("Can't make absolute path when root is None")
        return self.root / path

    def make_compilation(self):
        return Compilation(self)

    def call_and_catch_errors(self, f, *args, **kwargs):
        """Call the given function with the given arguments.  If it succeeds,
        return its return value.  If it raises a :class:`scss.errors.SassError`
        and `live_errors` is turned on, return CSS containing a traceback and
        error message.
        """
        try:
            return f(*args, **kwargs)
        except SassError as e:
            if self.live_errors:
                # TODO should this setting also capture and display warnings?
                return e.to_css()
            else:
                raise

    def compile(self, *filenames):
        # TODO this doesn't spit out the compilation itself, so if you want to
        # get something out besides just the output, you have to copy this
        # method.  that sucks.
        # TODO i think the right thing is to get all the constructors out of
        # SourceFile, since it's really the compiler that knows the import
        # paths and should be consulted about this.  reconsider all this (but
        # preserve it for now, SIGH) once importers are a thing
        compilation = self.make_compilation()
        for filename in filenames:
            # TODO maybe SourceFile should not be exposed to the end user, and
            # instead Compilation should have methods for add_string etc. that
            # can call normalize_path.
            # TODO it's not possible to inject custom files into the
            # /compiler/ as persistent across compiles, nor to provide "fake"
            # imports.  do we want the former?  is the latter better suited to
            # an extension?
            source = SourceFile.from_filename(self.normalize_path(filename))
            compilation.add_source(source)
        return self.call_and_catch_errors(compilation.run)

    def compile_sources(self, *sources):
        # TODO this api is not the best please don't use it.  this all needs to
        # be vastly simplified, still, somehow.
        compilation = self.make_compilation()
        for source in sources:
            compilation.add_source(source)
        return self.call_and_catch_errors(compilation.run)

    def compile_string(self, string):
        source = SourceFile.from_string(string)
        compilation = self.make_compilation()
        compilation.add_source(source)
        return self.call_and_catch_errors(compilation.run) class CoreExtension(Extension):
    name = 'core'
    namespace = Namespace()

    def handle_import(self, name, compilation, rule):
        """Implementation of the core Sass import mechanism, which just looks
        for files on disk.
        """
        # TODO this is all not terribly well-specified by Sass.  at worst,
        # it's unclear how far "upwards" we should be allowed to go.  but i'm
        # also a little fuzzy on e.g. how relative imports work from within a
        # file that's not actually in the search path.
        # TODO i think with the new origin semantics, i've made it possible to
        # import relative to the current file even if the current file isn't
        # anywhere in the search path.  is that right?
        path = PurePosixPath(name)

        search_exts = list(compilation.compiler.dynamic_extensions)
        if path.suffix and path.suffix in search_exts:
            basename = path.stem
        else:
            basename = path.name
        relative_to = path.parent
        search_path = []  # tuple of (origin, start_from)
        if relative_to.is_absolute():
            relative_to = PurePosixPath(*relative_to.parts[1:])
        elif rule.source_file.origin:
            # Search relative to the current file first, only if not doing an
            # absolute import
            search_path.append((
                rule.source_file.origin,
                rule.source_file.relpath.parent / relative_to,
            ))
        search_path.extend(
            (origin, relative_to)
            for origin in compilation.compiler.search_path
        )

        for prefix, suffix in product(('_', ''), search_exts):
            filename = prefix + basename + suffix
            for origin, relative_to in search_path:
                relpath = relative_to / filename
                # Lexically (ignoring symlinks!) eliminate .. from the part
                # of the path that exists within Sass-space.  pathlib
                # deliberately doesn't do this, but os.path does.
                relpath = PurePosixPath(os.path.normpath(str(relpath)))

                if rule.source_file.key == (origin, relpath):
                    # Avoid self-import
                    # TODO is this what ruby does?
                    continue

                path = origin / relpath
                if not path.exists():
                    continue

                # All good!
                # TODO if this file has already been imported, we'll do the
                # source preparation twice.  make it lazy.
                return SourceFile.read(origin, relpath) class FontsExtension(Extension):
    """Functions for creating and manipulating fonts."""
    name = 'fonts'
    namespace = Namespace() class Namespace(object):
    """..."""
    _mutable = True

    def __init__(self, variables=None, functions=None, mixins=None, mutable=True):
        self._mutable = mutable

        if variables is None:
            self._variables = VariableScope()
        else:
            # TODO parse into sass values once that's a thing, or require them
            # all to be
            self._variables = VariableScope([variables])

        if functions is None:
            self._functions = FunctionScope()
        else:
            self._functions = FunctionScope([functions._functions])

        self._mixins = MixinScope()

        self._imports = ImportScope()

    def _assert_mutable(self):
        if not self._mutable:
            raise AttributeError("This Namespace instance is immutable")

    @classmethod
    def derive_from(cls, *others):
        self = cls()
        if len(others) == 1:
            self._variables = others[0]._variables.new_child()
            self._functions = others[0]._functions.new_child()
            self._mixins = others[0]._mixins.new_child()
            self._imports = others[0]._imports.new_child()
        else:
            # Note that this will create a 2-dimensional scope where each of
            # these scopes is checked first in order.  TODO is this right?
            self._variables = VariableScope(other._variables for other in others)
            self._functions = FunctionScope(other._functions for other in others)
            self._mixins = MixinScope(other._mixins for other in others)
            self._imports = ImportScope(other._imports for other in others)
        return self

    def derive(self):
        """Return a new child namespace.  All existing variables are still
        readable and writeable, but any new variables will only exist within a
        new scope.
        """
        return type(self).derive_from(self)

    def declare(self, function):
        """Insert a Python function into this Namespace, detecting its name and
        argument count automatically.
        """
        self._auto_register_function(function, function.__name__)
        return function

    def declare_alias(self, name):
        """Insert a Python function into this Namespace with an
        explicitly-given name, but detect its argument count automatically.
        """
        def decorator(f):
            self._auto_register_function(f, name)
            return f

        return decorator

    def declare_internal(self, function):
        """Like declare(), but the registered function will also receive the
        current namespace as its first argument.  Useful for functions that
        inspect the state of the compilation, like ``variable-exists()``.
        Probably not so useful for anything else.
        """
        function._pyscss_needs_namespace = True
        self._auto_register_function(function, function.__name__, 1)
        return function

    def _auto_register_function(self, function, name, ignore_args=0):
        name = name.replace('_', '-').rstrip('-')
        argspec = inspect.getargspec(function)

        if argspec.varargs or argspec.keywords:
            # Accepts some arbitrary number of arguments
            arities = [None]
        else:
            # Accepts a fixed range of arguments
            if argspec.defaults:
                num_optional = len(argspec.defaults)
            else:
                num_optional = 0
            num_args = len(argspec.args) - ignore_args
            arities = range(num_args - num_optional, num_args + 1)

        for arity in arities:
            self.set_function(name, arity, function)

    @property
    def variables(self):
        return dict((k, self._variables[k]) for k in self._variables.keys())

    def variable(self, name, throw=False):
        name = normalize_var(name)
        return self._variables[name]

    def set_variable(self, name, value, local_only=False):
        self._assert_mutable()
        name = normalize_var(name)
        if not isinstance(value, Value):
            raise TypeError("Expected a Sass type, while setting %s got %r" % (name, value,))
        self._variables.set(name, value, force_local=local_only)

    def has_import(self, source):
        return source.path in self._imports

    def add_import(self, source, parent_rule):
        self._assert_mutable()
        self._imports[source.path] = [
            0,
            parent_rule.source_file.path,
            parent_rule.file_and_line,
        ]

    def use_import(self, import_key):
        self._assert_mutable()
        if import_key and import_key in self._imports:
            imports = self._imports[import_key]
            imports[0] += 1
            self.use_import(imports[1])

    def unused_imports(self):
        unused = []
        for import_key in self._imports.keys():
            imports = self._imports[import_key]
            if not imports[0]:
                unused.append((import_key[0], imports[2]))
        return unused

    def _get_callable(self, chainmap, name, arity):
        name = normalize_var(name)
        if arity is not None:
            # With explicit arity, try the particular arity before falling back
            # to the general case (None)
            try:
                return chainmap[name, arity]
            except KeyError:
                pass

        return chainmap[name, None]

    def _set_callable(self, chainmap, name, arity, cb):
        name = normalize_var(name)
        chainmap[name, arity] = cb

    def mixin(self, name, arity):
        return self._get_callable(self._mixins, name, arity)

    def set_mixin(self, name, arity, cb):
        self._assert_mutable()
        self._set_callable(self._mixins, name, arity, cb)

    def function(self, name, arity):
        return self._get_callable(self._functions, name, arity)

    def set_function(self, name, arity, cb):
        self._assert_mutable()
        self._set_callable(self._functions, name, arity, cb) BUILD_INFO = "pyScss v" + VERSION + " (" + REVISION + ")" PROJECT = "pyScss" VERSION = '.'.join(str(i) for i in VERSION_INFO) REVISION = '%04d%02d%02d' % DATE_INFO URL = 'http://github.com/Kronuz/pyScss' AUTHOR = "German M. Bravo (Kronuz)" AUTHOR_EMAIL = 'german.mb@gmail.com' LICENSE = "MIT" class SourceFile(object):
    """A single input file to be fed to the compiler.  Detects the encoding
    (according to CSS spec rules) and performs some light pre-processing.

    This class is mostly internal and you shouldn't have to worry about it.

    Source files are uniquely identified by their ``.key``, a 2-tuple of
    ``(origin, relpath)``.

    ``origin`` is an object from the compiler's search
    path, most often a directory represented by a :class:`pathlib.Path`.
    ``relpath`` is a relative path from there to the actual file, again usually
    a ``Path``.

    The idea here is that source files don't always actually come from the
    filesystem, yet import semantics are expressed in terms of paths.  By
    keeping the origin and relative path separate, it's possible for e.g.
    Django to swap in an object that has the ``Path`` interface, but actually
    looks for files in an arbitrary storage backend.  In that case it would
    make no sense to key files by their absolute path, as they may not exist on
    disk or even on the same machine.  Also, relative imports can then continue
    to work, because they're guaranteed to only try the same origin.

    The ``origin`` may thus be anything that implements a minimal ``Path``ish
    interface (division operator, ``.parent``, ``.resolve()``).  It may also be
    ``None``, indicating that the file came from a string or some other origin
    that can't usefully produce other files.

    ``relpath``, however, should always be a ``Path``. or string.  XXX only when origin  (There's little
    advantage to making it anything else.)  A ``relpath`` may **never** contain
    ".."; there is nothing above the origin.

    Note that one minor caveat of this setup is that it's possible for the same
    file on disk to be imported under two different names (even though symlinks
    are always resolved), if directories in the search path happen to overlap.
    """

    key = None
    """A 2-tuple of ``(origin, relpath)`` that uniquely identifies where the
    file came from and how to find its siblings.
    """

    def __init__(
            self, origin, relpath, contents, encoding=None,
            is_sass=None):
        """Not normally used.  See the three alternative constructors:
        :func:`SourceFile.from_file`, :func:`SourceFile.from_path`, and
        :func:`SourceFile.from_string`.
        """
        if not isinstance(contents, six.text_type):
            raise TypeError(
                "Expected text for 'contents', got {0}"
                .format(type(contents)))

        if origin and '..' in relpath.parts:
            raise ValueError(
                "relpath cannot contain ..: {0!r}".format(relpath))

        self.origin = origin
        self.relpath = relpath
        self.key = origin, relpath

        self.encoding = encoding
        if is_sass is None:
            # TODO autodetect from the contents if the extension is bogus
            # or missing?
            if origin:
                self.is_sass = relpath.suffix == '.sass'
            else:
                self.is_sass = False
        else:
            self.is_sass = is_sass
        self.contents = self.prepare_source(contents)

    @property
    def path(self):
        """Concatenation of ``origin`` and ``relpath``, as a string.  Used in
        stack traces and other debugging places.
        """
        if self.origin:
            return six.text_type(self.origin / self.relpath)
        else:
            return six.text_type(self.relpath)

    def __repr__(self):
        return "<{0} {1!r} from {2!r}>".format(
            type(self).__name__, self.relpath, self.origin)

    def __hash__(self):
        return hash(self.key)

    def __eq__(self, other):
        if self is other:
            return True

        if not isinstance(other, SourceFile):
            return NotImplemented

        return self.key == other.key

    def __ne__(self, other):
        return not self == other

    @classmethod
    def _key_from_path(cls, path, origin=MISSING):
        # Given an origin (which may be MISSING) and an absolute path,
        # return a key.
        if origin is MISSING:
            # Resolve only the parent, in case the file itself is a symlink
            origin = path.parent.resolve()
            relpath = Path(path.name)
        else:
            # Again, resolving the origin is fine; we just don't want to
            # resolve anything inside it, lest we ruin some intended symlink
            # structure
            origin = origin.resolve()
            # pathlib balks if this requires lexically ascending  <3
            relpath = path.relative_to(origin)

        return origin, relpath

    @classmethod
    def read(cls, origin, relpath, **kwargs):
        """Read a source file from an ``(origin, relpath)`` tuple, as would
        happen from an ``@import`` statement.
        """
        path = origin / relpath
        with path.open('rb') as f:
            return cls.from_file(f, origin, relpath, **kwargs)

    @classmethod
    def from_path(cls, path, origin=MISSING, **kwargs):
        """Read Sass source from a :class:`pathlib.Path`.

        If no origin is given, it's assumed to be the file's parent directory.
        """
        origin, relpath = cls._key_from_path(path, origin)

        # Open in binary mode so we can reliably detect the encoding
        with path.open('rb') as f:
            return cls.from_file(f, origin, relpath, **kwargs)

    # back-compat
    @classmethod
    def from_filename(cls, path_string, origin=MISSING, **kwargs):
        """ Read Sass source from a String specifying the path
        """
        path = Path(path_string)
        return cls.from_path(path, origin, **kwargs)

    @classmethod
    def from_file(cls, f, origin=MISSING, relpath=MISSING, **kwargs):
        """Read Sass source from a file or file-like object.

        If `origin` or `relpath` are missing, they are derived from the file's
        ``.name`` attribute as with `from_path`.  If it doesn't have one, the
        origin becomes None and the relpath becomes the file's repr.
        """
        contents = f.read()
        encoding = determine_encoding(contents)
        if isinstance(contents, six.binary_type):
            contents = contents.decode(encoding)

        if origin is MISSING or relpath is MISSING:
            filename = getattr(f, 'name', None)
            if filename is None:
                origin = None
                relpath = repr(f)
            else:
                origin, relpath = cls._key_from_path(Path(filename), origin)

        return cls(origin, relpath, contents, encoding=encoding, **kwargs)

    @classmethod
    def from_string(cls, string, relpath=None, encoding=None, is_sass=None):
        """Read Sass source from the contents of a string.

        The origin is always None.  `relpath` defaults to "string:...".
        """
        if isinstance(string, six.text_type):
            # Already decoded; we don't know what encoding to use for output,
            # though, so still check for a @charset.
            # TODO what if the given encoding conflicts with the one in the
            # file?  do we care?
            if encoding is None:
                encoding = determine_encoding(string)

            byte_contents = string.encode(encoding)
            text_contents = string
        elif isinstance(string, six.binary_type):
            encoding = determine_encoding(string)
            byte_contents = string
            text_contents = string.decode(encoding)
        else:
            raise TypeError("Expected text or bytes, got {0!r}".format(string))

        origin = None
        if relpath is None:
            m = hashlib.sha256()
            m.update(byte_contents)
            relpath = repr("string:{0}:{1}".format(
                m.hexdigest()[:16], text_contents[:100]))

        return cls(
            origin, relpath, text_contents, encoding=encoding,
            is_sass=is_sass,
        )

    def parse_scss_line(self, line, state):
        ret = ''

        if line is None:
            line = ''

        line = state['line_buffer'] + line

        if line and line[-1] == '\\':
            state['line_buffer'] = line[:-1]
            return ''
        else:
            state['line_buffer'] = ''

        output = state['prev_line']
        output = output.strip()

        state['prev_line'] = line

        ret += output
        ret += '\n'
        return ret

    def parse_sass_line(self, line, state):
        ret = ''

        if line is None:
            line = ''

        line = state['line_buffer'] + line

        if line and line[-1] == '\\':
            state['line_buffer'] = line[:-1]
            return ret
        else:
            state['line_buffer'] = ''

        indent = len(line) - len(line.lstrip())

        # make sure we support multi-space indent as long as indent is
        # consistent
        if indent and not state['indent_marker']:
            state['indent_marker'] = indent

        if state['indent_marker']:
            indent //= state['indent_marker']

        if indent == state['prev_indent']:
            # same indentation as previous line
            if state['prev_line']:
                state['prev_line'] += ';'
        elif indent > state['prev_indent']:
            # new indentation is greater than previous, we just entered a new
            # block
            state['prev_line'] += ' {'
            state['nested_blocks'] += 1
        else:
            # indentation is reset, we exited a block
            block_diff = state['prev_indent'] - indent
            if state['prev_line']:
                state['prev_line'] += ';'
            state['prev_line'] += ' }' * block_diff
            state['nested_blocks'] -= block_diff

        output = state['prev_line']
        output = output.strip()

        state['prev_indent'] = indent
        state['prev_line'] = line

        ret += output
        ret += '\n'
        return ret

    def prepare_source(self, codestr, sass=False):
        state = {
            'line_buffer': '',
            'prev_line': '',
            'prev_indent': 0,
            'nested_blocks': 0,
            'indent_marker': 0,
        }
        if self.is_sass:
            parse_line = self.parse_sass_line
        else:
            parse_line = self.parse_scss_line
        _codestr = codestr
        codestr = ''
        for line in _codestr.splitlines():
            codestr += parse_line(line, state)
        # parse the last line stored in prev_line buffer
        codestr += parse_line(None, state)

        # pop off the extra \n parse_line puts at the beginning
        codestr = codestr[1:]

        # protects codestr: "..." strings
        codestr = _strings_re.sub(
            lambda m: _reverse_safe_strings_re.sub(
                lambda n: _reverse_safe_strings[n.group(0)], m.group(0)),
            codestr)
        codestr = _urls_re.sub(
            lambda m: _reverse_safe_strings_re.sub(
                lambda n: _reverse_safe_strings[n.group(0)], m.group(0)),
            codestr)

        # removes multiple line comments
        codestr = _ml_comment_re.sub('', codestr)

        # removes inline comments, but not :// (protocol)
        codestr = _sl_comment_re.sub('', codestr)

        codestr = _safe_strings_re.sub(
            lambda m: _safe_strings[m.group(0)], codestr)

        # collapse the space in properties blocks
        codestr = _collapse_properties_space_re.sub(r'\1{', codestr)

        return codestr class String(Value):
    """Represents both CSS quoted string values and CSS identifiers (such as
    `left`).

    Makes no distinction between single and double quotes, except that the same
    quotes are preserved on string literals that pass through unmodified.
    Otherwise, double quotes are used.
    """

    sass_type_name = 'string'

    bad_identifier_rx = re.compile('[^-_a-zA-Z\x80-\U0010FFFF]')

    def __init__(self, value, quotes='"', literal=False):
        if isinstance(value, String):
            # TODO unclear if this should be here, but many functions rely on
            # it
            value = value.value
        elif isinstance(value, Number):
            # TODO this may only be necessary in the case of __radd__ and
            # number values
            value = six.text_type(value)

        if isinstance(value, six.binary_type):
            warn(FutureWarning(
                "String got a bytes type {0!r} "
                "-- this will no longer be supported in pyScss 2.0"
                .format(value)
            ))
            value = value.decode(DEFAULT_STRING_ENCODING)

        if not isinstance(value, six.text_type):
            raise TypeError("Expected string, got {0!r}".format(value))

        self.value = value
        self.quotes = quotes
        # TODO this isn't quite used yet
        if literal:
            self.original_literal = value
        else:
            self.original_literal = None

    @classmethod
    def unquoted(cls, value, literal=False):
        """Helper to create a string with no quotes."""
        return cls(value, quotes=None, literal=literal)

    def __hash__(self):
        return hash(self.value)

    def __repr__(self):
        if self.quotes:
            quotes = '(' + self.quotes + ')'
        else:
            quotes = ''
        return "<{0}{1} {2!r}>".format(
            type(self).__name__, quotes, self.value)

    def __eq__(self, other):
        return Boolean(isinstance(other, String) and self.value == other.value)

    def __add__(self, other):
        if isinstance(other, String):
            other_value = other.value
        else:
            other_value = other.render()

        return String(
            self.value + other_value,
            quotes='"' if self.quotes else None)

    def __mul__(self, other):
        # DEVIATION: Ruby Sass doesn't do this, because Ruby doesn't.  But
        # Python does, and in Ruby Sass it's just fatal anyway.
        if not isinstance(other, Number):
            return super(String, self).__mul__(other)

        if not other.is_unitless:
            raise TypeError("Can only multiply strings by unitless numbers")

        n = other.value
        if n != int(n):
            raise ValueError("Can only multiply strings by integers")

        return String(self.value * int(other.value), quotes=self.quotes)

    def _escape_character(self, match):
        """Given a single character, return it appropriately CSS-escaped."""
        # TODO is there any case where we'd want to use unicode escaping?
        # TODO unsure if this works with newlines
        return '\\' + match.group(0)

    def _is_name_start(self, ch):
        if ch == '_':
            return True
        if ord(ch) >= 128:
            return True
        if ch in string.ascii_letters:
            return True
        return False

    def render(self, compress=False):
        # TODO should preserve original literals here too -- even the quotes.
        # or at least that's what sass does.
        # Escape and add quotes as appropriate.
        if self.quotes is None:
            # If you deliberately construct a bareword with bogus CSS in it,
            # you're assumed to know what you're doing
            return self.value
        else:
            return self._render_quoted()

    def render_interpolated(self, compress=False):
        # Always render without quotes
        return self.value

    def _render_bareword(self):
        # TODO this is currently unused, and only implemented due to an
        # oversight, but would make for a much better implementation of
        # escape()

        # This is a bareword, so almost anything outside \w needs escaping
        ret = self.value
        ret = self.bad_identifier_rx.sub(self._escape_character, ret)

        # Also apply some minor quibbling rules about how barewords can
        # start: with a "name start", an escape, a hyphen followed by one
        # of those, or two hyphens.
        if not ret:
            # TODO is an unquoted empty string allowed to be rendered?
            pass
        elif ret[0] == '-':
            if ret[1] in '-\\' or self._is_name_start(ret[1]):
                pass
            else:
                # Escape the second character
                # TODO what if it's a digit, oops
                ret = ret[0] + '\\' + ret[1:]
        elif ret[0] == '\\' or self._is_name_start(ret[0]):
            pass
        else:
            # Escape the first character
            # TODO what if it's a digit, oops
            ret = '\\' + ret

        return ret

    def _render_quoted(self):
        # Strictly speaking, the only things we need to quote are the quotes
        # themselves, backslashes, and newlines.
        # TODO Ruby Sass takes backslashes in barewords literally, but treats
        # backslashes in quoted strings as escapes -- their mistake?
        # TODO In Ruby Sass, generated strings never have single quotes -- but
        # neither do variable interpolations, so I'm not sure what they're
        # doing
        quote = self.quotes

        ret = self.value
        ret = ret.replace('\\', '\\\\')
        ret = ret.replace(quote, '\\' + quote)
        # Note that a literal newline is ignored when escaped, so we have to
        # use the codepoint instead.  But we'll leave the newline as well, to
        # aid readability.
        ret = ret.replace('\n', '\\a\\\n')
        return quote + ret + quote
import os
import six
import scss.config as config
from pathlib import Path
from collections import namedtuple
from scss.calculator import Calculator
from scss.compiler import Compiler
from scss.extension.bootstrap import BootstrapExtension
from scss.extension.core import CoreExtension
from scss.extension.compass import CompassExtension
from scss.extension.extra import ExtraExtension
from scss.extension.fonts import FontsExtension
from scss.namespace import Namespace
from scss.scss_meta import (
    BUILD_INFO, PROJECT, VERSION, REVISION, URL, AUTHOR, AUTHOR_EMAIL, LICENSE,
)
from scss.source import SourceFile
from scss.types import String
from __future__ import absolute_import
from __future__ import print_function
from __future__ import unicode_literals
from __future__ import division





_default_scss_vars = {

    '$BUILD-INFO': String.unquoted(BUILD_INFO),