/usr/lib/python2.7/dist-packages/sassutils/wsgi.py is in python-libsass 0.11.0-2.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 | """:mod:`sassutils.wsgi` --- WSGI middleware for development purpose
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
"""
from __future__ import absolute_import, with_statement
import collections
import logging
import os
import os.path
from pkg_resources import resource_filename
from sass import CompileError
from .builder import Manifest
__all__ = 'SassMiddleware',
class SassMiddleware(object):
"""WSGI middleware for development purpose. Everytime a CSS file has
requested it finds a matched SASS/SCSS source file and then compiled
it into CSS.
It shows syntax errors in three ways:
Heading comment
The result CSS includes detailed error message in the heading
CSS comment e.g.:
.. code-block:: css
/*
Error: invalid property name
*/
Red text in ``body:before``
The result CSS draws detailed error message in ``:before``
pseudo-class of ``body`` element e.g.::
.. code-block:: css
/*
body:before {
content: 'Error: invalid property name';
color: maroon;
background-color: white;
}
*/
In most cases you could be aware of syntax error by refreshing your
working document because it will removes all other styles and leaves
only a red text.
:mod:`logging`
It logs syntax errors if exist during compilation to
``sassutils.wsgi.SassMiddleware`` logger with level ``ERROR``.
To enable this::
from logging import Formatter, StreamHandler, getLogger
logger = getLogger('sassutils.wsgi.SassMiddleware')
handler = StreamHandler(level=logging.ERROR)
formatter = Formatter(fmt='*' * 80 + '\n%(message)s\n' + '*' * 80)
handler.setFormatter(formatter)
logger.addHandler(handler)
Or simply::
import logging
logging.basicConfig()
:param app: the WSGI application to wrap
:type app: :class:`collections.Callable`
:param manifests: build settings. the same format to
:file:`setup.py` script's ``sass_manifests``
option
:type manifests: :class:`collections.Mapping`
:param package_dir: optional mapping of package names to directories.
the same format to :file:`setup.py` script's
``package_dir`` option
:type package_dir: :class:`collections.Mapping`
.. versionchanged:: 0.4.0
It creates also source map files with filenames followed by
:file:`.map` suffix.
.. versionadded:: 0.8.0
It logs syntax errors if exist during compilation to
``sassutils.wsgi.SassMiddleware`` logger with level ``ERROR``.
"""
def __init__(self, app, manifests, package_dir={},
error_status='200 OK'):
if not callable(app):
raise TypeError('app must be a WSGI-compliant callable object, '
'not ' + repr(app))
self.app = app
self.manifests = Manifest.normalize_manifests(manifests)
if not isinstance(package_dir, collections.Mapping):
raise TypeError('package_dir must be a mapping object, not ' +
repr(package_dir))
self.error_status = error_status
self.package_dir = dict(package_dir)
for package_name in self.manifests:
if package_name in self.package_dir:
continue
path = resource_filename(package_name, '')
self.package_dir[package_name] = path
self.paths = []
for package_name, manifest in self.manifests.items():
wsgi_path = manifest.wsgi_path
if not wsgi_path.startswith('/'):
wsgi_path = '/' + wsgi_path
if not wsgi_path.endswith('/'):
wsgi_path += '/'
package_dir = self.package_dir[package_name]
self.paths.append((wsgi_path, package_dir, manifest))
def __call__(self, environ, start_response):
path = environ.get('PATH_INFO', '/')
if path.endswith('.css'):
for prefix, package_dir, manifest in self.paths:
if not path.startswith(prefix):
continue
css_filename = path[len(prefix):]
sass_filename = css_filename[:-4]
try:
result = manifest.build_one(package_dir,
sass_filename,
source_map=True)
except (IOError, OSError):
break
except CompileError as e:
logger = logging.getLogger(__name__ + '.SassMiddleware')
logger.error(str(e))
start_response(
self.error_status,
[('Content-Type', 'text/css; charset=utf-8')]
)
return [
b'/*\n', str(e).encode('utf-8'), b'\n*/\n\n',
b'body:before { content: ',
self.quote_css_string(str(e)).encode('utf-8'),
b'; color: maroon; background-color: white',
b'; white-space: pre-wrap; display: block',
b'; font-family: "Courier New", monospace'
b'; user-select: text; }'
]
def read_file(path):
with open(path, 'rb') as in_:
while 1:
chunk = in_.read(4096)
if chunk:
yield chunk
else:
break
start_response('200 OK', [('Content-Type', 'text/css')])
return read_file(os.path.join(package_dir, result))
return self.app(environ, start_response)
@staticmethod
def quote_css_string(s):
"""Quotes a string as CSS string literal."""
return "'" + ''.join('\\%06x' % ord(c) for c in s) + "'"
|