arkindex-base-worker 0.4.0b2__py3-none-any.whl → 0.4.0b3__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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: arkindex-base-worker
3
- Version: 0.4.0b2
3
+ Version: 0.4.0b3
4
4
  Summary: Base Worker to easily build Arkindex ML workflows
5
5
  Author-email: Teklia <contact@teklia.com>
6
6
  Maintainer-email: Teklia <contact@teklia.com>
@@ -2,13 +2,13 @@ arkindex_worker/__init__.py,sha256=OlgCtTC9MaWeejviY0a3iQpALcRQGMVArFVVYwTF6I8,1
2
2
  arkindex_worker/cache.py,sha256=FTlB0coXofn5zTNRTcVIvh709mcw4a1bPGqkwWjKs3w,11248
3
3
  arkindex_worker/image.py,sha256=8Y0PYMbTEsFUv8lCNLBu7UaDy6um5YfHCefyXL2jpnE,14347
4
4
  arkindex_worker/models.py,sha256=bPQzGZNs5a6z6DEcygsa8T33VOqPlMUbwKzHqlKzwbw,9923
5
- arkindex_worker/utils.py,sha256=zrtMChXx_HGu4UkqXZBKPg3ys0UBFmQaizoX1riM3D4,9824
5
+ arkindex_worker/utils.py,sha256=q1EeLdC6ebYIH-C0LOAqw2cNpjCjVoP-Vbr-39mF4w0,9884
6
6
  arkindex_worker/worker/__init__.py,sha256=w1VlDzERabXIp625kkHnojyu5ctCM11WLw4ARh1ja3k,19818
7
7
  arkindex_worker/worker/base.py,sha256=JStHpwSP3bis9LLvV2C2n6GTWtLUVIDA9JPgPJEt17o,18717
8
8
  arkindex_worker/worker/classification.py,sha256=ECm1cnQPOj_9m-CoO0e182ElSySAUOoyddHrORbShhc,10951
9
9
  arkindex_worker/worker/corpus.py,sha256=s9bCxOszJMwRq1WWAmKjWq888mjDfbaJ18Wo7h-rNOw,1827
10
10
  arkindex_worker/worker/dataset.py,sha256=UXElhhARca9m7Himp-yxD5dAqWbdxDKWOUJUGgeCZXI,2934
11
- arkindex_worker/worker/element.py,sha256=5knEFHc0LDRRHI8IbJbiiQsOAoW7qYPf9lcVXsFlUEQ,34798
11
+ arkindex_worker/worker/element.py,sha256=yz7q-emuCIY6MI438QXQk1Cgq991QjYoLewNyUVE4ic,36411
12
12
  arkindex_worker/worker/entity.py,sha256=qGjQvOVXfP84rER0Dkui6q-rb9nTWerHVG0Z5voB8pU,15229
13
13
  arkindex_worker/worker/image.py,sha256=t_Az6IGnj0EZyvcA4XxfPikOUjn_pztgsyxTkFZhaXU,621
14
14
  arkindex_worker/worker/metadata.py,sha256=VRajtd2kaBvar9GercX4knvR6l1WFYjoCdJWU9ccKgk,7291
@@ -31,7 +31,7 @@ tests/test_elements_worker/test_classifications.py,sha256=fXZ8cSzIWwZ6LHsY7tKsy9
31
31
  tests/test_elements_worker/test_cli.py,sha256=a23i1pUDbXi23MUtbWwGEcLLrmc_YlrbDgOG3h66wLM,2620
32
32
  tests/test_elements_worker/test_corpus.py,sha256=c_LUHvkJIYgk_wXF06VQPNOoWfiZ06XpjOXrJ7MRiBc,4479
33
33
  tests/test_elements_worker/test_dataset.py,sha256=lSXqubhg1EEq2Y2goE8Y2RYaqIpM9Iejq6fGNW2BczU,11411
34
- tests/test_elements_worker/test_elements.py,sha256=dBhjQ8XZNIE7bjx5AaGaclPLZr1Ur_-tQ-ebS3S_Zn0,89142
34
+ tests/test_elements_worker/test_elements.py,sha256=v5MUD-a4gcmuaqG5UHu9AlzSEoRA2dudkht7cEVED_s,93227
35
35
  tests/test_elements_worker/test_entities.py,sha256=oav2dtvWWavQe1l3Drbxw1Ta2ocUJEVxJfDQ_r6-rYQ,36181
36
36
  tests/test_elements_worker/test_image.py,sha256=_E3UGdDOwTo1MW5KMS81PrdeSPBPWinWYoQPNy2F9Ro,2077
37
37
  tests/test_elements_worker/test_metadata.py,sha256=cm2NNaXxBYmYMkPexSPVTAqb2skDTB4mliwQCLz8Y98,22293
@@ -44,8 +44,8 @@ worker-demo/tests/conftest.py,sha256=XzNMNeg6pmABUAH8jN6eZTlZSFGLYjS3-DTXjiRN6Yc
44
44
  worker-demo/tests/test_worker.py,sha256=3DLd4NRK4bfyatG5P_PK4k9P9tJHx9XQq5_ryFEEFVg,304
