Skip to content

Commit 97440f7

Browse files
committed
reformat with ruff
1 parent 5cb856e commit 97440f7

9 files changed

Lines changed: 59 additions & 132 deletions

File tree

segmenter/main.py

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -63,9 +63,7 @@ def handler_stop_signals(signum, _):
6363

6464
if __name__ == "__main__":
6565
logger.info("Welcome!")
66-
logger.info(
67-
"Initialising signals handling and sanitizing the directories (step 1/2)"
68-
)
66+
logger.info("Initialising signals handling and sanitizing the directories (step 1/2)")
6967
signal.signal(signal.SIGINT, handler_stop_signals)
7068
signal.signal(signal.SIGTERM, handler_stop_signals)
7169

@@ -82,9 +80,7 @@ def handler_stop_signals(signum, _):
8280
# Starts the segmenter process
8381
logger.info("Starting the segmenter control process (step 2/2)")
8482
try:
85-
segmenter_thread = planktoscope.segmenter.SegmenterProcess(
86-
shutdown_event, "/home/pi/data"
87-
)
83+
segmenter_thread = planktoscope.segmenter.SegmenterProcess(shutdown_event, "/home/pi/data")
8884
except Exception:
8985
logger.error("The segmenter control process could not be started")
9086
segmenter_thread = None

segmenter/planktoscope/__init__.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,17 @@
11
# Copyright (C) 2021 Romain Bazile
2-
#
2+
#
33
# This file is part of the PlanktoScope software.
4-
#
4+
#
55
# PlanktoScope is free software: you can redistribute it and/or modify
66
# it under the terms of the GNU General Public License as published by
77
# the Free Software Foundation, either version 3 of the License, or
88
# (at your option) any later version.
9-
#
9+
#
1010
# PlanktoScope is distributed in the hope that it will be useful,
1111
# but WITHOUT ANY WARRANTY; without even the implied warranty of
1212
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1313
# GNU General Public License for more details.
14-
#
14+
#
1515
# You should have received a copy of the GNU General Public License
1616
# along with PlanktoScope. If not, see <http://www.gnu.org/licenses/>.
1717

segmenter/planktoscope/identity.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
# TODO: keep this as the default path, but allow changing it with an environment variable
2-
MACHINE_NAME_PATH = '/run/machine-name'
2+
MACHINE_NAME_PATH = "/run/machine-name"
3+
34

45
def load_machine_name(path=MACHINE_NAME_PATH):
56
"""Returns the machine name specified by the file at MACHINE_NAMEPATH.
67
78
Returns:
89
str: the machine name stored in the file at the path.
910
"""
10-
with open(path, encoding='utf-8') as file:
11+
with open(path, encoding="utf-8") as file:
1112
return file.readline().strip()

segmenter/planktoscope/mqtt.py

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -129,9 +129,7 @@ def on_connect(self, client, userdata, flags, rc):
129129
"5: Connection refused - not authorised",
130130
]
131131
# Print when connected
132-
logger.success(
133-
f"{self.name} connected to {self.hostname}:{self.port}! - {reason[rc]}"
134-
)
132+
logger.success(f"{self.name} connected to {self.hostname}:{self.port}! - {reason[rc]}")
135133
# When connected, run subscribe()
136134
self.client.subscribe(self.topic)
137135

@@ -140,9 +138,7 @@ def on_connect(self, client, userdata, flags, rc):
140138
def on_subscribe(self, client, obj, mid, granted_qos):
141139
# Print when subscribed
142140
# TODO Fix bug when this is called outside of this init function (for example when the imager subscribe to status/pump)
143-
logger.success(
144-
f"{self.name} subscribed to {self.topic}! - mid:{mid} qos:{granted_qos}"
145-
)
141+
logger.success(f"{self.name} subscribed to {self.topic}! - mid:{mid} qos:{granted_qos}")
146142

147143
# Run this command when Node-RED is sending a message on the subscribed topic
148144
@logger.catch
@@ -163,9 +159,7 @@ def on_message(self, client, userdata, msg):
163159
@logger.catch
164160
def on_disconnect(self, client, userdata, rc):
165161
if rc != 0:
166-
logger.error(
167-
f"Connection to the MQTT server is unexpectedly lost by {self.name}"
168-
)
162+
logger.error(f"Connection to the MQTT server is unexpectedly lost by {self.name}")
169163
else:
170164
logger.warning(f"Connection to the MQTT server is closed by {self.name}")
171165
# TODO for now, we just log the disconnection, we need to evaluate what to do

segmenter/planktoscope/segmenter/__init__.py

