Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 2 additions & 5 deletions .github/workflows/lint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,8 @@ jobs:
- name: Install lint dependencies
run: uv sync --group lint

- name: Run flake8
run: uv run flake8 sublime_lib

- name: Run mypy
run: uv run mypy sublime_lib
- name: Run ruff check
run: uvx ruff check sublime_lib

- name: Run pydocstyle (allow failure)
run: uv run pydocstyle sublime_lib
Expand Down
27 changes: 12 additions & 15 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,8 @@ build-backend = "hatchling.build"

[dependency-groups]
lint = [
"flake8>=3.9.2",
"mypy>=0.720",
"pydocstyle>=4.0.0",
"pydocstyle>=6.3.0",
"ruff>=0.17.1",
"sublime-text-stubs>=1.4200.0",
]

Expand All @@ -39,9 +38,6 @@ source = "vcs"
version-file = "sublime_lib/_version.py"
tag-pattern = "v{version}"

[tool.black]
line-length = 100

[tool.coverage.run]
omit = [
"*/tests/*",
Expand All @@ -50,15 +46,16 @@ omit = [
[tool.coverage.report]
show_missing = true

[tool.mypy]
check_untyped_defs = true
disable_error_code = "import-untyped"
disallow_untyped_defs = true
mypy_path = [
"stubs",
"sublime_lib",
]

[tool.pydocstyle]
match_dir = "^(?!_)"
match = "^(?!_).*\\.py"

[tool.ruff]
exclude = [
".git",
".github",
"docs",
"tests",
]
line-length = 100
target-version = "py38"
24 changes: 12 additions & 12 deletions sublime_lib/__init__.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
from .activity_indicator import ActivityIndicator
from .panel import Panel, OutputPanel
from .panel import OutputPanel, Panel
from .region_manager import RegionManager
from .resource_path import ResourcePath
from .settings_dict import NamedSettingsDict, SettingsDict
from .show_selection_panel import NO_SELECTION, show_selection_panel
from .syntax import list_syntaxes, get_syntax_for_scope
from .syntax import get_syntax_for_scope, list_syntaxes
from .view_stream import ViewStream
from .view_utils import LineEnding, close_view, new_view
from .window_utils import close_window, new_window
Expand All @@ -16,23 +16,23 @@
__version_tuple__ = (0, 0, 0, "dev")

__all__ = [
"__version__",
"__version_tuple__",
"NO_SELECTION",
"ActivityIndicator",
"Panel",
"LineEnding",
"NamedSettingsDict",
"OutputPanel",
"Panel",
"RegionManager",
"ResourcePath",
"NamedSettingsDict",
"SettingsDict",
"NO_SELECTION",
"show_selection_panel",
"list_syntaxes",
"get_syntax_for_scope",
"ViewStream",
"LineEnding",
"__version__",
"__version_tuple__",
"close_view",
"new_view",
"close_window",
"get_syntax_for_scope",
"list_syntaxes",
"new_view",
"new_window",
"show_selection_panel",
]
22 changes: 8 additions & 14 deletions sublime_lib/_util/collections.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
from __future__ import annotations

from collections.abc import Iterable, Mapping
from typing import TYPE_CHECKING

if TYPE_CHECKING:
from sublime_types import Value
from typing import Callable

from sublime_types import Value


__all__ = ['projection', 'get_selector']
__all__ = ["get_selector", "projection"]


def projection(d: Mapping[str, Value], keys: Mapping[str, str] | Iterable[str]) -> Value:
Expand All @@ -29,21 +31,15 @@ def projection(d: Mapping[str, Value], keys: Mapping[str, str] | Iterable[str])
"""
if isinstance(keys, Mapping):
return {
new_key: d[original_key]
for original_key, new_key in keys.items()
if original_key in d
new_key: d[original_key] for original_key, new_key in keys.items() if original_key in d
}
else:
return {
key: d[key]
for key in keys
if key in d
}
return {key: d[key] for key in keys if key in d}


def get_selector(
selector: Callable[[Mapping[str, Value]], Value] | Iterable[str] | str,
default_value: Value = None
default_value: Value = None,
) -> Callable[[Mapping[str, Value]], Value]:
if callable(selector):
return selector
Expand All @@ -52,6 +48,4 @@ def get_selector(
elif isinstance(selector, Iterable):
return lambda this: projection(this, selector)
else:
raise TypeError(
'The selector should be a function, string, or iterable of strings.'
)
raise TypeError("The selector should be a function, string, or iterable of strings.")
21 changes: 9 additions & 12 deletions sublime_lib/_util/enum.py
Original file line number Diff line number Diff line change
@@ -1,20 +1,18 @@
from __future__ import annotations
from enum import EnumMeta, Enum, Flag

from enum import Enum, EnumMeta, Flag
from functools import partial
from typing import Any, Callable


__all__ = ['ExtensibleConstructorMeta', 'construct_with_alternatives', 'construct_union']
__all__ = ["ExtensibleConstructorMeta", "construct_union", "construct_with_alternatives"]


class ExtensibleConstructorMeta(EnumMeta):
def __call__(cls, *args: Any, **kwargs: Any) -> Any:
return cls.__new__(cls, *args, **kwargs) # type: ignore


def extend_constructor(
constructor: Callable[..., Enum]
) -> Callable[[EnumMeta], EnumMeta]:
def extend_constructor(constructor: Callable[..., Enum]) -> Callable[[EnumMeta], EnumMeta]:
def decorator(cls: Any) -> EnumMeta:
next_constructor = partial(cls.__new__, cls)

Expand All @@ -28,10 +26,11 @@ def __new__(cls: EnumMeta, *args: Any, **kwargs: Any) -> Enum:


def construct_with_alternatives(
provider: Callable[..., Enum | None]
provider: Callable[..., Enum | None],
) -> Callable[[EnumMeta], EnumMeta]:
def constructor(next_constructor: Callable[..., Enum], cls: EnumMeta,
*args: Any, **kwargs: Any) -> Enum:
def constructor(
next_constructor: Callable[..., Enum], cls: EnumMeta, *args: Any, **kwargs: Any
) -> Enum:
try:
return next_constructor(*args, **kwargs)
except ValueError:
Expand All @@ -45,9 +44,7 @@ def constructor(next_constructor: Callable[..., Enum], cls: EnumMeta,


def _construct_union(
next_constructor: Callable[[Any], Flag],
cls: ExtensibleConstructorMeta,
*args: Any
next_constructor: Callable[[Any], Flag], cls: ExtensibleConstructorMeta, *args: Any
) -> Any:
if args:
ret, *rest = iter(next_constructor(arg) for arg in args)
Expand Down
46 changes: 23 additions & 23 deletions sublime_lib/_util/glob.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
from __future__ import annotations
from functools import lru_cache
from typing import Callable

import re
from functools import lru_cache
from typing import Callable

__all__ = ['get_glob_matcher']
__all__ = ["get_glob_matcher"]


GLOB_RE = re.compile(r"""(?x)(
Expand All @@ -14,39 +14,39 @@
)""")


@lru_cache()
@lru_cache
def get_glob_matcher(pattern: str) -> Callable[[str], bool]:
if pattern.startswith('/'):
if pattern.startswith("/"):
pattern = pattern[1:]
else:
pattern = '**/' + pattern
pattern = "**/" + pattern

expr_string = r'\A'
for component in pattern.split('/'):
if component == '':
expr_string = r"\A"
for component in pattern.split("/"):
if component == "":
pass
elif component == '*':
elif component == "*":
# Component must not be empty.
expr_string += r'(?:[^/])+' + '/'
elif component == '**':
expr_string += r'(?:.*(?:\Z|/))?'
elif '**' in component:
expr_string += r"(?:[^/])+" + "/"
elif component == "**":
expr_string += r"(?:.*(?:\Z|/))?"
elif "**" in component:
raise ValueError("Invalid pattern: '**' can only be an entire path component")
else:
for part in GLOB_RE.split(component):
if part == '':
if part == "":
pass
elif part == '*':
expr_string += r'(?:[^/])*'
elif part == '?':
expr_string += r'(?:[^/])'
elif part[0] == '[':
elif part == "*":
expr_string += r"(?:[^/])*"
elif part == "?":
expr_string += r"(?:[^/])"
elif part[0] == "[":
expr_string += part
else:
expr_string += re.escape(part)
expr_string += '/'
expr_string += "/"

expr_string = expr_string.rstrip('/') + r'\Z'
expr_string = expr_string.rstrip("/") + r"\Z"
expr = re.compile(expr_string)

return lambda path: (expr.search(path) is not None)
return lambda path: expr.search(path) is not None
15 changes: 9 additions & 6 deletions sublime_lib/_util/guard.py
Original file line number Diff line number Diff line change
@@ -1,20 +1,23 @@
from __future__ import annotations

from functools import wraps
from typing import TYPE_CHECKING

if TYPE_CHECKING:
from typing import Callable, ContextManager, TypeVar
from typing_extensions import ParamSpec, Concatenate
_Self = TypeVar('_Self')
_T = TypeVar('_T')
_P = ParamSpec('_P')

from typing_extensions import Concatenate, ParamSpec

_Self = TypeVar("_Self")
_T = TypeVar("_T")
_P = ParamSpec("_P")


def define_guard(
guard_fn: Callable[[_Self], ContextManager[object] | None]
guard_fn: Callable[[_Self], ContextManager[object] | None],
) -> Callable[[Callable[Concatenate[_Self, _P], _T]], Callable[Concatenate[_Self, _P], _T]]:
def decorator(
wrapped: Callable[Concatenate[_Self, _P], _T]
wrapped: Callable[Concatenate[_Self, _P], _T],
) -> Callable[Concatenate[_Self, _P], _T]:
@wraps(wrapped)
def wrapper(self: _Self, /, *args: _P.args, **kwargs: _P.kwargs) -> _T:
Expand Down
2 changes: 1 addition & 1 deletion sublime_lib/_util/named_value.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from __future__ import annotations


class NamedValue():
class NamedValue:
def __init__(self, name: str):
self.name = name

Expand Down
7 changes: 4 additions & 3 deletions sublime_lib/_util/weak_method.py
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
from __future__ import annotations
from types import MethodType
from typing import TYPE_CHECKING

import weakref
from types import MethodType
from typing import TYPE_CHECKING

if TYPE_CHECKING:
from typing import Callable

from typing_extensions import ParamSpec, TypeVar

P = ParamSpec("P")
T = TypeVar("T")

__all__ = ['weak_method']
__all__ = ["weak_method"]


def weak_method(method: Callable[P, T]) -> Callable[P, T | None]:
Expand Down
18 changes: 9 additions & 9 deletions sublime_lib/activity_indicator.py
Original file line number Diff line number Diff line change
@@ -1,25 +1,25 @@
from __future__ import annotations

from abc import ABCMeta, abstractmethod
from enum import IntEnum
from threading import Lock
from types import TracebackType
from uuid import uuid4

import sublime
from typing_extensions import Self

from ._util.weak_method import weak_method

__all__ = ['ActivityIndicator']
__all__ = ["ActivityIndicator"]


class StatusTarget(metaclass=ABCMeta):
@abstractmethod
def set(self, message: str) -> None:
...
def set(self, message: str) -> None: ...

@abstractmethod
def clear(self) -> None:
...
def clear(self) -> None: ...


class WindowTarget(StatusTarget):
Expand Down Expand Up @@ -93,15 +93,15 @@ def __del__(self) -> None:
self.stop()
self._target.clear()

def __enter__(self) -> ActivityIndicator:
def __enter__(self) -> Self:
self.start()
return self

def __exit__(
self,
exc_type: type,
exc_value: Exception,
traceback: TracebackType
exc_type: type[BaseException] | None,
exc_value: BaseException | None,
traceback: TracebackType | None,
) -> None:
self.stop()

Expand Down
Loading
Loading