As suggested in #449, perhaps blink and pulse should be implemented by setting .source rather than in a blink thread.
Also consider suggestion #397 - adding is_blinking property.
Would we _really_ need a .is_blinking property, or would it be sufficient to just check .source != None ?
Otherwise would we also get requests for .is_pulsing or .is_fading properties?
@martinohanlon what do you think?
I like the idea of using source internally to manage changes in value (i.e. blinking, fading), its self contained and can be implemented consistently across components.
I dont think an .is_blinking property is needed, it feels very specific with little reuse and as @lurch says where do you stop... If a user really needed to keep track of whether a component was blinking its an easy implementation in the calling program.
I dont think an
.is_blinking propertyis needed
Should #397 be closed then?
I'm happy with that :+1:
Let no one say I am not prepared to re-evaluate my views... ;)
Actually I was thinking of writing a helper (in the form of a decorator), that you could add to a generator function that would allow you to introspect the source function once the generator has started.
def smart_generator(fn):
class inner(object):
def __init__(self, *args, **kwargs):
self.func = wrapper
self.args = args
self.kwargs = kwargs
self.thread = None
def __iter__(self):
assert self.thread is None, 'smart_generator already iterating'
self.thread = threading.current_thread()
for v in fn(*self.args, **self.kwargs):
yield v
self.thread = None
def __repr__(self):
return '<smart_generator %s(%s) at 0x%08x on %s>' % (
fn.__name__,
', '.join(
([', '.join(repr(a) for a in self.args)] if self.args else []) +
([', '.join('%s=%r' % i for i in self.kwargs.items())] if self.kwargs else [])),
id(self),
self.thread)
@functools.wraps(fn)
def wrapper(*args, **kwargs):
return inner(*args, **kwargs)
return wrapper
@smart_generator
def foo(a, b, d=8, e=9, c=7):
'does things'
for x in range(5):
yield x
f = foo(1, '2', c='3', d=4)
print(f) # <smart_generator foo(1, '2', c='3', d=4) at 0xf78d9a8c>
assert f.func == foo
(latest copy at http://www.darkskies.za.net/~norman/scripts/gentest.py)
Then this allows a few things:
It many also be required to store current_thread on the smart_generator when it's active otherwise when _copy_values tries to set value, then it'll probably stop itself. The value setter shouldn't stop the thread if it's the thread currently iterating and setting the values.
Actually the more I think about this the original generator function should just be implemented as an iterable class (this would also allow parameters to be changed without replacing the event source - allowing for smoother transitions) The decorator is too much python magic.
Most helpful comment
I'm happy with that :+1: