33

I want to use alembic revision --autogenerate with my own model classes. Because of that I need to import them in myproject/alembic/env.py as described in the docs. But this doesn't work even if I tried a lot of variations.

I am not sure in which context (don't know if this is the correct word) does alembic run the env.py. Maybe that causes some errors.

This is the directory and file structure I use.

myproject/
    common/
        __init__.py
        model.py
    alembic/
        env.py

The error is kind of that

    from .common import model
SystemError: Parent module '' not loaded, cannot perform relative import

myproject itself is just a repository/working directory. It is not installed into the system (with pip3, apt-get, easyinstall or anything else).

4 Answers4

29

You can set the PYTHONPATH environment variable to control what python sees as the top level folder, eg. if you are in the root folder of your project:

PYTHONPATH=. alembic revision -m "..."

Then you can use a "normal" import in your alembic env.py, relative to your root folder, in your example:

from src.models.base import Base
K. Norbert
  • 10,138
  • 4
  • 45
  • 46
20

Fiddling around few hours with this same issue, I found out a solution. First, this is my structure right now:

. ← That's the root directory of my project
├── alembic.ini
├── dev-requirements.txt
├── requirements.txt
├── runtime.txt
├── setup.cfg
├── src
│   └── models
│       ├── base.py
│       ...
│       └── migrations
│           ├── env.py
│           ├── README
│           ├── script.py.mako
│           └── versions
│          
└── tests

in env.py I simply did this:

import sys
from os.path import abspath, dirname
sys.path.insert(0, dirname(dirname(dirname(abspath(__file__))))) # Insert <.>/src
import models # now it can be imported
target_metadata = models.base.Base.metadata

Hope you find this useful! :)

EDIT: I then did my first revision with the database empty (with no tables yet), alembic filled everything automatically for upgrade() and downgrade(). I did that in this way because not all my tables were automagically detected by alembic.

shackra
  • 364
  • 1
  • 12
  • 47
  • Side Note: You will need to adjust your alembic.init `script_location` to your new migrations folder path – Cobalt Jul 23 '20 at 21:09
17

Put this in your env.py to put the working directory onto the Python path:

import sys
import os

sys.path.insert(0, os.getcwd())
Joe Heffer
  • 299
  • 4
  • 6
  • Didn't work for me. I used `sys.path.insert(0, os.path.dirname(os.path.dirname(__file__)))` from this tutorial - https://www.learndatasci.com/tutorials/using-databases-python-postgres-sqlalchemy-and-alembic/ – Ernest Mar 09 '21 at 08:53
0

For alembic 1.5.5 and above, add the following to your alembic.ini:

prepend_sys_path = .

From alembic documentation: this will be prepended to sys.path if present, defaults to the current working directory.

Roman Nakutnyi
  • 341
  • 2
  • 7