Import Upstream version 0.22.0

This commit is contained in:
luoyaoming 2024-05-07 09:43:48 +08:00
parent be11e18fcc
commit f81cc0bca9
35 changed files with 246 additions and 511 deletions

1
.gitignore vendored
View File

@ -6,7 +6,6 @@
.*.swp
.DS_Store
._.DS_Store
.pytest_cache/
.coverage
.tox
/.libsass-upstream-version

2
.gitmodules vendored
View File

@ -1,3 +1,3 @@
[submodule "libsass"]
path = libsass
url = git://github.com/sass/libsass.git
url = https://github.com/sass/libsass

View File

@ -1,21 +1,35 @@
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.0.1
rev: v4.3.0
hooks:
- id: trailing-whitespace
- id: end-of-file-fixer
- id: check-yaml
- id: debug-statements
- id: double-quote-string-fixer
- id: name-tests-test
- id: requirements-txt-fixer
- repo: https://github.com/asottile/reorder_python_imports
rev: v3.8.5
hooks:
- id: reorder-python-imports
args: [--py36-plus]
- repo: https://github.com/asottile/add-trailing-comma
rev: v2.3.0
hooks:
- id: add-trailing-comma
args: [--py36-plus]
- repo: https://github.com/asottile/pyupgrade
rev: v3.1.0
hooks:
- id: pyupgrade
args: [--py36-plus]
- repo: https://github.com/pre-commit/mirrors-autopep8
rev: v1.7.0
hooks:
- id: autopep8
- repo: https://github.com/PyCQA/flake8
rev: 3.9.2
rev: 5.0.4
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

View File

@ -26,7 +26,7 @@ Tests
- 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
.. _`Azure Pipelines`: https://dev.azure.com/asottile/asottile/_build/latest?definitionId=22&branchName=main
Maintainer's guide

View File

@ -5,16 +5,16 @@ libsass-python: Sass_/SCSS for Python
: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
.. image:: https://dev.azure.com/asottile/asottile/_apis/build/status/sass.libsass-python?branchName=main
:target: https://dev.azure.com/asottile/asottile/_build/latest?definitionId=22&branchName=main
: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
.. image:: https://img.shields.io/azure-devops/coverage/asottile/asottile/22/main.svg
:target: https://dev.azure.com/asottile/asottile/_build/latest?definitionId=22&branchName=main
: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
.. image:: https://results.pre-commit.ci/badge/github/sass/libsass-python/main.svg
:target: https://results.pre-commit.ci/latest/github/sass/libsass-python/main
:alt: pre-commit.ci status
This package provides a simple Python extension module ``sass`` which is
@ -22,9 +22,9 @@ 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.
No need for Ruby nor Node.js.
It currently supports CPython 2.7, 3.6--3.8, and PyPy 2.3+!
It currently supports CPython 3.6+, and PyPy 3!
.. _Sass: https://sass-lang.com/
.. _LibSass: https://github.com/sass/libsass

View File

@ -1,6 +1,6 @@
trigger:
branches:
include: [master, test-me-*]
include: [main, test-me-*]
tags:
include: ['*']
@ -13,30 +13,21 @@ resources:
type: github
endpoint: github
name: asottile/azure-pipeline-templates
ref: refs/tags/v2.1.0
ref: refs/tags/v2.4.0
jobs:
- template: job--python-tox.yml@asottile
parameters:
toxenvs: [py27, py36]
toxenvs: [py37]
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]
toxenvs: [py37]
os: windows
architectures: [x64, x86]
wheel_tags: true
- template: job--python-tox.yml@asottile
parameters:
toxenvs: [pypy, pypy3, py27, py36, py37, py38, py39]
toxenvs: [pypy3, py36, py37, py38, py39]
os: linux

View File

