dvc-objects 5.0.0__tar.gz → 5.1.1__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 (52) hide show
  1. {dvc-objects-5.0.0 → dvc_objects-5.1.1}/.github/workflows/tests.yml +8 -8
  2. {dvc-objects-5.0.0 → dvc_objects-5.1.1}/.pre-commit-config.yaml +3 -8
  3. {dvc-objects-5.0.0/src/dvc_objects.egg-info → dvc_objects-5.1.1}/PKG-INFO +8 -7
  4. {dvc-objects-5.0.0 → dvc_objects-5.1.1}/noxfile.py +4 -9
  5. {dvc-objects-5.0.0 → dvc_objects-5.1.1}/pyproject.toml +10 -7
  6. {dvc-objects-5.0.0 → dvc_objects-5.1.1}/src/dvc_objects/db.py +10 -16
  7. {dvc-objects-5.0.0 → dvc_objects-5.1.1}/src/dvc_objects/executors.py +12 -59
  8. {dvc-objects-5.0.0 → dvc_objects-5.1.1}/src/dvc_objects/fs/__init__.py +3 -3
  9. {dvc-objects-5.0.0 → dvc_objects-5.1.1}/src/dvc_objects/fs/base.py +50 -58
  10. {dvc-objects-5.0.0 → dvc_objects-5.1.1}/src/dvc_objects/fs/callbacks.py +1 -1
  11. {dvc-objects-5.0.0 → dvc_objects-5.1.1}/src/dvc_objects/fs/errors.py +2 -2
  12. {dvc-objects-5.0.0 → dvc_objects-5.1.1}/src/dvc_objects/fs/generic.py +18 -17
  13. {dvc-objects-5.0.0 → dvc_objects-5.1.1}/src/dvc_objects/fs/local.py +2 -2
  14. {dvc-objects-5.0.0 → dvc_objects-5.1.1}/src/dvc_objects/fs/utils.py +9 -8
  15. {dvc-objects-5.0.0 → dvc_objects-5.1.1}/src/dvc_objects/obj.py +1 -1
  16. {dvc-objects-5.0.0 → dvc_objects-5.1.1}/src/dvc_objects/transfer.py +3 -3
  17. {dvc-objects-5.0.0 → dvc_objects-5.1.1/src/dvc_objects.egg-info}/PKG-INFO +8 -7
  18. {dvc-objects-5.0.0 → dvc_objects-5.1.1}/src/dvc_objects.egg-info/requires.txt +2 -2
  19. {dvc-objects-5.0.0 → dvc_objects-5.1.1}/tests/benchmarks/test_fs.py +3 -3
  20. {dvc-objects-5.0.0 → dvc_objects-5.1.1}/tests/fs/test_localfs.py +2 -3
  21. {dvc-objects-5.0.0 → dvc_objects-5.1.1}/.cruft.json +0 -0
  22. {dvc-objects-5.0.0 → dvc_objects-5.1.1}/.gitattributes +0 -0
  23. {dvc-objects-5.0.0 → dvc_objects-5.1.1}/.github/dependabot.yml +0 -0
  24. {dvc-objects-5.0.0 → dvc_objects-5.1.1}/.github/workflows/release.yml +0 -0
  25. {dvc-objects-5.0.0 → dvc_objects-5.1.1}/.github/workflows/update-template.yaml +0 -0
  26. {dvc-objects-5.0.0 → dvc_objects-5.1.1}/.gitignore +0 -0
  27. {dvc-objects-5.0.0 → dvc_objects-5.1.1}/CODE_OF_CONDUCT.rst +0 -0
  28. {dvc-objects-5.0.0 → dvc_objects-5.1.1}/CONTRIBUTING.rst +0 -0
  29. {dvc-objects-5.0.0 → dvc_objects-5.1.1}/LICENSE +0 -0
  30. {dvc-objects-5.0.0 → dvc_objects-5.1.1}/README.rst +0 -0
  31. {dvc-objects-5.0.0 → dvc_objects-5.1.1}/setup.cfg +0 -0
  32. {dvc-objects-5.0.0 → dvc_objects-5.1.1}/src/dvc_objects/__init__.py +0 -0
  33. {dvc-objects-5.0.0 → dvc_objects-5.1.1}/src/dvc_objects/compat.py +0 -0
  34. {dvc-objects-5.0.0 → dvc_objects-5.1.1}/src/dvc_objects/errors.py +0 -0
  35. {dvc-objects-5.0.0 → dvc_objects-5.1.1}/src/dvc_objects/fs/memory.py +0 -0
  36. {dvc-objects-5.0.0 → dvc_objects-5.1.1}/src/dvc_objects/fs/scheme.py +0 -0
  37. {dvc-objects-5.0.0 → dvc_objects-5.1.1}/src/dvc_objects/fs/system.py +0 -0
  38. {dvc-objects-5.0.0 → dvc_objects-5.1.1}/src/dvc_objects/py.typed +0 -0
  39. {dvc-objects-5.0.0 → dvc_objects-5.1.1}/src/dvc_objects.egg-info/SOURCES.txt +0 -0
  40. {dvc-objects-5.0.0 → dvc_objects-5.1.1}/src/dvc_objects.egg-info/dependency_links.txt +0 -0
  41. {dvc-objects-5.0.0 → dvc_objects-5.1.1}/src/dvc_objects.egg-info/top_level.txt +0 -0
  42. {dvc-objects-5.0.0 → dvc_objects-5.1.1}/tests/__init__.py +0 -0
  43. {dvc-objects-5.0.0 → dvc_objects-5.1.1}/tests/benchmarks/__init__.py +0 -0
  44. {dvc-objects-5.0.0 → dvc_objects-5.1.1}/tests/conftest.py +0 -0
  45. {dvc-objects-5.0.0 → dvc_objects-5.1.1}/tests/fs/__init__.py +0 -0
  46. {dvc-objects-5.0.0 → dvc_objects-5.1.1}/tests/fs/test_callbacks.py +0 -0
  47. {dvc-objects-5.0.0 → dvc_objects-5.1.1}/tests/fs/test_generic.py +0 -0
  48. {dvc-objects-5.0.0 → dvc_objects-5.1.1}/tests/fs/test_system.py +0 -0
  49. {dvc-objects-5.0.0 → dvc_objects-5.1.1}/tests/fs/test_utils.py +0 -0
  50. {dvc-objects-5.0.0 → dvc_objects-5.1.1}/tests/test_odb.py +0 -0
  51. {dvc-objects-5.0.0 → dvc_objects-5.1.1}/tests/test_reflink.py +0 -0
  52. {dvc-objects-5.0.0 → dvc_objects-5.1.1}/tests/test_transfer.py +0 -0
@@ -20,11 +20,10 @@ jobs:
20
20
  strategy:
21
21
  fail-fast: false
22
22
  matrix:
23
- os: [ubuntu-20.04, windows-latest, macos-latest]
24
- pyv: ['3.8', '3.9', '3.10', '3.11', '3.12']
23
+ os: [ubuntu-latest, windows-latest, macos-latest]
24
+ pyv: ['3.9', '3.10', '3.11', '3.12', '3.13']
25
25
  include:
26
- - {os: ubuntu-latest, pyv: 'pypy3.8'}
27
- - {os: macos-14, pyv: '3.12'}
26
+ - {os: ubuntu-latest, pyv: 'pypy3.9'}
28
27
 
29
28
  steps:
30
29
  - name: Check out the repository
@@ -37,7 +36,8 @@ jobs:
37
36
  with:
38
37
  python-version: ${{ matrix.pyv }}
39
38
  cache: pip
40
- cache-dependency-path: setup.cfg
39
+ allow-prereleases: true
40
+ cache-dependency-path: pyproject.toml
41
41
 
42
42
  - name: Upgrade pip and nox
43
43
  run: |
@@ -45,14 +45,14 @@ jobs:
45
45
  pip --version
46
46
  nox --version
47
47
 
48
- - name: Lint code and check dependencies
49
- run: nox -s lint safety
48
+ - name: Lint code
49
+ run: nox -s lint
50
50
 
51
51
  - name: Run tests
52
52
  run: nox -s tests-${{ matrix.nox_pyv || matrix.pyv }} -- --cov-report=xml
53
53
 
54
54
  - name: Upload coverage report
55
- uses: codecov/codecov-action@v3.1.4
55
+ uses: codecov/codecov-action@v5
56
56
 
57
57
  - name: Run benchmarks
58
58
  run: nox -s bench
@@ -2,7 +2,7 @@ default_language_version:
2
2
  python: python3
3
3
  repos:
4
4
  - repo: https://github.com/pre-commit/pre-commit-hooks
5
- rev: v4.5.0
5
+ rev: v5.0.0
6
6
  hooks:
7
7
  - id: check-added-large-files
8
8
  - id: check-case-conflict
@@ -20,18 +20,13 @@ repos:
20
20
  - id: sort-simple-yaml
21
21
  - id: trailing-whitespace
22
22
  - repo: https://github.com/astral-sh/ruff-pre-commit
23
- rev: 'v0.1.7'
23
+ rev: 'v0.11.12'
24
24
  hooks:
25
25
  - id: ruff
26
26
  args: [--fix, --exit-non-zero-on-fix]
27
27
  - id: ruff-format
28
28
  - repo: https://github.com/codespell-project/codespell
29
- rev: v2.2.6
29
+ rev: v2.4.1
30
30
  hooks:
31
31
  - id: codespell
32
32
  additional_dependencies: ["tomli"]
33
- - repo: https://github.com/asottile/pyupgrade
34
- rev: v3.15.0
35
- hooks:
36
- - id: pyupgrade
37
- args: [--py38-plus]
@@ -1,25 +1,25 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.4
2
2
  Name: dvc-objects
3
- Version: 5.0.0
3
+ Version: 5.1.1
4
4
  Summary: dvc objects - filesystem and object-db level abstractions to use in dvc and dvc-data
5
5
  Author-email: Iterative <support@dvc.org>
6
6
  License: Apache-2.0
7
7
  Project-URL: Issues, https://github.com/iterative/dvc-objects/issues
8
8
  Project-URL: Source, https://github.com/iterative/dvc-objects
9
9
  Classifier: Programming Language :: Python :: 3
10
- Classifier: Programming Language :: Python :: 3.8
11
10
  Classifier: Programming Language :: Python :: 3.9
12
11
  Classifier: Programming Language :: Python :: 3.10
13
12
  Classifier: Programming Language :: Python :: 3.11
14
13
  Classifier: Programming Language :: Python :: 3.12
14
+ Classifier: Programming Language :: Python :: 3.13
15
15
  Classifier: Development Status :: 4 - Beta
16
- Requires-Python: >=3.8
16
+ Requires-Python: >=3.9
17
17
  Description-Content-Type: text/x-rst
18
18
  License-File: LICENSE
19
- Requires-Dist: funcy>=1.14; python_version < "3.12"
20
19
  Requires-Dist: fsspec>=2024.2.0
20
+ Requires-Dist: funcy>=1.14; python_version < "3.12"
21
21
  Provides-Extra: tests
22
- Requires-Dist: pytest<8,>=7; extra == "tests"
22
+ Requires-Dist: pytest<9,>=7; extra == "tests"
23
23
  Requires-Dist: pytest-sugar; extra == "tests"
24
24
  Requires-Dist: pytest-cov>=4.1.0; extra == "tests"
25
25
  Requires-Dist: pytest-mock; extra == "tests"
@@ -28,7 +28,8 @@ Requires-Dist: pytest-asyncio<1,>=0.23.2; extra == "tests"
28
28
  Requires-Dist: reflink; extra == "tests"
29
29
  Provides-Extra: dev
30
30
  Requires-Dist: dvc-objects[tests]; extra == "dev"
31
- Requires-Dist: mypy==1.8.0; extra == "dev"
31
+ Requires-Dist: mypy==1.16.0; extra == "dev"
32
+ Dynamic: license-file
32
33
 
33
34
  DVC objects
34
35
  ===========
@@ -1,4 +1,5 @@
1
1
  """Automation using nox."""
2
+
2
3
  import glob
3
4
  import os
4
5
 
@@ -11,7 +12,9 @@ locations = "src", "tests"
11
12
  pip_dev_flags = ["--use-pep517"] # reflink package is still missing wheels
12
13
 
13
14
 
14
- @nox.session(python=["3.8", "3.9", "3.10", "3.11", "3.12", "pypy3.8", "pypy3.9"])
15
+ @nox.session(
16
+ python=["3.8", "3.9", "3.10", "3.11", "3.12", "3.13", "pypy3.8", "pypy3.9"]
17
+ )
15
18
  def tests(session: nox.Session) -> None:
16
19
  session.install(".[tests]", *pip_dev_flags)
