learning-loop-node 0.18.2__py3-none-any.whl → 0.18.4__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.
- learning_loop_node/detector/detector_node.py +2 -7
- learning_loop_node/detector/rest/detect.py +1 -6
- learning_loop_node/helpers/gdrive_downloader.py +0 -0
- {learning_loop_node-0.18.2.dist-info → learning_loop_node-0.18.4.dist-info}/METADATA +31 -36
- {learning_loop_node-0.18.2.dist-info → learning_loop_node-0.18.4.dist-info}/RECORD +15 -59
- {learning_loop_node-0.18.2.dist-info → learning_loop_node-0.18.4.dist-info}/WHEEL +2 -1
- learning_loop_node-0.18.4.dist-info/top_level.txt +1 -0
- learning_loop_node/examples/novelty_score_updater.py +0 -70
- learning_loop_node/tests/__init__.py +0 -0
- learning_loop_node/tests/annotator/__init__.py +0 -0
- learning_loop_node/tests/annotator/conftest.py +0 -55
- learning_loop_node/tests/annotator/pytest.ini +0 -10
- learning_loop_node/tests/annotator/test_annotator_node.py +0 -60
- learning_loop_node/tests/detector/__init__.py +0 -0
- learning_loop_node/tests/detector/conftest.py +0 -174
- learning_loop_node/tests/detector/inbox_filter/__init__.py +0 -0
- learning_loop_node/tests/detector/inbox_filter/test_observation.py +0 -31
- learning_loop_node/tests/detector/inbox_filter/test_relevance_group.py +0 -162
- learning_loop_node/tests/detector/inbox_filter/test_unexpected_observations_count.py +0 -35
- learning_loop_node/tests/detector/pytest.ini +0 -10
- learning_loop_node/tests/detector/test.jpg +0 -0
- learning_loop_node/tests/detector/test_client_communication.py +0 -177
- learning_loop_node/tests/detector/test_detector_node.py +0 -98
- learning_loop_node/tests/detector/test_outbox.py +0 -77
- learning_loop_node/tests/detector/test_relevance_filter.py +0 -43
- learning_loop_node/tests/detector/testing_detector.py +0 -28
- learning_loop_node/tests/general/__init__.py +0 -0
- learning_loop_node/tests/general/conftest.py +0 -68
- learning_loop_node/tests/general/pytest.ini +0 -10
- learning_loop_node/tests/general/test_data/file_1.txt +0 -1
- learning_loop_node/tests/general/test_data/file_2.txt +0 -1
- learning_loop_node/tests/general/test_data/model.json +0 -6
- learning_loop_node/tests/general/test_data_classes.py +0 -22
- learning_loop_node/tests/general/test_downloader.py +0 -84
- learning_loop_node/tests/general/test_learning_loop_node.py +0 -20
- learning_loop_node/tests/test_helper.py +0 -96
- learning_loop_node/tests/trainer/__init__.py +0 -0
- learning_loop_node/tests/trainer/conftest.py +0 -101
- learning_loop_node/tests/trainer/pytest.ini +0 -10
- learning_loop_node/tests/trainer/state_helper.py +0 -22
- learning_loop_node/tests/trainer/states/__init__.py +0 -0
- learning_loop_node/tests/trainer/states/test_state_cleanup.py +0 -27
- learning_loop_node/tests/trainer/states/test_state_detecting.py +0 -83
- learning_loop_node/tests/trainer/states/test_state_download_train_model.py +0 -67
- learning_loop_node/tests/trainer/states/test_state_prepare.py +0 -55
- learning_loop_node/tests/trainer/states/test_state_sync_confusion_matrix.py +0 -117
- learning_loop_node/tests/trainer/states/test_state_train.py +0 -65
- learning_loop_node/tests/trainer/states/test_state_upload_detections.py +0 -164
- learning_loop_node/tests/trainer/states/test_state_upload_model.py +0 -88
- learning_loop_node/tests/trainer/test_errors.py +0 -45
- learning_loop_node/tests/trainer/test_trainer_states.py +0 -39
- learning_loop_node/tests/trainer/testing_trainer_logic.py +0 -94
|
@@ -6,15 +6,10 @@ import subprocess
|
|
|
6
6
|
import sys
|
|
7
7
|
from dataclasses import asdict
|
|
8
8
|
from datetime import datetime
|
|
9
|
-
from typing import Dict, List, Optional
|
|
9
|
+
from typing import Dict, List, Literal, Optional
|
|
10
10
|
|
|
11
11
|
import numpy as np
|
|
12
12
|
|
|
13
|
-
try:
|
|
14
|
-
from typing import Literal
|
|
15
|
-
except ImportError: # Python <= 3.8
|
|
16
|
-
from typing_extensions import Literal # type: ignore
|
|
17
|
-
|
|
18
13
|
import socketio
|
|
19
14
|
from dacite import from_dict
|
|
20
15
|
from fastapi.encoders import jsonable_encoder
|
|
@@ -220,7 +215,7 @@ class DetectorNode(Node):
|
|
|
220
215
|
max_http_buffer_size=64 * 1024 * 1024, # 64 MiB
|
|
221
216
|
)
|
|
222
217
|
# Initialize and mount the ASGI app
|
|
223
|
-
self.sio_app = socketio.ASGIApp(self.sio, socketio_path='/socket.io')
|
|
218
|
+
self.sio_app = socketio.ASGIApp(self.sio, socketio_path='/ws/socket.io')
|
|
224
219
|
self.mount('/ws', self.sio_app)
|
|
225
220
|
# Register event handlers
|
|
226
221
|
|
|
@@ -1,10 +1,5 @@
|
|
|
1
1
|
import logging
|
|
2
|
-
from typing import TYPE_CHECKING, Optional
|
|
3
|
-
|
|
4
|
-
try:
|
|
5
|
-
from typing import Literal
|
|
6
|
-
except ImportError: # Python <= 3.8
|
|
7
|
-
from typing_extensions import Literal # type: ignore
|
|
2
|
+
from typing import TYPE_CHECKING, Literal, Optional
|
|
8
3
|
|
|
9
4
|
from fastapi import APIRouter, File, Header, Request, UploadFile
|
|
10
5
|
|
|
File without changes
|
|
@@ -1,42 +1,38 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
2
|
-
Name:
|
|
3
|
-
Version: 0.18.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: learning_loop_node
|
|
3
|
+
Version: 0.18.4
|
|
4
4
|
Summary: Python Library for Nodes which connect to the Zauberzeug Learning Loop
|
|
5
|
-
|
|
5
|
+
Author-email: Zauberzeug GmbH <info@zauberzeug.com>
|
|
6
6
|
License: MIT
|
|
7
|
-
Author: Zauberzeug GmbH
|
|
8
|
-
Author-email: info@zauberzeug.com
|
|
9
|
-
Requires-Python: >=3.8,<4.0
|
|
10
|
-
Classifier: License :: OSI Approved :: MIT License
|
|
11
|
-
Classifier: Programming Language :: Python :: 3
|
|
12
|
-
Classifier: Programming Language :: Python :: 3.8
|
|
13
|
-
Classifier: Programming Language :: Python :: 3.9
|
|
14
|
-
Classifier: Programming Language :: Python :: 3.10
|
|
15
|
-
Classifier: Programming Language :: Python :: 3.11
|
|
16
|
-
Requires-Dist: Pillow (>=10.0.0,<11.0.0)
|
|
17
|
-
Requires-Dist: aiofiles (>=0.7.0,<0.8.0)
|
|
18
|
-
Requires-Dist: aiohttp (>=3.8.4,<4.0.0)
|
|
19
|
-
Requires-Dist: async_generator (>=1.10,<2.0)
|
|
20
|
-
Requires-Dist: dacite (>=1.8.1,<2.0.0)
|
|
21
|
-
Requires-Dist: fastapi (>=0.93,<0.109)
|
|
22
|
-
Requires-Dist: fastapi-socketio (>=0.0.10,<0.0.11)
|
|
23
|
-
Requires-Dist: fastapi-utils (>=0.2.1,<0.3.0)
|
|
24
|
-
Requires-Dist: httpx (>=0.28.1,<0.29.0)
|
|
25
|
-
Requires-Dist: icecream (>=2.1.0,<3.0.0)
|
|
26
|
-
Requires-Dist: numpy (>=1.13.3,<2.0.0)
|
|
27
|
-
Requires-Dist: psutil (>=5.8.0,<6.0.0)
|
|
28
|
-
Requires-Dist: pynvml (>=11.4.1,<12.0.0)
|
|
29
|
-
Requires-Dist: pytest-mock (==3.6.1)
|
|
30
|
-
Requires-Dist: pytest-watch (>=4.2.0,<5.0.0)
|
|
31
|
-
Requires-Dist: python-multipart (>=0.0.5,<0.0.6)
|
|
32
|
-
Requires-Dist: python-socketio (>=5.7.2,<6.0.0)
|
|
33
|
-
Requires-Dist: requests (>=2.25.1,<3.0.0)
|
|
34
|
-
Requires-Dist: simplejson (>=3.17.2,<4.0.0)
|
|
35
|
-
Requires-Dist: tqdm (>=4.63.0,<5.0.0)
|
|
36
|
-
Requires-Dist: uvicorn[standard] (>=0.22.0,<0.23.0)
|
|
37
|
-
Requires-Dist: werkzeug (>=2.0.1,<3.0.0)
|
|
38
7
|
Project-URL: Repository, https://github.com/zauberzeug/learning_loop_node
|
|
8
|
+
Requires-Python: >=3.9
|
|
39
9
|
Description-Content-Type: text/markdown
|
|
10
|
+
Requires-Dist: fastapi<1.0,>=0.128
|
|
11
|
+
Requires-Dist: uvicorn[standard]<0.23.0,>=0.22.0
|
|
12
|
+
Requires-Dist: fastapi-utils<0.9.0,>=0.8.0
|
|
13
|
+
Requires-Dist: requests<3.0.0,>=2.25.1
|
|
14
|
+
Requires-Dist: python-socketio<6.0.0,>=5.7.2
|
|
15
|
+
Requires-Dist: simplejson<4.0.0,>=3.17.2
|
|
16
|
+
Requires-Dist: icecream<3.0.0,>=2.1.0
|
|
17
|
+
Requires-Dist: aiofiles<0.8.0,>=0.7.0
|
|
18
|
+
Requires-Dist: async_generator<2.0.0,>=1.10
|
|
19
|
+
Requires-Dist: pytest-watch<5.0.0,>=4.2.0
|
|
20
|
+
Requires-Dist: python-multipart<0.0.19,>=0.0.18
|
|
21
|
+
Requires-Dist: psutil<6.0.0,>=5.8.0
|
|
22
|
+
Requires-Dist: numpy<3.0,>=2.0
|
|
23
|
+
Requires-Dist: Pillow<12.0.0,>=11.0.0
|
|
24
|
+
Requires-Dist: tqdm<5.0.0,>=4.66.3
|
|
25
|
+
Requires-Dist: pytest-mock<4.0.0,>=3.6.1
|
|
26
|
+
Requires-Dist: pynvml<12.0.0,>=11.4.1
|
|
27
|
+
Requires-Dist: aiohttp<4.0.0,>=3.13.3
|
|
28
|
+
Requires-Dist: httpx<0.29.0,>=0.28.1
|
|
29
|
+
Requires-Dist: dacite<2.0.0,>=1.8.1
|
|
30
|
+
Provides-Extra: dev
|
|
31
|
+
Requires-Dist: pytest-flakefinder<2.0.0,>=1.1.0; extra == "dev"
|
|
32
|
+
Requires-Dist: retry<0.10.0,>=0.9.2; extra == "dev"
|
|
33
|
+
Requires-Dist: debugpy<2.0.0,>=1.6.7.post1; extra == "dev"
|
|
34
|
+
Requires-Dist: pytest-asyncio<0.22.0,>=0.21.1; extra == "dev"
|
|
35
|
+
Requires-Dist: autopep8<3.0.0,>=2.0.2; extra == "dev"
|
|
40
36
|
|
|
41
37
|
# Learning Loop Node
|
|
42
38
|
|
|
@@ -280,4 +276,3 @@ After a short time the converted model should be available as well.
|
|
|
280
276
|
- Nodes add properties to `model.json`, which contains all the information which are needed by subsequent nodes. These are typically the properties:
|
|
281
277
|
- `resolution`: resolution in which the model expects images (as `int`, since the resolution is mostly square - later, ` resolution_x`` resolution_y ` would also be conceivable or `resolutions` to give a list of possible resolutions)
|
|
282
278
|
- `categories`: list of categories with name, id, (later also type), in the order in which they are used by the model -- this is neccessary to be robust about renamings
|
|
283
|
-
|
|
@@ -1,4 +1,10 @@
|
|
|
1
1
|
learning_loop_node/__init__.py,sha256=onN5s8-x_xBsCM6NLmJO0Ym1sJHeCFaGw8qb0oQZmz8,364
|
|
2
|
+
learning_loop_node/data_exchanger.py,sha256=nd9JNPLn9amIeTcSIyUPpbE97ORAcb5yNphvmpgWSUQ,9095
|
|
3
|
+
learning_loop_node/globals.py,sha256=tgw_8RYOipPV9aYlyUhYtXfUxvJKRvfUk6u-qVAtZmY,174
|
|
4
|
+
learning_loop_node/loop_communication.py,sha256=d1tJZ9T_y22FrEq1XzvidgH6d-byGxFq3ovLvPBS4FA,7611
|
|
5
|
+
learning_loop_node/node.py,sha256=xK-xODRo7ov-dNNMcpLW2GAauvjKAK3K9RQh4P9S994,12160
|
|
6
|
+
learning_loop_node/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
7
|
+
learning_loop_node/rest.py,sha256=5X9IVW9kf1gNf8jifGW9g_gI_-9TEeoMMOW16jvwpRE,1599
|
|
2
8
|
learning_loop_node/annotation/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
3
9
|
learning_loop_node/annotation/annotator_logic.py,sha256=BTaopkJZkIf1CI5lfsVKsxbxoUIbDJrevavuQUT5e_c,1000
|
|
4
10
|
learning_loop_node/annotation/annotator_node.py,sha256=J5xwSnM5rwTWrTe-TI37J0JHKf_4PlDuABaHvgjYr_Q,4443
|
|
@@ -10,19 +16,18 @@ learning_loop_node/data_classes/general.py,sha256=GQ6vPEIm4qqBV4RZT_YS_dPeKMdbCK
|
|
|
10
16
|
learning_loop_node/data_classes/image_metadata.py,sha256=4FFs89iZAfr2Jh-40QqZ_GGmJ8hl_W61eHcCqHflJLE,2293
|
|
11
17
|
learning_loop_node/data_classes/socket_response.py,sha256=tIdt-oYf6ULoJIDYQCecNM9OtWR6_wJ9tL0Ksu83Vko,655
|
|
12
18
|
learning_loop_node/data_classes/training.py,sha256=TybwcCDf_NUaDUaOj30lPm-7Z3Qk9XFRibEX5qIv96Y,5737
|
|
13
|
-
learning_loop_node/data_exchanger.py,sha256=nd9JNPLn9amIeTcSIyUPpbE97ORAcb5yNphvmpgWSUQ,9095
|
|
14
19
|
learning_loop_node/detector/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
15
20
|
learning_loop_node/detector/detector_logic.py,sha256=8J70Fulrhex9IHFBAGYLR3a0-W-zsNj4h7mYLnrmUqM,2899
|
|
16
|
-
learning_loop_node/detector/detector_node.py,sha256=
|
|
21
|
+
learning_loop_node/detector/detector_node.py,sha256=g1moqT-d6I6pNv7XKweUT47P4QY53XdwRme_qXYFrBc,31805
|
|
17
22
|
learning_loop_node/detector/exceptions.py,sha256=C6KbNPlSbtfgDrZx2Hbhm7Suk9jVoR3fMRCO0CkrMsQ,196
|
|
23
|
+
learning_loop_node/detector/outbox.py,sha256=6F0MjFM-zNX-xWP_YGbmU0UYuyb0odsX_OcAxMPSzS0,12288
|
|
18
24
|
learning_loop_node/detector/inbox_filter/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
19
25
|
learning_loop_node/detector/inbox_filter/cam_observation_history.py,sha256=slPGm87TbBCfDUdpRTAM5yOz1An8Br5X_2HFJOGSrFg,3540
|
|
20
26
|
learning_loop_node/detector/inbox_filter/relevance_filter.py,sha256=81XQV6HST2hSH-In7VF8B4BfubgUdRHTLcc16VLjUxc,1518
|
|
21
|
-
learning_loop_node/detector/outbox.py,sha256=6F0MjFM-zNX-xWP_YGbmU0UYuyb0odsX_OcAxMPSzS0,12288
|
|
22
27
|
learning_loop_node/detector/rest/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
23
28
|
learning_loop_node/detector/rest/about.py,sha256=evHJ2svUZY_DFz0FSef5u9c5KW4Uc3GL7EbPinG9-dg,583
|
|
24
29
|
learning_loop_node/detector/rest/backdoor_controls.py,sha256=ZNaFOvC0OLWNtcLiG-NIqS_y1kkLP4csgk3CHhp8Gis,885
|
|
25
|
-
learning_loop_node/detector/rest/detect.py,sha256=
|
|
30
|
+
learning_loop_node/detector/rest/detect.py,sha256=BHcQbSuC1sYHRKl2wNchiasb3A4HJk9tVia11e9TS6Y,2597
|
|
26
31
|
learning_loop_node/detector/rest/model_version_control.py,sha256=P4FOG0U9HT6QtCoNt-1s1pT6drtgdVjGZWEuCAyuNmA,1370
|
|
27
32
|
learning_loop_node/detector/rest/operation_mode.py,sha256=1_xfutA_6nzdb4Q_jZiHQ5m_wA83bcG5jSIy-sfNIvk,1575
|
|
28
33
|
learning_loop_node/detector/rest/outbox_mode.py,sha256=H8coDNbgLGEfXmKQrhtXWeUHBAHpnrdZktuHXQz0xis,1148
|
|
@@ -32,8 +37,6 @@ learning_loop_node/enums/annotator.py,sha256=mtTAw-8LJIrHcYkBjYHCZuhYEEHS6QzSK8k
|
|
|
32
37
|
learning_loop_node/enums/detector.py,sha256=Qvm5LWWR9BfsDxHEQ8YzaPaUuSmp4BescYuV4X4ikwE,512
|
|
33
38
|
learning_loop_node/enums/general.py,sha256=OSpcIpdFjuRByON2xBoiIXl1SgDREIqkwnaxkTFjnHU,164
|
|
34
39
|
learning_loop_node/enums/trainer.py,sha256=VaD63guLO4aKgVfXT0EryPlXKQGegSET3Cp4R0uC_Ew,746
|
|
35
|
-
learning_loop_node/examples/novelty_score_updater.py,sha256=1DRgM9lxjFV-q2JvGDDsNLz_ic_rhEZ9wc6ZdjcxwPE,2038
|
|
36
|
-
learning_loop_node/globals.py,sha256=tgw_8RYOipPV9aYlyUhYtXfUxvJKRvfUk6u-qVAtZmY,174
|
|
37
40
|
learning_loop_node/helpers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
38
41
|
learning_loop_node/helpers/background_tasks.py,sha256=sbbS8JO1ls0ZCbNW68KOT9QLOFyFoJRXwwAq78iOmoA,3256
|
|
39
42
|
learning_loop_node/helpers/environment_reader.py,sha256=6DxDJecLHxiGczByhyVa_JssAwwft7vuNCGaEzoSY2I,1662
|
|
@@ -41,65 +44,18 @@ learning_loop_node/helpers/gdrive_downloader.py,sha256=zeYJciTAJVRpu_eFjwgYLCpIa
|
|
|
41
44
|
learning_loop_node/helpers/log_conf.py,sha256=hqVAa_9NnYEU6N0dcOKmph82p7MpgKqeF_eomTLYzWY,961
|
|
42
45
|
learning_loop_node/helpers/misc.py,sha256=bHIYeOoX_5FA1qhcNlG7_kVgVXDF5jipByDwTvs8Huw,8407
|
|
43
46
|
learning_loop_node/helpers/run.py,sha256=_uox-j3_K_bL3yCAwy3JYSOiIxrnhzVxyxWpCe8_J9U,876
|
|
44
|
-
learning_loop_node/loop_communication.py,sha256=d1tJZ9T_y22FrEq1XzvidgH6d-byGxFq3ovLvPBS4FA,7611
|
|
45
|
-
learning_loop_node/node.py,sha256=xK-xODRo7ov-dNNMcpLW2GAauvjKAK3K9RQh4P9S994,12160
|
|
46
|
-
learning_loop_node/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
47
|
-
learning_loop_node/rest.py,sha256=5X9IVW9kf1gNf8jifGW9g_gI_-9TEeoMMOW16jvwpRE,1599
|
|
48
|
-
learning_loop_node/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
49
|
-
learning_loop_node/tests/annotator/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
50
|
-
learning_loop_node/tests/annotator/conftest.py,sha256=b_J3Br5RzKl6BTeH9vfqq9Z6Th3OM_GpuGsfVxl4dlg,2100
|
|
51
|
-
learning_loop_node/tests/annotator/pytest.ini,sha256=8QdjmawLy1zAzXrJ88or1kpFDhJw0W5UOnDfGGs_igU,262
|
|
52
|
-
learning_loop_node/tests/annotator/test_annotator_node.py,sha256=OgdUj0PEWSe0KPTNVVi-1d7DoK7IC9Q3Q3G8TPiP9f4,2090
|
|
53
|
-
learning_loop_node/tests/detector/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
54
|
-
learning_loop_node/tests/detector/conftest.py,sha256=KMB4vXqKtmpp_wuGVyWyjVexeTOwHBtL5rnonUXq1mU,5379
|
|
55
|
-
learning_loop_node/tests/detector/inbox_filter/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
56
|
-
learning_loop_node/tests/detector/inbox_filter/test_observation.py,sha256=k4WYdvnuV7d_r7zI4M2aA8WuBjm0aycQ0vj1rGE2q4w,1370
|
|
57
|
-
learning_loop_node/tests/detector/inbox_filter/test_relevance_group.py,sha256=r-wABFQVsTNTjv7vYGr8wbHfOWy43F_B14ZDWHfiZ-A,7613
|
|
58
|
-
learning_loop_node/tests/detector/inbox_filter/test_unexpected_observations_count.py,sha256=A42gUuw4M2tg00ExFWg8kxhr6zT3l7t2H-tiO60QaNM,1746
|
|
59
|
-
learning_loop_node/tests/detector/pytest.ini,sha256=8QdjmawLy1zAzXrJ88or1kpFDhJw0W5UOnDfGGs_igU,262
|
|
60
|
-
learning_loop_node/tests/detector/test.jpg,sha256=msA-vHPmvPiro_D102Qmn1fn4vNfooqYYEXPxZUmYpk,161390
|
|
61
|
-
learning_loop_node/tests/detector/test_client_communication.py,sha256=rMKQGckHfAg4kZf4b4IvzhAXjv9vDHyMNii-eimvVXY,8143
|
|
62
|
-
learning_loop_node/tests/detector/test_detector_node.py,sha256=AeQkXR5BN2KiqCPIMLEfkssBMlhTW0N3YdPxpYvEz7M,3402
|
|
63
|
-
learning_loop_node/tests/detector/test_outbox.py,sha256=Glc7TvaYnjebQ1RNstMlwOA_I60CftgbxP1U7-7GuMg,2702
|
|
64
|
-
learning_loop_node/tests/detector/test_relevance_filter.py,sha256=pFDC262QgRUrhQmXFswiCDD9Fh2NK13lmQVCBpelF8s,2115
|
|
65
|
-
learning_loop_node/tests/detector/testing_detector.py,sha256=ZheFZFbdmNH6jW1tQLvNHy9xJjw_vsMpWRK7cJPQvNM,742
|
|
66
|
-
learning_loop_node/tests/general/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
67
|
-
learning_loop_node/tests/general/conftest.py,sha256=kEtkuVA2wgny-YBkLDn7Ff5j6ShOPghQUU0cH9IIl_8,2430
|
|
68
|
-
learning_loop_node/tests/general/pytest.ini,sha256=8QdjmawLy1zAzXrJ88or1kpFDhJw0W5UOnDfGGs_igU,262
|
|
69
|
-
learning_loop_node/tests/general/test_data/file_1.txt,sha256=Lis06nfvbFPVCBZyEgQlfI_Nle2YDq1GQBlYvEfFtxw,19
|
|
70
|
-
learning_loop_node/tests/general/test_data/file_2.txt,sha256=Xp8EETGhZBdVAgb4URowSSpOytwwwJdV0Renkdur7R8,19
|
|
71
|
-
learning_loop_node/tests/general/test_data/model.json,sha256=_xNDucGOWila8gWnu8yFfrqmQ45Xq-_39eLKzjRtvpE,516
|
|
72
|
-
learning_loop_node/tests/general/test_data_classes.py,sha256=RnDzRtB-eRfWnaaA6qAzC1W8wurFzJ4xt1Q5pd7ZCS0,721
|
|
73
|
-
learning_loop_node/tests/general/test_downloader.py,sha256=y4GcUyR0OAfrwltd6eyQgopwTt3DwjzX0Sr8yrooLec,3347
|
|
74
|
-
learning_loop_node/tests/general/test_learning_loop_node.py,sha256=SZd-VChpWnnsPN46pr4E_LL3ZevYx6psU-AWdVeOFpQ,770
|
|
75
|
-
learning_loop_node/tests/test_helper.py,sha256=Qj_jS0xVOnwZvSJjUkrDxRXFe93hSi0RdG0wAlDVguo,3379
|
|
76
|
-
learning_loop_node/tests/trainer/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
77
|
-
learning_loop_node/tests/trainer/conftest.py,sha256=eJUUBVRTmwcEooEN29hIa3eNuo0ogAPNn7Vqs9FSRDM,3660
|
|
78
|
-
learning_loop_node/tests/trainer/pytest.ini,sha256=8QdjmawLy1zAzXrJ88or1kpFDhJw0W5UOnDfGGs_igU,262
|
|
79
|
-
learning_loop_node/tests/trainer/state_helper.py,sha256=MDe9opeKruip74FoRFff8MSWGiQNFqDpPtIEIbgPnFc,919
|
|
80
|
-
learning_loop_node/tests/trainer/states/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
81
|
-
learning_loop_node/tests/trainer/states/test_state_cleanup.py,sha256=gZNxSSwnj9f0esExNnQzqadM6-sE3IsF5sNbD0bZNu8,1250
|
|
82
|
-
learning_loop_node/tests/trainer/states/test_state_detecting.py,sha256=y3WCOqe4LPH4Rf97x7MmybbHOBwEqS3oOxg0TxScSX8,3720
|
|
83
|
-
learning_loop_node/tests/trainer/states/test_state_download_train_model.py,sha256=-T8iAutBliv0MV5bV5lPvn2aNjF3vMBCj8iAZTC-Q7g,2992
|
|
84
|
-
learning_loop_node/tests/trainer/states/test_state_prepare.py,sha256=boCU93Bv2VWbW73MC_suTbwCcuR7RWn-6dgVvdiJ9tA,2291
|
|
85
|
-
learning_loop_node/tests/trainer/states/test_state_sync_confusion_matrix.py,sha256=R3UqQJ2GQMapwRQ5WuZJb9M5IfroD2QqFI4h8etiH0Y,5223
|
|
86
|
-
learning_loop_node/tests/trainer/states/test_state_train.py,sha256=ovRs8EepQjy0yQJssK0TdcZcraBhmUkbMWeNKdHS114,2893
|
|
87
|
-
learning_loop_node/tests/trainer/states/test_state_upload_detections.py,sha256=oFQGTeRZhW7MBISAfpe65KphZNxFUsZu3-5hD9_LS6k,7438
|
|
88
|
-
learning_loop_node/tests/trainer/states/test_state_upload_model.py,sha256=jHWLa48tNljZwIiqI-1z71ENRGnn7Z0BsVcDBVWVBj4,3642
|
|
89
|
-
learning_loop_node/tests/trainer/test_errors.py,sha256=LdIky-SuR4Owml8FlByD0GXdv3vGh6JuqDQgJfFdgkw,2102
|
|
90
|
-
learning_loop_node/tests/trainer/test_trainer_states.py,sha256=OFrHSjpTIcwDp-QRe8sdseTZr0Z5dVeCt_ani9pfCqI,1238
|
|
91
|
-
learning_loop_node/tests/trainer/testing_trainer_logic.py,sha256=vaz7EbsVRcSMyAfEGpXgNFj1yQc9dYLCYDrjjmYTZ1o,3765
|
|
92
47
|
learning_loop_node/trainer/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
93
48
|
learning_loop_node/trainer/downloader.py,sha256=AIyEKM4XYtd6VgmXrP3VayV9DpJzdURK1Brx81ePNSM,1470
|
|
94
49
|
learning_loop_node/trainer/exceptions.py,sha256=vbuoE6kssLQuA8zd3LiDHmZglP6E2IJJwEi5AZtWXxY,420
|
|
95
50
|
learning_loop_node/trainer/executor.py,sha256=XQ1TwgOF2pQv7bgzSaljDWG4I1ySjYXL8r9c_p9MX1Q,3947
|
|
96
51
|
learning_loop_node/trainer/io_helpers.py,sha256=ZnAPVqhq8XCHe1NoiOQJ_w0B-estcc8CBQHnb423UDw,7226
|
|
97
|
-
learning_loop_node/trainer/rest/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
98
|
-
learning_loop_node/trainer/rest/backdoor_controls.py,sha256=ZnK8ypY5r_q0-YZbtaOxhQThzuZvMsQHM5gJGESd_dE,5131
|
|
99
52
|
learning_loop_node/trainer/test_executor.py,sha256=6BVGDN_6f5GEMMEvDLSG1yzMybSvgXaP5uYpSfsVPP0,2224
|
|
100
53
|
learning_loop_node/trainer/trainer_logic.py,sha256=eK-01qZzi10UjLMCQX8vy5eW2FoghPj3rzzDC-s3Si4,8792
|
|
101
54
|
learning_loop_node/trainer/trainer_logic_generic.py,sha256=KcHmXr-Hp8_Wuejzj8odY6sRPqi6aw1SEXv3YlbjM98,27057
|
|
102
55
|
learning_loop_node/trainer/trainer_node.py,sha256=tsAMzJewdS7Bi_1b9FwG0d2lGlv2lY37pgOLWr0bP_I,4582
|
|
103
|
-
learning_loop_node
|
|
104
|
-
learning_loop_node
|
|
105
|
-
learning_loop_node-0.18.
|
|
56
|
+
learning_loop_node/trainer/rest/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
57
|
+
learning_loop_node/trainer/rest/backdoor_controls.py,sha256=ZnK8ypY5r_q0-YZbtaOxhQThzuZvMsQHM5gJGESd_dE,5131
|
|
58
|
+
learning_loop_node-0.18.4.dist-info/METADATA,sha256=V9kzX_sICIu_uGtGUYzFJT8UYxkcyVPJ63LCkW0jzJA,15017
|
|
59
|
+
learning_loop_node-0.18.4.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
60
|
+
learning_loop_node-0.18.4.dist-info/top_level.txt,sha256=nS5qiFc4stVF_VXVCVJxZnrqVOv3IGX5-_E3sLby6OE,19
|
|
61
|
+
learning_loop_node-0.18.4.dist-info/RECORD,,
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
learning_loop_node
|
|
@@ -1,70 +0,0 @@
|
|
|
1
|
-
import asyncio
|
|
2
|
-
import logging
|
|
3
|
-
import os
|
|
4
|
-
from typing import Dict
|
|
5
|
-
|
|
6
|
-
from tqdm import tqdm
|
|
7
|
-
|
|
8
|
-
from learning_loop_node.loop_communication import LoopCommunicator
|
|
9
|
-
|
|
10
|
-
os.environ['LOOP_HOST'] = 'preview.learning-loop.ai'
|
|
11
|
-
os.environ['LOOP_ORGANIZATION'] = 'zauberzeug'
|
|
12
|
-
os.environ['LOOP_PROJECT'] = 'demo'
|
|
13
|
-
|
|
14
|
-
logging.info('Starting novelty_score_updater')
|
|
15
|
-
glc = LoopCommunicator()
|
|
16
|
-
|
|
17
|
-
project_path = f'/{glc.organization}/projects/{glc.project}'
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
async def get_json_async(path) -> Dict:
|
|
21
|
-
url = f'{project_path}{path}'
|
|
22
|
-
response = await glc.get(url)
|
|
23
|
-
if response.status_code != 200:
|
|
24
|
-
raise Exception('bad response: ' + str(response))
|
|
25
|
-
return response.json()
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
def get_json(path):
|
|
29
|
-
return asyncio.get_event_loop().run_until_complete(get_json_async(path))
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
async def put_json_async(path, json) -> Dict:
|
|
33
|
-
response = await glc.async_client.put(path, json=json)
|
|
34
|
-
if response.status_code != 200:
|
|
35
|
-
raise Exception(f'bad response: {str(response)} \n {response.json()}')
|
|
36
|
-
return response.json()
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
def put_json(path, json):
|
|
40
|
-
return asyncio.get_event_loop().run_until_complete(put_json_async(path, json))
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
data = get_json(f'{project_path}/data')
|
|
44
|
-
categories = data['categories']
|
|
45
|
-
image_ids = data['image_ids'][0:1] # use only one image for testing
|
|
46
|
-
chunk_size = 50
|
|
47
|
-
|
|
48
|
-
images_data = []
|
|
49
|
-
for i in tqdm(range(0, len(image_ids), chunk_size), position=0, leave=True):
|
|
50
|
-
chunk_ids = image_ids[i:i+chunk_size]
|
|
51
|
-
chunk_data = get_json(f'{project_path}/images?ids={",".join(chunk_ids)}&model_version=1.1')
|
|
52
|
-
images_data += chunk_data['images']
|
|
53
|
-
|
|
54
|
-
novelty_scores = {}
|
|
55
|
-
for image_data in images_data:
|
|
56
|
-
image_id = image_data['id']
|
|
57
|
-
detections = image_data['box_detections']
|
|
58
|
-
novelty_score = 0
|
|
59
|
-
for d in detections:
|
|
60
|
-
if d['confidence'] > 20 and d['confidence'] < 80:
|
|
61
|
-
novelty_score += 1
|
|
62
|
-
novelty_scores[image_id] = novelty_score
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
put_json('/images/novelty_scores', json=novelty_scores)
|
|
66
|
-
|
|
67
|
-
loop = asyncio.get_event_loop()
|
|
68
|
-
loop.run_until_complete(glc.shutdown())
|
|
69
|
-
|
|
70
|
-
logging.info('novelty_score_updater stopped')
|
|
File without changes
|
|
File without changes
|
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
import asyncio
|
|
2
|
-
import logging
|
|
3
|
-
import os
|
|
4
|
-
import shutil
|
|
5
|
-
|
|
6
|
-
# ====================================== REDUNDANT FIXTURES IN ALL CONFTESTS ! ======================================
|
|
7
|
-
import sys
|
|
8
|
-
|
|
9
|
-
import pytest
|
|
10
|
-
|
|
11
|
-
from ...globals import GLOBALS
|
|
12
|
-
from ...loop_communication import LoopCommunicator
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
@pytest.fixture()
|
|
16
|
-
async def setup_test_project(): # pylint: disable=redefined-outer-name
|
|
17
|
-
loop_communicator = LoopCommunicator()
|
|
18
|
-
try:
|
|
19
|
-
await loop_communicator.delete("/zauberzeug/projects/pytest_nodelib_annotator?keep_images=true", timeout=10)
|
|
20
|
-
except Exception:
|
|
21
|
-
logging.exception("Failed to delete project pytest_nodelib_annotator")
|
|
22
|
-
sys.exit(1)
|
|
23
|
-
await asyncio.sleep(1)
|
|
24
|
-
project_conf = {
|
|
25
|
-
'project_name': 'pytest_nodelib_annotator', 'inbox': 0, 'annotate': 0, 'review': 0, 'complete': 3, 'image_style': 'beautiful',
|
|
26
|
-
'box_categories': 2, 'point_categories': 2, 'segmentation_categories': 2, 'thumbs': False, 'tags': 0,
|
|
27
|
-
'trainings': 1, 'box_detections': 3, 'box_annotations': 0}
|
|
28
|
-
assert (await loop_communicator.post("/zauberzeug/projects/generator", json=project_conf)).status_code == 200
|
|
29
|
-
yield
|
|
30
|
-
await loop_communicator.delete("/zauberzeug/projects/pytest_nodelib_annotator?keep_images=true", timeout=10)
|
|
31
|
-
await loop_communicator.shutdown()
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
@pytest.fixture(autouse=True, scope='session')
|
|
35
|
-
def clear_loggers():
|
|
36
|
-
"""Remove handlers from all loggers"""
|
|
37
|
-
# see https://github.com/pytest-dev/pytest/issues/5502
|
|
38
|
-
yield
|
|
39
|
-
|
|
40
|
-
loggers = [logging.getLogger()] + list(logging.Logger.manager.loggerDict.values())
|
|
41
|
-
for logger in loggers:
|
|
42
|
-
if not isinstance(logger, logging.Logger):
|
|
43
|
-
continue
|
|
44
|
-
handlers = getattr(logger, 'handlers', [])
|
|
45
|
-
for handler in handlers:
|
|
46
|
-
logger.removeHandler(handler)
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
@pytest.fixture(autouse=True, scope='function')
|
|
50
|
-
def data_folder():
|
|
51
|
-
GLOBALS.data_folder = '/tmp/learning_loop_lib_data'
|
|
52
|
-
shutil.rmtree(GLOBALS.data_folder, ignore_errors=True)
|
|
53
|
-
os.makedirs(GLOBALS.data_folder, exist_ok=True)
|
|
54
|
-
yield
|
|
55
|
-
shutil.rmtree(GLOBALS.data_folder, ignore_errors=True)
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
[pytest]
|
|
2
|
-
python_files = test_*.py
|
|
3
|
-
asyncio_mode = auto
|
|
4
|
-
|
|
5
|
-
cache_dir = /tmp/pytest_cache
|
|
6
|
-
|
|
7
|
-
# for debbuging tests:
|
|
8
|
-
; log_cli_level = INFO
|
|
9
|
-
; log_cli_format = %(asctime)s [%(levelname)8s] %(message)s (%(filename)s:%(lineno)s)
|
|
10
|
-
; log_cli_date_format=%Y-%m-%d %H:%M:%S
|
|
@@ -1,60 +0,0 @@
|
|
|
1
|
-
import os
|
|
2
|
-
from dataclasses import asdict
|
|
3
|
-
from typing import Dict
|
|
4
|
-
|
|
5
|
-
import pytest
|
|
6
|
-
from fastapi.encoders import jsonable_encoder
|
|
7
|
-
|
|
8
|
-
from ...annotation.annotator_logic import AnnotatorLogic
|
|
9
|
-
from ...annotation.annotator_node import AnnotatorNode
|
|
10
|
-
from ...data_classes import (
|
|
11
|
-
AnnotationData,
|
|
12
|
-
Category,
|
|
13
|
-
Context,
|
|
14
|
-
Point,
|
|
15
|
-
ToolOutput,
|
|
16
|
-
UserInput,
|
|
17
|
-
)
|
|
18
|
-
from ...enums import AnnotationEventType, CategoryType
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
class MockedAnnotatatorLogic(AnnotatorLogic):
|
|
22
|
-
async def handle_user_input(self, user_input: UserInput, history: Dict) -> ToolOutput:
|
|
23
|
-
return ToolOutput(svg="")
|
|
24
|
-
|
|
25
|
-
def create_empty_history(self) -> dict:
|
|
26
|
-
return {}
|
|
27
|
-
|
|
28
|
-
def logout_user(self, sid: str) -> bool:
|
|
29
|
-
return True
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
def default_user_input() -> UserInput:
|
|
33
|
-
annotation_data = AnnotationData(
|
|
34
|
-
coordinate=Point(x=0, y=0),
|
|
35
|
-
event_type=AnnotationEventType.LeftMouseDown,
|
|
36
|
-
context=Context(organization='zauberzeug', project='pytest_nodelib_annotator'),
|
|
37
|
-
image_uuid='10f7d7d2-4076-7006-af37-fa28a6a848ae',
|
|
38
|
-
category=Category(id='some_id', name='category_1', description='',
|
|
39
|
-
hotkey='', color='', type=CategoryType.Segmentation)
|
|
40
|
-
)
|
|
41
|
-
return UserInput(frontend_id='some_id', data=annotation_data)
|
|
42
|
-
|
|
43
|
-
# ------------------------------------------------------------ TESTS ------------------------------------------------------------
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
@pytest.mark.asyncio
|
|
47
|
-
@pytest.mark.usefixtures('setup_test_project')
|
|
48
|
-
async def test_image_download():
|
|
49
|
-
# pylint: disable=protected-access
|
|
50
|
-
|
|
51
|
-
image_folder = '/tmp/learning_loop_lib_data/zauberzeug/pytest_nodelib_annotator/images'
|
|
52
|
-
|
|
53
|
-
assert os.path.exists(image_folder) is False or len(os.listdir(image_folder)) == 0
|
|
54
|
-
|
|
55
|
-
node = AnnotatorNode(name="", uuid="", annotator_logic=MockedAnnotatatorLogic())
|
|
56
|
-
user_input = default_user_input()
|
|
57
|
-
await node._ensure_sio_connection() # This is required as the node is not "started"
|
|
58
|
-
_ = await node._handle_user_input(jsonable_encoder(asdict(user_input)))
|
|
59
|
-
|
|
60
|
-
assert os.path.exists(image_folder) is True and len(os.listdir(image_folder)) == 1
|
|
File without changes
|
|
@@ -1,174 +0,0 @@
|
|
|
1
|
-
import asyncio
|
|
2
|
-
import logging
|
|
3
|
-
import multiprocessing
|
|
4
|
-
import os
|
|
5
|
-
import shutil
|
|
6
|
-
import socket
|
|
7
|
-
from glob import glob
|
|
8
|
-
from multiprocessing import Process, log_to_stderr
|
|
9
|
-
from typing import AsyncGenerator
|
|
10
|
-
|
|
11
|
-
import numpy as np
|
|
12
|
-
import pytest
|
|
13
|
-
import socketio
|
|
14
|
-
import uvicorn
|
|
15
|
-
|
|
16
|
-
from learning_loop_node.data_classes import BoxDetection, ImageMetadata
|
|
17
|
-
from learning_loop_node.detector.detector_logic import DetectorLogic
|
|
18
|
-
|
|
19
|
-
from ...detector.detector_node import DetectorNode
|
|
20
|
-
from ...detector.outbox import Outbox
|
|
21
|
-
from ...globals import GLOBALS
|
|
22
|
-
from .testing_detector import TestingDetectorLogic
|
|
23
|
-
|
|
24
|
-
logging.basicConfig(level=logging.INFO)
|
|
25
|
-
|
|
26
|
-
# show ouptut from uvicorn server https://stackoverflow.com/a/66132186/364388
|
|
27
|
-
log_to_stderr(logging.INFO)
|
|
28
|
-
|
|
29
|
-
detector_port = GLOBALS.detector_port
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
def should_have_segmentations(request) -> bool:
|
|
33
|
-
should_have_seg = False
|
|
34
|
-
try:
|
|
35
|
-
should_have_seg = request.param
|
|
36
|
-
except Exception:
|
|
37
|
-
pass
|
|
38
|
-
return should_have_seg
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
@pytest.fixture(scope="session", name="event_loop")
|
|
42
|
-
def fixture_event_loop():
|
|
43
|
-
"""Overrides pytest default function scoped event loop"""
|
|
44
|
-
policy = asyncio.get_event_loop_policy()
|
|
45
|
-
loop = policy.new_event_loop()
|
|
46
|
-
yield loop
|
|
47
|
-
loop.close()
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
@pytest.fixture()
|
|
51
|
-
async def test_detector_node():
|
|
52
|
-
"""Initializes and runs a detector testnode. Note that the running instance and the one the function returns are not the same instances!"""
|
|
53
|
-
|
|
54
|
-
os.environ['LOOP_ORGANIZATION'] = 'zauberzeug'
|
|
55
|
-
os.environ['LOOP_PROJECT'] = 'demo'
|
|
56
|
-
|
|
57
|
-
detector = TestingDetectorLogic()
|
|
58
|
-
node = DetectorNode(name='test', detector=detector)
|
|
59
|
-
await port_is(free=True)
|
|
60
|
-
|
|
61
|
-
multiprocessing.set_start_method('fork', force=True)
|
|
62
|
-
assert multiprocessing.get_start_method() == 'fork'
|
|
63
|
-
# print('\n\n',multiprocessing.get_start_method())
|
|
64
|
-
|
|
65
|
-
proc = Process(target=uvicorn.run,
|
|
66
|
-
args=(node,),
|
|
67
|
-
kwargs={
|
|
68
|
-
"host": "127.0.0.1",
|
|
69
|
-
"port": detector_port,
|
|
70
|
-
}, daemon=True)
|
|
71
|
-
proc.start()
|
|
72
|
-
await port_is(free=False)
|
|
73
|
-
yield node
|
|
74
|
-
|
|
75
|
-
try:
|
|
76
|
-
await node._on_shutdown() # pylint: disable=protected-access
|
|
77
|
-
except Exception:
|
|
78
|
-
logging.exception('error while shutting down node')
|
|
79
|
-
|
|
80
|
-
try:
|
|
81
|
-
proc.kill()
|
|
82
|
-
except Exception: # for python 3.6
|
|
83
|
-
proc.terminate()
|
|
84
|
-
proc.join()
|
|
85
|
-
|
|
86
|
-
# from https://stackoverflow.com/a/52872579/364388
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
def is_port_in_use(port):
|
|
90
|
-
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
|
|
91
|
-
return s.connect_ex(('localhost', port)) == 0
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
async def port_is(free: bool):
|
|
95
|
-
for _ in range(10):
|
|
96
|
-
if not free and is_port_in_use(detector_port):
|
|
97
|
-
return
|
|
98
|
-
if free and not is_port_in_use(detector_port):
|
|
99
|
-
return
|
|
100
|
-
await asyncio.sleep(0.5)
|
|
101
|
-
raise Exception(f'port {detector_port} is {"not" if free else ""} free')
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
@pytest.fixture()
|
|
105
|
-
async def sio_client() -> AsyncGenerator[socketio.AsyncClient, None]:
|
|
106
|
-
sio = socketio.AsyncClient()
|
|
107
|
-
try_connect = True
|
|
108
|
-
retry_count = 0
|
|
109
|
-
while try_connect:
|
|
110
|
-
try:
|
|
111
|
-
await sio.connect(f"ws://localhost:{detector_port}", socketio_path="/ws/socket.io")
|
|
112
|
-
try_connect = False
|
|
113
|
-
except Exception:
|
|
114
|
-
logging.exception("Connection failed with error:")
|
|
115
|
-
logging.warning('trying again')
|
|
116
|
-
await asyncio.sleep(5)
|
|
117
|
-
retry_count += 1
|
|
118
|
-
if retry_count > 10:
|
|
119
|
-
raise Exception('Max Retry')
|
|
120
|
-
|
|
121
|
-
yield sio
|
|
122
|
-
await sio.disconnect()
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
def get_outbox_files(outbox: Outbox):
|
|
126
|
-
files = glob(f'{outbox.path}/**/*', recursive=True)
|
|
127
|
-
return [file for file in files if os.path.isfile(file)]
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
class MockDetectorLogic(DetectorLogic): # pylint: disable=abstract-method
|
|
131
|
-
def __init__(self):
|
|
132
|
-
super().__init__('mock')
|
|
133
|
-
self.image_metadata = ImageMetadata(
|
|
134
|
-
box_detections=[BoxDetection(category_name="test",
|
|
135
|
-
category_id="1",
|
|
136
|
-
confidence=0.9,
|
|
137
|
-
x=0, y=0, width=10, height=10,
|
|
138
|
-
model_name="mock", )])
|
|
139
|
-
|
|
140
|
-
def evaluate(self, image: np.ndarray) -> ImageMetadata:
|
|
141
|
-
return self.image_metadata
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
@pytest.fixture
|
|
145
|
-
def detector_node():
|
|
146
|
-
os.environ['LOOP_ORGANIZATION'] = 'test_organization'
|
|
147
|
-
os.environ['LOOP_PROJECT'] = 'test_project'
|
|
148
|
-
return DetectorNode(name="test_node", detector=MockDetectorLogic())
|
|
149
|
-
|
|
150
|
-
# ====================================== REDUNDANT FIXTURES IN ALL CONFTESTS ! ======================================
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
@pytest.fixture(autouse=True, scope='session')
|
|
154
|
-
def clear_loggers():
|
|
155
|
-
"""Remove handlers from all loggers"""
|
|
156
|
-
# see https://github.com/pytest-dev/pytest/issues/5502
|
|
157
|
-
yield
|
|
158
|
-
|
|
159
|
-
loggers = [logging.getLogger()] + list(logging.Logger.manager.loggerDict.values())
|
|
160
|
-
for logger in loggers:
|
|
161
|
-
if not isinstance(logger, logging.Logger):
|
|
162
|
-
continue
|
|
163
|
-
handlers = getattr(logger, 'handlers', [])
|
|
164
|
-
for handler in handlers:
|
|
165
|
-
logger.removeHandler(handler)
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
@pytest.fixture(autouse=True, scope='function')
|
|
169
|
-
def data_folder():
|
|
170
|
-
GLOBALS.data_folder = '/tmp/learning_loop_lib_data'
|
|
171
|
-
shutil.rmtree(GLOBALS.data_folder, ignore_errors=True)
|
|
172
|
-
os.makedirs(GLOBALS.data_folder, exist_ok=True)
|
|
173
|
-
yield
|
|
174
|
-
shutil.rmtree(GLOBALS.data_folder, ignore_errors=True)
|
|
File without changes
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
import time
|
|
2
|
-
from datetime import datetime, timedelta
|
|
3
|
-
|
|
4
|
-
from ....data_classes import BoxDetection, Observation
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
def test_aging():
|
|
8
|
-
_detection = Observation(BoxDetection(category_name='dirt', x=10, y=0, height=30, width=100,
|
|
9
|
-
model_name='model', confidence=0.30, category_id='some-id'))
|
|
10
|
-
time.sleep(0.2)
|
|
11
|
-
assert _detection.is_older_than(0.1)
|
|
12
|
-
assert not _detection.is_older_than(0.3)
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
def test_calculate_iou():
|
|
16
|
-
one = BoxDetection(category_name='dirt', x=10, y=0, width=30, height=100,
|
|
17
|
-
model_name='model', confidence=0.30, category_id='some-id')
|
|
18
|
-
two = BoxDetection(category_name='dirt', x=20, y=0, width=30, height=100,
|
|
19
|
-
model_name='model', confidence=0.61, category_id='some-id')
|
|
20
|
-
three = BoxDetection(category_name='dirt', x=0, y=30, width=10, height=10,
|
|
21
|
-
model_name='model', confidence=0.61, category_id='some-id')
|
|
22
|
-
|
|
23
|
-
assert one.intersection_over_union(two) == 0.5
|
|
24
|
-
assert one.intersection_over_union(three) == 0.0
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
def test_update_last_seen():
|
|
28
|
-
observation = Observation(BoxDetection(category_name='dirt', x=10, y=0, height=30,
|
|
29
|
-
width=100, model_name='model', confidence=0.30, category_id='some-id'))
|
|
30
|
-
observation.last_seen = datetime.now() - timedelta(seconds=.5)
|
|
31
|
-
assert observation.is_older_than(0.5)
|