Compare commits
7 Commits
Author | SHA1 | Date | |
---|---|---|---|
ce0a608db2
|
|||
219858e0b6
|
|||
a281a97b3e
|
|||
64f64b82dc
|
|||
9284346153
|
|||
292ca1df27
|
|||
f10b42a1f2
|
17
.cspell.json
17
.cspell.json
@ -1,10 +1,15 @@
|
||||
{
|
||||
"version": "0.2",
|
||||
"language": "en,en-gb",
|
||||
"ignoreWords": ["getframe", "pydantic", "UNLCK"],
|
||||
"words": ["chacl", "mdrs", "mdrsclient", "neurodata", "Neuroinformatics", "RIKEN"],
|
||||
"ignorePaths": [
|
||||
".env",
|
||||
"__pycache__"
|
||||
]
|
||||
"ignoreWords": ["followlinks", "getframe", "pycache", "pydantic", "UNLCK"],
|
||||
"words": [
|
||||
"chacl",
|
||||
"kikan",
|
||||
"mdrs",
|
||||
"mdrsclient",
|
||||
"neurodata",
|
||||
"Neuroinformatics",
|
||||
"RIKEN"
|
||||
],
|
||||
"ignorePaths": [".env", "__pycache__"]
|
||||
}
|
||||
|
2
.vscode/settings.json
vendored
2
.vscode/settings.json
vendored
@ -1,7 +1,7 @@
|
||||
{
|
||||
"editor.formatOnSave": true,
|
||||
"editor.codeActionsOnSave": {
|
||||
"source.organizeImports": true
|
||||
"source.organizeImports": "explicit"
|
||||
},
|
||||
"[python]": {
|
||||
"editor.defaultFormatter": "ms-python.black-formatter"
|
||||
|
@ -1 +1 @@
|
||||
1.2.0
|
||||
1.3.1
|
||||
|
@ -1,11 +1,11 @@
|
||||
from mdrsclient.api.file import FileApi
|
||||
from mdrsclient.api.folder import FolderApi
|
||||
from mdrsclient.api.laboratory import LaboratoryApi
|
||||
from mdrsclient.api.user import UserApi
|
||||
from mdrsclient.api.files import FilesApi
|
||||
from mdrsclient.api.folders import FoldersApi
|
||||
from mdrsclient.api.laboratories import LaboratoriesApi
|
||||
from mdrsclient.api.users import UsersApi
|
||||
|
||||
__all__ = [
|
||||
"FileApi",
|
||||
"FolderApi",
|
||||
"LaboratoryApi",
|
||||
"UserApi",
|
||||
"FilesApi",
|
||||
"FoldersApi",
|
||||
"LaboratoriesApi",
|
||||
"UsersApi",
|
||||
]
|
||||
|
@ -1,3 +1,4 @@
|
||||
import os
|
||||
from typing import Any, Final
|
||||
|
||||
from pydantic import TypeAdapter
|
||||
@ -10,12 +11,12 @@ from mdrsclient.models import File
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class FileCreateResponse:
|
||||
class FilesApiCreateResponse:
|
||||
id: str
|
||||
|
||||
|
||||
class FileApi(BaseApi):
|
||||
ENTRYPOINT: Final[str] = "v2/file/"
|
||||
class FilesApi(BaseApi):
|
||||
ENTRYPOINT: Final[str] = "v3/files/"
|
||||
|
||||
def retrieve(self, id: str) -> File:
|
||||
# print(self.__class__.__name__ + "::" + sys._getframe().f_code.co_name)
|
||||
@ -31,10 +32,10 @@ class FileApi(BaseApi):
|
||||
token_check(self.connection)
|
||||
data: dict[str, str | int] = {"folder_id": folder_id}
|
||||
try:
|
||||
with open(path, mode="rb") as fp:
|
||||
with open(os.path.realpath(path), mode="rb") as fp:
|
||||
response = self.connection.post(url, data=data, files={"file": fp})
|
||||
self._raise_response_error(response)
|
||||
ret = TypeAdapter(FileCreateResponse).validate_python(response.json())
|
||||
ret = TypeAdapter(FilesApiCreateResponse).validate_python(response.json())
|
||||
except OSError:
|
||||
raise UnexpectedException(f"Could not open `{path}` file.")
|
||||
return ret.id
|
||||
@ -46,7 +47,7 @@ class FileApi(BaseApi):
|
||||
if path is not None:
|
||||
# update file body
|
||||
try:
|
||||
with open(path, mode="rb") as fp:
|
||||
with open(os.path.realpath(path), mode="rb") as fp:
|
||||
response = self.connection.put(url, files={"file": fp})
|
||||
except OSError:
|
||||
raise UnexpectedException(f"Could not open `{path}` file.")
|
||||
@ -93,7 +94,7 @@ class FileApi(BaseApi):
|
||||
|
||||
def download(self, file: File, path: str) -> bool:
|
||||
# print(self.__class__.__name__ + "::" + sys._getframe().f_code.co_name)
|
||||
url = "v2/" + file.download_url
|
||||
url = file.download_url
|
||||
response = self.connection.get(url, stream=True)
|
||||
self._raise_response_error(response)
|
||||
try:
|
@ -11,12 +11,12 @@ from mdrsclient.models import Folder, FolderSimple
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class FolderCreateResponse:
|
||||
class FoldersApiCreateResponse:
|
||||
id: str
|
||||
|
||||
|
||||
class FolderApi(BaseApi):
|
||||
ENTRYPOINT: Final[str] = "v2/folder/"
|
||||
class FoldersApi(BaseApi):
|
||||
ENTRYPOINT: Final[str] = "v3/folders/"
|
||||
|
||||
def list(self, laboratory_id: int, path: str) -> list[FolderSimple]:
|
||||
# print(self.__class__.__name__ + "::" + sys._getframe().f_code.co_name)
|
||||
@ -46,7 +46,7 @@ class FolderApi(BaseApi):
|
||||
token_check(self.connection)
|
||||
response = self.connection.post(url, data=data)
|
||||
self._raise_response_error(response)
|
||||
ret = TypeAdapter(FolderCreateResponse).validate_python(response.json())
|
||||
ret = TypeAdapter(FoldersApiCreateResponse).validate_python(response.json())
|
||||
return ret.id
|
||||
|
||||
def update(self, folder: FolderSimple) -> bool:
|
@ -7,8 +7,8 @@ from mdrsclient.api.utils import token_check
|
||||
from mdrsclient.models import Laboratories, Laboratory
|
||||
|
||||
|
||||
class LaboratoryApi(BaseApi):
|
||||
ENTRYPOINT: Final[str] = "v2/laboratory/"
|
||||
class LaboratoriesApi(BaseApi):
|
||||
ENTRYPOINT: Final[str] = "v3/laboratories/"
|
||||
|
||||
def list(self) -> Laboratories:
|
||||
# print(self.__class__.__name__ + "::" + sys._getframe().f_code.co_name)
|
@ -1,46 +0,0 @@
|
||||
from dataclasses import field
|
||||
from typing import Final
|
||||
|
||||
import requests
|
||||
from pydantic import TypeAdapter
|
||||
from pydantic.dataclasses import dataclass
|
||||
|
||||
from mdrsclient.api.base import BaseApi
|
||||
from mdrsclient.exceptions import UnauthorizedException
|
||||
from mdrsclient.models import Laboratory, Token, User
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class UserAuthResponse(Token):
|
||||
is_reviewer: bool | None = None
|
||||
laboratories: list[Laboratory] = field(default_factory=list)
|
||||
|
||||
|
||||
class UserApi(BaseApi):
|
||||
ENTRYPOINT: Final[str] = "v2/"
|
||||
|
||||
def auth(self, username: str, password: str) -> tuple[User, Token]:
|
||||
# print(self.__class__.__name__ + "::" + sys._getframe().f_code.co_name)
|
||||
url = self.ENTRYPOINT + "auth/"
|
||||
data: dict[str, str | int] = {"username": username, "password": password}
|
||||
response = self.connection.post(url, data=data)
|
||||
if response.status_code == requests.codes.unauthorized:
|
||||
raise UnauthorizedException("Invalid username or password.")
|
||||
self._raise_response_error(response)
|
||||
obj = TypeAdapter(UserAuthResponse).validate_python(response.json())
|
||||
token = Token(access=obj.access, refresh=obj.refresh)
|
||||
laboratory_ids = list(map(lambda x: x.id, obj.laboratories))
|
||||
is_reviewer = obj.is_reviewer if obj.is_reviewer is not None else False
|
||||
user = User(id=token.user_id, username=username, laboratory_ids=laboratory_ids, is_reviewer=is_reviewer)
|
||||
return (user, token)
|
||||
|
||||
def refresh(self, token: Token) -> Token:
|
||||
# print(self.__class__.__name__ + "::" + sys._getframe().f_code.co_name)
|
||||
url = self.ENTRYPOINT + "refresh/"
|
||||
data: dict[str, str | int] = {"refresh": token.refresh}
|
||||
response = self.connection.post(url, data=data)
|
||||
if response.status_code == requests.codes.unauthorized:
|
||||
raise UnauthorizedException("Token is invalid or expired.")
|
||||
self._raise_response_error(response)
|
||||
token = TypeAdapter(Token).validate_python(response.json())
|
||||
return token
|
67
mdrsclient/api/users.py
Normal file
67
mdrsclient/api/users.py
Normal file
@ -0,0 +1,67 @@
|
||||
from typing import Final
|
||||
|
||||
import requests
|
||||
from pydantic import TypeAdapter
|
||||
from pydantic.dataclasses import dataclass
|
||||
|
||||
from mdrsclient.api.base import BaseApi
|
||||
from mdrsclient.exceptions import UnauthorizedException
|
||||
from mdrsclient.models import Token, User
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class UsersCurrentResponseLaboratory:
|
||||
id: int
|
||||
name: str
|
||||
role: int
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class UsersApiCurrentResponse:
|
||||
id: int
|
||||
username: str
|
||||
full_name: str
|
||||
email: str
|
||||
laboratories: list[UsersCurrentResponseLaboratory]
|
||||
is_staff: bool
|
||||
is_active: bool
|
||||
is_superuser: bool
|
||||
is_reviewer: bool
|
||||
last_login: str # ISO8601
|
||||
date_joined: str # ISO8601
|
||||
|
||||
|
||||
class UsersApi(BaseApi):
|
||||
ENTRYPOINT: Final[str] = "v3/users/"
|
||||
|
||||
def current(self) -> User:
|
||||
# print(self.__class__.__name__ + "::" + sys._getframe().f_code.co_name)
|
||||
url = self.ENTRYPOINT + "current/"
|
||||
response = self.connection.get(url)
|
||||
self._raise_response_error(response)
|
||||
obj = TypeAdapter(UsersApiCurrentResponse).validate_python(response.json())
|
||||
laboratory_ids = list(map(lambda x: x.id, obj.laboratories))
|
||||
user = User(id=obj.id, username=obj.username, laboratory_ids=laboratory_ids, is_reviewer=obj.is_reviewer)
|
||||
return user
|
||||
|
||||
def token(self, username: str, password: str) -> Token:
|
||||
# print(self.__class__.__name__ + "::" + sys._getframe().f_code.co_name)
|
||||
url = self.ENTRYPOINT + "token/"
|
||||
data: dict[str, str | int] = {"username": username, "password": password}
|
||||
response = self.connection.post(url, data=data)
|
||||
if response.status_code == requests.codes.unauthorized:
|
||||
raise UnauthorizedException("Invalid username or password.")
|
||||
self._raise_response_error(response)
|
||||
token = TypeAdapter(Token).validate_python(response.json())
|
||||
return token
|
||||
|
||||
def tokenRefresh(self, token: Token) -> Token:
|
||||
# print(self.__class__.__name__ + "::" + sys._getframe().f_code.co_name)
|
||||
url = self.ENTRYPOINT + "token/refresh/"
|
||||
data: dict[str, str | int] = {"refresh": token.refresh}
|
||||
response = self.connection.post(url, data=data)
|
||||
if response.status_code == requests.codes.unauthorized:
|
||||
raise UnauthorizedException("Token is invalid or expired.")
|
||||
self._raise_response_error(response)
|
||||
token = TypeAdapter(Token).validate_python(response.json())
|
||||
return token
|
@ -1,4 +1,4 @@
|
||||
from mdrsclient.api.user import UserApi
|
||||
from mdrsclient.api.users import UsersApi
|
||||
from mdrsclient.connection import MDRSConnection
|
||||
from mdrsclient.exceptions import UnauthorizedException
|
||||
|
||||
@ -8,9 +8,9 @@ def token_check(connection: MDRSConnection) -> None:
|
||||
connection.lock.acquire()
|
||||
if connection.token is not None:
|
||||
if connection.token.is_refresh_required:
|
||||
user_api = UserApi(connection)
|
||||
user_api = UsersApi(connection)
|
||||
try:
|
||||
connection.token = user_api.refresh(connection.token)
|
||||
connection.token = user_api.tokenRefresh(connection.token)
|
||||
except UnauthorizedException:
|
||||
connection.logout()
|
||||
elif connection.token.is_expired:
|
||||
|
@ -3,7 +3,7 @@ from abc import ABC, abstractmethod
|
||||
from typing import Any
|
||||
from unicodedata import normalize
|
||||
|
||||
from mdrsclient.api import FolderApi, LaboratoryApi
|
||||
from mdrsclient.api import FoldersApi, LaboratoriesApi
|
||||
from mdrsclient.config import ConfigFile
|
||||
from mdrsclient.connection import MDRSConnection
|
||||
from mdrsclient.exceptions import (
|
||||
@ -31,7 +31,7 @@ class BaseCommand(ABC):
|
||||
@classmethod
|
||||
def _find_laboratory(cls, connection: MDRSConnection, name: str) -> Laboratory:
|
||||
if connection.laboratories.empty() or connection.token is not None and connection.token.is_expired:
|
||||
laboratory_api = LaboratoryApi(connection)
|
||||
laboratory_api = LaboratoriesApi(connection)
|
||||
connection.laboratories = laboratory_api.list()
|
||||
laboratory = connection.laboratories.find_by_name(name)
|
||||
if laboratory is None:
|
||||
@ -42,7 +42,7 @@ class BaseCommand(ABC):
|
||||
def _find_folder(
|
||||
cls, connection: MDRSConnection, laboratory: Laboratory, path: str, password: str | None = None
|
||||
) -> Folder:
|
||||
folder_api = FolderApi(connection)
|
||||
folder_api = FoldersApi(connection)
|
||||
folders = folder_api.list(laboratory.id, normalize("NFC", path))
|
||||
if len(folders) != 1:
|
||||
raise UnexpectedException(f"Folder `{path}` not found.")
|
||||
|
@ -1,7 +1,7 @@
|
||||
from argparse import Namespace
|
||||
from typing import Any
|
||||
|
||||
from mdrsclient.api import FolderApi
|
||||
from mdrsclient.api import FoldersApi
|
||||
from mdrsclient.commands.base import BaseCommand
|
||||
from mdrsclient.exceptions import IllegalArgumentException
|
||||
from mdrsclient.models import FolderAccessLevel
|
||||
@ -36,5 +36,5 @@ class ChaclCommand(BaseCommand):
|
||||
connection = cls._create_connection(remote)
|
||||
laboratory = cls._find_laboratory(connection, laboratory_name)
|
||||
folder = cls._find_folder(connection, laboratory, r_path)
|
||||
folder_api = FolderApi(connection)
|
||||
folder_api = FoldersApi(connection)
|
||||
folder_api.acl(folder.id, access_level, is_recursive, password)
|
||||
|
@ -3,7 +3,7 @@ from argparse import Namespace
|
||||
from typing import Any
|
||||
from unicodedata import normalize
|
||||
|
||||
from mdrsclient.api import FileApi, FolderApi
|
||||
from mdrsclient.api import FilesApi, FoldersApi
|
||||
from mdrsclient.commands.base import BaseCommand
|
||||
from mdrsclient.exceptions import IllegalArgumentException
|
||||
|
||||
@ -56,7 +56,7 @@ class CpCommand(BaseCommand):
|
||||
d_sub_folder = d_parent_folder.find_sub_folder(d_basename)
|
||||
if d_sub_folder is not None:
|
||||
raise IllegalArgumentException(f"Cannot overwrite non-folder `{d_basename}` with folder `{d_path}`.")
|
||||
file_api = FileApi(connection)
|
||||
file_api = FilesApi(connection)
|
||||
if s_parent_folder.id != d_parent_folder.id or d_basename != s_basename:
|
||||
file_api.copy(s_file, d_parent_folder.id, normalize("NFC", d_basename))
|
||||
else:
|
||||
@ -73,6 +73,6 @@ class CpCommand(BaseCommand):
|
||||
if d_folder.id == s_folder.id:
|
||||
raise IllegalArgumentException(f"`{s_path}` and `{s_path}` are the same folder.")
|
||||
raise IllegalArgumentException(f"Cannot move `{s_path}` to `{d_path}`: Folder not empty.")
|
||||
folder_api = FolderApi(connection)
|
||||
folder_api = FoldersApi(connection)
|
||||
if s_parent_folder.id != d_parent_folder.id or s_basename != d_basename:
|
||||
folder_api.copy(s_folder, d_parent_folder.id, normalize("NFC", d_basename))
|
||||
|
@ -5,7 +5,7 @@ from typing import Any
|
||||
|
||||
from pydantic.dataclasses import dataclass
|
||||
|
||||
from mdrsclient.api import FileApi, FolderApi
|
||||
from mdrsclient.api import FilesApi, FoldersApi
|
||||
from mdrsclient.commands.base import BaseCommand
|
||||
from mdrsclient.connection import MDRSConnection
|
||||
from mdrsclient.exceptions import IllegalArgumentException
|
||||
@ -62,13 +62,13 @@ class DownloadCommand(BaseCommand):
|
||||
raise IllegalArgumentException(f"File or folder `{r_path}` not found.")
|
||||
if not is_recursive:
|
||||
raise IllegalArgumentException(f"Cannot download `{r_path}`: Is a folder.")
|
||||
folder_api = FolderApi(connection)
|
||||
folder_api = FoldersApi(connection)
|
||||
cls.__multiple_download_pickup_recursive_files(folder_api, download_files, folder.id, l_dirname)
|
||||
cls.__multiple_download(connection, download_files)
|
||||
|
||||
@classmethod
|
||||
def __multiple_download_pickup_recursive_files(
|
||||
cls, folder_api: FolderApi, infolist: list[DownloadFileInfo], folder_id: str, basedir: str
|
||||
cls, folder_api: FoldersApi, infolist: list[DownloadFileInfo], folder_id: str, basedir: str
|
||||
) -> None:
|
||||
folder = folder_api.retrieve(folder_id)
|
||||
dirname = os.path.join(basedir, folder.name)
|
||||
@ -83,11 +83,11 @@ class DownloadCommand(BaseCommand):
|
||||
|
||||
@classmethod
|
||||
def __multiple_download(cls, connection: MDRSConnection, infolist: list[DownloadFileInfo]) -> None:
|
||||
file_api = FileApi(connection)
|
||||
file_api = FilesApi(connection)
|
||||
with ThreadPoolExecutor(max_workers=CONCURRENT) as pool:
|
||||
pool.map(lambda x: cls.__multiple_download_worker(file_api, x), infolist)
|
||||
|
||||
@classmethod
|
||||
def __multiple_download_worker(cls, file_api: FileApi, info: DownloadFileInfo) -> None:
|
||||
def __multiple_download_worker(cls, file_api: FilesApi, info: DownloadFileInfo) -> None:
|
||||
file_api.download(info.file, info.path)
|
||||
print(info.path)
|
||||
|
@ -3,7 +3,7 @@ import os
|
||||
from argparse import Namespace
|
||||
from typing import Any
|
||||
|
||||
from mdrsclient.api import FileApi
|
||||
from mdrsclient.api import FilesApi
|
||||
from mdrsclient.commands.base import BaseCommand
|
||||
from mdrsclient.exceptions import IllegalArgumentException
|
||||
|
||||
@ -34,6 +34,6 @@ class FileMetadataCommand(BaseCommand):
|
||||
file = folder.find_file(r_basename)
|
||||
if file is None:
|
||||
raise IllegalArgumentException(f"File `{r_basename}` not found.")
|
||||
file_api = FileApi(connection)
|
||||
file_api = FilesApi(connection)
|
||||
metadata = file_api.metadata(file)
|
||||
print(json.dumps(metadata, ensure_ascii=False))
|
||||
|
@ -1,7 +1,7 @@
|
||||
from argparse import Namespace
|
||||
from typing import Any
|
||||
|
||||
from mdrsclient.api import LaboratoryApi
|
||||
from mdrsclient.api import LaboratoriesApi
|
||||
from mdrsclient.commands.base import BaseCommand
|
||||
|
||||
|
||||
@ -21,7 +21,7 @@ class LabsCommand(BaseCommand):
|
||||
def labs(cls, remote: str) -> None:
|
||||
remote = cls._parse_remote_host(remote)
|
||||
connection = cls._create_connection(remote)
|
||||
laboratory_api = LaboratoryApi(connection)
|
||||
laboratory_api = LaboratoriesApi(connection)
|
||||
laboratories = laboratory_api.list()
|
||||
connection.laboratories = laboratories
|
||||
label = {"id": "ID", "name": "Name", "pi_name": "PI", "full_name": "Laboratory"}
|
||||
|
@ -2,7 +2,7 @@ import getpass
|
||||
from argparse import Namespace
|
||||
from typing import Any
|
||||
|
||||
from mdrsclient.api import UserApi
|
||||
from mdrsclient.api import UsersApi
|
||||
from mdrsclient.commands.base import BaseCommand
|
||||
from mdrsclient.config import ConfigFile
|
||||
from mdrsclient.connection import MDRSConnection
|
||||
@ -30,8 +30,9 @@ class LoginCommand(BaseCommand):
|
||||
if config.url is None:
|
||||
raise MissingConfigurationException(f"Remote host `{remote}` is not found.")
|
||||
connection = MDRSConnection(config.remote, config.url)
|
||||
user_api = UserApi(connection)
|
||||
(user, token) = user_api.auth(username, password)
|
||||
print("Login Successful")
|
||||
connection.user = user
|
||||
user_api = UsersApi(connection)
|
||||
token = user_api.token(username, password)
|
||||
connection.token = token
|
||||
user = user_api.current()
|
||||
connection.user = user
|
||||
print("Login Successful")
|
||||
|
@ -4,7 +4,7 @@ from typing import Any
|
||||
|
||||
from pydantic.dataclasses import dataclass
|
||||
|
||||
from mdrsclient.api import FolderApi
|
||||
from mdrsclient.api import FoldersApi
|
||||
from mdrsclient.commands.base import BaseCommand
|
||||
from mdrsclient.connection import MDRSConnection
|
||||
from mdrsclient.exceptions import UnauthorizedException
|
||||
@ -82,7 +82,7 @@ class LsCommand(BaseCommand):
|
||||
"type": "Type",
|
||||
"acl": "Access",
|
||||
"laboratory": "Laboratory",
|
||||
"size": "Lock/Size",
|
||||
"size": "Size",
|
||||
"date": "Date",
|
||||
"name": "Name",
|
||||
}
|
||||
@ -90,11 +90,11 @@ class LsCommand(BaseCommand):
|
||||
for key in label.keys():
|
||||
length[key] = len(label[key]) if not context.is_quick else 0
|
||||
for sub_folder in folder.sub_folders:
|
||||
sub_laboratory = context.connection.laboratories.find_by_id(sub_folder.lab_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)"
|
||||
length["acl"] = max(length["acl"], len(sub_folder.access_level_name))
|
||||
length["laboratory"] = max(length["laboratory"], len(sub_laboratory_name))
|
||||
length["size"] = max(length["size"], len(sub_folder.lock_name))
|
||||
length["size"] = max(length["size"], len(str(folder.size)))
|
||||
length["date"] = max(length["date"], len(sub_folder.updated_at_name))
|
||||
length["name"] = max(length["name"], len(sub_folder.name))
|
||||
for file in folder.files:
|
||||
@ -118,10 +118,11 @@ class LsCommand(BaseCommand):
|
||||
print("-" * len(header.expandtabs()))
|
||||
|
||||
for sub_folder in sorted(folder.sub_folders, key=lambda x: x.name):
|
||||
sub_laboratory_name = cls._laboratory_name(context, sub_folder.lab_id)
|
||||
sub_laboratory_name = cls._laboratory_name(context, sub_folder.laboratory_id)
|
||||
sub_folder_type = "[d]" if sub_folder.lock is False else "[l]"
|
||||
print(
|
||||
f"{'[d]':{length['type']}}\t{sub_folder.access_level_name:{length['acl']}}\t"
|
||||
f"{sub_laboratory_name:{length['laboratory']}}\t{sub_folder.lock_name:{length['size']}}\t"
|
||||
f"{sub_folder_type:{length['type']}}\t{sub_folder.access_level_name:{length['acl']}}\t"
|
||||
f"{sub_laboratory_name:{length['laboratory']}}\t{sub_folder.size:{length['size']}}\t"
|
||||
f"{sub_folder.updated_at_name:{length['date']}}\t{sub_folder.name:{length['name']}}"
|
||||
)
|
||||
for file in sorted(folder.files, key=lambda x: x.name):
|
||||
@ -134,7 +135,7 @@ class LsCommand(BaseCommand):
|
||||
if context.is_recursive:
|
||||
print("")
|
||||
for sub_folder in sorted(folder.sub_folders, key=lambda x: x.name):
|
||||
folder_api = FolderApi(context.connection)
|
||||
folder_api = FoldersApi(context.connection)
|
||||
try:
|
||||
if sub_folder.lock:
|
||||
folder_api.auth(sub_folder.id, context.password)
|
||||
@ -149,15 +150,16 @@ class LsCommand(BaseCommand):
|
||||
"id": folder.id,
|
||||
"pid": folder.pid,
|
||||
"name": folder.name,
|
||||
"size": folder.size,
|
||||
"access_level": folder.access_level_name,
|
||||
"lock": folder.lock,
|
||||
"laboratory": cls._laboratory_name(context, folder.lab_id),
|
||||
"laboratory": cls._laboratory_name(context, folder.laboratory_id),
|
||||
"description": folder.description,
|
||||
"created_at": folder.created_at,
|
||||
"updated_at": folder.updated_at,
|
||||
}
|
||||
if isinstance(folder, Folder):
|
||||
folder_api = FolderApi(context.connection)
|
||||
folder_api = FoldersApi(context.connection)
|
||||
data["metadata"] = folder_api.metadata(folder.id)
|
||||
if context.is_recursive:
|
||||
sub_folders: list[dict[str, Any]] = []
|
||||
@ -187,7 +189,7 @@ class LsCommand(BaseCommand):
|
||||
# "thumbnail": file.thumbnail,
|
||||
"description": file.description,
|
||||
"metadata": file.metadata,
|
||||
"download_url": f"{context.connection.url}/v2/{file.download_url}",
|
||||
"download_url": f"{context.connection.url}/{file.download_url}",
|
||||
"created_at": file.created_at,
|
||||
"updated_at": file.updated_at,
|
||||
}
|
||||
|
@ -2,7 +2,7 @@ import json
|
||||
from argparse import Namespace
|
||||
from typing import Any
|
||||
|
||||
from mdrsclient.api import FolderApi
|
||||
from mdrsclient.api import FoldersApi
|
||||
from mdrsclient.commands.base import BaseCommand
|
||||
|
||||
|
||||
@ -26,6 +26,6 @@ class MetadataCommand(BaseCommand):
|
||||
connection = cls._create_connection(remote)
|
||||
laboratory = cls._find_laboratory(connection, laboratory_name)
|
||||
folder = cls._find_folder(connection, laboratory, r_path, password)
|
||||
folder_api = FolderApi(connection)
|
||||
folder_api = FoldersApi(connection)
|
||||
metadata = folder_api.metadata(folder.id)
|
||||
print(json.dumps(metadata, ensure_ascii=False))
|
||||
|
@ -3,7 +3,7 @@ from argparse import Namespace
|
||||
from typing import Any
|
||||
from unicodedata import normalize
|
||||
|
||||
from mdrsclient.api import FolderApi
|
||||
from mdrsclient.api import FoldersApi
|
||||
from mdrsclient.commands.base import BaseCommand
|
||||
from mdrsclient.exceptions import IllegalArgumentException
|
||||
|
||||
@ -31,5 +31,5 @@ class MkdirCommand(BaseCommand):
|
||||
parent_folder = cls._find_folder(connection, laboratory, r_dirname)
|
||||
if parent_folder.find_sub_folder(r_basename) is not None or parent_folder.find_file(r_basename) is not None:
|
||||
raise IllegalArgumentException(f"Cannot create folder `{r_path}`: File exists.")
|
||||
folder_api = FolderApi(connection)
|
||||
folder_api = FoldersApi(connection)
|
||||
folder_api.create(normalize("NFC", r_basename), parent_folder.id)
|
||||
|
@ -3,7 +3,7 @@ from argparse import Namespace
|
||||
from typing import Any
|
||||
from unicodedata import normalize
|
||||
|
||||
from mdrsclient.api import FileApi, FolderApi
|
||||
from mdrsclient.api import FilesApi, FoldersApi
|
||||
from mdrsclient.commands.base import BaseCommand
|
||||
from mdrsclient.exceptions import IllegalArgumentException
|
||||
|
||||
@ -52,7 +52,7 @@ class MvCommand(BaseCommand):
|
||||
d_sub_folder = d_parent_folder.find_sub_folder(d_basename)
|
||||
if d_sub_folder is not None:
|
||||
raise IllegalArgumentException(f"Cannot overwrite non-folder `{d_basename}` with folder `{d_path}`.")
|
||||
file_api = FileApi(connection)
|
||||
file_api = FilesApi(connection)
|
||||
if s_parent_folder.id != d_parent_folder.id or d_basename != s_basename:
|
||||
file_api.move(s_file, d_parent_folder.id, normalize("NFC", d_basename))
|
||||
else:
|
||||
@ -67,6 +67,6 @@ class MvCommand(BaseCommand):
|
||||
if d_folder.id == s_folder.id:
|
||||
raise IllegalArgumentException(f"`{s_path}` and `{s_path}` are the same folder.")
|
||||
raise IllegalArgumentException(f"Cannot move `{s_path}` to `{d_path}`: Folder not empty.")
|
||||
folder_api = FolderApi(connection)
|
||||
folder_api = FoldersApi(connection)
|
||||
if s_parent_folder.id != d_parent_folder.id or d_basename != s_basename:
|
||||
folder_api.move(s_folder, d_parent_folder.id, normalize("NFC", d_basename))
|
||||
|
@ -2,7 +2,7 @@ import os
|
||||
from argparse import Namespace
|
||||
from typing import Any
|
||||
|
||||
from mdrsclient.api import FileApi, FolderApi
|
||||
from mdrsclient.api import FilesApi, FoldersApi
|
||||
from mdrsclient.commands.base import BaseCommand
|
||||
from mdrsclient.exceptions import IllegalArgumentException
|
||||
|
||||
@ -34,7 +34,7 @@ class RmCommand(BaseCommand):
|
||||
parent_folder = cls._find_folder(connection, laboratory, r_dirname)
|
||||
file = parent_folder.find_file(r_basename)
|
||||
if file is not None:
|
||||
file_api = FileApi(connection)
|
||||
file_api = FilesApi(connection)
|
||||
file_api.destroy(file)
|
||||
else:
|
||||
folder = parent_folder.find_sub_folder(r_basename)
|
||||
@ -42,5 +42,5 @@ class RmCommand(BaseCommand):
|
||||
raise IllegalArgumentException(f"Cannot remove `{r_path}`: No such file or folder.")
|
||||
if not is_recursive:
|
||||
raise IllegalArgumentException(f"Cannot remove `{r_path}`: Is a folder.")
|
||||
folder_api = FolderApi(connection)
|
||||
folder_api = FoldersApi(connection)
|
||||
folder_api.destroy(folder.id, True)
|
||||
|
@ -5,7 +5,7 @@ from typing import Any
|
||||
|
||||
from pydantic.dataclasses import dataclass
|
||||
|
||||
from mdrsclient.api import FileApi, FolderApi
|
||||
from mdrsclient.api import FilesApi, FoldersApi
|
||||
from mdrsclient.commands.base import BaseCommand
|
||||
from mdrsclient.connection import MDRSConnection
|
||||
from mdrsclient.exceptions import IllegalArgumentException, MDRSException
|
||||
@ -40,7 +40,7 @@ class UploadCommand(BaseCommand):
|
||||
@classmethod
|
||||
def upload(cls, local_path: str, remote_path: str, is_recursive: bool) -> None:
|
||||
(remote, laboratory_name, r_path) = cls._parse_remote_host_with_path(remote_path)
|
||||
l_path = os.path.realpath(local_path)
|
||||
l_path = os.path.abspath(local_path)
|
||||
if not os.path.exists(l_path):
|
||||
raise IllegalArgumentException(f"File or directory `{local_path}` not found.")
|
||||
connection = cls._create_connection(remote)
|
||||
@ -50,11 +50,11 @@ class UploadCommand(BaseCommand):
|
||||
if os.path.isdir(l_path):
|
||||
if not is_recursive:
|
||||
raise IllegalArgumentException(f"Cannot upload `{local_path}`: Is a directory.")
|
||||
folder_api = FolderApi(connection)
|
||||
folder_api = FoldersApi(connection)
|
||||
folder_map: dict[str, Folder] = {}
|
||||
folder_map[r_path] = folder
|
||||
l_basename = os.path.basename(l_path)
|
||||
for dirpath, _, filenames in os.walk(l_path):
|
||||
for dirpath, _, filenames in os.walk(l_path, followlinks=True):
|
||||
sub = l_basename if dirpath == l_path else os.path.join(l_basename, os.path.relpath(dirpath, l_path))
|
||||
d_dirname = os.path.join(r_path, sub)
|
||||
d_basename = os.path.basename(d_dirname)
|
||||
@ -82,12 +82,12 @@ class UploadCommand(BaseCommand):
|
||||
|
||||
@classmethod
|
||||
def __multiple_upload(cls, connection: MDRSConnection, infos: list[UploadFileInfo]) -> None:
|
||||
file_api = FileApi(connection)
|
||||
file_api = FilesApi(connection)
|
||||
with ThreadPoolExecutor(max_workers=CONCURRENT) as pool:
|
||||
pool.map(lambda x: cls.__multiple_upload_worker(file_api, x), infos)
|
||||
|
||||
@classmethod
|
||||
def __multiple_upload_worker(cls, file_api: FileApi, info: UploadFileInfo) -> None:
|
||||
def __multiple_upload_worker(cls, file_api: FilesApi, info: UploadFileInfo) -> None:
|
||||
basename = os.path.basename(info.path)
|
||||
file = info.folder.find_file(basename)
|
||||
try:
|
||||
|
@ -15,7 +15,7 @@ class FolderAccessLevelItem(NamedTuple):
|
||||
|
||||
class FolderAccessLevel:
|
||||
# Bit Mask
|
||||
# - bit 0: Storage or Repository
|
||||
# - bit 0: Is Private
|
||||
# - bit 1: Is Public
|
||||
# - bit 2: With Password
|
||||
# - bit 3-7: (Reserved)
|
||||
@ -49,7 +49,8 @@ class FolderSimple:
|
||||
name: str
|
||||
access_level: int
|
||||
lock: bool
|
||||
lab_id: int
|
||||
size: int
|
||||
laboratory_id: int
|
||||
description: str
|
||||
created_at: str
|
||||
updated_at: str
|
||||
|
@ -1,6 +1,6 @@
|
||||
[tool.poetry]
|
||||
name = "mdrs-client-python"
|
||||
version = "1.2.0"
|
||||
version = "1.3.1"
|
||||
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>"]
|
||||
license = "MIT"
|
||||
@ -24,17 +24,17 @@ packages = [
|
||||
python = "^3.10"
|
||||
requests = "^2.31.0"
|
||||
python-dotenv = "^1.0.0"
|
||||
pydantic = "^2.4.2"
|
||||
pydantic-settings = "^2.0.3"
|
||||
pydantic = "^2.5.2"
|
||||
pydantic-settings = "^2.1.0"
|
||||
PyJWT = "^2.8.0"
|
||||
validators = "^0.22.0"
|
||||
|
||||
[tool.poetry.group.dev.dependencies]
|
||||
black = "^23.9.1"
|
||||
black = "^23.12.0"
|
||||
flake8 = "^6.1.0"
|
||||
Flake8-pyproject = "^1.2.3"
|
||||
isort = "^5.12.0"
|
||||
pyright = "^1.1.329"
|
||||
isort = "^5.13.0"
|
||||
pyright = "^1.1.339"
|
||||
|
||||
[tool.poetry.scripts]
|
||||
mdrs = 'mdrsclient.__main__:main'
|
||||
|
Reference in New Issue
Block a user