skip to Main Content

I am trying and failing to read a local .accdb file in my Python 3.11 app, which is running in an python:3.11-alpine container.

My Dockerfile executes without errors:

FROM python:3.11-alpine

EXPOSE 5001
ENV PYTHONDONTWRITEBYTECODE=1
ENV PYTHONUNBUFFERED=1
RUN apk update && apk add --no-cache gcc g++ musl-dev unixodbc-dev flex bison gawk
COPY requirements.txt .
RUN python -m pip install -r requirements.txt
RUN apk add --no-cache git autoconf automake libtool gettext-dev make
RUN git clone https://github.com/mdbtools/mdbtools.git
WORKDIR /mdbtools
RUN autoreconf -i -f
RUN ./configure --with-unixodbc=/usr --disable-dependency-tracking
RUN make
RUN make install
RUN echo -e "n[MDBTools]nDescription=MDBTools DrivernDriver=/usr/local/lib/odbc/libmdbodbc.so" >> /etc/odbcinst.ini
RUN apk add --no-cache nano

WORKDIR /app
COPY . /app
RUN adduser -u 5678 --disabled-password --gecos "" appuser && chown -R appuser /app
USER appuser

CMD ["python", "server.py"]

My Python script (accdb_test.py):

import pyodbc
import argparse

parser = argparse.ArgumentParser(description='Connect to an Access database.')
parser.add_argument('db_path', type=str, help='The path to the Access database')

args = parser.parse_args()

conn_str = (
    r'DRIVER={MDBTools};'
    r'DBQ=' + args.db_path + ';'
)
try:
    conn = pyodbc.connect(conn_str)
    print("Connection successful!")
except pyodbc.Error as e:
    print("Failed to connect to the database:", e)

I build the container connect to its terminal, than I run the script with this result:

/app $ python accdb_test.py /app/input_examples/caesar/MODEL_13-16_R01.ACCDB
['MDBTools']
File not found
File not found
Unable to locate database
Failed to connect to the database: ('HY000', 'The driver did not supply an error!')

The path to the .accdb file is correct, I checked:

/app $ ls -l /app/input_examples/caesar/MODEL_13-16_R01.ACCDB
-rwxrwxrwx    1 appuser  root      47116288 Mar 18 09:29 /app/input_examples/caesar/MODEL_13-16_R01.ACCDB

2

Answers


  1. As far as I can tell, mdbtools expects a 2-component connection string, with only a single semicolon.

    Since you end your connection string with a semicolon, it is looking for a file named /app/input_examples/caesar/MODEL_13-16_R01.ACCDB; and cannot find that file.

    This can be seen here in the source, it’s splitting the connection string into a maximum of 2 components, where any further separators and components get added to the file name.

    The fix is simple: remove the semicolon:

    conn_str = (
        r'DRIVER={MDBTools};'
        r'DBQ=' + args.db_path
    )
    
    Login or Signup to reply.
  2. The way mdbtools is being built in the original Dockerfile causes the g_strsplit() function (used here) to malfunction. The following Dockerfile allows g_strsplit() to work correctly and the .connect() will not fail when DBQ= has a trailing semicolon.

    FROM python:3.11-alpine
    
    RUN apk update
    RUN apk --no-cache add 
        build-base 
        autoconf 
        automake 
        glib 
        glib-dev 
        libc-dev 
        libtool 
        bison 
        flex-dev 
        unixodbc 
        unixodbc-dev 
        git
    
    RUN python -m pip install pyodbc
    
    RUN git clone https://github.com/mdbtools/mdbtools.git
    WORKDIR /mdbtools
    RUN autoreconf -i -f
    RUN ./configure --with-unixodbc=/usr --disable-man
    RUN make
    RUN make install
    
    RUN echo -e "n[MDBTools]nDescription=MDBTools DrivernDriver=/usr/local/lib/odbc/libmdbodbc.so" >> /etc/odbcinst.ini
    
    WORKDIR /app
    COPY accdb_test.py accdb_test.py
    COPY ansi92test.accdb ansi92test.accdb
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search