Compare commits
5 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
428be1289c
|
|||
|
4283481695
|
|||
|
ddb4300d85
|
|||
|
68670a6588
|
|||
| 6d8fd0a598 |
@@ -18,6 +18,32 @@ Create remote host configuration
|
|||||||
mdrs config create neurodata https://neurodata.riken.jp/api
|
mdrs config create neurodata https://neurodata.riken.jp/api
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### config update
|
||||||
|
|
||||||
|
Update the URL of a registered remote host.
|
||||||
|
|
||||||
|
```shell
|
||||||
|
mdrs config update neurodata https://neurodata.riken.jp/api
|
||||||
|
```
|
||||||
|
|
||||||
|
### config list
|
||||||
|
|
||||||
|
List registered remote hosts.
|
||||||
|
|
||||||
|
```shell
|
||||||
|
mdrs config list
|
||||||
|
mdrs config ls
|
||||||
|
```
|
||||||
|
|
||||||
|
### config delete
|
||||||
|
|
||||||
|
Remove a registered remote host.
|
||||||
|
|
||||||
|
```shell
|
||||||
|
mdrs config delete neurodata
|
||||||
|
mdrs config rm neurodata
|
||||||
|
```
|
||||||
|
|
||||||
### login
|
### login
|
||||||
|
|
||||||
Login to remote host
|
Login to remote host
|
||||||
@@ -150,6 +176,14 @@ mdrs file-metadata neurodata:/NIU/Repository/TEST/dataset/sample.dat
|
|||||||
mdrs file-metadata -p SHARING_PASSWORD neurodata:/NIU/Repository/PW_Open/Readme.txt
|
mdrs file-metadata -p SHARING_PASSWORD neurodata:/NIU/Repository/PW_Open/Readme.txt
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### version
|
||||||
|
|
||||||
|
Show the tool name and version number
|
||||||
|
|
||||||
|
```shell
|
||||||
|
mdrs version
|
||||||
|
```
|
||||||
|
|
||||||
### help
|
### help
|
||||||
|
|
||||||
Show the help message and exit
|
Show the help message and exit
|
||||||
|
|||||||
@@ -1 +0,0 @@
|
|||||||
1.3.13
|
|
||||||
@@ -17,6 +17,7 @@ from mdrsclient.commands import (
|
|||||||
MvCommand,
|
MvCommand,
|
||||||
RmCommand,
|
RmCommand,
|
||||||
UploadCommand,
|
UploadCommand,
|
||||||
|
VersionCommand,
|
||||||
WhoamiCommand,
|
WhoamiCommand,
|
||||||
)
|
)
|
||||||
from mdrsclient.exceptions import MDRSException
|
from mdrsclient.exceptions import MDRSException
|
||||||
@@ -29,6 +30,7 @@ def main() -> None:
|
|||||||
parsers = parser.add_subparsers(title="subcommands")
|
parsers = parser.add_subparsers(title="subcommands")
|
||||||
|
|
||||||
ConfigCommand.register(parsers)
|
ConfigCommand.register(parsers)
|
||||||
|
VersionCommand.register(parsers)
|
||||||
LoginCommand.register(parsers)
|
LoginCommand.register(parsers)
|
||||||
LogoutCommand.register(parsers)
|
LogoutCommand.register(parsers)
|
||||||
WhoamiCommand.register(parsers)
|
WhoamiCommand.register(parsers)
|
||||||
|
|||||||
@@ -1,8 +1,5 @@
|
|||||||
import os
|
from importlib.metadata import version
|
||||||
|
|
||||||
here = os.path.realpath(os.path.dirname(__file__))
|
__version__ = version("mdrs-client-python")
|
||||||
|
|
||||||
with open(os.path.join(here, "VERSION")) as version_file:
|
|
||||||
__version__ = version_file.read().strip()
|
|
||||||
|
|
||||||
__all__ = ["__version__"]
|
__all__ = ["__version__"]
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import mimetypes
|
import mimetypes
|
||||||
import os
|
import os
|
||||||
from typing import Any, Final
|
from typing import Any, Final
|
||||||
|
from unicodedata import normalize
|
||||||
|
|
||||||
from pydantic import TypeAdapter
|
from pydantic import TypeAdapter
|
||||||
from pydantic.dataclasses import dataclass
|
from pydantic.dataclasses import dataclass
|
||||||
@@ -53,7 +54,7 @@ class FilesApi(BaseApi):
|
|||||||
try:
|
try:
|
||||||
with open(os.path.realpath(path), mode="rb") as fp:
|
with open(os.path.realpath(path), mode="rb") as fp:
|
||||||
data = MultipartEncoder(
|
data = MultipartEncoder(
|
||||||
fields={"folder_id": folder_id, "file": (os.path.basename(path), fp, self._get_mime_type(path))}
|
fields={"folder_id": folder_id, "file": (normalize("NFC", os.path.basename(path)), fp, self._get_mime_type(path))}
|
||||||
)
|
)
|
||||||
response = self.connection.post(url, data=data, headers={"Content-Type": data.content_type})
|
response = self.connection.post(url, data=data, headers={"Content-Type": data.content_type})
|
||||||
self._raise_response_error(response)
|
self._raise_response_error(response)
|
||||||
@@ -75,7 +76,7 @@ class FilesApi(BaseApi):
|
|||||||
# update file body
|
# update file body
|
||||||
try:
|
try:
|
||||||
with open(os.path.realpath(path), mode="rb") as fp:
|
with open(os.path.realpath(path), mode="rb") as fp:
|
||||||
data = MultipartEncoder(fields={"file": (os.path.basename(path), fp, self._get_mime_type(path))})
|
data = MultipartEncoder(fields={"file": (normalize("NFC", os.path.basename(path)), fp, self._get_mime_type(path))})
|
||||||
response = self.connection.put(url, data=data, headers={"Content-Type": data.content_type})
|
response = self.connection.put(url, data=data, headers={"Content-Type": data.content_type})
|
||||||
except OSError:
|
except OSError:
|
||||||
raise UnexpectedException(f"Could not open `{path}` file.")
|
raise UnexpectedException(f"Could not open `{path}` file.")
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ from mdrsclient.commands.mkdir import MkdirCommand
|
|||||||
from mdrsclient.commands.mv import MvCommand
|
from mdrsclient.commands.mv import MvCommand
|
||||||
from mdrsclient.commands.rm import RmCommand
|
from mdrsclient.commands.rm import RmCommand
|
||||||
from mdrsclient.commands.upload import UploadCommand
|
from mdrsclient.commands.upload import UploadCommand
|
||||||
|
from mdrsclient.commands.version import VersionCommand
|
||||||
from mdrsclient.commands.whoami import WhoamiCommand
|
from mdrsclient.commands.whoami import WhoamiCommand
|
||||||
|
|
||||||
__all__ = [
|
__all__ = [
|
||||||
@@ -29,5 +30,6 @@ __all__ = [
|
|||||||
"MvCommand",
|
"MvCommand",
|
||||||
"RmCommand",
|
"RmCommand",
|
||||||
"UploadCommand",
|
"UploadCommand",
|
||||||
|
"VersionCommand",
|
||||||
"WhoamiCommand",
|
"WhoamiCommand",
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -26,10 +26,9 @@ class ConfigCommand(BaseCommand):
|
|||||||
update_parser.set_defaults(func=cls.func_update)
|
update_parser.set_defaults(func=cls.func_update)
|
||||||
# config list
|
# config list
|
||||||
list_parser = config_parsers.add_parser("list", help="list all the remote hosts", aliases=["ls"])
|
list_parser = config_parsers.add_parser("list", help="list all the remote hosts", aliases=["ls"])
|
||||||
list_parser.add_argument("-l", "--long", help="show the api url", action="store_true")
|
|
||||||
list_parser.set_defaults(func=cls.func_list)
|
list_parser.set_defaults(func=cls.func_list)
|
||||||
# config delete
|
# config delete
|
||||||
delete_parser = config_parsers.add_parser("delete", help="delete an existing remote host", aliases=["remove"])
|
delete_parser = config_parsers.add_parser("delete", help="delete an existing remote host", aliases=["remove", "rm"])
|
||||||
delete_parser.add_argument("remote", help="label of remote host")
|
delete_parser.add_argument("remote", help="label of remote host")
|
||||||
delete_parser.set_defaults(func=cls.func_delete)
|
delete_parser.set_defaults(func=cls.func_delete)
|
||||||
|
|
||||||
@@ -47,8 +46,7 @@ class ConfigCommand(BaseCommand):
|
|||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def func_list(cls, args: Namespace) -> None:
|
def func_list(cls, args: Namespace) -> None:
|
||||||
is_long = bool(args.long)
|
cls.list()
|
||||||
cls.list(is_long)
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def func_delete(cls, args: Namespace) -> None:
|
def func_delete(cls, args: Namespace) -> None:
|
||||||
@@ -74,13 +72,10 @@ class ConfigCommand(BaseCommand):
|
|||||||
config.url = url
|
config.url = url
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def list(cls, is_long: bool) -> None:
|
def list(cls) -> None:
|
||||||
config = ConfigFile("")
|
config = ConfigFile("")
|
||||||
for remote, url in config.list():
|
for remote, url in config.list():
|
||||||
line = f"{remote}:"
|
print(f"{remote}:\t{url}")
|
||||||
if is_long:
|
|
||||||
line += f"\t{url}"
|
|
||||||
print(line)
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def delete(cls, remote: str) -> None:
|
def delete(cls, remote: str) -> None:
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ class LsCommandContext:
|
|||||||
laboratory: Laboratory
|
laboratory: Laboratory
|
||||||
password: str
|
password: str
|
||||||
is_json: bool
|
is_json: bool
|
||||||
is_quick: bool
|
is_quiet: bool
|
||||||
is_recursive: bool
|
is_recursive: bool
|
||||||
|
|
||||||
|
|
||||||
@@ -35,7 +35,7 @@ class LsCommand(BaseCommand):
|
|||||||
ls_parser.add_argument("-J", "--json", help="turn on json output", action="store_true")
|
ls_parser.add_argument("-J", "--json", help="turn on json output", action="store_true")
|
||||||
ls_parser.add_argument(
|
ls_parser.add_argument(
|
||||||
"-q",
|
"-q",
|
||||||
"--quick",
|
"--quiet",
|
||||||
help="don't output header row. this option is forced if the -r option is specified",
|
help="don't output header row. this option is forced if the -r option is specified",
|
||||||
action="store_true",
|
action="store_true",
|
||||||
)
|
)
|
||||||
@@ -49,11 +49,11 @@ class LsCommand(BaseCommand):
|
|||||||
password = str(args.password) if args.password else None
|
password = str(args.password) if args.password else None
|
||||||
is_json = bool(args.json)
|
is_json = bool(args.json)
|
||||||
is_recursive = bool(args.recursive)
|
is_recursive = bool(args.recursive)
|
||||||
is_quick = bool(args.quick) if not is_recursive else True
|
is_quiet = bool(args.quiet) if not is_recursive else True
|
||||||
cls.ls(remote_path, password, is_json, is_recursive, is_quick)
|
cls.ls(remote_path, password, is_json, is_recursive, is_quiet)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def ls(cls, remote_path: str, password: str | None, is_json: bool, is_recursive: bool, is_quick: bool) -> None:
|
def ls(cls, remote_path: str, password: str | None, is_json: bool, is_recursive: bool, is_quiet: bool) -> None:
|
||||||
(remote, laboratory_name, r_path) = cls._parse_remote_host_with_path(remote_path)
|
(remote, laboratory_name, r_path) = cls._parse_remote_host_with_path(remote_path)
|
||||||
connection = cls._create_connection(remote)
|
connection = cls._create_connection(remote)
|
||||||
laboratory = cls._find_laboratory(connection, laboratory_name)
|
laboratory = cls._find_laboratory(connection, laboratory_name)
|
||||||
@@ -63,7 +63,7 @@ class LsCommand(BaseCommand):
|
|||||||
laboratory,
|
laboratory,
|
||||||
password if password is not None else "",
|
password if password is not None else "",
|
||||||
is_json,
|
is_json,
|
||||||
is_quick,
|
is_quiet,
|
||||||
is_recursive,
|
is_recursive,
|
||||||
)
|
)
|
||||||
folder = cls._find_folder(connection, laboratory, r_path, password)
|
folder = cls._find_folder(connection, laboratory, r_path, password)
|
||||||
@@ -89,7 +89,7 @@ class LsCommand(BaseCommand):
|
|||||||
}
|
}
|
||||||
length: dict[str, int] = {}
|
length: dict[str, int] = {}
|
||||||
for key in label.keys():
|
for key in label.keys():
|
||||||
length[key] = len(label[key]) if not context.is_quick else 0
|
length[key] = len(label[key]) if not context.is_quiet else 0
|
||||||
for sub_folder in folder.sub_folders:
|
for sub_folder in folder.sub_folders:
|
||||||
sub_laboratory = context.connection.laboratories.find_by_id(sub_folder.laboratory_id)
|
sub_laboratory = context.connection.laboratories.find_by_id(sub_folder.laboratory_id)
|
||||||
sub_laboratory_name = sub_laboratory.name if sub_laboratory is not None else "(invalid)"
|
sub_laboratory_name = sub_laboratory.name if sub_laboratory is not None else "(invalid)"
|
||||||
@@ -114,7 +114,7 @@ class LsCommand(BaseCommand):
|
|||||||
print(f"{context.prefix}{folder.path}:")
|
print(f"{context.prefix}{folder.path}:")
|
||||||
print(f"total {sum(f.size for f in files)}")
|
print(f"total {sum(f.size for f in files)}")
|
||||||
|
|
||||||
if not context.is_quick:
|
if not context.is_quiet:
|
||||||
print(header)
|
print(header)
|
||||||
print("-" * len(header.expandtabs()))
|
print("-" * len(header.expandtabs()))
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import os
|
|||||||
from argparse import Namespace
|
from argparse import Namespace
|
||||||
from concurrent.futures import ThreadPoolExecutor
|
from concurrent.futures import ThreadPoolExecutor
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
from unicodedata import normalize
|
||||||
|
|
||||||
from pydantic.dataclasses import dataclass
|
from pydantic.dataclasses import dataclass
|
||||||
|
|
||||||
@@ -81,7 +82,7 @@ class UploadCommand(BaseCommand):
|
|||||||
if folder_map.get(d_dirname) is None:
|
if folder_map.get(d_dirname) is None:
|
||||||
d_folder = folder_map[d_parent_dirname].find_sub_folder(d_basename)
|
d_folder = folder_map[d_parent_dirname].find_sub_folder(d_basename)
|
||||||
if d_folder is None:
|
if d_folder is None:
|
||||||
d_folder_id = folder_api.create(d_basename, folder_map[d_parent_dirname].id)
|
d_folder_id = folder_api.create(normalize("NFC", d_basename), folder_map[d_parent_dirname].id)
|
||||||
else:
|
else:
|
||||||
d_folder_id = d_folder.id
|
d_folder_id = d_folder.id
|
||||||
print(d_dirname)
|
print(d_dirname)
|
||||||
|
|||||||
@@ -0,0 +1,20 @@
|
|||||||
|
from argparse import Namespace
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
|
from mdrsclient.__version__ import __version__
|
||||||
|
from mdrsclient.commands.base import BaseCommand
|
||||||
|
|
||||||
|
|
||||||
|
class VersionCommand(BaseCommand):
|
||||||
|
@classmethod
|
||||||
|
def register(cls, parsers: Any) -> None:
|
||||||
|
version_parser = parsers.add_parser("version", help="show the version of this tool")
|
||||||
|
version_parser.set_defaults(func=cls.func)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def func(cls, args: Namespace) -> None:
|
||||||
|
cls.version()
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def version(cls) -> None:
|
||||||
|
print(f"mdrs {__version__}")
|
||||||
+3
-2
@@ -1,12 +1,12 @@
|
|||||||
[tool.poetry]
|
[tool.poetry]
|
||||||
name = "mdrs-client-python"
|
name = "mdrs-client-python"
|
||||||
version = "1.3.13"
|
version = "1.3.15"
|
||||||
description = "The mdrs-client-python is python library and a command-line client for up- and downloading files to and from MDRS based repository."
|
description = "The mdrs-client-python is python library and a command-line client for up- and downloading files to and from MDRS based repository."
|
||||||
authors = ["Yoshihiro OKUMURA <yoshihiro.okumura@riken.jp>"]
|
authors = ["Yoshihiro OKUMURA <yoshihiro.okumura@riken.jp>"]
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
classifiers=[
|
classifiers=[
|
||||||
"Development Status :: 3 - Alpha",
|
"Development Status :: 4 - Beta",
|
||||||
"Environment :: Console",
|
"Environment :: Console",
|
||||||
"Intended Audience :: Developers",
|
"Intended Audience :: Developers",
|
||||||
"Intended Audience :: Science/Research",
|
"Intended Audience :: Science/Research",
|
||||||
@@ -14,6 +14,7 @@ classifiers=[
|
|||||||
"Programming Language :: Python :: 3.11",
|
"Programming Language :: Python :: 3.11",
|
||||||
"Programming Language :: Python :: 3.12",
|
"Programming Language :: Python :: 3.12",
|
||||||
"Programming Language :: Python :: 3.13",
|
"Programming Language :: Python :: 3.13",
|
||||||
|
"Programming Language :: Python :: 3.14",
|
||||||
"OSI Approved :: MIT License",
|
"OSI Approved :: MIT License",
|
||||||
"Topic :: Utilities",
|
"Topic :: Utilities",
|
||||||
]
|
]
|
||||||
|
|||||||
Reference in New Issue
Block a user