Skip to content

Commit e76a46f

Browse files
committed
Add background processing (redux)
1 parent 7f897e4 commit e76a46f

File tree

3 files changed

+55
-12
lines changed

3 files changed

+55
-12
lines changed

stage7.1_background_proc/pycasa/model/image_folder.py

Lines changed: 32 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,10 @@
77

88
# ETS imports
99
from traits.api import (
10-
Directory, Event, HasStrictTraits, Instance, List, observe,
10+
Bool, Directory, Event, HasStrictTraits, Instance, List, observe, Property
11+
)
12+
from traits_futures.api import (
13+
CallFuture, submit_call, TraitsExecutor
1114
)
1215

1316
# Local imports
@@ -28,6 +31,12 @@ class ImageFolder(HasStrictTraits):
2831

2932
data_updated = Event
3033

34+
traits_executor = Instance(TraitsExecutor)
35+
36+
future = Instance(CallFuture)
37+
38+
executor_idle = Property(Bool, depends_on="future.done")
39+
3140
def __init__(self, **traits):
3241
# Don't forget this!
3342
super(ImageFolder, self).__init__(**traits)
@@ -62,8 +71,25 @@ def _create_metadata_df(self):
6271
for img in self.images
6372
])
6473

65-
def compute_num_faces(self, **kwargs):
66-
for i, image in enumerate(self.images):
67-
faces = image.detect_faces(**kwargs)
68-
self.data[NUM_FACE_COL].iat[i] = len(faces)
69-
self.data_updated = True
74+
def compute_num_faces_background(self, **kwargs):
75+
self.future = submit_call(
76+
self.traits_executor,
77+
self._compute_num_faces,
78+
**kwargs
79+
)
80+
81+
def _compute_num_faces(self, **kwargs):
82+
return [
83+
len(img_file.detect_faces(**kwargs))
84+
for img_file in self.images
85+
]
86+
87+
@observe("future:done")
88+
def _update_data(self, event):
89+
num_faces_all_images = self.future.result
90+
for idx, num_faces in enumerate(num_faces_all_images):
91+
self.data[NUM_FACE_COL].iat[idx] = num_faces
92+
self.data_updated = True
93+
94+
def _get_executor_idle(self):
95+
return self.future is None or self.future.done

stage7.1_background_proc/pycasa/ui/image_folder_view.py

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -68,8 +68,7 @@ def traits_view(self):
6868
visible_when="view_filter_controls",
6969
),
7070
Item("filtered_data",
71-
editor=DataFrameEditor(columns=DISPLAYED_COLUMNS,
72-
update="data_updated"),
71+
editor=DataFrameEditor(columns=DISPLAYED_COLUMNS),
7372
show_label=False, visible_when="len(model.data) > 0"),
7473
HGroup(
7574
Spring(),
@@ -79,8 +78,11 @@ def traits_view(self):
7978
),
8079
HGroup(
8180
Spring(),
82-
Item("scan", show_label=False,
83-
enabled_when="len(model.data) > 0"),
81+
Item(
82+
"scan",
83+
show_label=False,
84+
enabled_when="len(model.data) > 0 and model.executor_idle"
85+
),
8486
Spring(),
8587
),
8688
)
@@ -90,8 +92,12 @@ def traits_view(self):
9092

9193
@observe("scan")
9294
def scan_for_faces(self, event):
93-
self.model.compute_num_faces()
95+
self.model.compute_num_faces_background()
96+
97+
@observe("model:data_updated")
98+
def _update_all_data(self, event):
9499
self.all_data.update(self.model.data)
100+
self.update_filtered_data(None)
95101

96102
@observe("selected_years")
97103
def update_years(self, event):

stage7.1_background_proc/pycasa/ui/tasks/pycasa_task.py

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
# ETS imports
55
from traits.api import Instance
6+
from traits_futures.api import TraitsExecutor
67
from pyface.api import error, ImageResource
78
from pyface.action.api import StatusBarManager
89
from pyface.tasks.api import PaneItem, SplitEditorAreaPane, Task, TaskLayout
@@ -27,6 +28,9 @@ class PycasaTask(Task):
2728
#: The human-readable name of the task.
2829
name = "Pycasa"
2930

31+
#: An executor for background tasks
32+
traits_executor = Instance(TraitsExecutor, ())
33+
3034
central_pane = Instance(SplitEditorAreaPane)
3135

3236
# Task interface ----------------------------------------------------------
@@ -57,14 +61,21 @@ def open_in_central_pane(self, filepath):
5761
obj = ImageFile(filepath=filepath)
5862
self.central_pane.edit(obj, factory=ImageFileEditor)
5963
elif file_ext == "":
60-
obj = ImageFolder(directory=filepath)
64+
obj = ImageFolder(
65+
directory=filepath,
66+
traits_executor=self.traits_executor
67+
)
6168
self.central_pane.edit(obj, factory=ImageFolderEditor)
6269
else:
6370
print("Unsupported file format: {}".format(file_ext))
6471
obj = None
6572

6673
return obj
6774

75+
def prepare_destroy(self):
76+
self.traits_executor.shutdown()
77+
return super().prepare_destroy()
78+
6879
# Menu action methods -----------------------------------------------------
6980

7081
def request_open_new_path(self):

0 commit comments

Comments
 (0)