Skip to content

Commit 14f4fc3

Browse files
committed
Ensurer
A type of decorator that can make sure conditions are met before executing a setter, getter, or action
1 parent cb3947e commit 14f4fc3

File tree

2 files changed

+53
-1
lines changed

2 files changed

+53
-1
lines changed

puzzlepiece/piece.py

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
from pyqtgraph.Qt import QtWidgets
2+
from functools import wraps
23
import math
34

45
class Piece(QtWidgets.QGroupBox):
@@ -150,3 +151,54 @@ def elevate(self):
150151
"""
151152
if self.folder is not None:
152153
self.folder.setCurrentWidget(self)
154+
155+
156+
def ensurer(ensure_function):
157+
"""
158+
An ensurer is a decorator that can be placed on getters, setters, and actions, and it will run
159+
ahead of these functions. The intended behaviour is performing checks ahead of running the
160+
function - for example checking if a laser is connected ahead of trying to set its power.
161+
This way one ensurer can be written and used in multiple places easily.
162+
163+
For example, an ensurer can be defined as a Piece's method (in the main body of the class)::
164+
165+
@puzzlepiece.piece.ensurer
166+
def _ensure_connected(self):
167+
if not self.params['connected'].get_value():
168+
raise Exception('Laser not connected')
169+
170+
This can then be used when defining a param (below the param-defining decorator)::
171+
172+
@puzzlepiece.param.spinbox(self, 'power', 0.)
173+
@self._ensure_connected
174+
def power(self, value):
175+
self.laser.set_power(value)
176+
177+
@puzzlepiece.param.spinbox(self, 'wavelength', 0.)
178+
@self._ensure_connected
179+
def wavelength(self, value):
180+
self.laser.set_wavelength(value)
181+
182+
It can also be called directly if preferred::
183+
184+
self._ensure_connected()
185+
"""
186+
# Decorating a class method with ensure makes it a decorator.
187+
# Here we create this decorator and return it.
188+
@wraps(ensure_function)
189+
def ensure_decorator(self, main_function=None):
190+
if main_function is not None:
191+
# This means ensure_decorator was used as a decorator, and
192+
# main_function is the function being decorated. We therefore
193+
# wrap it with the ensuring functionality and return it
194+
@wraps(main_function)
195+
def wrapped_main(self, *args, **kwargs):
196+
ensure_function(self)
197+
return main_function(self, *args, **kwargs)
198+
return wrapped_main
199+
else:
200+
# If main_function is None, ensure_decorator has been called
201+
# directly instead of being used as a decorator, so we
202+
# just execute ensure_function
203+
ensure_function(self)
204+
return ensure_decorator

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
44

55
[project]
66
name = "puzzlepiece"
7-
version = "0.5.0"
7+
version = "0.6.0"
88
authors = [
99
{ name="Jakub Dranczewski", email="jakub.dranczewski@gmail.com" },
1010
]

0 commit comments

Comments
 (0)