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
2 changes: 1 addition & 1 deletion .vscode/extensions.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"recommendations": [
"ms-python.python",
"ms-python.vscode-pylance",
"astral-sh.ty",
"charliermarsh.ruff",
"esbenp.prettier-vscode",
Comment on lines 2 to 6
Copy link

Copilot AI Apr 25, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PR description says to keep Pylance for editor inlay hints, but this change removes the ms-python.vscode-pylance recommendation entirely. Either re-add the Pylance extension here, or update the PR description to match the intended editor setup (and ensure inlay hints are still enabled somewhere if that’s desired).

Copilot uses AI. Check for mistakes.
"EditorConfig.EditorConfig",
Expand Down
3 changes: 0 additions & 3 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
{
"python.defaultInterpreterPath": "${workspaceFolder}/.venv/bin/python",
"python.analysis.typeCheckingMode": "strict",
"python.analysis.inlayHints.functionReturnTypes": true,
"python.analysis.inlayHints.variableTypes": true,
"[python]": {
"editor.defaultFormatter": "charliermarsh.ruff"
}
Comment on lines 1 to 5
Copy link

Copilot AI Apr 25, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PR description mentions keeping Pylance for inlay hints, but these settings removed the explicit inlay-hint options (and strict typeCheckingMode). If inlay hints are still intended as part of the recommended setup, consider keeping the inlay-hint settings (or documenting the new defaults) so contributors get consistent editor behavior.

Copilot uses AI. Check for mistakes.
Expand Down
2 changes: 1 addition & 1 deletion justfile
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ fmt:
uv run ruff format .

lint:
uv run pyright src/watchfs tests
uv run ty check --error-on-warning src/watchfs tests
uv run ruff check .

fmt-docs:
Expand Down
9 changes: 1 addition & 8 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -35,18 +35,13 @@ watchfs = "watchfs.__main__:main"

[dependency-groups]
dev = [
"pyright>=1.1.406",
"ty>=0.0.32",
"ruff>=0.14.0",
"pytest>=8.4.2",
"pytest-rerunfailures>=16.0.1",
"tomli>=2.2.1",
]

[tool.pyright]
include = ["src/watchfs", "tests"]
pythonVersion = "3.12"
typeCheckingMode = "strict"

[tool.ruff]
line-length = 120
target-version = "py312"
Expand Down Expand Up @@ -91,8 +86,6 @@ select = [
]
ignore = [
"E501", # line too long, duplicate with ruff fmt
"F401", # imported but unused, duplicate with pyright
"F841", # local variable is assigned to but never used, duplicate with pyright
]

[tool.ruff.lint.isort]
Expand Down
2 changes: 1 addition & 1 deletion src/watchfs/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
from typing import TYPE_CHECKING

from colored import Back, Fore
from watchfiles import Change, awatch # type: ignore
from watchfiles import Change, awatch

from watchfs import __version__
from watchfs.as_sync import as_sync
Expand Down
10 changes: 6 additions & 4 deletions src/watchfs/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,12 @@ class ParseError(WatchFsBaseException):
code = ErrorCode.PARSE_ERROR


def handleUncaughtException(exctype: type[Exception], exception: Exception, trace: TracebackType):
oldHook(exctype, exception, trace)
def handle_uncaught_exception(
exctype: type[BaseException], exception: BaseException, trace: TracebackType | None
) -> None:
old_hook(exctype, exception, trace)
if isinstance(exception, WatchFsBaseException):
sys.exit(exception.code.value)
raise SystemExit(exception.code.value)


sys.excepthook, oldHook = handleUncaughtException, sys.excepthook
old_hook, sys.excepthook = sys.excepthook, handle_uncaught_exception
2 changes: 2 additions & 0 deletions src/watchfs/mappings.py
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,8 @@ def parse_sync_mapping(sync_mapping: str) -> Result[tuple[SyncMapping, bool], Pa

return Ok((SyncMapping(source=src_spec.path, target=dst_spec), bidirectional))

raise AssertionError("unreachable")


def _parse_ssh_url(spec: str) -> Result[SshTargetSpec, ParseError]:
parsed = urlparse(spec)
Expand Down
15 changes: 11 additions & 4 deletions src/watchfs/targets.py
Original file line number Diff line number Diff line change
Expand Up @@ -127,12 +127,19 @@ async def _run_command(
*,
stdin: IO[bytes] | int | None = None,
) -> subprocess.CompletedProcess[bytes]:
return await asyncio.to_thread(
subprocess.run,
return await asyncio.to_thread(_run_command_sync, command, stdin=stdin)


def _run_command_sync(
command: list[str],
*,
stdin: IO[bytes] | int | None = None,
) -> subprocess.CompletedProcess[bytes]:
return subprocess.run(
command,
stdin=stdin if stdin is not None else subprocess.DEVNULL,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
capture_output=True,
text=False,
)


Expand Down
50 changes: 26 additions & 24 deletions uv.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.