3 Commits

10 changed files with 124 additions and 72 deletions

10
.cspell.json Normal file
View File

@ -0,0 +1,10 @@
{
"version": "0.2",
"language": "en,en-gb",
"ignoreWords": ["getframe", "pydantic", "UNLCK"],
"words": ["chacl", "mdrs", "mdrsclient", "neurodata", "Neuroinformatics", "RIKEN"],
"ignorePaths": [
".env",
"__pycache__"
]
}

12
.editorconfig Normal file
View File

@ -0,0 +1,12 @@
# editorconfig.org
[*]
charset = utf-8
indent_style = space
indent_size = 2
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
[*.md]
trim_trailing_whitespace = false

17
.vscode/settings.json vendored
View File

@ -15,9 +15,12 @@
"[jsonc]": { "[jsonc]": {
"editor.defaultFormatter": "esbenp.prettier-vscode" "editor.defaultFormatter": "esbenp.prettier-vscode"
}, },
// Extensions - Black Formatter
"black-formatter.args": ["--line-length=120"],
// Extensions - Code Spell Checker // Extensions - Code Spell Checker
"cSpell.ignoreWords": ["getframe", "pydantic", "UNLCK"], // - see: .cspell.json
"cSpell.words": ["chacl", "mdrs", "mdrsclient", "neurodata", "Neuroinformatics", "RIKEN"], // Extensions - Flake8
"flake8.args": ["--max-line-length=120"],
// Extensions - isort // Extensions - isort
"isort.args": ["--profile=black"], "isort.args": ["--profile=black"],
// Extensions - Prettier // Extensions - Prettier
@ -28,16 +31,6 @@
"prettier.trailingComma": "all", "prettier.trailingComma": "all",
// Extensions - Pylance // Extensions - Pylance
"python.analysis.typeCheckingMode": "strict", "python.analysis.typeCheckingMode": "strict",
"python.analysis.exclude": ["api/migrations/[0-9]*.py"],
// Extensions - Python:black
"python.formatting.blackArgs": ["--line-length=120"],
"python.formatting.provider": "black",
// Extensions - Python:Flake8
"python.linting.enabled": true,
"python.linting.flake8Enabled": true,
"python.linting.flake8Args": ["--max-line-length=120"],
"python.linting.ignorePatterns": ["**/site-packages/**/*.py", ".vscode/*.py"],
"python.linting.lintOnSave": true,
// Extensions - Python Docstring Generator configuration // Extensions - Python Docstring Generator configuration
"autoDocstring.docstringFormat": "google" "autoDocstring.docstringFormat": "google"
} }

View File

@ -5,7 +5,7 @@ The mdrs-client-python is python library and a command-line client for up- and d
## Installing ## Installing
``` ```
pip install -e . poetry install
``` ```
## Example Usage ## Example Usage

View File

@ -1 +1 @@
1.1.1 1.2.0

View File

@ -1,3 +1,4 @@
from dataclasses import field
from typing import Final from typing import Final
import requests import requests
@ -6,14 +7,13 @@ from pydantic.dataclasses import dataclass
from mdrsclient.api.base import BaseApi from mdrsclient.api.base import BaseApi
from mdrsclient.exceptions import UnauthorizedException from mdrsclient.exceptions import UnauthorizedException
from mdrsclient.models import Token, User from mdrsclient.models import Laboratory, Token, User
@dataclass(frozen=True) @dataclass(frozen=True)
class UserAuthResponse(Token): class UserAuthResponse(Token):
is_reviewer: bool | None = None is_reviewer: bool | None = None
laboratory: str | None = None laboratories: list[Laboratory] = field(default_factory=list)
lab_id: int | None = None
class UserApi(BaseApi): class UserApi(BaseApi):
@ -29,7 +29,7 @@ class UserApi(BaseApi):
self._raise_response_error(response) self._raise_response_error(response)
obj = TypeAdapter(UserAuthResponse).validate_python(response.json()) obj = TypeAdapter(UserAuthResponse).validate_python(response.json())
token = Token(access=obj.access, refresh=obj.refresh) token = Token(access=obj.access, refresh=obj.refresh)
laboratory_ids = [obj.lab_id] if obj.lab_id is not None else [] laboratory_ids = list(map(lambda x: x.id, obj.laboratories))
is_reviewer = obj.is_reviewer if obj.is_reviewer is not None else False 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) user = User(id=token.user_id, username=username, laboratory_ids=laboratory_ids, is_reviewer=is_reviewer)
return (user, token) return (user, token)

View File

