Skip to content

Commit 8b0a29f

Browse files
committed
fixup: _RowView validation, efficient values/items, fix None-replication crash
1 parent eda1086 commit 8b0a29f

2 files changed

Lines changed: 41 additions & 2 deletions

File tree

cassandra/metadata.py

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,11 @@ class _RowView(Mapping):
6161
__slots__ = ("_row", "_index_map")
6262

6363
def __init__(self, row, index_map):
64+
if len(row) < max(index_map.values(), default=-1) + 1:
65+
raise ValueError(
66+
"row length (%d) is insufficient for index_map with max index %d"
67+
% (len(row), max(index_map.values(), default=-1))
68+
)
6469
self._row = row
6570
self._index_map = index_map
6671

@@ -73,6 +78,12 @@ def __iter__(self):
7378
def __len__(self):
7479
return len(self._index_map)
7580

81+
def values(self):
82+
return (self._row[i] for i in self._index_map.values())
83+
84+
def items(self):
85+
return ((k, self._row[i]) for k, i in self._index_map.items())
86+
7687
def get(self, key, default=None):
7788
idx = self._index_map.get(key)
7889
if idx is not None:
@@ -3121,7 +3132,7 @@ def _build_keyspace_metadata_internal(row):
31213132
# Read without mutating the row, since _RowView is read-only
31223133
name = row["keyspace_name"]
31233134
durable_writes = row.get("durable_writes", None)
3124-
replication = dict(row.get("replication")) if 'replication' in row else {}
3135+
replication = dict(row.get("replication")) if row.get("replication") else {}
31253136
replication_class = replication.pop("class") if 'class' in replication else None
31263137
return KeyspaceMetadata(name, durable_writes, replication_class, replication)
31273138

@@ -3189,7 +3200,7 @@ def get_table(self, keyspaces, keyspace, table):
31893200
def _build_keyspace_metadata_internal(row):
31903201
name = row["keyspace_name"]
31913202
durable_writes = row.get("durable_writes", None)
3192-
replication = dict(row.get("replication")) if 'replication' in row else {}
3203+
replication = dict(row.get("replication")) if row.get("replication") else {}
31933204
replication_class = replication.pop("class") if 'class' in replication else None
31943205
graph_engine = row.get("graph_engine", None)
31953206
return KeyspaceMetadata(name, durable_writes, replication_class, replication, graph_engine)

tests/unit/test_metadata.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -910,3 +910,31 @@ def test_row_factory_values(self):
910910
self.assertEqual(rows[0]["name"], "alice")
911911
self.assertEqual(rows[1]["id"], 2)
912912
self.assertEqual(rows[1]["name"], "bob")
913+
914+
def test_len(self):
915+
rv = _RowView(("a", "b", "c"), {"x": 0, "y": 1, "z": 2})
916+
self.assertEqual(len(rv), 3)
917+
rv2 = _RowView((), {})
918+
self.assertEqual(len(rv2), 0)
919+
920+
def test_keys(self):
921+
rv = _RowView(("a", "b"), {"x": 0, "y": 1})
922+
self.assertEqual(set(rv.keys()), {"x", "y"})
923+
924+
def test_values(self):
925+
rv = _RowView(("a", "b"), {"x": 0, "y": 1})
926+
self.assertEqual(list(rv.values()), ["a", "b"])
927+
928+
def test_items(self):
929+
rv = _RowView(("a", "b"), {"x": 0, "y": 1})
930+
self.assertEqual(set(rv.items()), {("x", "a"), ("y", "b")})
931+
932+
def test_init_raises_on_short_row(self):
933+
with self.assertRaises(ValueError):
934+
_RowView(("val",), {"a": 0, "b": 1})
935+
936+
def test_init_accepts_exact_row(self):
937+
_RowView(("a", "b"), {"a": 0, "b": 1})
938+
939+
def test_init_accepts_empty(self):
940+
_RowView((), {})

0 commit comments

Comments
 (0)