权限错误:[WinError 32] 进程无法访问文件,因为它正在被另一个进程使用:'./instance/test_db.sqlite

0 投票
1 回答
31 浏览
提问于 2025-04-13 14:37

我在处理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文件。我希望在通过一个fixture返回我的应用后,能够将其销毁,结构如下:

# ./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'

根据我的理解,在fixture中执行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数据库是在实例文件夹中创建的,这个文件夹相对于create_app()被调用的绝对路径(可能是在src或tests目录中)。

我找到了这个StackOverflow的帖子 Python PermissionError: [WinError 32] 该进程无法访问文件.....但我的文件是关闭的,我尝试在fixture的销毁部分明确关闭会话,像这样:

@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')

但这也没有帮助。还有一点奇怪的是,在最后一个例子中,我可以在yield app之后导入db_session,因为在其他任何测试用例中,如果我尝试在应用上下文之外进行这个导入,测试都会失败。

请问有什么建议吗?

1 个回答

0

好的,我再查了一下,发现了这个帖子:https://stackoverflow.com/a/21742461/9280629

看起来问题不是出在关闭会话上,而是因为引擎连接还在活跃。一旦我用 dispose() 函数处理掉我的引擎,sqlite3 的数据库文件就可以成功删除了。

撰写回答