superpathlib 2.0.9__tar.gz → 2.0.10__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (30) hide show
  1. {superpathlib-2.0.9/src/superpathlib.egg-info → superpathlib-2.0.10}/PKG-INFO +5 -4
  2. {superpathlib-2.0.9 → superpathlib-2.0.10}/pyproject.toml +3 -5
  3. {superpathlib-2.0.9 → superpathlib-2.0.10}/src/superpathlib/cached_content.py +1 -1
  4. {superpathlib-2.0.9 → superpathlib-2.0.10}/src/superpathlib/common_folders.py +15 -12
  5. {superpathlib-2.0.9 → superpathlib-2.0.10}/src/superpathlib/content_properties.py +2 -2
  6. {superpathlib-2.0.9 → superpathlib-2.0.10}/src/superpathlib/encryption.py +1 -0
  7. {superpathlib-2.0.9 → superpathlib-2.0.10}/src/superpathlib/extra_functionality.py +35 -34
  8. {superpathlib-2.0.9 → superpathlib-2.0.10}/src/superpathlib/metadata_properties.py +1 -9
  9. {superpathlib-2.0.9 → superpathlib-2.0.10}/src/superpathlib/override.py +7 -5
  10. {superpathlib-2.0.9 → superpathlib-2.0.10}/src/superpathlib/utils.py +2 -2
  11. {superpathlib-2.0.9 → superpathlib-2.0.10/src/superpathlib.egg-info}/PKG-INFO +5 -4
  12. {superpathlib-2.0.9 → superpathlib-2.0.10}/src/superpathlib.egg-info/requires.txt +1 -1
  13. {superpathlib-2.0.9 → superpathlib-2.0.10}/tests/test_cached_content.py +2 -2
  14. {superpathlib-2.0.9 → superpathlib-2.0.10}/tests/test_functionality.py +4 -0
  15. {superpathlib-2.0.9 → superpathlib-2.0.10}/tests/test_metadata.py +2 -2
  16. {superpathlib-2.0.9 → superpathlib-2.0.10}/LICENSE +0 -0
  17. {superpathlib-2.0.9 → superpathlib-2.0.10}/README.md +0 -0
  18. {superpathlib-2.0.9 → superpathlib-2.0.10}/setup.cfg +0 -0
  19. {superpathlib-2.0.9 → superpathlib-2.0.10}/src/superpathlib/__init__.py +0 -0
  20. {superpathlib-2.0.9 → superpathlib-2.0.10}/src/superpathlib/base.py +0 -0
  21. {superpathlib-2.0.9 → superpathlib-2.0.10}/src/superpathlib/path.py +0 -0
  22. {superpathlib-2.0.9 → superpathlib-2.0.10}/src/superpathlib/py.typed +0 -0
  23. {superpathlib-2.0.9 → superpathlib-2.0.10}/src/superpathlib/tags.py +0 -0
  24. {superpathlib-2.0.9 → superpathlib-2.0.10}/src/superpathlib.egg-info/SOURCES.txt +0 -0
  25. {superpathlib-2.0.9 → superpathlib-2.0.10}/src/superpathlib.egg-info/dependency_links.txt +0 -0
  26. {superpathlib-2.0.9 → superpathlib-2.0.10}/src/superpathlib.egg-info/top_level.txt +0 -0
  27. {superpathlib-2.0.9 → superpathlib-2.0.10}/tests/test_common_folders.py +0 -0
  28. {superpathlib-2.0.9 → superpathlib-2.0.10}/tests/test_content.py +0 -0
  29. {superpathlib-2.0.9 → superpathlib-2.0.10}/tests/test_encrypted_content.py +0 -0
  30. {superpathlib-2.0.9 → superpathlib-2.0.10}/tests/test_inheritance.py +0 -0
@@ -1,9 +1,9 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.4
2
2
  Name: superpathlib
3
- Version: 2.0.9
3
+ Version: 2.0.10
4
4
  Summary: Extended Pathlib
5
5
  Author-email: Quinten Roets <qdr2104@columbia.edu>
6
- License: MIT
6
+ License-Expression: MIT
7
7
  Project-URL: Source Code, https://github.com/quintenroets/superpathlib
