learning-loop-node 0.8.6__tar.gz → 0.8.7__tar.gz

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 learning-loop-node might be problematic. Click here for more details.

Files changed (87) hide show
  1. {learning_loop_node-0.8.6 → learning_loop_node-0.8.7}/PKG-INFO +4 -4
  2. {learning_loop_node-0.8.6 → learning_loop_node-0.8.7}/learning_loop_node/data_exchanger.py +16 -2
  3. {learning_loop_node-0.8.6 → learning_loop_node-0.8.7}/learning_loop_node/detector/detector_logic.py +1 -1
  4. {learning_loop_node-0.8.6 → learning_loop_node-0.8.7}/learning_loop_node/detector/detector_node.py +2 -0
  5. {learning_loop_node-0.8.6 → learning_loop_node-0.8.7}/learning_loop_node/tests/test_downloader.py +24 -1
  6. {learning_loop_node-0.8.6 → learning_loop_node-0.8.7}/learning_loop_node/trainer/trainer_logic.py +3 -3
  7. {learning_loop_node-0.8.6 → learning_loop_node-0.8.7}/pyproject.toml +5 -5
  8. {learning_loop_node-0.8.6 → learning_loop_node-0.8.7}/README.md +0 -0
  9. {learning_loop_node-0.8.6 → learning_loop_node-0.8.7}/learning_loop_node/__init__.py +0 -0
  10. {learning_loop_node-0.8.6 → learning_loop_node-0.8.7}/learning_loop_node/annotation/__init__.py +0 -0
  11. {learning_loop_node-0.8.6 → learning_loop_node-0.8.7}/learning_loop_node/annotation/annotator_logic.py +0 -0
  12. {learning_loop_node-0.8.6 → learning_loop_node-0.8.7}/learning_loop_node/annotation/annotator_node.py +0 -0
  13. {learning_loop_node-0.8.6 → learning_loop_node-0.8.7}/learning_loop_node/annotation/tests/test_annotator_node.py +0 -0
  14. {learning_loop_node-0.8.6 → learning_loop_node-0.8.7}/learning_loop_node/conftest.py +0 -0
  15. {learning_loop_node-0.8.6 → learning_loop_node-0.8.7}/learning_loop_node/converter/__init__.py +0 -0
  16. {learning_loop_node-0.8.6 → learning_loop_node-0.8.7}/learning_loop_node/converter/converter_logic.py +0 -0
  17. {learning_loop_node-0.8.6 → learning_loop_node-0.8.7}/learning_loop_node/converter/converter_node.py +0 -0
  18. {learning_loop_node-0.8.6 → learning_loop_node-0.8.7}/learning_loop_node/converter/tests/test_converter.py +0 -0
  19. {learning_loop_node-0.8.6 → learning_loop_node-0.8.7}/learning_loop_node/data_classes/__init__.py +0 -0
  20. {learning_loop_node-0.8.6 → learning_loop_node-0.8.7}/learning_loop_node/data_classes/annotations.py +0 -0
  21. {learning_loop_node-0.8.6 → learning_loop_node-0.8.7}/learning_loop_node/data_classes/detections.py +0 -0
  22. {learning_loop_node-0.8.6 → learning_loop_node-0.8.7}/learning_loop_node/data_classes/general.py +0 -0
  23. {learning_loop_node-0.8.6 → learning_loop_node-0.8.7}/learning_loop_node/data_classes/socket_response.py +0 -0
  24. {learning_loop_node-0.8.6 → learning_loop_node-0.8.7}/learning_loop_node/data_classes/training.py +0 -0
  25. {learning_loop_node-0.8.6 → learning_loop_node-0.8.7}/learning_loop_node/detector/__init__.py +0 -0
  26. {learning_loop_node-0.8.6 → learning_loop_node-0.8.7}/learning_loop_node/detector/inbox_filter/__init__.py +0 -0
  27. {learning_loop_node-0.8.6 → learning_loop_node-0.8.7}/learning_loop_node/detector/inbox_filter/cam_observation_history.py +0 -0
  28. {learning_loop_node-0.8.6 → learning_loop_node-0.8.7}/learning_loop_node/detector/inbox_filter/relevance_filter.py +0 -0
  29. {learning_loop_node-0.8.6 → learning_loop_node-0.8.7}/learning_loop_node/detector/inbox_filter/tests/test_observation.py +0 -0
  30. {learning_loop_node-0.8.6 → learning_loop_node-0.8.7}/learning_loop_node/detector/inbox_filter/tests/test_relevance_group.py +0 -0
  31. {learning_loop_node-0.8.6 → learning_loop_node-0.8.7}/learning_loop_node/detector/inbox_filter/tests/test_unexpected_observations_count.py +0 -0
  32. {learning_loop_node-0.8.6 → learning_loop_node-0.8.7}/learning_loop_node/detector/outbox.py +0 -0
  33. {learning_loop_node-0.8.6 → learning_loop_node-0.8.7}/learning_loop_node/detector/rest/__init__.py +0 -0
  34. {learning_loop_node-0.8.6 → learning_loop_node-0.8.7}/learning_loop_node/detector/rest/backdoor_controls.py +0 -0
  35. {learning_loop_node-0.8.6 → learning_loop_node-0.8.7}/learning_loop_node/detector/rest/detect.py +0 -0
  36. {learning_loop_node-0.8.6 → learning_loop_node-0.8.7}/learning_loop_node/detector/rest/operation_mode.py +0 -0
  37. {learning_loop_node-0.8.6 → learning_loop_node-0.8.7}/learning_loop_node/detector/rest/upload.py +0 -0
  38. {learning_loop_node-0.8.6 → learning_loop_node-0.8.7}/learning_loop_node/detector/tests/__init__.py +0 -0
  39. {learning_loop_node-0.8.6 → learning_loop_node-0.8.7}/learning_loop_node/detector/tests/conftest.py +0 -0
  40. {learning_loop_node-0.8.6 → learning_loop_node-0.8.7}/learning_loop_node/detector/tests/test.jpg +0 -0
  41. {learning_loop_node-0.8.6 → learning_loop_node-0.8.7}/learning_loop_node/detector/tests/test_client_communication.py +0 -0
  42. {learning_loop_node-0.8.6 → learning_loop_node-0.8.7}/learning_loop_node/detector/tests/test_outbox.py +0 -0
  43. {learning_loop_node-0.8.6 → learning_loop_node-0.8.7}/learning_loop_node/detector/tests/test_relevance_filter.py +0 -0
  44. {learning_loop_node-0.8.6 → learning_loop_node-0.8.7}/learning_loop_node/detector/tests/testing_detector.py +0 -0
  45. {learning_loop_node-0.8.6 → learning_loop_node-0.8.7}/learning_loop_node/examples/novelty_score_updater.py +0 -0
  46. {learning_loop_node-0.8.6 → learning_loop_node-0.8.7}/learning_loop_node/globals.py +0 -0
  47. {learning_loop_node-0.8.6 → learning_loop_node-0.8.7}/learning_loop_node/helpers/__init__.py +0 -0
  48. {learning_loop_node-0.8.6 → learning_loop_node-0.8.7}/learning_loop_node/helpers/environment_reader.py +0 -0
  49. {learning_loop_node-0.8.6 → learning_loop_node-0.8.7}/learning_loop_node/helpers/gdrive_downloader.py +0 -0
  50. {learning_loop_node-0.8.6 → learning_loop_node-0.8.7}/learning_loop_node/helpers/log_conf.py +0 -0
  51. {learning_loop_node-0.8.6 → learning_loop_node-0.8.7}/learning_loop_node/helpers/misc.py +0 -0
  52. {learning_loop_node-0.8.6 → learning_loop_node-0.8.7}/learning_loop_node/loop_communication.py +0 -0
  53. {learning_loop_node-0.8.6 → learning_loop_node-0.8.7}/learning_loop_node/node.py +0 -0
  54. {learning_loop_node-0.8.6 → learning_loop_node-0.8.7}/learning_loop_node/pytest.ini +0 -0
  55. {learning_loop_node-0.8.6 → learning_loop_node-0.8.7}/learning_loop_node/tests/__init__.py +0 -0
  56. {learning_loop_node-0.8.6 → learning_loop_node-0.8.7}/learning_loop_node/tests/conftest.py +0 -0
  57. {learning_loop_node-0.8.6 → learning_loop_node-0.8.7}/learning_loop_node/tests/test_data/file_1.txt +0 -0
  58. {learning_loop_node-0.8.6 → learning_loop_node-0.8.7}/learning_loop_node/tests/test_data/file_2.txt +0 -0
  59. {learning_loop_node-0.8.6 → learning_loop_node-0.8.7}/learning_loop_node/tests/test_data/model.json +0 -0
  60. {learning_loop_node-0.8.6 → learning_loop_node-0.8.7}/learning_loop_node/tests/test_data_classes.py +0 -0
  61. {learning_loop_node-0.8.6 → learning_loop_node-0.8.7}/learning_loop_node/tests/test_executor.py +0 -0
  62. {learning_loop_node-0.8.6 → learning_loop_node-0.8.7}/learning_loop_node/tests/test_helper.py +0 -0
  63. {learning_loop_node-0.8.6 → learning_loop_node-0.8.7}/learning_loop_node/tests/test_learning_loop_node.py +0 -0
  64. {learning_loop_node-0.8.6 → learning_loop_node-0.8.7}/learning_loop_node/trainer/__init__.py +0 -0
  65. {learning_loop_node-0.8.6 → learning_loop_node-0.8.7}/learning_loop_node/trainer/downloader.py +0 -0
  66. {learning_loop_node-0.8.6 → learning_loop_node-0.8.7}/learning_loop_node/trainer/executor.py +0 -0
  67. {learning_loop_node-0.8.6 → learning_loop_node-0.8.7}/learning_loop_node/trainer/io_helpers.py +0 -0
  68. {learning_loop_node-0.8.6 → learning_loop_node-0.8.7}/learning_loop_node/trainer/rest/__init__.py +0 -0
  69. {learning_loop_node-0.8.6 → learning_loop_node-0.8.7}/learning_loop_node/trainer/rest/backdoor_controls.py +0 -0
  70. {learning_loop_node-0.8.6 → learning_loop_node-0.8.7}/learning_loop_node/trainer/rest/controls.py +0 -0
  71. {learning_loop_node-0.8.6 → learning_loop_node-0.8.7}/learning_loop_node/trainer/tests/__init__.py +0 -0
  72. {learning_loop_node-0.8.6 → learning_loop_node-0.8.7}/learning_loop_node/trainer/tests/conftest.py +0 -0
  73. {learning_loop_node-0.8.6 → learning_loop_node-0.8.7}/learning_loop_node/trainer/tests/state_helper.py +0 -0
  74. {learning_loop_node-0.8.6 → learning_loop_node-0.8.7}/learning_loop_node/trainer/tests/states/__init__.py +0 -0
  75. {learning_loop_node-0.8.6 → learning_loop_node-0.8.7}/learning_loop_node/trainer/tests/states/test_state_cleanup.py +0 -0
  76. {learning_loop_node-0.8.6 → learning_loop_node-0.8.7}/learning_loop_node/trainer/tests/states/test_state_detecting.py +0 -0
  77. {learning_loop_node-0.8.6 → learning_loop_node-0.8.7}/learning_loop_node/trainer/tests/states/test_state_download_train_model.py +0 -0
  78. {learning_loop_node-0.8.6 → learning_loop_node-0.8.7}/learning_loop_node/trainer/tests/states/test_state_prepare.py +0 -0
  79. {learning_loop_node-0.8.6 → learning_loop_node-0.8.7}/learning_loop_node/trainer/tests/states/test_state_sync_confusion_matrix.py +0 -0
  80. {learning_loop_node-0.8.6 → learning_loop_node-0.8.7}/learning_loop_node/trainer/tests/states/test_state_train.py +0 -0
  81. {learning_loop_node-0.8.6 → learning_loop_node-0.8.7}/learning_loop_node/trainer/tests/states/test_state_upload_detections.py +0 -0
  82. {learning_loop_node-0.8.6 → learning_loop_node-0.8.7}/learning_loop_node/trainer/tests/states/test_state_upload_model.py +0 -0
  83. {learning_loop_node-0.8.6 → learning_loop_node-0.8.7}/learning_loop_node/trainer/tests/test_errors.py +0 -0
  84. {learning_loop_node-0.8.6 → learning_loop_node-0.8.7}/learning_loop_node/trainer/tests/test_trainer_states.py +0 -0
  85. {learning_loop_node-0.8.6 → learning_loop_node-0.8.7}/learning_loop_node/trainer/tests/testing_trainer_logic.py +0 -0
  86. {learning_loop_node-0.8.6 → learning_loop_node-0.8.7}/learning_loop_node/trainer/trainer_node.py +0 -0
  87. {learning_loop_node-0.8.6 → learning_loop_node-0.8.7}/learning_loop_node/trainer/training_syncronizer.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: learning-loop-node
