rclone-api 1.0.78__tar.gz → 1.0.80__tar.gz

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of rclone-api might be problematic. Click here for more details.

Files changed (70) hide show
  1. {rclone_api-1.0.78 → rclone_api-1.0.80}/PKG-INFO +1 -1
  2. {rclone_api-1.0.78 → rclone_api-1.0.80}/pyproject.toml +1 -1
  3. {rclone_api-1.0.78 → rclone_api-1.0.80}/src/rclone_api/group_files.py +56 -18
  4. {rclone_api-1.0.78 → rclone_api-1.0.80}/src/rclone_api/rclone.py +34 -42
  5. {rclone_api-1.0.78 → rclone_api-1.0.80}/src/rclone_api.egg-info/PKG-INFO +1 -1
  6. {rclone_api-1.0.78 → rclone_api-1.0.80}/tests/test_size_files.py +0 -7
  7. {rclone_api-1.0.78 → rclone_api-1.0.80}/.aiderignore +0 -0
  8. {rclone_api-1.0.78 → rclone_api-1.0.80}/.github/workflows/lint.yml +0 -0
  9. {rclone_api-1.0.78 → rclone_api-1.0.80}/.github/workflows/push_macos.yml +0 -0
  10. {rclone_api-1.0.78 → rclone_api-1.0.80}/.github/workflows/push_ubuntu.yml +0 -0
  11. {rclone_api-1.0.78 → rclone_api-1.0.80}/.github/workflows/push_win.yml +0 -0
  12. {rclone_api-1.0.78 → rclone_api-1.0.80}/.gitignore +0 -0
  13. {rclone_api-1.0.78 → rclone_api-1.0.80}/.pylintrc +0 -0
  14. {rclone_api-1.0.78 → rclone_api-1.0.80}/.vscode/launch.json +0 -0
  15. {rclone_api-1.0.78 → rclone_api-1.0.80}/.vscode/settings.json +0 -0
  16. {rclone_api-1.0.78 → rclone_api-1.0.80}/.vscode/tasks.json +0 -0
  17. {rclone_api-1.0.78 → rclone_api-1.0.80}/LICENSE +0 -0
  18. {rclone_api-1.0.78 → rclone_api-1.0.80}/MANIFEST.in +0 -0
  19. {rclone_api-1.0.78 → rclone_api-1.0.80}/README.md +0 -0
  20. {rclone_api-1.0.78 → rclone_api-1.0.80}/clean +0 -0
  21. {rclone_api-1.0.78 → rclone_api-1.0.80}/install +0 -0
  22. {rclone_api-1.0.78 → rclone_api-1.0.80}/lint +0 -0
  23. {rclone_api-1.0.78 → rclone_api-1.0.80}/requirements.testing.txt +0 -0
  24. {rclone_api-1.0.78 → rclone_api-1.0.80}/setup.cfg +0 -0
  25. {rclone_api-1.0.78 → rclone_api-1.0.80}/setup.py +0 -0
  26. {rclone_api-1.0.78 → rclone_api-1.0.80}/src/rclone_api/__init__.py +0 -0
  27. {rclone_api-1.0.78 → rclone_api-1.0.80}/src/rclone_api/assets/example.txt +0 -0
  28. {rclone_api-1.0.78 → rclone_api-1.0.80}/src/rclone_api/cli.py +0 -0
  29. {rclone_api-1.0.78 → rclone_api-1.0.80}/src/rclone_api/cmd/list_files.py +0 -0
  30. {rclone_api-1.0.78 → rclone_api-1.0.80}/src/rclone_api/completed_process.py +0 -0
  31. {rclone_api-1.0.78 → rclone_api-1.0.80}/src/rclone_api/config.py +0 -0
  32. {rclone_api-1.0.78 → rclone_api-1.0.80}/src/rclone_api/convert.py +0 -0
  33. {rclone_api-1.0.78 → rclone_api-1.0.80}/src/rclone_api/deprecated.py +0 -0
  34. {rclone_api-1.0.78 → rclone_api-1.0.80}/src/rclone_api/diff.py +0 -0
  35. {rclone_api-1.0.78 → rclone_api-1.0.80}/src/rclone_api/dir.py +0 -0
  36. {rclone_api-1.0.78 → rclone_api-1.0.80}/src/rclone_api/dir_listing.py +0 -0
  37. {rclone_api-1.0.78 → rclone_api-1.0.80}/src/rclone_api/exec.py +0 -0
  38. {rclone_api-1.0.78 → rclone_api-1.0.80}/src/rclone_api/file.py +0 -0
  39. {rclone_api-1.0.78 → rclone_api-1.0.80}/src/rclone_api/filelist.py +0 -0
  40. {rclone_api-1.0.78 → rclone_api-1.0.80}/src/rclone_api/process.py +0 -0
  41. {rclone_api-1.0.78 → rclone_api-1.0.80}/src/rclone_api/remote.py +0 -0
  42. {rclone_api-1.0.78 → rclone_api-1.0.80}/src/rclone_api/rpath.py +0 -0
  43. {rclone_api-1.0.78 → rclone_api-1.0.80}/src/rclone_api/scan_missing_folders.py +0 -0
  44. {rclone_api-1.0.78 → rclone_api-1.0.80}/src/rclone_api/types.py +0 -0
  45. {rclone_api-1.0.78 → rclone_api-1.0.80}/src/rclone_api/util.py +0 -0
  46. {rclone_api-1.0.78 → rclone_api-1.0.80}/src/rclone_api/walk.py +0 -0
  47. {rclone_api-1.0.78 → rclone_api-1.0.80}/src/rclone_api.egg-info/SOURCES.txt +0 -0
  48. {rclone_api-1.0.78 → rclone_api-1.0.80}/src/rclone_api.egg-info/dependency_links.txt +0 -0
  49. {rclone_api-1.0.78 → rclone_api-1.0.80}/src/rclone_api.egg-info/entry_points.txt +0 -0
  50. {rclone_api-1.0.78 → rclone_api-1.0.80}/src/rclone_api.egg-info/requires.txt +0 -0
  51. {rclone_api-1.0.78 → rclone_api-1.0.80}/src/rclone_api.egg-info/top_level.txt +0 -0
  52. {rclone_api-1.0.78 → rclone_api-1.0.80}/test +0 -0
  53. {rclone_api-1.0.78 → rclone_api-1.0.80}/tests/test_cmd_list_files.py +0 -0
  54. {rclone_api-1.0.78 → rclone_api-1.0.80}/tests/test_copy.py +0 -0
  55. {rclone_api-1.0.78 → rclone_api-1.0.80}/tests/test_copy_files.py +0 -0
  56. {rclone_api-1.0.78 → rclone_api-1.0.80}/tests/test_diff.py +0 -0
  57. {rclone_api-1.0.78 → rclone_api-1.0.80}/tests/test_group_files.py +0 -0
  58. {rclone_api-1.0.78 → rclone_api-1.0.80}/tests/test_is_synced.py +0 -0
  59. {rclone_api-1.0.78 → rclone_api-1.0.80}/tests/test_ls.py +0 -0
  60. {rclone_api-1.0.78 → rclone_api-1.0.80}/tests/test_mount.py +0 -0
  61. {rclone_api-1.0.78 → rclone_api-1.0.80}/tests/test_mount_s3.py +0 -0
  62. {rclone_api-1.0.78 → rclone_api-1.0.80}/tests/test_mount_webdav.py +0 -0
  63. {rclone_api-1.0.78 → rclone_api-1.0.80}/tests/test_obscure.py +0 -0
  64. {rclone_api-1.0.78 → rclone_api-1.0.80}/tests/test_remote_control.py +0 -0
  65. {rclone_api-1.0.78 → rclone_api-1.0.80}/tests/test_remotes.py +0 -0
  66. {rclone_api-1.0.78 → rclone_api-1.0.80}/tests/test_scan_missing_folders.py +0 -0
  67. {rclone_api-1.0.78 → rclone_api-1.0.80}/tests/test_serve_webdav.py +0 -0
  68. {rclone_api-1.0.78 → rclone_api-1.0.80}/tests/test_walk.py +0 -0
  69. {rclone_api-1.0.78 → rclone_api-1.0.80}/tox.ini +0 -0
  70. {rclone_api-1.0.78 → rclone_api-1.0.80}/upload_package.sh +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: rclone_api
