Skip to content

Commit 4ea8cf3

Browse files
authored
lint: allow ASYNC240 (#6703)
## 📝 Summary Some basic tidy with the new ruff rule
1 parent 54a81eb commit 4ea8cf3

File tree

13 files changed

+83
-25
lines changed

13 files changed

+83
-25
lines changed

marimo/_lint/linter.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
from marimo._lint.rule_engine import EarlyStoppingConfig, RuleEngine
1818
from marimo._loggers import capture_output
1919
from marimo._schemas.serialization import NotebookSerialization
20+
from marimo._utils import async_path
2021

2122
if TYPE_CHECKING:
2223
from collections.abc import AsyncIterator, Callable, Iterator
@@ -114,7 +115,7 @@ async def _process_single_file(self, file: Path) -> FileStatus:
114115
file_path = str(file)
115116
file_status = FileStatus(file=file_path)
116117
# Check if file exists first
117-
if not file.exists():
118+
if not await async_path.exists(file):
118119
self.errored = True
119120
file_status.failed = True
120121
file_status.message = f"File not found: {file_path}"

marimo/_server/export/exporter.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@
5353
)
5454
from marimo._server.tokens import SkewProtectionToken
5555
from marimo._types.ids import CellId_t
56+
from marimo._utils import async_path
5657
from marimo._utils.code import hash_code
5758
from marimo._utils.data_uri import build_data_url
5859
from marimo._utils.marimo_path import MarimoPath
@@ -529,10 +530,10 @@ async def _ensure_export_dir_async(self, directory: Path) -> None:
529530
if export_dir in self._created_dirs:
530531
return
531532

532-
if not directory.exists():
533+
if not await async_path.exists(directory):
533534
raise FileNotFoundError(f"Directory {directory} does not exist")
534535

535-
export_dir.mkdir(parents=True, exist_ok=True)
536+
await async_path.mkdir(export_dir, parents=True, exist_ok=True)
536537

537538
# Cache that we've created this directory
538539
self._created_dirs.add(export_dir)

