datamint 1.9.3__py3-none-any.whl → 2.0.1__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.

Potentially problematic release.


This version of datamint might be problematic. Click here for more details.

Files changed (35) hide show
  1. datamint/__init__.py +2 -0
  2. datamint/api/__init__.py +3 -0
  3. datamint/api/base_api.py +430 -0
  4. datamint/api/client.py +91 -0
  5. datamint/api/dto/__init__.py +10 -0
  6. datamint/api/endpoints/__init__.py +17 -0
  7. datamint/api/endpoints/annotations_api.py +984 -0
  8. datamint/api/endpoints/channels_api.py +28 -0
  9. datamint/api/endpoints/datasetsinfo_api.py +16 -0
  10. datamint/api/endpoints/projects_api.py +203 -0
  11. datamint/api/endpoints/resources_api.py +1013 -0
  12. datamint/api/endpoints/users_api.py +38 -0
  13. datamint/api/entity_base_api.py +347 -0
  14. datamint/apihandler/api_handler.py +3 -6
  15. datamint/apihandler/base_api_handler.py +6 -28
  16. datamint/apihandler/dto/__init__.py +0 -0
  17. datamint/apihandler/dto/annotation_dto.py +1 -1
  18. datamint/client_cmd_tools/datamint_upload.py +19 -30
  19. datamint/dataset/base_dataset.py +83 -86
  20. datamint/dataset/dataset.py +2 -2
  21. datamint/entities/__init__.py +20 -0
  22. datamint/entities/annotation.py +178 -0
  23. datamint/entities/base_entity.py +51 -0
  24. datamint/entities/channel.py +46 -0
  25. datamint/entities/datasetinfo.py +22 -0
  26. datamint/entities/project.py +64 -0
  27. datamint/entities/resource.py +130 -0
  28. datamint/entities/user.py +21 -0
  29. datamint/examples/example_projects.py +41 -44
  30. datamint/exceptions.py +27 -1
  31. {datamint-1.9.3.dist-info → datamint-2.0.1.dist-info}/METADATA +13 -9
  32. datamint-2.0.1.dist-info/RECORD +50 -0
  33. {datamint-1.9.3.dist-info → datamint-2.0.1.dist-info}/WHEEL +1 -1
  34. datamint-1.9.3.dist-info/RECORD +0 -29
  35. {datamint-1.9.3.dist-info → datamint-2.0.1.dist-info}/entry_points.txt +0 -0
@@ -0,0 +1,28 @@
1
+ """
2
+ Channels API endpoint for managing channel resources.
3
+
4
+ This module provides functionality to interact with channels,
5
+ which are collections of resources grouped together for
6
+ batch processing or organization purposes.
7
+ """
8
+
9
+ import logging
10
+ import httpx
11
+ from ..entity_base_api import EntityBaseApi
12
+ from datamint.entities.channel import Channel
13
+
14
+ logger = logging.getLogger(__name__)
15
+
16
+
17
+ class ChannelsApi(EntityBaseApi[Channel]):
18
+ """API client for channel-related operations.
19
+ """
20
+
21
+ def __init__(self, config, client: httpx.Client | None = None) -> None:
22
+ """Initialize the Channels API client.
23
+
24
+ Args:
25
+ config: API configuration containing base URL, API key, etc.
26
+ client: Optional HTTP client instance. If None, a new one will be created.
27
+ """
28
+ super().__init__(config, Channel, 'resources/channels', client)
@@ -0,0 +1,16 @@
1
+ from ..entity_base_api import ApiConfig, EntityBaseApi
2
+ from datamint.entities.datasetinfo import DatasetInfo
3
+ import httpx
4
+
5
+
6
+ class DatasetsInfoApi(EntityBaseApi[DatasetInfo]):
7
+ def __init__(self,
8
+ config: ApiConfig,
9
+ client: httpx.Client | None = None) -> None:
10
+ """Initialize the datasets API handler.
11
+
12
+ Args:
13
+ config: API configuration containing base URL, API key, etc.
14
+ client: Optional HTTP client instance. If None, a new one will be created.
15
+ """
16
+ super().__init__(config, DatasetInfo, 'datasets', client)
@@ -0,0 +1,203 @@
1
+ from typing import Sequence, Literal
2
+ from ..entity_base_api import ApiConfig, CRUDEntityApi
3
+ from datamint.entities.project import Project
4
+ from datamint.entities.resource import Resource
5
+ import httpx
6
+
7
+
8
+ class ProjectsApi(CRUDEntityApi[Project]):
9
+ """API handler for project-related endpoints."""
10
+
11
+ def __init__(self,
12
+ config: ApiConfig,
13
+ client: httpx.Client | None = None) -> None:
14
+ """Initialize the projects API handler.
15
+
16
+ Args:
17
+ config: API configuration containing base URL, API key, etc.
18
+ client: Optional HTTP client instance. If None, a new one will be created.
19
+ """
20
+ super().__init__(config, Project, 'projects', client)
21
+
22
+ def get_project_resources(self, project: Project | str) -> list[Resource]:
23
+ """Get resources associated with a specific project.
24
+
25
+ Args:
26
+ project: The ID or instance of the project to fetch resources for.
27
+
28
+ Returns:
29
+ A list of resource instances associated with the project.
30
+ """
31
+ response = self._get_child_entities(project, 'resources')
32
+ resources_data = response.json()
33
+ return [Resource(**item) for item in resources_data]
34
+
35
+ def create(self,
36
+ name: str,
37
+ description: str,
38
+ resources_ids: list[str] | None = None,
39
+ is_active_learning: bool = False,
40
+ two_up_display: bool = False
41
+ ) -> str:
42
+ """Create a new project.
43
+
44
+ Args:
45
+ name: The name of the project.
46
+ description: The description of the project.
47
+ resources_ids: The list of resource ids to be included in the project.
48
+ is_active_learning: Whether the project is an active learning project or not.
49
+ two_up_display: Allow annotators to display multiple resources for annotation.
50
+
51
+ Returns:
52
+ The id of the created project.
53
+ """
54
+ resources_ids = resources_ids or []
55
+ project_data = {'name': name,
56
+ 'is_active_learning': is_active_learning,
57
+ 'resource_ids': resources_ids,
58
+ 'annotation_set': {
59
+ "annotators": [],
60
+ "resource_ids": resources_ids,
61
+ "annotations": [],
62
+ "frame_labels": [],
63
+ "image_labels": [],
64
+ },
65
+ "two_up_display": two_up_display,
66
+ "require_review": False,
67
+ 'description': description}
68
+
69
+ return self._create(project_data)
70
+
71
+ def get_all(self, limit: int | None = None) -> Sequence[Project]:
72
+ """Get all projects.
73
+
74
+ Args:
75
+ limit: The maximum number of projects to return. If None, return all projects.
76
+
77
+ Returns:
78
+ A list of project instances.
79
+ """
80
+ return self.get_list(limit=limit, params={'includeArchived': True})
81
+
82
+ def get_by_name(self,
83
+ name: str,
84
+ include_archived: bool = True) -> Project | None:
85
+ """Get a project by its name.
86
+
87
+ Args:
88
+ name (str): The name of the project.
89
+ include_archived (bool): Whether to include archived projects in the search.
90
+
91
+ Returns:
92
+ The project instance if found, otherwise None.
93
+ """
94
+ if include_archived:
95
+ projects = self.get_list(params={'includeArchived': True})
96
+ else:
97
+ projects = self.get_all()
98
+ for project in projects:
99
+ if project.name == name:
100
+ return project
101
+ return None
102
+
103
+ def _get_by_name_or_id(self, project: str) -> Project | None:
104
+ """Get a project by its name or ID.
105
+
106
+ Args:
107
+ project (str): The name or ID of the project.
108
+
109
+ Returns:
110
+ The project instance if found, otherwise None.
111
+ """
112
+ projects = self.get_all()
113
+ for proj in projects:
114
+ if proj.name == project or proj.id == project:
115
+ return proj
116
+ return None
117
+
118
+ def add_resources(self,
119
+ resources: str | Sequence[str] | Resource | Sequence[Resource],
120
+ project: str | Project,
121
+ ) -> None:
122
+ """
123
+ Add resources to a project.
124
+
125
+ Args:
126
+ resources: The resource unique id or a list of resource unique ids.
127
+ project: The project name, id or :class:`Project` object to add the resource to.
128
+ """
129
+ if isinstance(resources, str):
130
+ resources_ids = [resources]
131
+ elif isinstance(resources, Resource):
132
+ resources_ids = [resources.id]
133
+ else:
134
+ resources_ids = [res if isinstance(res, str) else res.id for res in resources]
135
+
136
+ if isinstance(project, str):
137
+ if len(project) == 36:
138
+ project_id = project
139
+ else:
140
+ # get the project id by its name
141
+ project_found = self._get_by_name_or_id(project)
142
+ if project_found is None:
143
+ raise ValueError(f"Project '{project}' not found.")
144
+ project_id = project_found.id
145
+ else:
146
+ project_id = project.id
147
+
148
+ self._make_entity_request('POST', project_id, add_path='resources',
149
+ json={'resource_ids_to_add': resources_ids, 'all_files_selected': False})
150
+
151
+ def download(self, project: str | Project,
152
+ outpath: str,
153
+ all_annotations: bool = False,
154
+ include_unannotated: bool = False,
155
+ ) -> None:
156
+ """Download a project by its id.
157
+
158
+ Args:
159
+ project: The project id or Project instance.
160
+ outpath: The path to save the project zip file.
161
+ all_annotations: Whether to include all annotations in the downloaded dataset,
162
+ even those not made by the provided project.
163
+ include_unannotated: Whether to include unannotated resources in the downloaded dataset.
164
+ """
165
+ from tqdm.auto import tqdm
166
+ params = {'all_annotations': all_annotations}
167
+ if include_unannotated:
168
+ params['include_unannotated'] = include_unannotated
169
+
170
+ project_id = self._entid(project)
171
+ with self._stream_entity_request('GET', project_id,
172
+ add_path='annotated_dataset',
173
+ params=params) as response:
174
+ total_size = int(response.headers.get('content-length', 0))
175
+ if total_size == 0:
176
+ total_size = None
177
+ with tqdm(total=total_size, unit='B', unit_scale=True) as progress_bar:
178
+ with open(outpath, 'wb') as file:
179
+ for data in response.iter_bytes(1024):
180
+ progress_bar.update(len(data))
181
+ file.write(data)
182
+
183
+ def set_work_status(self,
184
+ resource: str | Resource,
185
+ project: str | Project,
186
+ status: Literal['opened', 'annotated', 'closed']) -> None:
187
+ """
188
+ Set the status of a resource.
189
+
190
+ Args:
191
+ annotation: The annotation unique id or an annotation object.
192
+ status: The new status to set.
193
+ """
194
+ resource_id = self._entid(resource)
195
+ proj_id = self._entid(project)
196
+
197
+ jsondata = {
198
+ 'status': status
199
+ }
200
+ self._make_entity_request('POST',
201
+ entity_id=proj_id,
202
+ add_path=f'resources/{resource_id}/status',
203
+ json=jsondata)