Skip to content

Commit df04fbe

Browse files
committed
Merge branch 'main' into pre-commit-ci-update-config
2 parents 474e284 + da7fa3f commit df04fbe

File tree

7 files changed

+24
-32
lines changed

7 files changed

+24
-32
lines changed

docs/source/changes.md

+1
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ releases are available on [PyPI](https://pypi.org/project/pytask) and
1717
relative to the config file.
1818
- {pull}`555` uses new-style hook wrappers and requires pluggy 1.3 for typing.
1919
- {pull}`557` fixes an issue with `@task(after=...)` in notebooks and terminals.
20+
- {pull}`566` makes universal-pathlib an official dependency.
2021

2122
## 0.4.5 - 2024-01-09
2223

docs/source/how_to_guides/remote_files.md

+1-6
Original file line numberDiff line numberDiff line change
@@ -7,16 +7,11 @@ lots of use cases to deal with remote files.
77
get started. So, some tasks reference remote files instead of local files.
88
- You store the workflow results in remote storage to save and distribute them.
99

10-
pytask uses [universal_pathlib](https://github.com/fsspec/universal_pathlib) to work
10+
pytask uses [universal-pathlib](https://github.com/fsspec/universal_pathlib) to work
1111
with remote files. The package provides a {mod}`pathlib`-like interface, making it very
1212
easy to interact with files from an HTTP(S)-, Dropbox-, S3-, GCP-, Azure-based
1313
filesystem, and many more.
1414

15-
```{warning}
16-
universal_pathlib does currently not support Python 3.12. To track progress, check the
17-
[releases `>0.1.4`](https://github.com/fsspec/universal_pathlib/releases).
18-
```
19-
2015
## HTTP(S)-based filesystem
2116

2217
As an example for dealing with an HTTP(S)-based filesystem, we will download the iris

pyproject.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ dependencies = [
3939
"sqlalchemy>=2",
4040
'tomli>=1; python_version < "3.11"',
4141
'typing-extensions; python_version < "3.9"',
42+
"universal-pathlib>=0.2.2",
4243
]
4344

4445
[project.readme]
@@ -53,7 +54,6 @@ name = "Tobias Raabe"
5354
5455

5556
[project.optional-dependencies]
56-
all = ['universal-pathlib; python_version<"3.12"']
5757
docs = [
5858
"furo",
5959
"ipython",

src/_pytask/collect.py

+1-7
Original file line numberDiff line numberDiff line change
@@ -44,13 +44,7 @@
4444
from _pytask.task_utils import task as task_decorator
4545
from _pytask.typing import is_task_function
4646
from rich.text import Text
47-
48-
try:
49-
from upath import UPath
50-
except ImportError: # pragma: no cover
51-
52-
class UPath: # type: ignore[no-redef]
53-
...
47+
from upath import UPath
5448

5549

5650
if TYPE_CHECKING:

src/_pytask/nodes.py

+19-16
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
from _pytask.typing import NoDefault
2121
from attrs import define
2222
from attrs import field
23+
from upath._stat import UPathStatResult
2324

2425

2526
if TYPE_CHECKING:
@@ -179,14 +180,7 @@ def state(self) -> str | None:
179180
180181
"""
181182
if self.path.exists():
182-
stat = self.path.stat()
183-
if isinstance(stat, stat_result):
184-
modification_time = self.path.stat().st_mtime
185-
return hash_path(self.path, modification_time)
186-
if isinstance(stat, dict):
187-
return stat.get("ETag", "0")
188-
msg = "Unknown stat object."
189-
raise NotImplementedError(msg)
183+
return _get_state(self.path)
190184
return None
191185

192186
def load(self, is_product: bool = False) -> Path: # noqa: ARG002
@@ -322,14 +316,7 @@ def from_path(cls, path: Path) -> PickleNode:
322316

323317
def state(self) -> str | None:
324318
if self.path.exists():
325-
stat = self.path.stat()
326-
if isinstance(stat, stat_result):
327-
modification_time = self.path.stat().st_mtime
328-
return hash_path(self.path, modification_time)
329-
if isinstance(stat, dict):
330-
return stat.get("ETag", "0")
331-
msg = "Unknown stat object."
332-
raise NotImplementedError(msg)
319+
return _get_state(self.path)
333320
return None
334321

335322
def load(self, is_product: bool = False) -> Any:
@@ -341,3 +328,19 @@ def load(self, is_product: bool = False) -> Any:
341328
def save(self, value: Any) -> None:
342329
with self.path.open("wb") as f:
343330
pickle.dump(value, f)
331+
332+
333+
def _get_state(path: Path) -> str:
334+
"""Get state of a path.
335+
336+
A simple function to handle local and remote files.
337+
338+
"""
339+
stat = path.stat()
340+
if isinstance(stat, stat_result):
341+
modification_time = path.stat().st_mtime
342+
return hash_path(path, modification_time)
343+
if isinstance(stat, UPathStatResult):
344+
return stat.as_info().get("ETag", "0")
345+
msg = "Unknown stat object."
346+
raise NotImplementedError(msg)

tests/test_execute.py

-1
Original file line numberDiff line numberDiff line change
@@ -918,7 +918,6 @@ def func(path): path.touch()
918918
assert tmp_path.joinpath("out.txt").exists()
919919

920920

921-
@pytest.mark.skipif(sys.version_info >= (3, 12), reason="Not supported in Python 3.12.")
922921
def test_with_http_path(runner, tmp_path):
923922
source = """
924923
from upath import UPath

tox.ini

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ passenv = CI
77
package = editable
88

99
[testenv:test]
10-
extras = all, test
10+
extras = test
1111
deps =
1212
pygraphviz;platform_system != "Windows"
1313
commands =

0 commit comments

Comments
 (0)