summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCoprDistGit <infra@openeuler.org>2023-04-11 00:17:13 +0000
committerCoprDistGit <infra@openeuler.org>2023-04-11 00:17:13 +0000
commitf5a4d2525976c604644b8aed5c3385268bec2468 (patch)
tree669f8282a8690cb77d5ec36353122f229b471731
parent4b587bb20d63f983f4d373c6bd4dc571beb14522 (diff)
automatic import of python-pytest-flask-sqlalchemy
-rw-r--r--.gitignore1
-rw-r--r--python-pytest-flask-sqlalchemy.spec1670
-rw-r--r--sources1
3 files changed, 1672 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
index e69de29..5215f46 100644
--- a/.gitignore
+++ b/.gitignore
@@ -0,0 +1 @@
+/pytest-flask-sqlalchemy-1.1.0.tar.gz
diff --git a/python-pytest-flask-sqlalchemy.spec b/python-pytest-flask-sqlalchemy.spec
new file mode 100644
index 0000000..b15ef54
--- /dev/null
+++ b/python-pytest-flask-sqlalchemy.spec
@@ -0,0 +1,1670 @@
+%global _empty_manifest_terminate_build 0
+Name: python-pytest-flask-sqlalchemy
+Version: 1.1.0
+Release: 1
+Summary: A pytest plugin for preserving test isolation in Flask-SQlAlchemy using database transactions.
+License: MIT
+URL: https://github.com/jeancochrane/pytest-flask-sqlalchemy
+Source0: https://mirrors.nju.edu.cn/pypi/web/packages/62/96/5cedf543603e19c4076c57628f06daeb211c5a770a35eafa39628e4d035f/pytest-flask-sqlalchemy-1.1.0.tar.gz
+BuildArch: noarch
+
+Requires: python3-pytest
+Requires: python3-pytest-mock
+Requires: python3-SQLAlchemy
+Requires: python3-Flask-SQLAlchemy
+Requires: python3-packaging
+Requires: python3-pytest-postgresql
+Requires: python3-psycopg2-binary
+Requires: python3-pytest
+
+%description
+# pytest-flask-sqlalchemy
+
+[![Build Status](https://travis-ci.org/jeancochrane/pytest-flask-sqlalchemy.svg?branch=master)](https://travis-ci.org/jeancochrane/pytest-flask-sqlalchemy) ![PyPI - Python Version](https://img.shields.io/pypi/pyversions/Django.svg)
+
+A [pytest](https://docs.pytest.org/en/latest/) plugin providing fixtures for running tests in
+transactions using [Flask-SQLAlchemy](http://flask-sqlalchemy.pocoo.org/latest/).
+
+## Contents
+
+- [**Motivation**](#motivation)
+- [**Quick examples**](#quick-examples)
+- [**Usage**](#usage)
+ - [Installation](#installation)
+ - [From PyPi](#from-pypi)
+ - [Development version](#development-version)
+ - [Supported backends](#supported-backends)
+ - [Configuration](#configuration)
+ - [Conftest setup](#conftest-setup)
+ - [Test configuration](#test-configuration)
+ - [`mocked-engines`](#mocked-engines)
+ - [`mocked-sessions`](#mocked-sessions)
+ - [`mocked-sessionmakers`](#mocked-sessionmakers)
+ - [Writing transactional tests](#writing-transactional-tests)
+ - [Fixtures](#fixtures)
+ - [`db_session`](#db_session)
+ - [`db_engine`](#db_engine)
+ - [Enabling transactions without fixtures](#enabling-transactions-without-fixtures)
+- [**Development**](#development)
+ - [Running the tests](#running-the-tests)
+ - [Acknowledgements](#acknowledgements)
+ - [Copyright](#copyright)
+
+## <a name="motivation"></a>Motivation
+
+Inspired by [Django's built-in support for transactional
+tests](https://jeancochrane.com/blog/django-test-transactions), this plugin
+seeks to provide comprehensive, easy-to-use Pytest fixtures for wrapping tests in
+database transactions for [Flask-SQLAlchemy](http://flask-sqlalchemy.pocoo.org/latest/)
+apps. The goal is to make testing stateful Flask-SQLAlchemy applications easier by
+providing fixtures that permit the developer to **make arbitrary database updates
+with the confidence that any changes made during a test will roll back** once the test exits.
+
+## <a name="quick-examples"></a>Quick examples
+
+Use the [`db_session` fixture](#db_session) to make **database updates that won't persist beyond
+the body of the test**:
+
+```python
+def test_a_transaction(db_session):
+ row = db_session.query(Table).get(1)
+ row.name = 'testing'
+
+ db_session.add(row)
+ db_session.commit()
+
+def test_transaction_doesnt_persist(db_session):
+ row = db_session.query(Table).get(1)
+ assert row.name != 'testing'
+```
+
+The [`db_engine` fixture](#db_engine) works the same way, but **copies the API of
+SQLAlchemy's [Engine
+object](http://docs.sqlalchemy.org/en/latest/core/connections.html#sqlalchemy.engine.Engine)**:
+
+```python
+def test_a_transaction_using_engine(db_engine):
+ with db_engine.begin() as conn:
+ row = conn.execute('''UPDATE table SET name = 'testing' WHERE id = 1''')
+
+def test_transaction_doesnt_persist(db_engine):
+ row_name = db_engine.execute('''SELECT name FROM table WHERE id = 1''').fetchone()[0]
+ assert row_name != 'testing'
+```
+
+Use [configuration properties](#test-configuration) to
+**mock database connections in an app and enforce nested transactions**,
+allowing any method from the codebase to run inside a test with the assurance
+that any database changes made will be rolled back at the end of the test:
+
+```ini
+# In setup.cfg
+
+[tool:pytest]
+mocked-sessions=database.db.session
+mocked-engines=database.engine
+```
+
+```python
+# In database.py
+
+db = flask_sqlalchemy.SQLAlchemy()
+engine = sqlalchemy.create_engine('DATABASE_URI')
+```
+
+```python
+# In models.py
+
+class Table(db.Model):
+ __tablename__ = 'table'
+ id = db.Column(db.Integer, primary_key=True)
+ name = db.Column(db.String(80))
+
+ def set_name(new_name):
+ self.name = new_name
+ db.session.add(self)
+ db.session.commit()
+```
+
+```python
+# In tests/test_set_name.py
+
+def test_set_name(db_session):
+ row = db_session.query(Table).get(1)
+ row.set_name('testing')
+ assert row.name == 'testing'
+
+def test_transaction_doesnt_persist(db_session):
+ row = db_session.query(Table).get(1)
+ assert row.name != 'testing'
+```
+
+# <a name="usage"></a>Usage
+
+## <a name="installation"></a>Installation
+
+### <a name="from-pypi"></a>From PyPi
+
+Install using pip:
+
+```
+pip install pytest-flask-sqlalchemy
+```
+
+Once installed, pytest will detect the plugin automatically during test collection.
+For basic background on using third-party plugins with pytest, see the [pytest
+documentation](https://docs.pytest.org/en/latest/plugins.html?highlight=plugins).
+
+### <a name="development-version"></a>Development version
+
+Clone the repo from GitHub and switch into the new directory:
+
+```
+git clone git@github.com:jeancochrane/pytest-flask-sqlalchemy.git
+cd pytest-flask-sqlalchemy
+```
+
+You can install using pip:
+
+```
+pip install .
+```
+
+### <a name="supported-backends"></a>Supported backends
+
+So far, pytest-flask-sqlalchemy has been most extensively tested against
+PostgreSQL 9.6. It should theoretically work with any backend that is supported
+by SQLAlchemy, but Postgres is the only backend that is currently tested by the
+test suite.
+
+Official support for SQLite and MySQL is [planned for a future
+release](https://github.com/jeancochrane/pytest-flask-sqlalchemy/issues/3).
+In the meantime, if you're using one of those backends and you run in to
+problems, we would greatly appreciate your help! [Open an
+issue](https://github.com/jeancochrane/pytest-flask-sqlalchemy/issues/new) if
+something isn't working as you expect.
+
+## <a name="configuration"></a>Configuration
+
+### <a name="conftest-setup"></a>Conftest setup
+
+This plugin assumes that a fixture called `_db` has been
+defined in the root conftest file for your tests. The `_db` fixture should
+expose access to a valid [SQLAlchemy `Session` object](http://docs.sqlalchemy.org/en/latest/orm/session_api.html?highlight=session#sqlalchemy.orm.session.Session) that can interact with your database,
+for example via the [`SQLAlchemy` initialization class](http://flask-sqlalchemy.pocoo.org/2.3/api/#flask_sqlalchemy.SQLAlchemy)
+that configures Flask-SQLAlchemy.
+
+The fixtures in this plugin depend on this `_db` fixture to access your
+database and create nested transactions to run tests in. **You must define
+this fixture in your `conftest.py` file for the plugin to work.**
+
+An example setup that will produce a valid `_db` fixture could look like this
+(this example comes from the [test setup](./tests/_conftest.py#L25-L61) for this repo):
+
+```python
+@pytest.fixture(scope='session')
+def database(request):
+ '''
+ Create a Postgres database for the tests, and drop it when the tests are done.
+ '''
+ pg_host = DB_OPTS.get("host")
+ pg_port = DB_OPTS.get("port")
+ pg_user = DB_OPTS.get("username")
+ pg_db = DB_OPTS["database"]
+
+ init_postgresql_database(pg_user, pg_host, pg_port, pg_db)
+
+ @request.addfinalizer
+ def drop_database():
+ drop_postgresql_database(pg_user, pg_host, pg_port, pg_db, 9.6)
+
+
+@pytest.fixture(scope='session')
+def app(database):
+ '''
+ Create a Flask app context for the tests.
+ '''
+ app = Flask(__name__)
+
+ app.config['SQLALCHEMY_DATABASE_URI'] = DB_CONN
+
+ return app
+
+
+@pytest.fixture(scope='session')
+def _db(app):
+ '''
+ Provide the transactional fixtures with access to the database via a Flask-SQLAlchemy
+ database connection.
+ '''
+ db = SQLAlchemy(app=app)
+
+ return db
+```
+
+Alternatively, if you already have a fixture that sets up database access for
+your tests, you can define `_db` to return that fixture directly:
+
+```python
+@pytest.fixture(scope='session')
+def database():
+ # Set up all your database stuff here
+ # ...
+ return db
+
+@pytest.fixture(scope='session')
+def _db(database):
+ return database
+```
+
+### <a name="test-configuration"></a>Test configuration
+
+This plugin allows you to configure a few different properties in a
+`setup.cfg` test configuration file in order to handle the specific database connection needs
+of your app. For basic background on setting up pytest configuration files, see
+the [pytest docs](https://docs.pytest.org/en/latest/customize.html#adding-default-options).
+
+All three configuration properties ([`mocked-engines`](#mocked-engines),
+[`mocked-sessions`](#mocked-sessions), and [`mocked-sessionmakers`](#mocked-sessionmakers))
+work by **[patching](https://docs.python.org/3/library/unittest.mock.html#unittest.mock.patch)
+one or more specified objects during a test**, replacing them with equivalent objects whose
+database interactions will run inside of a transaction and ultimately be
+rolled back when the test exits. Using these patches, you can call methods from
+your codebase that alter database state with the knowledge that no changes will persist
+beyond the body of the test.
+
+The configured patches are only applied in tests where a transactional fixture
+(either [`db_session`](#db_session) or [`db_engine`](#db_engine)) is included
+in the test function arguments.
+
+#### <a name="mocked-engines"></a>`mocked-engines`
+
+The `mocked-engines` property directs the plugin to [patch](https://docs.python.org/3/library/unittest.mock.html#unittest.mock.patch)
+objects in your codebase, typically SQLAlchemy [Engine](http://docs.sqlalchemy.org/en/latest/core/connections.html#sqlalchemy.engine.Engine)
+instances, replacing them with the [`db_engine` fixture](#db_engine) such that
+any database updates performed by the objects get rolled back at the end of
+the test.
+
+The value for this property should be formatted as a whitespace-separated list
+of standard Python import paths, like `database.engine`. This property is **optional**.
+
+Example:
+
+```python
+# In database.py
+
+engine = sqlalchemy.create_engine(DATABASE_URI)
+```
+
+```ini
+# In setup.cfg
+
+[tool:pytest]
+mocked-engines=database.engine
+```
+
+To patch multiple objects at once, separate the paths with a whitespace:
+
+```ini
+# In setup.cfg
+
+[tool:pytest]
+mocked-engines=database.engine database.second_engine
+```
+
+#### <a name="mocked-sessions"></a>`mocked-sessions`
+
+The `mocked-sessions` property directs the plugin to [patch](https://docs.python.org/3/library/unittest.mock.html#unittest.mock.patch)
+objects in your codebase, typically SQLAlchemy [Session](http://docs.sqlalchemy.org/en/latest/core/connections.html#sqlalchemy.engine.Engine)
+instances, replacing them with the [`db_session`](#db_session) fixture such that
+any database updates performed by the objects get rolled back at the end of
+the test.
+
+The value for this property should be formatted as a whitespace-separated list
+of standard Python import paths, like `database.db.session`. This property is **optional**.
+
+Example:
+
+```python
+# In database.py
+
+db = SQLAlchemy()
+```
+
+```ini
+# In setup.cfg
+
+[tool:pytest]
+mocked-sessions=database.db.session
+```
+
+To patch multiple objects at once, separate the paths with a whitespace:
+
+```ini
+# In setup.cfg
+
+[tool:pytest]
+mocked-sessions=database.db.session database.second_db.session
+```
+
+#### <a name="mocked-sessionmakers"></a>`mocked-sessionmakers`
+
+The `mocked-sessionmakers` property directs the plugin to [patch](https://docs.python.org/3/library/unittest.mock.html#unittest.mock.patch)
+objects in your codebase, typically instances of [SQLAlchemy's `sessionmaker`
+factory](http://docs.sqlalchemy.org/en/latest/orm/session_api.html?highlight=sessionmaker#sqlalchemy.orm.session.sessionmaker),
+replacing them with a mocked class that will return the transactional
+[`db_session`](#db_session) fixture. This can be useful if you have
+pre-configured instances of sessionmaker objects that you import in the code
+to spin up sessions on the fly.
+
+The value for this property should be formatted as a whitespace-separated list
+of standard Python import paths, like `database.WorkerSessionmaker`. This property is **optional**.
+
+Example:
+
+```python
+# In database.py
+
+WorkerSessionmaker = sessionmaker()
+```
+
+```ini
+[tool:pytest]
+mocked-sessionmakers=database.WorkerSessionmaker
+```
+
+To patch multiple objects at once, separate the paths with a whitespace.
+
+```ini
+[tool:pytest]
+mocked-sessionmakers=database.WorkerSessionmaker database.SecondWorkerSessionmaker
+```
+
+### <a name="writing-transactional-tests"></a>Writing transactional tests
+
+Once you have your [conftest file set up](#conftest-setup) and you've [overrided the
+necessary connectables in your test configuration](#test-configuration), you're ready
+to write some transactional tests. Simply import one of the module's [transactional
+fixtures](#fixtures) in your test signature, and the test will be wrapped in a transaction.
+
+Note that by default, **tests are only wrapped in transactions if they import one of
+the [transactional fixtures](#fixtures) provided by this module.** Tests that do not
+import the fixture will interact with your database without opening a transaction:
+
+```python
+# This test will be wrapped in a transaction.
+def transactional_test(db_session):
+ ...
+
+# This test **will not** be wrapped in a transaction, since it does not import a
+# transactional fixture.
+def non_transactional_test():
+ ...
+```
+
+The fixtures provide a way for you to control which tests require transactions and
+which don't. This is often useful, since avoiding transaction setup can speed up
+tests that don't interact with your database.
+
+For more information about the transactional fixtures provided by this module, read on
+to the [fixtures section](#fixtures). For guidance on how to automatically enable
+transactions without having to specify fixtures, see the section on [enabling transactions
+without fixtures](#enabling-transactions-without-fixtures).
+
+## <a name="fixtures"></a>Fixtures
+
+This plugin provides two fixtures for performing database updates inside nested
+transactions that get rolled back at the end of a test: [`db_session`](#db_session) and
+[`db_engine`](#db_engine). The fixtures provide similar functionality, but
+with different APIs.
+
+### <a name="db_session"></a>`db_session`
+
+The `db_session` fixture allows you to perform direct updates that will be
+rolled back when the test exits. It exposes the same API as [SQLAlchemy's
+`scoped_session` object](http://docs.sqlalchemy.org/en/latest/orm/contextual.html#sqlalchemy.orm.scoping.scoped_session).
+
+Including this fixture as a function argument of a test will activate any mocks that are defined
+by the configuration properties [`mocked-engines`](#mocked-engines), [`mocked-sessions`](#mocked-sessions),
+or [`mocked-sessionmakers`](#mocked-sessionmakers) in the test configuration file for
+the duration of that test.
+
+Example:
+
+```python
+def test_a_transaction(db_session):
+ row = db_session.query(Table).get(1)
+ row.name = 'testing'
+
+ db_session.add(row)
+ db_session.commit()
+
+def test_transaction_doesnt_persist(db_session):
+ row = db_session.query(Table).get(1)
+ assert row.name != 'testing'
+```
+
+### <a name="db_engine"></a>`db_engine`
+
+Like [`db_session`](#db_session), the `db_engine` fixture allows you to perform direct updates
+against the test database that will be rolled back when the test exits. It is
+an instance of Python's built-in [`MagicMock`](https://docs.python.org/3/library/unittest.mock.html#unittest.mock.MagicMock)
+class, with a spec set to match the API of [SQLAlchemy's
+`Engine`](http://docs.sqlalchemy.org/en/latest/core/connections.html#sqlalchemy.engine.Engine) object.
+
+Only a few `Engine` methods are exposed on this fixture:
+
+- `db_engine.begin`: begin a new nested transaction ([API docs](http://docs.sqlalchemy.org/en/latest/core/connections.html#sqlalchemy.engine.Engine.begin))
+- `db_engine.execute`: execute a raw SQL query ([API docs](http://docs.sqlalchemy.org/en/latest/core/connections.html#sqlalchemy.engine.Engine.execute))
+- `db_engine.raw_connection`: return a raw DBAPI connection ([API docs](http://docs.sqlalchemy.org/en/latest/core/connections.html#sqlalchemy.engine.Engine.raw_connection))
+
+Since `db_engine` is an instance of `MagicMock` with an `Engine` spec, other
+methods of the `Engine` API can be called, but they will not perform any useful
+work.
+
+Including this fixture as a function argument of a test will activate any mocks that are defined
+by the configuration properties [`mocked-engines`](#mocked-engines), [`mocked-sessions`](#mocked-sessions),
+or [`mocked-sessionmakers`](#mocked-sessionmakers) in the test configuration file for
+the duration of that test.
+
+Example:
+
+```python
+def test_a_transaction_using_engine(db_engine):
+ with db_engine.begin() as conn:
+ row = conn.execute('''UPDATE table SET name = 'testing' WHERE id = 1''')
+
+def test_transaction_doesnt_persist(db_engine):
+ row_name = db_engine.execute('''SELECT name FROM table WHERE id = 1''').fetchone()[0]
+ assert row_name != 'testing'
+```
+
+## <a name="enabling-transactions-without-fixtures"></a>Enabling transactions without fixtures
+
+If you know you want to make all of your tests transactional, it can be annoying to have
+to specify one of the [fixtures](#fixtures) in every test signature.
+
+The best way to automatically enable transactions without having to include an extra fixture
+in every test is to wire up an
+[autouse fixture](https://docs.pytest.org/en/latest/fixture.html#autouse-fixtures-xunit-setup-on-steroids)
+for your test suite. This can be as simple as:
+
+```python
+# Automatically enable transactions for all tests, without importing any extra fixtures.
+@pytest.fixture(autouse=True)
+def enable_transactional_tests(db_session):
+ pass
+```
+
+In this configuration, the `enable_transactional_tests` fixture will be automatically used in
+all tests, meaning that `db_session` will also be used. This way, all tests will be wrapped
+in transactions without having to explicitly require either `db_session` or `enable_transactional_tests`.
+
+# <a name="development"></a>Development
+
+## <a name="running-the-tests"></a>Running the tests
+
+To run the tests, start by installing a development version of the plugin that
+includes test dependencies:
+
+```
+pip install -e .[tests]
+```
+
+Next, export a [database connection string](http://docs.sqlalchemy.org/en/latest/core/engines.html#database-urls)
+that the tests can use (the database referenced by the string will be created
+during test setup, so it does not need to exist):
+
+```
+export TEST_DATABASE_URL=<db_connection_string>
+```
+
+Finally, run the tests using pytest:
+
+```
+pytest
+```
+
+## <a name="acknowledgements"></a>Acknowledgements
+
+This plugin was initially developed for testing
+[Dedupe.io](https://dedupe.io), a web app for record linkage and entity
+resolution using machine learning. Dedupe.io is built and maintained
+by [DataMade](https://datamade.us).
+
+The code is greatly indebted to [Alex Michael](https://github.com/alexmic),
+whose blog post ["Delightful testing with pytest and
+Flask-SQLAlchemy"](http://alexmic.net/flask-sqlalchemy-pytest/) helped
+establish the basic approach on which this plugin builds.
+
+Many thanks to [Igor Ghisi](https://github.com/igortg/), who donated the PyPi
+package name. Igor had been working on a similar plugin and proposed combining
+efforts. Thanks to Igor, the plugin name is much stronger.
+
+## <a name="copyright"></a>Copyright
+
+Copyright (c) 2019 Jean Cochrane and DataMade. Released under the MIT License.
+
+Third-party copyright in this distribution is noted where applicable.
+
+
+
+
+%package -n python3-pytest-flask-sqlalchemy
+Summary: A pytest plugin for preserving test isolation in Flask-SQlAlchemy using database transactions.
+Provides: python-pytest-flask-sqlalchemy
+BuildRequires: python3-devel
+BuildRequires: python3-setuptools
+BuildRequires: python3-pip
+%description -n python3-pytest-flask-sqlalchemy
+# pytest-flask-sqlalchemy
+
+[![Build Status](https://travis-ci.org/jeancochrane/pytest-flask-sqlalchemy.svg?branch=master)](https://travis-ci.org/jeancochrane/pytest-flask-sqlalchemy) ![PyPI - Python Version](https://img.shields.io/pypi/pyversions/Django.svg)
+
+A [pytest](https://docs.pytest.org/en/latest/) plugin providing fixtures for running tests in
+transactions using [Flask-SQLAlchemy](http://flask-sqlalchemy.pocoo.org/latest/).
+
+## Contents
+
+- [**Motivation**](#motivation)
+- [**Quick examples**](#quick-examples)
+- [**Usage**](#usage)
+ - [Installation](#installation)
+ - [From PyPi](#from-pypi)
+ - [Development version](#development-version)
+ - [Supported backends](#supported-backends)
+ - [Configuration](#configuration)
+ - [Conftest setup](#conftest-setup)
+ - [Test configuration](#test-configuration)
+ - [`mocked-engines`](#mocked-engines)
+ - [`mocked-sessions`](#mocked-sessions)
+ - [`mocked-sessionmakers`](#mocked-sessionmakers)
+ - [Writing transactional tests](#writing-transactional-tests)
+ - [Fixtures](#fixtures)
+ - [`db_session`](#db_session)
+ - [`db_engine`](#db_engine)
+ - [Enabling transactions without fixtures](#enabling-transactions-without-fixtures)
+- [**Development**](#development)
+ - [Running the tests](#running-the-tests)
+ - [Acknowledgements](#acknowledgements)
+ - [Copyright](#copyright)
+
+## <a name="motivation"></a>Motivation
+
+Inspired by [Django's built-in support for transactional
+tests](https://jeancochrane.com/blog/django-test-transactions), this plugin
+seeks to provide comprehensive, easy-to-use Pytest fixtures for wrapping tests in
+database transactions for [Flask-SQLAlchemy](http://flask-sqlalchemy.pocoo.org/latest/)
+apps. The goal is to make testing stateful Flask-SQLAlchemy applications easier by
+providing fixtures that permit the developer to **make arbitrary database updates
+with the confidence that any changes made during a test will roll back** once the test exits.
+
+## <a name="quick-examples"></a>Quick examples
+
+Use the [`db_session` fixture](#db_session) to make **database updates that won't persist beyond
+the body of the test**:
+
+```python
+def test_a_transaction(db_session):
+ row = db_session.query(Table).get(1)
+ row.name = 'testing'
+
+ db_session.add(row)
+ db_session.commit()
+
+def test_transaction_doesnt_persist(db_session):
+ row = db_session.query(Table).get(1)
+ assert row.name != 'testing'
+```
+
+The [`db_engine` fixture](#db_engine) works the same way, but **copies the API of
+SQLAlchemy's [Engine
+object](http://docs.sqlalchemy.org/en/latest/core/connections.html#sqlalchemy.engine.Engine)**:
+
+```python
+def test_a_transaction_using_engine(db_engine):
+ with db_engine.begin() as conn:
+ row = conn.execute('''UPDATE table SET name = 'testing' WHERE id = 1''')
+
+def test_transaction_doesnt_persist(db_engine):
+ row_name = db_engine.execute('''SELECT name FROM table WHERE id = 1''').fetchone()[0]
+ assert row_name != 'testing'
+```
+
+Use [configuration properties](#test-configuration) to
+**mock database connections in an app and enforce nested transactions**,
+allowing any method from the codebase to run inside a test with the assurance
+that any database changes made will be rolled back at the end of the test:
+
+```ini
+# In setup.cfg
+
+[tool:pytest]
+mocked-sessions=database.db.session
+mocked-engines=database.engine
+```
+
+```python
+# In database.py
+
+db = flask_sqlalchemy.SQLAlchemy()
+engine = sqlalchemy.create_engine('DATABASE_URI')
+```
+
+```python
+# In models.py
+
+class Table(db.Model):
+ __tablename__ = 'table'
+ id = db.Column(db.Integer, primary_key=True)
+ name = db.Column(db.String(80))
+
+ def set_name(new_name):
+ self.name = new_name
+ db.session.add(self)
+ db.session.commit()
+```
+
+```python
+# In tests/test_set_name.py
+
+def test_set_name(db_session):
+ row = db_session.query(Table).get(1)
+ row.set_name('testing')
+ assert row.name == 'testing'
+
+def test_transaction_doesnt_persist(db_session):
+ row = db_session.query(Table).get(1)
+ assert row.name != 'testing'
+```
+
+# <a name="usage"></a>Usage
+
+## <a name="installation"></a>Installation
+
+### <a name="from-pypi"></a>From PyPi
+
+Install using pip:
+
+```
+pip install pytest-flask-sqlalchemy
+```
+
+Once installed, pytest will detect the plugin automatically during test collection.
+For basic background on using third-party plugins with pytest, see the [pytest
+documentation](https://docs.pytest.org/en/latest/plugins.html?highlight=plugins).
+
+### <a name="development-version"></a>Development version
+
+Clone the repo from GitHub and switch into the new directory:
+
+```
+git clone git@github.com:jeancochrane/pytest-flask-sqlalchemy.git
+cd pytest-flask-sqlalchemy
+```
+
+You can install using pip:
+
+```
+pip install .
+```
+
+### <a name="supported-backends"></a>Supported backends
+
+So far, pytest-flask-sqlalchemy has been most extensively tested against
+PostgreSQL 9.6. It should theoretically work with any backend that is supported
+by SQLAlchemy, but Postgres is the only backend that is currently tested by the
+test suite.
+
+Official support for SQLite and MySQL is [planned for a future
+release](https://github.com/jeancochrane/pytest-flask-sqlalchemy/issues/3).
+In the meantime, if you're using one of those backends and you run in to
+problems, we would greatly appreciate your help! [Open an
+issue](https://github.com/jeancochrane/pytest-flask-sqlalchemy/issues/new) if
+something isn't working as you expect.
+
+## <a name="configuration"></a>Configuration
+
+### <a name="conftest-setup"></a>Conftest setup
+
+This plugin assumes that a fixture called `_db` has been
+defined in the root conftest file for your tests. The `_db` fixture should
+expose access to a valid [SQLAlchemy `Session` object](http://docs.sqlalchemy.org/en/latest/orm/session_api.html?highlight=session#sqlalchemy.orm.session.Session) that can interact with your database,
+for example via the [`SQLAlchemy` initialization class](http://flask-sqlalchemy.pocoo.org/2.3/api/#flask_sqlalchemy.SQLAlchemy)
+that configures Flask-SQLAlchemy.
+
+The fixtures in this plugin depend on this `_db` fixture to access your
+database and create nested transactions to run tests in. **You must define
+this fixture in your `conftest.py` file for the plugin to work.**
+
+An example setup that will produce a valid `_db` fixture could look like this
+(this example comes from the [test setup](./tests/_conftest.py#L25-L61) for this repo):
+
+```python
+@pytest.fixture(scope='session')
+def database(request):
+ '''
+ Create a Postgres database for the tests, and drop it when the tests are done.
+ '''
+ pg_host = DB_OPTS.get("host")
+ pg_port = DB_OPTS.get("port")
+ pg_user = DB_OPTS.get("username")
+ pg_db = DB_OPTS["database"]
+
+ init_postgresql_database(pg_user, pg_host, pg_port, pg_db)
+
+ @request.addfinalizer
+ def drop_database():
+ drop_postgresql_database(pg_user, pg_host, pg_port, pg_db, 9.6)
+
+
+@pytest.fixture(scope='session')
+def app(database):
+ '''
+ Create a Flask app context for the tests.
+ '''
+ app = Flask(__name__)
+
+ app.config['SQLALCHEMY_DATABASE_URI'] = DB_CONN
+
+ return app
+
+
+@pytest.fixture(scope='session')
+def _db(app):
+ '''
+ Provide the transactional fixtures with access to the database via a Flask-SQLAlchemy
+ database connection.
+ '''
+ db = SQLAlchemy(app=app)
+
+ return db
+```
+
+Alternatively, if you already have a fixture that sets up database access for
+your tests, you can define `_db` to return that fixture directly:
+
+```python
+@pytest.fixture(scope='session')
+def database():
+ # Set up all your database stuff here
+ # ...
+ return db
+
+@pytest.fixture(scope='session')
+def _db(database):
+ return database
+```
+
+### <a name="test-configuration"></a>Test configuration
+
+This plugin allows you to configure a few different properties in a
+`setup.cfg` test configuration file in order to handle the specific database connection needs
+of your app. For basic background on setting up pytest configuration files, see
+the [pytest docs](https://docs.pytest.org/en/latest/customize.html#adding-default-options).
+
+All three configuration properties ([`mocked-engines`](#mocked-engines),
+[`mocked-sessions`](#mocked-sessions), and [`mocked-sessionmakers`](#mocked-sessionmakers))
+work by **[patching](https://docs.python.org/3/library/unittest.mock.html#unittest.mock.patch)
+one or more specified objects during a test**, replacing them with equivalent objects whose
+database interactions will run inside of a transaction and ultimately be
+rolled back when the test exits. Using these patches, you can call methods from
+your codebase that alter database state with the knowledge that no changes will persist
+beyond the body of the test.
+
+The configured patches are only applied in tests where a transactional fixture
+(either [`db_session`](#db_session) or [`db_engine`](#db_engine)) is included
+in the test function arguments.
+
+#### <a name="mocked-engines"></a>`mocked-engines`
+
+The `mocked-engines` property directs the plugin to [patch](https://docs.python.org/3/library/unittest.mock.html#unittest.mock.patch)
+objects in your codebase, typically SQLAlchemy [Engine](http://docs.sqlalchemy.org/en/latest/core/connections.html#sqlalchemy.engine.Engine)
+instances, replacing them with the [`db_engine` fixture](#db_engine) such that
+any database updates performed by the objects get rolled back at the end of
+the test.
+
+The value for this property should be formatted as a whitespace-separated list
+of standard Python import paths, like `database.engine`. This property is **optional**.
+
+Example:
+
+```python
+# In database.py
+
+engine = sqlalchemy.create_engine(DATABASE_URI)
+```
+
+```ini
+# In setup.cfg
+
+[tool:pytest]
+mocked-engines=database.engine
+```
+
+To patch multiple objects at once, separate the paths with a whitespace:
+
+```ini
+# In setup.cfg
+
+[tool:pytest]
+mocked-engines=database.engine database.second_engine
+```
+
+#### <a name="mocked-sessions"></a>`mocked-sessions`
+
+The `mocked-sessions` property directs the plugin to [patch](https://docs.python.org/3/library/unittest.mock.html#unittest.mock.patch)
+objects in your codebase, typically SQLAlchemy [Session](http://docs.sqlalchemy.org/en/latest/core/connections.html#sqlalchemy.engine.Engine)
+instances, replacing them with the [`db_session`](#db_session) fixture such that
+any database updates performed by the objects get rolled back at the end of
+the test.
+
+The value for this property should be formatted as a whitespace-separated list
+of standard Python import paths, like `database.db.session`. This property is **optional**.
+
+Example:
+
+```python
+# In database.py
+
+db = SQLAlchemy()
+```
+
+```ini
+# In setup.cfg
+
+[tool:pytest]
+mocked-sessions=database.db.session
+```
+
+To patch multiple objects at once, separate the paths with a whitespace:
+
+```ini
+# In setup.cfg
+
+[tool:pytest]
+mocked-sessions=database.db.session database.second_db.session
+```
+
+#### <a name="mocked-sessionmakers"></a>`mocked-sessionmakers`
+
+The `mocked-sessionmakers` property directs the plugin to [patch](https://docs.python.org/3/library/unittest.mock.html#unittest.mock.patch)
+objects in your codebase, typically instances of [SQLAlchemy's `sessionmaker`
+factory](http://docs.sqlalchemy.org/en/latest/orm/session_api.html?highlight=sessionmaker#sqlalchemy.orm.session.sessionmaker),
+replacing them with a mocked class that will return the transactional
+[`db_session`](#db_session) fixture. This can be useful if you have
+pre-configured instances of sessionmaker objects that you import in the code
+to spin up sessions on the fly.
+
+The value for this property should be formatted as a whitespace-separated list
+of standard Python import paths, like `database.WorkerSessionmaker`. This property is **optional**.
+
+Example:
+
+```python
+# In database.py
+
+WorkerSessionmaker = sessionmaker()
+```
+
+```ini
+[tool:pytest]
+mocked-sessionmakers=database.WorkerSessionmaker
+```
+
+To patch multiple objects at once, separate the paths with a whitespace.
+
+```ini
+[tool:pytest]
+mocked-sessionmakers=database.WorkerSessionmaker database.SecondWorkerSessionmaker
+```
+
+### <a name="writing-transactional-tests"></a>Writing transactional tests
+
+Once you have your [conftest file set up](#conftest-setup) and you've [overrided the
+necessary connectables in your test configuration](#test-configuration), you're ready
+to write some transactional tests. Simply import one of the module's [transactional
+fixtures](#fixtures) in your test signature, and the test will be wrapped in a transaction.
+
+Note that by default, **tests are only wrapped in transactions if they import one of
+the [transactional fixtures](#fixtures) provided by this module.** Tests that do not
+import the fixture will interact with your database without opening a transaction:
+
+```python
+# This test will be wrapped in a transaction.
+def transactional_test(db_session):
+ ...
+
+# This test **will not** be wrapped in a transaction, since it does not import a
+# transactional fixture.
+def non_transactional_test():
+ ...
+```
+
+The fixtures provide a way for you to control which tests require transactions and
+which don't. This is often useful, since avoiding transaction setup can speed up
+tests that don't interact with your database.
+
+For more information about the transactional fixtures provided by this module, read on
+to the [fixtures section](#fixtures). For guidance on how to automatically enable
+transactions without having to specify fixtures, see the section on [enabling transactions
+without fixtures](#enabling-transactions-without-fixtures).
+
+## <a name="fixtures"></a>Fixtures
+
+This plugin provides two fixtures for performing database updates inside nested
+transactions that get rolled back at the end of a test: [`db_session`](#db_session) and
+[`db_engine`](#db_engine). The fixtures provide similar functionality, but
+with different APIs.
+
+### <a name="db_session"></a>`db_session`
+
+The `db_session` fixture allows you to perform direct updates that will be
+rolled back when the test exits. It exposes the same API as [SQLAlchemy's
+`scoped_session` object](http://docs.sqlalchemy.org/en/latest/orm/contextual.html#sqlalchemy.orm.scoping.scoped_session).
+
+Including this fixture as a function argument of a test will activate any mocks that are defined
+by the configuration properties [`mocked-engines`](#mocked-engines), [`mocked-sessions`](#mocked-sessions),
+or [`mocked-sessionmakers`](#mocked-sessionmakers) in the test configuration file for
+the duration of that test.
+
+Example:
+
+```python
+def test_a_transaction(db_session):
+ row = db_session.query(Table).get(1)
+ row.name = 'testing'
+
+ db_session.add(row)
+ db_session.commit()
+
+def test_transaction_doesnt_persist(db_session):
+ row = db_session.query(Table).get(1)
+ assert row.name != 'testing'
+```
+
+### <a name="db_engine"></a>`db_engine`
+
+Like [`db_session`](#db_session), the `db_engine` fixture allows you to perform direct updates
+against the test database that will be rolled back when the test exits. It is
+an instance of Python's built-in [`MagicMock`](https://docs.python.org/3/library/unittest.mock.html#unittest.mock.MagicMock)
+class, with a spec set to match the API of [SQLAlchemy's
+`Engine`](http://docs.sqlalchemy.org/en/latest/core/connections.html#sqlalchemy.engine.Engine) object.
+
+Only a few `Engine` methods are exposed on this fixture:
+
+- `db_engine.begin`: begin a new nested transaction ([API docs](http://docs.sqlalchemy.org/en/latest/core/connections.html#sqlalchemy.engine.Engine.begin))
+- `db_engine.execute`: execute a raw SQL query ([API docs](http://docs.sqlalchemy.org/en/latest/core/connections.html#sqlalchemy.engine.Engine.execute))
+- `db_engine.raw_connection`: return a raw DBAPI connection ([API docs](http://docs.sqlalchemy.org/en/latest/core/connections.html#sqlalchemy.engine.Engine.raw_connection))
+
+Since `db_engine` is an instance of `MagicMock` with an `Engine` spec, other
+methods of the `Engine` API can be called, but they will not perform any useful
+work.
+
+Including this fixture as a function argument of a test will activate any mocks that are defined
+by the configuration properties [`mocked-engines`](#mocked-engines), [`mocked-sessions`](#mocked-sessions),
+or [`mocked-sessionmakers`](#mocked-sessionmakers) in the test configuration file for
+the duration of that test.
+
+Example:
+
+```python
+def test_a_transaction_using_engine(db_engine):
+ with db_engine.begin() as conn:
+ row = conn.execute('''UPDATE table SET name = 'testing' WHERE id = 1''')
+
+def test_transaction_doesnt_persist(db_engine):
+ row_name = db_engine.execute('''SELECT name FROM table WHERE id = 1''').fetchone()[0]
+ assert row_name != 'testing'
+```
+
+## <a name="enabling-transactions-without-fixtures"></a>Enabling transactions without fixtures
+
+If you know you want to make all of your tests transactional, it can be annoying to have
+to specify one of the [fixtures](#fixtures) in every test signature.
+
+The best way to automatically enable transactions without having to include an extra fixture
+in every test is to wire up an
+[autouse fixture](https://docs.pytest.org/en/latest/fixture.html#autouse-fixtures-xunit-setup-on-steroids)
+for your test suite. This can be as simple as:
+
+```python
+# Automatically enable transactions for all tests, without importing any extra fixtures.
+@pytest.fixture(autouse=True)
+def enable_transactional_tests(db_session):
+ pass
+```
+
+In this configuration, the `enable_transactional_tests` fixture will be automatically used in
+all tests, meaning that `db_session` will also be used. This way, all tests will be wrapped
+in transactions without having to explicitly require either `db_session` or `enable_transactional_tests`.
+
+# <a name="development"></a>Development
+
+## <a name="running-the-tests"></a>Running the tests
+
+To run the tests, start by installing a development version of the plugin that
+includes test dependencies:
+
+```
+pip install -e .[tests]
+```
+
+Next, export a [database connection string](http://docs.sqlalchemy.org/en/latest/core/engines.html#database-urls)
+that the tests can use (the database referenced by the string will be created
+during test setup, so it does not need to exist):
+
+```
+export TEST_DATABASE_URL=<db_connection_string>
+```
+
+Finally, run the tests using pytest:
+
+```
+pytest
+```
+
+## <a name="acknowledgements"></a>Acknowledgements
+
+This plugin was initially developed for testing
+[Dedupe.io](https://dedupe.io), a web app for record linkage and entity
+resolution using machine learning. Dedupe.io is built and maintained
+by [DataMade](https://datamade.us).
+
+The code is greatly indebted to [Alex Michael](https://github.com/alexmic),
+whose blog post ["Delightful testing with pytest and
+Flask-SQLAlchemy"](http://alexmic.net/flask-sqlalchemy-pytest/) helped
+establish the basic approach on which this plugin builds.
+
+Many thanks to [Igor Ghisi](https://github.com/igortg/), who donated the PyPi
+package name. Igor had been working on a similar plugin and proposed combining
+efforts. Thanks to Igor, the plugin name is much stronger.
+
+## <a name="copyright"></a>Copyright
+
+Copyright (c) 2019 Jean Cochrane and DataMade. Released under the MIT License.
+
+Third-party copyright in this distribution is noted where applicable.
+
+
+
+
+%package help
+Summary: Development documents and examples for pytest-flask-sqlalchemy
+Provides: python3-pytest-flask-sqlalchemy-doc
+%description help
+# pytest-flask-sqlalchemy
+
+[![Build Status](https://travis-ci.org/jeancochrane/pytest-flask-sqlalchemy.svg?branch=master)](https://travis-ci.org/jeancochrane/pytest-flask-sqlalchemy) ![PyPI - Python Version](https://img.shields.io/pypi/pyversions/Django.svg)
+
+A [pytest](https://docs.pytest.org/en/latest/) plugin providing fixtures for running tests in
+transactions using [Flask-SQLAlchemy](http://flask-sqlalchemy.pocoo.org/latest/).
+
+## Contents
+
+- [**Motivation**](#motivation)
+- [**Quick examples**](#quick-examples)
+- [**Usage**](#usage)
+ - [Installation](#installation)
+ - [From PyPi](#from-pypi)
+ - [Development version](#development-version)
+ - [Supported backends](#supported-backends)
+ - [Configuration](#configuration)
+ - [Conftest setup](#conftest-setup)
+ - [Test configuration](#test-configuration)
+ - [`mocked-engines`](#mocked-engines)
+ - [`mocked-sessions`](#mocked-sessions)
+ - [`mocked-sessionmakers`](#mocked-sessionmakers)
+ - [Writing transactional tests](#writing-transactional-tests)
+ - [Fixtures](#fixtures)
+ - [`db_session`](#db_session)
+ - [`db_engine`](#db_engine)
+ - [Enabling transactions without fixtures](#enabling-transactions-without-fixtures)
+- [**Development**](#development)
+ - [Running the tests](#running-the-tests)
+ - [Acknowledgements](#acknowledgements)
+ - [Copyright](#copyright)
+
+## <a name="motivation"></a>Motivation
+
+Inspired by [Django's built-in support for transactional
+tests](https://jeancochrane.com/blog/django-test-transactions), this plugin
+seeks to provide comprehensive, easy-to-use Pytest fixtures for wrapping tests in
+database transactions for [Flask-SQLAlchemy](http://flask-sqlalchemy.pocoo.org/latest/)
+apps. The goal is to make testing stateful Flask-SQLAlchemy applications easier by
+providing fixtures that permit the developer to **make arbitrary database updates
+with the confidence that any changes made during a test will roll back** once the test exits.
+
+## <a name="quick-examples"></a>Quick examples
+
+Use the [`db_session` fixture](#db_session) to make **database updates that won't persist beyond
+the body of the test**:
+
+```python
+def test_a_transaction(db_session):
+ row = db_session.query(Table).get(1)
+ row.name = 'testing'
+
+ db_session.add(row)
+ db_session.commit()
+
+def test_transaction_doesnt_persist(db_session):
+ row = db_session.query(Table).get(1)
+ assert row.name != 'testing'
+```
+
+The [`db_engine` fixture](#db_engine) works the same way, but **copies the API of
+SQLAlchemy's [Engine
+object](http://docs.sqlalchemy.org/en/latest/core/connections.html#sqlalchemy.engine.Engine)**:
+
+```python
+def test_a_transaction_using_engine(db_engine):
+ with db_engine.begin() as conn:
+ row = conn.execute('''UPDATE table SET name = 'testing' WHERE id = 1''')
+
+def test_transaction_doesnt_persist(db_engine):
+ row_name = db_engine.execute('''SELECT name FROM table WHERE id = 1''').fetchone()[0]
+ assert row_name != 'testing'
+```
+
+Use [configuration properties](#test-configuration) to
+**mock database connections in an app and enforce nested transactions**,
+allowing any method from the codebase to run inside a test with the assurance
+that any database changes made will be rolled back at the end of the test:
+
+```ini
+# In setup.cfg
+
+[tool:pytest]
+mocked-sessions=database.db.session
+mocked-engines=database.engine
+```
+
+```python
+# In database.py
+
+db = flask_sqlalchemy.SQLAlchemy()
+engine = sqlalchemy.create_engine('DATABASE_URI')
+```
+
+```python
+# In models.py
+
+class Table(db.Model):
+ __tablename__ = 'table'
+ id = db.Column(db.Integer, primary_key=True)
+ name = db.Column(db.String(80))
+
+ def set_name(new_name):
+ self.name = new_name
+ db.session.add(self)
+ db.session.commit()
+```
+
+```python
+# In tests/test_set_name.py
+
+def test_set_name(db_session):
+ row = db_session.query(Table).get(1)
+ row.set_name('testing')
+ assert row.name == 'testing'
+
+def test_transaction_doesnt_persist(db_session):
+ row = db_session.query(Table).get(1)
+ assert row.name != 'testing'
+```
+
+# <a name="usage"></a>Usage
+
+## <a name="installation"></a>Installation
+
+### <a name="from-pypi"></a>From PyPi
+
+Install using pip:
+
+```
+pip install pytest-flask-sqlalchemy
+```
+
+Once installed, pytest will detect the plugin automatically during test collection.
+For basic background on using third-party plugins with pytest, see the [pytest
+documentation](https://docs.pytest.org/en/latest/plugins.html?highlight=plugins).
+
+### <a name="development-version"></a>Development version
+
+Clone the repo from GitHub and switch into the new directory:
+
+```
+git clone git@github.com:jeancochrane/pytest-flask-sqlalchemy.git
+cd pytest-flask-sqlalchemy
+```
+
+You can install using pip:
+
+```
+pip install .
+```
+
+### <a name="supported-backends"></a>Supported backends
+
+So far, pytest-flask-sqlalchemy has been most extensively tested against
+PostgreSQL 9.6. It should theoretically work with any backend that is supported
+by SQLAlchemy, but Postgres is the only backend that is currently tested by the
+test suite.
+
+Official support for SQLite and MySQL is [planned for a future
+release](https://github.com/jeancochrane/pytest-flask-sqlalchemy/issues/3).
+In the meantime, if you're using one of those backends and you run in to
+problems, we would greatly appreciate your help! [Open an
+issue](https://github.com/jeancochrane/pytest-flask-sqlalchemy/issues/new) if
+something isn't working as you expect.
+
+## <a name="configuration"></a>Configuration
+
+### <a name="conftest-setup"></a>Conftest setup
+
+This plugin assumes that a fixture called `_db` has been
+defined in the root conftest file for your tests. The `_db` fixture should
+expose access to a valid [SQLAlchemy `Session` object](http://docs.sqlalchemy.org/en/latest/orm/session_api.html?highlight=session#sqlalchemy.orm.session.Session) that can interact with your database,
+for example via the [`SQLAlchemy` initialization class](http://flask-sqlalchemy.pocoo.org/2.3/api/#flask_sqlalchemy.SQLAlchemy)
+that configures Flask-SQLAlchemy.
+
+The fixtures in this plugin depend on this `_db` fixture to access your
+database and create nested transactions to run tests in. **You must define
+this fixture in your `conftest.py` file for the plugin to work.**
+
+An example setup that will produce a valid `_db` fixture could look like this
+(this example comes from the [test setup](./tests/_conftest.py#L25-L61) for this repo):
+
+```python
+@pytest.fixture(scope='session')
+def database(request):
+ '''
+ Create a Postgres database for the tests, and drop it when the tests are done.
+ '''
+ pg_host = DB_OPTS.get("host")
+ pg_port = DB_OPTS.get("port")
+ pg_user = DB_OPTS.get("username")
+ pg_db = DB_OPTS["database"]
+
+ init_postgresql_database(pg_user, pg_host, pg_port, pg_db)
+
+ @request.addfinalizer
+ def drop_database():
+ drop_postgresql_database(pg_user, pg_host, pg_port, pg_db, 9.6)
+
+
+@pytest.fixture(scope='session')
+def app(database):
+ '''
+ Create a Flask app context for the tests.
+ '''
+ app = Flask(__name__)
+
+ app.config['SQLALCHEMY_DATABASE_URI'] = DB_CONN
+
+ return app
+
+
+@pytest.fixture(scope='session')
+def _db(app):
+ '''
+ Provide the transactional fixtures with access to the database via a Flask-SQLAlchemy
+ database connection.
+ '''
+ db = SQLAlchemy(app=app)
+
+ return db
+```
+
+Alternatively, if you already have a fixture that sets up database access for
+your tests, you can define `_db` to return that fixture directly:
+
+```python
+@pytest.fixture(scope='session')
+def database():
+ # Set up all your database stuff here
+ # ...
+ return db
+
+@pytest.fixture(scope='session')
+def _db(database):
+ return database
+```
+
+### <a name="test-configuration"></a>Test configuration
+
+This plugin allows you to configure a few different properties in a
+`setup.cfg` test configuration file in order to handle the specific database connection needs
+of your app. For basic background on setting up pytest configuration files, see
+the [pytest docs](https://docs.pytest.org/en/latest/customize.html#adding-default-options).
+
+All three configuration properties ([`mocked-engines`](#mocked-engines),
+[`mocked-sessions`](#mocked-sessions), and [`mocked-sessionmakers`](#mocked-sessionmakers))
+work by **[patching](https://docs.python.org/3/library/unittest.mock.html#unittest.mock.patch)
+one or more specified objects during a test**, replacing them with equivalent objects whose
+database interactions will run inside of a transaction and ultimately be
+rolled back when the test exits. Using these patches, you can call methods from
+your codebase that alter database state with the knowledge that no changes will persist
+beyond the body of the test.
+
+The configured patches are only applied in tests where a transactional fixture
+(either [`db_session`](#db_session) or [`db_engine`](#db_engine)) is included
+in the test function arguments.
+
+#### <a name="mocked-engines"></a>`mocked-engines`
+
+The `mocked-engines` property directs the plugin to [patch](https://docs.python.org/3/library/unittest.mock.html#unittest.mock.patch)
+objects in your codebase, typically SQLAlchemy [Engine](http://docs.sqlalchemy.org/en/latest/core/connections.html#sqlalchemy.engine.Engine)
+instances, replacing them with the [`db_engine` fixture](#db_engine) such that
+any database updates performed by the objects get rolled back at the end of
+the test.
+
+The value for this property should be formatted as a whitespace-separated list
+of standard Python import paths, like `database.engine`. This property is **optional**.
+
+Example:
+
+```python
+# In database.py
+
+engine = sqlalchemy.create_engine(DATABASE_URI)
+```
+
+```ini
+# In setup.cfg
+
+[tool:pytest]
+mocked-engines=database.engine
+```
+
+To patch multiple objects at once, separate the paths with a whitespace:
+
+```ini
+# In setup.cfg
+
+[tool:pytest]
+mocked-engines=database.engine database.second_engine
+```
+
+#### <a name="mocked-sessions"></a>`mocked-sessions`
+
+The `mocked-sessions` property directs the plugin to [patch](https://docs.python.org/3/library/unittest.mock.html#unittest.mock.patch)
+objects in your codebase, typically SQLAlchemy [Session](http://docs.sqlalchemy.org/en/latest/core/connections.html#sqlalchemy.engine.Engine)
+instances, replacing them with the [`db_session`](#db_session) fixture such that
+any database updates performed by the objects get rolled back at the end of
+the test.
+
+The value for this property should be formatted as a whitespace-separated list
+of standard Python import paths, like `database.db.session`. This property is **optional**.
+
+Example:
+
+```python
+# In database.py
+
+db = SQLAlchemy()
+```
+
+```ini
+# In setup.cfg
+
+[tool:pytest]
+mocked-sessions=database.db.session
+```
+
+To patch multiple objects at once, separate the paths with a whitespace:
+
+```ini
+# In setup.cfg
+
+[tool:pytest]
+mocked-sessions=database.db.session database.second_db.session
+```
+
+#### <a name="mocked-sessionmakers"></a>`mocked-sessionmakers`
+
+The `mocked-sessionmakers` property directs the plugin to [patch](https://docs.python.org/3/library/unittest.mock.html#unittest.mock.patch)
+objects in your codebase, typically instances of [SQLAlchemy's `sessionmaker`
+factory](http://docs.sqlalchemy.org/en/latest/orm/session_api.html?highlight=sessionmaker#sqlalchemy.orm.session.sessionmaker),
+replacing them with a mocked class that will return the transactional
+[`db_session`](#db_session) fixture. This can be useful if you have
+pre-configured instances of sessionmaker objects that you import in the code
+to spin up sessions on the fly.
+
+The value for this property should be formatted as a whitespace-separated list
+of standard Python import paths, like `database.WorkerSessionmaker`. This property is **optional**.
+
+Example:
+
+```python
+# In database.py
+
+WorkerSessionmaker = sessionmaker()
+```
+
+```ini
+[tool:pytest]
+mocked-sessionmakers=database.WorkerSessionmaker
+```
+
+To patch multiple objects at once, separate the paths with a whitespace.
+
+```ini
+[tool:pytest]
+mocked-sessionmakers=database.WorkerSessionmaker database.SecondWorkerSessionmaker
+```
+
+### <a name="writing-transactional-tests"></a>Writing transactional tests
+
+Once you have your [conftest file set up](#conftest-setup) and you've [overrided the
+necessary connectables in your test configuration](#test-configuration), you're ready
+to write some transactional tests. Simply import one of the module's [transactional
+fixtures](#fixtures) in your test signature, and the test will be wrapped in a transaction.
+
+Note that by default, **tests are only wrapped in transactions if they import one of
+the [transactional fixtures](#fixtures) provided by this module.** Tests that do not
+import the fixture will interact with your database without opening a transaction:
+
+```python
+# This test will be wrapped in a transaction.
+def transactional_test(db_session):
+ ...
+
+# This test **will not** be wrapped in a transaction, since it does not import a
+# transactional fixture.
+def non_transactional_test():
+ ...
+```
+
+The fixtures provide a way for you to control which tests require transactions and
+which don't. This is often useful, since avoiding transaction setup can speed up
+tests that don't interact with your database.
+
+For more information about the transactional fixtures provided by this module, read on
+to the [fixtures section](#fixtures). For guidance on how to automatically enable
+transactions without having to specify fixtures, see the section on [enabling transactions
+without fixtures](#enabling-transactions-without-fixtures).
+
+## <a name="fixtures"></a>Fixtures
+
+This plugin provides two fixtures for performing database updates inside nested
+transactions that get rolled back at the end of a test: [`db_session`](#db_session) and
+[`db_engine`](#db_engine). The fixtures provide similar functionality, but
+with different APIs.
+
+### <a name="db_session"></a>`db_session`
+
+The `db_session` fixture allows you to perform direct updates that will be
+rolled back when the test exits. It exposes the same API as [SQLAlchemy's
+`scoped_session` object](http://docs.sqlalchemy.org/en/latest/orm/contextual.html#sqlalchemy.orm.scoping.scoped_session).
+
+Including this fixture as a function argument of a test will activate any mocks that are defined
+by the configuration properties [`mocked-engines`](#mocked-engines), [`mocked-sessions`](#mocked-sessions),
+or [`mocked-sessionmakers`](#mocked-sessionmakers) in the test configuration file for
+the duration of that test.
+
+Example:
+
+```python
+def test_a_transaction(db_session):
+ row = db_session.query(Table).get(1)
+ row.name = 'testing'
+
+ db_session.add(row)
+ db_session.commit()
+
+def test_transaction_doesnt_persist(db_session):
+ row = db_session.query(Table).get(1)
+ assert row.name != 'testing'
+```
+
+### <a name="db_engine"></a>`db_engine`
+
+Like [`db_session`](#db_session), the `db_engine` fixture allows you to perform direct updates
+against the test database that will be rolled back when the test exits. It is
+an instance of Python's built-in [`MagicMock`](https://docs.python.org/3/library/unittest.mock.html#unittest.mock.MagicMock)
+class, with a spec set to match the API of [SQLAlchemy's
+`Engine`](http://docs.sqlalchemy.org/en/latest/core/connections.html#sqlalchemy.engine.Engine) object.
+
+Only a few `Engine` methods are exposed on this fixture:
+
+- `db_engine.begin`: begin a new nested transaction ([API docs](http://docs.sqlalchemy.org/en/latest/core/connections.html#sqlalchemy.engine.Engine.begin))
+- `db_engine.execute`: execute a raw SQL query ([API docs](http://docs.sqlalchemy.org/en/latest/core/connections.html#sqlalchemy.engine.Engine.execute))
+- `db_engine.raw_connection`: return a raw DBAPI connection ([API docs](http://docs.sqlalchemy.org/en/latest/core/connections.html#sqlalchemy.engine.Engine.raw_connection))
+
+Since `db_engine` is an instance of `MagicMock` with an `Engine` spec, other
+methods of the `Engine` API can be called, but they will not perform any useful
+work.
+
+Including this fixture as a function argument of a test will activate any mocks that are defined
+by the configuration properties [`mocked-engines`](#mocked-engines), [`mocked-sessions`](#mocked-sessions),
+or [`mocked-sessionmakers`](#mocked-sessionmakers) in the test configuration file for
+the duration of that test.
+
+Example:
+
+```python
+def test_a_transaction_using_engine(db_engine):
+ with db_engine.begin() as conn:
+ row = conn.execute('''UPDATE table SET name = 'testing' WHERE id = 1''')
+
+def test_transaction_doesnt_persist(db_engine):
+ row_name = db_engine.execute('''SELECT name FROM table WHERE id = 1''').fetchone()[0]
+ assert row_name != 'testing'
+```
+
+## <a name="enabling-transactions-without-fixtures"></a>Enabling transactions without fixtures
+
+If you know you want to make all of your tests transactional, it can be annoying to have
+to specify one of the [fixtures](#fixtures) in every test signature.
+
+The best way to automatically enable transactions without having to include an extra fixture
+in every test is to wire up an
+[autouse fixture](https://docs.pytest.org/en/latest/fixture.html#autouse-fixtures-xunit-setup-on-steroids)
+for your test suite. This can be as simple as:
+
+```python
+# Automatically enable transactions for all tests, without importing any extra fixtures.
+@pytest.fixture(autouse=True)
+def enable_transactional_tests(db_session):
+ pass
+```
+
+In this configuration, the `enable_transactional_tests` fixture will be automatically used in
+all tests, meaning that `db_session` will also be used. This way, all tests will be wrapped
+in transactions without having to explicitly require either `db_session` or `enable_transactional_tests`.
+
+# <a name="development"></a>Development
+
+## <a name="running-the-tests"></a>Running the tests
+
+To run the tests, start by installing a development version of the plugin that
+includes test dependencies:
+
+```
+pip install -e .[tests]
+```
+
+Next, export a [database connection string](http://docs.sqlalchemy.org/en/latest/core/engines.html#database-urls)
+that the tests can use (the database referenced by the string will be created
+during test setup, so it does not need to exist):
+
+```
+export TEST_DATABASE_URL=<db_connection_string>
+```
+
+Finally, run the tests using pytest:
+
+```
+pytest
+```
+
+## <a name="acknowledgements"></a>Acknowledgements
+
+This plugin was initially developed for testing
+[Dedupe.io](https://dedupe.io), a web app for record linkage and entity
+resolution using machine learning. Dedupe.io is built and maintained
+by [DataMade](https://datamade.us).
+
+The code is greatly indebted to [Alex Michael](https://github.com/alexmic),
+whose blog post ["Delightful testing with pytest and
+Flask-SQLAlchemy"](http://alexmic.net/flask-sqlalchemy-pytest/) helped
+establish the basic approach on which this plugin builds.
+
+Many thanks to [Igor Ghisi](https://github.com/igortg/), who donated the PyPi
+package name. Igor had been working on a similar plugin and proposed combining
+efforts. Thanks to Igor, the plugin name is much stronger.
+
+## <a name="copyright"></a>Copyright
+
+Copyright (c) 2019 Jean Cochrane and DataMade. Released under the MIT License.
+
+Third-party copyright in this distribution is noted where applicable.
+
+
+
+
+%prep
+%autosetup -n pytest-flask-sqlalchemy-1.1.0
+
+%build
+%py3_build
+
+%install
+%py3_install
+install -d -m755 %{buildroot}/%{_pkgdocdir}
+if [ -d doc ]; then cp -arf doc %{buildroot}/%{_pkgdocdir}; fi
+if [ -d docs ]; then cp -arf docs %{buildroot}/%{_pkgdocdir}; fi
+if [ -d example ]; then cp -arf example %{buildroot}/%{_pkgdocdir}; fi
+if [ -d examples ]; then cp -arf examples %{buildroot}/%{_pkgdocdir}; fi
+pushd %{buildroot}
+if [ -d usr/lib ]; then
+ find usr/lib -type f -printf "/%h/%f\n" >> filelist.lst
+fi
+if [ -d usr/lib64 ]; then
+ find usr/lib64 -type f -printf "/%h/%f\n" >> filelist.lst
+fi
+if [ -d usr/bin ]; then
+ find usr/bin -type f -printf "/%h/%f\n" >> filelist.lst
+fi
+if [ -d usr/sbin ]; then
+ find usr/sbin -type f -printf "/%h/%f\n" >> filelist.lst
+fi
+touch doclist.lst
+if [ -d usr/share/man ]; then
+ find usr/share/man -type f -printf "/%h/%f.gz\n" >> doclist.lst
+fi
+popd
+mv %{buildroot}/filelist.lst .
+mv %{buildroot}/doclist.lst .
+
+%files -n python3-pytest-flask-sqlalchemy -f filelist.lst
+%dir %{python3_sitelib}/*
+
+%files help -f doclist.lst
+%{_docdir}/*
+
+%changelog
+* Tue Apr 11 2023 Python_Bot <Python_Bot@openeuler.org> - 1.1.0-1
+- Package Spec generated
diff --git a/sources b/sources
new file mode 100644
index 0000000..ccaeb37
--- /dev/null
+++ b/sources
@@ -0,0 +1 @@
+3b3b9377387e28ece71090b927c3856e pytest-flask-sqlalchemy-1.1.0.tar.gz