3
- Version: 0.8.6
3
+ Version: 0.8.7
4
4
  Summary: Python Library for Nodes which connect to the Zauberzeug Learning Loop
5
5
  Home-page: https://github.com/zauberzeug/learning_loop_node
6
6
  License: MIT
@@ -18,8 +18,8 @@ Requires-Dist: aiofiles (>=0.7.0,<0.8.0)
18
18
  Requires-Dist: aiohttp (>=3.8.4,<4.0.0)
19
19
  Requires-Dist: async_generator (>=1.10,<2.0)
20
20
  Requires-Dist: dacite (>=1.8.1,<2.0.0)
21
- Requires-Dist: fastapi (>=0.70.1,<0.71.0)
22
- Requires-Dist: fastapi-socketio (>=0.0.6,<0.0.7)
21
+ Requires-Dist: fastapi (>=0.93,<1.0.0)
22
+ Requires-Dist: fastapi-socketio (>=0.0.10,<0.0.11)
23
23
  Requires-Dist: fastapi-utils (>=0.2.1,<0.3.0)
24
24
  Requires-Dist: httpx (>=0.24.1,<0.25.0)
25
25
  Requires-Dist: icecream (>=2.1.0,<3.0.0)
@@ -33,7 +33,7 @@ Requires-Dist: python-socketio (>=5.7.2,<6.0.0)
33
33
  Requires-Dist: requests (>=2.25.1,<3.0.0)