3
- Version: 1.0.78
3
+ Version: 1.0.80
4
4
  Summary: rclone api in python
5
5
  Home-page: https://github.com/zackees/rclone-api
6
6
  Maintainer: Zachary Vorhies
@@ -15,7 +15,7 @@ dependencies = [
15
15
  "python-dotenv>=1.0.0",
16
16
  ]
17
17
  # Change this with the version number bump.
18
- version = "1.0.78"
18
+ version = "1.0.80"
19
19
 
20
20
  [tool.setuptools]
21
21
  package-dir = {"" = "src"}
@@ -1,4 +1,11 @@
1
1
  from dataclasses import dataclass
2
+ from pathlib import Path
3
+
4
+
5
+ @dataclass
6
+ class PrefixResult:
7
+ prefix: str
8
+ files: list[str]
2
9
 
3
10
 
4
11
  @dataclass
@@ -178,23 +185,6 @@ def group_files(files: list[str], fully_qualified: bool = True) -> dict[str, lis
178
185
  return out
179
186
 
180
187
 
181
- def group_under_remote(
182
- files: list[str], fully_qualified: bool = True
183
- ) -> dict[str, list[str]]:
184
- """split between filename and remote"""
185
-
186
- #### DOE STHIS NEED TO BE REMOVEDD????? #####
187
-
188
- assert fully_qualified is True, "Not implemented for fully_qualified=False"
189
- out: dict[str, list[str]] = {}
190
- for file in files:
191
- parsed = parse_file(file)
192
- remote = f"{parsed.remote}:"
193
- file_list = out.setdefault(remote, [])
194
- file_list.append(parsed.to_string(include_remote=False, include_bucket=True))
195
- return out
196
-
197
-
198
188
  def group_under_remote_bucket(
199
189
  files: list[str], fully_qualified: bool = True
200
190
  ) -> dict[str, list[str]]:
@@ -212,4 +202,52 @@ def group_under_remote_bucket(
212
202
  return out
213
203
 
214
204
 
215
- __all__ = ["group_files", "group_under_remote", "group_under_remote_bucket"]
205
+ def _get_prefix(path: str) -> tuple[str, str] | None:
206
+ path_path: Path = Path(path)
207
+ parts = path_path.parts
208
+ if len(parts) == 1:
209
+ return None
210
+ return parts[0], "/".join(parts[1:])
211
+
212
+
213
+ def _common_prefix(prefix: str, files: list[str]) -> PrefixResult:
214
+ if not files:
215
+ return PrefixResult(prefix=prefix, files=[])
216
+ prefix = prefix
217
+ tmp: list[str] = list(files)
218
+ while True:
219
+ if not tmp:
220
+ break
221
+ prefix_set: set[str | None] = set()
222
+ for file in tmp:
223
+ pair = _get_prefix(file)
224
+ if pair is None:
225
+ break
226
+ _prefix, _ = pair
227
+ prefix_set.add(_prefix)
228
+ if len(prefix_set) > 1 or len(prefix_set) == 0:
229
+ break
230
+ next_prefix: str | None = prefix_set.pop()
231
+ if next_prefix is None:
232
+ break
233
+ prefix += f"/{next_prefix}"
234
+ new_tmp: list[str] = []
235
+ for file in tmp:
236
+ pair = _get_prefix(file)
237
+ assert pair is not None
238
+ _, path = pair
239
+ new_tmp.append(path)
240
+ tmp = new_tmp
241
+ return PrefixResult(prefix=prefix, files=tmp)
242
+
243
+
244
+ def group_under_one_prefix(prefix: str, files: list[str]) -> tuple[str, list[str]]:
245
+ """Group files under one prefix."""
246
+ if not files:
247
+ return prefix, []
248
+ prefix = prefix
249
+ result = _common_prefix(prefix, files)
250
+ return result.prefix, result.files
251
+
252
+
253
+ __all__ = ["group_files", "group_under_remote_bucket", "group_under_one_prefix"]
@@ -22,10 +22,7 @@ from rclone_api.diff import DiffItem, DiffOption, diff_stream_from_running_proce
22
22
  from rclone_api.dir_listing import DirListing
23
23
  from rclone_api.exec import RcloneExec
24
24
  from rclone_api.file import File
25
- from rclone_api.group_files import (
26
- group_files,
27
- group_under_remote_bucket,
28
- )
25
+ from rclone_api.group_files import group_files, group_under_one_prefix
29
26
  from rclone_api.process import Process
30
27
  from rclone_api.remote import Remote
31
28
  from rclone_api.rpath import RPath
@@ -849,44 +846,39 @@ class Rclone:
849
846
  verbose = get_verbose(verbose)
850
847
  check = get_check(check)
851
848
  files = list(files)
852
- prefix = src if src.endswith(":") else f"{src}/"
853
- if src:
854
- files = [f"{prefix}{f}" for f in files]
855
- file_list: dict[str, list[str]]
856
- file_list = group_under_remote_bucket(files)
857
849
  all_files: list[File] = []
858
- for src_path, files in file_list.items():
859
- cmd = ["lsjson", src_path, "--files-only", "-R"]
860
- with TemporaryDirectory() as tmpdir:
861
- # print("files: " + ",".join(files))
862
- include_files_txt = Path(tmpdir) / "include_files.txt"
863
- include_files_txt.write_text("\n".join(files), encoding="utf-8")
864
- cmd += ["--files-from", str(include_files_txt)]
865
- if fast_list:
866
- cmd.append("--fast-list")
867
- if other_args:
868
- cmd += other_args
869
- cp = self._run(cmd, check=check)
870
-
871
- if cp.returncode != 0:
872
- if check:
873
- raise ValueError(f"Error getting file sizes: {cp.stderr}")
874
- else:
875
- warnings.warn(f"Error getting file sizes: {cp.stderr}")
876
- stdout = cp.stdout
877
- pieces = src_path.split(":", 1)
878
- remote_name = pieces[0]
879
- parent_path: str | None
880
- if len(pieces) > 1:
881
- parent_path = pieces[1]
850
+ src, files = group_under_one_prefix(src, files)
851
+ cmd = ["lsjson", src, "--files-only", "-R"]
852
+ with TemporaryDirectory() as tmpdir:
853
+ # print("files: " + ",".join(files))
854
+ include_files_txt = Path(tmpdir) / "include_files.txt"
855
+ include_files_txt.write_text("\n".join(files), encoding="utf-8")
856
+ cmd += ["--files-from", str(include_files_txt)]
857
+ if fast_list:
858
+ cmd.append("--fast-list")
859
+ if other_args:
860
+ cmd += other_args
861
+ cp = self._run(cmd, check=check)
862
+
863
+ if cp.returncode != 0:
864
+ if check:
865
+ raise ValueError(f"Error getting file sizes: {cp.stderr}")
882
866
  else:
883
- parent_path = None
884
- remote = Remote(name=remote_name, rclone=self)
885
- paths: list[RPath] = RPath.from_json_str(
886
- stdout, remote, parent_path=parent_path
887
- )
888
- # print(paths)
889
- all_files += [File(p) for p in paths]
867
+ warnings.warn(f"Error getting file sizes: {cp.stderr}")
868
+ stdout = cp.stdout
869
+ pieces = src.split(":", 1)
870
+ remote_name = pieces[0]
871
+ parent_path: str | None
872
+ if len(pieces) > 1:
873
+ parent_path = pieces[1]
874
+ else:
875
+ parent_path = None
876
+ remote = Remote(name=remote_name, rclone=self)
877
+ paths: list[RPath] = RPath.from_json_str(
878
+ stdout, remote, parent_path=parent_path
879
+ )
880
+ # print(paths)
881
+ all_files += [File(p) for p in paths]
890
882
  file_sizes: dict[str, int] = {}
891
883
  f: File
892
884
  for f in all_files:
@@ -903,9 +895,9 @@ class Rclone:
903
895
  for path, size in file_sizes.items():
904
896
  # remove the prefix
905
897
  path_path = Path(path)
906
- path_str = path_path.relative_to(prefix).as_posix()
898
+ path_str = path_path.relative_to(src).as_posix()
907
899
  file_sizes_path_corrected[path_str] = size
908
900
  out: SizeResult = SizeResult(
909
- prefix=prefix, total_size=total_size, file_sizes=file_sizes_path_corrected
901
+ prefix=src, total_size=total_size, file_sizes=file_sizes_path_corrected
910
902
  )
911
903
  return out
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: rclone_api
3
- Version: 1.0.78
3
+ Version: 1.0.80
4
4
  Summary: rclone api in python
5
5
  Home-page: https://github.com/zackees/rclone-api
6
6
  Maintainer: Zachary Vorhies
@@ -64,18 +64,11 @@ class RcloneSizeFilesTester(unittest.TestCase):
64
64
  src = f"dst:{BUCKET_NAME}"
65
65
  for dirlisting in rclone.walk(src, max_depth=1):
66
66
  if is_first:
67
- # assert just one file
68
- # assert len(dirlisting.files) == 1
69
67
  self.assertEqual(len(dirlisting.files), 1)
70
- # assert it's first.txt
71
68
  self.assertEqual(dirlisting.files[0].name, "first.txt")
72
69
  is_first = False
73
- # print(dirlisting)
74
70
  for file in dirlisting.files_relative(src):
75
71
  files.append(file)
76
-
77
- # print(files)
78
-
79
72
  size_map: SizeResult = rclone.size_files(src=src, files=files, check=True)
80
73
  print(size_map)
81
74
  print("done")
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes