sqlalchemy: dict(row) causing TypeError: tuple indices must be integers or slices, not str

DISCLAIMER: This is a very weird bug, I don’t know if SQLAlchemy is the problem, but I couldn’t reproduce without it, there is a very easy workaround, but I felt like i should report this as it may hide something else.

Describe the bug Using dict() on an sqlalchemy.engine.Row object is producing TypeError: tuple indices must be integers or slices, not str in a very specific setup (see To Reproduce)

Expected behavior dict(row) should return the row as a dict.

To Reproduce This Dockerfile can show the error:

FROM python:3-alpine

RUN apk add --no-cache g++

RUN pip install --upgrade pip && pip install greenlet

RUN apk del g++

RUN pip install sqlalchemy

RUN echo $'\
from sqlalchemy import create_engine \n\
from sqlalchemy.orm import sessionmaker \n\
\n\
session = sessionmaker(bind=create_engine("sqlite://"))() \n\
result = session.execute("select 1, 2, 3").fetchall() \n\
row = result[0] \n\
\n\
print(dict(row)) \n\
' > script.py

RUN python script.py

Inline code is

from sqlalchemy import create_engine 
from sqlalchemy.orm import sessionmaker 

session = sessionmaker(bind=create_engine("sqlite://"))() 
result = session.execute("select 1, 2, 3").fetchall() 
row = result[0] 

print(dict(row))

Error

Traceback (most recent call last):
  File "//script.py", line 8, in <module>
    print(dict(row))
  File "/usr/local/lib/python3.9/site-packages/sqlalchemy/engine/row.py", line 104, in __getitem__
    return self._data[key]
TypeError: tuple indices must be integers or slices, not str

Versions.

  • OS: Alpine 3.13
  • Python: 3.9.4
  • SQLAlchemy: 1.4.6
  • Database: sqlite
  • DBAPI: ?

Additional context

The provided Dockerfile is a shrunk down version of what we use:

  • A base image with build dependencies installing all libs requiring compilation (greenlet)
  • A service image that install extra libs not requiring dependencies (sqlalchemy)

I have noticed that REMOVING or MOVING the RUN apk del g++ AFTER the installation of SQL Alchemy will solve the problem.

I also tried to reproduce in debian, compiling libs instead of wheels. with this Dockerfile and could not reproduce, so maybe it’s related to Alpine OR there’s something else installed in slim-buster.

FROM python:3-slim-buster

RUN apt-get update && apt-get install -y g++

RUN pip install --upgrade pip && pip install greenlet --no-binary :all:

RUN apt-get remove -y g++

RUN pip install sqlalchemy --no-binary :all:

RUN echo '\
from sqlalchemy import create_engine \n\
from sqlalchemy.orm import sessionmaker \n\
\n\
session = sessionmaker(bind=create_engine("sqlite://"))() \n\
result = session.execute("select 1, 2, 3").fetchall() \n\
row = result[0] \n\
\n\
print(dict(row)) \n\
' > script.py

RUN python script.py

WORKAROUND Using row._asdict() will solve the problem.

Have a nice day! and thank you for your amazing work.

About this issue

  • Original URL
  • State: closed
  • Created 3 years ago
  • Comments: 33 (22 by maintainers)

Most upvoted comments

I could work around using row._asdict() which returns _mapping 😃

_asdict is the official way. The idea is that in sa 1.4+ row behaves like a named tuple with the same underscore methods https://docs.python.org/3/library/collections.html#namedtuple-factory-function-for-tuples-with-named-fields

For context on @CaselIT’s comment, 1.4.40 is the latest version in the 1.4 series.

alright well i have somethign to work on for 1.4.7

we should also keep in mind that dict(row) is deprecated in any case. you can work around this now by using row._mapping.