El_Eze El_Eze - 6 months ago 43
Python Question

Python: import models in sub package

I'm pretty new to Python and I have been battling with the import for quit a bit now. I can't fully wrap my head around this concept. I have experience in ruby where the import concept is quite different.

1. The situations
I have this package

├── convortal
│   ├── dbconf.yaml
│   ├── helpers.py
│   ├── __init__.py
│   ├── models
│   │   ├── company.py
│   │   ├── country.py
│   │   ├── ez_key.py
│   │   ├── __init__.py
│   │   ├── __init__.pyc
│   │   ├── product_function.py
│   │   ├── __pycache__
│   │   │   ├── company.cpython-34.pyc
│   │   │   └── __init__.cpython-34.pyc
│   │   └── traveler_profile.py
│   └── __pycache__
│   └── __init__.cpython-34.pyc
├── README.md
├── requirements.txt
└── setup.py


convortal/__init___.py

import sys
from convortal.models import *
import convortal.helpers as hp

from dbconn import CtrlSession
from sqlalchemy import desc

# DECLARATIONS FOR SETUP.PY
APP_NAME = 'convortal'
__versionnum__ = ('0','0','1')
APP_VERSION = '.'.join([i for i in __versionnum__])

def convortal(argv):
....(code to read file and update DB)


convortal/models/__init__.py

__all__ = [
'Company',
'Country',
'EzKey',
'ProductFunction',
'TravelerProfile',
]

from dbconn import DBconn
from convortal.models.company import Company
from convortal.models.country import Country
from convortal.models.ez_key import EzKey
from convortal.models.product_function import ProductFunction
from convortal.models.traveler_profile import TravelerProfile
# create a connection to the DB
conn = DBconn('PROD')
# instantiate a Base object with this connection
Base = conn.Base()


Company model: convortal/models/company.py

import convortal
from sqlalchemy import Table, Column, Integer, ForeignKey, UniqueConstraint
from sqlalchemy.orm import relationship
from models import Base

class Company(Base):
...company table with autoload


What I want to achieve

I'm trying to create a package that can be imported to use this code with a routine that checks on a directory, collects a file with users and using this package updates, creates, or deactivates this users.

Also I'm trying to test this from the command line executing the app like this

(venv) ➜ convortal git:(master) ✗ python convortal/__init__.py


The
__init__.py
has the if statement

if __name__ == '__main__':
convortal(sys.argv[1:])


running this command should exit the app and show a message with a help string showing the arguments needed to execute the app.

The problem

I'm stuck with this error:

Traceback (most recent call last):
File "convortal/__init__.py", line 2, in <module>
from convortal.models import *
ImportError: No module named 'convortal'

Answer

Finally after battling for a week with my manager helping, we found the solution. I just want to share it in case someone else is having the same issue.

project layout

├── dbconf.yaml
├── helpers.py
├── __init__.py
└── models
    ├── company.py
    ├── country.py
    ├── ez_key.py
    ├── __init__.py
    ├── product_function.py
    └── traveler_profile.py

convortal/__init__.py

import sys
from . models import *
from . import helpers as hp
from sqlalchemy import desc

# DECLARATIONS FOR SETUP.PY
APP_NAME = 'convortal'
__versionnum__ = ('0','0','1')
APP_VERSION = '.'.join([i for i in __versionnum__])

def convortal(site_path, country_abbr):
....(code to read file and update DB)

convortal/models/__init__.py

__all__ = [
    'Company',
    'Country',
    'EzKey',
    'ProductFunction',
    'TravelerProfile',
]

from dbconn import DBconn
# create a connection to the DB
conn = DBconn('prod')
# instantiate a Base object with this connection
Base = conn.Base()

from . company import Company
from . country import Country
from . ez_key import EzKey
from . product_function import ProductFunction
from . traveler_profile import TravelerProfile

Company model: convortal/models/company.py

from sqlalchemy import Table, Column, Integer, ForeignKey, UniqueConstraint
from sqlalchemy.orm import relationship
from .. models import Base

class Company(Base):
...company table with autoload

With this layout I was able to query the DB from convortal/__init__.py and maintain the relations between the tables.

To execute a request, in this case you would have to follow this steps: 1. instantiate a session:

session = convortal.models.conn.get_session()

  1. make the request

qtest = session.query(convortal.models.EzCompany).filter_by(some_property=value)

The order in the convortal/models/__init__.py matters. Because I'm using Base in the rest of the modules in models package I had to create the Base variable before importing the models

It needs to be refactor to not use from . models import *