Repository: Textualize/textual

Issue:
DataTable `update_cell` with invalid column key does not raise exception
Currently the DataTable will only raise a `CellDoesNotExist` error if the **row** key does not exist, but not if the **column** key does not exist. 

Here's a simple example which also logs the table `_data`:

```python
from textual.app import App, ComposeResult
from textual.widgets import DataTable, RichLog


class TableApp(App):
    CSS = """
    DataTable {
        height: 1fr;
        border: double $primary;
    }

    RichLog {
        height: 1fr;
        border: double $primary;
    }
    """

    def compose(self) -> ComposeResult:
        yield DataTable()
        yield RichLog()

    def on_mount(self) -> None:
        table = app.query_one(DataTable)
        table.border_title = "Table View"
        table.add_column("Column1", key="C1")
        table.add_row("TargetValue", key="R1")

        log = self.query_one(RichLog)
        log.border_title = "Table Data"
        log.write("DataTable._data = ")
        log.write(table._data)

    def key_u(self) -> None:
        table = self.query_one(DataTable)
        table.update_cell("R1", "INVALID_COLUMN", "New Value")

        log = self.query_one(RichLog)
        log.write("\nDataTable._data = ")
        log.write(table._data)


app = TableApp()
if __name__ == "__main__":
    app.run()
```


Discussion:
We found the following entries in the [FAQ](https://textual.textualize.io/FAQ/) which you may find helpful:


- [No widget called TextLog](https://textual.textualize.io/FAQ/#no-widget-called-textlog)
- [Why do some key combinations never make it to my app?](https://textual.textualize.io/FAQ/#why-do-some-key-combinations-never-make-it-to-my-app)

Feel free to close this issue if you found an answer in the FAQ. Otherwise, please give us a little time to review.

This is an automated reply, generated by [FAQtory](https://github.com/willmcgugan/faqtory)

Resolving patch:
diff --git a/src/textual/widgets/_data_table.py b/src/textual/widgets/_data_table.py
--- a/src/textual/widgets/_data_table.py
+++ b/src/textual/widgets/_data_table.py
@@ -791,12 +791,15 @@ def update_cell(
         if isinstance(column_key, str):
             column_key = ColumnKey(column_key)
 
-        try:
-            self._data[row_key][column_key] = value
-        except KeyError:
+        if (
+            row_key not in self._row_locations
+            or column_key not in self._column_locations
+        ):
             raise CellDoesNotExist(
                 f"No cell exists for row_key={row_key!r}, column_key={column_key!r}."
-            ) from None
+            )
+
+        self._data[row_key][column_key] = value
         self._update_count += 1
 
         # Recalculate widths if necessary


Test patch:
diff --git a/tests/test_data_table.py b/tests/test_data_table.py
--- a/tests/test_data_table.py
+++ b/tests/test_data_table.py
@@ -671,6 +671,17 @@ async def test_update_cell_cell_doesnt_exist():
             table.update_cell("INVALID", "CELL", "Value")
 
 
+async def test_update_cell_invalid_column_key():
+    """Regression test for https://github.com/Textualize/textual/issues/3335"""
+    app = DataTableApp()
+    async with app.run_test():
+        table = app.query_one(DataTable)
+        table.add_column("Column1", key="C1")
+        table.add_row("TargetValue", key="R1")
+        with pytest.raises(CellDoesNotExist):
+            table.update_cell("R1", "INVALID_COLUMN", "New Value")
+
+
 async def test_update_cell_at_coordinate_exists():
     app = DataTableApp()
     async with app.run_test():