rclone-api 1.5.37__py3-none-any.whl → 1.5.39__py3-none-any.whl
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.
- rclone_api/__init__.py +1003 -1003
- rclone_api/config.py +186 -153
- rclone_api/db/__init__.py +3 -3
- rclone_api/detail/walk.py +116 -116
- rclone_api/dir.py +113 -113
- rclone_api/http_server.py +1 -1
- rclone_api/log.py +44 -44
- rclone_api/rclone_impl.py +1360 -1360
- rclone_api/s3/multipart/upload_parts_server_side_merge.py +546 -546
- rclone_api/scan_missing_folders.py +153 -153
- {rclone_api-1.5.37.dist-info → rclone_api-1.5.39.dist-info}/METADATA +1100 -1100
- {rclone_api-1.5.37.dist-info → rclone_api-1.5.39.dist-info}/RECORD +16 -16
- {rclone_api-1.5.37.dist-info → rclone_api-1.5.39.dist-info}/WHEEL +0 -0
- {rclone_api-1.5.37.dist-info → rclone_api-1.5.39.dist-info}/entry_points.txt +0 -0
- {rclone_api-1.5.37.dist-info → rclone_api-1.5.39.dist-info}/licenses/LICENSE +0 -0
- {rclone_api-1.5.37.dist-info → rclone_api-1.5.39.dist-info}/top_level.txt +0 -0
rclone_api/dir.py
CHANGED
@@ -1,113 +1,113 @@
|
|
1
|
-
import json
|
2
|
-
from pathlib import Path
|
3
|
-
from typing import Generator
|
4
|
-
|
5
|
-
from rclone_api.dir_listing import DirListing
|
6
|
-
from rclone_api.remote import Remote
|
7
|
-
from rclone_api.rpath import RPath
|
8
|
-
from rclone_api.types import ListingOption, Order
|
9
|
-
|
10
|
-
|
11
|
-
class Dir:
|
12
|
-
"""Remote file dataclass."""
|
13
|
-
|
14
|
-
@property
|
15
|
-
def remote(self) -> Remote:
|
16
|
-
return self.path.remote
|
17
|
-
|
18
|
-
@property
|
19
|
-
def name(self) -> str:
|
20
|
-
return self.path.name
|
21
|
-
|
22
|
-
def __init__(self, path: RPath | Remote) -> None:
|
23
|
-
"""Initialize Dir with either an RPath or Remote.
|
24
|
-
|
25
|
-
Args:
|
26
|
-
path: Either an RPath object or a Remote object
|
27
|
-
"""
|
28
|
-
if isinstance(path, Remote):
|
29
|
-
# Need to create an RPath for the Remote's root
|
30
|
-
self.path = RPath(
|
31
|
-
remote=path,
|
32
|
-
path=str(path),
|
33
|
-
name=str(path),
|
34
|
-
size=0,
|
35
|
-
mime_type="inode/directory",
|
36
|
-
mod_time="",
|
37
|
-
is_dir=True,
|
38
|
-
)
|
39
|
-
# Ensure the RPath has the same rclone instance as the Remote
|
40
|
-
self.path.set_rclone(path.rclone)
|
41
|
-
else:
|
42
|
-
self.path = path
|
43
|
-
# self.path.set_rclone(self.path.remote.rclone)
|
44
|
-
assert self.path.rclone is not None
|
45
|
-
|
46
|
-
def ls(
|
47
|
-
self,
|
48
|
-
max_depth: int | None = None,
|
49
|
-
glob: str | None = None,
|
50
|
-
order: Order = Order.NORMAL,
|
51
|
-
listing_option: ListingOption = ListingOption.ALL,
|
52
|
-
) -> DirListing:
|
53
|
-
"""List files and directories in the given path."""
|
54
|
-
assert self.path.rclone is not None
|
55
|
-
dir = Dir(self.path)
|
56
|
-
return self.path.rclone.ls(
|
57
|
-
dir,
|
58
|
-
max_depth=max_depth,
|
59
|
-
glob=glob,
|
60
|
-
order=order,
|
61
|
-
listing_option=listing_option,
|
62
|
-
)
|
63
|
-
|
64
|
-
def relative_to(self, other: "Dir") -> str:
|
65
|
-
"""Return the relative path to the other directory."""
|
66
|
-
self_path = Path(self.path.path)
|
67
|
-
other_path = Path(other.path.path)
|
68
|
-
rel_path = self_path.relative_to(other_path)
|
69
|
-
return str(rel_path.as_posix())
|
70
|
-
|
71
|
-
def walk(
|
72
|
-
self, breadth_first: bool, max_depth: int = -1
|
73
|
-
) -> Generator[DirListing, None, None]:
|
74
|
-
"""List files and directories in the given path."""
|
75
|
-
from rclone_api.detail.walk import walk
|
76
|
-
|
77
|
-
assert self.path.rclone is not None
|
78
|
-
return walk(self, breadth_first=breadth_first, max_depth=max_depth)
|
79
|
-
|
80
|
-
def to_json(self) -> dict:
|
81
|
-
"""Convert the Dir to a JSON serializable dictionary."""
|
82
|
-
return self.path.to_json()
|
83
|
-
|
84
|
-
def __str__(self) -> str:
|
85
|
-
return str(self.path)
|
86
|
-
|
87
|
-
def __repr__(self) -> str:
|
88
|
-
data = self.path.to_json()
|
89
|
-
data_str = json.dumps(data)
|
90
|
-
return data_str
|
91
|
-
|
92
|
-
def to_string(self, include_remote: bool = True) -> str:
|
93
|
-
"""Convert the File to a string."""
|
94
|
-
out = str(self.path)
|
95
|
-
if not include_remote:
|
96
|
-
_, out = out.split(":", 1)
|
97
|
-
return out
|
98
|
-
|
99
|
-
# / operator
|
100
|
-
def __truediv__(self, other: str) -> "Dir":
|
101
|
-
"""Join the current path with another path."""
|
102
|
-
path = Path(self.path.path) / other
|
103
|
-
rpath = RPath(
|
104
|
-
self.path.remote,
|
105
|
-
str(path.as_posix()),
|
106
|
-
name=other,
|
107
|
-
size=0,
|
108
|
-
mime_type="inode/directory",
|
109
|
-
mod_time="",
|
110
|
-
is_dir=True,
|
111
|
-
)
|
112
|
-
rpath.set_rclone(self.path.rclone)
|
113
|
-
return Dir(rpath)
|
1
|
+
import json
|
2
|
+
from pathlib import Path
|
3
|
+
from typing import Generator
|
4
|
+
|
5
|
+
from rclone_api.dir_listing import DirListing
|
6
|
+
from rclone_api.remote import Remote
|
7
|
+
from rclone_api.rpath import RPath
|
8
|
+
from rclone_api.types import ListingOption, Order
|
9
|
+
|
10
|
+
|
11
|
+
class Dir:
|
12
|
+
"""Remote file dataclass."""
|
13
|
+
|
14
|
+
@property
|
15
|
+
def remote(self) -> Remote:
|
16
|
+
return self.path.remote
|
17
|
+
|
18
|
+
@property
|
19
|
+
def name(self) -> str:
|
20
|
+
return self.path.name
|
21
|
+
|
22
|
+
def __init__(self, path: RPath | Remote) -> None:
|
23
|
+
"""Initialize Dir with either an RPath or Remote.
|
24
|
+
|
25
|
+
Args:
|
26
|
+
path: Either an RPath object or a Remote object
|
27
|
+
"""
|
28
|
+
if isinstance(path, Remote):
|
29
|
+
# Need to create an RPath for the Remote's root
|
30
|
+
self.path = RPath(
|
31
|
+
remote=path,
|
32
|
+
path=str(path),
|
33
|
+
name=str(path),
|
34
|
+
size=0,
|
35
|
+
mime_type="inode/directory",
|
36
|
+
mod_time="",
|
37
|
+
is_dir=True,
|
38
|
+
)
|
39
|
+
# Ensure the RPath has the same rclone instance as the Remote
|
40
|
+
self.path.set_rclone(path.rclone)
|
41
|
+
else:
|
42
|
+
self.path = path
|
43
|
+
# self.path.set_rclone(self.path.remote.rclone)
|
44
|
+
assert self.path.rclone is not None
|
45
|
+
|
46
|
+
def ls(
|
47
|
+
self,
|
48
|
+
max_depth: int | None = None,
|
49
|
+
glob: str | None = None,
|
50
|
+
order: Order = Order.NORMAL,
|
51
|
+
listing_option: ListingOption = ListingOption.ALL,
|
52
|
+
) -> DirListing:
|
53
|
+
"""List files and directories in the given path."""
|
54
|
+
assert self.path.rclone is not None
|
55
|
+
dir = Dir(self.path)
|
56
|
+
return self.path.rclone.ls(
|
57
|
+
dir,
|
58
|
+
max_depth=max_depth,
|
59
|
+
glob=glob,
|
60
|
+
order=order,
|
61
|
+
listing_option=listing_option,
|
62
|
+
)
|
63
|
+
|
64
|
+
def relative_to(self, other: "Dir") -> str:
|
65
|
+
"""Return the relative path to the other directory."""
|
66
|
+
self_path = Path(self.path.path)
|
67
|
+
other_path = Path(other.path.path)
|
68
|
+
rel_path = self_path.relative_to(other_path)
|
69
|
+
return str(rel_path.as_posix())
|
70
|
+
|
71
|
+
def walk(
|
72
|
+
self, breadth_first: bool, max_depth: int = -1
|
73
|
+
) -> Generator[DirListing, None, None]:
|
74
|
+
"""List files and directories in the given path."""
|
75
|
+
from rclone_api.detail.walk import walk
|
76
|
+
|
77
|
+
assert self.path.rclone is not None
|
78
|
+
return walk(self, breadth_first=breadth_first, max_depth=max_depth)
|
79
|
+
|
80
|
+
def to_json(self) -> dict:
|
81
|
+
"""Convert the Dir to a JSON serializable dictionary."""
|
82
|
+
return self.path.to_json()
|
83
|
+
|
84
|
+
def __str__(self) -> str:
|
85
|
+
return str(self.path)
|
86
|
+
|
87
|
+
def __repr__(self) -> str:
|
88
|
+
data = self.path.to_json()
|
89
|
+
data_str = json.dumps(data)
|
90
|
+
return data_str
|
91
|
+
|
92
|
+
def to_string(self, include_remote: bool = True) -> str:
|
93
|
+
"""Convert the File to a string."""
|
94
|
+
out = str(self.path)
|
95
|
+
if not include_remote:
|
96
|
+
_, out = out.split(":", 1)
|
97
|
+
return out
|
98
|
+
|
99
|
+
# / operator
|
100
|
+
def __truediv__(self, other: str) -> "Dir":
|
101
|
+
"""Join the current path with another path."""
|
102
|
+
path = Path(self.path.path) / other
|
103
|
+
rpath = RPath(
|
104
|
+
self.path.remote,
|
105
|
+
str(path.as_posix()),
|
106
|
+
name=other,
|
107
|
+
size=0,
|
108
|
+
mime_type="inode/directory",
|
109
|
+
mod_time="",
|
110
|
+
is_dir=True,
|
111
|
+
)
|
112
|
+
rpath.set_rclone(self.path.rclone)
|
113
|
+
return Dir(rpath)
|
rclone_api/http_server.py
CHANGED
@@ -150,7 +150,7 @@ class HttpServer:
|
|
150
150
|
response = httpx.get(url, timeout=_TIMEOUT)
|
151
151
|
response.raise_for_status()
|
152
152
|
files_and_dirs = _parse_files_and_dirs(response.content.decode())
|
153
|
-
return files_and_dirs.
|
153
|
+
return files_and_dirs.files, files_and_dirs.dirs
|
154
154
|
except Exception as e:
|
155
155
|
warnings.warn(f"Failed to list files on {self.url}: {e}")
|
156
156
|
return e
|
rclone_api/log.py
CHANGED
@@ -1,44 +1,44 @@
|
|
1
|
-
import logging
|
2
|
-
import sys
|
3
|
-
|
4
|
-
_INITIALISED = False
|
5
|
-
|
6
|
-
|
7
|
-
def setup_default_logging():
|
8
|
-
"""Set up default logging configuration if none exists."""
|
9
|
-
global _INITIALISED
|
10
|
-
if _INITIALISED:
|
11
|
-
return
|
12
|
-
if not logging.root.handlers:
|
13
|
-
logging.basicConfig(
|
14
|
-
level=logging.INFO,
|
15
|
-
format="%(asctime)s - %(name)s - %(levelname)s - %(message)s",
|
16
|
-
handlers=[
|
17
|
-
logging.StreamHandler(sys.stdout),
|
18
|
-
# Uncomment to add file logging
|
19
|
-
# logging.FileHandler('rclone_api.log')
|
20
|
-
],
|
21
|
-
)
|
22
|
-
|
23
|
-
|
24
|
-
def configure_logging(level=logging.INFO, log_file=None):
|
25
|
-
"""Configure logging for the rclone_api package.
|
26
|
-
|
27
|
-
Args:
|
28
|
-
level: The logging level (default: logging.INFO)
|
29
|
-
log_file: Optional path to a log file
|
30
|
-
"""
|
31
|
-
handlers = [logging.StreamHandler(sys.stdout)]
|
32
|
-
if log_file:
|
33
|
-
handlers.append(logging.FileHandler(log_file))
|
34
|
-
|
35
|
-
logging.basicConfig(
|
36
|
-
level=level,
|
37
|
-
format="%(asctime)s - %(name)s - %(levelname)s - %(message)s",
|
38
|
-
handlers=handlers,
|
39
|
-
force=True, # Override any existing configuration
|
40
|
-
)
|
41
|
-
|
42
|
-
|
43
|
-
# Call setup_default_logging when this module is imported
|
44
|
-
setup_default_logging()
|
1
|
+
import logging
|
2
|
+
import sys
|
3
|
+
|
4
|
+
_INITIALISED = False
|
5
|
+
|
6
|
+
|
7
|
+
def setup_default_logging():
|
8
|
+
"""Set up default logging configuration if none exists."""
|
9
|
+
global _INITIALISED
|
10
|
+
if _INITIALISED:
|
11
|
+
return
|
12
|
+
if not logging.root.handlers:
|
13
|
+
logging.basicConfig(
|
14
|
+
level=logging.INFO,
|
15
|
+
format="%(asctime)s - %(name)s - %(levelname)s - %(message)s",
|
16
|
+
handlers=[
|
17
|
+
logging.StreamHandler(sys.stdout),
|
18
|
+
# Uncomment to add file logging
|
19
|
+
# logging.FileHandler('rclone_api.log')
|
20
|
+
],
|
21
|
+
)
|
22
|
+
|
23
|
+
|
24
|
+
def configure_logging(level=logging.INFO, log_file=None):
|
25
|
+
"""Configure logging for the rclone_api package.
|
26
|
+
|
27
|
+
Args:
|
28
|
+
level: The logging level (default: logging.INFO)
|
29
|
+
log_file: Optional path to a log file
|
30
|
+
"""
|
31
|
+
handlers = [logging.StreamHandler(sys.stdout)]
|
32
|
+
if log_file:
|
33
|
+
handlers.append(logging.FileHandler(log_file))
|
34
|
+
|
35
|
+
logging.basicConfig(
|
36
|
+
level=level,
|
37
|
+
format="%(asctime)s - %(name)s - %(levelname)s - %(message)s",
|
38
|
+
handlers=handlers,
|
39
|
+
force=True, # Override any existing configuration
|
40
|
+
)
|
41
|
+
|
42
|
+
|
43
|
+
# Call setup_default_logging when this module is imported
|
44
|
+
setup_default_logging()
|