rclone-api 1.5.34__py3-none-any.whl → 1.5.35__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/config.py +153 -120
- {rclone_api-1.5.34.dist-info → rclone_api-1.5.35.dist-info}/METADATA +1 -1
- {rclone_api-1.5.34.dist-info → rclone_api-1.5.35.dist-info}/RECORD +7 -7
- {rclone_api-1.5.34.dist-info → rclone_api-1.5.35.dist-info}/WHEEL +0 -0
- {rclone_api-1.5.34.dist-info → rclone_api-1.5.35.dist-info}/entry_points.txt +0 -0
- {rclone_api-1.5.34.dist-info → rclone_api-1.5.35.dist-info}/licenses/LICENSE +0 -0
- {rclone_api-1.5.34.dist-info → rclone_api-1.5.35.dist-info}/top_level.txt +0 -0
rclone_api/config.py
CHANGED
@@ -1,120 +1,153 @@
|
|
1
|
-
import os
|
2
|
-
from dataclasses import dataclass, field
|
3
|
-
from pathlib import Path
|
4
|
-
from typing import Any, Dict, List
|
5
|
-
|
6
|
-
|
7
|
-
@dataclass
|
8
|
-
class Section:
|
9
|
-
name: str
|
10
|
-
data: Dict[str, str] = field(default_factory=dict)
|
11
|
-
|
12
|
-
def add(self, key: str, value: str) -> None:
|
13
|
-
self.data[key] = value
|
14
|
-
|
15
|
-
def type(self) -> str:
|
16
|
-
return self.data["type"]
|
17
|
-
|
18
|
-
def provider(self) -> str | None:
|
19
|
-
return self.data.get("provider")
|
20
|
-
|
21
|
-
def access_key_id(self) -> str:
|
22
|
-
if "access_key_id" in self.data:
|
23
|
-
return self.data["access_key_id"]
|
24
|
-
elif "account" in self.data:
|
25
|
-
return self.data["account"]
|
26
|
-
raise KeyError("No access key found")
|
27
|
-
|
28
|
-
def secret_access_key(self) -> str:
|
29
|
-
# return self.data["secret_access_key"]
|
30
|
-
if "secret_access_key" in self.data:
|
31
|
-
return self.data["secret_access_key"]
|
32
|
-
elif "key" in self.data:
|
33
|
-
return self.data["key"]
|
34
|
-
raise KeyError("No secret access key found")
|
35
|
-
|
36
|
-
def endpoint(self) -> str | None:
|
37
|
-
return self.data.get("endpoint")
|
38
|
-
|
39
|
-
|
40
|
-
@dataclass
|
41
|
-
class Parsed:
|
42
|
-
# sections: List[ParsedSection]
|
43
|
-
sections: dict[str, Section]
|
44
|
-
|
45
|
-
@staticmethod
|
46
|
-
def parse(content: str) -> "Parsed":
|
47
|
-
return parse_rclone_config(content)
|
48
|
-
|
49
|
-
|
50
|
-
@dataclass
|
51
|
-
class Config:
|
52
|
-
"""Rclone configuration dataclass."""
|
53
|
-
|
54
|
-
text: str
|
55
|
-
|
56
|
-
def parse(self) -> Parsed:
|
57
|
-
return Parsed.parse(self.text)
|
58
|
-
|
59
|
-
|
60
|
-
def find_conf_file(rclone: Any | None = None) -> Path | None:
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
#
|
67
|
-
#
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
if
|
72
|
-
return
|
73
|
-
if
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
1
|
+
import os
|
2
|
+
from dataclasses import dataclass, field
|
3
|
+
from pathlib import Path
|
4
|
+
from typing import Any, Dict, List
|
5
|
+
|
6
|
+
|
7
|
+
@dataclass
|
8
|
+
class Section:
|
9
|
+
name: str
|
10
|
+
data: Dict[str, str] = field(default_factory=dict)
|
11
|
+
|
12
|
+
def add(self, key: str, value: str) -> None:
|
13
|
+
self.data[key] = value
|
14
|
+
|
15
|
+
def type(self) -> str:
|
16
|
+
return self.data["type"]
|
17
|
+
|
18
|
+
def provider(self) -> str | None:
|
19
|
+
return self.data.get("provider")
|
20
|
+
|
21
|
+
def access_key_id(self) -> str:
|
22
|
+
if "access_key_id" in self.data:
|
23
|
+
return self.data["access_key_id"]
|
24
|
+
elif "account" in self.data:
|
25
|
+
return self.data["account"]
|
26
|
+
raise KeyError("No access key found")
|
27
|
+
|
28
|
+
def secret_access_key(self) -> str:
|
29
|
+
# return self.data["secret_access_key"]
|
30
|
+
if "secret_access_key" in self.data:
|
31
|
+
return self.data["secret_access_key"]
|
32
|
+
elif "key" in self.data:
|
33
|
+
return self.data["key"]
|
34
|
+
raise KeyError("No secret access key found")
|
35
|
+
|
36
|
+
def endpoint(self) -> str | None:
|
37
|
+
return self.data.get("endpoint")
|
38
|
+
|
39
|
+
|
40
|
+
@dataclass
|
41
|
+
class Parsed:
|
42
|
+
# sections: List[ParsedSection]
|
43
|
+
sections: dict[str, Section]
|
44
|
+
|
45
|
+
@staticmethod
|
46
|
+
def parse(content: str) -> "Parsed":
|
47
|
+
return parse_rclone_config(content)
|
48
|
+
|
49
|
+
|
50
|
+
@dataclass
|
51
|
+
class Config:
|
52
|
+
"""Rclone configuration dataclass."""
|
53
|
+
|
54
|
+
text: str
|
55
|
+
|
56
|
+
def parse(self) -> Parsed:
|
57
|
+
return Parsed.parse(self.text)
|
58
|
+
|
59
|
+
|
60
|
+
def find_conf_file(rclone: Any | None = None) -> Path | None:
|
61
|
+
import subprocess
|
62
|
+
|
63
|
+
from rclone_api import Rclone
|
64
|
+
from rclone_api.rclone_impl import RcloneImpl
|
65
|
+
|
66
|
+
# if os.environ.get("RCLONE_CONFIG"):
|
67
|
+
# return Path(os.environ["RCLONE_CONFIG"])
|
68
|
+
# return None
|
69
|
+
# rclone_conf = rclone_conf or Path.cwd() / "rclone.conf"
|
70
|
+
|
71
|
+
if os.environ.get("RCLONE_CONFIG"):
|
72
|
+
return Path(os.environ["RCLONE_CONFIG"])
|
73
|
+
if (conf := Path.cwd() / "rclone.conf").exists():
|
74
|
+
return conf
|
75
|
+
|
76
|
+
if rclone is None:
|
77
|
+
from rclone_api.install import rclone_download
|
78
|
+
|
79
|
+
err = rclone_download(Path("."))
|
80
|
+
if isinstance(err, Exception):
|
81
|
+
import warnings
|
82
|
+
|
83
|
+
warnings.warn(f"rclone_download failed: {err}")
|
84
|
+
return None
|
85
|
+
cmd_list: list[str] = [
|
86
|
+
"rclone",
|
87
|
+
"config",
|
88
|
+
"paths",
|
89
|
+
]
|
90
|
+
subproc: subprocess.CompletedProcess = subprocess.run(
|
91
|
+
args=cmd_list,
|
92
|
+
shell=True,
|
93
|
+
capture_output=True,
|
94
|
+
text=True,
|
95
|
+
)
|
96
|
+
if subproc.returncode == 0:
|
97
|
+
stdout = subproc.stdout
|
98
|
+
for line in stdout.splitlines():
|
99
|
+
parts = line.split(":", 1)
|
100
|
+
if len(parts) == 2:
|
101
|
+
_, value = parts
|
102
|
+
value = value.strip()
|
103
|
+
value_path = Path(value.strip())
|
104
|
+
if value_path.exists():
|
105
|
+
return value_path
|
106
|
+
else:
|
107
|
+
if isinstance(rclone, Rclone):
|
108
|
+
rclone = rclone.impl
|
109
|
+
else:
|
110
|
+
assert isinstance(rclone, RcloneImpl)
|
111
|
+
rclone_impl: RcloneImpl = rclone
|
112
|
+
assert isinstance(rclone_impl, RcloneImpl)
|
113
|
+
paths_or_err = rclone_impl.config_paths()
|
114
|
+
if isinstance(paths_or_err, Exception):
|
115
|
+
return None
|
116
|
+
paths = paths_or_err
|
117
|
+
path: Path
|
118
|
+
for path in paths:
|
119
|
+
if path.exists():
|
120
|
+
return path
|
121
|
+
return None
|
122
|
+
|
123
|
+
|
124
|
+
def parse_rclone_config(content: str) -> Parsed:
|
125
|
+
"""
|
126
|
+
Parses an rclone configuration file and returns a list of RcloneConfigSection objects.
|
127
|
+
|
128
|
+
Each section in the file starts with a line like [section_name]
|
129
|
+
followed by key=value pairs.
|
130
|
+
"""
|
131
|
+
sections: List[Section] = []
|
132
|
+
current_section: Section | None = None
|
133
|
+
|
134
|
+
lines = content.splitlines()
|
135
|
+
for line in lines:
|
136
|
+
line = line.strip()
|
137
|
+
# Skip empty lines and comments (assumed to start with '#' or ';')
|
138
|
+
if not line or line.startswith(("#", ";")):
|
139
|
+
continue
|
140
|
+
# New section header detected
|
141
|
+
if line.startswith("[") and line.endswith("]"):
|
142
|
+
section_name = line[1:-1].strip()
|
143
|
+
current_section = Section(name=section_name)
|
144
|
+
sections.append(current_section)
|
145
|
+
elif "=" in line and current_section is not None:
|
146
|
+
# Parse key and value, splitting only on the first '=' found
|
147
|
+
key, value = line.split("=", 1)
|
148
|
+
current_section.add(key.strip(), value.strip())
|
149
|
+
|
150
|
+
data: dict[str, Section] = {}
|
151
|
+
for section in sections:
|
152
|
+
data[section.name] = section
|
153
|
+
return Parsed(sections=data)
|
@@ -1,7 +1,7 @@
|
|
1
1
|
rclone_api/__init__.py,sha256=KxOU2UGnoqw1EDHwugFTHHgccfhq22trGiRDwX5Dsng,34086
|
2
2
|
rclone_api/cli.py,sha256=dibfAZIh0kXWsBbfp3onKLjyZXo54mTzDjUdzJlDlWo,231
|
3
3
|
rclone_api/completed_process.py,sha256=_IZ8IWK7DM1_tsbDEkH6wPZ-bbcrgf7A7smls854pmg,1775
|
4
|
-
rclone_api/config.py,sha256=
|
4
|
+
rclone_api/config.py,sha256=tahrSngQIX56jutiyMdk-TVmK8lMrLJ5H5rDsdFQRtM,4743
|
5
5
|
rclone_api/convert.py,sha256=Mx9Qo7zhkOedJd8LdhPvNGHp8znJzOk4f_2KWnoGc78,1012
|
6
6
|
rclone_api/deprecated.py,sha256=qWKpnZdYcBK7YQZKuVoWWXDwi-uqiAtbjgPcci_efow,590
|
7
7
|
rclone_api/diff.py,sha256=tMoJMAGmLSE6Q_7QhPf6PnCzb840djxMZtDmhc2GlGQ,5227
|
@@ -54,9 +54,9 @@ rclone_api/s3/multipart/upload_parts_inline.py,sha256=V7syKjFyVIe4U9Ahl5XgqVTzt9
|
|
54
54
|
rclone_api/s3/multipart/upload_parts_resumable.py,sha256=6-nlMclS8jyVvMvFbQDcZOX9MY1WbCcKA_s9bwuYxnk,9793
|
55
55
|
rclone_api/s3/multipart/upload_parts_server_side_merge.py,sha256=Fp2pdrs5dONQI9LkfNolgAGj1-Z2V1SsRd0r0sreuXI,18040
|
56
56
|
rclone_api/s3/multipart/upload_state.py,sha256=f-Aq2NqtAaMUMhYitlICSNIxCKurWAl2gDEUVizLIqw,6019
|
57
|
-
rclone_api-1.5.
|
58
|
-
rclone_api-1.5.
|
59
|
-
rclone_api-1.5.
|
60
|
-
rclone_api-1.5.
|
61
|
-
rclone_api-1.5.
|
62
|
-
rclone_api-1.5.
|
57
|
+
rclone_api-1.5.35.dist-info/licenses/LICENSE,sha256=b6pOoifSXiUaz_lDS84vWlG3fr4yUKwB8fzkrH9R8bQ,1064
|
58
|
+
rclone_api-1.5.35.dist-info/METADATA,sha256=bb59EsCikl2fAIPakFqltagrSVQdumz2Ip7KZTgHpHA,37155
|
59
|
+
rclone_api-1.5.35.dist-info/WHEEL,sha256=1tXe9gY0PYatrMPMDd6jXqjfpz_B-Wqm32CPfRC58XU,91
|
60
|
+
rclone_api-1.5.35.dist-info/entry_points.txt,sha256=fJteOlYVwgX3UbNuL9jJ0zUTuX2O79JFAeNgK7Sw7EQ,255
|
61
|
+
rclone_api-1.5.35.dist-info/top_level.txt,sha256=EvZ7uuruUpe9RiUyEp25d1Keq7PWYNT0O_-mr8FCG5g,11
|
62
|
+
rclone_api-1.5.35.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|