I. Preface: The application directory structure and modules are listed at the end of the post.
II. Statement of the Problem: If the PYTHONPATH is not set the application runs, but the unittest fails with the ImportError: No module named models.transactions. This happens when trying to import
Transactions in app.py. If the PYTHONPATH is set to /sandbox/app
both the application and
unittest run with no errors. The constraints for a solution are that the PYTHONPATH should not have to be set, and
the sys.path should not have to be modified programmatically.
III. Details: Consider the case when the PYTHONPATH is set and the test_app.py
is run as a package /sandbox$ python -m unittest tests.test_app
. Looking at the print statements for __main__
sprinkled throughout the code:
models : app.models.transactions
models : models.transactions
resources: app.resources.transactions
app : app.app
test : tests.test_app
The unittest imports the app first, and so there is app.models.transactions
. The next import that the app
attempts is resources.transactions
. When it is imported it makes its own import of models.transactions
, and
then we see the __name__
for app.resources.transactions
. This is followed by the app.app
import, and then finally the unittest module tests.test.app
. Setting the PYTHONPATH allows the application to resolve models.transactions!
One solution is to put the models.transactions
inside resources.transaction
. But is there another way to handle the problem?
For completeness, when the application is run the print statements for __main__
are:
models : models.transactions
resources: resources.transactions
app : __main__
This is expected, and no imports are being attempted which are above /sandbox/app
or sideways.
IV. Appendix
A.1 Directory Structure:
|-- sandbox
|-- app
|-- models
|-- __init__.py
|-- transactions.py
|-- resources
|-- __init__.py
|-- transactions.py
|-- __init__.py
|-- app.py
|-- tests
|-- __init__.py
|-- test_app.py
A.2 Modules:
(1) app:
from flask import Flask
from models.transactions import TransactionsModel
from resources.transactions import Transactions
print ' app : ', __name__
def create_app():
app = Flask(__name__)
return app
app = create_app()
if __name__ == '__main__':
app.run(host='127.0.0.1', port=5000, debug=True)
(2) models.transactions
print ' model : ', __name__
class TransactionsModel:
pass
(3) resources.transactions:
from models.transactions import TransactionsModel
print ' resources: ', __name__
class Transactions:
pass
(4) tests.test_app
import unittest
from app.app import create_app
from app.resources.transactions import Transactions
print ' test : ', __name__
class DonationTestCase(unittest.TestCase):
def setUp(self):
pass
def tearDown(self):
pass
def test_transactions_get_with_none_ids(self):
self.assertEqual(0, 0)
if __name__ == '__main__':
unittest.main()