@ -8,28 +8,37 @@ from mdrsclient.models.utils import iso8601_to_user_friendly
class FolderAccessLevelItem(NamedTuple): class FolderAccessLevelItem(NamedTuple):
id: int mask: int
key: str key: str
label: str label: str
class FolderAccessLevel: class FolderAccessLevel:
# Bit Mask
# - bit 0: Storage or Repository
# - bit 1: Is Public
# - bit 2: With Password
# - bit 3-7: (Reserved)
# - bit 8-15: Restricted Open
ACCESS_LEVELS: Final[list[FolderAccessLevelItem]] = [ ACCESS_LEVELS: Final[list[FolderAccessLevelItem]] = [
FolderAccessLevelItem(-1, "storage", "Storage"), FolderAccessLevelItem(0x0204, "5kikan_or_pw_open", "5Kikan or PW Open"),
FolderAccessLevelItem(0, "private", "Private"), FolderAccessLevelItem(0x0104, "cbs_or_pw_open", "CBS or PW Open"),
FolderAccessLevelItem(1, "cbs_open", "CBS Open"), FolderAccessLevelItem(0x0200, "5kikan_open", "5Kikan Open"),
FolderAccessLevelItem(2, "pw_open", "PW Open"), FolderAccessLevelItem(0x0100, "cbs_open", "CBS Open"),
FolderAccessLevelItem(3, "public", "Public"), FolderAccessLevelItem(0x0004, "pw_open", "PW Open"),
FolderAccessLevelItem(0x0002, "public", "Public"),
FolderAccessLevelItem(0x0001, "private", "Private"),
FolderAccessLevelItem(0x0000, "storage", "Storage"),
] ]
@staticmethod @staticmethod
def key2id(key: str) -> int | None: def key2id(key: str) -> int | None:
acl = next((x for x in FolderAccessLevel.ACCESS_LEVELS if x.key == key), None) acl = next((x for x in FolderAccessLevel.ACCESS_LEVELS if x.key == key), None)
return acl.id if acl is not None else None return acl.mask if acl is not None else None
@staticmethod @staticmethod
def id2label(id: int) -> str | None: def id2label(id: int) -> str | None:
acl = next((x for x in FolderAccessLevel.ACCESS_LEVELS if x.id == id), None) acl = next((x for x in FolderAccessLevel.ACCESS_LEVELS if (x.mask & id) == x.mask), None)
return acl.label if acl is not None else None return acl.label if acl is not None else None

74
pyproject.toml Normal file
View File

@ -0,0 +1,74 @@
[tool.poetry]
name = "mdrs-client-python"
version = "1.2.0"
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"
readme = "README.md"
classifiers=[
"Development Status :: 3 - Alpha",
"Environment :: Console",
"Intended Audience :: Developers",
"Intended Audience :: Science/Research",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"OSI Approved :: MIT License",
"Topic :: Utilities",
]
packages = [
{ include = "mdrsclient" }
]
[tool.poetry.dependencies]
python = "^3.10"
requests = "^2.31.0"
python-dotenv = "^1.0.0"
pydantic = "^2.4.2"
pydantic-settings = "^2.0.3"
PyJWT = "^2.8.0"
validators = "^0.22.0"
[tool.poetry.group.dev.dependencies]
black = "^23.9.1"
flake8 = "^6.1.0"
Flake8-pyproject = "^1.2.3"
isort = "^5.12.0"
pyright = "^1.1.329"
[tool.poetry.scripts]
mdrs = 'mdrsclient.__main__:main'
[build-system]
requires = ["poetry-core"]
build-backend = "poetry.core.masonry.api"
[tool.black]
line-length = 120
target-version = ['py310']
include = '\.pyi?$'
exclude = '''
/(
\.git
| \.venv
| __pycache__
| dist
)/
'''
[tool.flake8]
exclude = ".git, .venv, __pycache__, dist"
max-complexity = 10
max-line-length = 120
[tool.isort]
profile = "black"
line_length = 120
[tool.mypy]
[tool.pyright]
typeCheckingMode = "basic"
exclude = ["**/__pycache__", "**/.*", "dist"]
#reportUnknownMemberType = "warning"
#reportUnknownVariableType = "warning"

View File

@ -1,6 +0,0 @@
requests
python-dotenv
pydantic
pydantic-settings
PyJWT
validators

View File

@ -1,40 +0,0 @@
import os
from typing import Final
from setuptools import find_packages, setup
from mdrsclient import __version__
BASE_DIR: Final[str] = os.path.realpath(os.path.dirname(__file__))
with open(os.path.join(BASE_DIR, "requirements.txt")) as f:
__requirements__ = f.read().splitlines()
with open(os.path.join(BASE_DIR, "README.md")) as f:
__readme__ = f.read()
setup(
name="mdrsclient",
version=__version__,
description="A MDRS command-line tool",
long_description=__readme__,
author="Neuroinformatics Unit, RIKEN CBS",
license="MIT",
classifiers=[
"Development Status :: 3 - Alpha",
"Environment :: Console",
"Intended Audience :: Developers",
"Intended Audience :: Science/Research",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"OSI Approved :: MIT License",
"Topic :: Utilities",
],
packages=find_packages(),
include_package_data=True,
package_data={
"mdrsclient": ["VERSION"],
},
install_requires=__requirements__,
entry_points={"console_scripts": ["mdrs=mdrsclient.__main__:main"]},
)