Skip to content

Row does not support string-key indexing #582

@dlevy-msft-sql

Description

@dlevy-msft-sql

Summary

In mssql-python 1.6.0, Row no longer supports string-key indexing (row["ColumnName"]). This worked in 1.5.0 and is not called out as a breaking change in the v1.6.0 release notes.

Repro

import mssql_python

conn = mssql_python.connect("<your conn str>")
cur = conn.cursor()
cur.execute("SELECT 1 AS ProductID, 'foo' AS Name")
row = cur.fetchone()

print(row[0])           # works
print(row.ProductID)    # works (attribute access)
print(row["ProductID"]) # TypeError on 1.6.0; worked on 1.5.0

Output on 1.6.0

1
1
Traceback (most recent call last):
  File "probe.py", line N, in <module>
    print(row["ProductID"])
          ~~~^^^^^^^^^^^^^
TypeError: list indices must be integers or slices, not str

Versions

  • mssql-python 1.6.0 (verified via pip show mssql-python)
  • Python 3.14 on Windows
  • Server: Fabric SQL endpoint (not relevant; reproes with any SELECT ... AS Name)

The same script returns 1 on 1.5.0.

Why this matters

  1. Silent regression. The exception message (list indices must be integers or slices) reads like a Python typo, not a deliberate API change. Users will spend time debugging their query and column aliases before they suspect the driver.
  2. Not in release notes. The v1.6.0 notes list 1 enhancement and 6 bug fixes, none of which mention Row access semantics or list any "Breaking Changes" section. v0.14.0 set the precedent that breaking changes get their own section and migration notes — v1.6.0 should follow that convention.
  3. Public documentation uses this pattern. The official mssql-python quickstart on Microsoft Learn currently shows print(f"Inserted Product ID : {result['ProductID']}") (source). Anyone following the quickstart on 1.6.0 hits this on the last code block. (A docs fix to use attribute access is already staged in our v1.6.0 doc PR, but the broader user base relying on row["col"] in their own code is the real concern.)
  4. Attribute access isn't a complete substitute. row.ColumnName only works when the column alias is a valid Python identifier. For aliases with spaces, hyphens, reserved words, or computed/unnamed columns, string-key access was the only ergonomic option short of positional indexing.

Ask

Either:

  1. Restore Row.__getitem__(str) (preferred — matches pyodbc Row semantics and 1.5.0 behavior), or
  2. Document this as a breaking change in the v1.6.0 release notes with a migration recipe (switch to attribute or positional access; for non-identifier column names, suggest dict(zip([d[0] for d in cur.description], row)) or similar).

Happy to send a PR for either path if it would help.

Related context

Metadata

Metadata

Assignees

Labels

enhancementNew feature or requestinADOtriage doneIssues that are triaged by dev team and are in investigation.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions