We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
ToggleButton can get released with allow_no_selection=False
Ohai buddiez, I hope you're all doing goodie ^__^

I found a new bug probably due to "always_release" on ButtonBehavior having been changed recently:
`Changed in version 1.9.2: The default value is now False.`

Take the following example:
https://gist.github.com/42e02d13c31a6504b57d5cd3ac23a460

If you try to press a button, then release outside of it, its state will be "normal", even though it should remain "down".

I have made a small change to ButtonBehavior which adds an event "on_release_outside" and makes it set the state to normal by default, and overrode it in ToggleButtonBehavior to do nothing instead.

Incoming PR, so please give feedback! (EDIT: See #4594 )

Thanks for reading, see you around buddiez bliblibli ^__^


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `kivy/uix/behaviors/button.py`
Content:
```
1 '''
2 Button Behavior
3 ===============
4 
5 The :class:`~kivy.uix.behaviors.button.ButtonBehavior`
6 `mixin <https://en.wikipedia.org/wiki/Mixin>`_ class provides
7 :class:`~kivy.uix.button.Button` behavior. You can combine this class with
8 other widgets, such as an :class:`~kivy.uix.image.Image`, to provide
9 alternative buttons that preserve Kivy button behavior.
10 
11 For an overview of behaviors, please refer to the :mod:`~kivy.uix.behaviors`
12 documentation.
13 
14 Example
15 -------
16 
17 The following example adds button behavior to an image to make a checkbox that
18 behaves like a button::
19 
20     from kivy.app import App
21     from kivy.uix.image import Image
22     from kivy.uix.behaviors import ButtonBehavior
23 
24 
25     class MyButton(ButtonBehavior, Image):
26         def __init__(self, **kwargs):
27             super(MyButton, self).__init__(**kwargs)
28             self.source = 'atlas://data/images/defaulttheme/checkbox_off'
29 
30         def on_press(self):
31             self.source = 'atlas://data/images/defaulttheme/checkbox_on'
32 
33         def on_release(self):
34             self.source = 'atlas://data/images/defaulttheme/checkbox_off'
35 
36 
37     class SampleApp(App):
38         def build(self):
39             return MyButton()
40 
41 
42     SampleApp().run()
43 
44 See :class:`~kivy.uix.behaviors.ButtonBehavior` for details.
45 '''
46 
47 __all__ = ('ButtonBehavior', )
48 
49 from kivy.clock import Clock
50 from kivy.config import Config
51 from kivy.properties import OptionProperty, ObjectProperty, \
52     BooleanProperty, NumericProperty
53 from time import time
54 
55 
56 class ButtonBehavior(object):
57     '''
58     This `mixin <https://en.wikipedia.org/wiki/Mixin>`_ class provides
59     :class:`~kivy.uix.button.Button` behavior. Please see the
60     :mod:`button behaviors module <kivy.uix.behaviors.button>` documentation
61     for more information.
62 
63     :Events:
64         `on_press`
65             Fired when the button is pressed.
66         `on_release`
67             Fired when the button is released (i.e. the touch/click that
68             pressed the button goes away).
69 
70     '''
71 
72     state = OptionProperty('normal', options=('normal', 'down'))
73     '''The state of the button, must be one of 'normal' or 'down'.
74     The state is 'down' only when the button is currently touched/clicked,
75     otherwise its 'normal'.
76 
77     :attr:`state` is an :class:`~kivy.properties.OptionProperty` and defaults
78     to 'normal'.
79     '''
80 
81     last_touch = ObjectProperty(None)
82     '''Contains the last relevant touch received by the Button. This can
83     be used in `on_press` or `on_release` in order to know which touch
84     dispatched the event.
85 
86     .. versionadded:: 1.8.0
87 
88     :attr:`last_touch` is a :class:`~kivy.properties.ObjectProperty` and
89     defaults to `None`.
90     '''
91 
92     
93     min_state_time = NumericProperty(0)
94     '''The minimum period of time which the widget must remain in the
95     `'down'` state.
96 
97     .. versionadded:: 1.9.1
98 
99     :attr:`min_state_time` is a float and defaults to 0.035. This value is
100     taken from :class:`~kivy.config.Config`.
101     '''
102 
103     always_release = BooleanProperty(False)
104     '''This determines whether or not the widget fires an `on_release` event if
105     the touch_up is outside the widget.
106 
107     .. versionadded:: 1.9.0
108 
109     .. versionchanged:: 1.9.2
110         The default value is now False.
111 
112     :attr:`always_release` is a :class:`~kivy.properties.BooleanProperty` and
113     defaults to `False`.
114     '''
115 
116     def __init__(self, **kwargs):
117         self.register_event_type('on_press')
118         self.register_event_type('on_release')
119         if 'min_state_time' not in kwargs:
120             self.min_state_time = float(Config.get('graphics', 'min_state_time'))
121         super(ButtonBehavior, self).__init__(**kwargs)
122         self.__state_event = None
123         self.__touch_time = None
124         self.fbind('state', self.cancel_event)
125 
126     def _do_press(self):
127         self.state = 'down'
128 
129     def _do_release(self, *args):
130         self.state = 'normal'
131 
132     def cancel_event(self, *args):
133         if self.__state_event:
134             self.__state_event.cancel()
135             self.__state_event = None
136 
137     def on_touch_down(self, touch):
138         if super(ButtonBehavior, self).on_touch_down(touch):
139             return True
140         if touch.is_mouse_scrolling:
141             return False
142         if not self.collide_point(touch.x, touch.y):
143             return False
144         if self in touch.ud:
145             return False
146         touch.grab(self)
147         touch.ud[self] = True
148         self.last_touch = touch
149         self.__touch_time = time()
150         self._do_press()
151         self.dispatch('on_press')
152         return True
153 
154     def on_touch_move(self, touch):
155         if touch.grab_current is self:
156             return True
157         if super(ButtonBehavior, self).on_touch_move(touch):
158             return True
159         return self in touch.ud
160 
161     def on_touch_up(self, touch):
162         if touch.grab_current is not self:
163             return super(ButtonBehavior, self).on_touch_up(touch)
164         assert(self in touch.ud)
165         touch.ungrab(self)
166         self.last_touch = touch
167 
168         if (not self.always_release
169                 and not self.collide_point(*touch.pos)):
170             self.state = 'normal'
171             return
172 
173         touchtime = time() - self.__touch_time
174         if touchtime < self.min_state_time:
175             self.__state_event = Clock.schedule_once(
176                 self._do_release, self.min_state_time - touchtime)
177         else:
178             self._do_release()
179         self.dispatch('on_release')
180         return True
181 
182     def on_press(self):
183         pass
184 
185     def on_release(self):
186         pass
187 
188     def trigger_action(self, duration=0.1):
189         '''Trigger whatever action(s) have been bound to the button by calling
190         both the on_press and on_release callbacks.
191 
192         This simulates a quick button press without using any touch events.
193 
194         Duration is the length of the press in seconds. Pass 0 if you want
195         the action to happen instantly.
196 
197         .. versionadded:: 1.8.0
198         '''
199         self._do_press()
200         self.dispatch('on_press')
201 
202         def trigger_release(dt):
203             self._do_release()
204             self.dispatch('on_release')
205         if not duration:
206             trigger_release(0)
207         else:
208             Clock.schedule_once(trigger_release, duration)
209
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/kivy/uix/behaviors/button.py b/kivy/uix/behaviors/button.py
--- a/kivy/uix/behaviors/button.py
+++ b/kivy/uix/behaviors/button.py
@@ -167,7 +167,7 @@
 
         if (not self.always_release
                 and not self.collide_point(*touch.pos)):
-            self.state = 'normal'
+            self._do_release()
             return
 
         touchtime = time() - self.__touch_time

{"golden_diff": "diff --git a/kivy/uix/behaviors/button.py b/kivy/uix/behaviors/button.py\n--- a/kivy/uix/behaviors/button.py\n+++ b/kivy/uix/behaviors/button.py\n@@ -167,7 +167,7 @@\n \n         if (not self.always_release\n                 and not self.collide_point(*touch.pos)):\n-            self.state = 'normal'\n+            self._do_release()\n             return\n \n         touchtime = time() - self.__touch_time\n", "issue": "ToggleButton can get released with allow_no_selection=False\nOhai buddiez, I hope you're all doing goodie ^__^\n\nI found a new bug probably due to \"always_release\" on ButtonBehavior having been changed recently:\n`Changed in version 1.9.2: The default value is now False.`\n\nTake the following example:\nhttps://gist.github.com/42e02d13c31a6504b57d5cd3ac23a460\n\nIf you try to press a button, then release outside of it, its state will be \"normal\", even though it should remain \"down\".\n\nI have made a small change to ButtonBehavior which adds an event \"on_release_outside\" and makes it set the state to normal by default, and overrode it in ToggleButtonBehavior to do nothing instead.\n\nIncoming PR, so please give feedback! (EDIT: See #4594 )\n\nThanks for reading, see you around buddiez bliblibli ^__^\n\n", "before_files": [{"content": "'''\nButton Behavior\n===============\n\nThe :class:`~kivy.uix.behaviors.button.ButtonBehavior`\n`mixin <https://en.wikipedia.org/wiki/Mixin>`_ class provides\n:class:`~kivy.uix.button.Button` behavior. You can combine this class with\nother widgets, such as an :class:`~kivy.uix.image.Image`, to provide\nalternative buttons that preserve Kivy button behavior.\n\nFor an overview of behaviors, please refer to the :mod:`~kivy.uix.behaviors`\ndocumentation.\n\nExample\n-------\n\nThe following example adds button behavior to an image to make a checkbox that\nbehaves like a button::\n\n    from kivy.app import App\n    from kivy.uix.image import Image\n    from kivy.uix.behaviors import ButtonBehavior\n\n\n    class MyButton(ButtonBehavior, Image):\n        def __init__(self, **kwargs):\n            super(MyButton, self).__init__(**kwargs)\n            self.source = 'atlas://data/images/defaulttheme/checkbox_off'\n\n        def on_press(self):\n            self.source = 'atlas://data/images/defaulttheme/checkbox_on'\n\n        def on_release(self):\n            self.source = 'atlas://data/images/defaulttheme/checkbox_off'\n\n\n    class SampleApp(App):\n        def build(self):\n            return MyButton()\n\n\n    SampleApp().run()\n\nSee :class:`~kivy.uix.behaviors.ButtonBehavior` for details.\n'''\n\n__all__ = ('ButtonBehavior', )\n\nfrom kivy.clock import Clock\nfrom kivy.config import Config\nfrom kivy.properties import OptionProperty, ObjectProperty, \\\n    BooleanProperty, NumericProperty\nfrom time import time\n\n\nclass ButtonBehavior(object):\n    '''\n    This `mixin <https://en.wikipedia.org/wiki/Mixin>`_ class provides\n    :class:`~kivy.uix.button.Button` behavior. Please see the\n    :mod:`button behaviors module <kivy.uix.behaviors.button>` documentation\n    for more information.\n\n    :Events:\n        `on_press`\n            Fired when the button is pressed.\n        `on_release`\n            Fired when the button is released (i.e. the touch/click that\n            pressed the button goes away).\n\n    '''\n\n    state = OptionProperty('normal', options=('normal', 'down'))\n    '''The state of the button, must be one of 'normal' or 'down'.\n    The state is 'down' only when the button is currently touched/clicked,\n    otherwise its 'normal'.\n\n    :attr:`state` is an :class:`~kivy.properties.OptionProperty` and defaults\n    to 'normal'.\n    '''\n\n    last_touch = ObjectProperty(None)\n    '''Contains the last relevant touch received by the Button. This can\n    be used in `on_press` or `on_release` in order to know which touch\n    dispatched the event.\n\n    .. versionadded:: 1.8.0\n\n    :attr:`last_touch` is a :class:`~kivy.properties.ObjectProperty` and\n    defaults to `None`.\n    '''\n\n    \n    min_state_time = NumericProperty(0)\n    '''The minimum period of time which the widget must remain in the\n    `'down'` state.\n\n    .. versionadded:: 1.9.1\n\n    :attr:`min_state_time` is a float and defaults to 0.035. This value is\n    taken from :class:`~kivy.config.Config`.\n    '''\n\n    always_release = BooleanProperty(False)\n    '''This determines whether or not the widget fires an `on_release` event if\n    the touch_up is outside the widget.\n\n    .. versionadded:: 1.9.0\n\n    .. versionchanged:: 1.9.2\n        The default value is now False.\n\n    :attr:`always_release` is a :class:`~kivy.properties.BooleanProperty` and\n    defaults to `False`.\n    '''\n\n    def __init__(self, **kwargs):\n        self.register_event_type('on_press')\n        self.register_event_type('on_release')\n        if 'min_state_time' not in kwargs:\n            self.min_state_time = float(Config.get('graphics', 'min_state_time'))\n        super(ButtonBehavior, self).__init__(**kwargs)\n        self.__state_event = None\n        self.__touch_time = None\n        self.fbind('state', self.cancel_event)\n\n    def _do_press(self):\n        self.state = 'down'\n\n    def _do_release(self, *args):\n        self.state = 'normal'\n\n    def cancel_event(self, *args):\n        if self.__state_event:\n            self.__state_event.cancel()\n            self.__state_event = None\n\n    def on_touch_down(self, touch):\n        if super(ButtonBehavior, self).on_touch_down(touch):\n            return True\n        if touch.is_mouse_scrolling:\n            return False\n        if not self.collide_point(touch.x, touch.y):\n            return False\n        if self in touch.ud:\n            return False\n        touch.grab(self)\n        touch.ud[self] = True\n        self.last_touch = touch\n        self.__touch_time = time()\n        self._do_press()\n        self.dispatch('on_press')\n        return True\n\n    def on_touch_move(self, touch):\n        if touch.grab_current is self:\n            return True\n        if super(ButtonBehavior, self).on_touch_move(touch):\n            return True\n        return self in touch.ud\n\n    def on_touch_up(self, touch):\n        if touch.grab_current is not self:\n            return super(ButtonBehavior, self).on_touch_up(touch)\n        assert(self in touch.ud)\n        touch.ungrab(self)\n        self.last_touch = touch\n\n        if (not self.always_release\n                and not self.collide_point(*touch.pos)):\n            self.state = 'normal'\n            return\n\n        touchtime = time() - self.__touch_time\n        if touchtime < self.min_state_time:\n            self.__state_event = Clock.schedule_once(\n                self._do_release, self.min_state_time - touchtime)\n        else:\n            self._do_release()\n        self.dispatch('on_release')\n        return True\n\n    def on_press(self):\n        pass\n\n    def on_release(self):\n        pass\n\n    def trigger_action(self, duration=0.1):\n        '''Trigger whatever action(s) have been bound to the button by calling\n        both the on_press and on_release callbacks.\n\n        This simulates a quick button press without using any touch events.\n\n        Duration is the length of the press in seconds. Pass 0 if you want\n        the action to happen instantly.\n\n        .. versionadded:: 1.8.0\n        '''\n        self._do_press()\n        self.dispatch('on_press')\n\n        def trigger_release(dt):\n            self._do_release()\n            self.dispatch('on_release')\n        if not duration:\n            trigger_release(0)\n        else:\n            Clock.schedule_once(trigger_release, duration)\n", "path": "kivy/uix/behaviors/button.py"}], "after_files": [{"content": "'''\nButton Behavior\n===============\n\nThe :class:`~kivy.uix.behaviors.button.ButtonBehavior`\n`mixin <https://en.wikipedia.org/wiki/Mixin>`_ class provides\n:class:`~kivy.uix.button.Button` behavior. You can combine this class with\nother widgets, such as an :class:`~kivy.uix.image.Image`, to provide\nalternative buttons that preserve Kivy button behavior.\n\nFor an overview of behaviors, please refer to the :mod:`~kivy.uix.behaviors`\ndocumentation.\n\nExample\n-------\n\nThe following example adds button behavior to an image to make a checkbox that\nbehaves like a button::\n\n    from kivy.app import App\n    from kivy.uix.image import Image\n    from kivy.uix.behaviors import ButtonBehavior\n\n\n    class MyButton(ButtonBehavior, Image):\n        def __init__(self, **kwargs):\n            super(MyButton, self).__init__(**kwargs)\n            self.source = 'atlas://data/images/defaulttheme/checkbox_off'\n\n        def on_press(self):\n            self.source = 'atlas://data/images/defaulttheme/checkbox_on'\n\n        def on_release(self):\n            self.source = 'atlas://data/images/defaulttheme/checkbox_off'\n\n\n    class SampleApp(App):\n        def build(self):\n            return MyButton()\n\n\n    SampleApp().run()\n\nSee :class:`~kivy.uix.behaviors.ButtonBehavior` for details.\n'''\n\n__all__ = ('ButtonBehavior', )\n\nfrom kivy.clock import Clock\nfrom kivy.config import Config\nfrom kivy.properties import OptionProperty, ObjectProperty, \\\n    BooleanProperty, NumericProperty\nfrom time import time\n\n\nclass ButtonBehavior(object):\n    '''\n    This `mixin <https://en.wikipedia.org/wiki/Mixin>`_ class provides\n    :class:`~kivy.uix.button.Button` behavior. Please see the\n    :mod:`button behaviors module <kivy.uix.behaviors.button>` documentation\n    for more information.\n\n    :Events:\n        `on_press`\n            Fired when the button is pressed.\n        `on_release`\n            Fired when the button is released (i.e. the touch/click that\n            pressed the button goes away).\n\n    '''\n\n    state = OptionProperty('normal', options=('normal', 'down'))\n    '''The state of the button, must be one of 'normal' or 'down'.\n    The state is 'down' only when the button is currently touched/clicked,\n    otherwise its 'normal'.\n\n    :attr:`state` is an :class:`~kivy.properties.OptionProperty` and defaults\n    to 'normal'.\n    '''\n\n    last_touch = ObjectProperty(None)\n    '''Contains the last relevant touch received by the Button. This can\n    be used in `on_press` or `on_release` in order to know which touch\n    dispatched the event.\n\n    .. versionadded:: 1.8.0\n\n    :attr:`last_touch` is a :class:`~kivy.properties.ObjectProperty` and\n    defaults to `None`.\n    '''\n\n    \n    min_state_time = NumericProperty(0)\n    '''The minimum period of time which the widget must remain in the\n    `'down'` state.\n\n    .. versionadded:: 1.9.1\n\n    :attr:`min_state_time` is a float and defaults to 0.035. This value is\n    taken from :class:`~kivy.config.Config`.\n    '''\n\n    always_release = BooleanProperty(False)\n    '''This determines whether or not the widget fires an `on_release` event if\n    the touch_up is outside the widget.\n\n    .. versionadded:: 1.9.0\n\n    .. versionchanged:: 1.9.2\n        The default value is now False.\n\n    :attr:`always_release` is a :class:`~kivy.properties.BooleanProperty` and\n    defaults to `False`.\n    '''\n\n    def __init__(self, **kwargs):\n        self.register_event_type('on_press')\n        self.register_event_type('on_release')\n        if 'min_state_time' not in kwargs:\n            self.min_state_time = float(Config.get('graphics', 'min_state_time'))\n        super(ButtonBehavior, self).__init__(**kwargs)\n        self.__state_event = None\n        self.__touch_time = None\n        self.fbind('state', self.cancel_event)\n\n    def _do_press(self):\n        self.state = 'down'\n\n    def _do_release(self, *args):\n        self.state = 'normal'\n\n    def cancel_event(self, *args):\n        if self.__state_event:\n            self.__state_event.cancel()\n            self.__state_event = None\n\n    def on_touch_down(self, touch):\n        if super(ButtonBehavior, self).on_touch_down(touch):\n            return True\n        if touch.is_mouse_scrolling:\n            return False\n        if not self.collide_point(touch.x, touch.y):\n            return False\n        if self in touch.ud:\n            return False\n        touch.grab(self)\n        touch.ud[self] = True\n        self.last_touch = touch\n        self.__touch_time = time()\n        self._do_press()\n        self.dispatch('on_press')\n        return True\n\n    def on_touch_move(self, touch):\n        if touch.grab_current is self:\n            return True\n        if super(ButtonBehavior, self).on_touch_move(touch):\n            return True\n        return self in touch.ud\n\n    def on_touch_up(self, touch):\n        if touch.grab_current is not self:\n            return super(ButtonBehavior, self).on_touch_up(touch)\n        assert(self in touch.ud)\n        touch.ungrab(self)\n        self.last_touch = touch\n\n        if (not self.always_release\n                and not self.collide_point(*touch.pos)):\n            self._do_release()\n            return\n\n        touchtime = time() - self.__touch_time\n        if touchtime < self.min_state_time:\n            self.__state_event = Clock.schedule_once(\n                self._do_release, self.min_state_time - touchtime)\n        else:\n            self._do_release()\n        self.dispatch('on_release')\n        return True\n\n    def on_press(self):\n        pass\n\n    def on_release(self):\n        pass\n\n    def trigger_action(self, duration=0.1):\n        '''Trigger whatever action(s) have been bound to the button by calling\n        both the on_press and on_release callbacks.\n\n        This simulates a quick button press without using any touch events.\n\n        Duration is the length of the press in seconds. Pass 0 if you want\n        the action to happen instantly.\n\n        .. versionadded:: 1.8.0\n        '''\n        self._do_press()\n        self.dispatch('on_press')\n\n        def trigger_release(dt):\n            self._do_release()\n            self.dispatch('on_release')\n        if not duration:\n            trigger_release(0)\n        else:\n            Clock.schedule_once(trigger_release, duration)\n", "path": "kivy/uix/behaviors/button.py"}]}