Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make universal-pathlib 0.2.2 an official dependency. #566

Merged
merged 3 commits into from
Mar 8, 2024
Merged
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
1 change: 1 addition & 0 deletions docs/source/changes.md
Original file line number Diff line number Diff line change
@@ -17,6 +17,7 @@ releases are available on [PyPI](https://pypi.org/project/pytask) and
relative to the config file.
- {pull}`555` uses new-style hook wrappers and requires pluggy 1.3 for typing.
- {pull}`557` fixes an issue with `@task(after=...)` in notebooks and terminals.
- {pull}`566` makes universal-pathlib an official dependency.

## 0.4.5 - 2024-01-09

7 changes: 1 addition & 6 deletions docs/source/how_to_guides/remote_files.md
Original file line number Diff line number Diff line change
@@ -7,16 +7,11 @@ lots of use cases to deal with remote files.
get started. So, some tasks reference remote files instead of local files.
- You store the workflow results in remote storage to save and distribute them.

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

```{warning}
universal_pathlib does currently not support Python 3.12. To track progress, check the
[releases `>0.1.4`](https://github.com/fsspec/universal_pathlib/releases).
```

## HTTP(S)-based filesystem

As an example for dealing with an HTTP(S)-based filesystem, we will download the iris
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -39,6 +39,7 @@ dependencies = [
"sqlalchemy>=2",
'tomli>=1; python_version < "3.11"',
'typing-extensions; python_version < "3.9"',
"universal-pathlib>=0.2.2",
]

[project.readme]
@@ -53,7 +54,6 @@ name = "Tobias Raabe"
email = "raabe@posteo.de"

[project.optional-dependencies]
all = ['universal-pathlib; python_version<"3.12"']
docs = [
"furo",
"ipython",
8 changes: 1 addition & 7 deletions src/_pytask/collect.py
Original file line number Diff line number Diff line change
@@ -44,13 +44,7 @@
from _pytask.task_utils import task as task_decorator
from _pytask.typing import is_task_function
from rich.text import Text

try:
from upath import UPath
except ImportError: # pragma: no cover

class UPath: # type: ignore[no-redef]
...
from upath import UPath


if TYPE_CHECKING:
35 changes: 19 additions & 16 deletions src/_pytask/nodes.py
Original file line number Diff line number Diff line change
@@ -20,6 +20,7 @@
from _pytask.typing import NoDefault
from attrs import define
from attrs import field
from upath._stat import UPathStatResult


if TYPE_CHECKING:
@@ -179,14 +180,7 @@ def state(self) -> str | None:

"""
if self.path.exists():
stat = self.path.stat()
if isinstance(stat, stat_result):
modification_time = self.path.stat().st_mtime
return hash_path(self.path, modification_time)
if isinstance(stat, dict):
return stat.get("ETag", "0")
msg = "Unknown stat object."
raise NotImplementedError(msg)
return _get_state(self.path)
return None

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

def state(self) -> str | None:
if self.path.exists():
stat = self.path.stat()
if isinstance(stat, stat_result):
modification_time = self.path.stat().st_mtime
return hash_path(self.path, modification_time)
if isinstance(stat, dict):
return stat.get("ETag", "0")
msg = "Unknown stat object."
raise NotImplementedError(msg)
return _get_state(self.path)
return None

def load(self, is_product: bool = False) -> Any:
@@ -341,3 +328,19 @@ def load(self, is_product: bool = False) -> Any:
def save(self, value: Any) -> None:
with self.path.open("wb") as f:
pickle.dump(value, f)


def _get_state(path: Path) -> str:
"""Get state of a path.

A simple function to handle local and remote files.

"""
stat = path.stat()
if isinstance(stat, stat_result):
modification_time = path.stat().st_mtime
return hash_path(path, modification_time)
if isinstance(stat, UPathStatResult):
return stat.as_info().get("ETag", "0")
msg = "Unknown stat object."
raise NotImplementedError(msg)
1 change: 0 additions & 1 deletion tests/test_execute.py
Original file line number Diff line number Diff line change
@@ -918,7 +918,6 @@ def func(path): path.touch()
assert tmp_path.joinpath("out.txt").exists()


@pytest.mark.skipif(sys.version_info >= (3, 12), reason="Not supported in Python 3.12.")
def test_with_http_path(runner, tmp_path):
source = """
from upath import UPath
2 changes: 1 addition & 1 deletion tox.ini
Original file line number Diff line number Diff line change
@@ -7,7 +7,7 @@ passenv = CI
package = editable

[testenv:test]
extras = all, test
extras = test
deps =
pygraphviz;platform_system != "Windows"
commands =