esgpull 0.6.3__py3-none-any.whl
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.
- esgpull/__init__.py +12 -0
- esgpull/auth.py +181 -0
- esgpull/cli/__init__.py +73 -0
- esgpull/cli/add.py +103 -0
- esgpull/cli/autoremove.py +38 -0
- esgpull/cli/config.py +116 -0
- esgpull/cli/convert.py +285 -0
- esgpull/cli/decorators.py +342 -0
- esgpull/cli/download.py +74 -0
- esgpull/cli/facet.py +23 -0
- esgpull/cli/get.py +28 -0
- esgpull/cli/install.py +85 -0
- esgpull/cli/link.py +105 -0
- esgpull/cli/login.py +56 -0
- esgpull/cli/remove.py +73 -0
- esgpull/cli/retry.py +43 -0
- esgpull/cli/search.py +201 -0
- esgpull/cli/self.py +238 -0
- esgpull/cli/show.py +66 -0
- esgpull/cli/status.py +67 -0
- esgpull/cli/track.py +87 -0
- esgpull/cli/update.py +184 -0
- esgpull/cli/utils.py +247 -0
- esgpull/config.py +410 -0
- esgpull/constants.py +56 -0
- esgpull/context.py +724 -0
- esgpull/database.py +161 -0
- esgpull/download.py +162 -0
- esgpull/esgpull.py +447 -0
- esgpull/exceptions.py +167 -0
- esgpull/fs.py +253 -0
- esgpull/graph.py +460 -0
- esgpull/install_config.py +185 -0
- esgpull/migrations/README +1 -0
- esgpull/migrations/env.py +82 -0
- esgpull/migrations/script.py.mako +24 -0
- esgpull/migrations/versions/0.3.0_update_tables.py +170 -0
- esgpull/migrations/versions/0.3.1_update_tables.py +25 -0
- esgpull/migrations/versions/0.3.2_update_tables.py +26 -0
- esgpull/migrations/versions/0.3.3_update_tables.py +25 -0
- esgpull/migrations/versions/0.3.4_update_tables.py +25 -0
- esgpull/migrations/versions/0.3.5_update_tables.py +25 -0
- esgpull/migrations/versions/0.3.6_update_tables.py +26 -0
- esgpull/migrations/versions/0.3.7_update_tables.py +26 -0
- esgpull/migrations/versions/0.3.8_update_tables.py +26 -0
- esgpull/migrations/versions/0.4.0_update_tables.py +25 -0
- esgpull/migrations/versions/0.5.0_update_tables.py +26 -0
- esgpull/migrations/versions/0.5.1_update_tables.py +26 -0
- esgpull/migrations/versions/0.5.2_update_tables.py +25 -0
- esgpull/migrations/versions/0.5.3_update_tables.py +26 -0
- esgpull/migrations/versions/0.5.4_update_tables.py +25 -0
- esgpull/migrations/versions/0.5.5_update_tables.py +25 -0
- esgpull/migrations/versions/0.6.0_update_tables.py +25 -0
- esgpull/migrations/versions/0.6.1_update_tables.py +25 -0
- esgpull/migrations/versions/0.6.2_update_tables.py +25 -0
- esgpull/migrations/versions/0.6.3_update_tables.py +25 -0
- esgpull/models/__init__.py +31 -0
- esgpull/models/base.py +50 -0
- esgpull/models/dataset.py +34 -0
- esgpull/models/facet.py +18 -0
- esgpull/models/file.py +65 -0
- esgpull/models/options.py +164 -0
- esgpull/models/query.py +481 -0
- esgpull/models/selection.py +201 -0
- esgpull/models/sql.py +258 -0
- esgpull/models/synda_file.py +85 -0
- esgpull/models/tag.py +19 -0
- esgpull/models/utils.py +54 -0
- esgpull/presets.py +13 -0
- esgpull/processor.py +172 -0
- esgpull/py.typed +0 -0
- esgpull/result.py +53 -0
- esgpull/tui.py +346 -0
- esgpull/utils.py +54 -0
- esgpull/version.py +1 -0
- esgpull-0.6.3.dist-info/METADATA +110 -0
- esgpull-0.6.3.dist-info/RECORD +80 -0
- esgpull-0.6.3.dist-info/WHEEL +4 -0
- esgpull-0.6.3.dist-info/entry_points.txt +3 -0
- esgpull-0.6.3.dist-info/licenses/LICENSE +28 -0
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"""update tables
|
|
2
|
+
|
|
3
|
+
Revision ID: 0.4.0
|
|
4
|
+
Revises: 0.3.8
|
|
5
|
+
Create Date: 2023-05-02 11:52:41.283723
|
|
6
|
+
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
# revision identifiers, used by Alembic.
|
|
10
|
+
revision = "0.4.0"
|
|
11
|
+
down_revision = "0.3.8"
|
|
12
|
+
branch_labels = None
|
|
13
|
+
depends_on = None
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def upgrade() -> None:
|
|
17
|
+
# ### commands auto generated by Alembic - please adjust! ###
|
|
18
|
+
pass
|
|
19
|
+
# ### end Alembic commands ###
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def downgrade() -> None:
|
|
23
|
+
# ### commands auto generated by Alembic - please adjust! ###
|
|
24
|
+
pass
|
|
25
|
+
# ### end Alembic commands ###
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
"""update tables
|
|
2
|
+
|
|
3
|
+
Revision ID: 0.5.0
|
|
4
|
+
Revises: 0.4.0
|
|
5
|
+
Create Date: 2023-05-05 17:10:57.525968
|
|
6
|
+
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
# revision identifiers, used by Alembic.
|
|
11
|
+
revision = "0.5.0"
|
|
12
|
+
down_revision = "0.4.0"
|
|
13
|
+
branch_labels = None
|
|
14
|
+
depends_on = None
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def upgrade() -> None:
|
|
18
|
+
# ### commands auto generated by Alembic - please adjust! ###
|
|
19
|
+
pass
|
|
20
|
+
# ### end Alembic commands ###
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def downgrade() -> None:
|
|
24
|
+
# ### commands auto generated by Alembic - please adjust! ###
|
|
25
|
+
pass
|
|
26
|
+
# ### end Alembic commands ###
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
"""update tables
|
|
2
|
+
|
|
3
|
+
Revision ID: 0.5.1
|
|
4
|
+
Revises: 0.5.0
|
|
5
|
+
Create Date: 2023-05-17 18:09:56.258545
|
|
6
|
+
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
# revision identifiers, used by Alembic.
|
|
11
|
+
revision = "0.5.1"
|
|
12
|
+
down_revision = "0.5.0"
|
|
13
|
+
branch_labels = None
|
|
14
|
+
depends_on = None
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def upgrade() -> None:
|
|
18
|
+
# ### commands auto generated by Alembic - please adjust! ###
|
|
19
|
+
pass
|
|
20
|
+
# ### end Alembic commands ###
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def downgrade() -> None:
|
|
24
|
+
# ### commands auto generated by Alembic - please adjust! ###
|
|
25
|
+
pass
|
|
26
|
+
# ### end Alembic commands ###
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"""update tables
|
|
2
|
+
|
|
3
|
+
Revision ID: 0.5.2
|
|
4
|
+
Revises: 0.5.1
|
|
5
|
+
Create Date: 2023-06-06 14:13:19.695120
|
|
6
|
+
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
# revision identifiers, used by Alembic.
|
|
10
|
+
revision = "0.5.2"
|
|
11
|
+
down_revision = "0.5.1"
|
|
12
|
+
branch_labels = None
|
|
13
|
+
depends_on = None
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def upgrade() -> None:
|
|
17
|
+
# ### commands auto generated by Alembic - please adjust! ###
|
|
18
|
+
pass
|
|
19
|
+
# ### end Alembic commands ###
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def downgrade() -> None:
|
|
23
|
+
# ### commands auto generated by Alembic - please adjust! ###
|
|
24
|
+
pass
|
|
25
|
+
# ### end Alembic commands ###
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
"""update tables
|
|
2
|
+
|
|
3
|
+
Revision ID: 0.5.3
|
|
4
|
+
Revises: 0.5.2
|
|
5
|
+
Create Date: 2023-06-13 10:27:02.691266
|
|
6
|
+
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
# revision identifiers, used by Alembic.
|
|
11
|
+
revision = "0.5.3"
|
|
12
|
+
down_revision = "0.5.2"
|
|
13
|
+
branch_labels = None
|
|
14
|
+
depends_on = None
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def upgrade() -> None:
|
|
18
|
+
# ### commands auto generated by Alembic - please adjust! ###
|
|
19
|
+
pass
|
|
20
|
+
# ### end Alembic commands ###
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def downgrade() -> None:
|
|
24
|
+
# ### commands auto generated by Alembic - please adjust! ###
|
|
25
|
+
pass
|
|
26
|
+
# ### end Alembic commands ###
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"""update tables
|
|
2
|
+
|
|
3
|
+
Revision ID: 0.5.4
|
|
4
|
+
Revises: 0.5.3
|
|
5
|
+
Create Date: 2023-06-13 11:43:15.867306
|
|
6
|
+
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
# revision identifiers, used by Alembic.
|
|
10
|
+
revision = "0.5.4"
|
|
11
|
+
down_revision = "0.5.3"
|
|
12
|
+
branch_labels = None
|
|
13
|
+
depends_on = None
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def upgrade() -> None:
|
|
17
|
+
# ### commands auto generated by Alembic - please adjust! ###
|
|
18
|
+
pass
|
|
19
|
+
# ### end Alembic commands ###
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def downgrade() -> None:
|
|
23
|
+
# ### commands auto generated by Alembic - please adjust! ###
|
|
24
|
+
pass
|
|
25
|
+
# ### end Alembic commands ###
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"""update tables
|
|
2
|
+
|
|
3
|
+
Revision ID: 0.5.5
|
|
4
|
+
Revises: 0.5.4
|
|
5
|
+
Create Date: 2023-06-23 15:21:08.251368
|
|
6
|
+
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
# revision identifiers, used by Alembic.
|
|
10
|
+
revision = "0.5.5"
|
|
11
|
+
down_revision = "0.5.4"
|
|
12
|
+
branch_labels = None
|
|
13
|
+
depends_on = None
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def upgrade() -> None:
|
|
17
|
+
# ### commands auto generated by Alembic - please adjust! ###
|
|
18
|
+
pass
|
|
19
|
+
# ### end Alembic commands ###
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def downgrade() -> None:
|
|
23
|
+
# ### commands auto generated by Alembic - please adjust! ###
|
|
24
|
+
pass
|
|
25
|
+
# ### end Alembic commands ###
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"""update tables
|
|
2
|
+
|
|
3
|
+
Revision ID: 0.6.0
|
|
4
|
+
Revises: 0.5.5
|
|
5
|
+
Create Date: 2023-07-28 15:01:40.702583
|
|
6
|
+
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
# revision identifiers, used by Alembic.
|
|
10
|
+
revision = "0.6.0"
|
|
11
|
+
down_revision = "0.5.5"
|
|
12
|
+
branch_labels = None
|
|
13
|
+
depends_on = None
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def upgrade() -> None:
|
|
17
|
+
# ### commands auto generated by Alembic - please adjust! ###
|
|
18
|
+
pass
|
|
19
|
+
# ### end Alembic commands ###
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def downgrade() -> None:
|
|
23
|
+
# ### commands auto generated by Alembic - please adjust! ###
|
|
24
|
+
pass
|
|
25
|
+
# ### end Alembic commands ###
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"""update tables
|
|
2
|
+
|
|
3
|
+
Revision ID: 0.6.1
|
|
4
|
+
Revises: 0.6.0
|
|
5
|
+
Create Date: 2023-07-28 18:40:20.911726
|
|
6
|
+
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
# revision identifiers, used by Alembic.
|
|
10
|
+
revision = "0.6.1"
|
|
11
|
+
down_revision = "0.6.0"
|
|
12
|
+
branch_labels = None
|
|
13
|
+
depends_on = None
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def upgrade() -> None:
|
|
17
|
+
# ### commands auto generated by Alembic - please adjust! ###
|
|
18
|
+
pass
|
|
19
|
+
# ### end Alembic commands ###
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def downgrade() -> None:
|
|
23
|
+
# ### commands auto generated by Alembic - please adjust! ###
|
|
24
|
+
pass
|
|
25
|
+
# ### end Alembic commands ###
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"""update tables
|
|
2
|
+
|
|
3
|
+
Revision ID: 0.6.2
|
|
4
|
+
Revises: 0.6.1
|
|
5
|
+
Create Date: 2023-08-18 17:11:15.605131
|
|
6
|
+
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
# revision identifiers, used by Alembic.
|
|
10
|
+
revision = "0.6.2"
|
|
11
|
+
down_revision = "0.6.1"
|
|
12
|
+
branch_labels = None
|
|
13
|
+
depends_on = None
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def upgrade() -> None:
|
|
17
|
+
# ### commands auto generated by Alembic - please adjust! ###
|
|
18
|
+
pass
|
|
19
|
+
# ### end Alembic commands ###
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def downgrade() -> None:
|
|
23
|
+
# ### commands auto generated by Alembic - please adjust! ###
|
|
24
|
+
pass
|
|
25
|
+
# ### end Alembic commands ###
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"""update tables
|
|
2
|
+
|
|
3
|
+
Revision ID: 0.6.3
|
|
4
|
+
Revises: 0.6.2
|
|
5
|
+
Create Date: 2024-06-13 11:48:48.097943
|
|
6
|
+
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
# revision identifiers, used by Alembic.
|
|
10
|
+
revision = "0.6.3"
|
|
11
|
+
down_revision = "0.6.2"
|
|
12
|
+
branch_labels = None
|
|
13
|
+
depends_on = None
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def upgrade() -> None:
|
|
17
|
+
# ### commands auto generated by Alembic - please adjust! ###
|
|
18
|
+
pass
|
|
19
|
+
# ### end Alembic commands ###
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def downgrade() -> None:
|
|
23
|
+
# ### commands auto generated by Alembic - please adjust! ###
|
|
24
|
+
pass
|
|
25
|
+
# ### end Alembic commands ###
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
from typing import TypeVar
|
|
2
|
+
|
|
3
|
+
from esgpull.models.base import Base
|
|
4
|
+
from esgpull.models.dataset import Dataset
|
|
5
|
+
from esgpull.models.facet import Facet
|
|
6
|
+
from esgpull.models.file import FastFile, FileStatus
|
|
7
|
+
from esgpull.models.options import Option, Options
|
|
8
|
+
from esgpull.models.query import File, LegacyQuery, Query, QueryDict
|
|
9
|
+
from esgpull.models.selection import Selection
|
|
10
|
+
from esgpull.models.synda_file import SyndaFile
|
|
11
|
+
from esgpull.models.tag import Tag
|
|
12
|
+
|
|
13
|
+
Table = TypeVar("Table", bound=Base)
|
|
14
|
+
|
|
15
|
+
__all__ = [
|
|
16
|
+
"Base",
|
|
17
|
+
"Dataset",
|
|
18
|
+
"Facet",
|
|
19
|
+
"FastFile",
|
|
20
|
+
"File",
|
|
21
|
+
"FileStatus",
|
|
22
|
+
"LegacyQuery",
|
|
23
|
+
"Option",
|
|
24
|
+
"Options",
|
|
25
|
+
"Query",
|
|
26
|
+
"QueryDict",
|
|
27
|
+
"Selection",
|
|
28
|
+
"SyndaFile",
|
|
29
|
+
"Table",
|
|
30
|
+
"Tag",
|
|
31
|
+
]
|
esgpull/models/base.py
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
from collections.abc import Mapping
|
|
2
|
+
from dataclasses import Field
|
|
3
|
+
from hashlib import sha1
|
|
4
|
+
from typing import Any, ClassVar, TypeVar, cast
|
|
5
|
+
|
|
6
|
+
import sqlalchemy as sa
|
|
7
|
+
from sqlalchemy.orm import (
|
|
8
|
+
DeclarativeBase,
|
|
9
|
+
InstanceState,
|
|
10
|
+
Mapped,
|
|
11
|
+
MappedAsDataclass,
|
|
12
|
+
mapped_column,
|
|
13
|
+
)
|
|
14
|
+
|
|
15
|
+
T = TypeVar("T")
|
|
16
|
+
Sha = sa.String(40)
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class Base(MappedAsDataclass, DeclarativeBase):
|
|
20
|
+
__dataclass_fields__: ClassVar[dict[str, Field]]
|
|
21
|
+
__sql_attrs__ = ("id", "sha", "_sa_instance_state", "__dataclass_fields__")
|
|
22
|
+
|
|
23
|
+
sha: Mapped[str] = mapped_column(
|
|
24
|
+
Sha,
|
|
25
|
+
init=False,
|
|
26
|
+
repr=False,
|
|
27
|
+
primary_key=True,
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
@property
|
|
31
|
+
def _names(self) -> tuple[str, ...]:
|
|
32
|
+
result: tuple[str, ...] = ()
|
|
33
|
+
for name in self.__dataclass_fields__:
|
|
34
|
+
if name in self.__sql_attrs__:
|
|
35
|
+
continue
|
|
36
|
+
result += (name,)
|
|
37
|
+
return result
|
|
38
|
+
|
|
39
|
+
def _as_bytes(self) -> bytes:
|
|
40
|
+
raise NotImplementedError
|
|
41
|
+
|
|
42
|
+
def compute_sha(self) -> None:
|
|
43
|
+
self.sha = sha1(self._as_bytes()).hexdigest()
|
|
44
|
+
|
|
45
|
+
@property
|
|
46
|
+
def state(self) -> InstanceState:
|
|
47
|
+
return cast(InstanceState, sa.inspect(self))
|
|
48
|
+
|
|
49
|
+
def asdict(self) -> Mapping[str, Any]:
|
|
50
|
+
raise NotImplementedError
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from dataclasses import asdict, dataclass
|
|
4
|
+
|
|
5
|
+
from esgpull.models.utils import find_int, find_str
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
@dataclass
|
|
9
|
+
class Dataset:
|
|
10
|
+
dataset_id: str
|
|
11
|
+
master_id: str
|
|
12
|
+
version: str
|
|
13
|
+
data_node: str
|
|
14
|
+
size: int
|
|
15
|
+
number_of_files: int
|
|
16
|
+
|
|
17
|
+
@classmethod
|
|
18
|
+
def serialize(cls, source: dict) -> Dataset:
|
|
19
|
+
dataset_id = find_str(source["instance_id"]).partition("|")[0]
|
|
20
|
+
master_id, version = dataset_id.rsplit(".", 1)
|
|
21
|
+
data_node = find_str(source["data_node"])
|
|
22
|
+
size = find_int(source["size"])
|
|
23
|
+
number_of_files = find_int(source["number_of_files"])
|
|
24
|
+
return cls(
|
|
25
|
+
dataset_id=dataset_id,
|
|
26
|
+
master_id=master_id,
|
|
27
|
+
version=version,
|
|
28
|
+
data_node=data_node,
|
|
29
|
+
size=size,
|
|
30
|
+
number_of_files=number_of_files,
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
def asdict(self) -> dict:
|
|
34
|
+
return asdict(self)
|
esgpull/models/facet.py
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import sqlalchemy as sa
|
|
2
|
+
from sqlalchemy.orm import Mapped, mapped_column
|
|
3
|
+
|
|
4
|
+
from esgpull.models.base import Base
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class Facet(Base):
|
|
8
|
+
__tablename__ = "facet"
|
|
9
|
+
|
|
10
|
+
name: Mapped[str] = mapped_column(sa.String(64))
|
|
11
|
+
value: Mapped[str] = mapped_column(sa.String(255))
|
|
12
|
+
|
|
13
|
+
def _as_bytes(self) -> bytes:
|
|
14
|
+
self_tuple = (self.name, self.value)
|
|
15
|
+
return str(self_tuple).encode()
|
|
16
|
+
|
|
17
|
+
def __hash__(self) -> int:
|
|
18
|
+
return hash(self._as_bytes())
|
esgpull/models/file.py
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass
|
|
4
|
+
from enum import Enum
|
|
5
|
+
|
|
6
|
+
from typing_extensions import NotRequired, TypedDict
|
|
7
|
+
|
|
8
|
+
from esgpull.models.base import Base
|
|
9
|
+
from esgpull.models.utils import find_str
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class FileStatus(Enum):
|
|
13
|
+
New = "new"
|
|
14
|
+
Queued = "queued"
|
|
15
|
+
Starting = "starting"
|
|
16
|
+
Started = "started"
|
|
17
|
+
Pausing = "pausing"
|
|
18
|
+
Paused = "paused"
|
|
19
|
+
Error = "error"
|
|
20
|
+
Cancelled = "cancelled"
|
|
21
|
+
Done = "done"
|
|
22
|
+
|
|
23
|
+
@classmethod
|
|
24
|
+
def retryable(cls) -> list[FileStatus]:
|
|
25
|
+
return [cls.Error, cls.Cancelled]
|
|
26
|
+
|
|
27
|
+
@classmethod
|
|
28
|
+
def contains(cls, s: str) -> bool:
|
|
29
|
+
return s in [v.value for v in cls]
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class FileDict(TypedDict):
|
|
33
|
+
file_id: str
|
|
34
|
+
dataset_id: str
|
|
35
|
+
master_id: str
|
|
36
|
+
url: str
|
|
37
|
+
version: str
|
|
38
|
+
filename: str
|
|
39
|
+
local_path: str
|
|
40
|
+
data_node: str
|
|
41
|
+
checksum: str
|
|
42
|
+
checksum_type: str
|
|
43
|
+
size: int
|
|
44
|
+
status: NotRequired[str]
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
@dataclass(init=False)
|
|
48
|
+
class FastFile:
|
|
49
|
+
sha: str
|
|
50
|
+
file_id: str
|
|
51
|
+
checksum: str
|
|
52
|
+
|
|
53
|
+
def _as_bytes(self) -> bytes:
|
|
54
|
+
self_tuple = (self.file_id, self.checksum)
|
|
55
|
+
return str(self_tuple).encode()
|
|
56
|
+
|
|
57
|
+
@classmethod
|
|
58
|
+
def serialize(cls, source: dict) -> FastFile:
|
|
59
|
+
result = cls()
|
|
60
|
+
dataset_id = find_str(source["dataset_id"]).partition("|")[0]
|
|
61
|
+
filename = find_str(source["title"])
|
|
62
|
+
result.file_id = ".".join([dataset_id, filename])
|
|
63
|
+
result.checksum = find_str(source["checksum"])
|
|
64
|
+
Base.compute_sha(result) # type: ignore
|
|
65
|
+
return result
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from collections.abc import Iterator, MutableMapping
|
|
4
|
+
from enum import Enum
|
|
5
|
+
|
|
6
|
+
import sqlalchemy as sa
|
|
7
|
+
from sqlalchemy.orm import Mapped, mapped_column
|
|
8
|
+
|
|
9
|
+
from esgpull.models.base import Base
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class Option(Enum):
|
|
13
|
+
false = 0, False
|
|
14
|
+
true = 1, True
|
|
15
|
+
none = 2, None
|
|
16
|
+
notset = 3, None
|
|
17
|
+
|
|
18
|
+
@classmethod
|
|
19
|
+
def _missing_(cls, value):
|
|
20
|
+
if isinstance(value, str) and value in cls._member_map_:
|
|
21
|
+
return cls[value]
|
|
22
|
+
elif isinstance(value, bool):
|
|
23
|
+
if value:
|
|
24
|
+
return cls.true
|
|
25
|
+
else:
|
|
26
|
+
return cls.false
|
|
27
|
+
elif value is None:
|
|
28
|
+
return cls.none
|
|
29
|
+
else:
|
|
30
|
+
raise ValueError(value)
|
|
31
|
+
|
|
32
|
+
def is_set(self) -> bool:
|
|
33
|
+
return self in [
|
|
34
|
+
Option.true,
|
|
35
|
+
Option.false,
|
|
36
|
+
Option.none,
|
|
37
|
+
]
|
|
38
|
+
|
|
39
|
+
def is_bool(self) -> bool:
|
|
40
|
+
return self in [Option.true, Option.false]
|
|
41
|
+
|
|
42
|
+
def __bool__(self) -> bool:
|
|
43
|
+
if not self.is_bool():
|
|
44
|
+
raise ValueError(self)
|
|
45
|
+
return self == Option.true
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
class Options(Base):
|
|
49
|
+
__tablename__ = "options"
|
|
50
|
+
|
|
51
|
+
distrib: Mapped[Option] = mapped_column(sa.Enum(Option))
|
|
52
|
+
latest: Mapped[Option] = mapped_column(sa.Enum(Option))
|
|
53
|
+
replica: Mapped[Option] = mapped_column(sa.Enum(Option))
|
|
54
|
+
retracted: Mapped[Option] = mapped_column(sa.Enum(Option))
|
|
55
|
+
|
|
56
|
+
_distrib_ = Option(False)
|
|
57
|
+
_latest_ = Option(True)
|
|
58
|
+
_replica_ = Option(None)
|
|
59
|
+
_retracted_ = Option(False)
|
|
60
|
+
|
|
61
|
+
@classmethod
|
|
62
|
+
def default(cls) -> Options:
|
|
63
|
+
return cls(
|
|
64
|
+
cls._distrib_,
|
|
65
|
+
cls._latest_,
|
|
66
|
+
cls._replica_,
|
|
67
|
+
cls._retracted_,
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
@classmethod
|
|
71
|
+
def _set_defaults(
|
|
72
|
+
cls,
|
|
73
|
+
distrib: str | bool | None,
|
|
74
|
+
latest: str | bool | None,
|
|
75
|
+
replica: str | bool | None,
|
|
76
|
+
retracted: str | bool | None,
|
|
77
|
+
) -> None:
|
|
78
|
+
cls._distrib_ = Option(distrib)
|
|
79
|
+
cls._latest_ = Option(latest)
|
|
80
|
+
cls._replica_ = Option(replica)
|
|
81
|
+
cls._retracted_ = Option(retracted)
|
|
82
|
+
|
|
83
|
+
def __init__(
|
|
84
|
+
self,
|
|
85
|
+
distrib: Option | str | bool | None = Option.notset,
|
|
86
|
+
latest: Option | str | bool | None = Option.notset,
|
|
87
|
+
replica: Option | str | bool | None = Option.notset,
|
|
88
|
+
retracted: Option | str | bool | None = Option.notset,
|
|
89
|
+
):
|
|
90
|
+
setattr(self, "distrib", distrib)
|
|
91
|
+
setattr(self, "latest", latest)
|
|
92
|
+
setattr(self, "replica", replica)
|
|
93
|
+
setattr(self, "retracted", retracted)
|
|
94
|
+
|
|
95
|
+
def __setattr__(
|
|
96
|
+
self,
|
|
97
|
+
name: str,
|
|
98
|
+
value: Option | str | bool | None,
|
|
99
|
+
) -> None:
|
|
100
|
+
if name in self.__sql_attrs__:
|
|
101
|
+
super().__setattr__(name, value)
|
|
102
|
+
elif name in self._names:
|
|
103
|
+
super().__setattr__(name, Option(value))
|
|
104
|
+
else:
|
|
105
|
+
raise AttributeError(name)
|
|
106
|
+
|
|
107
|
+
def __getitem__(self, name: str) -> Option:
|
|
108
|
+
if name in self._names:
|
|
109
|
+
return getattr(self, name)
|
|
110
|
+
else:
|
|
111
|
+
raise KeyError(name)
|
|
112
|
+
|
|
113
|
+
def __setitem__(
|
|
114
|
+
self,
|
|
115
|
+
name: str,
|
|
116
|
+
value: Option | str | bool | None,
|
|
117
|
+
) -> None:
|
|
118
|
+
setattr(self, name, value)
|
|
119
|
+
|
|
120
|
+
def _as_bytes(self) -> bytes:
|
|
121
|
+
self_tuple = (self.distrib, self.latest, self.replica, self.retracted)
|
|
122
|
+
return str(self_tuple).encode()
|
|
123
|
+
|
|
124
|
+
def items(
|
|
125
|
+
self,
|
|
126
|
+
use_default: bool = False,
|
|
127
|
+
keep_notset: bool = False,
|
|
128
|
+
) -> Iterator[tuple[str, Option]]:
|
|
129
|
+
default = self.default()
|
|
130
|
+
for name in self._names:
|
|
131
|
+
option = getattr(self, name, Option.notset)
|
|
132
|
+
if option.is_set():
|
|
133
|
+
yield name, option
|
|
134
|
+
elif use_default:
|
|
135
|
+
yield name, getattr(default, name)
|
|
136
|
+
elif keep_notset:
|
|
137
|
+
yield name, option
|
|
138
|
+
|
|
139
|
+
def asdict(self) -> MutableMapping[str, bool | None]:
|
|
140
|
+
return {name: option.value[1] for name, option in self.items()}
|
|
141
|
+
|
|
142
|
+
def __bool__(self) -> bool:
|
|
143
|
+
return next(self.items(), None) is not None
|
|
144
|
+
|
|
145
|
+
def __rich_repr__(self) -> Iterator:
|
|
146
|
+
for name, option in self.items():
|
|
147
|
+
yield name, option.value
|
|
148
|
+
|
|
149
|
+
def __repr__(self) -> str:
|
|
150
|
+
cls_name = self.__class__.__name__
|
|
151
|
+
items = [f"{k}={v}" for k, v in self.__rich_repr__()]
|
|
152
|
+
return f"{cls_name}(" + ", ".join(items) + ")"
|
|
153
|
+
|
|
154
|
+
def trackable(self) -> bool:
|
|
155
|
+
return all(opt.is_set() for (_, opt) in self.items(keep_notset=True))
|
|
156
|
+
|
|
157
|
+
def apply_defaults(self, parent: Options):
|
|
158
|
+
for name, opt in self.items(keep_notset=True):
|
|
159
|
+
if opt.is_set():
|
|
160
|
+
continue
|
|
161
|
+
elif parent[name].is_set():
|
|
162
|
+
self[name] = parent[name]
|
|
163
|
+
else:
|
|
164
|
+
self[name] = self.default()[name]
|