45
45
  worker-demo/worker_demo/__init__.py,sha256=2BPomV8ZMNf3YXJgloatKeHQCE6QOkwmsHGkO6MkQuM,125
46
46
  worker-demo/worker_demo/worker.py,sha256=Rt-DjWa5iBP08k58NDZMfeyPuFbtNcbX6nc5jFX7GNo,440
47
- arkindex_base_worker-0.4.0b2.dist-info/LICENSE,sha256=NVshRi1efwVezMfW7xXYLrdDr2Li1AfwfGOd5WuH1kQ,1063
48
- arkindex_base_worker-0.4.0b2.dist-info/METADATA,sha256=wvefQTllKMq-jkbjsG1TMyuvF06h-XjBLgc79_j8MTU,3270
49
- arkindex_base_worker-0.4.0b2.dist-info/WHEEL,sha256=R0nc6qTxuoLk7ShA2_Y-UWkN8ZdfDBG2B6Eqpz2WXbs,91
50
- arkindex_base_worker-0.4.0b2.dist-info/top_level.txt,sha256=58NuslgxQC2vT4DiqZEgO4JqJRrYa2yeNI9QvkbfGQU,40
51
- arkindex_base_worker-0.4.0b2.dist-info/RECORD,,
47
+ arkindex_base_worker-0.4.0b3.dist-info/LICENSE,sha256=NVshRi1efwVezMfW7xXYLrdDr2Li1AfwfGOd5WuH1kQ,1063
48
+ arkindex_base_worker-0.4.0b3.dist-info/METADATA,sha256=KpYeTvNM7sruTB38VaQk_TephTtArTv1I6hrMI9iloM,3270
49
+ arkindex_base_worker-0.4.0b3.dist-info/WHEEL,sha256=R0nc6qTxuoLk7ShA2_Y-UWkN8ZdfDBG2B6Eqpz2WXbs,91
50
+ arkindex_base_worker-0.4.0b3.dist-info/top_level.txt,sha256=58NuslgxQC2vT4DiqZEgO4JqJRrYa2yeNI9QvkbfGQU,40
51
+ arkindex_base_worker-0.4.0b3.dist-info/RECORD,,
arkindex_worker/utils.py CHANGED
@@ -24,7 +24,12 @@ def pluralize(singular: str, count: int) -> str:
24
24
  if count == 1:
25
25
  return singular
26
26
 
27
- some_exceptions = {"entity": "entities", "metadata": "metadata", "class": "classes"}
27
+ some_exceptions = {
28
+ "child": "children",
29
+ "class": "classes",
30
+ "entity": "entities",
31
+ "metadata": "metadata",
32
+ }
28
33
  if singular in some_exceptions:
29
34
  return some_exceptions[singular]
30
35
 
@@ -3,6 +3,7 @@ ElementsWorker methods for elements and element types.
3
3
  """
4
4
 
5
5
  from collections.abc import Iterable
6
+ from operator import attrgetter
6
7
  from typing import NamedTuple
7
8
  from uuid import UUID
8
9
  from warnings import warn
@@ -346,6 +347,52 @@ class ElementMixin:
346
347
  child=child.id,
347
348
  )
348
349
 
350
+ @unsupported_cache
351
+ @batch_publication
352
+ def create_element_children(
353
+ self,
354
+ parent: Element,
355
+ children: list[Element],
356
+ batch_size: int = DEFAULT_BATCH_SIZE,
357
+ ) -> list[str]:
358
+ """
359
+ Link multiple elements to a single parent through the API.
360
+
361
+ :param parent: Parent element.
362
+ :param children: A list of child elements.
363
+ :param batch_size: The size of each batch, which will be used to split the publication to avoid API errors.
364
+
365
+ :returns: A list containing the string UUID of each child linked to the parent.
366
+ """
367
+ assert parent and isinstance(
368
+ parent, Element
369
+ ), "parent shouldn't be null and should be of type Element"
370
+
371
+ assert children and isinstance(
372
+ children, list
373
+ ), "children shouldn't be null and should be of type list"
374
+
375
+ for index, child in enumerate(children):
376
+ assert isinstance(
377
+ child, Element
378
+ ), f"Child at index {index} in children: Should be of type Element"
379
+
380
+ if self.is_read_only:
381
+ logger.warning("Cannot link elements as this worker is in read-only mode")
382
+ return
383
+
384
+ return [
385
+ child_id
386
+ for batch in make_batches(children, "child", batch_size)
387
+ for child_id in self.api_client.request(
388
+ "CreateElementChildren",
389
+ id=parent.id,
390
+ body={
391
+ "children": list(map(attrgetter("id"), batch)),
392
+ },
393
+ )["children"]
394
+ ]
395
+
349
396
  def partial_update_element(
350
397
  self, element: Element | CachedElement, **kwargs
351
398
  ) -> dict:
@@ -1500,6 +1500,139 @@ def test_create_element_parent(responses, mock_elements_worker):
1500
1500
  }
1501
1501
 
1502
1502
 
1503
+ @pytest.mark.parametrize(
1504
+ ("arg_name", "data", "error_message"),
1505
+ [
1506
+ (
1507
+ "parent",
1508
+ None,
1509
+ "parent shouldn't be null and should be of type Element",
1510
+ ),
1511
+ (
1512
+ "parent",
1513
+ "not element type",
1514
+ "parent shouldn't be null and should be of type Element",
1515
+ ),
1516
+ (
1517
+ "children",
1518
+ None,
1519
+ "children shouldn't be null and should be of type list",
1520
+ ),
1521
+ (
1522
+ "children",
1523
+ "not a list",
1524
+ "children shouldn't be null and should be of type list",
1525
+ ),
1526
+ (
1527
+ "children",
1528
+ [
1529
+ Element({"id": "11111111-1111-1111-1111-111111111111"}),
1530
+ "not element type",
1531
+ ],
1532
+ "Child at index 1 in children: Should be of type Element",
1533
+ ),
1534
+ ],
1535
+ )
1536
+ def test_create_element_children_wrong_params(
1537
+ arg_name, data, error_message, mock_elements_worker
1538
+ ):
1539
+ with pytest.raises(AssertionError, match=error_message):
1540
+ mock_elements_worker.create_element_children(
1541
+ **{
1542
+ "parent": Element({"id": "12341234-1234-1234-1234-123412341234"}),
1543
+ "children": [
1544
+ Element({"id": "11111111-1111-1111-1111-111111111111"}),
1545
+ Element({"id": "22222222-2222-2222-2222-222222222222"}),
1546
+ ],
1547
+ # Overwrite with wrong data
1548
+ arg_name: data,
1549
+ },
1550
+ )
1551
+
1552
+
1553
+ def test_create_element_children_api_error(responses, mock_elements_worker):
1554
+ parent = Element({"id": "12341234-1234-1234-1234-123412341234"})
1555
+ responses.add(
1556
+ responses.POST,
1557
+ f"http://testserver/api/v1/element/parent/{parent.id}/",
1558
+ status=418,
1559
+ )
1560
+
1561
+ with pytest.raises(ErrorResponse):
1562
+ mock_elements_worker.create_element_children(
1563
+ parent=parent,
1564
+ children=[
1565
+ Element({"id": "11111111-1111-1111-1111-111111111111"}),
1566
+ Element({"id": "22222222-2222-2222-2222-222222222222"}),
1567
+ ],
1568
+ )
1569
+
1570
+ assert len(responses.calls) == len(BASE_API_CALLS) + 1
1571
+ assert [
1572
+ (call.request.method, call.request.url) for call in responses.calls
1573
+ ] == BASE_API_CALLS + [
1574
+ (
1575
+ "POST",
1576
+ f"http://testserver/api/v1/element/parent/{parent.id}/",
1577
+ )
1578
+ ]
1579
+
1580
+
1581
+ @pytest.mark.parametrize("batch_size", [DEFAULT_BATCH_SIZE, 1])
1582
+ def test_create_element_children(batch_size, responses, mock_elements_worker):
1583
+ parent = Element({"id": "12341234-1234-1234-1234-123412341234"})
1584
+
1585
+ first_child = Element({"id": "11111111-1111-1111-1111-111111111111"})
1586
+ second_child = Element({"id": "22222222-2222-2222-2222-222222222222"})
1587
+
1588
+ responses.add(
1589
+ responses.POST,
1590
+ f"http://testserver/api/v1/element/parent/{parent.id}/",
1591
+ status=200,
1592
+ json={"children": []},
1593
+ )
1594
+
1595
+ mock_elements_worker.create_element_children(
1596
+ parent=parent,
1597
+ children=[first_child, second_child],
1598
+ batch_size=batch_size,
1599
+ )
1600
+
1601
+ bulk_api_calls = [
1602
+ (
1603
+ "POST",
1604
+ f"http://testserver/api/v1/element/parent/{parent.id}/",
1605
+ )
1606
+ ]
1607
+ if batch_size != DEFAULT_BATCH_SIZE:
1608
+ bulk_api_calls.append(
1609
+ (
1610
+ "POST",
1611
+ f"http://testserver/api/v1/element/parent/{parent.id}/",
1612
+ )
1613
+ )
1614
+
1615
+ assert len(responses.calls) == len(BASE_API_CALLS) + len(bulk_api_calls)
1616
+ assert [
1617
+ (call.request.method, call.request.url) for call in responses.calls
1618
+ ] == BASE_API_CALLS + bulk_api_calls
1619
+
1620
+ bodies = []
1621
+ first_call_idx = None
1622
+ if batch_size > 1:
1623
+ first_call_idx = -1
1624
+ bodies.append({"children": [first_child.id, second_child.id]})
1625
+ else:
1626
+ first_call_idx = -2
1627
+ bodies.append({"children": [first_child.id]})
1628
+ bodies.append({"children": [second_child.id]})
1629
+
1630
+ assert [
1631
+ json.loads(bulk_call.request.body)
1632
+ for bulk_call in responses.calls[first_call_idx:]
1633
+ ] == bodies
1634
+
1635
+
1503
1636
  @pytest.mark.parametrize(
1504
1637
  ("payload", "error"),
1505
1638
  [