8
8
  Requires-Python: >=3.10
9
9
  Description-Content-Type: text/markdown
@@ -17,13 +17,14 @@ Requires-Dist: PyYaml<7,>=6.0.1; extra == "full"
17
17
  Requires-Dist: xattr<2,>=0.10.1; extra == "full"
18
18
  Provides-Extra: dev
19
19
  Requires-Dist: hypothesis<7,>=6.97.1; extra == "dev"
20
- Requires-Dist: package-dev-tools<1,>=0.5.12; extra == "dev"
20
+ Requires-Dist: package-dev-tools<1,>=0.7.1; extra == "dev"
21
21
  Requires-Dist: types-PyYaml<7,>=6.0.12.12; extra == "dev"
22
22
  Requires-Dist: dirhash<1,>=0.2.1; extra == "dev"
23
23
  Requires-Dist: numpy<3,>=1.26.4; extra == "dev"
24
24
  Requires-Dist: package-utils<1,>=0.6.1; extra == "dev"
25
25
  Requires-Dist: PyYaml<7,>=6.0.1; extra == "dev"
26
26
  Requires-Dist: xattr<2,>=0.10.1; extra == "dev"
27
+ Dynamic: license-file
27
28
 
28
29
  # Superpathlib
29
30
  [![PyPI version](https://badge.fury.io/py/superpathlib.svg)](https://badge.fury.io/py/superpathlib)
@@ -1,9 +1,9 @@
1
1
  [project]
2
2
  name = "superpathlib"
3
- version = "2.0.9"
3
+ version = "2.0.10"
4
4
  description = "Extended Pathlib"
5
5
  authors = [{name = "Quinten Roets", email = "qdr2104@columbia.edu"}]
6
- license = {text = "MIT"}
6
+ license = "MIT"
7
7
  readme = "README.md"
8
8
  requires-python = ">=3.10"
9
9
  dependencies = [
@@ -20,7 +20,7 @@ full = [
20
20
  ]
21
21
  dev = [
22
22
  "hypothesis >=6.97.1, <7",
23
- "package-dev-tools >=0.5.12, <1",
23
+ "package-dev-tools >=0.7.1, <1",
24
24
 
25
25
  # types
26
26
  "types-PyYaml >=6.0.12.12, <7",
@@ -69,8 +69,6 @@ fix = true
69
69
  [tool.ruff.lint]
70
70
  select = ["ALL"]
71
71
  ignore = [
72
- "ANN101", # annotate self
73
- "ANN102", # annotate cls
74
72
  "ANN401", # annotated with Any
75
73
  "D", # docstrings
76
74
  "G004", # logging f-string
@@ -14,7 +14,7 @@ T = TypeVar("T")
14
14
 
15
15
  class Path(metadata_properties.Path):
16
16
  """
17
- Properties to for cached file content.
17
+ Properties for cached file content.
18
18
  """
19
19
 
20
20
  @cached_property
@@ -4,6 +4,7 @@ import typing
4
4
  from typing import Any, TypeVar
5
5
 
6
6
  from simple_classproperty import classproperty
7
+ from typing_extensions import Self
7
8
 
8
9
  from . import base
9
10
 
@@ -27,7 +28,9 @@ class PropertyMeta(abc.ABCMeta):
27
28
  ) -> "PropertyMeta":
28
29
  meta_class = super().__new__(cls, name, bases, attributes)
29
30
  if sys.version_info >= (3, 13):
30
- enable_classproperties(meta_class) # pragma: nocover
31
+ enable_classproperties(
32
+ meta_class, # type: ignore[arg-type]
33
+ ) # pragma: nocover
31
34
  return meta_class
32
35
 
33
36
 
@@ -42,37 +45,37 @@ class Path(base.Path, metaclass=PropertyMeta):
42
45
 
43
46
  @classmethod
44
47
  @classproperty
45
- def HOME(cls: type[T]) -> T: # noqa: N802
48
+ def HOME(cls) -> Self: # noqa: N802
46
49
  return cls.home()
47
50
 
48
51
  @classmethod
49
52
  @classproperty
50
- def docs(cls: type[T]) -> T:
53
+ def docs(cls) -> Self:
51
54
  path = cls.HOME / "Documents"
52
- return typing.cast(T, path)
55
+ return typing.cast("Self", path)
53
56
 
54
57
  @classmethod
55
58
  @classproperty
56
- def scripts(cls: type[T]) -> T:
59
+ def scripts(cls) -> Self:
57
60
  path = cls.docs / "Scripts"
58
- return typing.cast(T, path)
61
+ return typing.cast("Self", path)
59
62
 
60
63
  @classmethod
61
64
  @classproperty
62
- def script_assets(cls: type[T]) -> T:
65
+ def script_assets(cls) -> Self:
63
66
  path = cls.scripts / "assets"
64
- return typing.cast(T, path)
67
+ return typing.cast("Self", path)
65
68
 
66
69
  @classmethod
67
70
  @classproperty
68
- def assets(cls: type[T]) -> T:
71
+ def assets(cls) -> Self:
69
72
  """
70
73
  Often overwritten by child classes for specific project.
71
74
  """
72
- return typing.cast(T, cls.script_assets)
75
+ return typing.cast("Self", cls.script_assets)
73
76
 
74
77
  @classmethod
75
78
  @classproperty
76
- def draft(cls: type[T]) -> T:
79
+ def draft(cls) -> Self:
77
80
  path = cls.docs / "draft.txt"
78
- return typing.cast(T, path)
81
+ return typing.cast("Self", path)
@@ -53,12 +53,12 @@ class Path(base.Path):
53
53
  @content_lines.setter
54
54
  def content_lines(self, lines: Iterable[Any]) -> None:
55
55
  lines = (line for line in lines if line)
56
- self.lines = typing.cast(list[str], lines)
56
+ self.lines = typing.cast("list[str]", lines)
57
57
 
58
58
  @property
59
59
  def json(self) -> dict[str, Any] | list[Any]:
60
60
  value = json.loads(self.text or "{}")
61
- return typing.cast(dict[str, Any] | list[Any], value)
61
+ return typing.cast("dict[str, Any] | list[Any]", value)
62
62
 
63
63
  @json.setter
64
64
  def json(self, content: dict[Any, Any] | list[Any]) -> None:
@@ -62,6 +62,7 @@ class EncryptedPath(Path):
62
62
  self,
63
63
  encoding: str | None = None, # noqa: ARG002
64
64
  errors: str | None = None, # noqa: ARG002
65
+ newline: str | None = None, # noqa: ARG002
65
66
  ) -> str:
66
67
  return self.read_bytes().decode()
67
68
 
@@ -5,43 +5,44 @@ import tempfile
5
5
  import time
6
6
  import typing
7
7
  import urllib.parse
8
+ from collections import deque
8
9
  from collections.abc import Callable, Iterator
9
10
  from functools import cached_property
10
11
  from types import TracebackType
11
- from typing import Any, TypeVar, cast
12
+ from typing import Any, cast
13
+
14
+ from typing_extensions import Self
12
15
 
13
16
  from . import cached_content
14
17
  from .utils import find_first_match
15
18
 
16
- PathType = TypeVar("PathType", bound="Path")
17
-
18
19
 
19
20
  class Path(cached_content.Path):
20
21
  """
21
22
  Additional functionality.
22
23
  """
23
24
 
24
- def create_parent(self: PathType) -> PathType:
25
+ def create_parent(self) -> Self:
25
26
  self.parent.mkdir(parents=True, exist_ok=True)
26
27
  return self.parent
27
28
 
28
- def with_nonexistent_name(self: PathType) -> PathType:
29
+ def with_nonexistent_name(self) -> Self:
29
30
  path = self
30
31
  if path.exists():
31
32
  stem = path.stem
32
33
 
33
- def with_number(i: int) -> PathType:
34
+ def with_number(i: int) -> "Path":
34
35
  return path.with_stem(f"{stem} ({i})")
35
36
 
36
37
  def nonexistent(i: int) -> bool:
37
38
  return not with_number(i).exists()
38
39
 
39
40
  first_free_number = find_first_match(nonexistent)
40
- path = with_number(first_free_number)
41
+ path = cast("Self", with_number(first_free_number))
41
42
 
42
43
  return path
43
44
 
44
- def with_timestamp(self: PathType) -> PathType:
45
+ def with_timestamp(self) -> Self:
45
46
  from datetime import datetime, timezone
46
47
 
47
48
  timestamp = int(time.time()) # precision up to second
@@ -50,7 +51,7 @@ class Path(cached_content.Path):
50
51
 
51
52
  def copy_to(
52
53
  self,
53
- dest: PathType,
54
+ dest: Self,
54
55
  *,
55
56
  include_properties: bool = True,
56
57
  only_if_newer: bool = False,
@@ -60,7 +61,7 @@ class Path(cached_content.Path):
60
61
  if include_properties:
61
62
  self.copy_properties_to(dest)
62
63
 
63
- def copy_properties_to(self, dest: PathType) -> None:
64
+ def copy_properties_to(self, dest: Self) -> None:
64
65
  for path in dest.find():
65
66
  path.tag = self.tag
66
67
  path.mtime = self.mtime
@@ -70,20 +71,20 @@ class Path(cached_content.Path):
70
71
  # noinspection PyProtectedMember
71
72
  path_str = str(self)
72
73
  format_ = shutil._find_unpack_format(path_str) # type: ignore[attr-defined] # noqa: SLF001
73
- return typing.cast(str, format_)
74
+ return typing.cast("str", format_)
74
75
 
75
76
  def unpack_if_archive(
76
77
  self,
77
78
  *,
78
- extraction_directory: PathType | None = None,
79
+ extraction_directory: Self | None = None,
79
80
  recursive: bool = True,
80
81
  ) -> None:
81
82
  if self.archive_format is not None:
82
83
  self.unpack(extraction_directory, recursive=recursive)
83
84
 
84
85
  def unpack( # noqa: PLR0913
85
- self: PathType,
86
- extraction_directory: PathType | None = None,
86
+ self,
87
+ extraction_directory: Self | None = None,
87
88
  *,
88
89
  remove_existing: bool = True,
89
90
  preserve_properties: bool = True,
@@ -91,7 +92,7 @@ class Path(cached_content.Path):
91
92
  archive_format: str | None = None,
92
93
  recursive: bool = True,
93
94
  ) -> None:
94
- def cleanup(cleanup_path: PathType) -> None:
95
+ def cleanup(cleanup_path: Self) -> None:
95
96
  (cleanup_path / "__MACOSX").rmtree(missing_ok=True)
96
97
  subfolder = cleanup_path / cleanup_path.name
97
98
  if subfolder.exists() and cleanup_path.number_of_children == 1:
@@ -129,7 +130,7 @@ class Path(cached_content.Path):
129
130
  for path in extraction_directory.find():
130
131
  path.unpack_if_archive()
131
132
 
132
- def create_extraction_directory(self: PathType, archive_format: str) -> PathType:
133
+ def create_extraction_directory(self, archive_format: str) -> Self:
133
134
  extract_name = self.name
134
135
  # noinspection PyProtectedMember
135
136
  unpack_formats = shutil._UNPACK_FORMATS # type: ignore[attr-defined] # noqa: SLF001
@@ -180,7 +181,7 @@ class Path(cached_content.Path):
180
181
  def update(self, value: dict[Any, Any]) -> dict[Any, Any]:
181
182
  # only read and write if value to add not empty
182
183
  if value:
183
- current_content = cast(dict[Any, Any], self.yaml)
184
+ current_content = cast("dict[Any, Any]", self.yaml)
184
185
  updated_content = current_content | value
185
186
  self.yaml = updated_content
186
187
  else:
@@ -188,20 +189,20 @@ class Path(cached_content.Path):
188
189
  return updated_content
189
190
 
190
191
  def find(
191
- self: PathType,
192
- condition: Callable[[PathType], bool] | None = None,
193
- exclude: Callable[[PathType], bool] = lambda _: False,
192
+ self,
193
+ condition: Callable[[Self], bool] | None = None,
194
+ exclude: Callable[[Self], bool] = lambda _: False,
194
195
  *,
195
196
  recurse_on_match: bool = False,
196
197
  follow_symlinks: bool = False,
197
198
  only_folders: bool = False,
198
- ) -> Iterator[PathType]:
199
+ ) -> Iterator[Self]:
199
200
  """Find all subpaths under path that match condition.
200
201
 
201
202
  only_folders option can be used for efficiency reasons
202
203
  """
203
204
 
204
- def extract_children_to_recurse_on(path: PathType) -> Iterator[PathType]:
205
+ def extract_children_to_recurse_on(path: Self) -> Iterator[Self]:
205
206
  # skip folders that do not allow listing
206
207
  with contextlib.suppress(PermissionError):
207
208
  for child in path.iterdir():
@@ -213,12 +214,12 @@ class Path(cached_content.Path):
213
214
  if condition is None:
214
215
  recurse_on_match = True
215
216
 
216
- def condition(_: PathType) -> bool:
217
+ def condition(_: Self) -> bool:
217
218
  return True
218
219
 
219
- to_traverse = [self] if self.exists() else []
220
+ to_traverse = deque([self] if self.exists() else [])
220
221
  while to_traverse:
221
- path = to_traverse.pop(0)
222
+ path = to_traverse.popleft()
222
223
  if not exclude(path):
223
224
  match = condition(path)
224
225
  if match:
@@ -226,7 +227,7 @@ class Path(cached_content.Path):
226
227
  should_recurse = recurse_on_match or not match
227
228
  should_recurse_folder = only_folders or path.is_dir()
228
229
  if should_recurse and should_recurse_folder:
229
- to_traverse += list(extract_children_to_recurse_on(path))
230
+ to_traverse.extend(extract_children_to_recurse_on(path))
230
231
 
231
232
  def rmtree(
232
233
  self,
@@ -248,18 +249,18 @@ class Path(cached_content.Path):
248
249
  @classmethod
249
250
  def _on_error(
250
251
  cls,
251
- _: bool, # noqa: FBT001
252
+ func: Callable[[str], Any],
252
253
  path_str: str,
253
254
  exc_info: tuple[type[Exception], Exception, TracebackType],
254
255
  ) -> None:
255
256
  if exc_info[0] is PermissionError and os.name == "nt": # pragma: nocover
256
257
  path = Path(path_str)
257
258
  path.chmod(0o777)
258
- path.unlink()
259
+ func(path_str)
259
260
  else:
260
261
  raise exc_info[0]
261
262
 
262
- def subpath(self: PathType, *parts: str) -> PathType:
263
+ def subpath(self, *parts: str) -> Self:
263
264
  path = self
264
265
  tokens_to_replace = os.sep, "."
265
266
  for part in parts:
@@ -269,18 +270,18 @@ class Path(cached_content.Path):
269
270
  return path
270
271
 
271
272
  @classmethod
272
- def from_uri(cls: type[PathType], uri: str) -> PathType:
273
+ def from_uri(cls, uri: str) -> Self:
273
274
  path_str = urllib.parse.urlparse(uri).path
274
275
  return cls(path_str)
275
276
 
276
277
  @classmethod
277
278
  def tempfile(
278
- cls: type[PathType],
279
+ cls,
279
280
  *,
280
281
  in_memory: bool = True,
281
282
  create: bool = True,
282
283
  **kwargs: Any,
283
- ) -> PathType:
284
+ ) -> Self:
284
285
  """Usage:
285
286
 
286
287
  with Path.tempfile() as tmp: run_command(log_file=tmp) logs = tmp.text
@@ -298,12 +299,12 @@ class Path(cached_content.Path):
298
299
  return path
299
300
 
300
301
  @classmethod
301
- def tempdir(cls: type[PathType], *, in_memory: bool = True) -> PathType:
302
+ def tempdir(cls, *, in_memory: bool = True) -> Self:
302
303
  path = cls.tempfile(in_memory=in_memory, create=False)
303
304
  path.mkdir()
304
305
  return path
305
306
 
306
- def __enter__(self: PathType) -> PathType:
307
+ def __enter__(self) -> Self:
307
308
  return self
308
309
 
309
310
  def __exit__(
@@ -1,8 +1,6 @@
1
- import contextlib
2
1
  import hashlib
3
2
  import mimetypes
4
3
  import os
5
- import subprocess
6
4
  import warnings
7
5
  from collections.abc import Callable
8
6
  from functools import wraps
@@ -44,12 +42,6 @@ class Path(content_properties.Path):
44
42
  def mtime(self, time: float) -> None:
45
43
  os.utime(self, (time, time)) # set create time as well
46
44
 
47
- command = "touch", "-d", f"@{time}", self
48
- with contextlib.suppress(
49
- subprocess.CalledProcessError,
50
- ): # Doesn't work on Windows
51
- subprocess.run(command, check=False) # noqa: S603
52
-
53
45
  @property
54
46
  def tags(self) -> list[str]:
55
47
  from .tags import XDGTags # , autoimport
@@ -119,7 +111,7 @@ class Path(content_properties.Path):
119
111
 
120
112
  # use default algorithm used in cloud provider checksums
121
113
  # can be efficient because not used for cryptographic security
122
- return cast(str, dirhash.dirhash(self, "md5")) if self.has_children else None
114
+ return cast("str", dirhash.dirhash(self, "md5")) if self.has_children else None
123
115
 
124
116
  @property
125
117
  def file_content_hash(self) -> str:
@@ -6,6 +6,8 @@ from functools import wraps
6
6
  from os import PathLike
7
7
  from typing import IO, Any, TypeVar
8
8
 
9
+ from typing_extensions import Self
10
+
9
11
  from . import encryption
10
12
  from .metadata_properties import catch_missing
11
13
 
@@ -47,12 +49,12 @@ class Path(encryption.Path):
47
49
  def rmdir(self) -> None:
48
50
  return super().rmdir()
49
51
 
50
- def iterdir(self: T, *, missing_ok: bool = True) -> Generator[T, None, None]:
52
+ def iterdir(self, *, missing_ok: bool = True) -> Generator[Self, None, None]:
51
53
  if self.exists() or not missing_ok:
52
54
  yield from super().iterdir()
53
55
 
54
56
  @create_parent_on_missing
55
- def rename(self: T, target: str | T, *, exist_ok: bool = False) -> T:
57
+ def rename(self, target: str | Self, *, exist_ok: bool = False) -> Self:
56
58
  target_path = self.__class__(target)
57
59
  rename = super().replace if exist_ok else super().rename
58
60
  try:
@@ -71,7 +73,7 @@ class Path(encryption.Path):
71
73
  else:
72
74
  target_path.unlink() # pragma: nocover
73
75
  else:
74
- message = f"Target already exists: {target_path }"
76
+ message = f"Target already exists: {target_path}"
75
77
  raise RuntimeError(message) from exception
76
78
  else:
77
79
  target_path.create_parent()
@@ -80,9 +82,9 @@ class Path(encryption.Path):
80
82
  raise
81
83
  return target_path
82
84
 
83
- def replace(self: T, target: str | PathLike[str]) -> T:
85
+ def replace(self, target: str | PathLike[str]) -> Self:
84
86
  path = self.rename(target, exist_ok=True)
85
- return typing.cast(T, path)
87
+ return typing.cast("Self", path)
86
88
 
87
89
  def open(self, mode: str = "r", **kwargs: Any) -> IO[Any]: # type: ignore[override]
88
90
  try:
@@ -4,8 +4,8 @@ from collections.abc import Callable
4
4
  def find_first_match(condition: Callable[..., bool]) -> int:
5
5
  """
6
6
  :param condition: Condition that number needs to match.
7
- The condition is assumed to be valid for all integers staring
8
- from an initial value.
7
+ The condition is assumed to be valid for all integers starting
8
+ from an initial value.
9
9
  :return: First integer for which condition is valid.
10
10
  """
11
11
 
@@ -1,9 +1,9 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.4
2
2
  Name: superpathlib
3
- Version: 2.0.9
3
+ Version: 2.0.10
4
4
  Summary: Extended Pathlib
5
5
  Author-email: Quinten Roets <qdr2104@columbia.edu>
6
- License: MIT
6
+ License-Expression: MIT
7
7
  Project-URL: Source Code, https://github.com/quintenroets/superpathlib
8
8
  Requires-Python: >=3.10
9
9
  Description-Content-Type: text/markdown
@@ -17,13 +17,14 @@ Requires-Dist: PyYaml<7,>=6.0.1; extra == "full"
17
17
  Requires-Dist: xattr<2,>=0.10.1; extra == "full"
18
18
  Provides-Extra: dev
19
19
  Requires-Dist: hypothesis<7,>=6.97.1; extra == "dev"
20
- Requires-Dist: package-dev-tools<1,>=0.5.12; extra == "dev"
20
+ Requires-Dist: package-dev-tools<1,>=0.7.1; extra == "dev"
21
21
  Requires-Dist: types-PyYaml<7,>=6.0.12.12; extra == "dev"
22
22
  Requires-Dist: dirhash<1,>=0.2.1; extra == "dev"
23
23
  Requires-Dist: numpy<3,>=1.26.4; extra == "dev"
24
24
  Requires-Dist: package-utils<1,>=0.6.1; extra == "dev"
25
25
  Requires-Dist: PyYaml<7,>=6.0.1; extra == "dev"
26
26
  Requires-Dist: xattr<2,>=0.10.1; extra == "dev"
27
+ Dynamic: license-file
27
28
 
28
29
  # Superpathlib
29
30
  [![PyPI version](https://badge.fury.io/py/superpathlib.svg)](https://badge.fury.io/py/superpathlib)
@@ -2,7 +2,7 @@ simple-classproperty<5,>=4.0.2
2
2
 
3
3
  [dev]
4
4
  hypothesis<7,>=6.97.1
5
- package-dev-tools<1,>=0.5.12
5
+ package-dev-tools<1,>=0.7.1
6
6
  types-PyYaml<7,>=6.0.12.12
7
7
  dirhash<1,>=0.2.1
8
8
  numpy<3,>=1.26.4
@@ -32,7 +32,7 @@ def test_text(content: str) -> None:
32
32
  def test_content(path: Path, content: dict[str, dict[str, str]]) -> None:
33
33
  class Storage:
34
34
  content: CachedFileContent[dict[str, dict[str, str]]] = typing.cast(
35
- CachedFileContent[dict[str, dict[str, str]]],
35
+ "CachedFileContent[dict[str, dict[str, str]]]",
36
36
  path.cached_content,
37
37
  )
38
38
 
@@ -44,7 +44,7 @@ def test_content(path: Path, content: dict[str, dict[str, str]]) -> None:
44
44
  def test_created_content(path: Path, content: dict[str, dict[str, str]]) -> None:
45
45
  class Storage:
46
46
  content: CachedFileContent[dict[str, dict[str, str]]] = typing.cast(
47
- CachedFileContent[dict[str, dict[str, str]]],
47
+ "CachedFileContent[dict[str, dict[str, str]]]",
48
48
  path.create_cached_content({}),
49
49
  )
50
50
 
@@ -11,6 +11,8 @@ from tests.content import (
11
11
  )
12
12
  from tests.utils import ignore_fixture_warning
13
13
 
14
+ MTIME_TOLERANCE = 0.01
15
+
14
16
 
15
17
  def test_tempfile() -> None:
16
18
  with Path.tempfile() as path:
@@ -297,3 +299,5 @@ def test_rmdir(directory: Path) -> None:
297
299
 
298
300
  def test_touch(path: Path) -> None:
299
301
  path.touch(mtime=1)
302
+ assert path.exists()
303
+ assert abs(path.mtime - 1) < MTIME_TOLERANCE
@@ -6,7 +6,7 @@ from hypothesis import given, strategies
6
6
  from hypothesis.strategies import lists
7
7
 
8
8
  from superpathlib import Path
9
- from tests.content import byte_content, text_strategy
9
+ from tests.content import byte_content, slower_test_settings, text_strategy
10
10
  from tests.utils import ignore_fixture_warning
11
11
 
12
12
 
@@ -44,7 +44,7 @@ def test_tag(path: Path, content: str) -> None:
44
44
  assert path.tag == content
45
45
 
46
46
 
47
- @ignore_fixture_warning
47
+ @slower_test_settings
48
48
  @byte_content
49
49
  def test_size(path: Path, content: bytes) -> None:
50
50
  assert isinstance(Path.size, property)
File without changes
File without changes
File without changes