async def test_ziplatest(assert_run, event_loop): with event_loop.assert_cleanup(): xs = stream.range(0, 5, 2, interval=2) ys = stream.range(1, 5, 2, interval=2) | pipe.delay(1) zs = stream.ziplatest(xs, ys, default="▲") await assert_run(zs, [(0, "▲"), (0, 1), (2, 1), (2, 3), (4, 3)]) assert event_loop.steps == [1, 1, 1, 1] with event_loop.assert_cleanup(): xs = stream.range(0, 5, 2, interval=2) ys = stream.range(1, 5, 2, interval=2) | pipe.delay(1) zs = stream.ziplatest(xs, ys, partial=False) await assert_run(zs, [(0, 1), (2, 1), (2, 3), (4, 3)]) assert event_loop.steps == [1, 1, 1, 1]
async def test_ziplatest(assert_run, event_loop): with event_loop.assert_cleanup(): xs = stream.range(0, 5, 2, interval=2) ys = stream.range(1, 5, 2, interval=2) | pipe.delay(1) zs = stream.ziplatest(xs, ys, default='▲') await assert_run(zs, [(0, '▲'), (0, 1), (2, 1), (2, 3), (4, 3)]) assert event_loop.steps == [1, 1, 1, 1] with event_loop.assert_cleanup(): xs = stream.range(0, 5, 2, interval=2) ys = stream.range(1, 5, 2, interval=2) | pipe.delay(1) zs = stream.ziplatest(xs, ys, partial=False) await assert_run(zs, [(0, 1), (2, 1), (2, 3), (4, 3)]) assert event_loop.steps == [1, 1, 1, 1]
async def input(ic, name): field = ic.md.input_fields[name] owner = ic.user restart = field['can_read'] while restart: restart = False src = [await arg_stream(ic, owner, pathlib.Path(field['name']))] if 'owner' in field['args']: src.append(await arg_stream(ic, ic.user, field['args']['owner'])) s = stream.ziplatest(*src, partial=False) last = None async with core.streamcontext(s) as streamer: async for i in streamer: if 'owner' in field['args']: if i[1] is None: continue o = i[1]['val'] if o.pk != owner.pk: owner = o restart = True break out = dict(type='input', id=field['name'], disabled=True) out['owner'] = None if ic.user == owner else owner.username out['val'] = '' if i[0] is None or i[0]['val'] is None else str( i[0]['val']) out['disabled'] = not (field['can_write'] is True or (field['can_write'] is None and out['owner'] is None)) if last == out: continue last = out if field['args']['type'] in ['file', 'files', 'select-user']: out['val'] = None if i[0] is not None and field['args']['type'] != i[0]['type']: logger.warning( f"field type error: {field['args']['type']} != {i[0]['type']}" ) yield out
async def from_streams(base_reader): ''' Asyncio coroutine task to read from all streams & detect and then execute the command based on the confirmation tap ''' try: # Wait for half a second before processing the events await asyncio.sleep(0.5) # Grab the touchpad to draw gesture until this coroutine is cancelled base_reader.grab() # Init all the readers x_movement_reader = Reader(base_reader) y_movement_reader = Reader(base_reader) tap_detector_reader = Reader(base_reader) # Reload gesture command map reload_config() # Store the received coordinates coordinates_set = [] start_time = end_time = 0 # Zip the X and Y axis events for clarity. # It is processed separtely though when sanitizing the input zip_xy = ziplatest(y_movement(x_movement_reader), x_movement(y_movement_reader)) # Read the tap events as well to indicate # the start and end of gesture drawing merge_tap_xy = merge(zip_xy, tap_detector(tap_detector_reader)) async with merge_tap_xy.stream() as merged: async for event in merged: # The zip_xy events are in the form of tuples # while the tap events are evdev event objects if not isinstance(event, tuple): if event.value == 1: start_time = event.timestamp() elif event.value == 0: end_time = event.timestamp() # If the draw is too short, ignore and reset # cause it's not meaningful if (end_time - start_time) < 0.3: coordinates_set = [] continue detected_gesture = sanitize_and_notify(coordinates_set) # print(f'Detected gesture :- {detected_gesture}') coordinates_set = [] if detected_gesture is None: continue # If gesture detected then wait for a confirmation tap tapped, event = await confirmation_tap(base_reader) if tapped: notify(f"Confirmed. Running- {detected_gesture}") execute_command(detected_gesture) else: notify("Clearing gestures") else: coordinates_set.append(event) except asyncio.CancelledError: # Exit all readers from the base_reader once they are done x_movement_reader.exit() y_movement_reader.exit() tap_detector_reader.exit() # Ungrab and yield control of touchpad to the user base_reader.ungrab()
async def pprint(ic, args): a = [await my_stream.arg_stream(ic, ic.user, arg) for arg in args] source = stream.ziplatest(*a, partial=False) async with core.streamcontext(source) as streamer: async for item in streamer: keys = list() vals = dict() info = list() for i, val in enumerate(item): if val is None: continue if val.get('pk') is not None: info.append(await get_history(val['pk'])) if val['type'] is None: pass elif val['type'] in ['html']: if None not in keys: keys.insert(0, None) vals[None] = [None] * len(item) vals[None][i] = val['val'] elif val['type'] in [ 'int', 'float', 'str', 'text', 'textarea', 'files', 'stdout', 'error' ]: if None not in keys: keys.insert(0, None) vals[None] = [None] * len(item) vals[None][i] = render_to_string( f"wiki/plugins/inputs/pprint.html", context=val) elif val['type'] == 'user-list': for u, v in val['val'].items(): if u not in keys: keys.append(u) vals[u] = [None] * len(item) vals[u][i] = render_to_string( f"wiki/plugins/inputs/pprint.html", context=v) else: logger.error(val) if len(keys) == 0: yield None continue if len(keys) == 1 and keys[0] is None: html = " ".join(vals[keys[0]]) else: html = "<table>" for k in keys: html += "<tr><th>" if k is None: html += " " elif isinstance(k, User): html += f"{k.first_name} {k.last_name}" else: html += str(k) html += "</th>" for v in vals[k]: html += f"<td>{v!s}</td>" html += "</tr>" html += "</table>" if info: html = render_to_string("wiki/plugins/inputs/pprint_full.html", context={ 'html': html, 'info': "".join(info) }) yield {'type': 'html', 'val': html}
async def get(ic, args): if len(args) < 2: yield { 'type': 'error', 'val': "⚠ get() requires at least 2 arguments ⚠" } return if not isinstance(args[0], pathlib.Path): yield {'type': 'error', 'val': "⚠ get() first argument must be path ⚠"} return path = misc.normpath(ic, args[0]) md = await misc.get_markdown_factory().get_markdown(path.parent, ic.user) if md is None: yield { 'type': 'error', 'val': f"⚠ get() article {path.parent} does not exist ⚠" } return field = md.input_fields.get(path.name) if field is None: yield { 'type': 'error', 'val': f"⚠ get() article {path.name} does not exist ⚠" } q = Q(article=md.article) & Q(name=field['name']) if field['can_write'] in [False, None]: q &= Q(owner=ic.user) users = set() while True: src = [my_stream.read_field(ic, x, path) for x in users] src += [await my_stream.arg_stream(ic, ic.user, x) for x in args[1:]] if len(users) == 0: src += [my_stream.read_field(ic, ic.user, path)] s = stream.ziplatest(*src, partial=False) async with core.streamcontext(s) as streamer: async for i in streamer: users_new, is_list = await db_get_input_users( md, field, q, (i[len(users):])[:len(args[1:])]) if users_new is None: continue if set([u.pk for u in users]) != set([u.pk for u in users_new]): users = users_new break if is_list: yield { 'type': 'user-list', 'val': dict(zip([u.username for u in users], i[:len(users)])), } elif len(users) > 0: yield i[0] else: yield {'type': 'None', 'val': None} else: return