34
34
  Requires-Dist: simplejson (>=3.17.2,<4.0.0)
35
35
  Requires-Dist: tqdm (>=4.63.0,<5.0.0)
36
- Requires-Dist: uvicorn (>=0.13.3,<0.14.0)
36
+ Requires-Dist: uvicorn[standard] (>=0.22.0,<0.23.0)
37
37
  Requires-Dist: werkzeug (>=2.0.1,<3.0.0)
38
38
  Project-URL: Repository, https://github.com/zauberzeug/learning_loop_node
39
39
  Description-Content-Type: text/markdown
@@ -59,10 +59,23 @@ class DataExchanger():
59
59
  logging.warning('context was not set yet')
60
60
  return
61
61
 
62
+ await self.delete_corrupt_images(image_folder)
62
63
  new_image_ids = await asyncio.get_event_loop().run_in_executor(None, DataExchanger.filter_existing_images, image_ids, image_folder)
63
64
  paths, ids = create_resource_paths(self.context.organization, self.context.project, new_image_ids)
64
65
  await self._download_images(paths, ids, image_folder)
65
66
 
67
+ @staticmethod
68
+ async def delete_corrupt_images(image_folder: str) -> None:
69
+ logging.info('deleting corrupt images')
70
+ n_deleted = 0
71
+ for image in glob(f'{image_folder}/*.jpg'):
72
+ if not await DataExchanger.is_valid_image(image):
73
+ logging.debug(f' deleting image {image}')
74
+ os.remove(image)
75
+ n_deleted += 1
76
+
77
+ logging.info(f'deleted {n_deleted} images')
78
+
66
79
  @staticmethod
67
80
  def filter_existing_images(all_image_ids, image_folder) -> List[str]:
68
81
  logging.info(f'### Going to filter {len(all_image_ids)} images ids')
@@ -131,8 +144,9 @@ class DataExchanger():
131
144
  if not await self.is_valid_image(filename):
132
145
  os.remove(filename)
133
146
 
134
- async def is_valid_image(self, filename: str) -> bool:
135
- if not os.path.isfile(filename):
147
+ @staticmethod
148
+ async def is_valid_image(filename: str) -> bool:
149
+ if not os.path.isfile(filename) or os.path.getsize(filename) == 0:
136
150
  return False
137
151
  if not check_jpeg:
138
152
  return True
@@ -46,7 +46,7 @@ class DetectorLogic():
46
46
 
47
47
  @abstractmethod
48
48
  def init(self):
49
- """Initialize the model. Note that `model_info` is available as `self.model_info`"""
49
+ """Called when a (new) model was loaded. Initialize the model. Model information available via `self.model_info`"""
50
50
 
51
51
  @abstractmethod
52
52
  def evaluate(self, image: np.ndarray) -> Detections:
@@ -295,6 +295,8 @@ class DetectorNode(Node):
295
295
  self.log.error('could not reload app')
296
296
 
297
297
  async def get_detections(self, raw_image: np.ndarray, camera_id: Optional[str], tags: List[str], autoupload: Optional[str] = None) -> Optional[Dict]:
298
+ """Note: raw_image is a numpy array of type uint8, but not in the correrct shape!
299
+ It can be converted e.g. using cv2.imdecode(raw_image, cv2.IMREAD_COLOR)"""
298
300
  loop = asyncio.get_event_loop()
299
301
  detections: Detections = await loop.run_in_executor(None, self.detector_logic.evaluate, raw_image)
300
302
 
@@ -1,5 +1,8 @@
1
+ import os
2
+ import shutil
3
+
1
4
  from learning_loop_node.data_classes import Context
2
- from learning_loop_node.data_exchanger import DataExchanger
5
+ from learning_loop_node.data_exchanger import DataExchanger, check_jpeg
3
6
  from learning_loop_node.globals import GLOBALS
4
7
 
5
8
  from . import test_helper
@@ -46,3 +49,23 @@ async def test_download_training_data(data_exchanger: DataExchanger):
46
49
  image_ids = await data_exchanger.fetch_image_ids()
47
50
  image_data = await data_exchanger.download_images_data(image_ids)
48
51
  assert len(image_data) == 3
52
+
53
+
54
+ async def test_removal_of_corrupted_images(data_exchanger: DataExchanger):
55
+ image_ids = await data_exchanger.fetch_image_ids()
56
+
57
+ shutil.rmtree('/tmp/img_folder', ignore_errors=True)
58
+ os.makedirs('/tmp/img_folder', exist_ok=True)
59
+ await data_exchanger.download_images(image_ids, '/tmp/img_folder')
60
+ num_images = len(os.listdir('/tmp/img_folder'))
61
+
62
+ # Generate two corrupted images
63
+ with open('/tmp/img_folder/c0.jpg', 'w') as f:
64
+ f.write('')
65
+ with open('/tmp/img_folder/c1.jpg', 'w') as f:
66
+ f.write('I am no image')
67
+
68
+ await data_exchanger.delete_corrupt_images('/tmp/img_folder')
69
+
70
+ assert len(os.listdir('/tmp/img_folder')) == num_images if check_jpeg else num_images - 1
71
+ shutil.rmtree('/tmp/img_folder', ignore_errors=True)
@@ -54,8 +54,8 @@ class TrainerLogic():
54
54
  self._training: Optional[Training] = None
55
55
  self._active_training_io: Optional[ActiveTrainingIO] = None
56
56
  self._node: Optional[TrainerNode] = None
57
- self.restart_after_training = bool(int(os.environ.get('RESTART_AFTER_TRAINING', '0')))
58
- self.keep_old_trainings = bool(int(os.environ.get('KEEP_OLD_TRAININGS', '0')))
57
+ self.restart_after_training = os.environ.get('RESTART_AFTER_TRAINING', 'FALSE').lower() in ['true', '1']
58
+ self.keep_old_trainings = os.environ.get('KEEP_OLD_TRAININGS', 'FALSE').lower() in ['true', '1']
59
59
  self.inference_batch_size = int(os.environ.get('INFERENCE_BATCH_SIZE', '10'))
60
60
  logging.info(f'INFERENCE_BATCH_SIZE: {self.inference_batch_size}')
61
61
 
@@ -335,7 +335,7 @@ class TrainerLogic():
335
335
  try:
336
336
  new_model_id = await self._upload_model_return_new_id(self.training.context)
337
337
  if new_model_id is None:
338
- raise Exception('could not upload model')
338
+ raise Exception('could not upload model - maybe training failed')
339
339
  assert new_model_id is not None, 'uploaded_model must be set'
340
340
  logging.info(f'successfully uploaded model and received new model id: {new_model_id}')
341
341
  self.training.model_id_for_detecting = new_model_id
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "learning_loop_node"
3
- version = "v0.8.6"
3
+ version = "v0.8.7"
4
4
  description = "Python Library for Nodes which connect to the Zauberzeug Learning Loop"
5
5
  authors = ["Zauberzeug GmbH <info@zauberzeug.com>"]
6
6
  license = "MIT"
@@ -9,12 +9,12 @@ repository = "https://github.com/zauberzeug/learning_loop_node"
9
9
 
10
10
  [tool.poetry.dependencies]
11
11
  python = "^3.8"
12
+ fastapi = ">=0.93,<1.0.0"
13
+ fastapi-socketio = "^0.0.10"
14
+ uvicorn = {extras = ["standard"], version = "^0.22.0"}
15
+ fastapi-utils = "^0.2.1"
12
16
  requests = "^2.25.1"
13
17
  python-socketio = "^5.7.2"
14
- fastapi-socketio = "^0.0.6"
15
- fastapi = "^0.70.1"
16
- uvicorn = "^0.13.3"
17
- fastapi-utils = "^0.2.1"
18
18
  simplejson = "^3.17.2"
19
19
  icecream = "^2.1.0"
20
20
  aiofiles = "^0.7.0"