Search code examples
pythonflaskimportpytest

Flask pytest not able to find module


I have trawled through past posts regarding Flask import issues but I'm struggling to implement them on my particular case. Essentially, pytest cannot recognise any relative imports I make into my routing files or even my main.py

Here is my file structure

backend 
  | src / routes / budget_routes.py
  | src / routes / __init__.py

  | src / database.py
  | src / __init__.py
  | src / main.py

  | tests / test_budget_routes.py

Initially my tests were all passing with placeholder tests and no additional file imports in the budget_routes.py file

budget_routes.py (sys.path is commented out right now, and tests pass)


import sys, os
from flask import Blueprint, jsonify, request
import sqlite3

# sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '..', 'database')))
# from database import get_db


budget_routes = Blueprint('budget_routes', __name__)

@budget_routes.route('/get_budgets')
def get_budgets():
    return jsonify({'message': 'This is a placeholder response for get_budgets'})

test_budget_routes.py

import pytest
from src.main import app

@pytest.fixture
def client():
    app.config['TESTING'] = True
    with app.test_client() as client:
        yield client

def test_get_budgets(client):
    response = client.get('/get_budgets')
    assert response.status_code == 200
    assert b'This is a placeholder response for get_budgets' in response.data

However, when I uncomment the sys.path etc to try and pull in the database into the budget_routes.py file, the test throws this error

============================= ERRORS =============================
__________ ERROR collecting tests/test_budget_routes.py __________
ImportError while importing test module '/Users/sidraiqbal/flask_expense_apr24/backend/tests/test_budget_routes.py'.
Hint: make sure your test modules/packages have valid Python names.
Traceback:
/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/importlib/__init__.py:127: in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
tests/test_budget_routes.py:2: in <module>
    from src.main import app
src/main.py:2: in <module>
    from src.routes.budget_routes import budget_routes
src/routes/budget_routes.py:6: in <module>
    from database import get_db
E   ModuleNotFoundError: No module named 'database'

Here is my main.py too for reference

from flask import Flask
from src.routes.budget_routes import budget_routes
from src.database import get_db

app = Flask(__name__)
app.config['DEBUG'] = True
app.config['DATABASE'] = 'budget.db'

# Create SQLite database and table
def create_table():
    with app.app_context():
        db = get_db()
        c = db.cursor()
        c.execute('''CREATE TABLE IF NOT EXISTS budget
                    (id INTEGER PRIMARY KEY AUTOINCREMENT,
                    category TEXT,
                    amount REAL,
                    date DATETIME NOT NULL DEFAULT(datetime('now'))
                    )''')
        db.commit()

def close_connection(exception):
    db = getattr(g, '_database', None)
    if db is not None:
        db.close()

# Route for homepage
@app.route('/')
def home():
    return "<p>Hello</p>"

app.register_blueprint(budget_routes)

if __name__ == '__main__':
    create_table()  # Create the table when the app starts
    app.run()
  • I was expecting Pytest to find my database module
  • I have tried to adjust the database imports using .. notation as I saw this somewhere and it did not help
  • I also tried looking if the issue was with the main.py file importing the route via from src.routes.budget_routes instead of just from routes.budget_routes, but when I remove the src it fails with not being able to find the route folder. To be honest, I am also confused why it's working with the src. appended as I assumed it would need to move out of src and into routes, but I am new to Flask

Solution

  • from database import get_db assumes that database is at the same level as routes.budget_routes. I don't think that's the case. I think if you use from src.database import get_db it should work.