changed API endpoint from v2 to v3.
This commit is contained in:
parent
f10b42a1f2
commit
292ca1df27
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,11 +1,11 @@
|
||||
from mdrsclient.api.file import FileApi
|
||||
from mdrsclient.api.folder import FolderApi
|
||||
from mdrsclient.api.laboratory import LaboratoryApi
|
||||
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",
|
||||
"FilesApi",
|
||||
"FoldersApi",
|
||||
"LaboratoriesApi",
|
||||
"UsersApi",
|
||||
]
|
||||
|
@ -10,12 +10,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)
|
||||
@ -34,7 +34,7 @@ class FileApi(BaseApi):
|
||||
with open(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
|
||||
@ -93,7 +93,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,4 +1,3 @@
|
||||
from dataclasses import field
|
||||
from typing import Final
|
||||
|
||||
import requests
|
||||
@ -7,13 +6,7 @@ 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)
|
||||
from mdrsclient.models import Token, User
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
@ -24,7 +17,7 @@ class UsersCurrentResponseLaboratory:
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class UsersCurrentResponse:
|
||||
class UsersApiCurrentResponse:
|
||||
id: int
|
||||
username: str
|
||||
full_name: str
|
||||
@ -39,21 +32,21 @@ class UsersCurrentResponse:
|
||||
|
||||
|
||||
class UsersApi(BaseApi):
|
||||
ENTRYPOINT: Final[str] = "v2/"
|
||||
ENTRYPOINT: Final[str] = "v3/users/"
|
||||
|
||||
def current(self) -> User:
|
||||
# print(self.__class__.__name__ + "::" + sys._getframe().f_code.co_name)
|
||||
url = self.ENTRYPOINT + "users/current/"
|
||||
url = self.ENTRYPOINT + "current/"
|
||||
response = self.connection.get(url)
|
||||
self._raise_response_error(response)
|
||||
obj = TypeAdapter(UsersCurrentResponse).validate_python(response.json())
|
||||
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 + "users/token/"
|
||||
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:
|
||||
@ -64,7 +57,7 @@ class UsersApi(BaseApi):
|
||||
|
||||
def tokenRefresh(self, token: Token) -> Token:
|
||||
# print(self.__class__.__name__ + "::" + sys._getframe().f_code.co_name)
|
||||
url = self.ENTRYPOINT + "users/token/refresh/"
|
||||
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:
|
||||
|
@ -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"}
|
||||
|
@ -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
|
||||
@ -134,7 +134,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)
|
||||
@ -157,7 +157,7 @@ class LsCommand(BaseCommand):
|
||||
"updated_at": folder.updated_at,
|
||||
}
|
||||
if isinstance(folder, Folder):
|
||||
folder_api = FolderApi(context.connection)
|
||||
folder_api = FoldersApi(context.connection)
|
||||
print(folder.name)
|
||||
data["metadata"] = folder_api.metadata(folder.id)
|
||||
if context.is_recursive:
|
||||
|
@ -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
|
||||
@ -50,7 +50,7 @@ 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)
|
||||
@ -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:
|
||||
|
@ -30,10 +30,10 @@ PyJWT = "^2.8.0"
|
||||
validators = "^0.22.0"
|
||||
|
||||
[tool.poetry.group.dev.dependencies]
|
||||
black = "^23.11.0"
|
||||
black = "^23.12.0"
|
||||
flake8 = "^6.1.0"
|
||||
Flake8-pyproject = "^1.2.3"
|
||||
isort = "^5.12.0"
|
||||
isort = "^5.13.0"
|
||||
pyright = "^1.1.339"
|
||||
|
||||
[tool.poetry.scripts]
|
||||
|
Loading…
Reference in New Issue
Block a user