From 7f76b7e4da9f2b2ce538bb94c25aabaec9c12150 Mon Sep 17 00:00:00 2001 From: su-fang Date: Tue, 11 Oct 2022 11:05:16 +0800 Subject: [PATCH] Import Upstream version 0.21.0 --- .ackrc | 3 + .coveragerc | 28 + .gitignore | 18 + .gitmodules | 3 + .pre-commit-config.yaml | 21 + CODE_OF_CONDUCT.md | 10 + CONTRIBUTING.rst | 69 ++ LICENSE | 19 + MANIFEST.in | 9 + README.rst | 117 ++ _sass.c | 701 ++++++++++++ azure-pipelines.yml | 42 + bin/build-manylinux-wheels | 43 + bin/download-windows-wheels | 59 + docs/Makefile | 153 +++ docs/changes.rst | 841 ++++++++++++++ docs/conf.py | 277 +++++ docs/frameworks/flask.rst | 175 +++ docs/index.rst | 165 +++ docs/make.bat | 190 ++++ docs/pysassc.rst | 5 + docs/sass.rst | 2 + docs/sassutils.rst | 9 + docs/sassutils/builder.rst | 3 + docs/sassutils/distutils.rst | 3 + docs/sassutils/wsgi.rst | 3 + pysassc.py | 243 ++++ requirements-dev.txt | 5 + sass.py | 869 ++++++++++++++ sassc.py | 15 + sasstests.py | 1703 ++++++++++++++++++++++++++++ sassutils/__init__.py | 7 + sassutils/_compat.py | 7 + sassutils/builder.py | 303 +++++ sassutils/distutils.py | 200 ++++ sassutils/wsgi.py | 175 +++ setup.cfg | 9 + setup.py | 298 +++++ test/_f.scss | 1 + test/a.scss | 11 + test/b.scss | 5 + test/c.scss | 7 + test/d.scss | 11 + test/e.scss | 2 + test/g.scss | 9 + test/h.sass | 3 + test/subdir/_sub.scss | 5 + test/subdir/recur.scss | 4 + testpkg/setup.py | 11 + testpkg/testpkg/__init__.py | 0 testpkg/testpkg/static/css/README | 1 + testpkg/testpkg/static/scss/a.scss | 8 + tox.ini | 17 + 53 files changed, 6897 insertions(+) create mode 100644 .ackrc create mode 100644 .coveragerc create mode 100644 .gitignore create mode 100644 .gitmodules create mode 100644 .pre-commit-config.yaml create mode 100644 CODE_OF_CONDUCT.md create mode 100644 CONTRIBUTING.rst create mode 100644 LICENSE create mode 100644 MANIFEST.in create mode 100644 README.rst create mode 100644 _sass.c create mode 100644 azure-pipelines.yml create mode 100755 bin/build-manylinux-wheels create mode 100755 bin/download-windows-wheels create mode 100644 docs/Makefile create mode 100644 docs/changes.rst create mode 100644 docs/conf.py create mode 100644 docs/frameworks/flask.rst create mode 100644 docs/index.rst create mode 100644 docs/make.bat create mode 100644 docs/pysassc.rst create mode 100644 docs/sass.rst create mode 100644 docs/sassutils.rst create mode 100644 docs/sassutils/builder.rst create mode 100644 docs/sassutils/distutils.rst create mode 100644 docs/sassutils/wsgi.rst create mode 100755 pysassc.py create mode 100644 requirements-dev.txt create mode 100644 sass.py create mode 100644 sassc.py create mode 100644 sasstests.py create mode 100644 sassutils/__init__.py create mode 100644 sassutils/_compat.py create mode 100644 sassutils/builder.py create mode 100644 sassutils/distutils.py create mode 100644 sassutils/wsgi.py create mode 100644 setup.cfg create mode 100644 setup.py create mode 100644 test/_f.scss create mode 100644 test/a.scss create mode 100644 test/b.scss create mode 100644 test/c.scss create mode 100644 test/d.scss create mode 100644 test/e.scss create mode 100644 test/g.scss create mode 100644 test/h.sass create mode 100644 test/subdir/_sub.scss create mode 100644 test/subdir/recur.scss create mode 100644 testpkg/setup.py create mode 100644 testpkg/testpkg/__init__.py create mode 100644 testpkg/testpkg/static/css/README create mode 100644 testpkg/testpkg/static/scss/a.scss create mode 100644 tox.ini diff --git a/.ackrc b/.ackrc new file mode 100644 index 0000000..27f7000 --- /dev/null +++ b/.ackrc @@ -0,0 +1,3 @@ +--ignore-dir=.tox +--ignore-dir=build +--ignore-dir=libsass.egg-info diff --git a/.coveragerc b/.coveragerc new file mode 100644 index 0000000..7ca69fd --- /dev/null +++ b/.coveragerc @@ -0,0 +1,28 @@ +[run] +parallel = True +branch = True +source = $PWD +data_file = $PWD/.coverage +omit = + */.tox/* + /usr/* + */setup.py + +[report] +show_missing = True +exclude_lines = + # Have to re-enable the standard pragma + \#\s*pragma: no cover + + # Don't complain if tests don't hit defensive assertion code: + ^\s*raise AssertionError\b + ^\s*raise NotImplementedError\b + ^\s*return NotImplemented\b + ^\s*raise TypeError\b + ^\s*raise$ + + # Don't complain if non-runnable code isn't run: + ^if __name__ == ['"]__main__['"]:$ + +[html] +directory = coverage-html diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ecba708 --- /dev/null +++ b/.gitignore @@ -0,0 +1,18 @@ +*.egg +*.egg-info +*.pyc +*.pyd +*.so +.*.swp +.DS_Store +._.DS_Store +.pytest_cache/ +.coverage +.tox +/.libsass-upstream-version +build/ +dist/ +docs/_build +testpkg/build/ +testpkg/dist/ +testpkg/testpkg/static/css/*.scss.css diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..975b971 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "libsass"] +path = libsass +url = git://github.com/sass/libsass.git diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..b869a00 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,21 @@ +repos: +- repo: https://github.com/pre-commit/pre-commit-hooks + rev: v4.0.1 + hooks: + - id: trailing-whitespace + - id: end-of-file-fixer + - id: check-yaml + - id: debug-statements +- repo: https://github.com/PyCQA/flake8 + rev: 3.9.2 + hooks: + - id: flake8 + exclude: ^docs/conf.py +- repo: https://github.com/asottile/pyupgrade + rev: v2.16.0 + hooks: + - id: pyupgrade +- repo: https://github.com/asottile/add-trailing-comma + rev: v2.1.0 + hooks: + - id: add-trailing-comma diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 0000000..c4164af --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,10 @@ +Sass is more than a technology; Sass is driven by the community of individuals +that power its development and use every day. As a community, we want to embrace +the very differences that have made our collaboration so powerful, and work +together to provide the best environment for learning, growing, and sharing of +ideas. It is imperative that we keep Sass a fun, welcoming, challenging, and +fair place to play. + +[The full community guidelines can be found on the Sass website.][link] + +[link]: https://sass-lang.com/community-guidelines diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst new file mode 100644 index 0000000..8e73415 --- /dev/null +++ b/CONTRIBUTING.rst @@ -0,0 +1,69 @@ +Contributor's guide +=================== + +Coding style +------------ + +- Follow `PEP 8`_. flake8_ would help. +- Order imports by lexicographical order. +- Prefer relative imports. +- All functions, classes, methods, attributes, and modules should have + the docstring. +- Functions and methods should contain ``:param:``, ``:type:`` + (``:return:``, ``:rtype`` if it returns something), + (``:raise:`` if it may raise an error) in their docstring. + +.. _flake8: https://gitlab.com/pycqa/flake8 +.. _PEP 8: https://www.python.org/dev/peps/pep-0008 + + +Tests +----- + +- All code patches should contain one or more unit tests or regression tests. +- All code patches have to successfully run tests on every Python version + we aim to support. tox_ would help. +- All commits will be tested by `Azure Pipelines`_ (Linux and Windows). + +.. _tox: https://tox.readthedocs.io/ +.. _`Azure Pipelines`: https://dev.azure.com/asottile/asottile/_build/latest?definitionId=22&branchName=master + + +Maintainer's guide +================== + +Releasing +--------- + +Here's a brief check list for releasing a new version: + +- Double check if the version is correctly bumped. + You can bump the version by changing ``__version__`` in sass.py file. + Note that it might be already bumped by other maintainers, + so check what's the latest release version from PyPI_. +- The changelog has to be complete, and frozen. + "To be released" sentence has to be replaced by the actual release date. +- If the code freeze for the release is done (including version bump), + tag the commit using ``git tag`` command. The tag name has to simply be + the version name e.g. ``1.2.3``. Of course, the tag also has to be pushed + to the upstream repository. +- Make a source distribution and upload it to PyPI + (``python3 setup.py sdist upload``). + If it's successful the new version must appear on PyPI_. +- `Azure Pipelines`_ automatically makes binary wheels for Windows, but each + CI build takes a while. These wheels are not automatically uploaded, + but there's ``./bin/download-windows-wheels`` script that downloads built + wheels. Then upload them with ``twine``. +- Run ``./bin/build-manylinux-wheels`` to build linux wheels and upload them to + PyPI (takes ~5 minutes). +- The `docs website`__ also has to be updated. + It's currently a static website deployed on GitHub Pages. + Use ``python setup.py upload_doc`` command. + Although it seems possible to be automated using Github Actions. +- Manually create a release through https://github.com/sass/libsass-python/releases/ + +Ping Hong Minhee (hongminhee@member.fsf.org, @dahlia on GitHub) if you need +any help! + +.. _PyPI: https://pypi.org/pypi/libsass/ +__ https://sass.github.io/libsass-python/ diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..9d04669 --- /dev/null +++ b/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2015 Hong Minhee + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/MANIFEST.in b/MANIFEST.in new file mode 100644 index 0000000..f8ba9f2 --- /dev/null +++ b/MANIFEST.in @@ -0,0 +1,9 @@ +recursive-include libsass *.c +recursive-include libsass *.cpp +recursive-include libsass *.h +recursive-include libsass *.hpp +include libsass/Makefile +include .libsass-upstream-version +include test/*.scss +include README.rst +include LICENSE diff --git a/README.rst b/README.rst new file mode 100644 index 0000000..5eab138 --- /dev/null +++ b/README.rst @@ -0,0 +1,117 @@ +libsass-python: Sass_/SCSS for Python +===================================== + +.. image:: https://badge.fury.io/py/libsass.svg + :alt: PyPI + :target: https://pypi.org/pypi/libsass/ + +.. image:: https://dev.azure.com/asottile/asottile/_apis/build/status/sass.libsass-python?branchName=master + :target: https://dev.azure.com/asottile/asottile/_build/latest?definitionId=22&branchName=master + :alt: Build Status + +.. image:: https://img.shields.io/azure-devops/coverage/asottile/asottile/22/master.svg + :target: https://dev.azure.com/asottile/asottile/_build/latest?definitionId=22&branchName=master + :alt: Coverage Status + +.. image:: https://results.pre-commit.ci/badge/github/sass/libsass-python/master.svg + :target: https://results.pre-commit.ci/latest/github/sass/libsass-python/master + :alt: pre-commit.ci status + +This package provides a simple Python extension module ``sass`` which is +binding LibSass_ (written in C/C++ by Hampton Catlin and Aaron Leung). +It's very straightforward and there isn't any headache related Python +distribution/deployment. That means you can add just ``libsass`` into +your ``setup.py``'s ``install_requires`` list or ``requirements.txt`` file. +Need no Ruby nor Node.js. + +It currently supports CPython 2.7, 3.6--3.8, and PyPy 2.3+! + +.. _Sass: https://sass-lang.com/ +.. _LibSass: https://github.com/sass/libsass + + +Features +-------- + +- You don't need any Ruby/Node.js stack at all, for development or deployment + either. +- Fast. (LibSass_ is written in C++.) +- Simple API. See the below example code for details. +- Custom functions. +- ``@import`` callbacks. +- Support both tabbed (Sass) and braces (SCSS) syntax. +- WSGI middleware for ease of development. + It automatically compiles Sass/SCSS files for each request. +- ``setuptools``/``distutils`` integration. + You can build all Sass/SCSS files using + ``setup.py build_sass`` command. +- Works also on PyPy. +- Provides prebuilt wheel_ binaries for Linux, Windows, and Mac. + +.. _wheel: https://www.python.org/dev/peps/pep-0427/ + + +Install +------- + +It's available on PyPI_, so you can install it using ``pip`` (or +``easy_install``): + +.. code-block:: console + + $ pip install libsass + +.. note:: + + libsass requires some features introduced by the recent C++ standard. + You need a C++ compiler that support those features. + See also libsass project's README_ file. + +.. _PyPI: https://pypi.org/pypi/libsass/ +.. _README: https://github.com/sass/libsass#readme + + +.. _example: + +Example +------- + +.. code-block:: pycon + + >>> import sass + >>> print sass.compile(string='a { b { color: blue; } }') + a b { + color: blue; } + + +Docs +---- + +There's the user guide manual and the full API reference for ``libsass``: + +https://sass.github.io/libsass-python/ + +You can build the docs by yourself: + +.. code-block:: console + + $ cd docs/ + $ make html + +The built docs will go to ``docs/_build/html/`` directory. + + +Credit +------ + +Hong Minhee wrote this Python binding of LibSass_. + +Hampton Catlin and Aaron Leung wrote LibSass_, which is portable C/C++ +implementation of Sass_. + +Hampton Catlin originally designed Sass_ language and wrote the first +reference implementation of it in Ruby. + +The above three are all distributed under `MIT license`_. + +.. _MIT license: https://mit-license.org/ diff --git a/_sass.c b/_sass.c new file mode 100644 index 0000000..a3bec29 --- /dev/null +++ b/_sass.c @@ -0,0 +1,701 @@ +#include +#include + +#if PY_MAJOR_VERSION >= 3 +#define PySass_IF_PY3(three, two) (three) +#define PySass_Object_Bytes(o) PyUnicode_AsUTF8String(PyObject_Str(o)) +#define COLLECTIONS_ABC_MOD "collections.abc" +#else +#define PySass_IF_PY3(three, two) (two) +#define PySass_Object_Bytes(o) PyObject_Str(o) +#define COLLECTIONS_ABC_MOD "collections" +#endif + +static PyObject* _to_py_value(const union Sass_Value* value); +static union Sass_Value* _to_sass_value(PyObject* value); + +static union Sass_Value* _color_to_sass_value(PyObject* value); +static union Sass_Value* _number_to_sass_value(PyObject* value); +static union Sass_Value* _list_to_sass_value(PyObject* value); +static union Sass_Value* _mapping_to_sass_value(PyObject* value); +static union Sass_Value* _unicode_to_sass_value(PyObject* value); +static union Sass_Value* _warning_to_sass_value(PyObject* value); +static union Sass_Value* _error_to_sass_value(PyObject* value); +static union Sass_Value* _unknown_type_to_sass_error(PyObject* value); +static union Sass_Value* _exception_to_sass_error(); + + +static PyObject* _to_py_value(const union Sass_Value* value) { + PyObject* retv = NULL; + PyObject* types_mod = PyImport_ImportModule("sass"); + PyObject* sass_comma = PyObject_GetAttrString(types_mod, "SASS_SEPARATOR_COMMA"); + PyObject* sass_space = PyObject_GetAttrString(types_mod, "SASS_SEPARATOR_SPACE"); + + switch (sass_value_get_tag(value)) { + case SASS_NULL: + retv = Py_None; + Py_INCREF(retv); + break; + case SASS_BOOLEAN: + retv = PyBool_FromLong(sass_boolean_get_value(value)); + break; + case SASS_STRING: + retv = PyUnicode_FromString(sass_string_get_value(value)); + break; + case SASS_NUMBER: + retv = PyObject_CallMethod( + types_mod, + "SassNumber", + PySass_IF_PY3("dy", "ds"), + sass_number_get_value(value), + sass_number_get_unit(value) + ); + break; + case SASS_COLOR: + retv = PyObject_CallMethod( + types_mod, + "SassColor", + "dddd", + sass_color_get_r(value), + sass_color_get_g(value), + sass_color_get_b(value), + sass_color_get_a(value) + ); + break; + case SASS_LIST: { + size_t i = 0; + PyObject* items = PyTuple_New(sass_list_get_length(value)); + PyObject* separator = sass_comma; + int is_bracketed = sass_list_get_is_bracketed(value); + PyObject* bracketed = PyBool_FromLong(is_bracketed); + switch (sass_list_get_separator(value)) { + case SASS_COMMA: + separator = sass_comma; + break; + case SASS_SPACE: + separator = sass_space; + break; + case SASS_HASH: + assert(0); + break; + } + for (i = 0; i < sass_list_get_length(value); i += 1) { + PyTuple_SetItem( + items, + i, + _to_py_value(sass_list_get_value(value, i)) + ); + } + retv = PyObject_CallMethod( + types_mod, "SassList", "OOO", items, separator, bracketed + ); + break; + } + case SASS_MAP: { + size_t i = 0; + PyObject* items = PyTuple_New(sass_map_get_length(value)); + for (i = 0; i < sass_map_get_length(value); i += 1) { + PyObject* kvp = PyTuple_New(2); + PyTuple_SetItem( + kvp, 0, _to_py_value(sass_map_get_key(value, i)) + ); + PyTuple_SetItem( + kvp, 1, _to_py_value(sass_map_get_value(value, i)) + ); + PyTuple_SetItem(items, i, kvp); + } + retv = PyObject_CallMethod(types_mod, "SassMap", "(O)", items); + Py_DECREF(items); + break; + } + case SASS_ERROR: + case SASS_WARNING: + /* @warning and @error cannot be passed */ + break; + } + + if (retv == NULL) { + PyErr_SetString(PyExc_TypeError, "Unexpected sass type"); + } + + Py_DECREF(types_mod); + Py_DECREF(sass_comma); + Py_DECREF(sass_space); + return retv; +} + +static union Sass_Value* _color_to_sass_value(PyObject* value) { + union Sass_Value* retv = NULL; + PyObject* r_value = PyObject_GetAttrString(value, "r"); + PyObject* g_value = PyObject_GetAttrString(value, "g"); + PyObject* b_value = PyObject_GetAttrString(value, "b"); + PyObject* a_value = PyObject_GetAttrString(value, "a"); + retv = sass_make_color( + PyFloat_AsDouble(r_value), + PyFloat_AsDouble(g_value), + PyFloat_AsDouble(b_value), + PyFloat_AsDouble(a_value) + ); + Py_DECREF(r_value); + Py_DECREF(g_value); + Py_DECREF(b_value); + Py_DECREF(a_value); + return retv; +} + +static union Sass_Value* _list_to_sass_value(PyObject* value) { + PyObject* types_mod = PyImport_ImportModule("sass"); + PyObject* sass_comma = PyObject_GetAttrString(types_mod, "SASS_SEPARATOR_COMMA"); + PyObject* sass_space = PyObject_GetAttrString(types_mod, "SASS_SEPARATOR_SPACE"); + union Sass_Value* retv = NULL; + Py_ssize_t i = 0; + PyObject* items = PyObject_GetAttrString(value, "items"); + PyObject* separator = PyObject_GetAttrString(value, "separator"); + PyObject* bracketed = PyObject_GetAttrString(value, "bracketed"); + enum Sass_Separator sep = SASS_COMMA; + if (separator == sass_comma) { + sep = SASS_COMMA; + } else if (separator == sass_space) { + sep = SASS_SPACE; + } else { + assert(0); + } + int is_bracketed = bracketed == Py_True; + retv = sass_make_list(PyTuple_Size(items), sep, is_bracketed); + for (i = 0; i < PyTuple_Size(items); i += 1) { + sass_list_set_value( + retv, i, _to_sass_value(PyTuple_GetItem(items, i)) + ); + } + Py_DECREF(types_mod); + Py_DECREF(sass_comma); + Py_DECREF(sass_space); + Py_DECREF(items); + Py_DECREF(separator); + Py_DECREF(bracketed); + return retv; +} + +static union Sass_Value* _mapping_to_sass_value(PyObject* value) { + union Sass_Value* retv = NULL; + size_t i = 0; + Py_ssize_t pos = 0; + PyObject* d_key = NULL; + PyObject* d_value = NULL; + PyObject* dct = PyDict_New(); + PyDict_Update(dct, value); + retv = sass_make_map(PyDict_Size(dct)); + while (PyDict_Next(dct, &pos, &d_key, &d_value)) { + sass_map_set_key(retv, i, _to_sass_value(d_key)); + sass_map_set_value(retv, i, _to_sass_value(d_value)); + i += 1; + } + Py_DECREF(dct); + return retv; +} + +static union Sass_Value* _number_to_sass_value(PyObject* value) { + union Sass_Value* retv = NULL; + PyObject* d_value = PyObject_GetAttrString(value, "value"); + PyObject* unit = PyObject_GetAttrString(value, "unit"); + PyObject* bytes = PyUnicode_AsEncodedString(unit, "UTF-8", "strict"); + retv = sass_make_number( + PyFloat_AsDouble(d_value), PyBytes_AsString(bytes) + ); + Py_DECREF(d_value); + Py_DECREF(unit); + Py_DECREF(bytes); + return retv; +} + +static union Sass_Value* _unicode_to_sass_value(PyObject* value) { + union Sass_Value* retv = NULL; + PyObject* bytes = PyUnicode_AsEncodedString(value, "UTF-8", "strict"); + retv = sass_make_string(PyBytes_AsString(bytes)); + Py_DECREF(bytes); + return retv; +} + +static union Sass_Value* _warning_to_sass_value(PyObject* value) { + union Sass_Value* retv = NULL; + PyObject* msg = PyObject_GetAttrString(value, "msg"); + PyObject* bytes = PyUnicode_AsEncodedString(msg, "UTF-8", "strict"); + retv = sass_make_warning(PyBytes_AsString(bytes)); + Py_DECREF(msg); + Py_DECREF(bytes); + return retv; +} + +static union Sass_Value* _error_to_sass_value(PyObject* value) { + union Sass_Value* retv = NULL; + PyObject* msg = PyObject_GetAttrString(value, "msg"); + PyObject* bytes = PyUnicode_AsEncodedString(msg, "UTF-8", "strict"); + retv = sass_make_error(PyBytes_AsString(bytes)); + Py_DECREF(msg); + Py_DECREF(bytes); + return retv; +} + +static union Sass_Value* _unknown_type_to_sass_error(PyObject* value) { + union Sass_Value* retv = NULL; + PyObject* type = PyObject_Type(value); + PyObject* type_name = PyObject_GetAttrString(type, "__name__"); + PyObject* fmt = PyUnicode_FromString( + "Unexpected type: `{0}`.\n" + "Expected one of:\n" + "- None\n" + "- bool\n" + "- str\n" + "- SassNumber\n" + "- SassColor\n" + "- SassList\n" + "- dict\n" + "- SassMap\n" + "- SassWarning\n" + "- SassError\n" + ); + PyObject* format_meth = PyObject_GetAttrString(fmt, "format"); + PyObject* result = PyObject_CallFunctionObjArgs( + format_meth, type_name, NULL + ); + PyObject* bytes = PyUnicode_AsEncodedString(result, "UTF-8", "strict"); + retv = sass_make_error(PyBytes_AsString(bytes)); + Py_DECREF(type); + Py_DECREF(type_name); + Py_DECREF(fmt); + Py_DECREF(format_meth); + Py_DECREF(result); + Py_DECREF(bytes); + return retv; +} + +static PyObject* _exception_to_bytes() { + PyObject* retv = NULL; + PyObject* etype = NULL; + PyObject* evalue = NULL; + PyObject* etb = NULL; + PyErr_Fetch(&etype, &evalue, &etb); + PyErr_NormalizeException(&etype, &evalue, &etb); + { + PyObject* traceback_mod = PyImport_ImportModule("traceback"); + PyObject* traceback_parts = PyObject_CallMethod( + traceback_mod, "format_exception", "OOO", etype, evalue, etb + ); + PyList_Insert(traceback_parts, 0, PyUnicode_FromString("\n")); + PyObject* joinstr = PyUnicode_FromString(""); + PyObject* result = PyUnicode_Join(joinstr, traceback_parts); + retv = PyUnicode_AsEncodedString(result, "UTF-8", "strict"); + Py_DECREF(traceback_mod); + Py_DECREF(traceback_parts); + Py_DECREF(joinstr); + Py_DECREF(result); + } + Py_DECREF(etype); + Py_DECREF(evalue); + Py_DECREF(etb); + return retv; +} + +static union Sass_Value* _exception_to_sass_error() { + PyObject* bytes = _exception_to_bytes(); + union Sass_Value* retv = sass_make_error(PyBytes_AsString(bytes)); + Py_DECREF(bytes); + return retv; +} + +static Sass_Import_List _exception_to_sass_import_error(const char* path) { + PyObject* bytes = _exception_to_bytes(); + Sass_Import_List import_list = sass_make_import_list(1); + import_list[0] = sass_make_import_entry(path, 0, 0); + sass_import_set_error(import_list[0], PyBytes_AsString(bytes), 0, 0); + Py_DECREF(bytes); + return import_list; +} + +static union Sass_Value* _to_sass_value(PyObject* value) { + union Sass_Value* retv = NULL; + PyObject* types_mod = PyImport_ImportModule("sass"); + PyObject* sass_number_t = PyObject_GetAttrString(types_mod, "SassNumber"); + PyObject* sass_color_t = PyObject_GetAttrString(types_mod, "SassColor"); + PyObject* sass_list_t = PyObject_GetAttrString(types_mod, "SassList"); + PyObject* sass_warning_t = PyObject_GetAttrString(types_mod, "SassWarning"); + PyObject* sass_error_t = PyObject_GetAttrString(types_mod, "SassError"); + PyObject* collections_mod = PyImport_ImportModule(COLLECTIONS_ABC_MOD); + PyObject* mapping_t = PyObject_GetAttrString(collections_mod, "Mapping"); + + if (value == Py_None) { + retv = sass_make_null(); + } else if (PyBool_Check(value)) { + retv = sass_make_boolean(value == Py_True); + } else if (PyUnicode_Check(value)) { + retv = _unicode_to_sass_value(value); + } else if (PyBytes_Check(value)) { + retv = sass_make_string(PyBytes_AsString(value)); + /* XXX: PyMapping_Check returns true for lists and tuples in python3 :( */ + /* XXX: pypy derps on dicts: https://bitbucket.org/pypy/pypy/issue/1970 */ + } else if (PyDict_Check(value) || PyObject_IsInstance(value, mapping_t)) { + retv = _mapping_to_sass_value(value); + } else if (PyObject_IsInstance(value, sass_number_t)) { + retv = _number_to_sass_value(value); + } else if (PyObject_IsInstance(value, sass_color_t)) { + retv = _color_to_sass_value(value); + } else if (PyObject_IsInstance(value, sass_list_t)) { + retv = _list_to_sass_value(value); + } else if (PyObject_IsInstance(value, sass_warning_t)) { + retv = _warning_to_sass_value(value); + } else if (PyObject_IsInstance(value, sass_error_t)) { + retv = _error_to_sass_value(value); + } + + if (retv == NULL) { + retv = _unknown_type_to_sass_error(value); + } + + Py_DECREF(types_mod); + Py_DECREF(sass_number_t); + Py_DECREF(sass_color_t); + Py_DECREF(sass_list_t); + Py_DECREF(sass_warning_t); + Py_DECREF(sass_error_t); + Py_DECREF(collections_mod); + Py_DECREF(mapping_t); + return retv; +} + +static union Sass_Value* _call_py_f( + const union Sass_Value* sass_args, + Sass_Function_Entry cb, + struct Sass_Compiler* compiler +) { + size_t i; + PyObject* pyfunc = (PyObject*)sass_function_get_cookie(cb); + PyObject* py_args = PyTuple_New(sass_list_get_length(sass_args)); + PyObject* py_result = NULL; + union Sass_Value* sass_result = NULL; + + for (i = 0; i < sass_list_get_length(sass_args); i += 1) { + const union Sass_Value* sass_arg = sass_list_get_value(sass_args, i); + PyObject* py_arg = NULL; + if (!(py_arg = _to_py_value(sass_arg))) goto done; + PyTuple_SetItem(py_args, i, py_arg); + } + + if (!(py_result = PyObject_CallObject(pyfunc, py_args))) goto done; + sass_result = _to_sass_value(py_result); + +done: + if (sass_result == NULL) { + sass_result = _exception_to_sass_error(); + } + Py_XDECREF(py_args); + Py_XDECREF(py_result); + return sass_result; +} + + +static void _add_custom_functions( + struct Sass_Options* options, PyObject* custom_functions +) { + Py_ssize_t i; + Sass_Function_List fn_list = sass_make_function_list( + PyList_Size(custom_functions) + ); + for (i = 0; i < PyList_Size(custom_functions); i += 1) { + PyObject* sass_function = PyList_GetItem(custom_functions, i); + PyObject* signature = PySass_Object_Bytes(sass_function); + Sass_Function_Entry fn = sass_make_function( + PyBytes_AsString(signature), + _call_py_f, + sass_function + ); + sass_function_set_list_entry(fn_list, i, fn); + } + sass_option_set_c_functions(options, fn_list); +} + +static Sass_Import_List _call_py_importer_f( + const char* path, Sass_Importer_Entry cb, struct Sass_Compiler* comp +) { + PyObject* pyfunc = (PyObject*)sass_importer_get_cookie(cb); + PyObject* py_result = NULL; + Sass_Import_List sass_imports = NULL; + struct Sass_Import* previous; + const char* prev_path; + Py_ssize_t i; + + previous = sass_compiler_get_last_import(comp); + prev_path = sass_import_get_abs_path(previous); + + py_result = PyObject_CallFunction(pyfunc, PySass_IF_PY3("yy", "ss"), path, prev_path); + + /* Handle importer throwing an exception */ + if (!py_result) goto done; + + /* Could return None indicating it could not handle the import */ + if (py_result == Py_None) { + Py_XDECREF(py_result); + return NULL; + } + + /* Otherwise, we know our importer is well formed (because we wrap it) + * The return value will be a tuple of 1, 2, or 3 tuples */ + sass_imports = sass_make_import_list(PyTuple_Size(py_result)); + for (i = 0; i < PyTuple_Size(py_result); i += 1) { + char* path_str = NULL; /* XXX: Memory leak? */ + char* source_str = NULL; + char* sourcemap_str = NULL; + PyObject* tup = PyTuple_GetItem(py_result, i); + Py_ssize_t size = PyTuple_Size(tup); + + if (size == 1) { + PyArg_ParseTuple(tup, PySass_IF_PY3("y", "s"), &path_str); + } else if (size == 2) { + PyArg_ParseTuple( + tup, PySass_IF_PY3("yy", "ss"), &path_str, &source_str + ); + } else if (size == 3) { + PyArg_ParseTuple( + tup, PySass_IF_PY3("yyy", "sss"), + &path_str, &source_str, &sourcemap_str + ); + } + + /* We need to give copies of these arguments; libsass handles + * deallocation of them later, whereas path_str is left flapping + * in the breeze -- it's treated const, so that's okay. */ + if (source_str) source_str = sass_copy_c_string(source_str); + if (sourcemap_str) sourcemap_str = sass_copy_c_string(sourcemap_str); + + sass_imports[i] = sass_make_import_entry( + path_str, source_str, sourcemap_str + ); + } + +done: + if (sass_imports == NULL) { + sass_imports = _exception_to_sass_import_error(path); + } + + Py_XDECREF(py_result); + + return sass_imports; +} + +static void _add_custom_importers( + struct Sass_Options* options, PyObject* custom_importers +) { + Py_ssize_t i; + Sass_Importer_List importer_list; + + if (custom_importers == Py_None) { + return; + } + + importer_list = sass_make_importer_list(PyTuple_Size(custom_importers)); + + for (i = 0; i < PyTuple_Size(custom_importers); i += 1) { + PyObject* item = PyTuple_GetItem(custom_importers, i); + int priority = 0; + PyObject* import_function = NULL; + + PyArg_ParseTuple(item, "iO", &priority, &import_function); + + importer_list[i] = sass_make_importer( + _call_py_importer_f, priority, import_function + ); + } + + sass_option_set_c_importers(options, importer_list); +} + +static PyObject * +PySass_compile_string(PyObject *self, PyObject *args) { + struct Sass_Context *ctx; + struct Sass_Data_Context *context; + struct Sass_Options *options; + char *string, *include_paths; + const char *error_message, *output_string; + enum Sass_Output_Style output_style; + int source_comments, error_status, precision, indented, + source_map_embed, source_map_contents, + omit_source_map_url; + PyObject *custom_functions; + PyObject *custom_importers; + PyObject *source_map_root; + PyObject *result; + + if (!PyArg_ParseTuple(args, + PySass_IF_PY3("yiiyiOiOiiiO", "siisiOiOiiiO"), + &string, &output_style, &source_comments, + &include_paths, &precision, + &custom_functions, &indented, &custom_importers, + &source_map_contents, &source_map_embed, + &omit_source_map_url, &source_map_root)) { + return NULL; + } + + context = sass_make_data_context(sass_copy_c_string(string)); + options = sass_data_context_get_options(context); + sass_option_set_output_style(options, output_style); + sass_option_set_source_comments(options, source_comments); + sass_option_set_include_path(options, include_paths); + sass_option_set_precision(options, precision); + sass_option_set_is_indented_syntax_src(options, indented); + sass_option_set_source_map_contents(options, source_map_contents); + sass_option_set_source_map_embed(options, source_map_embed); + sass_option_set_omit_source_map_url(options, omit_source_map_url); + + if (PyBytes_Check(source_map_root) && PyBytes_Size(source_map_root)) { + sass_option_set_source_map_root( + options, PyBytes_AsString(source_map_root) + ); + } + + _add_custom_functions(options, custom_functions); + _add_custom_importers(options, custom_importers); + sass_compile_data_context(context); + + ctx = sass_data_context_get_context(context); + error_status = sass_context_get_error_status(ctx); + error_message = sass_context_get_error_message(ctx); + output_string = sass_context_get_output_string(ctx); + result = Py_BuildValue( + PySass_IF_PY3("hy", "hs"), + (short int) !error_status, + error_status ? error_message : output_string + ); + sass_delete_data_context(context); + return result; +} + +static PyObject * +PySass_compile_filename(PyObject *self, PyObject *args) { + struct Sass_Context *ctx; + struct Sass_File_Context *context; + struct Sass_Options *options; + char *filename, *include_paths; + const char *error_message, *output_string, *source_map_string; + enum Sass_Output_Style output_style; + int source_comments, error_status, precision, source_map_embed, + source_map_contents, omit_source_map_url; + PyObject *source_map_filename, *custom_functions, *custom_importers, + *result, *output_filename_hint, *source_map_root; + + if (!PyArg_ParseTuple(args, + PySass_IF_PY3("yiiyiOOOOiiiO", "siisiOOOOiiiO"), + &filename, &output_style, &source_comments, + &include_paths, &precision, + &source_map_filename, &custom_functions, + &custom_importers, &output_filename_hint, + &source_map_contents, &source_map_embed, + &omit_source_map_url, &source_map_root)) { + return NULL; + } + + context = sass_make_file_context(filename); + options = sass_file_context_get_options(context); + + if (PyBytes_Check(source_map_filename)) { + if (PyBytes_Size(source_map_filename)) { + sass_option_set_source_map_file( + options, PyBytes_AsString(source_map_filename) + ); + } + } + if (PyBytes_Check(output_filename_hint)) { + if (PyBytes_Size(output_filename_hint)) { + sass_option_set_output_path( + options, PyBytes_AsString(output_filename_hint) + ); + } + } + + if (PyBytes_Check(source_map_root) && PyBytes_Size(source_map_root)) { + sass_option_set_source_map_root( + options, PyBytes_AsString(source_map_root) + ); + } + + sass_option_set_output_style(options, output_style); + sass_option_set_source_comments(options, source_comments); + sass_option_set_include_path(options, include_paths); + sass_option_set_precision(options, precision); + sass_option_set_source_map_contents(options, source_map_contents); + sass_option_set_source_map_embed(options, source_map_embed); + sass_option_set_omit_source_map_url(options, omit_source_map_url); + _add_custom_functions(options, custom_functions); + _add_custom_importers(options, custom_importers); + sass_compile_file_context(context); + + ctx = sass_file_context_get_context(context); + error_status = sass_context_get_error_status(ctx); + error_message = sass_context_get_error_message(ctx); + output_string = sass_context_get_output_string(ctx); + source_map_string = sass_context_get_source_map_string(ctx); + result = Py_BuildValue( + PySass_IF_PY3("hyy", "hss"), + (short int) !error_status, + error_status ? error_message : output_string, + error_status || source_map_string == NULL ? "" : source_map_string + ); + sass_delete_file_context(context); + return result; +} + +static PyMethodDef PySass_methods[] = { + {"compile_string", PySass_compile_string, METH_VARARGS, + "Compile a Sass string."}, + {"compile_filename", PySass_compile_filename, METH_VARARGS, + "Compile a Sass file."}, + {NULL, NULL, 0, NULL} +}; + +static char PySass_doc[] = "The thin binding of libsass for Python."; + +PyObject* PySass_make_enum_dict() { + PyObject* dct = PyDict_New(); + PyDict_SetItemString(dct, "nested", PyLong_FromLong(SASS_STYLE_NESTED)); + PyDict_SetItemString(dct, "expanded", PyLong_FromLong(SASS_STYLE_EXPANDED)); + PyDict_SetItemString(dct, "compact", PyLong_FromLong(SASS_STYLE_COMPACT)); + PyDict_SetItemString(dct, "compressed", PyLong_FromLong(SASS_STYLE_COMPRESSED)); + return dct; +} + +void PySass_init_module(PyObject *module) { + PyModule_AddObject(module, "OUTPUT_STYLES", PySass_make_enum_dict()); + PyModule_AddObject(module, "libsass_version", PyUnicode_FromString(libsass_version())); +} + +#if PY_MAJOR_VERSION >= 3 + +static struct PyModuleDef sassmodule = { + PyModuleDef_HEAD_INIT, + "_sass", + PySass_doc, + -1, + PySass_methods +}; + +PyMODINIT_FUNC +PyInit__sass() +{ + PyObject *module = PyModule_Create(&sassmodule); + if (module != NULL) { + PySass_init_module(module); + } + return module; +} + +#else + +PyMODINIT_FUNC +init_sass() +{ + PyObject *module; + module = Py_InitModule3("_sass", PySass_methods, PySass_doc); + if (module != NULL) { + PySass_init_module(module); + } +} + +#endif diff --git a/azure-pipelines.yml b/azure-pipelines.yml new file mode 100644 index 0000000..7a1584c --- /dev/null +++ b/azure-pipelines.yml @@ -0,0 +1,42 @@ +trigger: + branches: + include: [master, test-me-*] + tags: + include: ['*'] + +resources: + repositories: + - repository: self + checkoutOptions: + submodules: true + - repository: asottile + type: github + endpoint: github + name: asottile/azure-pipeline-templates + ref: refs/tags/v2.1.0 + +jobs: +- template: job--python-tox.yml@asottile + parameters: + toxenvs: [py27, py36] + os: macos + wheel_tags: true +- template: job--python-tox.yml@asottile + parameters: + toxenvs: [py27] + os: windows + architectures: [x64, x86] + name_postfix: _py27 + wheel_tags: true + pre_test: + - script: rm -rf libsass/test +- template: job--python-tox.yml@asottile + parameters: + toxenvs: [py36] + os: windows + architectures: [x64, x86] + wheel_tags: true +- template: job--python-tox.yml@asottile + parameters: + toxenvs: [pypy, pypy3, py27, py36, py37, py38, py39] + os: linux diff --git a/bin/build-manylinux-wheels b/bin/build-manylinux-wheels new file mode 100755 index 0000000..6d42531 --- /dev/null +++ b/bin/build-manylinux-wheels @@ -0,0 +1,43 @@ +#!/usr/bin/env python3 +"""Script for building 'manylinux' wheels for libsass. + +Run me after putting the source distribution on pypi. + +See: https://www.python.org/dev/peps/pep-0513/ +""" +import os +import pipes +import subprocess +import tempfile + + +def check_call(*cmd): + print( + 'build-manylinux-wheels>> ' + + ' '.join(pipes.quote(part) for part in cmd), + ) + subprocess.check_call(cmd) + + +def main(): + os.makedirs('dist', exist_ok=True) + for python in ('cp27-cp27mu', 'cp36-cp36m'): + with tempfile.TemporaryDirectory() as work: + pip = '/opt/python/{}/bin/pip'.format(python) + check_call( + 'docker', 'run', '-ti', + # Use this so the files are not owned by root + '--user', '{}:{}'.format(os.getuid(), os.getgid()), + # We'll do building in /work and copy results to /dist + '-v', '{}:/work:rw'.format(work), + '-v', '{}:/dist:rw'.format(os.path.abspath('dist')), + 'quay.io/pypa/manylinux1_x86_64:latest', + 'bash', '-exc', + '{} wheel --verbose --wheel-dir /work --no-deps libsass && ' + 'auditwheel repair --wheel-dir /dist /work/*.whl'.format(pip), + ) + return 0 + + +if __name__ == '__main__': + exit(main()) diff --git a/bin/download-windows-wheels b/bin/download-windows-wheels new file mode 100755 index 0000000..56f95d2 --- /dev/null +++ b/bin/download-windows-wheels @@ -0,0 +1,59 @@ +#!/usr/bin/env python3 +import argparse +import io +import json +import os.path +import re +import urllib.request +import zipfile + +DEFINITION_RE = re.compile( + r'https://dev.azure.com/(?P[^/]+)/(?P[^/]+)' + r'/_build/latest\?definitionId=(?P\d+)', +) +BUILDS = 'https://dev.azure.com/{org}/{project}/_apis/build/builds?api-version=5.0&definitions={definition}&$top=5' # noqa: E501 +ARTIFACTS = 'https://dev.azure.com/{org}/{project}/_apis/build/builds/{build}/artifacts?api-version=5.0' # noqa: E501 + + +def main() -> int: + parser = argparse.ArgumentParser() + parser.add_argument('tag') + parser.add_argument('--dest', default='dist') + args = parser.parse_args() + + with open('README.rst') as f: + match = DEFINITION_RE.search(f.read()) + assert match + + builds_resp = urllib.request.urlopen(BUILDS.format(**match.groupdict())) + builds_json = json.load(builds_resp) + + build_id = next( + iter([ + build['id'] for build in builds_json['value'] + if build['status'] == 'completed' + if build['result'] == 'succeeded' + if build['sourceBranch'] == f'refs/tags/{args.tag}' + ]), + ) + + artifacts_url = ARTIFACTS.format(build=build_id, **match.groupdict()) + artifacts_resp = urllib.request.urlopen(artifacts_url) + artifacts_json = json.load(artifacts_resp) + + os.makedirs(args.dest, exist_ok=True) + for artifact in artifacts_json['value']: + if artifact['name'].startswith('wheel_'): + print(f'artifact: {artifact["name"]}') + resp = urllib.request.urlopen(artifact['resource']['downloadUrl']) + bio = io.BytesIO(resp.read()) + with zipfile.ZipFile(bio) as zipf: + for info in zipf.infolist(): + if info.filename.endswith('.whl'): + info.filename = os.path.basename(info.filename) + zipf.extract(info, path=args.dest) + return 0 + + +if __name__ == '__main__': + exit(main()) diff --git a/docs/Makefile b/docs/Makefile new file mode 100644 index 0000000..bfbbcce --- /dev/null +++ b/docs/Makefile @@ -0,0 +1,153 @@ +# Makefile for Sphinx documentation +# + +# You can set these variables from the command line. +SPHINXOPTS = +SPHINXBUILD = sphinx-build +PAPER = +BUILDDIR = _build + +# Internal variables. +PAPEROPT_a4 = -D latex_paper_size=a4 +PAPEROPT_letter = -D latex_paper_size=letter +ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . +# the i18n builder cannot share the environment and doctrees with the others +I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . + +.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext + +help: + @echo "Please use \`make ' where is one of" + @echo " html to make standalone HTML files" + @echo " dirhtml to make HTML files named index.html in directories" + @echo " singlehtml to make a single large HTML file" + @echo " pickle to make pickle files" + @echo " json to make JSON files" + @echo " htmlhelp to make HTML files and a HTML help project" + @echo " qthelp to make HTML files and a qthelp project" + @echo " devhelp to make HTML files and a Devhelp project" + @echo " epub to make an epub" + @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" + @echo " latexpdf to make LaTeX files and run them through pdflatex" + @echo " text to make text files" + @echo " man to make manual pages" + @echo " texinfo to make Texinfo files" + @echo " info to make Texinfo files and run them through makeinfo" + @echo " gettext to make PO message catalogs" + @echo " changes to make an overview of all changed/added/deprecated items" + @echo " linkcheck to check all external links for integrity" + @echo " doctest to run all doctests embedded in the documentation (if enabled)" + +clean: + -rm -rf $(BUILDDIR)/* + +html: + $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html + @echo + @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." + +dirhtml: + $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml + @echo + @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." + +singlehtml: + $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml + @echo + @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." + +pickle: + $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle + @echo + @echo "Build finished; now you can process the pickle files." + +json: + $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json + @echo + @echo "Build finished; now you can process the JSON files." + +htmlhelp: + $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp + @echo + @echo "Build finished; now you can run HTML Help Workshop with the" \ + ".hhp project file in $(BUILDDIR)/htmlhelp." + +qthelp: + $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp + @echo + @echo "Build finished; now you can run "qcollectiongenerator" with the" \ + ".qhcp project file in $(BUILDDIR)/qthelp, like this:" + @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/libsass.qhcp" + @echo "To view the help file:" + @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/libsass.qhc" + +devhelp: + $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp + @echo + @echo "Build finished." + @echo "To view the help file:" + @echo "# mkdir -p $$HOME/.local/share/devhelp/libsass" + @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/libsass" + @echo "# devhelp" + +epub: + $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub + @echo + @echo "Build finished. The epub file is in $(BUILDDIR)/epub." + +latex: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo + @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." + @echo "Run \`make' in that directory to run these through (pdf)latex" \ + "(use \`make latexpdf' here to do that automatically)." + +latexpdf: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo "Running LaTeX files through pdflatex..." + $(MAKE) -C $(BUILDDIR)/latex all-pdf + @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." + +text: + $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text + @echo + @echo "Build finished. The text files are in $(BUILDDIR)/text." + +man: + $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man + @echo + @echo "Build finished. The manual pages are in $(BUILDDIR)/man." + +texinfo: + $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo + @echo + @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." + @echo "Run \`make' in that directory to run these through makeinfo" \ + "(use \`make info' here to do that automatically)." + +info: + $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo + @echo "Running Texinfo files through makeinfo..." + make -C $(BUILDDIR)/texinfo info + @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." + +gettext: + $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale + @echo + @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." + +changes: + $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes + @echo + @echo "The overview file is in $(BUILDDIR)/changes." + +linkcheck: + $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck + @echo + @echo "Link check complete; look for any errors in the above output " \ + "or in $(BUILDDIR)/linkcheck/output.txt." + +doctest: + $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest + @echo "Testing of doctests in the sources finished, look at the " \ + "results in $(BUILDDIR)/doctest/output.txt." diff --git a/docs/changes.rst b/docs/changes.rst new file mode 100644 index 0000000..67c7858 --- /dev/null +++ b/docs/changes.rst @@ -0,0 +1,841 @@ +Changelog +========= + +Version 0.21.1 +-------------- + +Released on May 20, 2021. + +- Fix build on OpenBSD. [:issue:`310` by Denis Fondras]. +- Produce abi3 wheels on windows. [:issue:`322` by Anthony Sottile] +- Make the manpage build reproducible. [:issue:`319` by Chris Lamb] +- Follow up the libsass upstream: 3.6.5 --- See the release notes of LibSass + 3.6.5__. [:issue:`344` by Anthony Sottile] + +__ https://github.com/sass/libsass/releases/tag/3.6.5 + +Version 0.20.1 +-------------- + +Released on August 27, 2020. + +- (no changes, re-releasing to test build automation) + + +Version 0.20.0 +-------------- + +Released on May 1, 2020. + +- Produce abi3 wheels on macos / linux [:issue:`307` by Anthony Sottile] +- Follow up the libsass upstream: 3.6.4 --- See the release notes of LibSass + 3.6.4__. [:issue:`313` by Anthony Sottile] + +__ https://github.com/sass/libsass/releases/tag/3.6.4 + + +Version 0.19.4 +-------------- + +Released on November 3, 2019. + +- Follow up the libsass upstream: 3.6.3 --- See the release notes of LibSass + 3.6.3__. [:issue:`304` by Anthony Sottile] + +__ https://github.com/sass/libsass/releases/tag/3.6.3 + + +Version 0.19.3 +-------------- + +Released on October 5, 2019. + +- Follow up the libsass upstream: 3.6.2 --- See the release notes of LibSass + 3.6.2__. [:issue:`302` by Anthony Sottile] + +__ https://github.com/sass/libsass/releases/tag/3.6.2 + + +Version 0.19.2 +-------------- + +Released on June 16, 2019. + +- Follow up the libsass upstream: 3.6.1 --- See the release notes of LibSass + 3.6.1__. [:issue:`298` by Anthony Sottile] + +__ https://github.com/sass/libsass/releases/tag/3.6.1 + + +Version 0.19.1 +-------------- + +Released on May 18, 2019. + +- Re-release of 0.19.0 with windows python2.7 wheels [:issue:`297` by Anthony + Sottile] + + +Version 0.19.0 +-------------- + +Released on May 18, 2019. + +- Follow up the libsass upstream: 3.6.0 --- See the release notes of LibSass + 3.6.0__. [:issue:`295` by Anthony Sottile] + +__ https://github.com/sass/libsass/releases/tag/3.6.0 + + +Version 0.18.0 +-------------- + +Release on March 13, 2019 + +- Add support for previous import path to importer callbacks [:issue:`287` + :issue:`291` by Frankie Dintino] + +Version 0.17.0 +-------------- + +Release on January 03, 2019 + +- Add several new cli options [:issue:`279` :issue:`268` by Frankie Dintino] + - ``--sourcemap-file``: output file for source map + - ``--sourcemap-contents``: embed ``sourcesContent`` in source map + - ``--sourcemap-embed``: embed ``sourceMappingURL`` as data uri + - ``--omit-sourcemap-url``: omit source map url comment from output + - ``--sourcemap-root``: base path, emitted as ``sourceRoot`` in source map +- Fix ``.sass`` in ``WsgiMiddleware`` (again) [:issue:`280` by Anthony Sottile] + +Version 0.16.1 +-------------- + +Released on November 25, 2018. + +- Fix compilation on macos mojave [:issue:`276` :issue:`277` by Anthony + Sottile] +- Fix ``.sass`` in ``WsgiMiddleware`` for ``strip_extension=True`` + [:issue:`278` by Anthony Sottile] + + +Version 0.16.0 +-------------- + +Released on November 13, 2018. + +- Use ``-lc++`` link flag when compiling with ``clang`` [:issue:`270` by + Christian Thieme :issue:`271` by Anthony Sottile] +- Honor ``strip_extension`` in ``SassMiddleware`` [:issue:`274` by Anthony + Sottile] +- Follow up the libsass upstream: 3.5.5 --- See the release notes of LibSass + 3.5.5__. [:issue:`275` by Anthony Sottile] + +__ https://github.com/sass/libsass/releases/tag/3.5.5 + + +Version 0.15.1 +-------------- + +Released on September 24, 2018. + +- Fix ``setup.py sdist`` (regressed in 0.15.0) [:issue:`267` by + Anthony Sottile] + + +Version 0.15.0 +-------------- + +Released on September 16, 2018. + +- Fix invalid escape sequences [:issue:`249` by Anthony Sottile] +- Add code of conduct [:issue:`251` by Nick Schonning] +- Add support for python3.7 and remove testing for python3.4 [:issue:`254` + by Anthony Sottile] +- Add ``strip_extension`` option for wsgi / distutils builder [:issue:`55` + :issue:`258` by Anthony Sottile :issue:`260` by Morten Brekkevold] +- Deprecate ``sassc`` (replaced by ``pysassc``). [:issue:`262` by + Anthony Sottile] +- Import abc classes from ``collections.abc`` to remove ``DeprecationWarning`` + [:issue:`264` by Gary van der Merwe :issue:`265` by Anthony Sottile] + + +Version 0.14.5 +-------------- + +Released on April 25, 2018. + +- Follow up the libsass upstream: 3.5.4 --- See the release notes of LibSass + 3.5.4__. [:issue:`247` by Anthony Sottile] + +__ https://github.com/sass/libsass/releases/tag/3.5.4 + + +Version 0.14.4 +-------------- + +Released on April 24, 2018. + +- Add ability to specify imports for custom extensions. This provides a + way to enable imports of ``.css`` files (which was removed in 3.5.3). + Specify ``--import-extensions .css`` to restore the previous behavior. + [:issue:`246` by Samuel Colvin] + + +Version 0.14.3 +-------------- + +Released on April 23, 2018. + +- Follow up the libsass upstream: 3.5.3 --- See the release notes of LibSass + 3.5.3__. [:issue:`244` by Anthony Sottile] + +__ https://github.com/sass/libsass/releases/tag/3.5.3 + + +Version 0.14.2 +-------------- + +Released on March 16, 2018. + +- Follow up the libsass upstream: 3.5.2 --- See the release notes of LibSass + 3.5.2__. [:issue:`243` by Anthony Sottile] + +__ https://github.com/sass/libsass/releases/tag/3.5.2 + + +Version 0.14.1 +-------------- + +Released on March 12, 2018. + +- Follow up the libsass upstream: 3.5.1 --- See the release notes of LibSass + 3.5.1__. [:issue:`242` by Anthony Sottile] + +__ https://github.com/sass/libsass/releases/tag/3.5.1 + + +Version 0.14.0 +-------------- + +Released on March 6, 2018. + +- Follow up the libsass upstream: 3.5.0 --- See the release notes of LibSass + 3.5.0__. [:issue:`241` by Anthony Sottile] +- ``SassList`` type gained an additional option ``bracketed=False`` to match + the upstream changes to the ``sass_list`` type. [:issue:`184` by Anthony + Sottile] + +__ https://github.com/sass/libsass/releases/tag/3.5.0 + + +Version 0.13.7 +-------------- + +Released on February 5, 2018. + +- Follow up the libsass upstream: 3.4.9 --- See the release notes of LibSass + 3.4.9__. [:issue:`232` by Anthony Sottile] + +__ https://github.com/sass/libsass/releases/tag/3.4.9 + + +Version 0.13.6 +-------------- + +Released on January 19, 2018. + +- libsass-python has moved to the sass organization! + + +Version 0.13.5 +-------------- + +Released on January 11, 2018. + +- Follow up the libsass upstream: 3.4.8 --- See the release notes of LibSass + 3.4.8__. [:issue:`228` by Anthony Sottile] + +__ https://github.com/sass/libsass/releases/tag/3.4.8 + + +Version 0.13.4 +-------------- + +Released on November 14, 2017. + +- Follow up the libsass upstream: 3.4.7 --- See the release notes of LibSass + 3.4.7__. [:issue:`226` by Anthony Sottile] + +__ https://github.com/sass/libsass/releases/tag/3.4.7 + + +Version 0.13.3 +-------------- + +Released on October 11, 2017. + +- Sort input files for determinism [:issue:`212` by Bernhard M. Wiedemann] +- Include LICENSE file in distributions [:issue:`216` by Dougal J. Sutherland] +- Add a ``pysassc`` entry to replace ``sassc`` [:issue:`218` by + Anthony Sottile] +- Enable building with dynamic linking [:issue:`219` by Marcel Plch] +- Follow up the libsass upstream: 3.4.6 --- See the release notes of LibSass + 3.4.6__. [:issue:`221` by Anthony Sottile] + +__ https://github.com/sass/libsass/releases/tag/3.4.6 + + +Version 0.13.2 +-------------- + +Released on June 14, 2017. + +- Always add cwd to import paths [:issue:`208` by Anthony Sottile] + + +Version 0.13.1 +-------------- + +Released on June 8, 2017. + +- Follow up the libsass upstream: 3.4.5 --- See the release notes of LibSass + 3.4.5__. [:issue:`207` by Anthony Sottile] + +__ https://github.com/sass/libsass/releases/tag/3.4.5 + + +Version 0.13.0 +-------------- + +Released on June 7, 2017. + +- Use ``getfullargspec`` when available in python 3. [:issue:`188` by + Thom Wiggers] +- Use ``sass_copy_c_string`` instead of ``strdup`` for portability + [:issue:`196` by Anthony Sottile] +- Use ``-std=gnu++0x`` to fix installation under cygwin [:issue:`195` + :issue:`197` by Anthony Sottile] +- Correct source map url [:issue:`201` :issue:`202` by Anthony Sottile] +- Remove ``--watch`` [:issue:`203` by Anthony Sottile] +- Follow up the libsass upstream: 3.4.4 --- See the release notes of LibSass + 3.4.4__. [:issue:`205` by Anthony Sottile] + +__ https://github.com/sass/libsass/releases/tag/3.4.4 + + +Version 0.12.3 +-------------- + +Released on January 7, 2017. + +- Follow up the libsass upstream: 3.4.3 --- See the release notes of LibSass + 3.4.3__. [:issue:`178` by Anthony Sottile] + +__ https://github.com/sass/libsass/releases/tag/3.4.3 + + +Version 0.12.2 +-------------- + +Released on January 5, 2017. + +- Follow up the libsass upstream: 3.4.2 --- See the release notes of LibSass + 3.4.2__. [:issue:`176` by Anthony Sottile] + +__ https://github.com/sass/libsass/releases/tag/3.4.2 + + +Version 0.12.1 +-------------- + +Released on December 20, 2016. + +- Follow up the libsass upstream: 3.4.1 --- See the release notes of LibSass + 3.4.1__. [:issue:`175` by Anthony Sottile] + +__ https://github.com/sass/libsass/releases/tag/3.4.1 + + +Version 0.12.0 +-------------- + +Released on December 10, 2016. + +- Follow up the libsass upstream: 3.4.0 --- See the release notes of LibSass + 3.4.0__. [:issue:`173` by Anthony Sottile] + +__ https://github.com/sass/libsass/releases/tag/3.4.0 + + +Version 0.11.2 +-------------- + +Released on October 24, 2016. + +- Drop support for python2.6 [:issue:`158` by Anthony Sottile] +- Deprecate ``--watch`` [:issue:`156` by Anthony Sottile] +- Preserve line endings [:issue:`160` by Anthony Sottile] +- Follow up the libsass upstream: 3.3.6 --- See the release notes of LibSass + 3.3.6__. [:issue:`167` by Anthony Sottile] + +__ https://github.com/sass/libsass/releases/tag/3.3.6 + + + +Version 0.11.1 +-------------- + +Released on April 22, 2016. + +- Follow up the libsass upstream: 3.3.5 --- See the release notes of LibSass + 3.3.5__. [:issue:`148` by Anthony Sottile] + +__ https://github.com/sass/libsass/releases/tag/3.3.5 + +Version 0.11.0 +-------------- + +Released on March 23, 2016. + +- Follow up the libsass upstream: 3.3.4 --- See the release notes of LibSass + 3.3.4__. [:issue:`144` by Anthony Sottile] +- Expose libsass version in ``sassc --version`` and ``sass.libsass_version`` + [:issue:`142` :issue:`141` :issue:`140` by Anthony Sottile] +- Fix warning about unused enum on switch [:issue:`127` :issue:`131` by + Anthony Sottile] +- Sourcemaps no longer imply source comments [:issue:`124` :issue:`130` by + Tim Tisdall] +- Add ``--source-comments`` option to ``sassc`` [:issue:`124` :issue:`130` by + Anthony Sottile] +- Improve formatting of ``CompileError`` under python3 [:issue:`123` by Anthony + Sottile] +- Raise when compiling a directory which does not exist [:issue:`116` + :issue:`119` by Anthony Sottile] + +__ https://github.com/sass/libsass/releases/tag/3.3.4 + +Version 0.10.1 +-------------- + +Released on January 29, 2016. + +- Follow up the libsass upstream: 3.3.3 --- See the release notes of LibSass + 3.3.3__. [by Anthony Sottile] +- Allow -t for style like sassc [:issue:`98` by Anthony Sottile] + +__ https://github.com/sass/libsass/releases/tag/3.3.3 + +Version 0.10.0 +-------------- + +Released on December 15, 2015. + +- Support custom import callbacks [:issue:`81` by Alice Zoë Bevan–McGregor, + Anthony Sottile] +- Disallow arbitrary kwargs in compile() [:issue:`109` by Anthony Sottile] + +Version 0.9.3 +------------- + +Released on December 03, 2015. + +- Support "indented" Sass compilation [:issue:`41` by Alice Zoë Bevan–McGregor] +- Fix wheels on windows [:issue:`28` :issue:`49` by Anthony Sottile] + +Version 0.9.2 +------------- + +Released on November 12, 2015. + +- Follow up the libsass upstream: 3.3.2 --- See the release notes of LibSass + 3.3.2__. [by Anthony Sottile] +- Require VS 2015 to build on windows [:issue:`99` by Anthony Sottile] + +__ https://github.com/sass/libsass/releases/tag/3.3.2 + +Version 0.9.1 +------------- + +Released on October 29, 2015. + +- Follow up the libsass upstream: 3.3.1 --- See the release notes of LibSass + 3.3.1__. [by Anthony Sottile] + +__ https://github.com/sass/libsass/releases/tag/3.3.1 + + +Version 0.9.0 +------------- + +Released on October 28, 2015. + +- Fix a bug with writing UTF-8 to a file [:issue:`72` by Caleb Ely] +- Fix a segmentation fault on ^C [:issue:`87` by Anthony Sottile] +- Follow up the libsass upstream: 3.3.0 --- See the release notes of LibSass + 3.3.0__. [:issue:`96` by Anthony Sottile] + +__ https://github.com/sass/libsass/releases/tag/3.3.0 + + +Version 0.8.3 +------------- + +Released on August 2, 2015. + +- Follow up the libsass upstream: 3.2.5 --- See the release notes of LibSass + 3.2.5__. [:issue:`79`, :issue:`80` by Anthony Sottile] +- Fixed a bug that :file:`*.sass` files were ignored. + [:issue:`78` by Guilhem MAS-PAITRAULT] + +__ https://github.com/sass/libsass/releases/tag/3.2.5 + + +Version 0.8.2 +------------- + +Released on May 19, 2015. + +- Follow up the libsass upstream: 3.2.4 --- See the release notes of LibSass + 3.2.3__, and 3.2.4__. [:issue:`69` by Anthony Sottile] +- The default value of :class:`~sassutils.wsgi.SassMiddleware`'s + ``error_status`` parameter was changed from ``'500 Internal Server Error'`` + to ``'200 OK'`` so that Mozilla Firefox can render the error message well. + [:issue:`67`, :issue:`68`, :issue:`70` by zxv] + +__ https://github.com/sass/libsass/releases/tag/3.2.3 +__ https://github.com/sass/libsass/releases/tag/3.2.4 + + +Version 0.8.1 +------------- + +Released on May 14, 2015. + +- Fixed a bug that there was no ``'expanded'`` in :const:`sass.OUTPUT_STYLES` + but ``'expected'`` instead which is a typo. [:issue:`66` by Triangle717] +- Fixed broken FreeBSD build. [:issue:`65` by Toshiharu Moriyama] + + +Version 0.8.0 +------------- + +Released on May 3, 2015. + +- Follow up the libsass upstream: 3.2.2 --- See the release notes of LibSass + 3.2.0__, 3.2.1__, and 3.2.2__. + [:issue:`61`, :issue:`52`, :issue:`56`, :issue:`58`, :issue:`62`, :issue:`64` + by Anthony Sottile] + + - Compact and expanded output styles [:issue:`37`] + - Strings and interpolation closer to Ruby Sass + - The correctness of the generated sourcemap files + - Directive buddling + - Full support for the ``@at-root`` directive + - Full support for ``!global`` variable scoping + +- Now underscored files are ignored when compiling a directory. + [:issue:`57` by Anthony Sottile] +- Fixed broken FreeBSD build. [:issue:`34`, :issue:`60` by Ilya Baryshev] +- :class:`~sassutils.wsgi.SassMiddleware` became to log syntax errors + if exist during compilation to ``sassutils.wsgi.SassMiddleware`` logger + with level ``ERROR``. [:issue:`42`] + +__ https://github.com/sass/libsass/releases/tag/3.2.0 +__ https://github.com/sass/libsass/releases/tag/3.2.1 +__ https://github.com/sass/libsass/releases/tag/3.2.2 + + +Version 0.7.0 +------------- + +Released on March 6, 2015. + +Anthony Sottile contributed to the most of this release. Huge thanks to him! + +- Follow up the libsass upstream: 3.1.0 --- See the `release note`__ of LibSass. + [:issue:`38`, :issue:`43` by Anthony Sottile] + + - Custom functions and imports + - Decrementing in ``@for`` loops + - ``@debug`` and ``@error`` + - ``not`` operator + - ``nth()`` for maps + - ``inspect()`` + - ``feature-exists()`` + - ``unique-id()`` + - ``random()`` + +- Added custom functions support. [:issue:`13`, :issue:`44` by Anthony Sottile] + + - Added :class:`sass.SassFunction` class. + - Added ``custom_functions`` parameter to :func:`sass.compile()` function. + - Added data types for custom functions: + + - :class:`sass.SassNumber` + - :class:`sass.SassColor` + - :class:`sass.SassList` + - :class:`sass.SassMap` + - :class:`sass.SassError` + - :class:`sass.SassWarning` + +- Added ``precision`` parameter to :func:`sass.compile()` function. + [:issue:`39` by Andrea Stagi] +- :program:`sassc` has a new :option:`-p `/:option:`--precision + ` option. [:issue:`39` by Andrea Stagi] + +__ https://github.com/sass/libsass/releases/tag/3.1.0 + + +Version 0.6.2 +------------- + +Released on November 25, 2014. + +Although 0.6.0--0.6.1 have needed GCC (G++) 4.8+, LLVM Clang 3.3+, +now it became back to only need GCC (G++) 4.6+, LLVM Clang 2.9+, +or Visual Studio 2013 Update 4+. + +- Follow up the libsass upstream: 3.0.2 --- See the `release note`__ of libsass. + [:issue:`33` by Rodolphe Pelloux-Prayer] +- Fixed a bug that :program:`sassc --watch` crashed when a file is not + compilable on the first try. [:issue:`32` by Alan Justino da Silva] +- Fixed broken build on Windows. + +__ https://github.com/sass/libsass/releases/tag/3.0.2 + + +Version 0.6.1 +------------- + +Released on November 6, 2014. + +- Follow up the libsass upstream: 3.0.1 --- See the `release note`__ of LibSass. +- Fixed a bug that :class:`~sassutils.wsgi.SassMiddleware` never closes + the socket on some WSGI servers e.g. ``eventlet.wsgi``. + +__ https://github.com/sass/libsass/releases/tag/3.0.1 + + +Version 0.6.0 +------------- + +Released on October 27, 2014. + +Note that since libsass-python 0.6.0 (and libsass 3.0) it requires C++11 +to compile. Although 0.6.2 became back to only need GCC (G++) 4.6+, +LLVM Clang 2.9+, from 0.6.0 to 0.6.1 you need GCC (G++) 4.8+, LLVM Clang 3.3+, +or Visual Studio 2013 Update 4+. + +- Follow up the libsass upstream: 3.0 --- See the `release note`__ of LibSass. + + - Decent extends support + - Basic Sass Maps Support + - Better UTF-8 Support + - ``call()`` function + - Better Windows Support + - Spec Enhancements + +- Added missing `partial import`_ support. [:issue:`27` by item4] +- :const:`~sass.SOURCE_COMMENTS` became deprecated. +- :func:`sass.compile()`'s parameter ``source_comments`` now can take only + :const:`bool` instead of :const:`str`. String values like ``'none'``, + ``'line_numbers'``, and ``'map'`` become deprecated, and will be obsolete + soon. +- :func:`~sassutils.builder.build_directory()` function has a new optional + parameter ``output_style``. +- :meth:`~sassutils.builder.Build.build()` method has a new optional + parameter ``output_style``. +- Added ``--output-style``/``-s`` option to + :class:`~sassutils.distutils.build_sass` command. [:issue:`25`] + +__ https://github.com/sass/libsass/releases/tag/3.0 +.. _partial import: https://sass-lang.com/documentation/file.SASS_REFERENCE.html#partials + + +Version 0.5.1 +------------- + +Released on September 23, 2014. + +- Fixed a bug that :class:`~sassutils.wsgi.SassMiddleware` yielded + :class:`str` instead of :class:`bytes` on Python 3. +- Fixed several Unicode-related bugs on Windows. +- Fixed a bug that :func:`~sassutils.builder.build_directory()`, + :class:`~sassutils.wsgi.SassMiddleware`, and + :class:`~sassutils.distutils.build_sass` don't recursively build + subdirectories. + + +Version 0.5.0 +------------- + +Released on June 6, 2014. + +- Follow up the libsass upstream: 2.0 --- See the `release note`__ of LibSass. + + - Added indented syntax support (:file:`*.sass` files). + - Added expanded selector support (BEM). + - Added string functions. + - Fixed UTF-8 support. + - Backward incompatibility: broken extends. + +__ https://github.com/sass/libsass/releases/tag/v2.0 + + +Unstable version 0.4.2.20140529.cd3ee1cbe3 +------------------------------------------ + +Released on May 29, 2014. + +- Version scheme changed to use periods (``.``) instead of hyphens (``-``) + due to setuptools seems to treat hyphens special. +- Fixed malformed packaging that doesn't correctly preserve the package name + and version. + + +Unstable Version 0.4.2-20140528-cd3ee1cbe3 +------------------------------------------ + +Released on May 28, 2014. + +- Follow up the libsass upstream: + :upcommit:`cd3ee1cbe34d5316eb762a43127a3de9575454ee`. + + +Version 0.4.2 +------------- + +Released on May 22, 2014. + +- Fixed build failing on Mac OS X 10.8 or earlier. [:issue:`19`] +- Fixed :exc:`UnicodeEncodeError` that :meth:`Manifest.build_one() + ` method rises when the input source + contains any non-ASCII Unicode characters. + + +Version 0.4.1 +------------- + +Released on May 20, 2014. + +- Fixed :exc:`UnicodeEncodeError` that rise when the input source contains + any non-ASCII Unicode characters. + + +Version 0.4.0 +------------- + +Released on May 6, 2014. + +- :program:`sassc` has a new :option:`-w `/:option:`--watch + ` option. +- Expose source maps support: + + - :program:`sassc` has a new :option:`-m `/:option:`-g + `/:option:`--sourcemap ` option. + - :class:`~sassutils.wsgi.SassMiddleware` now also creates source map files + with filenames followed by :file:`.map` suffix. + - :meth:`Manifest.build_one() ` method + has a new ``source_map`` option. This option builds also a source map + file with the filename followed by :file:`.map` suffix. + - :func:`sass.compile()` has a new optional parameter ``source_comments``. + It can be one of :const:`sass.SOURCE_COMMENTS` keys. It also has + a new parameter ``source_map_filename`` which is required only when + ``source_comments='map'``. + +- Fixed Python 3 incompatibility of :program:`sassc` program. +- Fixed a bug that multiple ``include_paths`` doesn't work on Windows. + + +Version 0.3.0 +------------- + +Released on February 21, 2014. + +- Added support for Python 3.3. [:issue:`7`] +- Dropped support for Python 2.5. +- Fixed build failing on Mac OS X. + [:issue:`4`, :issue:`5`, :issue:`6` by Hyungoo Kang] +- Now the builder creates target subdirectories recursively even if they don't + exist yet, rather than silently failing. + [:issue:`8`, :issue:`9` by Philipp Volguine] +- Merged recent changes from libsass 1.0.1: `57a2f62--v1.0.1`_. + + - Supports `variable arguments`_. + - Supports sourcemaps. + +.. _57a2f62--v1.0.1: https://github.com/sass/libsass/compare/57a2f627b4d2fbd3cf1913b241f1d5aa31e35580...v1.0.1 +.. _variable arguments: https://sass-lang.com/docs/yardoc/file.SASS_CHANGELOG.html#variable_arguments + + +Version 0.2.4 +------------- + +Released on December 4, 2012. + +- Added :mod:`sassc` CLI executable script. +- Added :const:`sass.OUTPUT_STYLES` constant map. +- Merged recent changes from libsass upstream: + `e997102--a84b181`__. + +__ https://github.com/sass/libsass/compare/e9971023785dabd41aa44f431f603f62b15e6017...a84b181a6e59463c0ac9796ca7fdaf4864f0ad84 + + +Version 0.2.3 +------------- + +Released on October 24, 2012. + +- :mod:`sassutils.distutils`: Prevent double monkey patch of ``sdist``. +- Merged upstream changes of libsass. + + +Version 0.2.2 +------------- + +Released on September 28, 2012. + +- Fixed a link error on PyPy and Linux. +- Fixed build errors on Windows. + + +Version 0.2.1 +------------- + +Released on September 12, 2012. + +- Support Windows. + + +Version 0.2.0 +------------- + +Released on August 24, 2012. + +- Added new :mod:`sassutils` package. + + - Added :mod:`sassutils.builder` module to build the whole directory + at a time. + - Added :mod:`sassutils.distutils` module for :mod:`distutils` and + :mod:`setuptools` integration. + - Added :mod:`sassutils.wsgi` module which provides a development-purpose + WSGI middleware. + +- Added :class:`~sassutils.distutils.build_sass` command for + :mod:`distutils`/:mod:`setuptools`. + + +Version 0.1.1 +------------- + +Released on August 18, 2012. + +- Fixed segmentation fault for reading ``filename`` which does not exist. + Now it raises a proper ``exceptions.IOError`` exception. + + +Version 0.1.0 +------------- + +Released on August 17, 2012. Initial version. diff --git a/docs/conf.py b/docs/conf.py new file mode 100644 index 0000000..921d65c --- /dev/null +++ b/docs/conf.py @@ -0,0 +1,277 @@ +# -*- coding: utf-8 -*- +# +# libsass documentation build configuration file, created by +# sphinx-quickstart on Sun Aug 19 22:45:57 2012. +# +# This file is execfile()d with the current directory set to its containing dir. +# +# Note that not all possible configuration values are present in this +# autogenerated file. +# +# All configuration values have a default; values that are commented out +# serve to show the default. +import os +import sys +import warnings + +# If extensions (or modules to document with autodoc) are in another directory, +# add these directories to sys.path here. If the directory is relative to the +# documentation root, use os.path.abspath to make it absolute, like shown here. +sys.path.insert(0, os.path.abspath('..')) + +import sass + +# -- General configuration ----------------------------------------------------- + +# If your documentation needs a minimal Sphinx version, state it here. +needs_sphinx = '1.3' + +suppress_warnings = ['image.nonlocal_uri'] + +# Add any Sphinx extension module names here, as strings. They can be extensions +# coming with Sphinx (named 'sphinx.ext.*') or your custom ones. +extensions = [ + 'sphinx.ext.autodoc', 'sphinx.ext.intersphinx', + 'sphinx.ext.extlinks', +] + +# Add any paths that contain templates here, relative to this directory. +templates_path = ['_templates'] + +# The suffix of source filenames. +source_suffix = '.rst' + +# The encoding of source files. +#source_encoding = 'utf-8-sig' + +# The master toctree document. +master_doc = 'index' + +# General information about the project. +project = u'libsass' +copyright = u'2012, Hong Minhee' + +# The version info for the project you're documenting, acts as replacement for +# |version| and |release|, also used in various other places throughout the +# built documents. +# +# The short X.Y version. (Parse setup.py script.) +version = sass.__version__ +# The full version, including alpha/beta/rc tags. +release = version + +intersphinx_mapping = {'python': ('https://docs.python.org/3', None)} + +# The language for content autogenerated by Sphinx. Refer to documentation +# for a list of supported languages. +#language = None + +# There are two options for replacing |today|: either, you set today to some +# non-false value, then it is used: +#today = '' +# Else, today_fmt is used as the format for a strftime call. +#today_fmt = '%B %d, %Y' + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +exclude_patterns = ['_build'] + +# The reST default role (used for this markup: `text`) to use for all documents. +#default_role = None + +# If true, '()' will be appended to :func: etc. cross-reference text. +#add_function_parentheses = True + +# If true, the current module name will be prepended to all description +# unit titles (such as .. function::). +#add_module_names = True + +# If true, sectionauthor and moduleauthor directives will be shown in the +# output. They are ignored by default. +#show_authors = False + +# The name of the Pygments (syntax highlighting) style to use. +pygments_style = 'sphinx' + +# A list of ignored prefixes for module index sorting. +#modindex_common_prefix = [] + + +# -- Options for HTML output --------------------------------------------------- + +# The theme to use for HTML and HTML Help pages. See the documentation for +# a list of builtin themes. +html_theme = 'alabaster' + +# Theme options are theme-specific and customize the look and feel of a theme +# further. For a list of options available for each theme, see the +# documentation. +#html_theme_options = {} + +# Add any paths that contain custom themes here, relative to this directory. +#html_theme_path = [] + +# The name for this set of Sphinx documents. If None, it defaults to +# " v documentation". +#html_title = None + +# A shorter title for the navigation bar. Default is the same as html_title. +#html_short_title = None + +# The name of an image file (relative to this directory) to place at the top +# of the sidebar. +#html_logo = None + +# The name of an image file (within the static path) to use as favicon of the +# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 +# pixels large. +#html_favicon = None + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +html_static_path = ['_static'] + +# If not '', a 'Last updated on:' timestamp is inserted at every page bottom, +# using the given strftime format. +#html_last_updated_fmt = '%b %d, %Y' + +# If true, SmartyPants will be used to convert quotes and dashes to +# typographically correct entities. +#html_use_smartypants = True + +# Custom sidebar templates, maps document names to template names. +#html_sidebars = {} + +# Additional templates that should be rendered to pages, maps page names to +# template names. +#html_additional_pages = {} + +# If false, no module index is generated. +#html_domain_indices = True + +# If false, no index is generated. +#html_use_index = True + +# If true, the index is split into individual pages for each letter. +#html_split_index = False + +# If true, links to the reST sources are added to the pages. +#html_show_sourcelink = True + +# If true, "Created using Sphinx" is shown in the HTML footer. Default is True. +#html_show_sphinx = True + +# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. +#html_show_copyright = True + +# If true, an OpenSearch description file will be output, and all pages will +# contain a tag referring to it. The value of this option must be the +# base URL from which the finished HTML is served. +#html_use_opensearch = '' + +# This is the file name suffix for HTML files (e.g. ".xhtml"). +#html_file_suffix = None + +# Output file base name for HTML help builder. +htmlhelp_basename = 'libsassdoc' + + +# -- Options for LaTeX output -------------------------------------------------- + +latex_elements = { +# The paper size ('letterpaper' or 'a4paper'). +#'papersize': 'letterpaper', + +# The font size ('10pt', '11pt' or '12pt'). +#'pointsize': '10pt', + +# Additional stuff for the LaTeX preamble. +#'preamble': '', +} + +# Grouping the document tree into LaTeX files. List of tuples +# (source start file, target name, title, author, documentclass [howto/manual]). +latex_documents = [ + ( + 'index', 'libsass.tex', u'libsass Documentation', + u'Hong Minhee', 'manual', + ), +] + +# The name of an image file (relative to this directory) to place at the top of +# the title page. +#latex_logo = None + +# For "manual" documents, if this is true, then toplevel headings are parts, +# not chapters. +#latex_use_parts = False + +# If true, show page references after internal links. +#latex_show_pagerefs = False + +# If true, show URL addresses after external links. +#latex_show_urls = False + +# Documents to append as an appendix to all manuals. +#latex_appendices = [] + +# If false, no module index is generated. +#latex_domain_indices = True + + +# -- Options for manual page output -------------------------------------------- + +# One entry per manual page. List of tuples +# (source start file, name, description, authors, manual section). +man_pages = [ + ( + 'index', 'libsass', u'libsass Documentation', + [u'Hong Minhee'], 1, + ), +] + +# If true, show URL addresses after external links. +#man_show_urls = False + + +# -- Options for Texinfo output ------------------------------------------------ + +# Grouping the document tree into Texinfo files. List of tuples +# (source start file, target name, title, author, +# dir menu entry, description, category) +texinfo_documents = [ + ( + 'index', 'libsass', u'libsass Documentation', + u'Hong Minhee', 'libsass', 'One line description of project.', + 'Miscellaneous', + ), +] + +# Documents to append as an appendix to all manuals. +#texinfo_appendices = [] + +# If false, no module index is generated. +#texinfo_domain_indices = True + +# How to display URL addresses: 'footnote', 'no', or 'inline'. +#texinfo_show_urls = 'footnote' + + +# Example configuration for intersphinx: refer to the Python standard library. +intersphinx_mapping = { + 'python': ('https://docs.python.org/', None), + 'setuptools': ('https://setuptools.readthedocs.io/en/latest/', None), + 'flask': ('http://flask.pocoo.org/docs/', None), +} + + +extlinks = { + 'issue': ('https://github.com/sass/libsass-python/issues/%s', '#'), + 'branch': ( + 'https://github.com/sass/libsass-python/compare/master...%s', + '', + ), + 'commit': ('https://github.com/sass/libsass-python/commit/%s', ''), + 'upcommit': ('https://github.com/sass/libsass/commit/%s', ''), +} diff --git a/docs/frameworks/flask.rst b/docs/frameworks/flask.rst new file mode 100644 index 0000000..c6974eb --- /dev/null +++ b/docs/frameworks/flask.rst @@ -0,0 +1,175 @@ +Using with Flask +================ + +This guide explains how to use libsass with the Flask_ web framework. +:mod:`sassutils` package provides several tools that can be integrated +into web applications written in Flask. + +.. _Flask: http://flask.pocoo.org/ + +.. contents:: + + +Directory layout +---------------- + +Imagine the project contained in such directory layout: + +- :file:`setup.py` +- :file:`myapp/` + + - :file:`__init__.py` + - :file:`static/` + + - :file:`sass/` + - :file:`css/` + - :file:`templates/` + +Sass/SCSS files will go inside :file:`myapp/static/sass/` directory. +Compiled CSS files will go inside :file:`myapp/static/css/` directory. +CSS files can be regenerated, so add :file:`myapp/static/css/` into your +ignore list like :file:`.gitignore` or :file:`.hgignore`. + + +Defining manifest +----------------- + +The :mod:`sassutils` defines a concept named :dfn:`manifest`. +Manifest is the build settings of Sass/SCSS. It specifies some paths +related to building Sass/SCSS: + +- The path of the directory which contains Sass/SCSS source files. +- The path of the directory which the compiled CSS files will go. +- The path, exposed to HTTP (through WSGI), of the directory that + will contain the compiled CSS files. + +Every package may have its own manifest. Paths have to be relative +to the path of the package. + +For example, in the above project, the package name is :mod:`myapp`. +The path of the package is :file:`myapp/`. The path of the Sass/SCSS +directory is :file:`static/sass/` (relative to the package directory). +The path of the CSS directory is :file:`static/css/`. +The exposed path is :file:`/static/css`. + +These settings can be represented as the following manifests:: + + { + 'myapp': ('static/sass', 'static/css', '/static/css') + } + +As you can see the above, the set of manifests are represented in dictionary, +in which the keys are packages names and the values are tuples of paths. + + +Building Sass/SCSS for each request +----------------------------------- + +.. seealso:: + + Flask --- `Hooking in WSGI Middlewares`__ + The section which explains how to integrate WSGI middlewares to + Flask. + + Flask --- :ref:`flask:app-dispatch` + The documentation which explains how Flask dispatches each + request internally. + + __ http://flask.pocoo.org/docs/quickstart/#hooking-in-wsgi-middlewares + +In development, manually building Sass/SCSS files for each change is +a tedious task. :class:`~sassutils.wsgi.SassMiddleware` makes the web +application build Sass/SCSS files for each request automatically. +It's a WSGI middleware, so it can be plugged into the web app written in +Flask. + +:class:`~sassutils.wsgi.SassMiddleware` takes two required parameters: + +- The WSGI-compliant callable object. +- The set of manifests represented as a dictionary. + +So:: + + from flask import Flask + from sassutils.wsgi import SassMiddleware + + app = Flask(__name__) + + app.wsgi_app = SassMiddleware(app.wsgi_app, { + 'myapp': ('static/sass', 'static/css', '/static/css') + }) + +And then, if you want to link a compiled CSS file, use the +:func:`~flask.url_for()` function: + +.. sourcecode:: html+jinja + + + +.. note:: + + The linked filename is :file:`style.scss.css`, not just :file:`style.scss`. + All compiled filenames have trailing ``.css`` suffix. + + +Building Sass/SCSS for each deployment +-------------------------------------- + +.. note:: + + This section assumes that you use setuptools_ for deployment. + +.. seealso:: + + Flask --- :ref:`flask:distribute-deployment` + How to deploy Flask application using setuptools_. + +If libsass is installed in the :file:`site-packages` (for example, +your virtualenv), the :file:`setup.py` script also gets a new command +provided by libsass: :class:`~sassutils.distutils.build_sass`. +The command is aware of the ``sass_manifests`` option of :file:`setup.py` and +builds all Sass/SCSS sources according to the manifests. + +Add these arguments to :file:`setup.py` script:: + + setup( + # ..., + setup_requires=['libsass >= 0.6.0'], + sass_manifests={ + 'myapp': ('static/sass', 'static/css', '/static/css') + } + ) + +The ``setup_requires`` option makes sure that libsass is installed +in :file:`site-packages` (for example, your virtualenv) before +the :file:`setup.py` script. That means if you run the :file:`setup.py` +script and libsass isn't installed in advance, it will automatically +install libsass first. + +The ``sass_manifests`` specifies the manifests for libsass. + +Now :program:`setup.py build_sass` will compile all Sass/SCSS files +in the specified path and generates compiled CSS files inside the specified +path (according to the manifests). + +If you use it with ``sdist`` or ``bdist`` commands, the packed archive will +also contain the compiled CSS files! + +.. sourcecode:: console + + $ python setup.py build_sass sdist + +You can add aliases to make these commands always run the ``build_sass`` +command first. Make :file:`setup.cfg` config: + +.. sourcecode:: ini + + [aliases] + sdist = build_sass sdist + bdist = build_sass bdist + +Now it automatically builds Sass/SCSS sources and include the compiled CSS files +to the package archive when you run :program:`setup.py sdist`. + +.. _setuptools: https://pypi.org/pypi/setuptools/ diff --git a/docs/index.rst b/docs/index.rst new file mode 100644 index 0000000..2613f79 --- /dev/null +++ b/docs/index.rst @@ -0,0 +1,165 @@ +libsass-python: Sass_/SCSS for Python +===================================== + +This package provides a simple Python extension module :mod:`sass` which is +binding LibSass_ (written in C/C++ by Hampton Catlin and Aaron Leung). +It's very straightforward and there isn't any headache related Python +distribution/deployment. That means you can add just ``libsass`` into +your :file:`setup.py`'s ``install_requires`` list or :file:`requirements.txt` +file. + +It currently supports CPython 2.6, 2.7, 3.5--3.7, and PyPy 2.3+! + +.. _Sass: https://sass-lang.com/ +.. _LibSass: https://github.com/sass/libsass + + +Features +-------- + +- You don't need any Ruby/Node.js stack at all, for development or deployment + either. +- Fast. (LibSass_ is written in C++.) +- Simple API. See :ref:`example code ` for details. +- Custom functions. +- ``@import`` callbacks. +- Support both tabbed (Sass) and braces (SCSS) syntax. +- WSGI middleware for ease of development. + It automatically compiles Sass/SCSS files for each request. + See also :mod:`sassutils.wsgi` for details. +- :mod:`setuptools`/:mod:`distutils` integration. + You can build all Sass/SCSS files using + :program:`setup.py build_sass` command. + See also :mod:`sassutils.distutils` for details. +- Works also on PyPy. +- Provides prebuilt wheel (:pep:`427`) binaries for Windows and Mac. + + +Install +------- + +It's available on PyPI_, so you can install it using :program:`pip`: + +.. code-block:: console + + $ pip install libsass + +.. note:: + + libsass requires some features introduced by the recent C++ standard. + You need a C++ compiler that support those features. + See also libsass project's README_ file. + +.. _PyPI: https://pypi.org/pypi/libsass/ +.. _README: https://github.com/sass/libsass#readme + + +.. _example: + +Examples +-------- + +Compile a String of Sass to CSS +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +>>> import sass +>>> sass.compile(string='a { b { color: blue; } }') +'a b {\n color: blue; }\n' + +Compile a Directory of Sass Files to CSS +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +>>> import sass +>>> import os +>>> os.mkdir('css') +>>> os.mkdir('sass') +>>> scss = """\ +... $theme_color: #cc0000; +... body { +... background-color: $theme_color; +... } +... """ +>>> with open('sass/example.scss', 'w') as example_scss: +... example_scss.write(scss) +... +>>> sass.compile(dirname=('sass', 'css'), output_style='compressed') +>>> with open('css/example.css') as example_css: +... print(example_css.read()) +... +body{background-color:#c00} + + +User's Guide +------------ + +.. toctree:: + :maxdepth: 2 + + frameworks/flask + changes + + +References +---------- + +.. toctree:: + :maxdepth: 2 + + pysassc + sass + sassutils + + +Credit +------ + +Hong Minhee wrote this Python binding of LibSass_. + +Hampton Catlin and Aaron Leung wrote LibSass_, which is portable C/C++ +implementation of Sass_. + +Hampton Catlin originally designed Sass_ language and wrote the first +reference implementation of it in Ruby. + +The above three are all distributed under `MIT license`_. + +.. _MIT license: https://mit-license.org/ + + +Open source +----------- + +GitHub (Git repository + issues) + https://github.com/sass/libsass-python + +Azure Pipelines CI (linux + windows) + https://dev.azure.com/asottile/asottile/_build/latest?definitionId=22&branchName=master + + .. image:: https://dev.azure.com/asottile/asottile/_apis/build/status/sass.libsass-python?branchName=master + :target: https://dev.azure.com/asottile/asottile/_build/latest?definitionId=22&branchName=master + :alt: Build Status + +Azure Pipelines Coverage (Test coverage) + https://dev.azure.com/asottile/asottile/_build/latest?definitionId=22&branchName=master + + .. image:: https://img.shields.io/azure-devops/coverage/asottile/asottile/22/master.svg + :target: https://dev.azure.com/asottile/asottile/_build/latest?definitionId=22&branchName=master + :alt: Coverage Status + +PyPI + https://pypi.org/pypi/libsass/ + + .. image:: https://badge.fury.io/py/libsass.svg + :alt: PyPI + :target: https://pypi.org/pypi/libsass/ + +Changelog + :doc:`changes` + + +Indices and tables +------------------ + +- :ref:`genindex` +- :ref:`modindex` +- :ref:`search` diff --git a/docs/make.bat b/docs/make.bat new file mode 100644 index 0000000..78edea1 --- /dev/null +++ b/docs/make.bat @@ -0,0 +1,190 @@ +@ECHO OFF + +REM Command file for Sphinx documentation + +if "%SPHINXBUILD%" == "" ( + set SPHINXBUILD=sphinx-build +) +set BUILDDIR=_build +set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% . +set I18NSPHINXOPTS=%SPHINXOPTS% . +if NOT "%PAPER%" == "" ( + set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS% + set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS% +) + +if "%1" == "" goto help + +if "%1" == "help" ( + :help + echo.Please use `make ^` where ^ is one of + echo. html to make standalone HTML files + echo. dirhtml to make HTML files named index.html in directories + echo. singlehtml to make a single large HTML file + echo. pickle to make pickle files + echo. json to make JSON files + echo. htmlhelp to make HTML files and a HTML help project + echo. qthelp to make HTML files and a qthelp project + echo. devhelp to make HTML files and a Devhelp project + echo. epub to make an epub + echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter + echo. text to make text files + echo. man to make manual pages + echo. texinfo to make Texinfo files + echo. gettext to make PO message catalogs + echo. changes to make an overview over all changed/added/deprecated items + echo. linkcheck to check all external links for integrity + echo. doctest to run all doctests embedded in the documentation if enabled + goto end +) + +if "%1" == "clean" ( + for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i + del /q /s %BUILDDIR%\* + goto end +) + +if "%1" == "html" ( + %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The HTML pages are in %BUILDDIR%/html. + goto end +) + +if "%1" == "dirhtml" ( + %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml. + goto end +) + +if "%1" == "singlehtml" ( + %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml. + goto end +) + +if "%1" == "pickle" ( + %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle + if errorlevel 1 exit /b 1 + echo. + echo.Build finished; now you can process the pickle files. + goto end +) + +if "%1" == "json" ( + %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json + if errorlevel 1 exit /b 1 + echo. + echo.Build finished; now you can process the JSON files. + goto end +) + +if "%1" == "htmlhelp" ( + %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp + if errorlevel 1 exit /b 1 + echo. + echo.Build finished; now you can run HTML Help Workshop with the ^ +.hhp project file in %BUILDDIR%/htmlhelp. + goto end +) + +if "%1" == "qthelp" ( + %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp + if errorlevel 1 exit /b 1 + echo. + echo.Build finished; now you can run "qcollectiongenerator" with the ^ +.qhcp project file in %BUILDDIR%/qthelp, like this: + echo.^> qcollectiongenerator %BUILDDIR%\qthelp\libsass.qhcp + echo.To view the help file: + echo.^> assistant -collectionFile %BUILDDIR%\qthelp\libsass.ghc + goto end +) + +if "%1" == "devhelp" ( + %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. + goto end +) + +if "%1" == "epub" ( + %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The epub file is in %BUILDDIR%/epub. + goto end +) + +if "%1" == "latex" ( + %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex + if errorlevel 1 exit /b 1 + echo. + echo.Build finished; the LaTeX files are in %BUILDDIR%/latex. + goto end +) + +if "%1" == "text" ( + %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The text files are in %BUILDDIR%/text. + goto end +) + +if "%1" == "man" ( + %SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The manual pages are in %BUILDDIR%/man. + goto end +) + +if "%1" == "texinfo" ( + %SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo. + goto end +) + +if "%1" == "gettext" ( + %SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The message catalogs are in %BUILDDIR%/locale. + goto end +) + +if "%1" == "changes" ( + %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes + if errorlevel 1 exit /b 1 + echo. + echo.The overview file is in %BUILDDIR%/changes. + goto end +) + +if "%1" == "linkcheck" ( + %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck + if errorlevel 1 exit /b 1 + echo. + echo.Link check complete; look for any errors in the above output ^ +or in %BUILDDIR%/linkcheck/output.txt. + goto end +) + +if "%1" == "doctest" ( + %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest + if errorlevel 1 exit /b 1 + echo. + echo.Testing of doctests in the sources finished, look at the ^ +results in %BUILDDIR%/doctest/output.txt. + goto end +) + +:end diff --git a/docs/pysassc.rst b/docs/pysassc.rst new file mode 100644 index 0000000..9fee79f --- /dev/null +++ b/docs/pysassc.rst @@ -0,0 +1,5 @@ + +.. program:: pysassc + +.. automodule:: pysassc + :members: diff --git a/docs/sass.rst b/docs/sass.rst new file mode 100644 index 0000000..6fb5c1c --- /dev/null +++ b/docs/sass.rst @@ -0,0 +1,2 @@ +.. automodule:: sass + :members: diff --git a/docs/sassutils.rst b/docs/sassutils.rst new file mode 100644 index 0000000..7da0dfa --- /dev/null +++ b/docs/sassutils.rst @@ -0,0 +1,9 @@ + +.. automodule:: sassutils + + .. toctree:: + :maxdepth: 2 + + sassutils/builder + sassutils/distutils + sassutils/wsgi diff --git a/docs/sassutils/builder.rst b/docs/sassutils/builder.rst new file mode 100644 index 0000000..1234e94 --- /dev/null +++ b/docs/sassutils/builder.rst @@ -0,0 +1,3 @@ + +.. automodule:: sassutils.builder + :members: diff --git a/docs/sassutils/distutils.rst b/docs/sassutils/distutils.rst new file mode 100644 index 0000000..ff90702 --- /dev/null +++ b/docs/sassutils/distutils.rst @@ -0,0 +1,3 @@ + +.. automodule:: sassutils.distutils + :members: diff --git a/docs/sassutils/wsgi.rst b/docs/sassutils/wsgi.rst new file mode 100644 index 0000000..27d1199 --- /dev/null +++ b/docs/sassutils/wsgi.rst @@ -0,0 +1,3 @@ + +.. automodule:: sassutils.wsgi + :members: diff --git a/pysassc.py b/pysassc.py new file mode 100755 index 0000000..b3ef1b0 --- /dev/null +++ b/pysassc.py @@ -0,0 +1,243 @@ +#!/usr/bin/env python +r""":mod:`pysassc` --- SassC compliant command line interface +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This provides SassC_ compliant CLI executable named :program:`pysassc`: + +.. sourcecode:: console + + $ pysassc + Usage: pysassc [options] SCSS_FILE [CSS_FILE] + +There are options as well: + +.. option:: -t