marimo/_server/sessions.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@
7575
from marimo._server.types import ProcessLike
7676
from marimo._server.utils import print_, print_tabbed
7777
from marimo._types.ids import CellId_t, ConsumerId, SessionId
78+
from marimo._utils import async_path
7879
from marimo._utils.disposable import Disposable
7980
from marimo._utils.distributor import (
8081
ConnectionDistributor,
@@ -898,7 +899,7 @@ def _start_file_watcher_for_session(self, session: Session) -> None:
898899

899900
async def on_file_changed(path: Path) -> None:
900901
# Skip if the session does not relate to the file
901-
if session.app_file_manager.path != os.path.abspath(path):
902+
if session.app_file_manager.path != await async_path.abspath(path):
902903
return
903904

904905
# Use the centralized file change handler
@@ -1148,7 +1149,7 @@ async def handle_file_change(
11481149
This method reloads the notebook and sends appropriate operations
11491150
to the frontend when a marimo file is modified.
11501151
"""
1151-
abs_file_path = os.path.abspath(file_path)
1152+
abs_file_path = await async_path.abspath(file_path)
11521153

11531154
# Use a lock to prevent concurrent processing of the same file
11541155
if abs_file_path not in self._file_change_locks:

marimo/_utils/async_path.py

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,11 @@ async def expanduser(self) -> AsyncPath:
195195
result = await asyncio.to_thread(self._path.expanduser)
196196
return self.__class__(result)
197197

198+
async def absolute(self) -> AsyncPath:
199+
"""Return an absolute version of this path."""
200+
result = await asyncio.to_thread(self._path.absolute)
201+
return self.__class__(result)
202+
198203
# Context manager support for opening files
199204

200205
def open(
@@ -230,3 +235,42 @@ class AsyncWindowsPath(AsyncPath, PureWindowsPath):
230235

231236
def __getattr__(self, name: str) -> Any:
232237
return super().__getattr__(name) # type: ignore
238+
239+
240+
# Module-level convenience functions for compatibility with aio_path
241+
242+
243+
async def exists(path: StrPath) -> bool:
244+
"""Check if a path exists asynchronously."""
245+
return await AsyncPath(path).exists()
246+
247+
248+
async def isfile(path: StrPath) -> bool:
249+
"""Check if a path is a file asynchronously."""
250+
return await AsyncPath(path).is_file()
251+
252+
253+
async def isdir(path: StrPath) -> bool:
254+
"""Check if a path is a directory asynchronously."""
255+
return await AsyncPath(path).is_dir()
256+
257+
258+
async def abspath(path: StrPath) -> str:
259+
"""Return absolute path asynchronously."""
260+
result = await AsyncPath(path).absolute()
261+
return str(result)
262+
263+
264+
async def normpath(path: str) -> str:
265+
"""Normalize a pathname asynchronously."""
266+
return await asyncio.to_thread(os.path.normpath, path)
267+
268+
269+
async def mkdir(
270+
path: StrPath,
271+
mode: int = 0o777,
272+
parents: bool = False,
273+
exist_ok: bool = False,
274+
) -> None:
275+
"""Create a directory asynchronously."""
276+
await AsyncPath(path).mkdir(mode=mode, parents=parents, exist_ok=exist_ok)

marimo/_utils/file_watcher.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
from marimo import _loggers
1313
from marimo._dependencies.dependencies import DependencyManager
14+
from marimo._utils import async_path
1415

1516
LOGGER = _loggers.marimo_logger()
1617

@@ -79,7 +80,7 @@ def _get_modified(self) -> Optional[float]:
7980

8081
async def _poll(self) -> None:
8182
while self._running:
82-
if not os.path.exists(self.path):
83+
if not await async_path.exists(self.path):
8384
LOGGER.warning(f"File at {self.path} does not exist.")
8485
raise FileNotFoundError(f"File at {self.path} does not exist.")
8586

marimo/_utils/files.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77
from pathlib import Path
88
from typing import TYPE_CHECKING, Union
99

10+
from marimo._utils import async_path
11+
1012
if TYPE_CHECKING:
1113
from collections.abc import AsyncGenerator, Generator
1214

@@ -107,12 +109,12 @@ async def async_expand_file_patterns(
107109
seen = set()
108110

109111
for pattern in file_patterns:
110-
if os.path.isfile(pattern):
112+
if await async_path.isfile(pattern):
111113
path = Path(pattern)
112114
if path not in seen:
113115
seen.add(path)
114116
yield path
115-
elif os.path.isdir(pattern):
117+
elif await async_path.isdir(pattern):
116118
async for file_path in async_get_files(pattern):
117119
if file_path not in seen:
118120
seen.add(file_path)
@@ -124,7 +126,7 @@ async def async_expand_file_patterns(
124126
root = _get_root(pattern)
125127

126128
# Get all files from root and filter by pattern
127-
if os.path.isdir(root):
129+
if await async_path.isdir(root):
128130
async for file_path in async_get_files(root):
129131
if (
130132
fnmatch.fnmatch(str(file_path), pattern)

pixi.lock

Lines changed: 6 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pyproject.toml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -362,7 +362,6 @@ ignore = [
362362
"PERF203", # try-except within a loop incurs performance overhead; not always possible
363363
"PERF401", # Use {message_str} to create a transformed list; at the cost of readability
364364
"PERF403", # Use a dictionary comprehension instead of a for-loop; at the cost of readability
365-
"ASYNC240", # Async functions should not use os.path methods, use trio.Path or anyio.path
366365
# TODO: we should fix these, and enable this rule
367366
"PT011", # `pytest.raises(ValueError)` is too broad, set the `match` parameter or use a more specific exception
368367
"E501", # Line too long, we still trim

scripts/pycheck.sh

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,5 @@ echo "[check: format]"
1010
hatch run ruff format
1111
echo "[check: typecheck]"
1212
hatch run typecheck:check
13+
echo "[check: update-lock]"
14+
hatch run pixi lock

tests/_cli/test_cli_export.py

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
import pytest
1616

1717
from marimo._dependencies.dependencies import DependencyManager
18+
from marimo._utils import async_path
1819
from marimo._utils.platform import is_windows
1920
from tests._server.templates.utils import normalize_index_html
2021
from tests.mocks import snapshotter
@@ -323,7 +324,7 @@ async def test_export_watch(self, temp_marimo_file: str) -> None:
323324
assert f"Watching {temp_marimo_file}" in line
324325
break
325326

326-
assert not path.exists(temp_out_file)
327+
assert not await async_path.exists(temp_out_file)
327328

328329
# Modify file
329330
with open(temp_marimo_file, "a") as f: # noqa: ASYNC230
@@ -653,7 +654,7 @@ async def test_export_watch_script(self, temp_marimo_file: str) -> None:
653654
assert f"Watching {temp_marimo_file}" in line
654655
break
655656

656-
assert not path.exists(temp_out_file)
657+
assert not await async_path.exists(temp_out_file)
657658

658659
# Modify file
659660
with open(temp_marimo_file, "a") as f: # noqa: ASYNC230
@@ -668,7 +669,7 @@ async def test_export_watch_script(self, temp_marimo_file: str) -> None:
668669
break
669670

670671
await asyncio.sleep(0.1)
671-
assert path.exists(temp_out_file)
672+
assert await async_path.exists(temp_out_file)
672673

673674
@pytest.mark.skipif(
674675
condition=DependencyManager.watchdog.has(),
@@ -771,7 +772,7 @@ async def test_export_watch_markdown(self, temp_marimo_file: str) -> None:
771772
assert f"Watching {temp_marimo_file}" in line
772773
break
773774

774-
assert not path.exists(temp_out_file)
775+
assert not await async_path.exists(temp_out_file)
775776

776777
# Modify file
777778
with open(temp_marimo_file, "a") as f: # noqa: ASYNC230
@@ -786,7 +787,7 @@ async def test_export_watch_markdown(self, temp_marimo_file: str) -> None:
786787
break
787788

788789
await asyncio.sleep(0.1)
789-
assert path.exists(temp_out_file)
790+
assert await async_path.exists(temp_out_file)
790791

791792
@pytest.mark.skipif(
792793
condition=DependencyManager.watchdog.has(),

0 commit comments

Comments
 (0)