diff --git a/stubs/libsass/@tests/stubtest_allowlist.txt b/stubs/libsass/@tests/stubtest_allowlist.txt new file mode 100644 index 000000000..a93ae4db3 --- /dev/null +++ b/stubs/libsass/@tests/stubtest_allowlist.txt @@ -0,0 +1,6 @@ +# Error: is not present in stub +# ============================= +# These are only implemented for the purposes of emitting an error +# we don't want these to appear mutable in a type checking context +sass.SassMap.__delitem__ +sass.SassMap.__setitem__ diff --git a/stubs/libsass/METADATA.toml b/stubs/libsass/METADATA.toml new file mode 100644 index 000000000..2d48b88a6 --- /dev/null +++ b/stubs/libsass/METADATA.toml @@ -0,0 +1,3 @@ +version = "0.22.*" +requires = ["types-setuptools"] +upstream_repository = "https://github.com/sass/libsass-python" diff --git a/stubs/libsass/sass.pyi b/stubs/libsass/sass.pyi new file mode 100644 index 000000000..d43fe4e5d --- /dev/null +++ b/stubs/libsass/sass.pyi @@ -0,0 +1,176 @@ +import enum +from _typeshed import ReadableBuffer, SupportsKeysAndGetItem +from collections.abc import Callable, Iterable, Iterator, Mapping, Sequence, Set as AbstractSet +from typing import Any, Generic, NamedTuple, SupportsFloat, TypeVar, overload, type_check_only +from typing_extensions import Literal, ParamSpec, Self, SupportsIndex, TypeAlias + +_T = TypeVar("_T") +_KT = TypeVar("_KT") +_VT_co = TypeVar("_VT_co", covariant=True) +_P = ParamSpec("_P") +_Mode: TypeAlias = Literal["string", "filename", "dirname"] +_OutputStyle: TypeAlias = Literal["nested", "expanded", "compact", "compressed"] +_ConvertsToFloat: TypeAlias = SupportsFloat | SupportsIndex | str | ReadableBuffer +_CustomFunctions: TypeAlias = Mapping[str, Callable[..., Any]] | Sequence[Callable[..., Any]] | AbstractSet[Callable[..., Any]] +_ImportCallbackRet: TypeAlias = ( + list[tuple[str, str, str]] | list[tuple[str, str]] | list[tuple[str]] | list[tuple[str, ...]] | None +) +_ImportCallback: TypeAlias = Callable[[str], _ImportCallbackRet] | Callable[[str, str], _ImportCallbackRet] + +__version__: str +libsass_version: str +OUTPUT_STYLES: dict[str, int] +SOURCE_COMMENTS: dict[str, int] +MODES: frozenset[_Mode] + +class CompileError(ValueError): + def __init__(self, msg: str) -> None: ... + +# _P needs to be positional only and can't contain varargs, but there is no way to express that +# the arguments also need +class SassFunction(Generic[_P, _T]): + @classmethod + def from_lambda(cls, name: str, lambda_: Callable[_P, _T]) -> SassFunction[_P, _T]: ... + @classmethod + def from_named_function(cls, function: Callable[_P, _T]) -> SassFunction[_P, _T]: ... + name: str + arguments: tuple[str, ...] + callable_: Callable[_P, _T] + def __init__(self, name: str, arguments: Sequence[str], callable_: Callable[_P, _T]) -> None: ... + @property + def signature(self) -> str: ... + def __call__(self, *args: _P.args, **kwargs: _P.kwargs) -> _T: ... + +@overload +def compile( + *, + string: str, + output_style: _OutputStyle = "nested", + source_comments: bool = False, + source_map_contents: bool = False, + source_map_embed: bool = False, + omit_source_map_url: bool = False, + source_map_root: str | None = None, + include_paths: Sequence[str] = (), + precision: int = 5, + custom_functions: _CustomFunctions = (), + indented: bool = False, + importers: Iterable[tuple[int, _ImportCallback]] | None = None, +) -> str: ... +@overload +def compile( + *, + filename: str, + output_style: _OutputStyle = "nested", + source_comments: bool = False, + source_map_filename: None = None, + output_filename_hint: str | None = None, + source_map_contents: bool = False, + source_map_embed: bool = False, + omit_source_map_url: bool = False, + source_map_root: str | None = None, + include_paths: Sequence[str] = (), + precision: int = 5, + custom_functions: _CustomFunctions = (), + importers: Iterable[tuple[int, _ImportCallback]] | None = None, +) -> str: ... +@overload +def compile( + *, + filename: str, + output_style: _OutputStyle = "nested", + source_comments: bool = False, + source_map_filename: str, + output_filename_hint: str | None = None, + source_map_contents: bool = False, + source_map_embed: bool = False, + omit_source_map_url: bool = False, + source_map_root: str | None = None, + include_paths: Sequence[str] = (), + precision: int = 5, + custom_functions: _CustomFunctions = (), + importers: Iterable[tuple[int, _ImportCallback]] | None = None, +) -> tuple[str, str]: ... +@overload +def compile( + *, + dirname: tuple[str, str], + output_style: _OutputStyle = "nested", + source_comments: bool = False, + source_map_contents: bool = False, + source_map_embed: bool = False, + omit_source_map_url: bool = False, + source_map_root: str | None = None, + include_paths: Sequence[str] = (), + precision: int = 5, + custom_functions: _CustomFunctions = (), + importers: Iterable[tuple[int, _ImportCallback]] | None = None, +) -> None: ... +def and_join(strings: Sequence[str]) -> str: ... +@type_check_only +class _SassNumber(NamedTuple): + value: float + unit: str + +class SassNumber(_SassNumber): + def __new__(cls, value: _ConvertsToFloat, unit: str | bytes) -> Self: ... + +@type_check_only +class _SassColor(NamedTuple): + r: float + g: float + b: float + a: float + +class SassColor(_SassColor): + def __new__(cls, r: _ConvertsToFloat, g: _ConvertsToFloat, b: _ConvertsToFloat, a: _ConvertsToFloat) -> Self: ... + +@type_check_only +class _Separator(enum.Enum): + SASS_SEPARATOR_COMMA = enum.auto() + SASS_SEPARATOR_SPACE = enum.auto() + +SASS_SEPARATOR_COMMA: Literal[_Separator.SASS_SEPARATOR_COMMA] +SASS_SEPARATOR_SPACE: Literal[_Separator.SASS_SEPARATOR_SPACE] + +@type_check_only +class _SassList(NamedTuple, Generic[_T]): + items: tuple[_T, ...] + separator: _Separator + bracketed: bool + +class SassList(_SassList[_T]): + def __new__(cls, items: Iterable[_T], separator: _Separator, bracketed: bool = ...) -> SassList[_T]: ... + +@type_check_only +class _SassError(NamedTuple): + msg: str + +class SassError(_SassError): + def __new__(cls, msg: str | bytes) -> Self: ... + +@type_check_only +class _SassWarning(NamedTuple): + msg: str + +class SassWarning(_SassWarning): + def __new__(cls, msg: str | bytes) -> Self: ... + +class SassMap(Mapping[_KT, _VT_co]): + # copied from dict.__init__ in builtins.pyi, since it uses dict() internally + @overload + def __init__(self) -> None: ... + @overload + def __init__(self: SassMap[str, _VT_co], **kwargs: _VT_co) -> None: ... + @overload + def __init__(self, __map: SupportsKeysAndGetItem[_KT, _VT_co]) -> None: ... + @overload + def __init__(self: SassMap[str, _VT_co], __map: SupportsKeysAndGetItem[str, _VT_co], **kwargs: _VT_co) -> None: ... + @overload + def __init__(self, __iterable: Iterable[tuple[_KT, _VT_co]]) -> None: ... + @overload + def __init__(self: SassMap[str, _VT_co], __iterable: Iterable[tuple[str, _VT_co]], **kwargs: _VT_co) -> None: ... + def __getitem__(self, key: _KT) -> _VT_co: ... + def __iter__(self) -> Iterator[_KT]: ... + def __len__(self) -> int: ... + def __hash__(self) -> int: ... diff --git a/stubs/libsass/sassutils/__init__.pyi b/stubs/libsass/sassutils/__init__.pyi new file mode 100644 index 000000000..e69de29bb diff --git a/stubs/libsass/sassutils/builder.pyi b/stubs/libsass/sassutils/builder.pyi new file mode 100644 index 000000000..7d23a6fbb --- /dev/null +++ b/stubs/libsass/sassutils/builder.pyi @@ -0,0 +1,34 @@ +from collections.abc import Mapping +from re import Pattern +from typing import Any + +from sass import _OutputStyle + +SUFFIXES: frozenset[str] +SUFFIX_PATTERN: Pattern[str] + +def build_directory( + sass_path: str, + css_path: str, + output_style: _OutputStyle = "nested", + _root_sass: None = None, # internal arguments for recursion + _root_css: None = None, # internal arguments for recursion + strip_extension: bool = False, +) -> dict[str, str]: ... + +class Manifest: + @classmethod + def normalize_manifests( + cls, manifests: Mapping[str, Manifest | tuple[Any, ...] | Mapping[str, Any] | str] | None + ) -> dict[str, Manifest]: ... + sass_path: str + css_path: str + wsgi_path: str + strip_extension: bool + def __init__( + self, sass_path: str, css_path: str | None = None, wsgi_path: str | None = None, strip_extension: bool | None = None + ) -> None: ... + def resolve_filename(self, package_dir: str, filename: str) -> tuple[str, str]: ... + def unresolve_filename(self, package_dir: str, filename: str) -> str: ... + def build(self, package_dir: str, output_style: _OutputStyle = "nested") -> frozenset[str]: ... + def build_one(self, package_dir: str, filename: str, source_map: bool = False) -> str: ... diff --git a/stubs/libsass/sassutils/distutils.pyi b/stubs/libsass/sassutils/distutils.pyi new file mode 100644 index 000000000..309488346 --- /dev/null +++ b/stubs/libsass/sassutils/distutils.pyi @@ -0,0 +1,14 @@ +from sassutils.builder import Manifest as Manifest +from setuptools import Command, Distribution + +def validate_manifests(dist: Distribution, attr: str, value: object) -> None: ... + +class build_sass(Command): + description: str + user_options: list[tuple[str, str, str]] + package_dir: dict[str, str] | None + output_style: str + def initialize_options(self) -> None: ... + def finalize_options(self) -> None: ... + def run(self) -> None: ... + def get_package_dir(self, package: str) -> str: ... diff --git a/stubs/libsass/sassutils/wsgi.pyi b/stubs/libsass/sassutils/wsgi.pyi new file mode 100644 index 000000000..fa2a9d792 --- /dev/null +++ b/stubs/libsass/sassutils/wsgi.pyi @@ -0,0 +1,22 @@ +from _typeshed.wsgi import StartResponse, WSGIApplication, WSGIEnvironment +from collections.abc import Iterable, Mapping +from typing import Any + +from sassutils.builder import Manifest + +class SassMiddleware: + app: WSGIApplication + manifests: dict[str, Manifest] + error_status: str + package_dir: Mapping[str, str] + paths: list[tuple[str, str, Manifest]] + def __init__( + self, + app: WSGIApplication, + manifests: Mapping[str, Manifest | tuple[Any, ...] | Mapping[str, Any] | str] | None, + package_dir: Mapping[str, str] = {}, + error_status: str = "200 OK", + ) -> None: ... + def __call__(self, environ: WSGIEnvironment, start_response: StartResponse) -> Iterable[bytes]: ... + @staticmethod + def quote_css_string(s: str) -> str: ...