@ -23,13 +23,13 @@ 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)
pip = f'/opt/python/{python}/bin/pip'
check_call(
'docker', 'run', '-ti',
# Use this so the files are not owned by root
'--user', '{}:{}'.format(os.getuid(), os.getgid()),
'--user', f'{os.getuid()}:{os.getgid()}',
# We'll do building in /work and copy results to /dist
'-v', '{}:/work:rw'.format(work),
'-v', f'{work}:/work:rw',
'-v', '{}:/dist:rw'.format(os.path.abspath('dist')),
'quay.io/pypa/manylinux1_x86_64:latest',
'bash', '-exc',
@ -40,4 +40,4 @@ def main():
if __name__ == '__main__':
exit(main())
raise SystemExit(main())

View File

@ -56,4 +56,4 @@ def main() -> int:
if __name__ == '__main__':
exit(main())
raise SystemExit(main())

12
debian/changelog vendored
View File

@ -1,12 +0,0 @@
libsass-python (0.21.0-ok2) yangtze; urgency=medium
* Fix command 'install' has no such option 'install_layout'.
Add pysassc-man.patch.
-- sufang <sufang@kylinos.cn> Tue, 11 Oct 2022 11:07:40 +0800
libsass-python (0.21.0-ok1) yangtze; urgency=medium
* Build for openkylin.
-- sufang <sufang@kylinos.cn> Tue, 11 Oct 2022 10:19:07 +0800

47
debian/control vendored
View File

@ -1,47 +0,0 @@
Source: libsass-python
Section: python
Priority: optional
Maintainer: OpenKylin Developers <packaging@lists.openkylin.top>
Build-Depends:
debhelper-compat (= 13),
dh-python,
python3-all-dev,
python3-setuptools,
python3-six,
python3-sphinx,
python3-werkzeug,
python3-flake8,
python3-pytest,
python3-doc,
python-flask-doc,
python-setuptools-doc,
libsass-dev (>= 3.6.5)
Standards-Version: 4.6.0
Vcs-Browser: https://gitee.com/openkylin/libsass-python
Vcs-Git: https://gitee.com/openkylin/libsass-python.git
Homepage: https://sass.github.io/libsass-python
Rules-Requires-Root: no
X-Python-Version: >= 2.6
X-Python3-Version: >= 3.2
Package: python3-libsass
Architecture: any
Depends: ${misc:Depends}, ${python3:Depends}, ${shlibs:Depends}
Description: SASS for Python 3: a straightforward binding of libsass for Python
This package provides a simple Python 3 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.
Package: pysassc
Section: web
Architecture: all
Depends: ${misc:Depends}, ${python3:Depends}, ${shlibs:Depends}, python3-libsass
Description: SASS for Python: command line utility for libsass
This package provides a simple Python script to access libsass
functionnalities.
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.

86
debian/copyright vendored
View File

@ -1,86 +0,0 @@
Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
Upstream-Name: libsass-python
Source: <url://example.com>
#
# Please double check copyright with the licensecheck(1) command.
Files: .ackrc
.coveragerc
.gitignore
.gitmodules
.pre-commit-config.yaml
CODE_OF_CONDUCT.md
CONTRIBUTING.rst
MANIFEST.in
README.rst
_sass.c
azure-pipelines.yml
bin/build-manylinux-wheels
bin/download-windows-wheels
docs/Makefile
docs/changes.rst
docs/conf.py
docs/frameworks/flask.rst
docs/index.rst
docs/make.bat
docs/pysassc.rst
docs/sass.rst
docs/sassutils.rst
docs/sassutils/builder.rst
docs/sassutils/distutils.rst
docs/sassutils/wsgi.rst
pysassc.py
requirements-dev.txt
sass.py
sassc.py
sasstests.py
sassutils/__init__.py
sassutils/_compat.py
sassutils/builder.py
sassutils/distutils.py
sassutils/wsgi.py
setup.cfg
setup.py
test/_f.scss
test/a.scss
test/b.scss
test/c.scss
test/d.scss
test/e.scss
test/g.scss
test/h.sass
test/subdir/_sub.scss
test/subdir/recur.scss
testpkg/setup.py
testpkg/testpkg/__init__.py
testpkg/testpkg/static/css/README
testpkg/testpkg/static/scss/a.scss
tox.ini
Copyright: __NO_COPYRIGHT_NOR_LICENSE__
License: __NO_COPYRIGHT_NOR_LICENSE__
#----------------------------------------------------------------------------
# Files marked as NO_LICENSE_TEXT_FOUND may be covered by the following
# license/copyright files.
#----------------------------------------------------------------------------
# License file: LICENSE
Copyright (c) 2015 Hong Minhee <https://hongminhee.org/>
.
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.

View File

@ -1 +0,0 @@
../docs/changes.rst

View File

@ -1,2 +0,0 @@
usr/bin/sassc
usr/lib/*/dist-packages/__pycache__/*.pyc

View File

@ -1 +0,0 @@
# You must remove unused comment lines for the released package.

View File

@ -1 +0,0 @@
usr/bin/pysassc

View File

@ -1 +0,0 @@
debian/tmp/usr/share/man/man1/pysassc.1

View File

@ -1,4 +0,0 @@
usr/lib/python3*/*-packages/*.py
usr/lib/python3*/*-packages/_sass*.so
usr/lib/python3*/*-packages/*.egg-info/
usr/lib/python3*/*-packages/sassutils/

View File

@ -1 +0,0 @@
usr/share/man/man3/libsass.3

41
debian/rules vendored
View File

@ -1,41 +0,0 @@
#!/usr/bin/make -f
export DH_VERBOSE=1
export PYTHON_EGG_CACHE=$(CURDIR)/debian/tmp
export DEB_BUILD_MAINT_OPTIONS = hardening=+all
export SYSTEM_SASS = 1
export SETUPTOOLS_USE_DISTUTILS=stdlib
%: .libsass-upstream-version
dh $@ --with python3 --buildsystem=pybuild
.libsass-upstream-version:
dpkg-query -f '$${Version}\n' -W libsass-dev|sed 's/-.*//' > .libsass-upstream-version
override_dh_auto_build:
pybuild --build -p "$(shell py3versions -vr)"
# build doc once
pybuild -s custom --build -p $(shell py3versions -vd) \
--build-args="env PYTHONPATH={build_dir} python3 -m sphinx -N -bman docs/ build/man"
override_dh_auto_install:
dh_auto_install -O--buildsystem=pybuild
mkdir -p $(CURDIR)/debian/tmp/usr/share/man/man1
mkdir -p $(CURDIR)/debian/tmp/usr/share/man/man3
cp $(CURDIR)/build/man/pysassc.1 $(CURDIR)/debian/tmp/usr/share/man/man1/
cp $(CURDIR)/build/man/libsass.3 $(CURDIR)/debian/tmp/usr/share/man/man3/
rm $(CURDIR)/debian/tmp/usr/lib/python*/dist-packages/sasstests.py
sed -i '1c#!/usr/bin/python3' $(CURDIR)/debian/tmp/usr/bin/pysassc
override_dh_auto_test:
ifeq (,$(filter nocheck,$(DEB_BUILD_OPTIONS)))
# Skip DistutilsTestCase.* to not rebuild sass again
pybuild -s custom --test -p "$(shell py3versions -vr)" \
--test-args="cd {build_dir}; \
{interpreter} -m pytest -k 'not DistutilsTestCase' sasstests.py"
endif
override_dh_auto_clean:
dh_auto_clean -O--buildsystem=pybuild
rm -fr libsass.egg-info .libsass-upstream-version

View File

@ -1 +0,0 @@
3.0 (native)

View File

@ -1,5 +0,0 @@
---
Bug-Database: https://github.com/dahlia/libsass-python/issues
Bug-Submit: https://github.com/dahlia/libsass-python/issues/new
Repository: https://github.com/dahlia/libsass-python.git
Repository-Browse: https://github.com/dahlia/libsass-python

4
debian/watch vendored
View File

@ -1,4 +0,0 @@
version=4
opts="filenamemangle=s%(?:.*?)?v?(\d[\d.]*)\.tar\.gz%@PACKAGE@-$1.tar.gz%" \
https://github.com/dahlia/libsass-python/tags \
(?:.*?/)?v?(\d[\d.]*)\.tar\.gz debian uupdate

View File

@ -1,7 +1,15 @@
Changelog
=========
Version 0.21.1
Version 0.22.0
--------------
Released on November 12, 2022.
- Remove python 2.x support [:issue:`373` by anthony sottile].
- Remove deprecated ``sassc`` cli [:issue:`379` by anthony sottile].
Version 0.21.0
--------------
Released on May 20, 2021.

View File

@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
#
# libsass documentation build configuration file, created by
# sphinx-quickstart on Sun Aug 19 22:45:57 2012.
@ -14,12 +13,13 @@ import os
import sys
import warnings
import sass
# 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 -----------------------------------------------------
@ -48,8 +48,8 @@ source_suffix = '.rst'
master_doc = 'index'
# General information about the project.
project = u'libsass'
copyright = u'2012, Hong Minhee'
project = 'libsass'
copyright = '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
@ -180,23 +180,23 @@ htmlhelp_basename = 'libsassdoc'
# -- Options for LaTeX output --------------------------------------------------
latex_elements = {
# The paper size ('letterpaper' or 'a4paper').
#'papersize': 'letterpaper',
# The paper size ('letterpaper' or 'a4paper').
# 'papersize': 'letterpaper',
# The font size ('10pt', '11pt' or '12pt').
#'pointsize': '10pt',
# The font size ('10pt', '11pt' or '12pt').
# 'pointsize': '10pt',
# Additional stuff for the LaTeX preamble.
#'preamble': '',
# 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',
),
(
'index', 'libsass.tex', 'libsass Documentation',
'Hong Minhee', 'manual',
),
]
# The name of an image file (relative to this directory) to place at the top of
@ -226,10 +226,8 @@ latex_documents = [
# (source start file, name, description, authors, manual section).
man_pages = [
(
'index', 'libsass', u'libsass Documentation', [u'Hong Minhee'], 3,
),
(
'pysassc', 'pysassc', u'pysassc Documentation', [u'Hong Minhee'], 1,
'index', 'libsass', 'libsass Documentation',
['Hong Minhee'], 1,
),
]
@ -243,11 +241,11 @@ man_pages = [
# (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',
),
(
'index', 'libsass', 'libsass Documentation',
'Hong Minhee', 'libsass', 'One line description of project.',
'Miscellaneous',
),
]
# Documents to append as an appendix to all manuals.
@ -271,7 +269,7 @@ intersphinx_mapping = {
extlinks = {
'issue': ('https://github.com/sass/libsass-python/issues/%s', '#'),
'branch': (
'https://github.com/sass/libsass-python/compare/master...%s',
'https://github.com/sass/libsass-python/compare/main...%s',
'',
),
'commit': ('https://github.com/sass/libsass-python/commit/%s', ''),

View File

@ -8,7 +8,7 @@ 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+!
It currently supports CPython 3.6+ and PyPy 3!
.. _Sass: https://sass-lang.com/
.. _LibSass: https://github.com/sass/libsass
@ -133,17 +133,17 @@ 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
https://dev.azure.com/asottile/asottile/_build/latest?definitionId=22&branchName=main
.. 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
.. image:: https://dev.azure.com/asottile/asottile/_apis/build/status/sass.libsass-python?branchName=main
:target: https://dev.azure.com/asottile/asottile/_build/latest?definitionId=22&branchName=main
:alt: Build Status
Azure Pipelines Coverage (Test coverage)
https://dev.azure.com/asottile/asottile/_build/latest?definitionId=22&branchName=master
https://dev.azure.com/asottile/asottile/_build/latest?definitionId=22&branchName=main
.. 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
.. image:: https://img.shields.io/azure-devops/coverage/asottile/asottile/22/main.svg
:target: https://dev.azure.com/asottile/asottile/_build/latest?definitionId=22&branchName=main
:alt: Coverage Status
PyPI

View File

@ -88,10 +88,7 @@ There are options as well:
.. _SassC: https://github.com/sass/sassc
"""
from __future__ import print_function
import functools
import io
import optparse
import sys
import warnings
@ -219,7 +216,7 @@ def main(argv=sys.argv, stdout=sys.stdout, stderr=sys.stderr):
include_paths=options.include_paths,
precision=options.precision,
)
except (IOError, OSError) as e:
except OSError as e:
error(e)
return 3
except sass.CompileError as e:
@ -229,10 +226,10 @@ def main(argv=sys.argv, stdout=sys.stdout, stderr=sys.stderr):
if len(args) < 2:
print(css, file=stdout)
else:
with io.open(args[1], 'w', encoding='utf-8', newline='') as f:
with open(args[1], 'w', encoding='utf-8', newline='') as f:
f.write(css)
if source_map_filename:
with io.open(
with open(
source_map_filename, 'w', encoding='utf-8', newline='',
) as f:
f.write(source_map)

95
sass.py
View File

@ -10,28 +10,21 @@ type.
'a b {\n color: blue; }\n'
"""
from __future__ import absolute_import
import collections
import collections.abc
import inspect
import io
import os
import os.path
import re
import sys
import warnings
from six import string_types, text_type, PY2
import _sass
from sassutils._compat import collections_abc
__all__ = (
'MODES', 'OUTPUT_STYLES', 'SOURCE_COMMENTS', 'CompileError', 'SassColor',
'SassError', 'SassFunction', 'SassList', 'SassMap', 'SassNumber',
'SassWarning', 'and_join', 'compile', 'libsass_version',
)
__version__ = '0.21.0'
__version__ = '0.22.0'
libsass_version = _sass.libsass_version
@ -52,19 +45,19 @@ MODES = frozenset(('string', 'filename', 'dirname'))
def to_native_s(s):
if isinstance(s, bytes) and not PY2: # pragma: no cover (py3)
s = s.decode('UTF-8')
elif isinstance(s, text_type) and PY2: # pragma: no cover (py2)
s = s.encode('UTF-8')
return s
if isinstance(s, bytes):
return s.decode('UTF-8')
else:
return s
class CompileError(ValueError):
"""The exception type that is raised by :func:`compile()`.
It is a subtype of :exc:`exceptions.ValueError`.
"""
def __init__(self, msg):
super(CompileError, self).__init__(to_native_s(msg))
super().__init__(to_native_s(msg))
def mkdirp(path):
@ -76,7 +69,7 @@ def mkdirp(path):
raise
class SassFunction(object):
class SassFunction:
"""Custom function for Sass. It can be instantiated using
:meth:`from_lambda()` and :meth:`from_named_function()` as well.
@ -107,16 +100,10 @@ class SassFunction(object):
:rtype: :class:`SassFunction`
"""
if PY2: # pragma: no cover
a = inspect.getargspec(lambda_)
varargs, varkw, defaults, kwonlyargs = (
a.varargs, a.keywords, a.defaults, None,
)
else: # pragma: no cover
a = inspect.getfullargspec(lambda_)
varargs, varkw, defaults, kwonlyargs = (
a.varargs, a.varkw, a.defaults, a.kwonlyargs,
)
a = inspect.getfullargspec(lambda_)
varargs, varkw, defaults, kwonlyargs = (
a.varargs, a.varkw, a.defaults, a.kwonlyargs,
)
if varargs or varkw or defaults or kwonlyargs:
raise TypeError(
@ -142,9 +129,9 @@ class SassFunction(object):
return cls.from_lambda(function.__name__, function)
def __init__(self, name, arguments, callable_):
if not isinstance(name, string_types):
if not isinstance(name, str):
raise TypeError('name must be a string, not ' + repr(name))
elif not isinstance(arguments, collections_abc.Sequence):
elif not isinstance(arguments, collections.abc.Sequence):
raise TypeError(
'arguments must be a sequence, not ' +
repr(arguments),
@ -263,7 +250,7 @@ def compile_dirname(
if s:
v = v.decode('UTF-8')
mkdirp(os.path.dirname(output_filename))
with io.open(
with open(
output_filename, 'w', encoding='UTF-8', newline='',
) as output_file:
output_file.write(v)
@ -277,7 +264,7 @@ def _check_no_remaining_kwargs(func, kwargs):
raise TypeError(
'{}() got unexpected keyword argument(s) {}'.format(
func.__name__,
', '.join("'{}'".format(arg) for arg in sorted(kwargs)),
', '.join(f"'{arg}'" for arg in sorted(kwargs)),
),
)
@ -563,7 +550,7 @@ def compile(**kwargs):
)
precision = kwargs.pop('precision', 5)
output_style = kwargs.pop('output_style', 'nested')
if not isinstance(output_style, string_types):
if not isinstance(output_style, str):
raise TypeError(
'output_style must be a string, not ' +
repr(output_style),
@ -586,7 +573,7 @@ def compile(**kwargs):
elif source_comments in ('line_numbers', 'default'):
deprecation_message = (
'you can simply pass True to '
"source_comments instead of " +
'source_comments instead of ' +
repr(source_comments)
)
source_comments = True
@ -612,9 +599,9 @@ def compile(**kwargs):
def _get_file_arg(key):
ret = kwargs.pop(key, None)
if ret is not None and not isinstance(ret, string_types):
raise TypeError('{} must be a string, not {!r}'.format(key, ret))
elif isinstance(ret, text_type):
if ret is not None and not isinstance(ret, str):
raise TypeError(f'{key} must be a string, not {ret!r}')
elif isinstance(ret, str):
ret = ret.encode(fs_encoding)
if ret and 'filename' not in modes:
raise CompileError(
@ -631,25 +618,25 @@ def compile(**kwargs):
omit_source_map_url = kwargs.pop('omit_source_map_url', False)
source_map_root = kwargs.pop('source_map_root', None)
if isinstance(source_map_root, text_type):
if isinstance(source_map_root, str):
source_map_root = source_map_root.encode('utf-8')
# #208: cwd is always included in include paths
include_paths = (os.getcwd(),)
include_paths += tuple(kwargs.pop('include_paths', ()) or ())
include_paths = os.pathsep.join(include_paths)
if isinstance(include_paths, text_type):
if isinstance(include_paths, str):
include_paths = include_paths.encode(fs_encoding)
custom_functions = kwargs.pop('custom_functions', ())
if isinstance(custom_functions, collections_abc.Mapping):
if isinstance(custom_functions, collections.abc.Mapping):
custom_functions = [
SassFunction.from_lambda(name, lambda_)
for name, lambda_ in custom_functions.items()
]
elif isinstance(
custom_functions,
(collections_abc.Set, collections_abc.Sequence),
(collections.abc.Set, collections.abc.Sequence),
):
custom_functions = [
func if isinstance(func, SassFunction)
@ -676,7 +663,7 @@ def compile(**kwargs):
if 'string' in modes:
string = kwargs.pop('string')
if isinstance(string, text_type):
if isinstance(string, str):
string = string.encode('utf-8')
indented = kwargs.pop('indented', False)
if not isinstance(indented, bool):
@ -695,11 +682,11 @@ def compile(**kwargs):
return v.decode('utf-8')
elif 'filename' in modes:
filename = kwargs.pop('filename')
if not isinstance(filename, string_types):
if not isinstance(filename, str):
raise TypeError('filename must be a string, not ' + repr(filename))
elif not os.path.isfile(filename):
raise IOError('{!r} seems not a file'.format(filename))
elif isinstance(filename, text_type):
raise OSError(f'{filename!r} seems not a file')
elif isinstance(filename, str):
filename = filename.encode(fs_encoding)
_check_no_remaining_kwargs(compile, kwargs)
s, v, source_map = _sass.compile_filename(
@ -780,9 +767,9 @@ class SassNumber(collections.namedtuple('SassNumber', ('value', 'unit'))):
def __new__(cls, value, unit):
value = float(value)
if not isinstance(unit, text_type):
if not isinstance(unit, str):
unit = unit.decode('UTF-8')
return super(SassNumber, cls).__new__(cls, value, unit)
return super().__new__(cls, value, unit)
class SassColor(collections.namedtuple('SassColor', ('r', 'g', 'b', 'a'))):
@ -792,7 +779,7 @@ class SassColor(collections.namedtuple('SassColor', ('r', 'g', 'b', 'a'))):
g = float(g)
b = float(b)
a = float(a)
return super(SassColor, cls).__new__(cls, r, g, b, a)
return super().__new__(cls, r, g, b, a)
SASS_SEPARATOR_COMMA = collections.namedtuple('SASS_SEPARATOR_COMMA', ())()
@ -802,7 +789,7 @@ SEPARATORS = frozenset((SASS_SEPARATOR_COMMA, SASS_SEPARATOR_SPACE))
class SassList(
collections.namedtuple(
'SassList', ('items', 'separator', 'bracketed'),
'SassList', ('items', 'separator', 'bracketed'),
),
):
@ -810,26 +797,26 @@ class SassList(
items = tuple(items)
assert separator in SEPARATORS, separator
assert isinstance(bracketed, bool), bracketed
return super(SassList, cls).__new__(cls, items, separator, bracketed)
return super().__new__(cls, items, separator, bracketed)
class SassError(collections.namedtuple('SassError', ('msg',))):
def __new__(cls, msg):
if not isinstance(msg, text_type):
if not isinstance(msg, str):
msg = msg.decode('UTF-8')
return super(SassError, cls).__new__(cls, msg)
return super().__new__(cls, msg)
class SassWarning(collections.namedtuple('SassWarning', ('msg',))):
def __new__(cls, msg):
if not isinstance(msg, text_type):
if not isinstance(msg, str):
msg = msg.decode('UTF-8')
return super(SassWarning, cls).__new__(cls, msg)
return super().__new__(cls, msg)
class SassMap(collections_abc.Mapping):
class SassMap(collections.abc.Mapping):
"""Because sass maps can have mapping types as keys, we need an immutable
hashable mapping type.
@ -858,7 +845,7 @@ class SassMap(collections_abc.Mapping):
# Our interface
def __repr__(self):
return '{}({})'.format(type(self).__name__, frozenset(self.items()))
return f'{type(self).__name__}({frozenset(self.items())})'
def __hash__(self):
return self._hash

View File

@ -1,15 +0,0 @@
import warnings
import pysassc
def main(*args, **kwargs):
warnings.warn(
'The `sassc` entrypoint is deprecated, please use `pysassc`',
FutureWarning,
),
return pysassc.main(*args, **kwargs)
if __name__ == '__main__':
exit(main())

View File

@ -1,12 +1,10 @@
# -*- coding: utf-8 -*-
import base64
import collections.abc
import contextlib
import functools
import glob
import json
import io
import os
import json
import os.path
import re
import shutil
@ -17,15 +15,13 @@ import traceback
import unittest
import pytest
from six import StringIO, b, string_types, text_type
from werkzeug.test import Client
from werkzeug.wrappers import Response
import pysassc
import sass
import sassc
from sassutils._compat import collections_abc
from sassutils.builder import Manifest, build_directory
from sassutils.builder import build_directory
from sassutils.builder import Manifest
from sassutils.wsgi import SassMiddleware
@ -71,7 +67,7 @@ A_EXPECTED_MAP = {
),
}
with io.open('test/a.scss', newline='') as f:
with open('test/a.scss', newline='') as f:
A_EXPECTED_MAP_CONTENTS = dict(A_EXPECTED_MAP, sourcesContent=[f.read()])
B_EXPECTED_CSS = '''\
@ -95,7 +91,7 @@ h1 a {
color: green; }
'''
D_EXPECTED_CSS = u'''\
D_EXPECTED_CSS = '''\
@charset "UTF-8";
body {
background-color: green; }
@ -103,7 +99,7 @@ body {
font: '나눔고딕', sans-serif; }
'''
D_EXPECTED_CSS_WITH_MAP = u'''\
D_EXPECTED_CSS_WITH_MAP = '''\
@charset "UTF-8";
body {
background-color: green; }
@ -149,7 +145,7 @@ re_base64_data_uri = re.compile(r'^data:[^;]*?;base64,(.+)$')
def _map_in_output_dir(s):
def cb(match):
filename = os.path.basename(match.group(1))
return '/*# sourceMappingURL={} */'.format(filename)
return f'/*# sourceMappingURL={filename} */'
return re_sourcemap_url.sub(cb, s)
@ -163,9 +159,9 @@ def no_warnings(recwarn):
class BaseTestCase(unittest.TestCase):
def assert_source_map_equal(self, expected, actual):
if isinstance(expected, string_types):
if isinstance(expected, str):
expected = json.loads(expected)
if isinstance(actual, string_types):
if isinstance(actual, str):
actual = json.loads(actual)
assert expected == actual
@ -175,7 +171,7 @@ class BaseTestCase(unittest.TestCase):
tree = json.load(f)
except ValueError as e: # pragma: no cover
f.seek(0)
msg = '{!s}\n\n{}:\n\n{}'.format(e, filename, f.read())
msg = f'{e!s}\n\n{filename}:\n\n{f.read()}'
raise ValueError(msg)
self.assert_source_map_equal(expected, tree)
@ -196,7 +192,7 @@ class SassTestCase(BaseTestCase):
assert re.match(r'^\d+\.\d+\.\d+$', sass.__version__)
def test_output_styles(self):
assert isinstance(sass.OUTPUT_STYLES, collections_abc.Mapping)
assert isinstance(sass.OUTPUT_STYLES, collections.abc.Mapping)
assert 'nested' in sass.OUTPUT_STYLES
def test_and_join(self):
@ -294,9 +290,9 @@ a {
a b {
color: blue; }
'''
actual = sass.compile(string=u'a { color: blue; } /* 유니코드 */')
actual = sass.compile(string='a { color: blue; } /* 유니코드 */')
self.assertEqual(
u'''@charset "UTF-8";
'''@charset "UTF-8";
a {
color: blue; }
@ -330,11 +326,11 @@ a {
def test_importer_one_arg(self):
"""Demonstrates one-arg importers + chaining."""
def importer_returning_one_argument(path):
assert type(path) is text_type
assert type(path) is str
return (
# Trigger the import of an actual file
('test/b.scss',),
(path, '.{0}-one-arg {{ color: blue; }}'.format(path)),
(path, f'.{path}-one-arg {{ color: blue; }}'),
)
ret = sass.compile(
@ -428,11 +424,11 @@ a {
path,
'a { color: red; }',
json.dumps({
"version": 3,
"sources": [
path + ".db",
'version': 3,
'sources': [
path + '.db',
],
"mappings": ";AAAA,CAAC,CAAC;EAAE,KAAK,EAAE,GAAI,GAAI",
'mappings': ';AAAA,CAAC,CAAC;EAAE,KAAK,EAAE,GAAI,GAAI',
}),
),
)
@ -448,17 +444,17 @@ a {
def test_importers_raises_exception(self):
def importer(path):
raise ValueError('Bad path: {}'.format(path))
raise ValueError(f'Bad path: {path}')
with assert_raises_compile_error(
RegexMatcher(
r'^Error: \n'
r' Traceback \(most recent call last\):\n'
r'.+'
r'ValueError: Bad path: hi\n'
r' on line 1:9 of stdin\n'
r'>> @import "hi";\n'
r' --------\^\n',
r'^Error: \n'
r' Traceback \(most recent call last\):\n'
r'.+'
r'ValueError: Bad path: hi\n'
r' on line 1:9 of stdin\n'
r'>> @import "hi";\n'
r' --------\^\n',
),
):
sass.compile(string='@import "hi";', importers=((0, importer),))
@ -469,14 +465,14 @@ a {
with assert_raises_compile_error(
RegexMatcher(
r'^Error: \n'
r' Traceback \(most recent call last\):\n'
r'.+'
r'ValueError: Expected importer result to be a tuple of '
r'length \(1, 2, 3\) but got 0: \(\)\n'
r' on line 1:9 of stdin\n'
r'>> @import "hi";\n'
r' --------\^\n',
r'^Error: \n'
r' Traceback \(most recent call last\):\n'
r'.+'
r'ValueError: Expected importer result to be a tuple of '
r'length \(1, 2, 3\) but got 0: \(\)\n'
r' on line 1:9 of stdin\n'
r'>> @import "hi";\n'
r' --------\^\n',
),
):
sass.compile(string='@import "hi";', importers=((0, importer),))
@ -487,14 +483,14 @@ a {
with assert_raises_compile_error(
RegexMatcher(
r'^Error: \n'
r' Traceback \(most recent call last\):\n'
r'.+'
r'ValueError: Expected importer result to be a tuple of '
r"length \(1, 2, 3\) but got 4: \('a', 'b', 'c', 'd'\)\n"
r' on line 1:9 of stdin\n'
r'>> @import "hi";\n'
r' --------\^\n',
r'^Error: \n'
r' Traceback \(most recent call last\):\n'
r'.+'
r'ValueError: Expected importer result to be a tuple of '
r"length \(1, 2, 3\) but got 4: \('a', 'b', 'c', 'd'\)\n"
r' on line 1:9 of stdin\n'
r'>> @import "hi";\n'
r' --------\^\n',
),
):
sass.compile(string='@import "hi";', importers=((0, importer),))
@ -640,31 +636,31 @@ class BuilderTestCase(BaseTestCase):
result_files = build_directory(self.sass_path, css_path)
assert len(result_files) == 8
assert 'a.scss.css' == result_files['a.scss']
with io.open(
with open(
os.path.join(css_path, 'a.scss.css'), encoding='UTF-8',
) as f:
css = f.read()
assert A_EXPECTED_CSS == css
assert 'b.scss.css' == result_files['b.scss']
with io.open(
with open(
os.path.join(css_path, 'b.scss.css'), encoding='UTF-8',
) as f:
css = f.read()
assert B_EXPECTED_CSS == css
assert 'c.scss.css' == result_files['c.scss']
with io.open(
with open(
os.path.join(css_path, 'c.scss.css'), encoding='UTF-8',
) as f:
css = f.read()
assert C_EXPECTED_CSS == css
assert 'd.scss.css' == result_files['d.scss']
with io.open(
with open(
os.path.join(css_path, 'd.scss.css'), encoding='UTF-8',
) as f:
css = f.read()
assert D_EXPECTED_CSS == css
assert 'e.scss.css' == result_files['e.scss']
with io.open(
with open(
os.path.join(css_path, 'e.scss.css'), encoding='UTF-8',
) as f:
css = f.read()
@ -673,7 +669,7 @@ class BuilderTestCase(BaseTestCase):
os.path.join('subdir', 'recur.scss.css'),
result_files[os.path.join('subdir', 'recur.scss')],
)
with io.open(
with open(
os.path.join(css_path, 'g.scss.css'), encoding='UTF-8',
) as f:
css = f.read()
@ -683,12 +679,12 @@ class BuilderTestCase(BaseTestCase):
result_files[os.path.join('subdir', 'recur.scss')],
)
assert 'h.sass.css' == result_files['h.sass']
with io.open(
with open(
os.path.join(css_path, 'h.sass.css'), encoding='UTF-8',
) as f:
css = f.read()
assert H_EXPECTED_CSS == css
with io.open(
with open(
os.path.join(css_path, 'subdir', 'recur.scss.css'),
encoding='UTF-8',
) as f:
@ -703,7 +699,7 @@ class BuilderTestCase(BaseTestCase):
)
assert len(result_files) == 8
assert 'a.scss.css' == result_files['a.scss']
with io.open(
with open(
os.path.join(css_path, 'a.scss.css'), encoding='UTF-8',
) as f:
css = f.read()
@ -755,7 +751,7 @@ class ManifestTestCase(BaseTestCase):
with open(os.path.join(d, 'css', 'a.scss.css')) as f:
assert A_EXPECTED_CSS == f.read()
m.build_one(d, 'b.scss', source_map=True)
with io.open(
with open(
os.path.join(d, 'css', 'b.scss.css'), encoding='UTF-8',
) as f:
assert f.read() == _map_in_output_dir(B_EXPECTED_CSS_WITH_MAP)
@ -773,7 +769,7 @@ class ManifestTestCase(BaseTestCase):
os.path.join(d, 'css', 'b.scss.css.map'),
)
m.build_one(d, 'd.scss', source_map=True)
with io.open(
with open(
os.path.join(d, 'css', 'd.scss.css'), encoding='UTF-8',
) as f:
assert f.read() == _map_in_output_dir(D_EXPECTED_CSS_WITH_MAP)
@ -838,7 +834,7 @@ class WsgiTestCase(BaseTestCase):
r = client.get('/static/a.scss.css')
assert r.status_code == 200
self.assertEqual(
b(_map_in_output_dir(A_EXPECTED_CSS_WITH_MAP)),
_map_in_output_dir(A_EXPECTED_CSS_WITH_MAP).encode(),
r.data,
)
assert r.mimetype == 'text/css'
@ -903,7 +899,7 @@ class DistutilsTestCase(BaseTestCase):
return os.path.join(
os.path.dirname(__file__),
'testpkg', 'testpkg', 'static', 'css',
*args
*args,
)
def list_built_css(self):
@ -942,8 +938,8 @@ class DistutilsTestCase(BaseTestCase):
class SasscTestCase(BaseTestCase):
def setUp(self):
self.out = StringIO()
self.err = StringIO()
self.out = io.StringIO()
self.err = io.StringIO()
def test_no_args(self):
exit_code = pysassc.main(['pysassc'], self.out, self.err)
@ -973,17 +969,6 @@ class SasscTestCase(BaseTestCase):
assert self.err.getvalue() == ''
assert A_EXPECTED_CSS.strip() == self.out.getvalue().strip()
def test_sassc_stdout(self):
with pytest.warns(FutureWarning) as warninfo:
exit_code = sassc.main(
['sassc', 'test/a.scss'],
self.out, self.err,
)
assert 'use `pysassc`' in warninfo[0].message.args[0]
assert exit_code == 0
assert self.err.getvalue() == ''
assert A_EXPECTED_CSS.strip() == self.out.getvalue().strip()
def test_pysassc_output(self):
fd, tmp = tempfile.mkstemp('.css')
try:
@ -995,7 +980,7 @@ class SasscTestCase(BaseTestCase):
assert exit_code == 0
assert self.err.getvalue() == ''
assert self.out.getvalue() == ''
with io.open(tmp, encoding='UTF-8', newline='') as f:
with open(tmp, encoding='UTF-8', newline='') as f:
assert A_EXPECTED_CSS.strip() == f.read().strip()
finally:
os.remove(tmp)
@ -1011,7 +996,7 @@ class SasscTestCase(BaseTestCase):
assert exit_code == 0
assert self.err.getvalue() == ''
assert self.out.getvalue() == ''
with io.open(tmp, encoding='UTF-8') as f:
with open(tmp, encoding='UTF-8') as f:
assert D_EXPECTED_CSS.strip() == f.read().strip()
finally:
os.remove(tmp)
@ -1093,10 +1078,10 @@ class CompileDirectoriesTest(unittest.TestCase):
input_dir = os.path.join(tmpdir, 'input')
output_dir = os.path.join(tmpdir, 'output')
os.makedirs(input_dir)
with io.open(
with open(
os.path.join(input_dir, 'test.scss'), 'w', encoding='UTF-8',
) as f:
f.write(u'a { content: ""; }')
f.write('a { content: ""; }')
# Raised a UnicodeEncodeError in py2 before #82 (issue #72)
# Also raised a UnicodeEncodeError in py3 if the default encoding
# couldn't represent it (such as cp1252 on windows)
@ -1131,7 +1116,7 @@ class CompileDirectoriesTest(unittest.TestCase):
class SassFunctionTest(unittest.TestCase):
def test_from_lambda(self):
lambda_ = lambda abc, d: None # pragma: no branch # noqa: E731
def lambda_(abc, d): return None # pragma: no branch # noqa: E731
sf = sass.SassFunction.from_lambda('func_name', lambda_)
assert 'func_name' == sf.name
assert ('$abc', '$d') == sf.arguments
@ -1164,14 +1149,14 @@ def test_sass_func_type_errors(func):
class SassTypesTest(unittest.TestCase):
def test_number_no_conversion(self):
num = sass.SassNumber(123., u'px')
num = sass.SassNumber(123., 'px')
assert type(num.value) is float, type(num.value)
assert type(num.unit) is text_type, type(num.unit)
assert type(num.unit) is str, type(num.unit)
def test_number_conversion(self):
num = sass.SassNumber(123, b'px')
assert type(num.value) is float, type(num.value)
assert type(num.unit) is text_type, type(num.unit)
assert type(num.unit) is str, type(num.unit)
def test_color_no_conversion(self):
color = sass.SassColor(1., 2., 3., .5)
@ -1198,20 +1183,20 @@ class SassTypesTest(unittest.TestCase):
assert lst.separator is sass.SASS_SEPARATOR_SPACE, lst.separator
def test_sass_warning_no_conversion(self):
warn = sass.SassWarning(u'error msg')
assert type(warn.msg) is text_type, type(warn.msg)
warn = sass.SassWarning('error msg')
assert type(warn.msg) is str, type(warn.msg)
def test_sass_warning_no_conversion_bytes_message(self):
warn = sass.SassWarning(b'error msg')
assert type(warn.msg) is text_type, type(warn.msg)
assert type(warn.msg) is str, type(warn.msg)
def test_sass_error_no_conversion(self):
err = sass.SassError(u'error msg')
assert type(err.msg) is text_type, type(err.msg)
err = sass.SassError('error msg')
assert type(err.msg) is str, type(err.msg)
def test_sass_error_conversion(self):
err = sass.SassError(b'error msg')
assert type(err.msg) is text_type, type(err.msg)
assert type(err.msg) is str, type(err.msg)
def raises():
@ -1244,11 +1229,11 @@ def returns_none():
def returns_unicode():
return u''
return ''
def returns_bytes():
return u''.encode('UTF-8')
return ''.encode()
def returns_number():
@ -1380,7 +1365,7 @@ def assert_raises_compile_error(expected):
assert msg == expected, (msg, expected)
class RegexMatcher(object):
class RegexMatcher:
def __init__(self, reg, flags=None):
self.reg = re.compile(reg, re.MULTILINE | re.DOTALL)
@ -1393,14 +1378,14 @@ class CustomFunctionsTest(unittest.TestCase):
def test_raises(self):
with assert_raises_compile_error(
RegexMatcher(
r'^Error: error in C function raises: \n'
r' Traceback \(most recent call last\):\n'
r'.+'
r'AssertionError: foo\n'
r' on line 1:14 of stdin, in function `raises`\n'
r' from line 1:14 of stdin\n'
r'>> a { content: raises\(\); }\n'
r' -------------\^\n$',
r'^Error: error in C function raises: \n'
r' Traceback \(most recent call last\):\n'
r'.+'
r'AssertionError: foo\n'
r' on line 1:14 of stdin, in function `raises`\n'
r' from line 1:14 of stdin\n'
r'>> a { content: raises\(\); }\n'
r' -------------\^\n$',
),
):
compile_with_func('a { content: raises(); }')
@ -1472,13 +1457,13 @@ class CustomFunctionsTest(unittest.TestCase):
def test_unicode(self):
self.assertEqual(
compile_with_func('a { content: returns_unicode(); }'),
u'\ufeffa{content:☃}\n',
'\ufeffa{content:☃}\n',
)
def test_bytes(self):
self.assertEqual(
compile_with_func('a { content: returns_bytes(); }'),
u'\ufeffa{content:☃}\n',
'\ufeffa{content:☃}\n',
)
def test_number(self):
@ -1550,7 +1535,7 @@ class CustomFunctionsTest(unittest.TestCase):
def test_identity_strings(self):
self.assertEqual(
compile_with_func('a { content: identity(returns_unicode()); }'),
u'\ufeffa{content:☃}\n',
'\ufeffa{content:☃}\n',
)
def test_identity_number(self):
@ -1626,7 +1611,7 @@ class CustomFunctionsTest(unittest.TestCase):
def test_stack_trace_formatting():
try:
sass.compile(string=u'a{')
sass.compile(string='a{')
raise AssertionError('expected to raise CompileError')
except sass.CompileError:
tb = traceback.format_exc()

View File

@ -1,7 +0,0 @@
from six import PY2
if PY2: # pragma: no cover (PY2)
import collections as collections_abc # noqa: F401
else: # pragma: no cover (PY3)
import collections.abc as collections_abc # noqa: F401

View File

@ -2,17 +2,12 @@
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
"""
import io
import os
import collections.abc
import os.path
import re
import warnings
from six import string_types
from sass import compile
from sassutils._compat import collections_abc
__all__ = 'SUFFIXES', 'SUFFIX_PATTERN', 'Manifest', 'build_directory'
@ -69,7 +64,7 @@ def build_directory(
output_style=output_style,
include_paths=[_root_sass],
)
with io.open(
with open(
css_fullname, 'w', encoding='utf-8', newline='',
) as css_file:
css_file.write(css)
@ -88,7 +83,7 @@ def build_directory(
return result
class Manifest(object):
class Manifest:
"""Building manifest of Sass/SCSS.
:param sass_path: the path of the directory that contains Sass/SCSS
@ -105,7 +100,7 @@ class Manifest(object):
def normalize_manifests(cls, manifests):
if manifests is None:
manifests = {}
elif isinstance(manifests, collections_abc.Mapping):
elif isinstance(manifests, collections.abc.Mapping):
manifests = dict(manifests)
else:
raise TypeError(
@ -113,7 +108,7 @@ class Manifest(object):
repr(manifests),
)
for package_name, manifest in manifests.items():
if not isinstance(package_name, string_types):
if not isinstance(package_name, str):
raise TypeError(
'manifest keys must be a string of package '
'name, not ' + repr(package_name),
@ -122,9 +117,9 @@ class Manifest(object):
continue
elif isinstance(manifest, tuple):
manifest = Manifest(*manifest)
elif isinstance(manifest, collections_abc.Mapping):
elif isinstance(manifest, collections.abc.Mapping):
manifest = Manifest(**manifest)
elif isinstance(manifest, string_types):
elif isinstance(manifest, str):
manifest = Manifest(manifest)
else:
raise TypeError(
@ -142,21 +137,21 @@ class Manifest(object):
wsgi_path=None,
strip_extension=None,
):
if not isinstance(sass_path, string_types):
if not isinstance(sass_path, str):
raise TypeError(
'sass_path must be a string, not ' +
repr(sass_path),
)
if css_path is None:
css_path = sass_path
elif not isinstance(css_path, string_types):
elif not isinstance(css_path, str):
raise TypeError(
'css_path must be a string, not ' +
repr(css_path),
)
if wsgi_path is None:
wsgi_path = css_path
elif not isinstance(wsgi_path, string_types):
elif not isinstance(wsgi_path, str):
raise TypeError(
'wsgi_path must be a string, not ' +
repr(wsgi_path),
@ -292,11 +287,11 @@ class Manifest(object):
css_folder = os.path.dirname(css_path)
if not os.path.exists(css_folder):
os.makedirs(css_folder)
with io.open(css_path, 'w', encoding='utf-8', newline='') as f:
with open(css_path, 'w', encoding='utf-8', newline='') as f:
f.write(css)
if source_map:
# Source maps are JSON, and JSON has to be UTF-8 encoded
with io.open(
with open(
source_map_path, 'w', encoding='utf-8', newline='',
) as f:
f.write(source_map)

View File

@ -67,19 +67,17 @@ The option can also be a mapping of package names to manifest dictionaries::
Added ``--output-style``/``-s`` option to :class:`build_sass` command.
"""
from __future__ import absolute_import
import functools
import os.path
import distutils.errors
import distutils.log
import distutils.util
import functools
import os.path
from setuptools import Command
from setuptools.command.sdist import sdist
from sass import OUTPUT_STYLES
from .builder import Manifest
from sass import OUTPUT_STYLES
__all__ = 'build_sass', 'validate_manifests'

View File

@ -2,22 +2,19 @@
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
"""
from __future__ import absolute_import
import collections.abc
import logging
import os
import os.path
from pkg_resources import resource_filename
from sass import CompileError
from sassutils._compat import collections_abc
from .builder import Manifest
from sass import CompileError
__all__ = 'SassMiddleware',
class SassMiddleware(object):
class SassMiddleware:
r"""WSGI middleware for development purpose. Every time a CSS file has
requested it finds a matched Sass/SCSS source file and then compiled
it into CSS.
@ -100,7 +97,7 @@ class SassMiddleware(object):
)
self.app = app
self.manifests = Manifest.normalize_manifests(manifests)
if not isinstance(package_dir, collections_abc.Mapping):
if not isinstance(package_dir, collections.abc.Mapping):
raise TypeError(
'package_dir must be a mapping object, not ' +
repr(package_dir),
@ -138,7 +135,7 @@ class SassMiddleware(object):
sass_filename,
source_map=True,
)
except (IOError, OSError):
except OSError:
break
except CompileError as e:
logger = logging.getLogger(__name__ + '.SassMiddleware')

View File

@ -1,11 +1,5 @@
#!/usr/bin/env python
from __future__ import print_function
import ast
import atexit
import distutils.cmd
import distutils.log
import distutils.sysconfig
import os.path
import platform
import shutil
@ -13,7 +7,11 @@ import subprocess
import sys
import tempfile
from setuptools import Extension, setup
import distutils.cmd
import distutils.log
import distutils.sysconfig
from setuptools import Extension
from setuptools import setup
MACOS_FLAG = ['-mmacosx-version-min=10.7']
FLAGS_POSIX = [
@ -83,9 +81,9 @@ else:
libsass_version = libsass_version_file.read().decode('UTF-8').strip()
if sys.platform == 'win32':
# This looks wrong, but is required for some reason :(
define = r'/DLIBSASS_VERSION="\"{}\""'.format(libsass_version)
define = fr'/DLIBSASS_VERSION="\"{libsass_version}\""'
else:
define = '-DLIBSASS_VERSION="{}"'.format(libsass_version)
define = f'-DLIBSASS_VERSION="{libsass_version}"'
for directory in (
os.path.join('libsass', 'src'),
@ -185,7 +183,7 @@ def readme():
try:
with open(os.path.join(os.path.dirname(__file__), 'README.rst')) as f:
return f.read()
except IOError:
except OSError:
pass
@ -232,7 +230,7 @@ if sys.version_info >= (3,) and platform.python_implementation() == 'CPython':
else:
class bdist_wheel(wheel.bdist_wheel.bdist_wheel):
def finalize_options(self):
self.py_limited_api = 'cp3{}'.format(sys.version_info[1])
self.py_limited_api = f'cp3{sys.version_info[1]}'
super().finalize_options()
cmdclass['bdist_wheel'] = bdist_wheel
@ -246,7 +244,7 @@ setup(
version=version(),
ext_modules=[sass_extension],
packages=['sassutils'],
py_modules=['pysassc', 'sass', 'sassc', 'sasstests'],
py_modules=['pysassc', 'sass', 'sasstests'],
package_data={
'': [
'README.rst',
@ -267,11 +265,8 @@ setup(
],
'console_scripts': [
['pysassc = pysassc:main'],
# TODO: remove `sassc` entry (#134)
['sassc = sassc:main'],
],
},
install_requires=['six'],
classifiers=[
'Development Status :: 5 - Production/Stable',
'Environment :: Web Environment',
@ -280,7 +275,6 @@ setup(
'Operating System :: OS Independent',
'Programming Language :: C',
'Programming Language :: C++',
'Programming Language :: Python :: 2.7',
'Programming Language :: Python :: 3',
'Programming Language :: Python :: 3.6',
'Programming Language :: Python :: 3.7',
@ -294,5 +288,6 @@ setup(
'Topic :: Software Development :: Code Generators',
'Topic :: Software Development :: Compilers',
],
python_requires='>=3.6',
cmdclass=cmdclass,
)

View File

@ -1,5 +1,5 @@
[tox]
envlist = pypy,pypy3,py27,py36,py37,py38,py39,pre-commit
envlist = pypy3,py36,py37,py38,py39,pre-commit
[testenv]
usedevelop = true