elapi 2.4.11__tar.gz → 2.4.13__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.
- {elapi-2.4.11 → elapi-2.4.13}/PKG-INFO +6 -4
- {elapi-2.4.11 → elapi-2.4.13}/README.md +2 -1
- {elapi-2.4.11 → elapi-2.4.13}/pyproject.toml +5 -4
- elapi-2.4.13/src/elapi/VERSION +1 -0
- {elapi-2.4.11 → elapi-2.4.13}/src/elapi/api/_handle_unexp_response.py +14 -2
- {elapi-2.4.11 → elapi-2.4.13}/src/elapi/api/_names.py +5 -0
- elapi-2.4.13/src/elapi/api/_supported_versions/5.5.10.json +62 -0
- elapi-2.4.13/src/elapi/api/_supported_versions/5.5.11.json +62 -0
- elapi-2.4.13/src/elapi/api/_supported_versions/5.5.12.json +62 -0
- elapi-2.4.13/src/elapi/api/_supported_versions/5.5.13.json +62 -0
- elapi-2.4.13/src/elapi/api/_supported_versions/5.5.9.json +59 -0
- {elapi-2.4.11 → elapi-2.4.13}/src/elapi/path.py +1 -1
- {elapi-2.4.11 → elapi-2.4.13}/src/elapi/plugins/bill_teams/bill_teams.py +65 -48
- {elapi-2.4.11 → elapi-2.4.13}/src/elapi/plugins/bill_teams/cli.py +29 -2
- {elapi-2.4.11 → elapi-2.4.13}/src/elapi/plugins/experiments/_doc.py +3 -3
- elapi-2.4.11/src/elapi/VERSION +0 -1
- {elapi-2.4.11 → elapi-2.4.13}/LICENSE +0 -0
- {elapi-2.4.11 → elapi-2.4.13}/src/elapi/.DS_Store +0 -0
- {elapi-2.4.11 → elapi-2.4.13}/src/elapi/__init__.py +0 -0
- {elapi-2.4.11 → elapi-2.4.13}/src/elapi/_core_init/__init__.py +0 -0
- {elapi-2.4.11 → elapi-2.4.13}/src/elapi/_core_init/_cache.py +0 -0
- {elapi-2.4.11 → elapi-2.4.13}/src/elapi/_core_init/_loggers/__init__.py +0 -0
- {elapi-2.4.11 → elapi-2.4.13}/src/elapi/_core_init/_loggers/base.py +0 -0
- {elapi-2.4.11 → elapi-2.4.13}/src/elapi/_core_init/_loggers/handlers/__init__.py +0 -0
- {elapi-2.4.11 → elapi-2.4.13}/src/elapi/_core_init/_loggers/handlers/base.py +0 -0
- {elapi-2.4.11 → elapi-2.4.13}/src/elapi/_core_init/_loggers/handlers/callback.py +0 -0
- {elapi-2.4.11 → elapi-2.4.13}/src/elapi/_core_init/_loggers/handlers/stderr.py +0 -0
- {elapi-2.4.11 → elapi-2.4.13}/src/elapi/_core_init/_utils.py +0 -0
- {elapi-2.4.11 → elapi-2.4.13}/src/elapi/_names.py +0 -0
- {elapi-2.4.11 → elapi-2.4.13}/src/elapi/_vendor/__init__.py +0 -0
- {elapi-2.4.11 → elapi-2.4.13}/src/elapi/_vendor/haggis/LICENSE +0 -0
- {elapi-2.4.11 → elapi-2.4.13}/src/elapi/_vendor/haggis/__init__.py +0 -0
- {elapi-2.4.11 → elapi-2.4.13}/src/elapi/_vendor/haggis/logs.py +0 -0
- {elapi-2.4.11 → elapi-2.4.13}/src/elapi/_vendor/haggis/version.py +0 -0
- {elapi-2.4.11 → elapi-2.4.13}/src/elapi/api/__init__.py +0 -0
- {elapi-2.4.11 → elapi-2.4.13}/src/elapi/api/_openapi_parser.py +0 -0
- {elapi-2.4.11 → elapi-2.4.13}/src/elapi/api/_supported_versions/5.1.15.json +0 -0
- {elapi-2.4.11 → elapi-2.4.13}/src/elapi/api/_supported_versions/5.2.0.json +0 -0
- {elapi-2.4.11 → elapi-2.4.13}/src/elapi/api/_supported_versions/5.2.1.json +0 -0
- {elapi-2.4.11 → elapi-2.4.13}/src/elapi/api/_supported_versions/5.2.2.json +0 -0
- {elapi-2.4.11 → elapi-2.4.13}/src/elapi/api/_supported_versions/5.2.3.json +0 -0
- {elapi-2.4.11 → elapi-2.4.13}/src/elapi/api/_supported_versions/5.2.4.json +0 -0
- {elapi-2.4.11 → elapi-2.4.13}/src/elapi/api/_supported_versions/5.2.5.json +0 -0
- {elapi-2.4.11 → elapi-2.4.13}/src/elapi/api/_supported_versions/5.2.6.json +0 -0
- {elapi-2.4.11 → elapi-2.4.13}/src/elapi/api/_supported_versions/5.2.7.json +0 -0
- {elapi-2.4.11 → elapi-2.4.13}/src/elapi/api/_supported_versions/5.2.8.json +0 -0
- {elapi-2.4.11 → elapi-2.4.13}/src/elapi/api/_supported_versions/5.3.0.json +0 -0
- {elapi-2.4.11 → elapi-2.4.13}/src/elapi/api/_supported_versions/5.3.1.json +0 -0
- {elapi-2.4.11 → elapi-2.4.13}/src/elapi/api/_supported_versions/5.3.10.json +0 -0
- {elapi-2.4.11 → elapi-2.4.13}/src/elapi/api/_supported_versions/5.3.11.json +0 -0
- {elapi-2.4.11 → elapi-2.4.13}/src/elapi/api/_supported_versions/5.3.2.json +0 -0
- {elapi-2.4.11 → elapi-2.4.13}/src/elapi/api/_supported_versions/5.3.3.json +0 -0
- {elapi-2.4.11 → elapi-2.4.13}/src/elapi/api/_supported_versions/5.3.4.json +0 -0
- {elapi-2.4.11 → elapi-2.4.13}/src/elapi/api/_supported_versions/5.3.5.json +0 -0
- {elapi-2.4.11 → elapi-2.4.13}/src/elapi/api/_supported_versions/5.3.6.json +0 -0
- {elapi-2.4.11 → elapi-2.4.13}/src/elapi/api/_supported_versions/5.3.7.json +0 -0
- {elapi-2.4.11 → elapi-2.4.13}/src/elapi/api/_supported_versions/5.3.8.json +0 -0
- {elapi-2.4.11 → elapi-2.4.13}/src/elapi/api/_supported_versions/5.3.9.json +0 -0
- {elapi-2.4.11 → elapi-2.4.13}/src/elapi/api/_supported_versions/5.4.0.json +0 -0
- {elapi-2.4.11 → elapi-2.4.13}/src/elapi/api/_supported_versions/5.4.1.json +0 -0
- {elapi-2.4.11 → elapi-2.4.13}/src/elapi/api/_supported_versions/5.4.2.json +0 -0
- {elapi-2.4.11 → elapi-2.4.13}/src/elapi/api/_supported_versions/5.4.3.json +0 -0
- {elapi-2.4.11 → elapi-2.4.13}/src/elapi/api/_supported_versions/5.4.4.json +0 -0
- {elapi-2.4.11 → elapi-2.4.13}/src/elapi/api/_supported_versions/5.4.5.json +0 -0
- {elapi-2.4.11 → elapi-2.4.13}/src/elapi/api/_supported_versions/5.4.6.json +0 -0
- {elapi-2.4.11 → elapi-2.4.13}/src/elapi/api/_supported_versions/5.5.0.json +0 -0
- {elapi-2.4.11 → elapi-2.4.13}/src/elapi/api/_supported_versions/5.5.1.json +0 -0
- {elapi-2.4.11 → elapi-2.4.13}/src/elapi/api/_supported_versions/5.5.2.json +0 -0
- {elapi-2.4.11 → elapi-2.4.13}/src/elapi/api/_supported_versions/5.5.3.json +0 -0
- {elapi-2.4.11 → elapi-2.4.13}/src/elapi/api/_supported_versions/5.5.4.json +0 -0
- {elapi-2.4.11 → elapi-2.4.13}/src/elapi/api/_supported_versions/5.5.5.json +0 -0
- {elapi-2.4.11 → elapi-2.4.13}/src/elapi/api/_supported_versions/5.5.6.json +0 -0
- {elapi-2.4.11 → elapi-2.4.13}/src/elapi/api/_supported_versions/5.5.7.json +0 -0
- {elapi-2.4.11 → elapi-2.4.13}/src/elapi/api/_supported_versions/5.5.8.json +0 -0
- {elapi-2.4.11 → elapi-2.4.13}/src/elapi/api/api.py +0 -0
- {elapi-2.4.11 → elapi-2.4.13}/src/elapi/api/endpoint.py +0 -0
- {elapi-2.4.11 → elapi-2.4.13}/src/elapi/api/validators.py +0 -0
- {elapi-2.4.11 → elapi-2.4.13}/src/elapi/cli/__init__.py +0 -0
- {elapi-2.4.11 → elapi-2.4.13}/src/elapi/cli/__main__.py +0 -0
- {elapi-2.4.11 → elapi-2.4.13}/src/elapi/cli/_plugin_handler.py +0 -0
- {elapi-2.4.11 → elapi-2.4.13}/src/elapi/cli/_venv_state_manager.py +0 -0
- {elapi-2.4.11 → elapi-2.4.13}/src/elapi/cli/doc.py +0 -0
- {elapi-2.4.11 → elapi-2.4.13}/src/elapi/cli/elapi.py +0 -0
- {elapi-2.4.11 → elapi-2.4.13}/src/elapi/configuration/__init__.py +0 -0
- {elapi-2.4.11 → elapi-2.4.13}/src/elapi/configuration/_config_history.py +0 -0
- {elapi-2.4.11 → elapi-2.4.13}/src/elapi/configuration/_overload_history.py +0 -0
- {elapi-2.4.11 → elapi-2.4.13}/src/elapi/configuration/config.py +0 -0
- {elapi-2.4.11 → elapi-2.4.13}/src/elapi/configuration/overridable_vars.py +0 -0
- {elapi-2.4.11 → elapi-2.4.13}/src/elapi/configuration/validators.py +0 -0
- {elapi-2.4.11 → elapi-2.4.13}/src/elapi/core_validators/__init__.py +0 -0
- {elapi-2.4.11 → elapi-2.4.13}/src/elapi/core_validators/base.py +0 -0
- {elapi-2.4.11 → elapi-2.4.13}/src/elapi/core_validators/path.py +0 -0
- {elapi-2.4.11 → elapi-2.4.13}/src/elapi/loggers/__init__.py +0 -0
- {elapi-2.4.11 → elapi-2.4.13}/src/elapi/loggers/base.py +0 -0
- {elapi-2.4.11 → elapi-2.4.13}/src/elapi/loggers/handlers/__init__.py +0 -0
- {elapi-2.4.11 → elapi-2.4.13}/src/elapi/loggers/handlers/file.py +0 -0
- {elapi-2.4.11 → elapi-2.4.13}/src/elapi/loggers/log_file.py +0 -0
- {elapi-2.4.11 → elapi-2.4.13}/src/elapi/plugins/.DS_Store +0 -0
- {elapi-2.4.11 → elapi-2.4.13}/src/elapi/plugins/__init__.py +0 -0
- {elapi-2.4.11 → elapi-2.4.13}/src/elapi/plugins/bill_teams/__init__.py +0 -0
- {elapi-2.4.11 → elapi-2.4.13}/src/elapi/plugins/bill_teams/_doc.py +0 -0
- {elapi-2.4.11 → elapi-2.4.13}/src/elapi/plugins/bill_teams/configuration.py +0 -0
- {elapi-2.4.11 → elapi-2.4.13}/src/elapi/plugins/bill_teams/formats.py +0 -0
- {elapi-2.4.11 → elapi-2.4.13}/src/elapi/plugins/bill_teams/generate_table.py +0 -0
- {elapi-2.4.11 → elapi-2.4.13}/src/elapi/plugins/bill_teams/logger.py +0 -0
- {elapi-2.4.11 → elapi-2.4.13}/src/elapi/plugins/bill_teams/names.py +0 -0
- {elapi-2.4.11 → elapi-2.4.13}/src/elapi/plugins/bill_teams/registry.py +0 -0
- {elapi-2.4.11 → elapi-2.4.13}/src/elapi/plugins/bill_teams/specification.py +0 -0
- {elapi-2.4.11 → elapi-2.4.13}/src/elapi/plugins/bill_teams/utils.py +0 -0
- {elapi-2.4.11 → elapi-2.4.13}/src/elapi/plugins/bill_teams/validators.py +0 -0
- {elapi-2.4.11 → elapi-2.4.13}/src/elapi/plugins/commons/__init__.py +0 -0
- {elapi-2.4.11 → elapi-2.4.13}/src/elapi/plugins/commons/cli.py +0 -0
- {elapi-2.4.11 → elapi-2.4.13}/src/elapi/plugins/commons/cli_helpers.py +0 -0
- {elapi-2.4.11 → elapi-2.4.13}/src/elapi/plugins/commons/export.py +0 -0
- {elapi-2.4.11 → elapi-2.4.13}/src/elapi/plugins/commons/get_data_from_input_or_path.py +0 -0
- {elapi-2.4.11 → elapi-2.4.13}/src/elapi/plugins/commons/get_information.py +0 -0
- {elapi-2.4.11 → elapi-2.4.13}/src/elapi/plugins/commons/get_location_from_headers.py +0 -0
- {elapi-2.4.11 → elapi-2.4.13}/src/elapi/plugins/commons/get_whoami.py +0 -0
- {elapi-2.4.11 → elapi-2.4.13}/src/elapi/plugins/experiments/__init__.py +0 -0
- {elapi-2.4.11 → elapi-2.4.13}/src/elapi/plugins/experiments/cli.py +0 -0
- {elapi-2.4.11 → elapi-2.4.13}/src/elapi/plugins/experiments/experiments.py +0 -0
- {elapi-2.4.11 → elapi-2.4.13}/src/elapi/plugins/experiments/formats.py +0 -0
- {elapi-2.4.11 → elapi-2.4.13}/src/elapi/plugins/mail/__init__.py +0 -0
- {elapi-2.4.11 → elapi-2.4.13}/src/elapi/plugins/mail/_yagmail_patch.py +0 -0
- {elapi-2.4.11 → elapi-2.4.13}/src/elapi/plugins/mail/cli.py +0 -0
- {elapi-2.4.11 → elapi-2.4.13}/src/elapi/plugins/mail/configuration.py +0 -0
- {elapi-2.4.11 → elapi-2.4.13}/src/elapi/plugins/mail/mail.py +0 -0
- {elapi-2.4.11 → elapi-2.4.13}/src/elapi/plugins/mail/names.py +0 -0
- {elapi-2.4.11 → elapi-2.4.13}/src/elapi/plugins/mail/yagmail_configuration.py +0 -0
- {elapi-2.4.11 → elapi-2.4.13}/src/elapi/plugins/show_config.py +0 -0
- {elapi-2.4.11 → elapi-2.4.13}/src/elapi/styles/__init__.py +0 -0
- {elapi-2.4.11 → elapi-2.4.13}/src/elapi/styles/_markdown_doc.py +0 -0
- {elapi-2.4.11 → elapi-2.4.13}/src/elapi/styles/_missing.py +0 -0
- {elapi-2.4.11 → elapi-2.4.13}/src/elapi/styles/base.py +0 -0
- {elapi-2.4.11 → elapi-2.4.13}/src/elapi/styles/colors.py +0 -0
- {elapi-2.4.11 → elapi-2.4.13}/src/elapi/styles/formats.py +0 -0
- {elapi-2.4.11 → elapi-2.4.13}/src/elapi/styles/highlight.py +0 -0
- {elapi-2.4.11 → elapi-2.4.13}/src/elapi/styles/rich_utils.py +0 -0
- {elapi-2.4.11 → elapi-2.4.13}/src/elapi/utils/__init__.py +0 -0
- {elapi-2.4.11 → elapi-2.4.13}/src/elapi/utils/messages.py +0 -0
- {elapi-2.4.11 → elapi-2.4.13}/src/elapi/utils/typer_patches.py +0 -0
- {elapi-2.4.11 → elapi-2.4.13}/src/elapi/utils/utils.py +0 -0
- {elapi-2.4.11 → elapi-2.4.13}/src/elapi/validators.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: elapi
|
|
3
|
-
Version: 2.4.
|
|
3
|
+
Version: 2.4.13
|
|
4
4
|
Summary: elAPI is a powerful, extensible API client for eLabFTW.
|
|
5
5
|
Keywords: elabftw,api
|
|
6
6
|
Author: Alexander Haller, Mahadi Xion
|
|
@@ -25,14 +25,15 @@ Requires-Dist: httpx[http2]>=0.28.1,<0.29
|
|
|
25
25
|
Requires-Dist: httpx-auth>=0.23.1,<0.24
|
|
26
26
|
Requires-Dist: rich>=13.8.0,<14
|
|
27
27
|
Requires-Dist: typer[all]>=0.9.0,<0.10
|
|
28
|
-
Requires-Dist: pyyaml==6.0.
|
|
29
|
-
Requires-Dist: mistune
|
|
28
|
+
Requires-Dist: pyyaml==6.0.3
|
|
29
|
+
Requires-Dist: mistune>=3.1.3
|
|
30
30
|
Requires-Dist: click>=8.1.8,<8.2
|
|
31
31
|
Requires-Dist: httpx-limiter>=0.3.0,<0.4.0
|
|
32
32
|
Requires-Dist: httpx-aiohttp>=0.1.12,<0.2
|
|
33
33
|
Requires-Dist: pydantic>=2.12.3
|
|
34
34
|
Requires-Dist: urllib3>=2.6.3
|
|
35
35
|
Requires-Dist: aiohttp>=3.13.5
|
|
36
|
+
Requires-Dist: lxml>=6.1.0
|
|
36
37
|
Requires-Dist: jinja2>=3.1.6,<3.2 ; extra == 'mail'
|
|
37
38
|
Requires-Dist: nameparser>=1.1.3 ; extra == 'mail'
|
|
38
39
|
Requires-Dist: yagmail>=0.15.293,<0.16 ; extra == 'mail'
|
|
@@ -148,7 +149,8 @@ your configuration details.
|
|
|
148
149
|
|
|
149
150
|
elAPI is compatible with the following Python versions: `3.11`, `3.12`, `3.13`, `3.14`. elAPI supports
|
|
150
151
|
the [eLabFTW REST API v2](https://doc.elabftw.net/api/v2/), and can be used with the following eLabFTW
|
|
151
|
-
versions: `5.5.
|
|
152
|
+
versions: `5.5.13`, `5.5.12`, `5.5.11`, `5.5.10`, `5.5.9`, `5.5.8`, `5.5.7`, `5.5.6`, `5.5.5`, `5.5.4`, `5.5.3`, `5.5.2`, `5.5.1`, `5.5.0`,
|
|
153
|
+
`5.4.6`, `5.4.5`, `5.4.4`, `5.4.3`, `5.4.2`, `5.4.1`,
|
|
152
154
|
`5.4.0`, `5.3.11`, `5.3.10`, `5.3.9`, `5.3.8`, `5.3.7`, `5.3.6`,
|
|
153
155
|
`5.3.5`, `5.3.4`, `5.3.3`, `5.3.2`, `5.3.1`, `5.3.0`, `5.2.8`, `5.2.7`, `5.2.6`, `5.2.5`, `5.2.4`,
|
|
154
156
|
`5.2.3`, `5.2.2`, `5.2.1`, `5.2.0`, `5.1.1`.
|
|
@@ -96,7 +96,8 @@ your configuration details.
|
|
|
96
96
|
|
|
97
97
|
elAPI is compatible with the following Python versions: `3.11`, `3.12`, `3.13`, `3.14`. elAPI supports
|
|
98
98
|
the [eLabFTW REST API v2](https://doc.elabftw.net/api/v2/), and can be used with the following eLabFTW
|
|
99
|
-
versions: `5.5.
|
|
99
|
+
versions: `5.5.13`, `5.5.12`, `5.5.11`, `5.5.10`, `5.5.9`, `5.5.8`, `5.5.7`, `5.5.6`, `5.5.5`, `5.5.4`, `5.5.3`, `5.5.2`, `5.5.1`, `5.5.0`,
|
|
100
|
+
`5.4.6`, `5.4.5`, `5.4.4`, `5.4.3`, `5.4.2`, `5.4.1`,
|
|
100
101
|
`5.4.0`, `5.3.11`, `5.3.10`, `5.3.9`, `5.3.8`, `5.3.7`, `5.3.6`,
|
|
101
102
|
`5.3.5`, `5.3.4`, `5.3.3`, `5.3.2`, `5.3.1`, `5.3.0`, `5.2.8`, `5.2.7`, `5.2.6`, `5.2.5`, `5.2.4`,
|
|
102
103
|
`5.2.3`, `5.2.2`, `5.2.1`, `5.2.0`, `5.1.1`.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "elapi"
|
|
3
|
-
version = "2.4.
|
|
3
|
+
version = "2.4.13"
|
|
4
4
|
description = "elAPI is a powerful, extensible API client for eLabFTW."
|
|
5
5
|
authors = [{ name = "Alexander Haller, Mahadi Xion", email = "elabftw@uni-heidelberg.de" }]
|
|
6
6
|
requires-python = ">=3.11.0,<4"
|
|
@@ -30,8 +30,8 @@ dependencies = [
|
|
|
30
30
|
"httpx-auth>=0.23.1,<0.24",
|
|
31
31
|
"rich>=13.8.0,<14",
|
|
32
32
|
"typer[all]>=0.9.0,<0.10",
|
|
33
|
-
"pyyaml==6.0.
|
|
34
|
-
"mistune
|
|
33
|
+
"pyyaml==6.0.3",
|
|
34
|
+
"mistune>=3.1.3",
|
|
35
35
|
"click>=8.1.8,<8.2",
|
|
36
36
|
"httpx-limiter>=0.3.0,<0.4.0",
|
|
37
37
|
"httpx-aiohttp>=0.1.12,<0.2",
|
|
@@ -40,6 +40,7 @@ dependencies = [
|
|
|
40
40
|
# Used by yagmail, but added explicitly here to get an important security update
|
|
41
41
|
"aiohttp>=3.13.5",
|
|
42
42
|
# Used by httpx-aiohttp, but added explicitly here to get an important security update
|
|
43
|
+
"lxml>=6.1.0",
|
|
43
44
|
]
|
|
44
45
|
license-files = [
|
|
45
46
|
"LICENSE",
|
|
@@ -74,7 +75,7 @@ build-backend = "uv_build"
|
|
|
74
75
|
[dependency-groups]
|
|
75
76
|
dev = [
|
|
76
77
|
"mypy>=1.18.2",
|
|
77
|
-
"pip
|
|
78
|
+
"pip>26.0.1", # vendy requires pip
|
|
78
79
|
"ptpython>=3.0.23,<4",
|
|
79
80
|
"vendy>=0.0.3",
|
|
80
81
|
]
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
2.4.13
|
|
@@ -1,11 +1,23 @@
|
|
|
1
1
|
import json
|
|
2
|
+
from typing import TypedDict
|
|
2
3
|
|
|
3
4
|
from ..loggers import Logger
|
|
4
5
|
from ..utils import UnexpectedAPIResponseType
|
|
5
6
|
from ._names import ElabUserGroups
|
|
6
7
|
|
|
7
8
|
logger = Logger()
|
|
8
|
-
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class _ElabUserTeamsDict(TypedDict, total=False):
|
|
12
|
+
id: int
|
|
13
|
+
name: str
|
|
14
|
+
usergroup: int
|
|
15
|
+
is_admin: bool
|
|
16
|
+
is_owner: bool
|
|
17
|
+
is_archived: bool
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
NewUserTeamsType = list[_ElabUserTeamsDict]
|
|
9
21
|
|
|
10
22
|
_DEBUG_LOG_EMIT_ONCE: bool = False
|
|
11
23
|
|
|
@@ -13,7 +25,7 @@ _DEBUG_LOG_EMIT_ONCE: bool = False
|
|
|
13
25
|
def handle_new_user_teams(user_teams: str | NewUserTeamsType) -> NewUserTeamsType:
|
|
14
26
|
global _DEBUG_LOG_EMIT_ONCE
|
|
15
27
|
|
|
16
|
-
struct_user_teams: list[
|
|
28
|
+
struct_user_teams: list[_ElabUserTeamsDict] = []
|
|
17
29
|
match user_teams:
|
|
18
30
|
case list():
|
|
19
31
|
struct_user_teams = user_teams
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
{
|
|
2
|
+
"apikeys": [],
|
|
3
|
+
"compounds": [],
|
|
4
|
+
"config": [],
|
|
5
|
+
"dspace": [],
|
|
6
|
+
"event": [],
|
|
7
|
+
"events": [],
|
|
8
|
+
"experiments": [
|
|
9
|
+
"comments",
|
|
10
|
+
"compounds_links",
|
|
11
|
+
"experiments_links",
|
|
12
|
+
"items_links",
|
|
13
|
+
"revisions",
|
|
14
|
+
"steps",
|
|
15
|
+
"tags",
|
|
16
|
+
"uploads"
|
|
17
|
+
],
|
|
18
|
+
"experiments_templates": [
|
|
19
|
+
"revisions",
|
|
20
|
+
"steps",
|
|
21
|
+
"tags"
|
|
22
|
+
],
|
|
23
|
+
"exports": [],
|
|
24
|
+
"extra_fields_keys": [],
|
|
25
|
+
"favtags": [],
|
|
26
|
+
"idps": [
|
|
27
|
+
"certs",
|
|
28
|
+
"endpoints"
|
|
29
|
+
],
|
|
30
|
+
"idps_sources": [],
|
|
31
|
+
"import": [],
|
|
32
|
+
"info": [],
|
|
33
|
+
"items": [
|
|
34
|
+
"comments",
|
|
35
|
+
"compounds_links",
|
|
36
|
+
"experiments_links",
|
|
37
|
+
"items_links",
|
|
38
|
+
"revisions",
|
|
39
|
+
"steps",
|
|
40
|
+
"tags",
|
|
41
|
+
"uploads"
|
|
42
|
+
],
|
|
43
|
+
"items_types": [
|
|
44
|
+
"steps",
|
|
45
|
+
"tags"
|
|
46
|
+
],
|
|
47
|
+
"reports": [],
|
|
48
|
+
"storage_units": [],
|
|
49
|
+
"teams": [
|
|
50
|
+
"experiments_categories",
|
|
51
|
+
"experiments_status",
|
|
52
|
+
"items_status",
|
|
53
|
+
"resources_categories",
|
|
54
|
+
"teamgroups"
|
|
55
|
+
],
|
|
56
|
+
"todolist": [],
|
|
57
|
+
"unfinished_steps": [],
|
|
58
|
+
"users": [
|
|
59
|
+
"notifications",
|
|
60
|
+
"uploads"
|
|
61
|
+
]
|
|
62
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
{
|
|
2
|
+
"apikeys": [],
|
|
3
|
+
"compounds": [],
|
|
4
|
+
"config": [],
|
|
5
|
+
"dspace": [],
|
|
6
|
+
"event": [],
|
|
7
|
+
"events": [],
|
|
8
|
+
"experiments": [
|
|
9
|
+
"comments",
|
|
10
|
+
"compounds_links",
|
|
11
|
+
"experiments_links",
|
|
12
|
+
"items_links",
|
|
13
|
+
"revisions",
|
|
14
|
+
"steps",
|
|
15
|
+
"tags",
|
|
16
|
+
"uploads"
|
|
17
|
+
],
|
|
18
|
+
"experiments_templates": [
|
|
19
|
+
"revisions",
|
|
20
|
+
"steps",
|
|
21
|
+
"tags"
|
|
22
|
+
],
|
|
23
|
+
"exports": [],
|
|
24
|
+
"extra_fields_keys": [],
|
|
25
|
+
"favtags": [],
|
|
26
|
+
"idps": [
|
|
27
|
+
"certs",
|
|
28
|
+
"endpoints"
|
|
29
|
+
],
|
|
30
|
+
"idps_sources": [],
|
|
31
|
+
"import": [],
|
|
32
|
+
"info": [],
|
|
33
|
+
"items": [
|
|
34
|
+
"comments",
|
|
35
|
+
"compounds_links",
|
|
36
|
+
"experiments_links",
|
|
37
|
+
"items_links",
|
|
38
|
+
"revisions",
|
|
39
|
+
"steps",
|
|
40
|
+
"tags",
|
|
41
|
+
"uploads"
|
|
42
|
+
],
|
|
43
|
+
"items_types": [
|
|
44
|
+
"steps",
|
|
45
|
+
"tags"
|
|
46
|
+
],
|
|
47
|
+
"reports": [],
|
|
48
|
+
"storage_units": [],
|
|
49
|
+
"teams": [
|
|
50
|
+
"experiments_categories",
|
|
51
|
+
"experiments_status",
|
|
52
|
+
"items_status",
|
|
53
|
+
"resources_categories",
|
|
54
|
+
"teamgroups"
|
|
55
|
+
],
|
|
56
|
+
"todolist": [],
|
|
57
|
+
"unfinished_steps": [],
|
|
58
|
+
"users": [
|
|
59
|
+
"notifications",
|
|
60
|
+
"uploads"
|
|
61
|
+
]
|
|
62
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
{
|
|
2
|
+
"apikeys": [],
|
|
3
|
+
"compounds": [],
|
|
4
|
+
"config": [],
|
|
5
|
+
"dspace": [],
|
|
6
|
+
"event": [],
|
|
7
|
+
"events": [],
|
|
8
|
+
"experiments": [
|
|
9
|
+
"comments",
|
|
10
|
+
"compounds_links",
|
|
11
|
+
"experiments_links",
|
|
12
|
+
"items_links",
|
|
13
|
+
"revisions",
|
|
14
|
+
"steps",
|
|
15
|
+
"tags",
|
|
16
|
+
"uploads"
|
|
17
|
+
],
|
|
18
|
+
"experiments_templates": [
|
|
19
|
+
"revisions",
|
|
20
|
+
"steps",
|
|
21
|
+
"tags"
|
|
22
|
+
],
|
|
23
|
+
"exports": [],
|
|
24
|
+
"extra_fields_keys": [],
|
|
25
|
+
"favtags": [],
|
|
26
|
+
"idps": [
|
|
27
|
+
"certs",
|
|
28
|
+
"endpoints"
|
|
29
|
+
],
|
|
30
|
+
"idps_sources": [],
|
|
31
|
+
"import": [],
|
|
32
|
+
"info": [],
|
|
33
|
+
"items": [
|
|
34
|
+
"comments",
|
|
35
|
+
"compounds_links",
|
|
36
|
+
"experiments_links",
|
|
37
|
+
"items_links",
|
|
38
|
+
"revisions",
|
|
39
|
+
"steps",
|
|
40
|
+
"tags",
|
|
41
|
+
"uploads"
|
|
42
|
+
],
|
|
43
|
+
"items_types": [
|
|
44
|
+
"steps",
|
|
45
|
+
"tags"
|
|
46
|
+
],
|
|
47
|
+
"reports": [],
|
|
48
|
+
"storage_units": [],
|
|
49
|
+
"teams": [
|
|
50
|
+
"experiments_categories",
|
|
51
|
+
"experiments_status",
|
|
52
|
+
"items_status",
|
|
53
|
+
"resources_categories",
|
|
54
|
+
"teamgroups"
|
|
55
|
+
],
|
|
56
|
+
"todolist": [],
|
|
57
|
+
"unfinished_steps": [],
|
|
58
|
+
"users": [
|
|
59
|
+
"notifications",
|
|
60
|
+
"uploads"
|
|
61
|
+
]
|
|
62
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
{
|
|
2
|
+
"apikeys": [],
|
|
3
|
+
"compounds": [],
|
|
4
|
+
"config": [],
|
|
5
|
+
"dspace": [],
|
|
6
|
+
"event": [],
|
|
7
|
+
"events": [],
|
|
8
|
+
"experiments": [
|
|
9
|
+
"comments",
|
|
10
|
+
"compounds_links",
|
|
11
|
+
"experiments_links",
|
|
12
|
+
"items_links",
|
|
13
|
+
"revisions",
|
|
14
|
+
"steps",
|
|
15
|
+
"tags",
|
|
16
|
+
"uploads"
|
|
17
|
+
],
|
|
18
|
+
"experiments_templates": [
|
|
19
|
+
"revisions",
|
|
20
|
+
"steps",
|
|
21
|
+
"tags"
|
|
22
|
+
],
|
|
23
|
+
"exports": [],
|
|
24
|
+
"extra_fields_keys": [],
|
|
25
|
+
"favtags": [],
|
|
26
|
+
"idps": [
|
|
27
|
+
"certs",
|
|
28
|
+
"endpoints"
|
|
29
|
+
],
|
|
30
|
+
"idps_sources": [],
|
|
31
|
+
"import": [],
|
|
32
|
+
"info": [],
|
|
33
|
+
"items": [
|
|
34
|
+
"comments",
|
|
35
|
+
"compounds_links",
|
|
36
|
+
"experiments_links",
|
|
37
|
+
"items_links",
|
|
38
|
+
"revisions",
|
|
39
|
+
"steps",
|
|
40
|
+
"tags",
|
|
41
|
+
"uploads"
|
|
42
|
+
],
|
|
43
|
+
"items_types": [
|
|
44
|
+
"steps",
|
|
45
|
+
"tags"
|
|
46
|
+
],
|
|
47
|
+
"reports": [],
|
|
48
|
+
"storage_units": [],
|
|
49
|
+
"teams": [
|
|
50
|
+
"experiments_categories",
|
|
51
|
+
"experiments_status",
|
|
52
|
+
"items_status",
|
|
53
|
+
"resources_categories",
|
|
54
|
+
"teamgroups"
|
|
55
|
+
],
|
|
56
|
+
"todolist": [],
|
|
57
|
+
"unfinished_steps": [],
|
|
58
|
+
"users": [
|
|
59
|
+
"notifications",
|
|
60
|
+
"uploads"
|
|
61
|
+
]
|
|
62
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
{
|
|
2
|
+
"apikeys": [],
|
|
3
|
+
"compounds": [],
|
|
4
|
+
"config": [],
|
|
5
|
+
"dspace": [],
|
|
6
|
+
"event": [],
|
|
7
|
+
"events": [],
|
|
8
|
+
"experiments": [
|
|
9
|
+
"comments",
|
|
10
|
+
"compounds_links",
|
|
11
|
+
"experiments_links",
|
|
12
|
+
"items_links",
|
|
13
|
+
"revisions",
|
|
14
|
+
"steps",
|
|
15
|
+
"tags",
|
|
16
|
+
"uploads"
|
|
17
|
+
],
|
|
18
|
+
"experiments_templates": [
|
|
19
|
+
"revisions",
|
|
20
|
+
"steps",
|
|
21
|
+
"tags"
|
|
22
|
+
],
|
|
23
|
+
"exports": [],
|
|
24
|
+
"extra_fields_keys": [],
|
|
25
|
+
"favtags": [],
|
|
26
|
+
"idps": [],
|
|
27
|
+
"idps_sources": [],
|
|
28
|
+
"import": [],
|
|
29
|
+
"info": [],
|
|
30
|
+
"items": [
|
|
31
|
+
"comments",
|
|
32
|
+
"compounds_links",
|
|
33
|
+
"experiments_links",
|
|
34
|
+
"items_links",
|
|
35
|
+
"revisions",
|
|
36
|
+
"steps",
|
|
37
|
+
"tags",
|
|
38
|
+
"uploads"
|
|
39
|
+
],
|
|
40
|
+
"items_types": [
|
|
41
|
+
"steps",
|
|
42
|
+
"tags"
|
|
43
|
+
],
|
|
44
|
+
"reports": [],
|
|
45
|
+
"storage_units": [],
|
|
46
|
+
"teams": [
|
|
47
|
+
"experiments_categories",
|
|
48
|
+
"experiments_status",
|
|
49
|
+
"items_status",
|
|
50
|
+
"resources_categories",
|
|
51
|
+
"teamgroups"
|
|
52
|
+
],
|
|
53
|
+
"todolist": [],
|
|
54
|
+
"unfinished_steps": [],
|
|
55
|
+
"users": [
|
|
56
|
+
"notifications",
|
|
57
|
+
"uploads"
|
|
58
|
+
]
|
|
59
|
+
}
|
|
@@ -240,7 +240,7 @@ class ProperPath:
|
|
|
240
240
|
f"Could not open file {self._error_helper_compare_path_source(self.name, file)}. "
|
|
241
241
|
f"Exception: {e!r}"
|
|
242
242
|
)
|
|
243
|
-
self.PathException = e
|
|
243
|
+
self.PathException = e.__class__
|
|
244
244
|
raise e
|
|
245
245
|
except (os_exception := OSError) as e:
|
|
246
246
|
self.err_logger.debug(
|
|
@@ -1,6 +1,8 @@
|
|
|
1
|
+
from collections import defaultdict
|
|
1
2
|
from datetime import datetime
|
|
3
|
+
from functools import cached_property
|
|
2
4
|
from pathlib import Path
|
|
3
|
-
from typing import Union
|
|
5
|
+
from typing import TypedDict, Union
|
|
4
6
|
|
|
5
7
|
from dateutil import parser
|
|
6
8
|
from dateutil.relativedelta import relativedelta
|
|
@@ -14,6 +16,30 @@ from ..commons import AsyncInformation, Information, RecursiveInformation
|
|
|
14
16
|
logger = Logger()
|
|
15
17
|
|
|
16
18
|
|
|
19
|
+
class TeamMembersDict(TypedDict):
|
|
20
|
+
firstname: str
|
|
21
|
+
lastname: str
|
|
22
|
+
email: str
|
|
23
|
+
usergroup: str
|
|
24
|
+
is_archived: bool
|
|
25
|
+
is_expired: bool
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class TeamsDict(TypedDict, total=False):
|
|
29
|
+
active_member_count: int
|
|
30
|
+
admins: dict[str, TeamMembersDict]
|
|
31
|
+
members: dict[str, TeamMembersDict]
|
|
32
|
+
on_trial: bool
|
|
33
|
+
team_created_at: str
|
|
34
|
+
team_id: int
|
|
35
|
+
team_name: str
|
|
36
|
+
total_archived_member_count: int
|
|
37
|
+
total_expired_member_count: int
|
|
38
|
+
total_member_count: int
|
|
39
|
+
total_unarchived_member_count: int
|
|
40
|
+
trial_ends_at: str
|
|
41
|
+
|
|
42
|
+
|
|
17
43
|
class UsersInformation:
|
|
18
44
|
__slots__ = "users", "user_id_prefix"
|
|
19
45
|
endpoint_name = "users"
|
|
@@ -27,6 +53,7 @@ class UsersInformation:
|
|
|
27
53
|
)
|
|
28
54
|
for user in all_users:
|
|
29
55
|
if (user_teams := user.get("teams")) is not None:
|
|
56
|
+
# noinspection PyTypeChecker
|
|
30
57
|
if handle_new_user_teams(user_teams) is not None:
|
|
31
58
|
return all_users
|
|
32
59
|
return await fallback_all_users.items()
|
|
@@ -102,7 +129,7 @@ class OwnersInformation:
|
|
|
102
129
|
|
|
103
130
|
|
|
104
131
|
class TeamsList:
|
|
105
|
-
__slots__ = "users", "teams", "contract"
|
|
132
|
+
__slots__ = "users", "teams", "contract", "__dict__"
|
|
106
133
|
|
|
107
134
|
def __init__(
|
|
108
135
|
self,
|
|
@@ -112,16 +139,12 @@ class TeamsList:
|
|
|
112
139
|
self.users = users_information
|
|
113
140
|
self.teams = teams_information
|
|
114
141
|
|
|
115
|
-
@
|
|
142
|
+
@cached_property
|
|
116
143
|
def BILL_RUN_DATE(self) -> datetime:
|
|
144
|
+
# cached_property is used to make sure that the same
|
|
145
|
+
# current datetime is used for all comparisons
|
|
117
146
|
return datetime.now()
|
|
118
147
|
|
|
119
|
-
@BILL_RUN_DATE.setter
|
|
120
|
-
def BILL_RUN_DATE(self, value):
|
|
121
|
-
raise AttributeError(
|
|
122
|
-
"BILL_RUN_DATE is always the current date. It cannot be modified!"
|
|
123
|
-
)
|
|
124
|
-
|
|
125
148
|
@property
|
|
126
149
|
def LAUNCH_DATE(self) -> datetime:
|
|
127
150
|
return datetime(2023, 8, 1, 0, 0, 0)
|
|
@@ -141,62 +164,44 @@ class TeamsList:
|
|
|
141
164
|
return True
|
|
142
165
|
return False
|
|
143
166
|
|
|
144
|
-
def
|
|
167
|
+
def _get_teams(self, admins_only: bool = False) -> dict:
|
|
145
168
|
# Generate teams information with team owners
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
169
|
+
# noinspection PyTypeChecker
|
|
170
|
+
team_members: defaultdict[str, dict[str, TeamMembersDict]] = defaultdict(dict)
|
|
171
|
+
# noinspection PyTypeChecker
|
|
172
|
+
admins: defaultdict[str, dict[str, TeamMembersDict]] = defaultdict(dict)
|
|
173
|
+
teams: dict[str, TeamsDict] = {}
|
|
149
174
|
for u in self.users:
|
|
150
175
|
user_teams = handle_new_user_teams(u["teams"])
|
|
151
|
-
for team in user_teams: # O(n^2):
|
|
176
|
+
for team in user_teams: # O(n^2): we iterate over the "teams" field
|
|
152
177
|
uid = u["userid"]
|
|
153
178
|
# Get teams user count
|
|
154
179
|
team_id = str(team["id"])
|
|
155
|
-
|
|
156
|
-
|
|
180
|
+
team_members[team_id].update(
|
|
181
|
+
{
|
|
157
182
|
uid: {
|
|
158
183
|
"firstname": u["firstname"],
|
|
159
184
|
"lastname": u["lastname"],
|
|
160
185
|
"email": u["email"],
|
|
161
186
|
"usergroup": team["usergroup"],
|
|
162
|
-
"
|
|
187
|
+
"is_archived": bool(team["is_archived"]),
|
|
188
|
+
"is_expired": self.is_user_expired(user_data=u),
|
|
163
189
|
}
|
|
164
190
|
}
|
|
165
|
-
|
|
166
|
-
|
|
191
|
+
)
|
|
192
|
+
if team["usergroup"] == ElabUserGroups.admin:
|
|
193
|
+
admins[team_id].update(
|
|
167
194
|
{
|
|
168
195
|
uid: {
|
|
169
196
|
"firstname": u["firstname"],
|
|
170
197
|
"lastname": u["lastname"],
|
|
171
198
|
"email": u["email"],
|
|
172
199
|
"usergroup": team["usergroup"],
|
|
173
|
-
"
|
|
200
|
+
"is_archived": bool(team["is_archived"]),
|
|
201
|
+
"is_expired": self.is_user_expired(user_data=u),
|
|
174
202
|
}
|
|
175
203
|
}
|
|
176
204
|
)
|
|
177
|
-
if team["usergroup"] == ElabUserGroups.admin:
|
|
178
|
-
if not admins.get(team_id):
|
|
179
|
-
admins[team_id] = {
|
|
180
|
-
uid: {
|
|
181
|
-
"firstname": u["firstname"],
|
|
182
|
-
"lastname": u["lastname"],
|
|
183
|
-
"email": u["email"],
|
|
184
|
-
"usergroup": team["usergroup"],
|
|
185
|
-
"expired": self.is_user_expired(user_data=u),
|
|
186
|
-
}
|
|
187
|
-
}
|
|
188
|
-
else:
|
|
189
|
-
admins[team_id].update(
|
|
190
|
-
{
|
|
191
|
-
uid: {
|
|
192
|
-
"firstname": u["firstname"],
|
|
193
|
-
"lastname": u["lastname"],
|
|
194
|
-
"email": u["email"],
|
|
195
|
-
"usergroup": team["usergroup"],
|
|
196
|
-
"expired": self.is_user_expired(user_data=u),
|
|
197
|
-
}
|
|
198
|
-
}
|
|
199
|
-
)
|
|
200
205
|
# Get team basic information
|
|
201
206
|
teams[team_id] = {}
|
|
202
207
|
teams[team_id]["team_name"] = team["name"]
|
|
@@ -214,10 +219,22 @@ class TeamsList:
|
|
|
214
219
|
teams[team_id]["members"] = {}
|
|
215
220
|
teams[team_id]["members"] = team_members[team_id]
|
|
216
221
|
teams[team_id]["admins"] = admins.get(team_id, {})
|
|
217
|
-
teams[team_id]["
|
|
218
|
-
teams[team_id]["
|
|
222
|
+
teams[team_id]["total_member_count"] = len(team_members[team_id])
|
|
223
|
+
teams[team_id]["total_unarchived_member_count"] = 0
|
|
224
|
+
teams[team_id]["total_archived_member_count"] = 0
|
|
225
|
+
teams[team_id]["total_expired_member_count"] = 0
|
|
226
|
+
teams[team_id]["active_member_count"] = 0
|
|
219
227
|
for k in team_members[team_id]:
|
|
220
|
-
if team_members[team_id][k]["
|
|
228
|
+
if not team_members[team_id][k]["is_archived"]:
|
|
229
|
+
teams[team_id]["total_unarchived_member_count"] += 1
|
|
230
|
+
if team_members[team_id][k]["is_archived"]:
|
|
231
|
+
teams[team_id]["total_archived_member_count"] += 1
|
|
232
|
+
if team_members[team_id][k]["is_expired"]:
|
|
233
|
+
teams[team_id]["total_expired_member_count"] += 1
|
|
234
|
+
if not (
|
|
235
|
+
team_members[team_id][k]["is_expired"]
|
|
236
|
+
or team_members[team_id][k]["is_archived"]
|
|
237
|
+
):
|
|
221
238
|
teams[team_id]["active_member_count"] += 1
|
|
222
239
|
# Add trial information
|
|
223
240
|
trial_starts_at = self.team_trial_start_date(
|
|
@@ -225,12 +242,12 @@ class TeamsList:
|
|
|
225
242
|
)
|
|
226
243
|
trial_ends_at = trial_starts_at + self.TRIAL_PERIOD
|
|
227
244
|
teams[team_id]["trial_ends_at"] = str(trial_ends_at)
|
|
228
|
-
teams[team_id]["on_trial"] = trial_ends_at >
|
|
245
|
+
teams[team_id]["on_trial"] = trial_ends_at > self.BILL_RUN_DATE
|
|
229
246
|
|
|
230
247
|
return teams
|
|
231
248
|
|
|
232
249
|
def items(self, admins_only: bool = False) -> dict:
|
|
233
|
-
return self.
|
|
250
|
+
return self._get_teams(admins_only)
|
|
234
251
|
|
|
235
252
|
|
|
236
253
|
class OwnersList:
|