lfss 0.12.0__tar.gz → 0.12.2__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.
- {lfss-0.12.0 → lfss-0.12.2}/PKG-INFO +10 -11
- {lfss-0.12.0 → lfss-0.12.2}/Readme.md +1 -1
- {lfss-0.12.0 → lfss-0.12.2}/docs/Client.md +1 -2
- {lfss-0.12.0 → lfss-0.12.2}/docs/changelog.md +8 -0
- {lfss-0.12.0 → lfss-0.12.2}/lfss/api/connector.py +2 -2
- {lfss-0.12.0 → lfss-0.12.2}/lfss/cli/__init__.py +4 -7
- {lfss-0.12.0 → lfss-0.12.2}/lfss/cli/cli.py +70 -22
- lfss-0.12.2/lfss/cli/cli_lib.py +64 -0
- {lfss-0.12.0 → lfss-0.12.2}/lfss/eng/utils.py +5 -1
- {lfss-0.12.0 → lfss-0.12.2}/pyproject.toml +11 -10
- {lfss-0.12.0 → lfss-0.12.2}/docs/Enviroment_variables.md +0 -0
- {lfss-0.12.0 → lfss-0.12.2}/docs/Known_issues.md +0 -0
- {lfss-0.12.0 → lfss-0.12.2}/docs/Permission.md +0 -0
- {lfss-0.12.0 → lfss-0.12.2}/docs/Webdav.md +0 -0
- {lfss-0.12.0 → lfss-0.12.2}/frontend/api.js +0 -0
- {lfss-0.12.0 → lfss-0.12.2}/frontend/index.html +0 -0
- {lfss-0.12.0 → lfss-0.12.2}/frontend/info.css +0 -0
- {lfss-0.12.0 → lfss-0.12.2}/frontend/info.js +0 -0
- {lfss-0.12.0 → lfss-0.12.2}/frontend/login.css +0 -0
- {lfss-0.12.0 → lfss-0.12.2}/frontend/login.js +0 -0
- {lfss-0.12.0 → lfss-0.12.2}/frontend/popup.css +0 -0
- {lfss-0.12.0 → lfss-0.12.2}/frontend/popup.js +0 -0
- {lfss-0.12.0 → lfss-0.12.2}/frontend/scripts.js +0 -0
- {lfss-0.12.0 → lfss-0.12.2}/frontend/state.js +0 -0
- {lfss-0.12.0 → lfss-0.12.2}/frontend/styles.css +0 -0
- {lfss-0.12.0 → lfss-0.12.2}/frontend/thumb.css +0 -0
- {lfss-0.12.0 → lfss-0.12.2}/frontend/thumb.js +0 -0
- {lfss-0.12.0 → lfss-0.12.2}/frontend/utils.js +0 -0
- {lfss-0.12.0 → lfss-0.12.2}/lfss/api/__init__.py +0 -0
- {lfss-0.12.0 → lfss-0.12.2}/lfss/cli/balance.py +0 -0
- {lfss-0.12.0 → lfss-0.12.2}/lfss/cli/log.py +0 -0
- {lfss-0.12.0 → lfss-0.12.2}/lfss/cli/panel.py +0 -0
- {lfss-0.12.0 → lfss-0.12.2}/lfss/cli/serve.py +0 -0
- {lfss-0.12.0 → lfss-0.12.2}/lfss/cli/user.py +0 -0
- {lfss-0.12.0 → lfss-0.12.2}/lfss/cli/vacuum.py +0 -0
- {lfss-0.12.0 → lfss-0.12.2}/lfss/eng/__init__.py +0 -0
- {lfss-0.12.0 → lfss-0.12.2}/lfss/eng/bounded_pool.py +0 -0
- {lfss-0.12.0 → lfss-0.12.2}/lfss/eng/config.py +0 -0
- {lfss-0.12.0 → lfss-0.12.2}/lfss/eng/connection_pool.py +0 -0
- {lfss-0.12.0 → lfss-0.12.2}/lfss/eng/database.py +0 -0
- {lfss-0.12.0 → lfss-0.12.2}/lfss/eng/datatype.py +0 -0
- {lfss-0.12.0 → lfss-0.12.2}/lfss/eng/error.py +0 -0
- {lfss-0.12.0 → lfss-0.12.2}/lfss/eng/log.py +0 -0
- {lfss-0.12.0 → lfss-0.12.2}/lfss/eng/thumb.py +0 -0
- {lfss-0.12.0 → lfss-0.12.2}/lfss/sql/init.sql +0 -0
- {lfss-0.12.0 → lfss-0.12.2}/lfss/sql/pragma.sql +0 -0
- {lfss-0.12.0 → lfss-0.12.2}/lfss/svc/app.py +0 -0
- {lfss-0.12.0 → lfss-0.12.2}/lfss/svc/app_base.py +0 -0
- {lfss-0.12.0 → lfss-0.12.2}/lfss/svc/app_dav.py +0 -0
- {lfss-0.12.0 → lfss-0.12.2}/lfss/svc/app_native.py +0 -0
- {lfss-0.12.0 → lfss-0.12.2}/lfss/svc/common_impl.py +0 -0
- {lfss-0.12.0 → lfss-0.12.2}/lfss/svc/request_log.py +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: lfss
|
3
|
-
Version: 0.12.
|
3
|
+
Version: 0.12.2
|
4
4
|
Summary: Lite file storage service
|
5
5
|
Home-page: https://github.com/MenxLi/lfss
|
6
6
|
Author: Li, Mengxun
|
@@ -10,16 +10,15 @@ Classifier: Programming Language :: Python :: 3
|
|
10
10
|
Classifier: Programming Language :: Python :: 3.10
|
11
11
|
Classifier: Programming Language :: Python :: 3.11
|
12
12
|
Classifier: Programming Language :: Python :: 3.12
|
13
|
-
|
14
|
-
Requires-Dist:
|
15
|
-
Requires-Dist:
|
16
|
-
Requires-Dist:
|
17
|
-
Requires-Dist:
|
18
|
-
Requires-Dist:
|
13
|
+
Provides-Extra: all
|
14
|
+
Requires-Dist: aiofiles (==24.*) ; extra == "all"
|
15
|
+
Requires-Dist: aiosqlite (==0.*) ; extra == "all"
|
16
|
+
Requires-Dist: fastapi[standard] (==0.*) ; extra == "all"
|
17
|
+
Requires-Dist: mimesniff (==1.*) ; extra == "all"
|
18
|
+
Requires-Dist: pillow ; extra == "all"
|
19
19
|
Requires-Dist: requests (==2.*)
|
20
|
-
Requires-Dist: rich
|
21
|
-
Requires-Dist: stream-zip (==0.*)
|
22
|
-
Requires-Dist: uvicorn (==0.*)
|
20
|
+
Requires-Dist: rich ; extra == "all"
|
21
|
+
Requires-Dist: stream-zip (==0.*) ; extra == "all"
|
23
22
|
Project-URL: Repository, https://github.com/MenxLi/lfss
|
24
23
|
Description-Content-Type: text/markdown
|
25
24
|
|
@@ -41,7 +40,7 @@ Tested on 2 million files, and it is still fast.
|
|
41
40
|
|
42
41
|
Usage:
|
43
42
|
```sh
|
44
|
-
pip install lfss
|
43
|
+
pip install "lfss[all]"
|
45
44
|
lfss-user add <username> <password>
|
46
45
|
lfss-serve
|
47
46
|
```
|
@@ -1,5 +1,13 @@
|
|
1
1
|
## 0.12
|
2
2
|
|
3
|
+
### 0.12.2
|
4
|
+
- Setup optional dependencies
|
5
|
+
- Present only the name by default for CLI list command
|
6
|
+
|
7
|
+
### 0.12.1
|
8
|
+
- Add `cat` command
|
9
|
+
- Use unicode icons for CLI list command
|
10
|
+
|
3
11
|
### 0.12.0
|
4
12
|
- Change default script to client CLI
|
5
13
|
- Client CLI default to verbose output
|
@@ -212,12 +212,12 @@ class Connector:
|
|
212
212
|
if response is None: return None
|
213
213
|
return response.content
|
214
214
|
|
215
|
-
def get_stream(self, path: str) -> Iterator[bytes]:
|
215
|
+
def get_stream(self, path: str, chunk_size = 1024) -> Iterator[bytes]:
|
216
216
|
"""Downloads a file from the specified path, will raise PathNotFoundError if path not found."""
|
217
217
|
path = _p(path)
|
218
218
|
response = self._get(path, stream=True)
|
219
219
|
if response is None: raise PathNotFoundError("Path not found: " + path)
|
220
|
-
return response.iter_content(chunk_size
|
220
|
+
return response.iter_content(chunk_size)
|
221
221
|
|
222
222
|
def get_json(self, path: str) -> Optional[dict]:
|
223
223
|
path = _p(path)
|
@@ -16,16 +16,13 @@ def catch_request_error(error_code_handler: Optional[ dict[int, Callable[[reques
|
|
16
16
|
print(f"\033[91m[Error message]: {e.response.text}\033[0m")
|
17
17
|
|
18
18
|
T = TypeVar('T')
|
19
|
-
def line_sep(iter: Iterable[T], enable=True, start=True, end=True, color="\033[90m") -> Generator[T, None, None]:
|
19
|
+
def line_sep(iter: Iterable[T], enable=True, start=True, end=True, middle=False, color="\033[90m") -> Generator[T, None, None]:
|
20
20
|
screen_width = os.get_terminal_size().columns
|
21
21
|
def print_ln():
|
22
22
|
if enable: print(color + "-" * screen_width + "\033[0m")
|
23
23
|
|
24
|
-
if start:
|
25
|
-
print_ln()
|
24
|
+
if start: print_ln()
|
26
25
|
for i, line in enumerate(iter):
|
27
|
-
if i > 0:
|
28
|
-
print_ln()
|
26
|
+
if i > 0 and middle: print_ln()
|
29
27
|
yield line
|
30
|
-
if end:
|
31
|
-
print_ln()
|
28
|
+
if end: print_ln()
|
@@ -1,12 +1,15 @@
|
|
1
1
|
from pathlib import Path
|
2
2
|
import argparse, typing, sys
|
3
3
|
from lfss.api import Connector, upload_directory, upload_file, download_file, download_directory
|
4
|
-
from lfss.eng.datatype import
|
4
|
+
from lfss.eng.datatype import (
|
5
|
+
FileReadPermission, AccessLevel,
|
6
|
+
FileSortKey, DirSortKey,
|
7
|
+
FileRecord, DirectoryRecord, PathContents
|
8
|
+
)
|
5
9
|
from lfss.eng.utils import decode_uri_components, fmt_storage_size
|
6
|
-
from . import catch_request_error, line_sep as _line_sep
|
7
10
|
|
8
|
-
|
9
|
-
|
11
|
+
from . import catch_request_error, line_sep
|
12
|
+
from .cli_lib import mimetype_unicode, stream_text
|
10
13
|
|
11
14
|
def parse_permission(s: str) -> FileReadPermission:
|
12
15
|
for p in FileReadPermission:
|
@@ -25,6 +28,50 @@ def default_error_handler_dict(path: str):
|
|
25
28
|
404: lambda _: print(f"\033[31mNot found\033[0m ({path})", file=sys.stderr),
|
26
29
|
409: lambda _: print(f"\033[31mConflict\033[0m ({path})", file=sys.stderr),
|
27
30
|
}
|
31
|
+
def print_path_list(
|
32
|
+
path_list: list[FileRecord] | list[DirectoryRecord] | PathContents,
|
33
|
+
detailed: bool = False
|
34
|
+
):
|
35
|
+
dirs: list[DirectoryRecord]
|
36
|
+
files: list[FileRecord]
|
37
|
+
if isinstance(path_list, PathContents):
|
38
|
+
dirs = path_list.dirs
|
39
|
+
files = path_list.files
|
40
|
+
else:
|
41
|
+
dirs = [p for p in path_list if isinstance(p, DirectoryRecord)]
|
42
|
+
files = [p for p in path_list if isinstance(p, FileRecord)]
|
43
|
+
# check if terminal supports unicode
|
44
|
+
supports_unicode = sys.stdout.encoding.lower().startswith("utf")
|
45
|
+
def print_ln(r: DirectoryRecord | FileRecord):
|
46
|
+
nonlocal detailed, supports_unicode
|
47
|
+
match (r, supports_unicode):
|
48
|
+
case (DirectoryRecord(), True):
|
49
|
+
print(mimetype_unicode(r), end=" ")
|
50
|
+
case (DirectoryRecord(), False):
|
51
|
+
print("[D]", end=" ")
|
52
|
+
case (FileRecord(), True):
|
53
|
+
print(mimetype_unicode(r), end=" ")
|
54
|
+
case (FileRecord(), False):
|
55
|
+
print("[F]", end=" ")
|
56
|
+
case _:
|
57
|
+
print("[?]", end=" ")
|
58
|
+
# if not detailed, only print name
|
59
|
+
if not detailed:
|
60
|
+
if isinstance(r, DirectoryRecord):
|
61
|
+
assert r.url.endswith("/")
|
62
|
+
print(decode_uri_components(r.url).rstrip("/").split("/")[-1], end="/")
|
63
|
+
else:
|
64
|
+
print(decode_uri_components(r.url).split("/")[-1], end="")
|
65
|
+
else:
|
66
|
+
print(decode_uri_components(r.url), end="")
|
67
|
+
if isinstance(r, FileRecord):
|
68
|
+
print(f" :: {fmt_storage_size(r.file_size)} {r.permission.name}", end="")
|
69
|
+
print()
|
70
|
+
|
71
|
+
for d in line_sep(dirs, end=False):
|
72
|
+
print_ln(d)
|
73
|
+
for f in line_sep(files, start=False):
|
74
|
+
print_ln(f)
|
28
75
|
|
29
76
|
def parse_arguments():
|
30
77
|
parser = argparse.ArgumentParser(description="Client-side command line interface, set LFSS_ENDPOINT and LFSS_TOKEN environment variables for authentication.")
|
@@ -74,7 +121,7 @@ def parse_arguments():
|
|
74
121
|
sp_list.add_argument("path", help="Path to list", type=str)
|
75
122
|
sp_list.add_argument("--offset", type=int, default=0, help="Offset of the list")
|
76
123
|
sp_list.add_argument("--limit", type=int, default=100, help="Limit of the list")
|
77
|
-
sp_list.add_argument("-l", "--long", action="store_true", help="Detailed list
|
124
|
+
sp_list.add_argument("-l", "--long", action="store_true", help="Detailed list")
|
78
125
|
sp_list.add_argument("--order", "--order-by", type=str, help="Order of the list", default="", choices=typing.get_args(FileSortKey))
|
79
126
|
sp_list.add_argument("--reverse", "--order-desc", action="store_true", help="Reverse the list order")
|
80
127
|
|
@@ -83,7 +130,7 @@ def parse_arguments():
|
|
83
130
|
sp_list_d.add_argument("path", help="Path to list", type=str)
|
84
131
|
sp_list_d.add_argument("--offset", type=int, default=0, help="Offset of the list")
|
85
132
|
sp_list_d.add_argument("--limit", type=int, default=100, help="Limit of the list")
|
86
|
-
sp_list_d.add_argument("-l", "--long", action="store_true", help="Detailed list
|
133
|
+
sp_list_d.add_argument("-l", "--long", action="store_true", help="Detailed list")
|
87
134
|
sp_list_d.add_argument("--order", "--order-by", type=str, help="Order of the list", default="", choices=typing.get_args(DirSortKey))
|
88
135
|
sp_list_d.add_argument("--reverse", "--order-desc", action="store_true", help="Reverse the list order")
|
89
136
|
|
@@ -93,10 +140,14 @@ def parse_arguments():
|
|
93
140
|
sp_list_f.add_argument("--offset", type=int, default=0, help="Offset of the list")
|
94
141
|
sp_list_f.add_argument("--limit", type=int, default=100, help="Limit of the list")
|
95
142
|
sp_list_f.add_argument("-r", "--recursive", "--flat", action="store_true", help="List files recursively")
|
96
|
-
sp_list_f.add_argument("-l", "--long", action="store_true", help="Detailed list
|
143
|
+
sp_list_f.add_argument("-l", "--long", action="store_true", help="Detailed list")
|
97
144
|
sp_list_f.add_argument("--order", "--order-by", type=str, help="Order of the list", default="", choices=typing.get_args(FileSortKey))
|
98
145
|
sp_list_f.add_argument("--reverse", "--order-desc", action="store_true", help="Reverse the list order")
|
99
146
|
|
147
|
+
# show content
|
148
|
+
sp_show = sp.add_parser("concatenate", help="Concatenate and print files", aliases=["cat"])
|
149
|
+
sp_show.add_argument("path", help="Path to the text files", type=str, nargs="+")
|
150
|
+
sp_show.add_argument("-e", "--encoding", type=str, default="utf-8", help="Text file encoding, default utf-8")
|
100
151
|
return parser.parse_args()
|
101
152
|
|
102
153
|
def main():
|
@@ -213,13 +264,7 @@ def main():
|
|
213
264
|
order_by=args.order,
|
214
265
|
order_desc=args.reverse,
|
215
266
|
)
|
216
|
-
|
217
|
-
d.url = decode_uri_components(d.url)
|
218
|
-
print(f"[d{i+1}] {d if args.long else d.url}")
|
219
|
-
for i, f in enumerate(line_sep(res.files)):
|
220
|
-
f.url = decode_uri_components(f.url)
|
221
|
-
print(f"[f{i+1}] {f if args.long else f.url}")
|
222
|
-
|
267
|
+
print_path_list(res, detailed=args.long)
|
223
268
|
if len(res.dirs) + len(res.files) == args.limit:
|
224
269
|
print(f"\033[33m[Warning] List limit reached, use --offset and --limit to list more items.\033[0m")
|
225
270
|
|
@@ -233,10 +278,7 @@ def main():
|
|
233
278
|
order_by=args.order,
|
234
279
|
order_desc=args.reverse,
|
235
280
|
)
|
236
|
-
|
237
|
-
f.url = decode_uri_components(f.url)
|
238
|
-
print(f"[{i+1}] {f if args.long else f.url}")
|
239
|
-
|
281
|
+
print_path_list(res, detailed=args.long)
|
240
282
|
if len(res) == args.limit:
|
241
283
|
print(f"\033[33m[Warning] List limit reached, use --offset and --limit to list more files.\033[0m")
|
242
284
|
|
@@ -250,13 +292,19 @@ def main():
|
|
250
292
|
order_by=args.order,
|
251
293
|
order_desc=args.reverse,
|
252
294
|
)
|
253
|
-
|
254
|
-
d.url = decode_uri_components(d.url)
|
255
|
-
print(f"[{i+1}] {d if args.long else d.url}")
|
256
|
-
|
295
|
+
print_path_list(res, detailed=args.long)
|
257
296
|
if len(res) == args.limit:
|
258
297
|
print(f"\033[33m[Warning] List limit reached, use --offset and --limit to list more directories.\033[0m")
|
259
298
|
|
299
|
+
elif args.command in ["cat", "concatenate"]:
|
300
|
+
for _p in args.path:
|
301
|
+
with catch_request_error(default_error_handler_dict(_p)):
|
302
|
+
try:
|
303
|
+
for chunk in stream_text(connector, _p, encoding=args.encoding):
|
304
|
+
print(chunk, end="")
|
305
|
+
except (FileNotFoundError, ValueError) as e:
|
306
|
+
print(f"\033[31m{e}\033[0m", file=sys.stderr)
|
307
|
+
|
260
308
|
else:
|
261
309
|
raise NotImplementedError(f"Command {args.command} not implemented.")
|
262
310
|
|
@@ -0,0 +1,64 @@
|
|
1
|
+
|
2
|
+
from ..api.connector import Connector
|
3
|
+
from ..eng.datatype import DirectoryRecord, FileRecord
|
4
|
+
|
5
|
+
def mimetype_unicode(r: DirectoryRecord | FileRecord):
|
6
|
+
if isinstance(r, DirectoryRecord):
|
7
|
+
return "📁"
|
8
|
+
if r.mime_type in ["application/pdf", "application/x-pdf"]:
|
9
|
+
return "📕"
|
10
|
+
elif r.mime_type.startswith("image/"):
|
11
|
+
return "🖼️"
|
12
|
+
elif r.mime_type.startswith("video/"):
|
13
|
+
return "🎞️"
|
14
|
+
elif r.mime_type.startswith("audio/"):
|
15
|
+
return "🎵"
|
16
|
+
elif r.mime_type in ["application/zip", "application/x-tar", "application/gzip", "application/x-7z-compressed"]:
|
17
|
+
return "📦"
|
18
|
+
elif r.mime_type in ["application/vnd.ms-excel", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"]:
|
19
|
+
return "📊"
|
20
|
+
elif r.mime_type in ["application/x-msdownload", "application/x-executable", "application/x-mach-binary", "application/x-elf"]:
|
21
|
+
return "💻"
|
22
|
+
elif r.mime_type in ["application/vnd.ms-powerpoint", "application/vnd.openxmlformats-officedocument.presentationml.presentation"]:
|
23
|
+
return "📈"
|
24
|
+
elif r.mime_type in set([
|
25
|
+
"text/html", "application/xhtml+xml", "application/xml", "text/css", "text/x-scss", "application/javascript", "text/javascript",
|
26
|
+
"application/json", "text/x-yaml", "text/x-markdown", "application/wasm",
|
27
|
+
"text/x-ruby", "application/x-ruby", "text/x-perl", "application/x-lisp",
|
28
|
+
"text/x-haskell", "text/x-lua", "application/x-tcl",
|
29
|
+
"text/x-python", "text/x-java-source", "text/x-go", "application/x-rust", "text/x-asm",
|
30
|
+
"application/sql", "text/x-c", "text/x-c++", "text/x-csharp",
|
31
|
+
"application/x-httpd-php", "application/x-sh", "application/x-shellscript",
|
32
|
+
"application/x-latex", "application/x-tex",
|
33
|
+
]):
|
34
|
+
return "👨💻"
|
35
|
+
elif r.mime_type.startswith("text/"):
|
36
|
+
return "📃"
|
37
|
+
return "📄"
|
38
|
+
|
39
|
+
def stream_text(
|
40
|
+
conn: Connector,
|
41
|
+
path: str,
|
42
|
+
encoding="utf-8",
|
43
|
+
chunk_size=1024 * 8,
|
44
|
+
):
|
45
|
+
"""
|
46
|
+
Stream text content of a file from the server.
|
47
|
+
Raise FileNotFoundError if the file does not exist.
|
48
|
+
Raise ValueError if the file size exceeds MAX_TEXT_SIZE.
|
49
|
+
|
50
|
+
Yields str chunks.
|
51
|
+
"""
|
52
|
+
MAX_TEXT_SIZE = 100 * 1024 * 1024 # 100 MB
|
53
|
+
r = conn.get_fmeta(path)
|
54
|
+
if r is None:
|
55
|
+
raise FileNotFoundError(f"File not found: {path}")
|
56
|
+
if r.file_size > MAX_TEXT_SIZE:
|
57
|
+
raise ValueError(f"File size {r.file_size} exceeds maximum text size {MAX_TEXT_SIZE}")
|
58
|
+
ss = conn.get_stream(r.url, chunk_size=chunk_size)
|
59
|
+
total_read = 0
|
60
|
+
for chunk in ss:
|
61
|
+
total_read += len(chunk)
|
62
|
+
if total_read > MAX_TEXT_SIZE:
|
63
|
+
raise ValueError(f"File size exceeds maximum text size {MAX_TEXT_SIZE}")
|
64
|
+
yield chunk.decode(encoding, errors='replace') # decode bytes to str, replace errors
|
@@ -3,7 +3,6 @@ import urllib.parse
|
|
3
3
|
import pathlib
|
4
4
|
import functools
|
5
5
|
import hashlib
|
6
|
-
import aiofiles
|
7
6
|
import asyncio
|
8
7
|
from asyncio import Lock
|
9
8
|
from collections import OrderedDict
|
@@ -11,6 +10,11 @@ from concurrent.futures import ThreadPoolExecutor
|
|
11
10
|
from typing import TypeVar, Callable, Awaitable
|
12
11
|
from functools import wraps, partial
|
13
12
|
from uuid import uuid4
|
13
|
+
try:
|
14
|
+
# optional dependency for client-side
|
15
|
+
import aiofiles
|
16
|
+
except ImportError:
|
17
|
+
pass
|
14
18
|
|
15
19
|
async def copy_file(source: str|pathlib.Path, destination: str|pathlib.Path):
|
16
20
|
async with aiofiles.open(source, mode='rb') as src:
|
@@ -1,6 +1,6 @@
|
|
1
1
|
[tool.poetry]
|
2
2
|
name = "lfss"
|
3
|
-
version = "0.12.
|
3
|
+
version = "0.12.2"
|
4
4
|
description = "Lite file storage service"
|
5
5
|
authors = ["Li, Mengxun <mengxunli@whu.edu.cn>"]
|
6
6
|
readme = "Readme.md"
|
@@ -11,15 +11,16 @@ include = ["Readme.md", "docs/*", "frontend/*", "lfss/sql/*"]
|
|
11
11
|
[tool.poetry.dependencies]
|
12
12
|
python = ">=3.10" # PEP-622
|
13
13
|
requests = "2.*"
|
14
|
-
aiosqlite = "0.*"
|
15
|
-
aiofiles = "24.*"
|
16
|
-
mimesniff = "1.*"
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
14
|
+
aiosqlite = {"version" = "0.*", "optional" = true}
|
15
|
+
aiofiles = {"version" = "24.*", "optional" = true}
|
16
|
+
mimesniff = {"version" = "1.*", "optional" = true}
|
17
|
+
stream-zip = {"version" = "0.*", "optional" = true}
|
18
|
+
pillow = {"version" = "*", "optional" = true}
|
19
|
+
rich = {"version" = "*", "optional" = true}
|
20
|
+
fastapi = {"version" = "0.*", "optional" = true, "extras" = ["standard"]}
|
21
|
+
|
22
|
+
[tool.poetry.extras]
|
23
|
+
all = ["aiosqlite", "aiofiles", "mimesniff", "fastapi", "stream-zip", "pillow", "rich"]
|
23
24
|
|
24
25
|
[tool.poetry.dev-dependencies]
|
25
26
|
pytest = "*"
|
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
|
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
|
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
|
File without changes
|
File without changes
|
File without changes
|