Lines changed: 29 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -69,13 +69,9 @@
6969
"SEGMENTER_PIPELINE_SUBTRACT_CONSECUTIVE_MASKS", "False"
7070
).lower() in ("true", "1", "t")
7171
if SUBTRACT_CONSECUTIVE_MASKS:
72-
logger.info(
73-
"The segmentation pipeline will subtract masks between consecutive raw frames!"
74-
)
72+
logger.info("The segmentation pipeline will subtract masks between consecutive raw frames!")
7573
else:
76-
logger.info(
77-
"The segmentation pipeline will NOT subtract masks between consecutive raw frames!"
78-
)
74+
logger.info("The segmentation pipeline will NOT subtract masks between consecutive raw frames!")
7975

8076

8177
################################################################################
@@ -170,9 +166,7 @@ def _calculate_flat(self, images_list, images_number, images_root_path):
170166

171167
# make sure image number is smaller than image list
172168
if images_number > len(images_list):
173-
logger.error(
174-
"The image number can't be bigger than the length of the provided list!"
175-
)
169+
logger.error("The image number can't be bigger than the length of the provided list!")
176170
images_number = len(images_list)
177171

178172
logger.debug(f"Opening {images_number} images: {images_list[:images_number]}")
@@ -230,9 +224,7 @@ def _open_and_apply_flat(self, filepath, flat_ref):
230224
# logger.debug(resource.getrusage(resource.RUSAGE_SELF).ru_maxrss)
231225
# logger.debug(time.monotonic() - start)
232226

233-
image = skimage.exposure.rescale_intensity(
234-
image, in_range=(0, 1.04), out_range="uint8"
235-
)
227+
image = skimage.exposure.rescale_intensity(image, in_range=(0, 1.04), out_range="uint8")
236228
# logger.debug(resource.getrusage(resource.RUSAGE_SELF).ru_maxrss)
237229
logger.debug(time.monotonic() - start)
238230
logger.success("Flat calc")
@@ -433,9 +425,7 @@ def pipe_full(conn):
433425
return len(w) == 0
434426

435427
img_object = io.BytesIO()
436-
PIL.Image.fromarray(cv2.cvtColor(img, cv2.COLOR_BGR2RGB)).save(
437-
img_object, format="JPEG"
438-
)
428+
PIL.Image.fromarray(cv2.cvtColor(img, cv2.COLOR_BGR2RGB)).save(img_object, format="JPEG")
439429
logger.debug("Sending the object in the pipe!")
440430
if not pipe_full(planktoscope.segmenter.streamer.sender):
441431
planktoscope.segmenter.streamer.sender.send(img_object)
@@ -484,9 +474,7 @@ def __augment_slice(dim_slice, max_dims, size=10):
484474

485475
labels, nlabels = skimage.measure.label(mask, return_num=True)
486476
regionprops = skimage.measure.regionprops(labels)
487-
regionprops_filtered = [
488-
region for region in regionprops if region.filled_area >= min_area
489-
]
477+
regionprops_filtered = [region for region in regionprops if region.filled_area >= min_area]
490478
object_number = len(regionprops_filtered)
491479
logger.debug(f"Found {nlabels} labels, or {object_number} after size filtering")
492480

@@ -526,9 +514,7 @@ def __augment_slice(dim_slice, max_dims, size=10):
526514
# publish metrics about the found object
527515
self.segmenter_client.client.publish(
528516
"status/segmenter/metric",
529-
json.dumps(
530-
object_metadata, cls=planktoscope.segmenter.encoder.NpEncoder
531-
),
517+
json.dumps(object_metadata, cls=planktoscope.segmenter.encoder.NpEncoder),
532518
)
533519

534520
if "objects" in self.__global_metadata:
@@ -578,9 +564,7 @@ def __augment_slice(dim_slice, max_dims, size=10):
578564

579565
def _pipe(self, ecotaxa_export):
580566
logger.info("Finding images")
581-
images_list = self._find_files(
582-
self.__working_path, ("JPG", "jpg", "JPEG", "jpeg")
583-
)
567+
images_list = self._find_files(self.__working_path, ("JPG", "jpg", "JPEG", "jpeg"))
584568

585569
logger.debug(f"Images found are {images_list}")
586570
images_count = len(images_list)
@@ -606,9 +590,7 @@ def _pipe(self, ecotaxa_export):
606590
"status/segmenter", '{"status":"Calculating flat"}'
607591
)
608592
if images_count < 10:
609-
self._calculate_flat(
610-
images_list[0:images_count], images_count, self.__working_path
611-
)
593+
self._calculate_flat(images_list[0:images_count], images_count, self.__working_path)
612594
else:
613595
self._calculate_flat(images_list[0:10], 10, self.__working_path)
614596

@@ -627,7 +609,7 @@ def _pipe(self, ecotaxa_export):
627609
# Publish the object_id to via MQTT to Node-RED
628610
self.segmenter_client.client.publish(
629611
"status/segmenter",
630-
f'{{"status":"Segmenting image {filename}, image {i+1}/{images_count}"}}',
612+
f'{{"status":"Segmenting image {filename}, image {i + 1}/{images_count}"}}',
631613
)
632614

633615
# we recalculate the flat if the heuristics detected we should
@@ -638,13 +620,9 @@ def _pipe(self, ecotaxa_export):
638620
flat = self._calculate_flat(images_list, 10, self.__working_path)
639621
elif i > (len(images_list) - 11):
640622
# We are too close to the end of the list, take the previous 10 images instead of the next 10
641-
flat = self._calculate_flat(
642-
images_list[i - 10 : i], 10, self.__working_path
643-
)
623+
flat = self._calculate_flat(images_list[i - 10 : i], 10, self.__working_path)
644624
else:
645-
flat = self._calculate_flat(
646-
images_list[i : i + 10], 10, self.__working_path
647-
)
625+
flat = self._calculate_flat(images_list[i : i + 10], 10, self.__working_path)
648626
if self.__save_debug_img:
649627
self._save_image(
650628
self.__flat,
@@ -667,7 +645,7 @@ def _pipe(self, ecotaxa_export):
667645
os.makedirs(self.__working_debug_path)
668646

669647
start = time.monotonic()
670-
logger.info(f"Starting work on {name}, image {i+1}/{images_count}")
648+
logger.info(f"Starting work on {name}, image {i + 1}/{images_count}")
671649

672650
img = self._open_and_apply_flat(
673651
os.path.join(self.__working_path, images_list[i]), self.__flat
@@ -713,7 +691,7 @@ def _pipe(self, ecotaxa_export):
713691

714692
total_duration = (time.monotonic() - first_start) / 60
715693
logger.success(
716-
f"{images_count} images done in {total_duration} minutes, or an average of {average_time}s per image or {total_duration*60/images_count}s per image"
694+
f"{images_count} images done in {total_duration} minutes, or an average of {average_time}s per image or {total_duration * 60 / images_count}s per image"
717695
)
718696
logger.success(
719697
f"We also found {total_objects} objects, or an average of {total_objects / (total_duration * 60)}objects per second"
@@ -733,9 +711,7 @@ def _pipe(self, ecotaxa_export):
733711
else:
734712
logger.info("There are no objects to export")
735713
else:
736-
logger.info(
737-
"We are not creating the ecotaxa output archive for this folder"
738-
)
714+
logger.info("We are not creating the ecotaxa output archive for this folder")
739715

740716
# cleanup
741717
# we're done free some mem
@@ -781,13 +757,9 @@ def segment_list(self, path_list: list, force=False, ecotaxa_export=True):
781757
if os.path.exists(os.path.join(path, "metadata.json")):
782758
# The file exists, let's check if we force or not
783759
# we also need to check for the presence of done.txt in each folder
784-
logger.debug(
785-
f"{path}: Checking for the presence of done.txt or forcing({force})"
786-
)
760+
logger.debug(f"{path}: Checking for the presence of done.txt or forcing({force})")
787761
if os.path.exists(os.path.join(path, "done.txt")) and not force:
788-
logger.debug(
789-
f"Moving to the next folder, {path} has already been segmented"
790-
)
762+
logger.debug(f"Moving to the next folder, {path} has already been segmented")
791763
else:
792764
# forcing, let's gooooo
793765
try:
@@ -799,9 +771,7 @@ def segment_list(self, path_list: list, force=False, ecotaxa_export=True):
799771
logger.debug(f"Moving to the next folder, {path} has no metadata.json")
800772
if exception is None:
801773
# Publish the status "Done" to via MQTT to Node-RED
802-
self.segmenter_client.client.publish(
803-
"status/segmenter", '{"status":"Done"}'
804-
)
774+
self.segmenter_client.client.publish("status/segmenter", '{"status":"Done"}')
805775
else:
806776
self.segmenter_client.client.publish(
807777
"status/segmenter",
@@ -933,11 +903,7 @@ def treat_message(self):
933903
# {"action":"segment"}
934904
if "settings" in last_message:
935905
# force rework of already done folder
936-
force = (
937-
last_message["settings"]["force"]
938-
if "force" in last_message
939-
else False
940-
)
906+
force = last_message["settings"]["force"] if "force" in last_message else False
941907

942908
# parse folders recursively starting from the given parameter
943909
recursive = (
@@ -948,9 +914,7 @@ def treat_message(self):
948914

949915
# generate ecotaxa output archive
950916
ecotaxa_export = (
951-
last_message["settings"]["ecotaxa"]
952-
if "ecotaxa" in last_message
953-
else True
917+
last_message["settings"]["ecotaxa"] if "ecotaxa" in last_message else True
954918
)
955919

956920
if "keep" in last_message["settings"]:
@@ -965,9 +929,7 @@ def treat_message(self):
965929
path = last_message["path"] if "path" in last_message else None
966930

967931
# Publish the status "Started" to via MQTT to Node-RED
968-
self.segmenter_client.client.publish(
969-
"status/segmenter", '{"status":"Started"}'
970-
)
932+
self.segmenter_client.client.publish("status/segmenter", '{"status":"Started"}')
971933
if path:
972934
if recursive:
973935
self.segment_all(path, force, ecotaxa_export)
@@ -980,34 +942,24 @@ def treat_message(self):
980942
logger.info("The segmentation has been interrupted.")
981943

982944
# Publish the status "Interrupted" to via MQTT to Node-RED
983-
self.segmenter_client.client.publish(
984-
"status/segmenter", '{"status":"Interrupted"}'
985-
)
945+
self.segmenter_client.client.publish("status/segmenter", '{"status":"Interrupted"}')
986946

987947
elif last_message["action"] == "update_config":
988-
logger.error(
989-
"We can't update the configuration while we are segmenting."
990-
)
948+
logger.error("We can't update the configuration while we are segmenting.")
991949

992950
# Publish the status "Interrupted" to via MQTT to Node-RED
993-
self.segmenter_client.client.publish(
994-
"status/segmenter", '{"status":"Busy"}'
995-
)
951+
self.segmenter_client.client.publish("status/segmenter", '{"status":"Busy"}')
996952

997953
elif last_message["action"] != "":
998-
logger.warning(
999-
f"We did not understand the received request {last_message}"
1000-
)
954+
logger.warning(f"We did not understand the received request {last_message}")
1001955

1002956
################################################################################
1003957
# While loop for capturing commands from Node-RED
1004958
################################################################################
1005959
@logger.catch
1006960
def run(self):
1007961
"""This is the function that needs to be started to create a thread"""
1008-
logger.info(
1009-
f"The segmenter control thread has been started in process {os.getpid()}"
1010-
)
962+
logger.info(f"The segmenter control thread has been started in process {os.getpid()}")
1011963

1012964
# MQTT Service connection
1013965
self.segmenter_client = planktoscope.mqtt.MQTT_Client(
@@ -1021,20 +973,14 @@ def run(self):
1021973
address = ("", 8001)
1022974
fps = 0.5
1023975
refresh_delay = 3 # was 1/fps
1024-
handler = functools.partial(
1025-
planktoscope.segmenter.streamer.StreamingHandler, refresh_delay
1026-
)
976+
handler = functools.partial(planktoscope.segmenter.streamer.StreamingHandler, refresh_delay)
1027977
try:
1028978
server = planktoscope.segmenter.streamer.StreamingServer(address, handler)
1029979
except Exception as e:
1030-
logger.exception(
1031-
f"An exception has occurred when starting up the segmenter: {e}"
1032-
)
980+
logger.exception(f"An exception has occurred when starting up the segmenter: {e}")
1033981
raise e
1034982

1035-
self.streaming_thread = threading.Thread(
1036-
target=server.serve_forever, daemon=True
1037-
)
983+
self.streaming_thread = threading.Thread(target=server.serve_forever, daemon=True)
1038984
# start streaming only when needed
1039985
self.streaming_thread.start()
1040986

segmenter/planktoscope/segmenter/ecotaxa.py

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -240,7 +240,7 @@ def ecotaxa_export(archive_filepath, metadata, image_base_path, keep_files=False
240240
# sometimes the camera resolution is not exported as string
241241
if not isinstance(metadata["acq_camera_resolution"], str):
242242
metadata["acq_camera_resolution"] = (
243-
f'{metadata["acq_camera_resolution"][0]}x{metadata["acq_camera_resolution"][1]}'
243+
f"{metadata['acq_camera_resolution'][0]}x{metadata['acq_camera_resolution'][1]}"
244244
)
245245

246246
# let's go!
@@ -277,14 +277,10 @@ def ecotaxa_export(archive_filepath, metadata, image_base_path, keep_files=False
277277
# add the tsv to the archive
278278
archive.writestr(
279279
tsv_filename,
280-
io.BytesIO(
281-
tsv_content.to_csv(sep="\t", encoding="utf-8", index=False).encode()
282-
).read(),
280+
io.BytesIO(tsv_content.to_csv(sep="\t", encoding="utf-8", index=False).encode()).read(),
283281
)
284282
if keep_files:
285283
tsv_file = os.path.join(image_base_path, tsv_filename)
286-
tsv_content.to_csv(
287-
path_or_buf=tsv_file, sep="\t", encoding="utf-8", index=False
288-
)
284+
tsv_content.to_csv(path_or_buf=tsv_file, sep="\t", encoding="utf-8", index=False)
289285
logger.success("Ecotaxa archive is ready!")
290286
return 1

0 commit comments

Comments
 (0)