17
20
  session.run(
@@ -39,14 +42,6 @@ def lint(session: nox.Session) -> None:
39
42
  session.run("python", "-m", "mypy")
40
43
 
41
44
 
42
- @nox.session
43
- def safety(session: nox.Session) -> None:
44
- """Scan dependencies for insecure packages."""
45
- session.install(".[dev]", *pip_dev_flags)
46
- session.install("safety")
47
- session.run("safety", "check", "--full-report")
48
-
49
-
50
45
  @nox.session
51
46
  def build(session: nox.Session) -> None:
52
47
  session.install("build", "setuptools", "twine")
@@ -12,18 +12,18 @@ license = {text = "Apache-2.0"}
12
12
  authors = [{ name = "Iterative", email = "support@dvc.org" }]
13
13
  classifiers = [
14
14
  "Programming Language :: Python :: 3",
15
- "Programming Language :: Python :: 3.8",
16
15
  "Programming Language :: Python :: 3.9",
17
16
  "Programming Language :: Python :: 3.10",
18
17
  "Programming Language :: Python :: 3.11",
19
18
  "Programming Language :: Python :: 3.12",
19
+ "Programming Language :: Python :: 3.13",
20
20
  "Development Status :: 4 - Beta",
21
21
  ]
22
- requires-python = ">=3.8"
22
+ requires-python = ">=3.9"
23
23
  dynamic = ["version"]
24
24
  dependencies = [
25
- "funcy>=1.14; python_version < '3.12'",
26
25
  "fsspec>=2024.2.0",
26
+ "funcy>=1.14; python_version < '3.12'",
27
27
  ]
28
28
 
29
29
  [project.urls]
@@ -32,7 +32,7 @@ Source = "https://github.com/iterative/dvc-objects"
32
32
 
33
33
  [project.optional-dependencies]
34
34
  tests = [
35
- "pytest<8,>=7",
35
+ "pytest>=7,<9",
36
36
  "pytest-sugar",
37
37
  "pytest-cov>=4.1.0",
38
38
  "pytest-mock",
@@ -42,7 +42,7 @@ tests = [
42
42
  ]
43
43
  dev = [
44
44
  "dvc-objects[tests]",
45
- "mypy==1.8.0",
45
+ "mypy==1.16.0",
46
46
  ]
47
47
 
48
48
  [tool.setuptools.packages.find]
@@ -102,8 +102,13 @@ module = [
102
102
 
103
103
  [tool.codespell]
104
104
  ignore-words-list = "cachable,"
105
+ skip = "CODE_OF_CONDUCT.rst"
105
106
 
106
107
  [tool.ruff]
108
+ output-format = "full"
109
+ show-fixes = true
110
+
111
+ [tool.ruff.lint]
107
112
  ignore = [
108
113
  "ISC001", # single-line-implicit-string-concatenation
109
114
  "PLR2004", # magic-value-comparison
@@ -156,8 +161,6 @@ select = [
156
161
  "W", # pycodestyle - Warning
157
162
  "YTT", # flake8-2020
158
163
  ]
159
- show-source = true
160
- show-fixes = true
161
164
 
162
165
  [tool.ruff.lint.flake8-pytest-style]
163
166
  fixture-parentheses = false
@@ -1,5 +1,6 @@
1
1
  import itertools
2
2
  import logging
3
+ from collections.abc import Iterable, Iterator
3
4
  from contextlib import suppress
4
5
  from functools import partial
5
6
  from io import BytesIO
@@ -7,11 +8,7 @@ from typing import (
7
8
  TYPE_CHECKING,
8
9
  BinaryIO,
9
10
  Callable,
10
- Iterable,
11
- Iterator,
12
- List,
13
11
  Optional,
14
- Tuple,
15
12
  Union,
16
13
  cast,
17
14
  )
@@ -126,7 +123,7 @@ class ObjectDB:
126
123
  raise ObjectDBPermissionError("Cannot add to read-only ODB")
127
124
 
128
125
  if isinstance(data, bytes):
129
- fobj: "BinaryIO" = BytesIO(data)
126
+ fobj: BinaryIO = BytesIO(data)
130
127
  size: Optional[int] = len(data)
131
128
  else:
132
129
  fobj = data
@@ -139,9 +136,9 @@ class ObjectDB:
139
136
 
140
137
  def add(
141
138
  self,
142
- path: Union["AnyFSPath", List["AnyFSPath"]],
139
+ path: Union["AnyFSPath", list["AnyFSPath"]],
143
140
  fs: "FileSystem",
144
- oid: Union[str, List[str]],
141
+ oid: Union[str, list[str]],
145
142
  hardlink: bool = False,
146
143
  callback: "Callback" = DEFAULT_CALLBACK,
147
144
  check_exists: bool = True,
@@ -206,7 +203,7 @@ class ObjectDB:
206
203
  for oid in self.all():
207
204
  self.delete(oid)
208
205
 
209
- def _oid_parts(self, oid: str) -> Tuple[str, str]:
206
+ def _oid_parts(self, oid: str) -> tuple[str, str]:
210
207
  return oid[:2], oid[2:]
211
208
 
212
209
  def oid_to_path(self, oid) -> str:
@@ -218,7 +215,7 @@ class ObjectDB:
218
215
  jobs: Optional[int] = None,
219
216
  ) -> Iterator[str]:
220
217
  if prefixes:
221
- paths: Union[str, List[str]] = list(map(self.oid_to_path, prefixes))
218
+ paths: Union[str, list[str]] = list(map(self.oid_to_path, prefixes))
222
219
  if len(paths) == 1:
223
220
  paths = paths[0]
224
221
  prefix = True
@@ -262,14 +259,11 @@ class ObjectDB:
262
259
  prefixes: Optional[Iterable[str]] = None,
263
260
  jobs: Optional[int] = None,
264
261
  ) -> Iterator[str]:
265
- count = 0
266
- for oid in self._list_oids(prefixes=prefixes, jobs=jobs):
262
+ for i, oid in enumerate(self._list_oids(prefixes=prefixes, jobs=jobs), start=1):
267
263
  yield oid
268
- count += 1
269
- if count > limit:
264
+ if i > limit:
270
265
  logger.debug(
271
- "`_list_oids()` returned max %r oids, "
272
- "skipping remaining results",
266
+ "`_list_oids()` returned max %r oids, skipping remaining results",
273
267
  limit,
274
268
  )
275
269
  return
@@ -351,7 +345,7 @@ class ObjectDB:
351
345
 
352
346
  yield from self._list_oids(prefixes=traverse_prefixes, jobs=jobs)
353
347
 
354
- def all(self, jobs=None): # noqa: A003
348
+ def all(self, jobs=None):
355
349
  """Iterate over all oids in this fs.
356
350
 
357
351
  Hashes will be fetched in parallel threads according to prefix
@@ -1,22 +1,8 @@
1
1
  import asyncio
2
- import queue
3
- import sys
2
+ from collections.abc import Coroutine, Iterable, Iterator, Sequence
4
3
  from concurrent import futures
5
4
  from itertools import islice
6
- from typing import (
7
- Any,
8
- Callable,
9
- Coroutine,
10
- Dict,
11
- Iterable,
12
- Iterator,
13
- List,
14
- Optional,
15
- Sequence,
16
- Set,
17
- Tuple,
18
- TypeVar,
19
- )
5
+ from typing import Any, Callable, Optional, TypeVar
20
6
 
21
7
  from fsspec import Callback
22
8
 
@@ -24,18 +10,12 @@ _T = TypeVar("_T")
24
10
 
25
11
 
26
12
  class ThreadPoolExecutor(futures.ThreadPoolExecutor):
27
- _max_workers: int
28
-
29
13
  def __init__(
30
14
  self, max_workers: Optional[int] = None, cancel_on_error: bool = False, **kwargs
31
15
  ):
32
16
  super().__init__(max_workers=max_workers, **kwargs)
33
17
  self._cancel_on_error = cancel_on_error
34
18
 
35
- @property
36
- def max_workers(self) -> int:
37
- return self._max_workers
38
-
39
19
  def imap_unordered(
40
20
  self, fn: Callable[..., _T], *iterables: Iterable[Any]
41
21
  ) -> Iterator[_T]:
@@ -43,52 +23,25 @@ class ThreadPoolExecutor(futures.ThreadPoolExecutor):
43
23
 
44
24
  It does not create all the futures at once to reduce memory usage.
45
25
  """
46
-
47
26
  it = zip(*iterables)
48
- if self.max_workers == 1:
27
+ if self._max_workers == 1:
49
28
  for args in it:
50
29
  yield fn(*args)
51
30
  return
52
31
 
53
- def create_taskset(n: int) -> Set[futures.Future]:
32
+ def create_taskset(n: int) -> set[futures.Future]:
54
33
  return {self.submit(fn, *args) for args in islice(it, n)}
55
34
 
56
- tasks = create_taskset(self.max_workers * 5)
35
+ tasks = create_taskset(self._max_workers * 5)
57
36
  while tasks:
58
37
  done, tasks = futures.wait(tasks, return_when=futures.FIRST_COMPLETED)
59
38
  for fut in done:
60
39
  yield fut.result()
61
40
  tasks.update(create_taskset(len(done)))
62
41
 
63
- def shutdown(self, wait=True, *, cancel_futures=False):
64
- if sys.version_info > (3, 9):
65
- return super().shutdown(wait=wait, cancel_futures=cancel_futures)
66
- else: # noqa: RET505
67
- with self._shutdown_lock:
68
- self._shutdown = True
69
- if cancel_futures:
70
- # Drain all work items from the queue, and then cancel their
71
- # associated futures.
72
- while True:
73
- try:
74
- work_item = self._work_queue.get_nowait()
75
- except queue.Empty:
76
- break
77
- if work_item is not None:
78
- work_item.future.cancel()
79
-
80
- # Send a wake-up to prevent threads calling
81
- # _work_queue.get(block=True) from permanently blocking.
82
- self._work_queue.put(None) # type: ignore[arg-type]
83
- if wait:
84
- for t in self._threads:
85
- t.join()
86
-
87
42
  def __exit__(self, exc_type, exc_val, exc_tb):
88
- if self._cancel_on_error:
89
- self.shutdown(wait=True, cancel_futures=exc_val is not None)
90
- else:
91
- self.shutdown(wait=True)
43
+ cancel_futures = self._cancel_on_error and exc_val is not None
44
+ self.shutdown(wait=True, cancel_futures=cancel_futures)
92
45
  return False
93
46
 
94
47
 
@@ -99,7 +52,7 @@ async def batch_coros( # noqa: C901
99
52
  timeout: Optional[int] = None,
100
53
  return_exceptions: bool = False,
101
54
  nofiles: bool = False,
102
- ) -> List[Any]:
55
+ ) -> list[Any]:
103
56
  """Run the given in coroutines in parallel.
104
57
 
105
58
  The asyncio loop will be kept saturated with up to `batch_size` tasks in
@@ -116,12 +69,12 @@ async def batch_coros( # noqa: C901
116
69
  batch_size = len(coros)
117
70
  assert batch_size > 0
118
71
 
119
- def create_taskset(n: int) -> Dict[asyncio.Task, int]:
72
+ def create_taskset(n: int) -> dict[asyncio.Task, int]:
120
73
  return {asyncio.create_task(coro): i for i, coro in islice(it, n)}
121
74
 
122
- it: Iterator[Tuple[int, Coroutine]] = enumerate(coros)
75
+ it: Iterator[tuple[int, Coroutine]] = enumerate(coros)
123
76
  tasks = create_taskset(batch_size)
124
- results: Dict[int, Any] = {}
77
+ results: dict[int, Any] = {}
125
78
  while tasks:
126
79
  done, pending = await asyncio.wait(
127
80
  tasks.keys(), timeout=timeout, return_when=asyncio.FIRST_COMPLETED
@@ -133,7 +86,7 @@ async def batch_coros( # noqa: C901
133
86
  for fut in done:
134
87
  try:
135
88
  result = fut.result()
136
- except Exception as exc: # noqa: BLE001
89
+ except Exception as exc:
137
90
  if not return_exceptions:
138
91
  for pending_fut in pending:
139
92
  pending_fut.cancel()
@@ -1,5 +1,5 @@
1
- from collections.abc import Mapping
2
- from typing import TYPE_CHECKING, Iterator, Type
1
+ from collections.abc import Iterator, Mapping
2
+ from typing import TYPE_CHECKING
3
3
  from urllib.parse import urlparse
4
4
 
5
5
  from . import generic # noqa: F401
@@ -83,7 +83,7 @@ class Registry(Mapping):
83
83
  def __init__(self, reg) -> None:
84
84
  self._registry = reg
85
85
 
86
- def __getitem__(self, key: str) -> Type["FileSystem"]:
86
+ def __getitem__(self, key: str) -> type["FileSystem"]:
87
87
  entry = self._registry.get(key) or self._registry[Schemes.LOCAL]
88
88
  try:
89
89
  return _import_class(entry["class"])
@@ -5,6 +5,7 @@ import ntpath
5
5
  import os
6
6
  import posixpath
7
7
  import shutil
8
+ from collections.abc import Iterable, Iterator, Sequence
8
9
  from functools import partial
9
10
  from multiprocessing import cpu_count
10
11
  from typing import (
@@ -12,14 +13,8 @@ from typing import (
12
13
  TYPE_CHECKING,
13
14
  Any,
14
15
  ClassVar,
15
- Dict,
16
- Iterable,
17
- Iterator,
18
- List,
19
16
  Literal,
20
17
  Optional,
21
- Sequence,
22
- Tuple,
23
18
  Union,
24
19
  overload,
25
20
  )
@@ -49,7 +44,7 @@ AnyFSPath = str
49
44
 
50
45
  # An info() entry, might evolve to a TypedDict
51
46
  # in the future (e.g for properly type 'size' etc).
52
- Entry = Dict[str, Any]
47
+ Entry = dict[str, Any]
53
48
 
54
49
 
55
50
  class LinkError(OSError):
@@ -68,7 +63,7 @@ class FileSystem:
68
63
 
69
64
  flavour = posixpath
70
65
  protocol = "base"
71
- REQUIRES: ClassVar[Dict[str, str]] = {}
66
+ REQUIRES: ClassVar[dict[str, str]] = {}
72
67
  _JOBS = 4 * cpu_count()
73
68
 
74
69
  HASH_JOBS = max(1, min(4, cpu_count() // 2))
@@ -90,13 +85,13 @@ class FileSystem:
90
85
  self.fs = fs
91
86
 
92
87
  @cached_property
93
- def fs_args(self) -> Dict[str, Any]:
88
+ def fs_args(self) -> dict[str, Any]:
94
89
  ret = {"skip_instance_cache": True}
95
90
  ret.update(self._prepare_credentials(**self._config))
96
91
  return ret
97
92
 
98
93
  @property
99
- def config(self) -> Dict[str, Any]:
94
+ def config(self) -> dict[str, Any]:
100
95
  return self._config
101
96
 
102
97
  @property
@@ -114,11 +109,11 @@ class FileSystem:
114
109
  return cls.flavour.join(*parts)
115
110
 
116
111
  @classmethod
117
- def split(cls, path: str) -> Tuple[str, str]:
112
+ def split(cls, path: str) -> tuple[str, str]:
118
113
  return cls.flavour.split(path)
119
114
 
120
115
  @classmethod
121
- def splitext(cls, path: str) -> Tuple[str, str]:
116
+ def splitext(cls, path: str) -> tuple[str, str]:
122
117
  return cls.flavour.splitext(path)
123
118
 
124
119
  def normpath(self, path: str) -> str:
@@ -147,7 +142,7 @@ class FileSystem:
147
142
  return cls.flavour.commonpath(list(paths))
148
143
 
149
144
  @classmethod
150
- def parts(cls, path: str) -> Tuple[str, ...]:
145
+ def parts(cls, path: str) -> tuple[str, ...]:
151
146
  drive, path = cls.flavour.splitdrive(path.rstrip(cls.flavour.sep))
152
147
 
153
148
  ret = []
@@ -229,7 +224,7 @@ class FileSystem:
229
224
  start = "."
230
225
  return self.flavour.relpath(self.abspath(path), start=self.abspath(start))
231
226
 
232
- def relparts(self, path: str, start: Optional[str] = None) -> Tuple[str, ...]:
227
+ def relparts(self, path: str, start: Optional[str] = None) -> tuple[str, ...]:
233
228
  return self.parts(self.relpath(path, start=start))
234
229
 
235
230
  @classmethod
@@ -252,7 +247,7 @@ class FileSystem:
252
247
  return self._config.get("version_aware", False)
253
248
 
254
249
  @staticmethod
255
- def _get_kwargs_from_urls(urlpath: str) -> "Dict[str, Any]":
250
+ def _get_kwargs_from_urls(urlpath: str) -> "dict[str, Any]":
256
251
  from fsspec.utils import infer_storage_options
257
252
 
258
253
  options = infer_storage_options(urlpath)
@@ -262,14 +257,14 @@ class FileSystem:
262
257
 
263
258
  def _prepare_credentials(
264
259
  self,
265
- **config: Dict[str, Any],
266
- ) -> Dict[str, Any]:
260
+ **config: dict[str, Any],
261
+ ) -> dict[str, Any]:
267
262
  """Prepare the arguments for authentication to the
268
263
  host filesystem"""
269
264
  return {}
270
265
 
271
266
  @classmethod
272
- def get_missing_deps(cls) -> List[str]:
267
+ def get_missing_deps(cls) -> list[str]:
273
268
  from importlib.util import find_spec
274
269
 
275
270
  return [pkg for pkg, mod in cls.REQUIRES.items() if not find_spec(mod)]
@@ -301,7 +296,7 @@ class FileSystem:
301
296
  return entry["size"] == 0
302
297
 
303
298
  @overload
304
- def open( # noqa: A003
299
+ def open(
305
300
  self,
306
301
  path: AnyFSPath,
307
302
  mode: Literal["rb", "br", "wb"],
@@ -310,15 +305,14 @@ class FileSystem:
310
305
  return self.open(path, mode, **kwargs)
311
306
 
312
307
  @overload
313
- def open( # noqa: A003
308
+ def open(
314
309
  self,
315
310
  path: AnyFSPath,
316
311
  mode: Literal["r", "rt", "w"] = "r",
317
312
  **kwargs: Any,
318
- ) -> "TextIO":
319
- ...
313
+ ) -> "TextIO": ...
320
314
 
321
- def open( # noqa: A003
315
+ def open(
322
316
  self,
323
317
  path: AnyFSPath,
324
318
  mode: str = "r",
@@ -339,21 +333,21 @@ class FileSystem:
339
333
 
340
334
  def cat(
341
335
  self,
342
- path: Union[AnyFSPath, List[AnyFSPath]],
336
+ path: Union[AnyFSPath, list[AnyFSPath]],
343
337
  recursive: bool = False,
344
338
  on_error: Literal["raise", "omit", "return"] = "raise",
345
339
  **kwargs: Any,
346
- ) -> Union[bytes, Dict[AnyFSPath, bytes]]:
340
+ ) -> Union[bytes, dict[AnyFSPath, bytes]]:
347
341
  return self.fs.cat(path, recursive=recursive, on_error=on_error, **kwargs)
348
342
 
349
343
  def cat_ranges(
350
344
  self,
351
- paths: List[AnyFSPath],
352
- starts: List[int],
353
- ends: List[int],
345
+ paths: list[AnyFSPath],
346
+ starts: list[int],
347
+ ends: list[int],
354
348
  max_gap: Optional[int] = None,
355
349
  **kwargs,
356
- ) -> List[bytes]:
350
+ ) -> list[bytes]:
357
351
  return self.fs.cat_ranges(paths, starts, ends, max_gap=max_gap, **kwargs)
358
352
 
359
353
  def cat_file(
@@ -409,7 +403,7 @@ class FileSystem:
409
403
 
410
404
  def pipe(
411
405
  self,
412
- path: Union[AnyFSPath, Dict[AnyFSPath, bytes]],
406
+ path: Union[AnyFSPath, dict[AnyFSPath, bytes]],
413
407
  value: Optional[bytes] = None,
414
408
  **kwargs: Any,
415
409
  ) -> None:
@@ -434,24 +428,22 @@ class FileSystem:
434
428
  path: AnyFSPath,
435
429
  callback: fsspec.Callback = ...,
436
430
  batch_size: Optional[int] = ...,
437
- ) -> bool:
438
- ...
431
+ ) -> bool: ...
439
432
 
440
433
  @overload
441
434
  def exists(
442
435
  self,
443
- path: List[AnyFSPath],
436
+ path: list[AnyFSPath],
444
437
  callback: fsspec.Callback = ...,
445
438
  batch_size: Optional[int] = ...,
446
- ) -> List[bool]:
447
- ...
439
+ ) -> list[bool]: ...
448
440
 
449
441
  def exists(
450
442
  self,
451
- path: Union[AnyFSPath, List[AnyFSPath]],
443
+ path: Union[AnyFSPath, list[AnyFSPath]],
452
444
  callback: fsspec.Callback = DEFAULT_CALLBACK,
453
445
  batch_size: Optional[int] = None,
454
- ) -> Union[bool, List[bool]]:
446
+ ) -> Union[bool, list[bool]]:
455
447
  if isinstance(path, str):
456
448
  return self.fs.exists(path)
457
449
  callback.set_size(len(path))
@@ -513,19 +505,21 @@ class FileSystem:
513
505
  return not (self.is_symlink(path) or self.is_hardlink(path))
514
506
 
515
507
  @overload
516
- def ls(self, path: AnyFSPath, detail: Literal[True], **kwargs) -> "Iterator[Entry]":
517
- ...
508
+ def ls(
509
+ self, path: AnyFSPath, detail: Literal[True], **kwargs
510
+ ) -> "Iterator[Entry]": ...
518
511
 
519
512
  @overload
520
- def ls(self, path: AnyFSPath, detail: Literal[False], **kwargs) -> Iterator[str]:
521
- ...
513
+ def ls(
514
+ self, path: AnyFSPath, detail: Literal[False], **kwargs
515
+ ) -> Iterator[str]: ...
522
516
 
523
517
  def ls(self, path, detail=False, **kwargs):
524
518
  return self.fs.ls(path, detail=detail, **kwargs)
525
519
 
526
520
  def find(
527
521
  self,
528
- path: Union[AnyFSPath, List[AnyFSPath]],
522
+ path: Union[AnyFSPath, list[AnyFSPath]],
529
523
  prefix: bool = False,
530
524
  batch_size: Optional[int] = None,
531
525
  **kwargs,
@@ -565,7 +559,7 @@ class FileSystem:
565
559
 
566
560
  def rm(
567
561
  self,
568
- path: Union[AnyFSPath, List[AnyFSPath]],
562
+ path: Union[AnyFSPath, list[AnyFSPath]],
569
563
  recursive: bool = False,
570
564
  **kwargs,
571
565
  ) -> None:
@@ -580,17 +574,15 @@ class FileSystem:
580
574
  callback: fsspec.Callback = ...,
581
575
  batch_size: Optional[int] = ...,
582
576
  **kwargs,
583
- ) -> "Entry":
584
- ...
577
+ ) -> "Entry": ...
585
578
 
586
579
  @overload
587
580
  def info(
588
581
  self,
589
- path: List[AnyFSPath],
582
+ path: list[AnyFSPath],
590
583
  callback: fsspec.Callback = ...,
591
584
  batch_size: Optional[int] = ...,
592
- ) -> List["Entry"]:
593
- ...
585
+ ) -> list["Entry"]: ...
594
586
 
595
587
  def info(self, path, callback=DEFAULT_CALLBACK, batch_size=None, **kwargs):
596
588
  if isinstance(path, str):
@@ -667,7 +659,7 @@ class FileSystem:
667
659
  def size(self, path: AnyFSPath) -> Optional[int]:
668
660
  return self.fs.size(path)
669
661
 
670
- def sizes(self, paths: List[AnyFSPath]) -> List[Optional[int]]:
662
+ def sizes(self, paths: list[AnyFSPath]) -> list[Optional[int]]:
671
663
  return self.fs.sizes(paths)
672
664
 
673
665
  def du(
@@ -676,13 +668,13 @@ class FileSystem:
676
668
  total: bool = True,
677
669
  maxdepth: Optional[int] = None,
678
670
  **kwargs: Any,
679
- ) -> Union[int, Dict[AnyFSPath, int]]:
671
+ ) -> Union[int, dict[AnyFSPath, int]]:
680
672
  return self.fs.du(path, total=total, maxdepth=maxdepth, **kwargs)
681
673
 
682
674
  def put(
683
675
  self,
684
- from_info: Union[AnyFSPath, List[AnyFSPath]],
685
- to_info: Union[AnyFSPath, List[AnyFSPath]],
676
+ from_info: Union[AnyFSPath, list[AnyFSPath]],
677
+ to_info: Union[AnyFSPath, list[AnyFSPath]],
686
678
  callback: fsspec.Callback = DEFAULT_CALLBACK,
687
679
  recursive: bool = False,
688
680
  batch_size: Optional[int] = None,
@@ -714,8 +706,8 @@ class FileSystem:
714
706
 
715
707
  def get(
716
708
  self,
717
- from_info: Union[AnyFSPath, List[AnyFSPath]],
718
- to_info: Union[AnyFSPath, List[AnyFSPath]],
709
+ from_info: Union[AnyFSPath, list[AnyFSPath]],
710
+ to_info: Union[AnyFSPath, list[AnyFSPath]],
719
711
  callback: fsspec.Callback = DEFAULT_CALLBACK,
720
712
  recursive: bool = False,
721
713
  batch_size: Optional[int] = None,
@@ -730,8 +722,8 @@ class FileSystem:
730
722
  self.fs.get_file(rpath, lpath, callback=child, **kwargs)
731
723
 
732
724
  if isinstance(from_info, list) and isinstance(to_info, list):
733
- from_infos: List[AnyFSPath] = from_info
734
- to_infos: List[AnyFSPath] = to_info
725
+ from_infos: list[AnyFSPath] = from_info
726
+ to_infos: list[AnyFSPath] = to_info
735
727
  else:
736
728
  assert isinstance(from_info, str)
737
729
  assert isinstance(to_info, str)
@@ -797,7 +789,7 @@ class ObjectFileSystem(FileSystem):
797
789
 
798
790
  def find(
799
791
  self,
800
- path: Union[AnyFSPath, List[AnyFSPath]],
792
+ path: Union[AnyFSPath, list[AnyFSPath]],
801
793
  prefix: bool = False,
802
794
  batch_size: Optional[int] = None,
803
795
  **kwargs,
@@ -807,7 +799,7 @@ class ObjectFileSystem(FileSystem):
807
799
  else:
808
800
  paths = path
809
801
 
810
- def _make_args(paths: List[AnyFSPath]) -> Iterator[Tuple[str, str]]:
802
+ def _make_args(paths: list[AnyFSPath]) -> Iterator[tuple[str, str]]:
811
803
  for path in paths:
812
804
  if prefix and not path.endswith(self.flavour.sep):
813
805
  parent = self.parent(path)
@@ -22,4 +22,4 @@ class CallbackStream:
22
22
 
23
23
 
24
24
  def wrap_file(file, callback: "fsspec.Callback") -> BinaryIO:
25
- return cast(BinaryIO, CallbackStream(file, callback))
25
+ return cast("BinaryIO", CallbackStream(file, callback))
@@ -1,4 +1,4 @@
1
- from typing import TYPE_CHECKING, List, Optional
1
+ from typing import TYPE_CHECKING, Optional
2
2
 
3
3
  if TYPE_CHECKING:
4
4
  from .base import FileSystem
@@ -18,7 +18,7 @@ class RemoteMissingDepsError(Exception):
18
18
  fs: "FileSystem",
19
19
  protocol: str,
20
20
  url: str,
21
- missing: Optional[List[str]] = None,
21
+ missing: Optional[list[str]] = None,
22
22
  ) -> None:
23
23
  self.protocol = protocol
24
24
  self.fs = fs
@@ -4,7 +4,7 @@ import logging
4
4
  import os
5
5
  from contextlib import suppress
6
6
  from functools import wraps
7
- from typing import TYPE_CHECKING, Any, Callable, List, Optional, Union
7
+ from typing import TYPE_CHECKING, Any, Callable, Optional, Union
8
8
 
9
9
  from fsspec.asyn import get_loop
10
10
  from fsspec.callbacks import DEFAULT_CALLBACK
@@ -68,9 +68,9 @@ def _link(
68
68
 
69
69
  def copy(
70
70
  from_fs: "FileSystem",
71
- from_path: Union["AnyFSPath", List["AnyFSPath"]],
71
+ from_path: Union["AnyFSPath", list["AnyFSPath"]],
72
72
  to_fs: "FileSystem",
73
- to_path: Union["AnyFSPath", List["AnyFSPath"]],
73
+ to_path: Union["AnyFSPath", list["AnyFSPath"]],
74
74
  callback: "Callback" = DEFAULT_CALLBACK,
75
75
  batch_size: Optional[int] = None,
76
76
  on_error: Optional[TransferErrorHandler] = None,
@@ -116,7 +116,7 @@ def copy(
116
116
  return to_fs.put_file(
117
117
  fobj, to_p, size=size, callback=child, **put_file_kwargs
118
118
  )
119
- except Exception as exc: # noqa: BLE001
119
+ except Exception as exc:
120
120
  if on_error is not None:
121
121
  on_error(from_p, to_p, exc)
122
122
  else:
@@ -133,9 +133,9 @@ def copy(
133
133
 
134
134
 
135
135
  def _put( # noqa: C901
136
- from_paths: List["AnyFSPath"],
136
+ from_paths: list["AnyFSPath"],
137
137
  to_fs: "FileSystem",
138
- to_paths: List["AnyFSPath"],
138
+ to_paths: list["AnyFSPath"],
139
139
  callback: "Callback" = DEFAULT_CALLBACK,
140
140
  batch_size: Optional[int] = None,
141
141
  on_error: Optional[TransferErrorHandler] = None,
@@ -151,7 +151,7 @@ def _put( # noqa: C901
151
151
  return to_fs.put_file(
152
152
  from_path, to_path, callback=child, **put_file_kwargs
153
153
  )
154
- except Exception as exc: # noqa: BLE001
154
+ except Exception as exc:
155
155
  if on_error is not None:
156
156
  on_error(from_path, to_path, exc)
157
157
  else:
@@ -199,8 +199,8 @@ def _put( # noqa: C901
199
199
 
200
200
  def _get( # noqa: C901
201
201
  from_fs: "FileSystem",
202
- from_paths: List["AnyFSPath"],
203
- to_paths: List["AnyFSPath"],
202
+ from_paths: list["AnyFSPath"],
203
+ to_paths: list["AnyFSPath"],
204
204
  callback: "Callback" = DEFAULT_CALLBACK,
205
205
  batch_size: Optional[int] = None,
206
206
  on_error: Optional[TransferErrorHandler] = None,
@@ -217,7 +217,7 @@ def _get( # noqa: C901
217
217
  return from_fs.get_file(
218
218
  from_path, tmp_file, callback=child, **get_file_kwargs
219
219
  )
220
- except Exception as exc: # noqa: BLE001
220
+ except Exception as exc:
221
221
  if on_error is not None:
222
222
  on_error(from_path, to_path, exc)
223
223
  else:
@@ -265,7 +265,7 @@ def _get( # noqa: C901
265
265
 
266
266
 
267
267
  def _try_links(
268
- links: List["str"],
268
+ links: list["str"],
269
269
  from_fs: "FileSystem",
270
270
  from_path: "AnyFSPath",
271
271
  to_fs: "FileSystem",
@@ -299,6 +299,7 @@ def _try_links(
299
299
  errno.ENOTTY,
300
300
  errno.ENOSYS,
301
301
  errno.EINVAL,
302
+ errno.EAGAIN,
302
303
  ):
303
304
  raise
304
305
  error = exc
@@ -310,11 +311,11 @@ def _try_links(
310
311
 
311
312
  def transfer( # noqa: PLR0912, C901
312
313
  from_fs: "FileSystem",
313
- from_path: Union["AnyFSPath", List["AnyFSPath"]],
314
+ from_path: Union["AnyFSPath", list["AnyFSPath"]],
314
315
  to_fs: "FileSystem",
315
- to_path: Union["AnyFSPath", List["AnyFSPath"]],
316
+ to_path: Union["AnyFSPath", list["AnyFSPath"]],
316
317
  hardlink: bool = False,
317
- links: Optional[List["str"]] = None,
318
+ links: Optional[list["str"]] = None,
318
319
  callback: "Callback" = DEFAULT_CALLBACK,
319
320
  batch_size: Optional[int] = None,
320
321
  on_error: Optional[TransferErrorHandler] = None,
@@ -375,7 +376,7 @@ def transfer( # noqa: PLR0912, C901
375
376
  on_error(from_p, to_p, exc)
376
377
  else:
377
378
  raise
378
- except Exception as exc: # noqa: BLE001
379
+ except Exception as exc:
379
380
  if on_error is not None:
380
381
  on_error(from_p, to_p, exc)
381
382
  else:
@@ -405,12 +406,12 @@ def _test_link(
405
406
 
406
407
 
407
408
  def test_links(
408
- links: List["str"],
409
+ links: list["str"],
409
410
  from_fs: "FileSystem",
410
411
  from_path: "AnyFSPath",
411
412
  to_fs: "FileSystem",
412
413
  to_path: "AnyFSPath",
413
- ) -> List["AnyFSPath"]:
414
+ ) -> list["AnyFSPath"]:
414
415
  from .utils import tmp_fname
415
416
 
416
417
  from_file = from_fs.join(from_path, tmp_fname())
@@ -127,8 +127,8 @@ class FsspecLocalFileSystem(fsspec.AbstractFileSystem):
127
127
  self.rm_file(tmp_info)
128
128
  raise
129
129
 
130
- def open(self, path, mode="r", encoding=None, **kwargs): # noqa: A003
131
- return open(path, mode=mode, encoding=encoding) # noqa: SIM115
130
+ def open(self, path, mode="r", encoding=None, **kwargs):
131
+ return open(path, mode=mode, encoding=encoding)
132
132
 
133
133
  def symlink(self, path1, path2):
134
134
  return self.fs.symlink(path1, path2)
@@ -5,10 +5,11 @@ import shutil
5
5
  import stat
6
6
  import sys
7
7
  import threading
8
+ from collections.abc import Collection, Iterator
8
9
  from concurrent import futures
9
10
  from contextlib import contextmanager, suppress
10
11
  from secrets import token_urlsafe
11
- from typing import TYPE_CHECKING, Any, Collection, Dict, Iterator, Optional, Set, Union
12
+ from typing import TYPE_CHECKING, Any, Optional, Union
12
13
 
13
14
  from fsspec.callbacks import DEFAULT_CALLBACK
14
15
 
@@ -207,7 +208,7 @@ def exists(
207
208
  file_paths: Union["AnyFSPath", Collection["AnyFSPath"]],
208
209
  callback: "Callback" = DEFAULT_CALLBACK,
209
210
  batch_size: Optional[int] = None,
210
- ) -> Dict[str, bool]:
211
+ ) -> dict[str, bool]:
211
212
  """Return batched fs.exists results.
212
213
 
213
214
  Runs batched fs.exists() calls in parallel with fs.ls() until all paths
@@ -221,7 +222,7 @@ def exists(
221
222
  return {path: fs.exists(path)}
222
223
 
223
224
  paths_lock = threading.Lock()
224
- results: Dict[str, bool] = {}
225
+ results: dict[str, bool] = {}
225
226
  results_lock = threading.Lock()
226
227
  callback.set_size(len(paths))
227
228
  jobs = batch_size or fs.jobs
@@ -260,9 +261,9 @@ def exists(
260
261
 
261
262
  def _exist_query(
262
263
  fs: "FileSystem",
263
- paths: Set["AnyFSPath"],
264
+ paths: set["AnyFSPath"],
264
265
  paths_lock: threading.Lock,
265
- results: Dict[str, bool],
266
+ results: dict[str, bool],
266
267
  results_lock: threading.Lock,
267
268
  batch_size: int,
268
269
  callback: "Callback",
@@ -282,9 +283,9 @@ def _exist_query(
282
283
 
283
284
  def _list_query(
284
285
  fs: "FileSystem",
285
- paths: Set["AnyFSPath"],
286
+ paths: set["AnyFSPath"],
286
287
  paths_lock: threading.Lock,
287
- results: Dict[str, bool],
288
+ results: dict[str, bool],
288
289
  results_lock: threading.Lock,
289
290
  callback: "Callback",
290
291
  ):
@@ -294,7 +295,7 @@ def _list_query(
294
295
  with paths_lock:
295
296
  if not paths:
296
297
  return
297
- kwargs: Dict[str, Any] = {}
298
+ kwargs: dict[str, Any] = {}
298
299
  if fs.version_aware:
299
300
  kwargs["versions"] = True
300
301
  contents = fs.ls(parent, **kwargs)
@@ -5,7 +5,7 @@ if TYPE_CHECKING:
5
5
 
6
6
 
7
7
  class Object:
8
- __slots__ = ("path", "fs", "oid")
8
+ __slots__ = ("fs", "oid", "path")
9
9
 
10
10
  def __init__(
11
11
  self,
@@ -1,12 +1,12 @@
1
- from typing import TYPE_CHECKING, Optional, Set
1
+ from typing import TYPE_CHECKING, Optional
2
2
 
3
3
  if TYPE_CHECKING:
4
4
  from .db import ObjectDB
5
5
 
6
6
 
7
7
  def transfer(
8
- src: "ObjectDB", dest: "ObjectDB", oids: Set["str"], jobs: Optional[int] = None
9
- ) -> Set["str"]:
8
+ src: "ObjectDB", dest: "ObjectDB", oids: set["str"], jobs: Optional[int] = None
9
+ ) -> set["str"]:
10
10
  src_exists = set(src.oids_exist(oids, jobs=jobs))
11
11
  src_missing = oids - src_exists
12
12
 
@@ -1,25 +1,25 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.4
2
2
  Name: dvc-objects
3
- Version: 5.0.0
3
+ Version: 5.1.1
4
4
  Summary: dvc objects - filesystem and object-db level abstractions to use in dvc and dvc-data
5
5
  Author-email: Iterative <support@dvc.org>
6
6
  License: Apache-2.0
7
7
  Project-URL: Issues, https://github.com/iterative/dvc-objects/issues
8
8
  Project-URL: Source, https://github.com/iterative/dvc-objects
9
9
  Classifier: Programming Language :: Python :: 3
10
- Classifier: Programming Language :: Python :: 3.8
11
10
  Classifier: Programming Language :: Python :: 3.9
12
11
  Classifier: Programming Language :: Python :: 3.10
13
12
  Classifier: Programming Language :: Python :: 3.11
14
13
  Classifier: Programming Language :: Python :: 3.12
14
+ Classifier: Programming Language :: Python :: 3.13
15
15
  Classifier: Development Status :: 4 - Beta
16
- Requires-Python: >=3.8
16
+ Requires-Python: >=3.9
17
17
  Description-Content-Type: text/x-rst
18
18
  License-File: LICENSE
19
- Requires-Dist: funcy>=1.14; python_version < "3.12"
20
19
  Requires-Dist: fsspec>=2024.2.0
20
+ Requires-Dist: funcy>=1.14; python_version < "3.12"
21
21
  Provides-Extra: tests
22
- Requires-Dist: pytest<8,>=7; extra == "tests"
22
+ Requires-Dist: pytest<9,>=7; extra == "tests"
23
23
  Requires-Dist: pytest-sugar; extra == "tests"
24
24
  Requires-Dist: pytest-cov>=4.1.0; extra == "tests"
25
25
  Requires-Dist: pytest-mock; extra == "tests"
@@ -28,7 +28,8 @@ Requires-Dist: pytest-asyncio<1,>=0.23.2; extra == "tests"
28
28
  Requires-Dist: reflink; extra == "tests"
29
29
  Provides-Extra: dev
30
30
  Requires-Dist: dvc-objects[tests]; extra == "dev"
31
- Requires-Dist: mypy==1.8.0; extra == "dev"
31
+ Requires-Dist: mypy==1.16.0; extra == "dev"
32
+ Dynamic: license-file
32
33
 
33
34
  DVC objects
34
35
  ===========
@@ -5,10 +5,10 @@ funcy>=1.14
5
5
 
6
6
  [dev]
7
7
  dvc-objects[tests]
8
- mypy==1.8.0
8
+ mypy==1.16.0
9
9
 
10
10
  [tests]
11
- pytest<8,>=7
11
+ pytest<9,>=7
12
12
  pytest-sugar
13
13
  pytest-cov>=4.1.0
14
14
  pytest-mock
@@ -44,9 +44,9 @@ def paths(original, links):
44
44
 
45
45
  def test_link(benchmark, paths, links, link):
46
46
  def setup():
47
- for link in links.iterdir():
48
- if link.is_file():
49
- link.unlink()
47
+ for lnk in links.iterdir():
48
+ if lnk.is_file():
49
+ lnk.unlink()
50
50
 
51
51
  def _link(paths):
52
52
  for src, path in paths:
@@ -1,6 +1,5 @@
1
1
  import os
2
2
  from os import fspath
3
- from typing import Dict, List, Set, Tuple
4
3
 
5
4
  import pytest
6
5
 
@@ -98,11 +97,11 @@ def test_walk(dir_path):
98
97
 
99
98
  def test_walk_detail(dir_path):
100
99
  fs = LocalFileSystem()
101
- walk_results: List[Tuple[str, Dict[str, Dict], Dict[str, Dict]]] = list(
100
+ walk_results: list[tuple[str, dict[str, dict], dict[str, dict]]] = list(
102
101
  fs.walk(fspath(dir_path), detail=True)
103
102
  )
104
103
 
105
- expected: List[Tuple[str, Set[str], Set[str]]] = [
104
+ expected: list[tuple[str, set[str], set[str]]] = [
106
105
  (str(dir_path), {"data"}, {"code.py", "bar", "тест", "foo"}),
107
106
  (str(dir_path / "data"), {"sub"}, {"file"}),
108
107
  (str(dir_path / "data" / "sub"), set(), {"file"}),
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes