Skip to content

0.4.1 — Signal writes and clearing

Latest

Choose a tag to compare

@github-actions github-actions released this 30 Aug 15:39

Changed

  • A Signal seeded with nothing is now reported instead of built dead. A signal takes its type from the value you create it with, so bs.Signal(None) inferred the type of None itself and could never hold anything else: every later set() raised Expected NoneType, got str, at an arbitrary write, with a message naming neither the mistake nor the fix. It now raises where the mistake was made. This reaches map() too, which types the derived signal from the transform's first result: a transform that returns None for the value it is first called with now raises there, instead of building the same dead signal and failing somewhere else later. Check this when you upgrade if you seed a signal from data that can be missing, or map() a transform that can return None. Pass allow_empty=True with the type named, as in bs.Signal(None, allow_empty=True, dtype=date), when the value can be empty; give the transform a value for every input, as in due.map(lambda d: d.strftime("%b %d") if d else ""), when it cannot. Signals seeded with a value, and map() over a transform that returns one, are unaffected. (#481)

Fixed

  • TextArea.insert() and append() no longer write alongside the placeholder. On a TextArea built with placeholder= and still showing it — a log or output pane you also write to from code is the ordinary case — text written through either method was added to the placeholder instead of replacing it: the screen read Type something herewritten by code, value went on returning '', and on_input and on_change stopped firing. The silence was permanent rather than momentary, so every later edit the user made went unannounced too and value stayed empty for the rest of the field's life. Both methods now drop the placeholder first, as assigning to value always did. A TextArea with no placeholder, or one whose placeholder is already gone, is unaffected, and so is CodeEditor, which has no placeholder to write onto. (#491)
  • A field's value now follows a write to its bound Signal. Writing to a signal bound to a TextField, PasswordField, PathField or SpinnerField moved what the field displayed but not what value reported — the two disagreed about the same state, silently, until the user focused and left the field. value now follows a write your code made, including clear() on a signal declared allow_empty=True, while still reporting the last committed value while the user is typing, which is unchanged. A programmatic write made while that field currently has keyboard focus is indistinguishable from typing and still waits for the commit. TextArea, CodeEditor, NumberField, DateField, TimeField and Select already behaved this way and are untouched. Check this when you upgrade if you handle on_change on a field your code writes through a bound signal. The change event that used to arrive a focus cycle late now moves with value: it no longer fires when the user changes nothing, and it now fires when the user types the field back to the text it held before your write. Writing a field through field.value, which is how Form.set() writes, is unaffected, and so is every change the user makes. (#482)
  • TextArea and CodeEditor now honor a Signal.clear(). Clearing a signal bound to either widget left the old text on screen, so the signal read empty and the widget did not; the other seven field widgets that take a signal all honored it. Whether it worked depended on something unrelated to the widget — the same clear was honored or ignored according to what else in your application happened to be bound to that signal. Since 0.4.0 wired these two in both directions, the next edit to a widget left stale this way also pushed its old text back and silently un-emptied the signal. Clearing the widget itself, with widget.clear(), was always correct and is unchanged. (#490)
  • A Signal a text field made for you can now be cleared. TextField, PasswordField, PathField and SpinnerField hand you a Signal through .signal whether or not you bound one, and clearing that signal raised Expected str, got NoneType, telling you to pass allow_empty=True to a Signal() call you never wrote — advice no edit of yours could follow. Those four now allow empty, so field.signal.clear() empties the field and the signal reads '', the empty of a value that lives in the widget's own variable. A signal you built yourself is unchanged, and so is field.clear(), which always worked. Slider and Checkbox still refuse, and still should: a slider always has a position and a checkbox always has a state, so neither has an empty value its variable could hold. The refusal now names setting a value as the way out, rather than only a constructor you may not own. (#484)

What's Changed

  • fix(core): signal no longer guards None when applying text value to field by @israel-dryer in #502
  • fix(fields): a field's value follows a programmatic signal write (#482) by @israel-dryer in #503
  • fix(signal): a signal seeded with None, no dtype and without allowing… by @israel-dryer in #504
  • fix(textarea): drop the placeholder before insert() and append() write by @israel-dryer in #505
  • Fix/widget owned signal clear 484 by @israel-dryer in #506

Full Changelog: v0.4.0...v0.4.1