我在拆除我的 pytest 上下文时遇到了麻烦。 我有一个 Flask 应用程序,它在我的实例目录中创建 sqlite3 数据库,如下所示:
# ./src/app_factory/__init__.py
def create_app():
app = Flask(__name__, instance_path=f'{os.path.abspath("instance")}', instance_relative_config=True, template_folder='templates')
# some code here
with app.app_context():
from database.database_factory import init_db
init_db()
# some other code here
return app
init_db()
函数定义如下:
# ./src/database/database_factory.py
engine = create_engine(current_app.config['SQLALCHEMY_DATABASE_URI'])
db_session = scoped_session(sessionmaker(autocommit=False,
autoflush=False,
bind=engine))
def init_db():
from database.models import Base, Table1, Table2, Table3, Table4
Base.metadata.create_all(bind=engine,
tables=[Table1.__table__, Table2.__table__, Table3.__table__, Table4.__table__])
@current_app.teardown_appcontext
def shutdown_session(exception=None):
db_session.remove()
我正在为此应用程序编写一些测试,但在测试后删除
./tests/instance/test_db.sqlite
文件时遇到问题。我想在将我的应用程序放在固定装置中后将其拆掉,如下所示:
# ./tests/unit/conftest.py
@pytest.fixture()
def app():
app = create_app()
yield app
os.remove('./instance/test_db.sqlite')
测试失败,并出现错误“PermissionError:[WinError 32]该进程无法访问该文件,因为该文件正在被另一个进程使用:'./instance/test_db.sqlite'”
据我了解,在固定装置中的
yield app
之后,应用程序上下文应该不再可用,因此scoped_session
应该关闭。所以我不明白是什么导致了这个问题,我什至不确定活动的应用程序上下文是否是这个错误的原因。
我不确定它是否相关,但我的应用程序的布局如下所示:
.
├── src/
│ ├── app_factory/
│ │ └── __init__.py
│ ├── database/
│ │ └── database_factory.py
│ └── instance/
│ └── test_db.sqlite
└── tests/
├── unit/
│ ├── conftest.py (this has fixtures)
│ └── test_db.py
└── instance/
└── test_db.sqlite (I want to delete this one as part of teardown)
sqlite3 db 在实例文件夹中创建,该文件夹相对于调用
create_app()
的绝对路径(在 src 或测试目录中)。
我发现了这篇SO帖子Python PermissionError:[WinError 32]进程无法访问文件.....但我的文件已关闭并且我尝试在固定装置的拆卸部分中显式关闭会话,如下所示:
@pytest.fixture()
def app():
app = create_app()
yield app
from database.database_factory import db_session
db_session.close()
db_session.remove()
os.remove('./instance/test_db.sqlite')
但这也没有帮助。同样奇怪的是,在最后一个示例中,我可以在
db_session
之后导入 yield app
,因为在任何其他测试用例中,如果我尝试在应用程序上下文之外执行此导入,测试都会失败。
请大家多多指教。
好吧,我又搜索了一下,发现了这篇文章:https://stackoverflow.com/a/21742461/9280629
看起来问题不在于关闭会话,而在于引擎连接处于活动状态。一旦我用
dispose()
功能处理了我的引擎,sqlite3 db文件就可以成功删除。