hirundo 0.1.7__py3-none-any.whl → 0.1.9__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.
- hirundo/__init__.py +17 -9
- hirundo/_constraints.py +34 -2
- hirundo/_env.py +12 -1
- hirundo/_http.py +19 -0
- hirundo/_iter_sse_retrying.py +63 -19
- hirundo/cli.py +75 -16
- hirundo/dataset_optimization.py +519 -127
- hirundo/enum.py +8 -5
- hirundo/git.py +95 -28
- hirundo/logger.py +3 -1
- hirundo/storage.py +246 -75
- hirundo-0.1.9.dist-info/METADATA +212 -0
- hirundo-0.1.9.dist-info/RECORD +20 -0
- {hirundo-0.1.7.dist-info → hirundo-0.1.9.dist-info}/WHEEL +1 -1
- hirundo-0.1.7.dist-info/METADATA +0 -118
- hirundo-0.1.7.dist-info/RECORD +0 -19
- {hirundo-0.1.7.dist-info → hirundo-0.1.9.dist-info}/LICENSE +0 -0
- {hirundo-0.1.7.dist-info → hirundo-0.1.9.dist-info}/entry_points.txt +0 -0
- {hirundo-0.1.7.dist-info → hirundo-0.1.9.dist-info}/top_level.txt +0 -0
hirundo/enum.py
CHANGED
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
from enum import Enum
|
|
2
2
|
|
|
3
3
|
|
|
4
|
-
class
|
|
4
|
+
class LabelingType(str, Enum):
|
|
5
5
|
"""
|
|
6
|
-
Enum indicate what type of
|
|
6
|
+
Enum indicate what type of labeling is used for the given dataset.
|
|
7
7
|
Supported types are:
|
|
8
8
|
"""
|
|
9
9
|
|
|
10
|
-
|
|
11
|
-
|
|
10
|
+
SINGLE_LABEL_CLASSIFICATION = "SingleLabelClassification"
|
|
11
|
+
OBJECT_DETECTION = "ObjectDetection"
|
|
12
|
+
SPEECH_TO_TEXT = "SpeechToText"
|
|
12
13
|
|
|
13
14
|
|
|
14
15
|
class DatasetMetadataType(str, Enum):
|
|
@@ -17,4 +18,6 @@ class DatasetMetadataType(str, Enum):
|
|
|
17
18
|
Supported types are:
|
|
18
19
|
"""
|
|
19
20
|
|
|
20
|
-
|
|
21
|
+
HIRUNDO_CSV = "HirundoCSV"
|
|
22
|
+
COCO = "COCO"
|
|
23
|
+
YOLO = "YOLO"
|
hirundo/git.py
CHANGED
|
@@ -1,13 +1,16 @@
|
|
|
1
|
+
import datetime
|
|
1
2
|
import re
|
|
2
|
-
|
|
3
|
+
import typing
|
|
3
4
|
|
|
4
5
|
import pydantic
|
|
5
6
|
import requests
|
|
6
7
|
from pydantic import BaseModel, field_validator
|
|
7
8
|
from pydantic_core import Url
|
|
8
9
|
|
|
10
|
+
from hirundo._constraints import RepoUrl
|
|
9
11
|
from hirundo._env import API_HOST
|
|
10
12
|
from hirundo._headers import get_auth_headers, json_headers
|
|
13
|
+
from hirundo._http import raise_for_status_with_reason
|
|
11
14
|
from hirundo._timeouts import MODIFY_TIMEOUT, READ_TIMEOUT
|
|
12
15
|
from hirundo.logger import get_logger
|
|
13
16
|
|
|
@@ -30,14 +33,14 @@ class GitSSHAuthBase(BaseModel):
|
|
|
30
33
|
"""
|
|
31
34
|
The SSH key for the Git repository
|
|
32
35
|
"""
|
|
33
|
-
ssh_password:
|
|
36
|
+
ssh_password: typing.Optional[str]
|
|
34
37
|
"""
|
|
35
38
|
The password for the SSH key for the Git repository.
|
|
36
39
|
"""
|
|
37
40
|
|
|
38
41
|
|
|
39
42
|
class GitRepo(BaseModel):
|
|
40
|
-
id:
|
|
43
|
+
id: typing.Optional[int] = None
|
|
41
44
|
"""
|
|
42
45
|
The ID of the Git repository.
|
|
43
46
|
"""
|
|
@@ -46,25 +49,25 @@ class GitRepo(BaseModel):
|
|
|
46
49
|
"""
|
|
47
50
|
A name to identify the Git repository in the Hirundo system.
|
|
48
51
|
"""
|
|
49
|
-
repository_url:
|
|
52
|
+
repository_url: typing.Union[str, RepoUrl]
|
|
50
53
|
"""
|
|
51
54
|
The URL of the Git repository, it should start with `ssh://` or `https://` or be in the form `user@host:path`.
|
|
52
55
|
If it is in the form `user@host:path`, it will be rewritten to `ssh://user@host:path`.
|
|
53
56
|
"""
|
|
54
|
-
organization_id:
|
|
57
|
+
organization_id: typing.Optional[int] = None
|
|
55
58
|
"""
|
|
56
59
|
The ID of the organization that the Git repository belongs to.
|
|
57
60
|
If not provided, it will be assigned to your default organization.
|
|
58
61
|
"""
|
|
59
62
|
|
|
60
|
-
plain_auth:
|
|
63
|
+
plain_auth: typing.Optional[GitPlainAuthBase] = pydantic.Field(
|
|
61
64
|
default=None, examples=[None, {"username": "ben", "password": "password"}]
|
|
62
65
|
)
|
|
63
66
|
"""
|
|
64
67
|
The plain authentication details for the Git repository.
|
|
65
68
|
Use this if using a special user with a username and password for authentication.
|
|
66
69
|
"""
|
|
67
|
-
ssh_auth:
|
|
70
|
+
ssh_auth: typing.Optional[GitSSHAuthBase] = pydantic.Field(
|
|
68
71
|
default=None,
|
|
69
72
|
examples=[
|
|
70
73
|
{
|
|
@@ -82,43 +85,92 @@ class GitRepo(BaseModel):
|
|
|
82
85
|
|
|
83
86
|
@field_validator("repository_url", mode="before", check_fields=True)
|
|
84
87
|
@classmethod
|
|
85
|
-
def check_valid_repository_url(cls, repository_url: str):
|
|
86
|
-
# Check if the URL
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
88
|
+
def check_valid_repository_url(cls, repository_url: typing.Union[str, RepoUrl]):
|
|
89
|
+
# Check if the URL has the `@` and `:` pattern with a non-numeric section before the next slash
|
|
90
|
+
match = re.match("([^@]+@[^:]+):([^0-9/][^/]*)/(.+)", str(repository_url))
|
|
91
|
+
if match:
|
|
92
|
+
user_host = match.group(1)
|
|
93
|
+
path = match.group(2) + "/" + match.group(3)
|
|
94
|
+
rewritten_url = Url(f"ssh://{user_host}/{path}")
|
|
95
|
+
# Check if the URL already has a protocol
|
|
96
|
+
url_scheme = rewritten_url.scheme
|
|
97
|
+
logger.info(
|
|
98
|
+
"Modified Git repo to replace %s@%s:%s/%s with %s",
|
|
99
|
+
url_scheme,
|
|
100
|
+
match.group(1),
|
|
101
|
+
match.group(2),
|
|
102
|
+
match.group(3),
|
|
103
|
+
rewritten_url,
|
|
104
|
+
)
|
|
105
|
+
return rewritten_url
|
|
106
|
+
if not str(repository_url).startswith("ssh://") and not str(
|
|
107
|
+
repository_url
|
|
108
|
+
).startswith("https://"):
|
|
99
109
|
raise ValueError("Repository URL must start with 'ssh://' or 'https://'")
|
|
110
|
+
if not isinstance(repository_url, Url):
|
|
111
|
+
repository_url = Url(repository_url)
|
|
100
112
|
return repository_url
|
|
101
113
|
|
|
102
|
-
def create(self):
|
|
114
|
+
def create(self, replace_if_exists: bool = False) -> int:
|
|
103
115
|
"""
|
|
104
116
|
Create a Git repository in the Hirundo system.
|
|
117
|
+
|
|
118
|
+
Args:
|
|
119
|
+
replace_if_exists: If a Git repository with the same name already exists, replace it.
|
|
105
120
|
"""
|
|
106
121
|
git_repo = requests.post(
|
|
107
122
|
f"{API_HOST}/git-repo/",
|
|
108
|
-
json=
|
|
123
|
+
json={
|
|
124
|
+
**self.model_dump(mode="json"),
|
|
125
|
+
"replace_if_exists": replace_if_exists,
|
|
126
|
+
},
|
|
109
127
|
headers={
|
|
110
128
|
**json_headers,
|
|
111
129
|
**get_auth_headers(),
|
|
112
130
|
},
|
|
113
131
|
timeout=MODIFY_TIMEOUT,
|
|
114
132
|
)
|
|
115
|
-
git_repo
|
|
133
|
+
raise_for_status_with_reason(git_repo)
|
|
116
134
|
git_repo_id = git_repo.json()["id"]
|
|
117
135
|
self.id = git_repo_id
|
|
118
136
|
return git_repo_id
|
|
119
137
|
|
|
120
138
|
@staticmethod
|
|
121
|
-
def
|
|
139
|
+
def get_by_id(git_repo_id: int) -> "GitRepoOut":
|
|
140
|
+
"""
|
|
141
|
+
Retrieves a `GitRepo` instance from the server by its ID
|
|
142
|
+
|
|
143
|
+
Args:
|
|
144
|
+
git_repo_id: The ID of the `GitRepo` to retrieve
|
|
145
|
+
"""
|
|
146
|
+
git_repo = requests.get(
|
|
147
|
+
f"{API_HOST}/git-repo/{git_repo_id}",
|
|
148
|
+
headers=get_auth_headers(),
|
|
149
|
+
timeout=READ_TIMEOUT,
|
|
150
|
+
)
|
|
151
|
+
raise_for_status_with_reason(git_repo)
|
|
152
|
+
return GitRepoOut(**git_repo.json())
|
|
153
|
+
|
|
154
|
+
@staticmethod
|
|
155
|
+
def get_by_name(
|
|
156
|
+
name: str,
|
|
157
|
+
) -> "GitRepoOut":
|
|
158
|
+
"""
|
|
159
|
+
Retrieves a `GitRepo` instance from the server by its name
|
|
160
|
+
|
|
161
|
+
Args:
|
|
162
|
+
name: The name of the `GitRepo` to retrieve
|
|
163
|
+
"""
|
|
164
|
+
git_repo = requests.get(
|
|
165
|
+
f"{API_HOST}/git-repo/by-name/{name}",
|
|
166
|
+
headers=get_auth_headers(),
|
|
167
|
+
timeout=READ_TIMEOUT,
|
|
168
|
+
)
|
|
169
|
+
raise_for_status_with_reason(git_repo)
|
|
170
|
+
return GitRepoOut(**git_repo.json())
|
|
171
|
+
|
|
172
|
+
@staticmethod
|
|
173
|
+
def list() -> list["GitRepoOut"]:
|
|
122
174
|
"""
|
|
123
175
|
List all Git repositories in the Hirundo system.
|
|
124
176
|
"""
|
|
@@ -129,8 +181,14 @@ class GitRepo(BaseModel):
|
|
|
129
181
|
},
|
|
130
182
|
timeout=READ_TIMEOUT,
|
|
131
183
|
)
|
|
132
|
-
git_repos
|
|
133
|
-
|
|
184
|
+
raise_for_status_with_reason(git_repos)
|
|
185
|
+
git_repo_json = git_repos.json()
|
|
186
|
+
return [
|
|
187
|
+
GitRepoOut(
|
|
188
|
+
**git_repo,
|
|
189
|
+
)
|
|
190
|
+
for git_repo in git_repo_json
|
|
191
|
+
]
|
|
134
192
|
|
|
135
193
|
@staticmethod
|
|
136
194
|
def delete_by_id(git_repo_id: int):
|
|
@@ -147,7 +205,7 @@ class GitRepo(BaseModel):
|
|
|
147
205
|
},
|
|
148
206
|
timeout=MODIFY_TIMEOUT,
|
|
149
207
|
)
|
|
150
|
-
git_repo
|
|
208
|
+
raise_for_status_with_reason(git_repo)
|
|
151
209
|
|
|
152
210
|
def delete(self):
|
|
153
211
|
"""
|
|
@@ -156,3 +214,12 @@ class GitRepo(BaseModel):
|
|
|
156
214
|
if not self.id:
|
|
157
215
|
raise ValueError("No GitRepo has been created")
|
|
158
216
|
GitRepo.delete_by_id(self.id)
|
|
217
|
+
|
|
218
|
+
|
|
219
|
+
class GitRepoOut(BaseModel):
|
|
220
|
+
id: int
|
|
221
|
+
name: str
|
|
222
|
+
repository_url: RepoUrl
|
|
223
|
+
|
|
224
|
+
created_at: datetime.datetime
|
|
225
|
+
updated_at: datetime.datetime
|
hirundo/logger.py
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import logging
|
|
2
|
+
import os
|
|
2
3
|
|
|
3
4
|
|
|
4
5
|
def get_logger(name: str) -> logging.Logger:
|
|
5
6
|
logger = logging.getLogger(name)
|
|
6
|
-
|
|
7
|
+
log_level = os.getenv("LOG_LEVEL")
|
|
8
|
+
logger.setLevel(log_level if log_level else logging.INFO)
|
|
7
9
|
logger.addHandler(logging.StreamHandler())
|
|
8
10
|
return logger
|