Skip to content

Make universal-pathlib 0.2.2 an official dependency. #566

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

Merged
merged 3 commits into from
Mar 8, 2024
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
1 change: 1 addition & 0 deletions docs/source/changes.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
7 changes: 1 addition & 6 deletions docs/source/how_to_guides/remote_files.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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]
Expand All @@ -53,7 +54,6 @@ name = "Tobias Raabe"
email = "[email protected]"

[project.optional-dependencies]
all = ['universal-pathlib; python_version<"3.12"']
docs = [
"furo",
"ipython",
Expand Down
8 changes: 1 addition & 7 deletions src/_pytask/collect.py
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
35 changes: 19 additions & 16 deletions src/_pytask/nodes.py
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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:
Expand All @@ -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
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion tox.ini
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ passenv = CI
package = editable

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