From 6ba5d17522c5565dccea7f6012cb2ca49b7e340c Mon Sep 17 00:00:00 2001 From: Dmytro Tyzhnenko Date: Wed, 3 Jun 2026 00:30:31 +0300 Subject: [PATCH 01/12] feat: Remove only specified DBs in mongodb_factory --- pytest_mongo/factories/client.py | 7 ++++++- pytest_mongo/plugin.py | 18 ++++++++++++++++++ tests/conftest.py | 3 +++ tests/test_mongo.py | 18 ++++++++++++++++++ 4 files changed, 45 insertions(+), 1 deletion(-) diff --git a/pytest_mongo/factories/client.py b/pytest_mongo/factories/client.py index 971cfea..1742655 100644 --- a/pytest_mongo/factories/client.py +++ b/pytest_mongo/factories/client.py @@ -10,7 +10,9 @@ def mongodb( - process_fixture_name: str, tz_aware: bool | None = None + process_fixture_name: str, + tz_aware: bool | None = None, + databases: list[str] | None = None, ) -> Callable[[FixtureRequest], Iterator[MongoClient]]: """Mongo database factory. @@ -44,6 +46,9 @@ def mongodb_factory(request: FixtureRequest) -> Iterator[MongoClient]: yield mongo_conn for db_name in mongo_conn.list_database_names(): + if databases and db_name not in databases: + continue + database = mongo_conn[db_name] for collection_name in database.list_collection_names(): collection = database[collection_name] diff --git a/pytest_mongo/plugin.py b/pytest_mongo/plugin.py index d0a8b1a..84c5775 100644 --- a/pytest_mongo/plugin.py +++ b/pytest_mongo/plugin.py @@ -31,6 +31,10 @@ "Have mongo client timezone aware (ini: mongo_tz_aware; " "use --mongo-tz-aware/--no-mongo-tz-aware to override)" ) +_help_databases = ( + "List of MongoDB databases to clean in the fixture. Otherwise, all databases " + "are cleaned exclude system.*." +) def pytest_addoption(parser: Parser) -> None: @@ -57,6 +61,12 @@ def pytest_addoption(parser: Parser) -> None: default=False, ) + parser.addini( + name="mongo_databases", + help=_help_databases, + default=[], + ) + parser.addoption( "--mongo-exec", action="store", @@ -95,6 +105,14 @@ def pytest_addoption(parser: Parser) -> None: dest="mongo_tz_aware", help=_help_tz_aware, ) + parser.addoption( + "--mongo-databases", + help=_help_databases, + dest="mongo_databases", + type=str, + nargs="*", + action="extend", + ) mongo_proc = factories.mongo_proc() diff --git a/tests/conftest.py b/tests/conftest.py index 96179c7..d02b5c1 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -13,4 +13,7 @@ mongo_proc_rand = process.mongo_proc(port=None, params=mongo_params) mongodb_rand = client.mongodb("mongo_proc_rand") + +mongo_proc4 = process.mongo_proc(port=27072, params=mongo_params) +mongodb4 = client.mongodb("mongo_proc4", databases=["test_db"]) # pylint:enable=invalid-name diff --git a/tests/test_mongo.py b/tests/test_mongo.py index 915b285..79edc57 100644 --- a/tests/test_mongo.py +++ b/tests/test_mongo.py @@ -56,3 +56,21 @@ def test_random_port(mongodb_rand: MongoClient) -> None: server_info = mongodb_rand.server_info() assert "ok" in server_info assert server_info["ok"] == 1.0 + +class TestCleanSpecifiedDatabases: + """Test if only specified databases are cleaned.""" + + def test_clean_specified_databases(self, mongodb4: MongoClient) -> None: + """Test if only specified databases are cleaned.""" + test_db = mongodb4["test_db"] + test_db.test.insert_one({"test": "test"}) + test_db2 = mongodb4["test_db2"] + test_db2.test.insert_one({"test": "test"}) + + assert "test_db" in mongodb4.list_database_names() + assert "test_db2" in mongodb4.list_database_names() + + def test_clean_specified_databases_again(self, mongodb4: MongoClient) -> None: + """Test if only specified databases are cleaned.""" + assert "test_db" not in mongodb4.list_database_names() + assert "test_db2" in mongodb4.list_database_names() \ No newline at end of file From 8e9159ac47ce69a72bd475fcfc8a84c6bc50954f Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 2 Jun 2026 21:34:08 +0000 Subject: [PATCH 02/12] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- tests/test_mongo.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/test_mongo.py b/tests/test_mongo.py index 79edc57..e72bf35 100644 --- a/tests/test_mongo.py +++ b/tests/test_mongo.py @@ -57,6 +57,7 @@ def test_random_port(mongodb_rand: MongoClient) -> None: assert "ok" in server_info assert server_info["ok"] == 1.0 + class TestCleanSpecifiedDatabases: """Test if only specified databases are cleaned.""" @@ -73,4 +74,4 @@ def test_clean_specified_databases(self, mongodb4: MongoClient) -> None: def test_clean_specified_databases_again(self, mongodb4: MongoClient) -> None: """Test if only specified databases are cleaned.""" assert "test_db" not in mongodb4.list_database_names() - assert "test_db2" in mongodb4.list_database_names() \ No newline at end of file + assert "test_db2" in mongodb4.list_database_names() From c35915aac6c9de4de7b02499f94a1f1235e8eb2e Mon Sep 17 00:00:00 2001 From: Dmytro Tyzhnenko Date: Wed, 3 Jun 2026 00:44:45 +0300 Subject: [PATCH 03/12] docs: add 812.feature.rst --- newsfragments/812.feature.rst | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 newsfragments/812.feature.rst diff --git a/newsfragments/812.feature.rst b/newsfragments/812.feature.rst new file mode 100644 index 0000000..a98a147 --- /dev/null +++ b/newsfragments/812.feature.rst @@ -0,0 +1,2 @@ +Improve mongodb_factory to delete the only provided databases. +It's useful to run xdist tests in parallel, and avoid deleting databases created by other test workers. From 326f2df7710710f0fbddc5c478614c4d54dade36 Mon Sep 17 00:00:00 2001 From: Dmytro Tyzhnenko Date: Wed, 3 Jun 2026 00:51:12 +0300 Subject: [PATCH 04/12] bug: fix configuration --- pytest_mongo/config.py | 2 ++ pytest_mongo/factories/client.py | 9 ++++++++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/pytest_mongo/config.py b/pytest_mongo/config.py index be52a6f..335d23d 100644 --- a/pytest_mongo/config.py +++ b/pytest_mongo/config.py @@ -16,6 +16,7 @@ class MongoConfig: port_search_count: int params: str tz_aware: bool + databases: list[str] | None def get_config(request: FixtureRequest) -> MongoConfig: @@ -34,5 +35,6 @@ def get_mongo_option(option: str) -> Any: port_search_count=int(get_mongo_option("port_search_count")), params=get_mongo_option("params"), tz_aware=get_mongo_option("tz_aware"), + databases=get_mongo_option("databases"), ) return cfg diff --git a/pytest_mongo/factories/client.py b/pytest_mongo/factories/client.py index 1742655..837ab19 100644 --- a/pytest_mongo/factories/client.py +++ b/pytest_mongo/factories/client.py @@ -18,6 +18,7 @@ def mongodb( :param str process_fixture_name: name of the process fixture :param bool tz_aware: whether the client to be timezone aware or not + :param list databases: list of database names to be cleaned, if None all databases will be cleaned :rtype: func :returns: function which makes a connection to mongo """ @@ -38,6 +39,12 @@ def mongodb_factory(request: FixtureRequest) -> Iterator[MongoClient]: elif config.tz_aware is not None and isinstance(config.tz_aware, bool): mongo_tz_aware = config.tz_aware + mongo_databases = None + if databases is not None: + mongo_databases = databases + elif config.databases is not None and isinstance(config.databases, list): + mongo_databases = config.databases + mongo_host = mongodb_process.host mongo_port = mongodb_process.port @@ -46,7 +53,7 @@ def mongodb_factory(request: FixtureRequest) -> Iterator[MongoClient]: yield mongo_conn for db_name in mongo_conn.list_database_names(): - if databases and db_name not in databases: + if mongo_databases and db_name not in mongo_databases: continue database = mongo_conn[db_name] From 0ec9aab5b69113e7acc22c60e6da813bc286ca3b Mon Sep 17 00:00:00 2001 From: Dmytro Tyzhnenko Date: Wed, 3 Jun 2026 00:54:43 +0300 Subject: [PATCH 05/12] chore: typo fix --- pytest_mongo/plugin.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pytest_mongo/plugin.py b/pytest_mongo/plugin.py index 84c5775..9ae0c9e 100644 --- a/pytest_mongo/plugin.py +++ b/pytest_mongo/plugin.py @@ -33,7 +33,7 @@ ) _help_databases = ( "List of MongoDB databases to clean in the fixture. Otherwise, all databases " - "are cleaned exclude system.*." + "are cleaned excluding system.*. collections" ) From 011b08a55e185a4fcf0219c44206620a856754e3 Mon Sep 17 00:00:00 2001 From: Dmytro Tyzhnenko Date: Wed, 3 Jun 2026 00:58:09 +0300 Subject: [PATCH 06/12] chore: make linter happy --- pytest_mongo/factories/client.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pytest_mongo/factories/client.py b/pytest_mongo/factories/client.py index 837ab19..84282d9 100644 --- a/pytest_mongo/factories/client.py +++ b/pytest_mongo/factories/client.py @@ -18,7 +18,7 @@ def mongodb( :param str process_fixture_name: name of the process fixture :param bool tz_aware: whether the client to be timezone aware or not - :param list databases: list of database names to be cleaned, if None all databases will be cleaned + :param list databases: list of database names to be cleaned :rtype: func :returns: function which makes a connection to mongo """ From 6154e7c57d90bb6eadf9643b4949a3b983927bf6 Mon Sep 17 00:00:00 2001 From: Dmytro Tyzhnenko Date: Wed, 24 Jun 2026 23:58:04 +0300 Subject: [PATCH 07/12] feat: add keep parameter --- pytest_mongo/config.py | 6 ++++-- pytest_mongo/factories/client.py | 33 ++++++++++++++++++++++++-------- pytest_mongo/plugin.py | 30 +++++++++++++++++++++++------ tests/conftest.py | 3 ++- tests/test_mongo.py | 19 ------------------ tests/test_mongo_cleanup.py | 20 +++++++++++++++++++ 6 files changed, 75 insertions(+), 36 deletions(-) create mode 100644 tests/test_mongo_cleanup.py diff --git a/pytest_mongo/config.py b/pytest_mongo/config.py index 335d23d..6434b45 100644 --- a/pytest_mongo/config.py +++ b/pytest_mongo/config.py @@ -16,7 +16,8 @@ class MongoConfig: port_search_count: int params: str tz_aware: bool - databases: list[str] | None + remove_dbs: list[str] | None + keep_dbs: list[str] | None def get_config(request: FixtureRequest) -> MongoConfig: @@ -35,6 +36,7 @@ def get_mongo_option(option: str) -> Any: port_search_count=int(get_mongo_option("port_search_count")), params=get_mongo_option("params"), tz_aware=get_mongo_option("tz_aware"), - databases=get_mongo_option("databases"), + remove_dbs=get_mongo_option("remove_dbs"), + keep_dbs=get_mongo_option("keep_dbs"), ) return cfg diff --git a/pytest_mongo/factories/client.py b/pytest_mongo/factories/client.py index 84282d9..a2cd1c4 100644 --- a/pytest_mongo/factories/client.py +++ b/pytest_mongo/factories/client.py @@ -12,17 +12,25 @@ def mongodb( process_fixture_name: str, tz_aware: bool | None = None, - databases: list[str] | None = None, + remove_dbs: list[str] | None = None, + keep_dbs: list[str] | None = None, ) -> Callable[[FixtureRequest], Iterator[MongoClient]]: """Mongo database factory. :param str process_fixture_name: name of the process fixture :param bool tz_aware: whether the client to be timezone aware or not - :param list databases: list of database names to be cleaned + :param list remove_dbs: list of database names to be cleaned + :param list keep_dbs: list of database names to be kept :rtype: func :returns: function which makes a connection to mongo """ + if remove_dbs is not None and keep_dbs is not None and set(remove_dbs).intersection(set(keep_dbs)): + raise ValueError( + "remove_dbs and keep_dbs cannot have overlapping database names" + ) + + @pytest.fixture def mongodb_factory(request: FixtureRequest) -> Iterator[MongoClient]: """Client fixture for MongoDB. @@ -39,11 +47,17 @@ def mongodb_factory(request: FixtureRequest) -> Iterator[MongoClient]: elif config.tz_aware is not None and isinstance(config.tz_aware, bool): mongo_tz_aware = config.tz_aware - mongo_databases = None - if databases is not None: - mongo_databases = databases - elif config.databases is not None and isinstance(config.databases, list): - mongo_databases = config.databases + mongo_remove_dbs = None + if remove_dbs is not None: + mongo_remove_dbs = remove_dbs + elif config.remove_dbs is not None and isinstance(config.remove_dbs, list): + mongo_remove_dbs = config.remove_dbs + + mongo_keep_dbs = None + if keep_dbs is not None: + mongo_keep_dbs = keep_dbs + elif config.keep_dbs is not None and isinstance(config.keep_dbs, list): + mongo_keep_dbs = config.keep_dbs mongo_host = mongodb_process.host mongo_port = mongodb_process.port @@ -53,7 +67,10 @@ def mongodb_factory(request: FixtureRequest) -> Iterator[MongoClient]: yield mongo_conn for db_name in mongo_conn.list_database_names(): - if mongo_databases and db_name not in mongo_databases: + if mongo_keep_dbs and db_name in mongo_keep_dbs: + continue + + if mongo_remove_dbs and db_name not in mongo_remove_dbs: continue database = mongo_conn[db_name] diff --git a/pytest_mongo/plugin.py b/pytest_mongo/plugin.py index 9ae0c9e..17eda1e 100644 --- a/pytest_mongo/plugin.py +++ b/pytest_mongo/plugin.py @@ -31,10 +31,14 @@ "Have mongo client timezone aware (ini: mongo_tz_aware; " "use --mongo-tz-aware/--no-mongo-tz-aware to override)" ) -_help_databases = ( +_help_remove_dbs = ( "List of MongoDB databases to clean in the fixture. Otherwise, all databases " "are cleaned excluding system.*. collections" ) +_help_keep_dbs = ( + "List of MongoDB databases to keep in the fixture. Otherwise, all databases " + "are cleaned excluding system.*. collections" +) def pytest_addoption(parser: Parser) -> None: @@ -62,8 +66,14 @@ def pytest_addoption(parser: Parser) -> None: ) parser.addini( - name="mongo_databases", - help=_help_databases, + name="mongo_remove_dbs", + help=_help_remove_dbs, + default=[], + ) + + parser.addini( + name="mongo_keep_dbs", + help=_help_keep_dbs, default=[], ) @@ -106,9 +116,17 @@ def pytest_addoption(parser: Parser) -> None: help=_help_tz_aware, ) parser.addoption( - "--mongo-databases", - help=_help_databases, - dest="mongo_databases", + "--mongo-remove-dbs", + help=_help_remove_dbs, + dest="mongo_remove_dbs", + type=str, + nargs="*", + action="extend", + ) + parser.addoption( + "--mongo-keep-dbs", + help=_help_keep_dbs, + dest="mongo_keep_dbs", type=str, nargs="*", action="extend", diff --git a/tests/conftest.py b/tests/conftest.py index d02b5c1..4180eaf 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -15,5 +15,6 @@ mongodb_rand = client.mongodb("mongo_proc_rand") mongo_proc4 = process.mongo_proc(port=27072, params=mongo_params) -mongodb4 = client.mongodb("mongo_proc4", databases=["test_db"]) +mongodb4 = client.mongodb("mongo_proc4", remove_dbs=["test_db"]) +mongodb5 = client.mongodb("mongo_proc4", keep_dbs=["test_db2"]) # pylint:enable=invalid-name diff --git a/tests/test_mongo.py b/tests/test_mongo.py index e72bf35..915b285 100644 --- a/tests/test_mongo.py +++ b/tests/test_mongo.py @@ -56,22 +56,3 @@ def test_random_port(mongodb_rand: MongoClient) -> None: server_info = mongodb_rand.server_info() assert "ok" in server_info assert server_info["ok"] == 1.0 - - -class TestCleanSpecifiedDatabases: - """Test if only specified databases are cleaned.""" - - def test_clean_specified_databases(self, mongodb4: MongoClient) -> None: - """Test if only specified databases are cleaned.""" - test_db = mongodb4["test_db"] - test_db.test.insert_one({"test": "test"}) - test_db2 = mongodb4["test_db2"] - test_db2.test.insert_one({"test": "test"}) - - assert "test_db" in mongodb4.list_database_names() - assert "test_db2" in mongodb4.list_database_names() - - def test_clean_specified_databases_again(self, mongodb4: MongoClient) -> None: - """Test if only specified databases are cleaned.""" - assert "test_db" not in mongodb4.list_database_names() - assert "test_db2" in mongodb4.list_database_names() diff --git a/tests/test_mongo_cleanup.py b/tests/test_mongo_cleanup.py new file mode 100644 index 0000000..2485d5d --- /dev/null +++ b/tests/test_mongo_cleanup.py @@ -0,0 +1,20 @@ +from pymongo import MongoClient + +def test_clean_specified_databases(mongodb4: MongoClient) -> None: + """Test if only specified databases are cleaned.""" + test_db = mongodb4["test_db"] + test_db.test.insert_one({"test": "test"}) + test_db2 = mongodb4["test_db2"] + test_db2.test.insert_one({"test": "test"}) + + assert "test_db" in mongodb4.list_database_names() + assert "test_db2" in mongodb4.list_database_names() + +def test_clean_specified_databases_again(mongodb5: MongoClient) -> None: + """Test if only specified databases are cleaned.""" + assert "test_db" not in mongodb5.list_database_names() + assert "test_db2" in mongodb5.list_database_names() + +def test_keep_specified_databases(mongodb5: MongoClient) -> None: + assert "test_db" not in mongodb5.list_database_names() + assert "test_db2" in mongodb5.list_database_names() From 839353c514ef4ed1dd2429ec24fd6239e7fc3981 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 24 Jun 2026 20:58:19 +0000 Subject: [PATCH 08/12] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- pytest_mongo/factories/client.py | 12 ++++++------ tests/test_mongo_cleanup.py | 3 +++ 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/pytest_mongo/factories/client.py b/pytest_mongo/factories/client.py index a2cd1c4..d1b1943 100644 --- a/pytest_mongo/factories/client.py +++ b/pytest_mongo/factories/client.py @@ -24,12 +24,12 @@ def mongodb( :rtype: func :returns: function which makes a connection to mongo """ - - if remove_dbs is not None and keep_dbs is not None and set(remove_dbs).intersection(set(keep_dbs)): - raise ValueError( - "remove_dbs and keep_dbs cannot have overlapping database names" - ) - + if ( + remove_dbs is not None + and keep_dbs is not None + and set(remove_dbs).intersection(set(keep_dbs)) + ): + raise ValueError("remove_dbs and keep_dbs cannot have overlapping database names") @pytest.fixture def mongodb_factory(request: FixtureRequest) -> Iterator[MongoClient]: diff --git a/tests/test_mongo_cleanup.py b/tests/test_mongo_cleanup.py index 2485d5d..5324cd2 100644 --- a/tests/test_mongo_cleanup.py +++ b/tests/test_mongo_cleanup.py @@ -1,5 +1,6 @@ from pymongo import MongoClient + def test_clean_specified_databases(mongodb4: MongoClient) -> None: """Test if only specified databases are cleaned.""" test_db = mongodb4["test_db"] @@ -10,11 +11,13 @@ def test_clean_specified_databases(mongodb4: MongoClient) -> None: assert "test_db" in mongodb4.list_database_names() assert "test_db2" in mongodb4.list_database_names() + def test_clean_specified_databases_again(mongodb5: MongoClient) -> None: """Test if only specified databases are cleaned.""" assert "test_db" not in mongodb5.list_database_names() assert "test_db2" in mongodb5.list_database_names() + def test_keep_specified_databases(mongodb5: MongoClient) -> None: assert "test_db" not in mongodb5.list_database_names() assert "test_db2" in mongodb5.list_database_names() From 71ee7ac24fbf60513a68b3830e73aa8daf16507f Mon Sep 17 00:00:00 2001 From: Dmytro Tyzhnenko Date: Thu, 25 Jun 2026 00:11:04 +0300 Subject: [PATCH 09/12] docs: update newsfragments --- newsfragments/812.feature.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/newsfragments/812.feature.rst b/newsfragments/812.feature.rst index a98a147..d6d16b5 100644 --- a/newsfragments/812.feature.rst +++ b/newsfragments/812.feature.rst @@ -1,2 +1,3 @@ -Improve mongodb_factory to delete the only provided databases. +Improve mongodb_factory to keep or delete provided databases. It's useful to run xdist tests in parallel, and avoid deleting databases created by other test workers. +Now you can keep preseed databases which won't be deleted after each test. From 80a15fdd0d456ac28c8c7f898b141f33b9f0af54 Mon Sep 17 00:00:00 2001 From: Dmytro Tyzhnenko Date: Thu, 25 Jun 2026 00:13:58 +0300 Subject: [PATCH 10/12] chore: set type to parser ini --- pytest_mongo/plugin.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pytest_mongo/plugin.py b/pytest_mongo/plugin.py index 17eda1e..8ff5698 100644 --- a/pytest_mongo/plugin.py +++ b/pytest_mongo/plugin.py @@ -67,12 +67,14 @@ def pytest_addoption(parser: Parser) -> None: parser.addini( name="mongo_remove_dbs", + type="args", help=_help_remove_dbs, default=[], ) parser.addini( name="mongo_keep_dbs", + type="args", help=_help_keep_dbs, default=[], ) From 1443d376ffe3f1d5b878023c67d5efecaaaaf8d2 Mon Sep 17 00:00:00 2001 From: Dmytro Tyzhnenko Date: Thu, 25 Jun 2026 00:15:24 +0300 Subject: [PATCH 11/12] chore: make linter happy --- tests/test_mongo_cleanup.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/test_mongo_cleanup.py b/tests/test_mongo_cleanup.py index 5324cd2..2132907 100644 --- a/tests/test_mongo_cleanup.py +++ b/tests/test_mongo_cleanup.py @@ -19,5 +19,6 @@ def test_clean_specified_databases_again(mongodb5: MongoClient) -> None: def test_keep_specified_databases(mongodb5: MongoClient) -> None: + """Test if only specified databases are kept.""" assert "test_db" not in mongodb5.list_database_names() assert "test_db2" in mongodb5.list_database_names() From 294e28d80cd95ec2e7579ba5b9e8c66bcc85308c Mon Sep 17 00:00:00 2001 From: Dmytro Tyzhnenko Date: Thu, 25 Jun 2026 00:18:33 +0300 Subject: [PATCH 12/12] chore: make linter happy p.2 --- tests/test_mongo_cleanup.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/test_mongo_cleanup.py b/tests/test_mongo_cleanup.py index 2132907..e195cc8 100644 --- a/tests/test_mongo_cleanup.py +++ b/tests/test_mongo_cleanup.py @@ -1,3 +1,5 @@ +"""Test MongoDB cleanup functionality.""" + from pymongo import MongoClient