prompt: We are currently solving the following issue within our repository. Here is the issue text:
  --- BEGIN ISSUE ---
  Not specifying an `on_select` callback for Table leads to a TypeError
  **Describe the bug**
  If you leave out a `on_select` callable on `Table` and click a row, you get a traceback in the terminal:
  ```python
  Traceback (most recent call last):
    File "C:\\Users\\brcan\\Desktop\\snippets\\.venv\\lib\\site-packages\\toga_winforms\\widgets\\table.py", line 74, in _native_item_selection_changed
      self.interface.on_select(self.interface, row=self.interface.data[e.ItemIndex])
  TypeError : 'NoneType' object is not callable
  ```
  
  **To Reproduce**
  Steps to reproduce the behavior:
  1. Go to https://toga.readthedocs.io/en/latest/tutorial/tutorial-2.html
  2. Run the example
  3. Click on any row of the table
  4. See error
  
  **Expected behavior**
  No error.
  
  **Environment:**
   - Operating System: Windows 10
   - Python version: CPython 3.8.3
   - Software versions:
     - Briefcase:
     - Toga: 0.3.0dev22
     - ...
  
  
  --- END ISSUE ---
  
  Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
  --- BEGIN FILES ---
  Path: `src/winforms/toga_winforms/widgets/table.py`
  Content:
  ```
  1 from travertino.size import at_least
  2 
  3 from toga_winforms.libs import WinForms
  4 
  5 from .base import Widget
  6 
  7 
  8 class Table(Widget):
  9     def create(self):
  10         self._container = self
  11         self.native = WinForms.ListView()
  12         self.native.View = WinForms.View.Details
  13         self._cache = []
  14         self._first_item = 0
  15 
  16         dataColumn = []
  17         for i, (heading, accessor) in enumerate(zip(
  18                     self.interface.headings,
  19                     self.interface._accessors
  20                 )):
  21             dataColumn.append(self._create_column(heading, accessor))
  22 
  23         self.native.FullRowSelect = True
  24         self.native.MultiSelect = self.interface.multiple_select
  25         self.native.DoubleBuffered = True
  26         self.native.VirtualMode = True
  27         self.native.Columns.AddRange(dataColumn)
  28 
  29         self.native.ItemSelectionChanged += self._native_item_selection_changed
  30         self.native.RetrieveVirtualItem += self._native_retrieve_virtual_item
  31         self.native.CacheVirtualItems += self._native_cache_virtual_items
  32         self.native.VirtualItemsSelectionRangeChanged += self._native_virtual_item_selection_range_changed
  33 
  34     def _native_virtual_item_selection_range_changed(self, sender, e):
  35         # update selection interface property
  36         self.interface._selection = self._selected_rows()
  37 
  38         # `Shift` key or Range selection handler
  39         if e.IsSelected and self.interface.multiple_select and self.interface.on_select:
  40             # call on select with the last row of the multi selection
  41             selected = self.interface.data[e.EndIndex]
  42             self.interface.on_select(self.interface, row=selected)
  43 
  44     def _native_retrieve_virtual_item(self, sender, e):
  45         # Because ListView is in VirtualMode, it's necessary implement
  46         # VirtualItemsSelectionRangeChanged event to create ListViewItem when it's needed
  47         if self._cache and e.ItemIndex >= self._first_item and \
  48            e.ItemIndex < self._first_item + len(self._cache):
  49             e.Item = self._cache[e.ItemIndex - self._first_item]
  50         else:
  51             e.Item = WinForms.ListViewItem(self.row_data(self.interface.data[e.ItemIndex]))
  52 
  53     def _native_cache_virtual_items(self, sender, e):
  54         if self._cache and e.StartIndex >= self._first_item and \
  55            e.EndIndex <= self._first_item + len(self._cache):
  56             # If the newly requested cache is a subset of the old cache,
  57             # no need to rebuild everything, so do nothing
  58             return
  59 
  60         # Now we need to rebuild the cache.
  61         self._first_item = e.StartIndex
  62         new_length = e.EndIndex - e.StartIndex + 1
  63         self._cache = []
  64 
  65         # Fill the cache with the appropriate ListViewItems.
  66         for i in range(new_length):
  67             self._cache.append(WinForms.ListViewItem(self.row_data(self.interface.data[i])))
  68 
  69     def _native_item_selection_changed(self, sender, e):
  70         # update selection interface property
  71         self.interface._selection = self._selected_rows()
  72 
  73         if e.IsSelected:
  74             self.interface.on_select(self.interface, row=self.interface.data[e.ItemIndex])
  75 
  76     def _selected_rows(self):
  77         if not self.native.SelectedIndices.Count:
  78             return None
  79 
  80         if self.interface.multiple_select:
  81             selected = [row for i, row in enumerate(self.interface.data) if i in self.native.SelectedIndices]
  82             return selected
  83         else:
  84             return self.interface.data[self.native.SelectedIndices[0]]
  85 
  86     def _create_column(self, heading, accessor):
  87         col = WinForms.ColumnHeader()
  88         col.Text = heading
  89         col.Name = accessor
  90         return col
  91 
  92     def change_source(self, source):
  93         self.update_data()
  94 
  95     def row_data(self, item):
  96         # TODO: Winforms can't support icons in tree cells; so, if the data source
  97         # specifies an icon, strip it when converting to row data.
  98         def strip_icon(item, attr):
  99             val = getattr(item, attr, self.interface.missing_value)
  100 
  101             if isinstance(val, tuple):
  102                 return str(val[1])
  103             return str(val)
  104 
  105         return [
  106             strip_icon(item, attr)
  107             for attr in self.interface._accessors
  108         ]
  109 
  110     def update_data(self):
  111         self.native.VirtualListSize = len(self.interface.data)
  112         self._cache = []
  113 
  114     def insert(self, index, item):
  115         self.update_data()
  116 
  117     def change(self, item):
  118         self.interface.factory.not_implemented('Table.change()')
  119 
  120     def remove(self, item):
  121         self.update_data()
  122 
  123     def clear(self):
  124         self.update_data()
  125 
  126     def set_on_select(self, handler):
  127         pass
  128 
  129     def scroll_to_row(self, row):
  130         self.native.EnsureVisible(row)
  131 
  132     def rehint(self):
  133         self.interface.intrinsic.width = at_least(self.interface.MIN_WIDTH)
  134         self.interface.intrinsic.height = at_least(self.interface.MIN_HEIGHT)
  135 
  136     def remove_column(self, accessor):
  137         self.native.Columns.RemoveByKey(accessor)
  138 
  139     def add_column(self, heading, accessor):
  140         self.native.Columns.Add(self._create_column(heading, accessor))
  141         self.update_data()
  142
  ```
  --- 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()
  
  ```
  
golden_diff: diff --git a/src/winforms/toga_winforms/widgets/table.py b/src/winforms/toga_winforms/widgets/table.py
  --- a/src/winforms/toga_winforms/widgets/table.py
  +++ b/src/winforms/toga_winforms/widgets/table.py
  @@ -70,7 +70,7 @@
           # update selection interface property
           self.interface._selection = self._selected_rows()
   
  -        if e.IsSelected:
  +        if e.IsSelected and self.interface.on_select:
               self.interface.on_select(self.interface, row=self.interface.data[e.ItemIndex])
   
       def _selected_rows(self):
  
verification_info: {"golden_diff": "diff --git a/src/winforms/toga_winforms/widgets/table.py b/src/winforms/toga_winforms/widgets/table.py\n--- a/src/winforms/toga_winforms/widgets/table.py\n+++ b/src/winforms/toga_winforms/widgets/table.py\n@@ -70,7 +70,7 @@\n         # update selection interface property\n         self.interface._selection = self._selected_rows()\n \n-        if e.IsSelected:\n+        if e.IsSelected and self.interface.on_select:\n             self.interface.on_select(self.interface, row=self.interface.data[e.ItemIndex])\n \n     def _selected_rows(self):\n", "issue": "Not specifying an `on_select` callback for Table leads to a TypeError\n**Describe the bug**\r\nIf you leave out a `on_select` callable on `Table` and click a row, you get a traceback in the terminal:\r\n```python\r\nTraceback (most recent call last):\r\n  File \"C:\\\\Users\\\\brcan\\\\Desktop\\\\snippets\\\\.venv\\\\lib\\\\site-packages\\\\toga_winforms\\\\widgets\\\\table.py\", line 74, in _native_item_selection_changed\r\n    self.interface.on_select(self.interface, row=self.interface.data[e.ItemIndex])\r\nTypeError : 'NoneType' object is not callable\r\n```\r\n\r\n**To Reproduce**\r\nSteps to reproduce the behavior:\r\n1. Go to https://toga.readthedocs.io/en/latest/tutorial/tutorial-2.html\r\n2. Run the example\r\n3. Click on any row of the table\r\n4. See error\r\n\r\n**Expected behavior**\r\nNo error.\r\n\r\n**Environment:**\r\n - Operating System: Windows 10\r\n - Python version: CPython 3.8.3\r\n - Software versions:\r\n   - Briefcase:\r\n   - Toga: 0.3.0dev22\r\n   - ...\r\n\n", "before_files": [{"content": "from travertino.size import at_least\n\nfrom toga_winforms.libs import WinForms\n\nfrom .base import Widget\n\n\nclass Table(Widget):\n    def create(self):\n        self._container = self\n        self.native = WinForms.ListView()\n        self.native.View = WinForms.View.Details\n        self._cache = []\n        self._first_item = 0\n\n        dataColumn = []\n        for i, (heading, accessor) in enumerate(zip(\n                    self.interface.headings,\n                    self.interface._accessors\n                )):\n            dataColumn.append(self._create_column(heading, accessor))\n\n        self.native.FullRowSelect = True\n        self.native.MultiSelect = self.interface.multiple_select\n        self.native.DoubleBuffered = True\n        self.native.VirtualMode = True\n        self.native.Columns.AddRange(dataColumn)\n\n        self.native.ItemSelectionChanged += self._native_item_selection_changed\n        self.native.RetrieveVirtualItem += self._native_retrieve_virtual_item\n        self.native.CacheVirtualItems += self._native_cache_virtual_items\n        self.native.VirtualItemsSelectionRangeChanged += self._native_virtual_item_selection_range_changed\n\n    def _native_virtual_item_selection_range_changed(self, sender, e):\n        # update selection interface property\n        self.interface._selection = self._selected_rows()\n\n        # `Shift` key or Range selection handler\n        if e.IsSelected and self.interface.multiple_select and self.interface.on_select:\n            # call on select with the last row of the multi selection\n            selected = self.interface.data[e.EndIndex]\n            self.interface.on_select(self.interface, row=selected)\n\n    def _native_retrieve_virtual_item(self, sender, e):\n        # Because ListView is in VirtualMode, it's necessary implement\n        # VirtualItemsSelectionRangeChanged event to create ListViewItem when it's needed\n        if self._cache and e.ItemIndex >= self._first_item and \\\n           e.ItemIndex < self._first_item + len(self._cache):\n            e.Item = self._cache[e.ItemIndex - self._first_item]\n        else:\n            e.Item = WinForms.ListViewItem(self.row_data(self.interface.data[e.ItemIndex]))\n\n    def _native_cache_virtual_items(self, sender, e):\n        if self._cache and e.StartIndex >= self._first_item and \\\n           e.EndIndex <= self._first_item + len(self._cache):\n            # If the newly requested cache is a subset of the old cache,\n            # no need to rebuild everything, so do nothing\n            return\n\n        # Now we need to rebuild the cache.\n        self._first_item = e.StartIndex\n        new_length = e.EndIndex - e.StartIndex + 1\n        self._cache = []\n\n        # Fill the cache with the appropriate ListViewItems.\n        for i in range(new_length):\n            self._cache.append(WinForms.ListViewItem(self.row_data(self.interface.data[i])))\n\n    def _native_item_selection_changed(self, sender, e):\n        # update selection interface property\n        self.interface._selection = self._selected_rows()\n\n        if e.IsSelected:\n            self.interface.on_select(self.interface, row=self.interface.data[e.ItemIndex])\n\n    def _selected_rows(self):\n        if not self.native.SelectedIndices.Count:\n            return None\n\n        if self.interface.multiple_select:\n            selected = [row for i, row in enumerate(self.interface.data) if i in self.native.SelectedIndices]\n            return selected\n        else:\n            return self.interface.data[self.native.SelectedIndices[0]]\n\n    def _create_column(self, heading, accessor):\n        col = WinForms.ColumnHeader()\n        col.Text = heading\n        col.Name = accessor\n        return col\n\n    def change_source(self, source):\n        self.update_data()\n\n    def row_data(self, item):\n        # TODO: Winforms can't support icons in tree cells; so, if the data source\n        # specifies an icon, strip it when converting to row data.\n        def strip_icon(item, attr):\n            val = getattr(item, attr, self.interface.missing_value)\n\n            if isinstance(val, tuple):\n                return str(val[1])\n            return str(val)\n\n        return [\n            strip_icon(item, attr)\n            for attr in self.interface._accessors\n        ]\n\n    def update_data(self):\n        self.native.VirtualListSize = len(self.interface.data)\n        self._cache = []\n\n    def insert(self, index, item):\n        self.update_data()\n\n    def change(self, item):\n        self.interface.factory.not_implemented('Table.change()')\n\n    def remove(self, item):\n        self.update_data()\n\n    def clear(self):\n        self.update_data()\n\n    def set_on_select(self, handler):\n        pass\n\n    def scroll_to_row(self, row):\n        self.native.EnsureVisible(row)\n\n    def rehint(self):\n        self.interface.intrinsic.width = at_least(self.interface.MIN_WIDTH)\n        self.interface.intrinsic.height = at_least(self.interface.MIN_HEIGHT)\n\n    def remove_column(self, accessor):\n        self.native.Columns.RemoveByKey(accessor)\n\n    def add_column(self, heading, accessor):\n        self.native.Columns.Add(self._create_column(heading, accessor))\n        self.update_data()\n", "path": "src/winforms/toga_winforms/widgets/table.py"}], "after_files": [{"content": "from travertino.size import at_least\n\nfrom toga_winforms.libs import WinForms\n\nfrom .base import Widget\n\n\nclass Table(Widget):\n    def create(self):\n        self._container = self\n        self.native = WinForms.ListView()\n        self.native.View = WinForms.View.Details\n        self._cache = []\n        self._first_item = 0\n\n        dataColumn = []\n        for i, (heading, accessor) in enumerate(zip(\n                    self.interface.headings,\n                    self.interface._accessors\n                )):\n            dataColumn.append(self._create_column(heading, accessor))\n\n        self.native.FullRowSelect = True\n        self.native.MultiSelect = self.interface.multiple_select\n        self.native.DoubleBuffered = True\n        self.native.VirtualMode = True\n        self.native.Columns.AddRange(dataColumn)\n\n        self.native.ItemSelectionChanged += self._native_item_selection_changed\n        self.native.RetrieveVirtualItem += self._native_retrieve_virtual_item\n        self.native.CacheVirtualItems += self._native_cache_virtual_items\n        self.native.VirtualItemsSelectionRangeChanged += self._native_virtual_item_selection_range_changed\n\n    def _native_virtual_item_selection_range_changed(self, sender, e):\n        # update selection interface property\n        self.interface._selection = self._selected_rows()\n\n        # `Shift` key or Range selection handler\n        if e.IsSelected and self.interface.multiple_select and self.interface.on_select:\n            # call on select with the last row of the multi selection\n            selected = self.interface.data[e.EndIndex]\n            self.interface.on_select(self.interface, row=selected)\n\n    def _native_retrieve_virtual_item(self, sender, e):\n        # Because ListView is in VirtualMode, it's necessary implement\n        # VirtualItemsSelectionRangeChanged event to create ListViewItem when it's needed\n        if self._cache and e.ItemIndex >= self._first_item and \\\n           e.ItemIndex < self._first_item + len(self._cache):\n            e.Item = self._cache[e.ItemIndex - self._first_item]\n        else:\n            e.Item = WinForms.ListViewItem(self.row_data(self.interface.data[e.ItemIndex]))\n\n    def _native_cache_virtual_items(self, sender, e):\n        if self._cache and e.StartIndex >= self._first_item and \\\n           e.EndIndex <= self._first_item + len(self._cache):\n            # If the newly requested cache is a subset of the old cache,\n            # no need to rebuild everything, so do nothing\n            return\n\n        # Now we need to rebuild the cache.\n        self._first_item = e.StartIndex\n        new_length = e.EndIndex - e.StartIndex + 1\n        self._cache = []\n\n        # Fill the cache with the appropriate ListViewItems.\n        for i in range(new_length):\n            self._cache.append(WinForms.ListViewItem(self.row_data(self.interface.data[i])))\n\n    def _native_item_selection_changed(self, sender, e):\n        # update selection interface property\n        self.interface._selection = self._selected_rows()\n\n        if e.IsSelected and self.interface.on_select:\n            self.interface.on_select(self.interface, row=self.interface.data[e.ItemIndex])\n\n    def _selected_rows(self):\n        if not self.native.SelectedIndices.Count:\n            return None\n\n        if self.interface.multiple_select:\n            selected = [row for i, row in enumerate(self.interface.data) if i in self.native.SelectedIndices]\n            return selected\n        else:\n            return self.interface.data[self.native.SelectedIndices[0]]\n\n    def _create_column(self, heading, accessor):\n        col = WinForms.ColumnHeader()\n        col.Text = heading\n        col.Name = accessor\n        return col\n\n    def change_source(self, source):\n        self.update_data()\n\n    def row_data(self, item):\n        # TODO: Winforms can't support icons in tree cells; so, if the data source\n        # specifies an icon, strip it when converting to row data.\n        def strip_icon(item, attr):\n            val = getattr(item, attr, self.interface.missing_value)\n\n            if isinstance(val, tuple):\n                return str(val[1])\n            return str(val)\n\n        return [\n            strip_icon(item, attr)\n            for attr in self.interface._accessors\n        ]\n\n    def update_data(self):\n        self.native.VirtualListSize = len(self.interface.data)\n        self._cache = []\n\n    def insert(self, index, item):\n        self.update_data()\n\n    def change(self, item):\n        self.interface.factory.not_implemented('Table.change()')\n\n    def remove(self, item):\n        self.update_data()\n\n    def clear(self):\n        self.update_data()\n\n    def set_on_select(self, handler):\n        pass\n\n    def scroll_to_row(self, row):\n        self.native.EnsureVisible(row)\n\n    def rehint(self):\n        self.interface.intrinsic.width = at_least(self.interface.MIN_WIDTH)\n        self.interface.intrinsic.height = at_least(self.interface.MIN_HEIGHT)\n\n    def remove_column(self, accessor):\n        self.native.Columns.RemoveByKey(accessor)\n\n    def add_column(self, heading, accessor):\n        self.native.Columns.Add(self._create_column(heading, accessor))\n        self.update_data()\n", "path": "src/winforms/toga_winforms/widgets/table.py"}]}