arkindex-base-worker 0.5.0a3__py3-none-any.whl → 0.5.0b1__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.
- {arkindex_base_worker-0.5.0a3.dist-info → arkindex_base_worker-0.5.0b1.dist-info}/METADATA +4 -7
- {arkindex_base_worker-0.5.0a3.dist-info → arkindex_base_worker-0.5.0b1.dist-info}/RECORD +16 -16
- {arkindex_base_worker-0.5.0a3.dist-info → arkindex_base_worker-0.5.0b1.dist-info}/WHEEL +1 -1
- {arkindex_base_worker-0.5.0a3.dist-info → arkindex_base_worker-0.5.0b1.dist-info}/top_level.txt +1 -0
- arkindex_worker/image.py +4 -17
- arkindex_worker/worker/__init__.py +0 -14
- arkindex_worker/worker/base.py +7 -0
- arkindex_worker/worker/classification.py +3 -3
- arkindex_worker/worker/element.py +71 -45
- arkindex_worker/worker/entity.py +71 -30
- examples/standalone/python/worker.py +171 -0
- examples/tooled/python/worker.py +50 -0
- tests/test_elements_worker/test_element.py +200 -26
- tests/test_elements_worker/test_entity_list_and_check.py +165 -32
- tests/test_image.py +10 -2
- arkindex_worker/worker/version.py +0 -58
- tests/test_elements_worker/test_version.py +0 -60
- {arkindex_base_worker-0.5.0a3.dist-info → arkindex_base_worker-0.5.0b1.dist-info/licenses}/LICENSE +0 -0
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import pytest
|
|
2
2
|
from responses import matchers
|
|
3
3
|
|
|
4
|
+
from arkindex.exceptions import ErrorResponse
|
|
4
5
|
from arkindex_worker.models import Transcription
|
|
5
6
|
from arkindex_worker.worker.entity import MissingEntityType
|
|
6
7
|
from tests import CORPUS_ID
|
|
@@ -8,67 +9,158 @@ from tests import CORPUS_ID
|
|
|
8
9
|
from . import BASE_API_CALLS
|
|
9
10
|
|
|
10
11
|
|
|
11
|
-
def
|
|
12
|
-
|
|
13
|
-
|
|
12
|
+
def test_create_entity_type_wrong_name(mock_elements_worker):
|
|
13
|
+
with pytest.raises(
|
|
14
|
+
AssertionError, match="name shouldn't be null and should be of type str"
|
|
15
|
+
):
|
|
16
|
+
mock_elements_worker.create_entity_type(name=None)
|
|
14
17
|
|
|
15
|
-
|
|
18
|
+
with pytest.raises(
|
|
19
|
+
AssertionError, match="name shouldn't be null and should be of type str"
|
|
20
|
+
):
|
|
21
|
+
mock_elements_worker.create_entity_type(name=1234)
|
|
16
22
|
|
|
17
|
-
|
|
23
|
+
|
|
24
|
+
def test_create_entity_type_api_error(responses, mock_elements_worker):
|
|
18
25
|
responses.add(
|
|
19
26
|
responses.POST,
|
|
20
27
|
"http://testserver/api/v1/entity/types/",
|
|
21
|
-
status=
|
|
28
|
+
status=418,
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
with pytest.raises(ErrorResponse):
|
|
32
|
+
mock_elements_worker.create_entity_type(name="firstname")
|
|
33
|
+
|
|
34
|
+
assert len(responses.calls) == len(BASE_API_CALLS) + 1
|
|
35
|
+
assert [
|
|
36
|
+
(call.request.method, call.request.url) for call in responses.calls
|
|
37
|
+
] == BASE_API_CALLS + [("POST", "http://testserver/api/v1/entity/types/")]
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def test_create_entity_type_already_exists(responses, mock_elements_worker):
|
|
41
|
+
assert mock_elements_worker.entity_types == {}
|
|
42
|
+
|
|
43
|
+
responses.add(
|
|
44
|
+
responses.POST,
|
|
45
|
+
"http://testserver/api/v1/entity/types/",
|
|
46
|
+
status=400,
|
|
22
47
|
match=[
|
|
23
|
-
matchers.json_params_matcher(
|
|
24
|
-
{
|
|
25
|
-
"name": "new-entity",
|
|
26
|
-
"corpus": CORPUS_ID,
|
|
27
|
-
}
|
|
28
|
-
)
|
|
48
|
+
matchers.json_params_matcher({"name": "firstname", "corpus": CORPUS_ID})
|
|
29
49
|
],
|
|
50
|
+
)
|
|
51
|
+
responses.add(
|
|
52
|
+
responses.GET,
|
|
53
|
+
f"http://testserver/api/v1/corpus/{CORPUS_ID}/entity-types/",
|
|
54
|
+
status=200,
|
|
30
55
|
json={
|
|
31
|
-
"
|
|
32
|
-
"
|
|
33
|
-
"
|
|
34
|
-
|
|
56
|
+
"count": 1,
|
|
57
|
+
"next": None,
|
|
58
|
+
"results": [
|
|
59
|
+
{"id": "lastname-id", "name": "lastname", "color": "ffd1b3"},
|
|
60
|
+
{"id": "firstname-id", "name": "firstname", "color": "ffd1b3"},
|
|
61
|
+
],
|
|
35
62
|
},
|
|
36
63
|
)
|
|
37
64
|
|
|
38
|
-
mock_elements_worker.
|
|
39
|
-
entity_types=checked_types,
|
|
40
|
-
)
|
|
65
|
+
mock_elements_worker.create_entity_type(name="firstname")
|
|
41
66
|
|
|
42
|
-
|
|
67
|
+
assert len(responses.calls) == len(BASE_API_CALLS) + 2
|
|
68
|
+
assert [
|
|
69
|
+
(call.request.method, call.request.url) for call in responses.calls
|
|
70
|
+
] == BASE_API_CALLS + [
|
|
71
|
+
("POST", "http://testserver/api/v1/entity/types/"),
|
|
72
|
+
("GET", f"http://testserver/api/v1/corpus/{CORPUS_ID}/entity-types/"),
|
|
73
|
+
]
|
|
74
|
+
|
|
75
|
+
# Make sure the entity_types attribute has been updated
|
|
43
76
|
assert mock_elements_worker.entity_types == {
|
|
44
|
-
"
|
|
45
|
-
"
|
|
77
|
+
"lastname": "lastname-id",
|
|
78
|
+
"firstname": "firstname-id",
|
|
46
79
|
}
|
|
47
80
|
|
|
81
|
+
|
|
82
|
+
def test_create_entity_type(responses, mock_elements_worker):
|
|
83
|
+
assert mock_elements_worker.entity_types == {}
|
|
84
|
+
|
|
85
|
+
responses.add(
|
|
86
|
+
responses.POST,
|
|
87
|
+
"http://testserver/api/v1/entity/types/",
|
|
88
|
+
status=200,
|
|
89
|
+
match=[
|
|
90
|
+
matchers.json_params_matcher({"name": "firstname", "corpus": CORPUS_ID})
|
|
91
|
+
],
|
|
92
|
+
json={
|
|
93
|
+
"id": "firstname-id",
|
|
94
|
+
"name": "firstname",
|
|
95
|
+
"corpus": CORPUS_ID,
|
|
96
|
+
"color": "ffd1b3",
|
|
97
|
+
},
|
|
98
|
+
)
|
|
99
|
+
|
|
100
|
+
mock_elements_worker.create_entity_type(name="firstname")
|
|
101
|
+
|
|
48
102
|
assert len(responses.calls) == len(BASE_API_CALLS) + 1
|
|
49
103
|
assert [
|
|
50
104
|
(call.request.method, call.request.url) for call in responses.calls
|
|
51
105
|
] == BASE_API_CALLS + [
|
|
52
|
-
(
|
|
53
|
-
"POST",
|
|
54
|
-
"http://testserver/api/v1/entity/types/",
|
|
55
|
-
),
|
|
106
|
+
("POST", "http://testserver/api/v1/entity/types/"),
|
|
56
107
|
]
|
|
57
108
|
|
|
109
|
+
# Make sure the entity_types attribute has been updated
|
|
110
|
+
assert mock_elements_worker.entity_types == {"firstname": "firstname-id"}
|
|
58
111
|
|
|
59
|
-
|
|
112
|
+
|
|
113
|
+
def test_check_required_entity_types_wrong_entity_types(mock_elements_worker):
|
|
114
|
+
with pytest.raises(
|
|
115
|
+
AssertionError,
|
|
116
|
+
match="entity_types shouldn't be null and should be of type list",
|
|
117
|
+
):
|
|
118
|
+
mock_elements_worker.check_required_entity_types(entity_types=None)
|
|
119
|
+
|
|
120
|
+
with pytest.raises(
|
|
121
|
+
AssertionError,
|
|
122
|
+
match="entity_types shouldn't be null and should be of type list",
|
|
123
|
+
):
|
|
124
|
+
mock_elements_worker.check_required_entity_types(entity_types=1234)
|
|
125
|
+
|
|
126
|
+
with pytest.raises(
|
|
127
|
+
AssertionError,
|
|
128
|
+
match="Entity type at index 1 in entity_types: Should be of type str",
|
|
129
|
+
):
|
|
130
|
+
mock_elements_worker.check_required_entity_types(
|
|
131
|
+
entity_types=["firstname", 1234]
|
|
132
|
+
)
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
def test_check_required_entity_types_wrong_create_missing(mock_elements_worker):
|
|
136
|
+
with pytest.raises(
|
|
137
|
+
AssertionError,
|
|
138
|
+
match="create_missing shouldn't be null and should be of type bool",
|
|
139
|
+
):
|
|
140
|
+
mock_elements_worker.check_required_entity_types(
|
|
141
|
+
entity_types=["firstname"], create_missing=None
|
|
142
|
+
)
|
|
143
|
+
|
|
144
|
+
with pytest.raises(
|
|
145
|
+
AssertionError,
|
|
146
|
+
match="create_missing shouldn't be null and should be of type bool",
|
|
147
|
+
):
|
|
148
|
+
mock_elements_worker.check_required_entity_types(
|
|
149
|
+
entity_types=["firstname"], create_missing=1234
|
|
150
|
+
)
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
def test_check_required_entity_types_do_not_create_missing(
|
|
60
154
|
responses, mock_elements_worker
|
|
61
155
|
):
|
|
62
156
|
# Set one entity type
|
|
63
|
-
mock_elements_worker.entity_types = {"
|
|
64
|
-
|
|
65
|
-
checked_types = ["person", "new-entity"]
|
|
157
|
+
mock_elements_worker.entity_types = {"lastname": "lastname-id"}
|
|
66
158
|
|
|
67
159
|
with pytest.raises(
|
|
68
|
-
MissingEntityType, match="Entity type `
|
|
160
|
+
MissingEntityType, match="Entity type `firstname` was not in the corpus."
|
|
69
161
|
):
|
|
70
162
|
mock_elements_worker.check_required_entity_types(
|
|
71
|
-
entity_types=
|
|
163
|
+
entity_types=["lastname", "firstname"], create_missing=False
|
|
72
164
|
)
|
|
73
165
|
|
|
74
166
|
assert len(responses.calls) == len(BASE_API_CALLS)
|
|
@@ -77,6 +169,47 @@ def test_check_required_entity_types_no_creation_allowed(
|
|
|
77
169
|
] == BASE_API_CALLS
|
|
78
170
|
|
|
79
171
|
|
|
172
|
+
def test_check_required_entity_types(responses, mock_elements_worker):
|
|
173
|
+
# Set one entity type
|
|
174
|
+
mock_elements_worker.entity_types = {"lastname": "lastname-id"}
|
|
175
|
+
|
|
176
|
+
# Call to create a new entity type
|
|
177
|
+
responses.add(
|
|
178
|
+
responses.POST,
|
|
179
|
+
"http://testserver/api/v1/entity/types/",
|
|
180
|
+
status=200,
|
|
181
|
+
match=[
|
|
182
|
+
matchers.json_params_matcher({"name": "firstname", "corpus": CORPUS_ID})
|
|
183
|
+
],
|
|
184
|
+
json={
|
|
185
|
+
"id": "firstname-id",
|
|
186
|
+
"name": "firstname",
|
|
187
|
+
"corpus": CORPUS_ID,
|
|
188
|
+
"color": "ffd1b3",
|
|
189
|
+
},
|
|
190
|
+
)
|
|
191
|
+
|
|
192
|
+
mock_elements_worker.check_required_entity_types(
|
|
193
|
+
entity_types=["lastname", "firstname"], create_missing=True
|
|
194
|
+
)
|
|
195
|
+
|
|
196
|
+
assert len(responses.calls) == len(BASE_API_CALLS) + 1
|
|
197
|
+
assert [
|
|
198
|
+
(call.request.method, call.request.url) for call in responses.calls
|
|
199
|
+
] == BASE_API_CALLS + [
|
|
200
|
+
(
|
|
201
|
+
"POST",
|
|
202
|
+
"http://testserver/api/v1/entity/types/",
|
|
203
|
+
),
|
|
204
|
+
]
|
|
205
|
+
|
|
206
|
+
# Make sure the entity_types attribute has been updated
|
|
207
|
+
assert mock_elements_worker.entity_types == {
|
|
208
|
+
"lastname": "lastname-id",
|
|
209
|
+
"firstname": "firstname-id",
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
|
|
80
213
|
def test_list_transcription_entities_deprecation(fake_dummy_worker):
|
|
81
214
|
transcription = Transcription({"id": "fake_transcription_id"})
|
|
82
215
|
worker_version = "worker_version_id"
|
tests/test_image.py
CHANGED
|
@@ -234,7 +234,7 @@ def test_open_image_rotate_mirror(rotation_angle, mirrored, expected_path):
|
|
|
234
234
|
@pytest.mark.parametrize(
|
|
235
235
|
("polygon", "error"),
|
|
236
236
|
[
|
|
237
|
-
# Polygon
|
|
237
|
+
# Polygon isn't a list or tuple
|
|
238
238
|
(
|
|
239
239
|
{
|
|
240
240
|
"polygon": [
|
|
@@ -252,7 +252,15 @@ def test_open_image_rotate_mirror(rotation_angle, mirrored, expected_path):
|
|
|
252
252
|
[99, 208],
|
|
253
253
|
]
|
|
254
254
|
},
|
|
255
|
-
"
|
|
255
|
+
"Polygon must be a valid list or tuple of points.",
|
|
256
|
+
),
|
|
257
|
+
# Polygon hasn't enough points
|
|
258
|
+
(
|
|
259
|
+
[
|
|
260
|
+
[99, 200],
|
|
261
|
+
[25, 224],
|
|
262
|
+
],
|
|
263
|
+
"Polygon should have at least three points.",
|
|
256
264
|
),
|
|
257
265
|
# Point coordinates are not integers
|
|
258
266
|
(
|
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
"""
|
|
2
|
-
ElementsWorker methods for worker versions.
|
|
3
|
-
"""
|
|
4
|
-
|
|
5
|
-
import functools
|
|
6
|
-
from warnings import warn
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
def worker_version_deprecation(func):
|
|
10
|
-
@functools.wraps(func)
|
|
11
|
-
def wrapper(self, *args, **kwargs):
|
|
12
|
-
warn("WorkerVersion usage is deprecated.", DeprecationWarning, stacklevel=2)
|
|
13
|
-
return func(self, *args, **kwargs)
|
|
14
|
-
|
|
15
|
-
return wrapper
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
class WorkerVersionMixin:
|
|
19
|
-
@worker_version_deprecation
|
|
20
|
-
def get_worker_version(self, worker_version_id: str) -> dict:
|
|
21
|
-
"""
|
|
22
|
-
Warns:
|
|
23
|
-
----
|
|
24
|
-
This method is **deprecated**.
|
|
25
|
-
|
|
26
|
-
Retrieve a worker version, using the [ElementsWorker][arkindex_worker.worker.ElementsWorker]'s internal cache when possible.
|
|
27
|
-
|
|
28
|
-
:param worker_version_id: ID of the worker version to retrieve.
|
|
29
|
-
:returns: The requested worker version, as returned by the ``RetrieveWorkerVersion`` API endpoint.
|
|
30
|
-
"""
|
|
31
|
-
if worker_version_id is None:
|
|
32
|
-
raise ValueError("No worker version ID")
|
|
33
|
-
|
|
34
|
-
if worker_version_id in self._worker_version_cache:
|
|
35
|
-
return self._worker_version_cache[worker_version_id]
|
|
36
|
-
|
|
37
|
-
worker_version = self.api_client.request(
|
|
38
|
-
"RetrieveWorkerVersion", id=worker_version_id
|
|
39
|
-
)
|
|
40
|
-
self._worker_version_cache[worker_version_id] = worker_version
|
|
41
|
-
|
|
42
|
-
return worker_version
|
|
43
|
-
|
|
44
|
-
@worker_version_deprecation
|
|
45
|
-
def get_worker_version_slug(self, worker_version_id: str) -> str:
|
|
46
|
-
"""
|
|
47
|
-
Warns:
|
|
48
|
-
----
|
|
49
|
-
This method is **deprecated**.
|
|
50
|
-
|
|
51
|
-
Retrieve the slug of the worker of a worker version, from a worker version UUID.
|
|
52
|
-
Uses a worker version from the internal cache if possible, otherwise makes an API request.
|
|
53
|
-
|
|
54
|
-
:param worker_version_id: ID of the worker version to find a slug for.
|
|
55
|
-
:returns: Slug of the worker of this worker version.
|
|
56
|
-
"""
|
|
57
|
-
worker_version = self.get_worker_version(worker_version_id)
|
|
58
|
-
return worker_version["worker"]["slug"]
|
|
@@ -1,60 +0,0 @@
|
|
|
1
|
-
import pytest
|
|
2
|
-
|
|
3
|
-
TEST_VERSION_ID = "test_123"
|
|
4
|
-
TEST_SLUG = "some_slug"
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
def test_get_worker_version(fake_dummy_worker):
|
|
8
|
-
api_client = fake_dummy_worker.api_client
|
|
9
|
-
|
|
10
|
-
response = {"worker": {"slug": TEST_SLUG}}
|
|
11
|
-
|
|
12
|
-
api_client.add_response("RetrieveWorkerVersion", response, id=TEST_VERSION_ID)
|
|
13
|
-
|
|
14
|
-
with pytest.deprecated_call(match="WorkerVersion usage is deprecated."):
|
|
15
|
-
res = fake_dummy_worker.get_worker_version(TEST_VERSION_ID)
|
|
16
|
-
|
|
17
|
-
assert res == response
|
|
18
|
-
assert fake_dummy_worker._worker_version_cache[TEST_VERSION_ID] == response
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
def test_get_worker_version__uses_cache(fake_dummy_worker):
|
|
22
|
-
api_client = fake_dummy_worker.api_client
|
|
23
|
-
|
|
24
|
-
response = {"worker": {"slug": TEST_SLUG}}
|
|
25
|
-
|
|
26
|
-
api_client.add_response("RetrieveWorkerVersion", response, id=TEST_VERSION_ID)
|
|
27
|
-
|
|
28
|
-
with pytest.deprecated_call(match="WorkerVersion usage is deprecated."):
|
|
29
|
-
response_1 = fake_dummy_worker.get_worker_version(TEST_VERSION_ID)
|
|
30
|
-
|
|
31
|
-
with pytest.deprecated_call(match="WorkerVersion usage is deprecated."):
|
|
32
|
-
response_2 = fake_dummy_worker.get_worker_version(TEST_VERSION_ID)
|
|
33
|
-
|
|
34
|
-
assert response_1 == response
|
|
35
|
-
assert response_1 == response_2
|
|
36
|
-
|
|
37
|
-
# assert that only one call to the API
|
|
38
|
-
assert len(api_client.history) == 1
|
|
39
|
-
assert not api_client.responses
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
def test_get_worker_version_slug(mocker, fake_dummy_worker):
|
|
43
|
-
fake_dummy_worker.get_worker_version = mocker.MagicMock()
|
|
44
|
-
fake_dummy_worker.get_worker_version.return_value = {
|
|
45
|
-
"id": TEST_VERSION_ID,
|
|
46
|
-
"worker": {"slug": "mock_slug"},
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
with pytest.deprecated_call(match="WorkerVersion usage is deprecated."):
|
|
50
|
-
slug = fake_dummy_worker.get_worker_version_slug(TEST_VERSION_ID)
|
|
51
|
-
assert slug == "mock_slug"
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
def test_get_worker_version_slug_none(fake_dummy_worker):
|
|
55
|
-
# WARNING: pytest.deprecated_call must be placed BEFORE pytest.raises, otherwise `match` argument won't be checked
|
|
56
|
-
with (
|
|
57
|
-
pytest.deprecated_call(match="WorkerVersion usage is deprecated."),
|
|
58
|
-
pytest.raises(ValueError, match="No worker version ID"),
|
|
59
|
-
):
|
|
60
|
-
fake_dummy_worker.get_worker_version_slug(None)
|
{arkindex_base_worker-0.5.0a3.dist-info → arkindex_base_worker-0.5.0b1.dist-info/licenses}/LICENSE
RENAMED
|
File without changes
|