From b6a2d448f2edf9799bd7e8fc8937570201bdc153 Mon Sep 17 00:00:00 2001 From: epenet <6771947+epenet@users.noreply.github.com> Date: Fri, 18 Oct 2024 10:11:18 +0200 Subject: [PATCH 1/4] feat: improve xdist compatibility --- src/syrupy/data.py | 11 ++++++++ src/syrupy/report.py | 31 +++++++++++++++++++++ src/syrupy/session.py | 63 ++++++++++++++++++++++++++++++++++++++++--- 3 files changed, 102 insertions(+), 3 deletions(-) diff --git a/src/syrupy/data.py b/src/syrupy/data.py index 3d710f97..97b83608 100644 --- a/src/syrupy/data.py +++ b/src/syrupy/data.py @@ -4,6 +4,7 @@ ) from typing import ( TYPE_CHECKING, + Any, Dict, Iterator, List, @@ -124,6 +125,16 @@ def __iter__(self) -> Iterator["SnapshotCollection"]: def __contains__(self, key: str) -> bool: return key in self._snapshot_collections + def serialize(self) -> dict[str, Any]: + return {k: [c.name for c in v] for k, v in self._snapshot_collections.items()} + + def merge_serialized(self, data: dict[str, Any]) -> None: + for location, names in data.items(): + snapshot_collection = SnapshotCollection(location=location) + for name in names: + snapshot_collection.add(Snapshot(name)) + self.update(snapshot_collection) + @dataclass class DiffedLine: diff --git a/src/syrupy/report.py b/src/syrupy/report.py index 7d07e14c..b04eb3cd 100644 --- a/src/syrupy/report.py +++ b/src/syrupy/report.py @@ -508,6 +508,37 @@ def _ran_items_match_location(self, snapshot_location: str) -> bool: for item in self.ran_items ) + def serialize(self) -> dict[str, Any]: + return { + "discovered": self.discovered.serialize(), + "created": self.created.serialize(), + "failed": self.failed.serialize(), + "matched": self.matched.serialize(), + "updated": self.updated.serialize(), + "used": self.used.serialize(), + "_collected_items": [ + { + "nodeid": c.nodeid, + "name": c.name, + "path": str(c.path), + "modulename": c.obj.__module__, # type: ignore[attr-defined] + "methodname": c.obj.__name__, # type: ignore[attr-defined] + } + for c in list(self.collected_items) + ], + "_selected_items": { + key: status.value for key, status in self.selected_items.items() + }, + } + + def merge_serialized(self, data: dict[str, Any]) -> None: + self.discovered.merge_serialized(data["discovered"]) + self.created.merge_serialized(data["created"]) + self.failed.merge_serialized(data["failed"]) + self.matched.merge_serialized(data["matched"]) + self.updated.merge_serialized(data["updated"]) + self.used.merge_serialized(data["used"]) + @dataclass(frozen=True) class Expression: diff --git a/src/syrupy/session.py b/src/syrupy/session.py index 9770948a..050231c8 100644 --- a/src/syrupy/session.py +++ b/src/syrupy/session.py @@ -1,3 +1,5 @@ +import json +import os from collections import defaultdict from dataclasses import ( dataclass, @@ -46,6 +48,20 @@ class ItemStatus(Enum): SKIPPED = "skipped" +class _FakePytestObject: + def __init__(self, collected_item: dict[str, str]) -> None: + self.__module__ = collected_item["modulename"] + self.__name__ = collected_item["methodname"] + + +class _FakePytestItem: + def __init__(self, collected_item: dict[str, str]) -> None: + self.nodeid = collected_item["nodeid"] + self.name = collected_item["name"] + self.path = Path(collected_item["path"]) + self.obj = _FakePytestObject(collected_item) + + @dataclass class SnapshotSession: pytest_session: "pytest.Session" @@ -127,6 +143,24 @@ def ran_item( except ValueError: pass # if we don't understand the outcome, leave the item as "not run" + def _merge_collected_items(self, collected_items: list[dict[str, str]]) -> None: + for collected_item in collected_items: + custom_item = _FakePytestItem(collected_item) + if not any( + t.nodeid == custom_item.nodeid and t.name == custom_item.nodeid + for t in self._collected_items + ): + self._collected_items.add(custom_item) # type: ignore[arg-type] + + def _merge_selected_items(self, selected_items: dict[str, str]) -> None: + for key, selected_item in selected_items.items(): + if key in self._selected_items: + status = ItemStatus(selected_item) + if status != ItemStatus.NOT_RUN: + self._selected_items[key] = status + else: + self._selected_items[key] = ItemStatus(selected_item) + def finish(self) -> int: exitstatus = 0 self.flush_snapshot_write_queue() @@ -139,9 +173,15 @@ def finish(self) -> int: ) if is_xdist_worker(): - # TODO: If we're in a pytest-xdist worker, we need to combine the reports - # of all the workers so that the controller can handle unused - # snapshot removal. + worker_count = os.getenv("PYTEST_XDIST_WORKER_COUNT") + with open(".pytest_syrupy_worker_count", "w", encoding="utf-8") as f: + f.write(worker_count) # type: ignore[arg-type] + with open( + f".pytest_syrupy_{os.getenv("PYTEST_XDIST_WORKER")}_result", + "w", + encoding="utf-8", + ) as f: + json.dump(self.report.serialize(), f, indent=2) return exitstatus elif is_xdist_controller(): # TODO: If we're in a pytest-xdist controller, merge all the reports. @@ -149,6 +189,23 @@ def finish(self) -> int: # partially functional. return exitstatus + worker_count = None + try: + with open(".pytest_syrupy_worker_count", encoding="utf-8") as f: + worker_count = f.read() + os.remove(".pytest_syrupy_worker_count") + except FileNotFoundError: + pass + + if worker_count: + for i in range(int(worker_count)): + with open(f".pytest_syrupy_gw{i}_result", encoding="utf-8") as f: + data = json.load(f) + self._merge_collected_items(data["_collected_items"]) + self._merge_selected_items(data["_selected_items"]) + self.report.merge_serialized(data) + os.remove(f".pytest_syrupy_gw{i}_result") + if self.report.num_unused: if self.update_snapshots: self.remove_unused_snapshots( From 27f535dcbcbadac5222c10ac42b7e57ee4b177c6 Mon Sep 17 00:00:00 2001 From: epenet <6771947+epenet@users.noreply.github.com> Date: Fri, 18 Oct 2024 10:28:38 +0200 Subject: [PATCH 2/4] adjust tests --- tests/integration/test_custom_comparator.py | 8 +-- tests/integration/test_pytest_extension.py | 6 +- .../test_single_file_multiple_extensions.py | 12 ++-- .../test_snapshot_option_include_details.py | 16 ++--- .../integration/test_snapshot_option_name.py | 12 ++-- .../test_snapshot_option_update.py | 58 +++++++------------ .../test_snapshot_option_warn_unused.py | 12 ++-- .../test_snapshot_outside_directory.py | 12 ++-- .../test_snapshot_similar_names_default.py | 24 ++++---- ...t_snapshot_similar_names_file_extension.py | 24 ++++---- tests/integration/test_snapshot_skipped.py | 12 ++-- .../test_snapshot_use_extension.py | 16 ++--- tests/integration/test_xfail.py | 8 +-- 13 files changed, 101 insertions(+), 119 deletions(-) diff --git a/tests/integration/test_custom_comparator.py b/tests/integration/test_custom_comparator.py index d88ebf9e..ad426f3a 100644 --- a/tests/integration/test_custom_comparator.py +++ b/tests/integration/test_custom_comparator.py @@ -71,18 +71,18 @@ def test_passed_custom(snapshot_custom): @pytest.mark.xfail(strict=False) -def test_failed_snapshots(generate_snapshots): +def test_failed_snapshots(generate_snapshots, plugin_args): testdir = generate_snapshots[1] testdir.makepyfile(test_file=generate_snapshots[2]["failed"]) - result = testdir.runpytest("-v") + result = testdir.runpytest("-v", *plugin_args) result.stdout.re_match_lines((r"1 snapshot failed\.")) assert result.ret == 1 @pytest.mark.xfail(strict=False) -def test_updated_snapshots(generate_snapshots, plugin_args_fails_xdist): +def test_updated_snapshots(generate_snapshots, plugin_args): _, testdir, initial = generate_snapshots testdir.makepyfile(test_file=initial["failed"]) - result = testdir.runpytest("-v", "--snapshot-update", *plugin_args_fails_xdist) + result = testdir.runpytest("-v", "--snapshot-update", *plugin_args) result.stdout.re_match_lines((r"1 snapshot updated\.")) assert result.ret == 0 diff --git a/tests/integration/test_pytest_extension.py b/tests/integration/test_pytest_extension.py index d8186fa7..556ea38c 100644 --- a/tests/integration/test_pytest_extension.py +++ b/tests/integration/test_pytest_extension.py @@ -46,7 +46,7 @@ def test_example(snapshot): assert result.ret == 0 -def test_does_not_print_empty_snapshot_report(testdir, plugin_args_fails_xdist): +def test_does_not_print_empty_snapshot_report(testdir, plugin_args): testdir.makeconftest("") testcase_no_snapshots = """ def test_example(snapshot): @@ -61,7 +61,7 @@ def test_example(snapshot): ) result = testdir.runpytest( - "-v", "test_file_no.py", "--snapshot-update", *plugin_args_fails_xdist + "-v", "test_file_no.py", "--snapshot-update", *plugin_args ) result.stdout.re_match_lines((r".*test_file_no.py.*")) assert "snapshot report" not in result.stdout.str() @@ -69,7 +69,7 @@ def test_example(snapshot): assert result.ret == 0 result = testdir.runpytest( - "-v", "test_file_yes.py", "--snapshot-update", *plugin_args_fails_xdist + "-v", "test_file_yes.py", "--snapshot-update", *plugin_args ) result.stdout.re_match_lines((r".*test_file_yes.py.*", r".*snapshot report.*")) assert result.ret == 0 diff --git a/tests/integration/test_single_file_multiple_extensions.py b/tests/integration/test_single_file_multiple_extensions.py index 8c4fb0dc..fe2e73c5 100644 --- a/tests/integration/test_single_file_multiple_extensions.py +++ b/tests/integration/test_single_file_multiple_extensions.py @@ -1,7 +1,7 @@ from pathlib import Path -def test_multiple_file_extensions(testdir, plugin_args_fails_xdist): +def test_multiple_file_extensions(testdir, plugin_args): file_extension = "ext2.ext1" testcase = f""" @@ -21,7 +21,7 @@ def test_dot_in_filename(snapshot): test_file: Path = testdir.makepyfile(test_file=testcase) - result = testdir.runpytest("-v", "--snapshot-update", *plugin_args_fails_xdist) + result = testdir.runpytest("-v", "--snapshot-update", *plugin_args) result.stdout.re_match_lines((r"1 snapshot generated\.")) assert "snapshots unused" not in result.stdout.str() assert result.ret == 0 @@ -34,13 +34,13 @@ def test_dot_in_filename(snapshot): ) assert snapshot_file.exists() - result = testdir.runpytest("-v", *plugin_args_fails_xdist) + result = testdir.runpytest("-v", *plugin_args) result.stdout.re_match_lines((r"1 snapshot passed\.")) assert "snapshots unused" not in result.stdout.str() assert result.ret == 0 -def test_class_style(testdir, plugin_args_fails_xdist): +def test_class_style(testdir, plugin_args): """ Regression test for https://github.com/syrupy-project/syrupy/issues/717 """ @@ -60,7 +60,7 @@ def test_foo(self, snapshot): test_file: Path = testdir.makepyfile(test_file=testcase) - result = testdir.runpytest("-v", "--snapshot-update", *plugin_args_fails_xdist) + result = testdir.runpytest("-v", "--snapshot-update", *plugin_args) result.stdout.re_match_lines((r"1 snapshot generated\.")) assert "deleted" not in result.stdout.str() assert result.ret == 0 @@ -70,7 +70,7 @@ def test_foo(self, snapshot): ) assert snapshot_file.exists() - result = testdir.runpytest("-v", *plugin_args_fails_xdist) + result = testdir.runpytest("-v", *plugin_args) result.stdout.re_match_lines((r"1 snapshot passed\.")) assert "snapshots unused" not in result.stdout.str() assert result.ret == 0 diff --git a/tests/integration/test_snapshot_option_include_details.py b/tests/integration/test_snapshot_option_include_details.py index e2224c64..5c25f83d 100644 --- a/tests/integration/test_snapshot_option_include_details.py +++ b/tests/integration/test_snapshot_option_include_details.py @@ -68,12 +68,12 @@ def test_unused_snapshots_details( expected_status_code, run_testfiles_with_update, testcases, - plugin_args_fails_xdist, + plugin_args, ): testdir = run_testfiles_with_update(test_file=testcases) testdir.makepyfile(test_file=testcases["used"]) - result = testdir.runpytest(*options, *plugin_args_fails_xdist) + result = testdir.runpytest(*options, *plugin_args) result.stdout.re_match_lines( ( r"1 snapshot passed\. 1 snapshot unused\.", @@ -85,7 +85,7 @@ def test_unused_snapshots_details( def test_unused_snapshots_details_multiple_tests( - run_testfiles_with_update, testcases, extra_testcases, plugin_args_fails_xdist + run_testfiles_with_update, testcases, extra_testcases, plugin_args ): testdir = run_testfiles_with_update( test_file=testcases, test_second_file=extra_testcases @@ -95,7 +95,7 @@ def test_unused_snapshots_details_multiple_tests( test_second_file="", ) - result = testdir.runpytest("-v", "--snapshot-details", *plugin_args_fails_xdist) + result = testdir.runpytest("-v", "--snapshot-details", *plugin_args) result.stdout.re_match_lines( ( r"2 snapshots passed\. 2 snapshots unused\.", @@ -108,7 +108,7 @@ def test_unused_snapshots_details_multiple_tests( def test_unused_snapshots_details_multiple_locations( - run_testfiles_with_update, testcases, extra_testcases, plugin_args_fails_xdist + run_testfiles_with_update, testcases, extra_testcases, plugin_args ): testdir = run_testfiles_with_update( test_file=testcases, test_second_file=extra_testcases @@ -118,7 +118,7 @@ def test_unused_snapshots_details_multiple_locations( test_second_file=extra_testcases["extra_a"], ) - result = testdir.runpytest("-v", "--snapshot-details", *plugin_args_fails_xdist) + result = testdir.runpytest("-v", "--snapshot-details", *plugin_args) result.stdout.re_match_lines_random( ( r"2 snapshots passed\. 2 snapshots unused\.", @@ -131,13 +131,13 @@ def test_unused_snapshots_details_multiple_locations( def test_unused_snapshots_details_no_details_on_deletion( - run_testfiles_with_update, testcases, plugin_args_fails_xdist + run_testfiles_with_update, testcases, plugin_args ): testdir = run_testfiles_with_update(test_file=testcases) testdir.makepyfile(test_file=testcases["used"]) result = testdir.runpytest( - "-v", "--snapshot-details", "--snapshot-update", *plugin_args_fails_xdist + "-v", "--snapshot-details", "--snapshot-update", *plugin_args ) result.stdout.re_match_lines( ( diff --git a/tests/integration/test_snapshot_option_name.py b/tests/integration/test_snapshot_option_name.py index fd58df57..f1cf969b 100644 --- a/tests/integration/test_snapshot_option_name.py +++ b/tests/integration/test_snapshot_option_name.py @@ -32,25 +32,25 @@ def run_testcases(testdir, testcases): return testdir, testcases -def test_run_all(run_testcases, plugin_args_fails_xdist): +def test_run_all(run_testcases, plugin_args): testdir, testcases = run_testcases - result = testdir.runpytest("-v", *plugin_args_fails_xdist) + result = testdir.runpytest("-v", *plugin_args) result.stdout.re_match_lines("2 snapshots passed") assert result.ret == 0 -def test_failure(run_testcases, plugin_args_fails_xdist): +def test_failure(run_testcases, plugin_args): testdir, testcases = run_testcases testdir.makepyfile(test_1=testcases["modified"]) - result = testdir.runpytest("-vv", *plugin_args_fails_xdist) + result = testdir.runpytest("-vv", *plugin_args) result.stdout.re_match_lines("1 snapshot failed. 1 snapshot passed.") assert result.ret == 1 -def test_update(run_testcases, plugin_args_fails_xdist): +def test_update(run_testcases, plugin_args): testdir, testcases = run_testcases testdir.makepyfile(test_1=testcases["modified"]) - result = testdir.runpytest("-v", "--snapshot-update", *plugin_args_fails_xdist) + result = testdir.runpytest("-v", "--snapshot-update", *plugin_args) assert "Can not relate snapshot name" not in str(result.stdout) result.stdout.re_match_lines("1 snapshot passed. 1 snapshot updated.") assert result.ret == 0 diff --git a/tests/integration/test_snapshot_option_update.py b/tests/integration/test_snapshot_option_update.py index c4991f93..dcaac1d8 100644 --- a/tests/integration/test_snapshot_option_update.py +++ b/tests/integration/test_snapshot_option_update.py @@ -184,17 +184,17 @@ def test_update_failure_shows_snapshot_diff( def test_update_success_shows_snapshot_report( - run_testcases, testcases_updated, plugin_args_fails_xdist + run_testcases, testcases_updated, plugin_args ): testdir = run_testcases[1] testdir.makepyfile(**testcases_updated) - result = testdir.runpytest("-v", "--snapshot-update", *plugin_args_fails_xdist) + result = testdir.runpytest("-v", "--snapshot-update", *plugin_args) result.stdout.re_match_lines((r"5 snapshots passed\. 5 snapshots updated\.")) assert result.ret == 0 def test_update_targets_only_selected_parametrized_tests_for_update_dash_m( - run_testcases, plugin_args_fails_xdist + run_testcases, plugin_args ): updated_tests = { "test_used": ( @@ -210,7 +210,7 @@ def test_used(snapshot, actual): testdir = run_testcases[1] testdir.makepyfile(**updated_tests) result = testdir.runpytest( - "-v", "--snapshot-update", *plugin_args_fails_xdist, "-m", "parametrize" + "-v", "--snapshot-update", *plugin_args, "-m", "parametrize" ) result.stdout.re_match_lines( ( @@ -224,7 +224,7 @@ def test_used(snapshot, actual): def test_update_targets_only_selected_parametrized_tests_for_update_dash_k( - run_testcases, plugin_args_fails_xdist + run_testcases, plugin_args ): updated_tests = { "test_used": ( @@ -240,7 +240,7 @@ def test_used(snapshot, actual): testdir = run_testcases[1] testdir.makepyfile(**updated_tests) result = testdir.runpytest( - "-v", "--snapshot-update", *plugin_args_fails_xdist, "-k", "test_used[2]" + "-v", "--snapshot-update", *plugin_args, "-k", "test_used[2]" ) result.stdout.re_match_lines((r"1 snapshot updated\.")) assert "Deleted" not in result.stdout.str() @@ -250,7 +250,7 @@ def test_used(snapshot, actual): def test_update_targets_only_selected_parametrized_tests_for_removal_dash_k( - run_testcases, plugin_args_fails_xdist + run_testcases, plugin_args ): updated_tests = { "test_used": ( @@ -266,7 +266,7 @@ def test_used(snapshot, actual): testdir = run_testcases[1] testdir.makepyfile(**updated_tests) result = testdir.runpytest( - "-v", "--snapshot-update", *plugin_args_fails_xdist, "-k", "test_used[" + "-v", "--snapshot-update", *plugin_args, "-k", "test_used[" ) result.stdout.re_match_lines( ( @@ -279,9 +279,7 @@ def test_used(snapshot, actual): assert Path(*snapshot_path, "test_updated_1.ambr").exists() -def test_update_targets_only_selected_class_tests_dash_k( - testdir, plugin_args_fails_xdist -): +def test_update_targets_only_selected_class_tests_dash_k(testdir, plugin_args): test_content = """ import pytest @@ -298,15 +296,13 @@ def test_case_2(self, snapshot): assert Path(testdir.tmpdir, "__snapshots__", "test_content.ambr").exists() result = testdir.runpytest( - "test_content.py", "-v", *plugin_args_fails_xdist, "-k", "test_case_2" + "test_content.py", "-v", *plugin_args, "-k", "test_case_2" ) result.stdout.re_match_lines((r"1 snapshot passed\.")) assert "snaphot unused" not in result.stdout.str() -def test_update_targets_only_selected_module_tests_dash_k( - testdir, plugin_args_fails_xdist -): +def test_update_targets_only_selected_module_tests_dash_k(testdir, plugin_args): test_content = """ import pytest @@ -322,21 +318,19 @@ def test_case_2(snapshot): assert Path(testdir.tmpdir, "__snapshots__", "test_content.ambr").exists() result = testdir.runpytest( - "test_content.py", "-v", *plugin_args_fails_xdist, "-k", "test_case_2" + "test_content.py", "-v", *plugin_args, "-k", "test_case_2" ) result.stdout.re_match_lines((r"1 snapshot passed\.")) assert "snaphot unused" not in result.stdout.str() -def test_update_targets_only_selected_module_tests_nodes( - run_testcases, plugin_args_fails_xdist -): +def test_update_targets_only_selected_module_tests_nodes(run_testcases, plugin_args): testdir = run_testcases[1] snapfile_empty = Path("__snapshots__", "empty_snapfile.ambr") testdir.makefile(".ambr", **{str(snapfile_empty): ""}) testfile = Path(testdir.tmpdir, "test_used.py") result = testdir.runpytest( - "-v", f"{testfile}::test_used", "--snapshot-update", *plugin_args_fails_xdist + "-v", f"{testfile}::test_used", "--snapshot-update", *plugin_args ) result.stdout.re_match_lines((r"3 snapshots passed\.")) assert "unused" not in result.stdout.str() @@ -368,7 +362,7 @@ def test_update_targets_only_selected_module_tests_nodes_pyargs( def test_update_targets_only_selected_module_tests_file_for_update( - run_testcases, plugin_args_fails_xdist + run_testcases, plugin_args ): testdir = run_testcases[1] snapfile_empty = Path("__snapshots__", "empty_snapfile.ambr") @@ -384,9 +378,7 @@ def test_used(snapshot, actual): """ ) ) - result = testdir.runpytest( - "-v", "test_used.py", "--snapshot-update", *plugin_args_fails_xdist - ) + result = testdir.runpytest("-v", "test_used.py", "--snapshot-update", *plugin_args) result.stdout.re_match_lines( ( r"3 snapshots passed\. 2 unused snapshots deleted\.", @@ -399,7 +391,7 @@ def test_used(snapshot, actual): def test_update_targets_only_selected_module_tests_file_for_removal( - run_testcases, plugin_args_fails_xdist + run_testcases, plugin_args ): testdir = run_testcases[1] testdir.makepyfile( @@ -412,9 +404,7 @@ def test_used(snapshot): ) snapfile_empty = Path("__snapshots__", "empty_snapfile.ambr") testdir.makefile(".ambr", **{str(snapfile_empty): ""}) - result = testdir.runpytest( - "-v", "test_used.py", "--snapshot-update", *plugin_args_fails_xdist - ) + result = testdir.runpytest("-v", "test_used.py", "--snapshot-update", *plugin_args) result.stdout.re_match_lines( ( r"5 unused snapshots deleted\.", @@ -427,14 +417,12 @@ def test_used(snapshot): assert not Path("__snapshots__", "test_used.ambr").exists() -def test_update_removes_empty_snapshot_collection_only( - run_testcases, plugin_args_fails_xdist -): +def test_update_removes_empty_snapshot_collection_only(run_testcases, plugin_args): testdir = run_testcases[1] snapfile_empty = Path("__snapshots__", "empty_snapfile.ambr") testdir.makefile(".ambr", **{str(snapfile_empty): ""}) assert snapfile_empty.exists() - result = testdir.runpytest("-v", "--snapshot-update", *plugin_args_fails_xdist) + result = testdir.runpytest("-v", "--snapshot-update", *plugin_args) result.stdout.re_match_lines( ( r"10 snapshots passed\. 1 unused snapshot deleted\.", @@ -447,15 +435,13 @@ def test_update_removes_empty_snapshot_collection_only( assert Path("__snapshots__", "test_used.ambr").exists() -def test_update_removes_hanging_snapshot_collection_file( - run_testcases, plugin_args_fails_xdist -): +def test_update_removes_hanging_snapshot_collection_file(run_testcases, plugin_args): testdir = run_testcases[1] snapfile_used = Path("__snapshots__", "test_used.ambr") snapfile_hanging = Path("__snapshots__", "hanging_snapfile.abc") testdir.makefile(".abc", **{str(snapfile_hanging): ""}) assert snapfile_hanging.exists() - result = testdir.runpytest("-v", "--snapshot-update", *plugin_args_fails_xdist) + result = testdir.runpytest("-v", "--snapshot-update", *plugin_args) result.stdout.re_match_lines( ( r"10 snapshots passed\. 1 unused snapshot deleted\.", diff --git a/tests/integration/test_snapshot_option_warn_unused.py b/tests/integration/test_snapshot_option_warn_unused.py index 99442583..40f3ee85 100644 --- a/tests/integration/test_snapshot_option_warn_unused.py +++ b/tests/integration/test_snapshot_option_warn_unused.py @@ -28,11 +28,11 @@ def run_testcases(testdir, testcases): return testdir, testcases -def test_unused_snapshots_failure(run_testcases, plugin_args_fails_xdist): +def test_unused_snapshots_failure(run_testcases, plugin_args): testdir, testcases = run_testcases testdir.makepyfile(test_file=testcases["used"]) - result = testdir.runpytest("-v", *plugin_args_fails_xdist) + result = testdir.runpytest("-v", *plugin_args) result.stdout.re_match_lines( ( r"1 snapshot passed\. 1 snapshot unused\.", @@ -42,11 +42,11 @@ def test_unused_snapshots_failure(run_testcases, plugin_args_fails_xdist): assert result.ret == 1 -def test_unused_snapshots_warning(run_testcases, plugin_args_fails_xdist): +def test_unused_snapshots_warning(run_testcases, plugin_args): testdir, testcases = run_testcases testdir.makepyfile(test_file=testcases["used"]) - result = testdir.runpytest("-v", "--snapshot-warn-unused", *plugin_args_fails_xdist) + result = testdir.runpytest("-v", "--snapshot-warn-unused", *plugin_args) result.stdout.re_match_lines( ( r"1 snapshot passed\. 1 snapshot unused\.", @@ -56,11 +56,11 @@ def test_unused_snapshots_warning(run_testcases, plugin_args_fails_xdist): assert result.ret == 0 -def test_unused_snapshots_deletion(run_testcases, plugin_args_fails_xdist): +def test_unused_snapshots_deletion(run_testcases, plugin_args): testdir, testcases = run_testcases testdir.makepyfile(test_file=testcases["used"]) - result = testdir.runpytest("-v", "--snapshot-update", *plugin_args_fails_xdist) + result = testdir.runpytest("-v", "--snapshot-update", *plugin_args) result.stdout.re_match_lines( ( r"1 snapshot passed\. 1 unused snapshot deleted\.", diff --git a/tests/integration/test_snapshot_outside_directory.py b/tests/integration/test_snapshot_outside_directory.py index 87defe71..e8a7d37b 100644 --- a/tests/integration/test_snapshot_outside_directory.py +++ b/tests/integration/test_snapshot_outside_directory.py @@ -57,25 +57,25 @@ def test_generated_snapshots(generate_snapshots): assert result.ret == 0 -def test_unmatched_snapshots(generate_snapshots, plugin_args_fails_xdist): +def test_unmatched_snapshots(generate_snapshots, plugin_args): _, testdir, testcases = generate_snapshots testdir.makepyfile(test_file=testcases["one"]) - result = testdir.runpytest("-v", *plugin_args_fails_xdist) + result = testdir.runpytest("-v", *plugin_args) result.stdout.re_match_lines((r"1 snapshot passed. 1 snapshot unused\.")) assert result.ret == 1 -def test_updated_snapshots_partial_delete(generate_snapshots, plugin_args_fails_xdist): +def test_updated_snapshots_partial_delete(generate_snapshots, plugin_args): _, testdir, testcases = generate_snapshots testdir.makepyfile(test_file=testcases["one"]) - result = testdir.runpytest("-v", "--snapshot-update", *plugin_args_fails_xdist) + result = testdir.runpytest("-v", "--snapshot-update", *plugin_args) result.stdout.re_match_lines(r"1 snapshot passed. 1 unused snapshot deleted\.") assert result.ret == 0 -def test_updated_snapshots_full_delete(generate_snapshots, plugin_args_fails_xdist): +def test_updated_snapshots_full_delete(generate_snapshots, plugin_args): _, testdir, testcases = generate_snapshots testdir.makepyfile(test_file=testcases["zero"]) - result = testdir.runpytest("-v", "--snapshot-update", *plugin_args_fails_xdist) + result = testdir.runpytest("-v", "--snapshot-update", *plugin_args) result.stdout.re_match_lines(r"2 unused snapshots deleted\.") assert result.ret == 0 diff --git a/tests/integration/test_snapshot_similar_names_default.py b/tests/integration/test_snapshot_similar_names_default.py index ea832a74..7dc3cabf 100644 --- a/tests/integration/test_snapshot_similar_names_default.py +++ b/tests/integration/test_snapshot_similar_names_default.py @@ -36,61 +36,61 @@ def run_testcases(testdir, testcases): return testdir, testcases -def test_run_all(run_testcases, plugin_args_fails_xdist): +def test_run_all(run_testcases, plugin_args): testdir, testcases = run_testcases - result = testdir.runpytest("-v", *plugin_args_fails_xdist) + result = testdir.runpytest("-v", *plugin_args) result.stdout.re_match_lines("9 snapshots passed") assert result.ret == 0 -def test_run_single_file(run_testcases, plugin_args_fails_xdist): +def test_run_single_file(run_testcases, plugin_args): testdir, testcases = run_testcases - result = testdir.runpytest("-v", "test_1.py", *plugin_args_fails_xdist) + result = testdir.runpytest("-v", "test_1.py", *plugin_args) result.stdout.re_match_lines("3 snapshots passed") assert result.ret == 0 -def test_run_single_test_case_in_file(run_testcases, plugin_args_fails_xdist): +def test_run_single_test_case_in_file(run_testcases, plugin_args): testdir, testcases = run_testcases - result = testdir.runpytest("-v", "test_2.py::test_a", *plugin_args_fails_xdist) + result = testdir.runpytest("-v", "test_2.py::test_a", *plugin_args) result.stdout.re_match_lines("1 snapshot passed") assert result.ret == 0 -def test_run_all_but_one(run_testcases, plugin_args_fails_xdist): +def test_run_all_but_one(run_testcases, plugin_args): testdir, testcases = run_testcases result = testdir.runpytest( "-v", "--snapshot-details", "test_1.py", "test_2.py::test_a", - *plugin_args_fails_xdist, + *plugin_args, ) result.stdout.re_match_lines("4 snapshots passed") assert result.ret == 0 -def test_run_both_files_by_node(run_testcases, plugin_args_fails_xdist): +def test_run_both_files_by_node(run_testcases, plugin_args): testdir, testcases = run_testcases result = testdir.runpytest( "-v", "--snapshot-details", "test_1.py::test_a", "test_2.py::test_a", - *plugin_args_fails_xdist, + *plugin_args, ) result.stdout.re_match_lines("2 snapshots passed") assert result.ret == 0 -def test_run_both_files_by_node_2(run_testcases, plugin_args_fails_xdist): +def test_run_both_files_by_node_2(run_testcases, plugin_args): testdir, testcases = run_testcases result = testdir.runpytest( "-v", "--snapshot-details", "test_1.py::test_b", "test_2.py::test_a", - *plugin_args_fails_xdist, + *plugin_args, ) result.stdout.re_match_lines("2 snapshots passed") assert result.ret == 0 diff --git a/tests/integration/test_snapshot_similar_names_file_extension.py b/tests/integration/test_snapshot_similar_names_file_extension.py index 520baad7..b513b964 100644 --- a/tests/integration/test_snapshot_similar_names_file_extension.py +++ b/tests/integration/test_snapshot_similar_names_file_extension.py @@ -41,45 +41,45 @@ def run_testcases(testdir, testcases): return testdir, testcases -def test_run_all(run_testcases, plugin_args_fails_xdist): +def test_run_all(run_testcases, plugin_args): testdir, testcases = run_testcases result = testdir.runpytest( "-v", "--snapshot-default-extension", "syrupy.extensions.single_file.SingleFileSnapshotExtension", - *plugin_args_fails_xdist, + *plugin_args, ) result.stdout.re_match_lines("9 snapshots passed") assert result.ret == 0 -def test_run_single_file(run_testcases, plugin_args_fails_xdist): +def test_run_single_file(run_testcases, plugin_args): testdir, testcases = run_testcases result = testdir.runpytest( "-v", "--snapshot-default-extension", "syrupy.extensions.single_file.SingleFileSnapshotExtension", "test_1.py", - *plugin_args_fails_xdist, + *plugin_args, ) result.stdout.re_match_lines("3 snapshots passed") assert result.ret == 0 -def test_run_single_test_case_in_file(run_testcases, plugin_args_fails_xdist): +def test_run_single_test_case_in_file(run_testcases, plugin_args): testdir, testcases = run_testcases result = testdir.runpytest( "-v", "--snapshot-default-extension", "syrupy.extensions.single_file.SingleFileSnapshotExtension", "test_2.py::test_a", - *plugin_args_fails_xdist, + *plugin_args, ) result.stdout.re_match_lines("1 snapshot passed") assert result.ret == 0 -def test_run_all_but_one(run_testcases, plugin_args_fails_xdist): +def test_run_all_but_one(run_testcases, plugin_args): testdir, testcases = run_testcases result = testdir.runpytest( "-v", @@ -88,13 +88,13 @@ def test_run_all_but_one(run_testcases, plugin_args_fails_xdist): "syrupy.extensions.single_file.SingleFileSnapshotExtension", "test_1.py", "test_2.py::test_a", - *plugin_args_fails_xdist, + *plugin_args, ) result.stdout.re_match_lines("4 snapshots passed") assert result.ret == 0 -def test_run_both_files_by_node(run_testcases, plugin_args_fails_xdist): +def test_run_both_files_by_node(run_testcases, plugin_args): testdir, testcases = run_testcases result = testdir.runpytest( "-v", @@ -103,13 +103,13 @@ def test_run_both_files_by_node(run_testcases, plugin_args_fails_xdist): "syrupy.extensions.single_file.SingleFileSnapshotExtension", "test_1.py::test_a", "test_2.py::test_a", - *plugin_args_fails_xdist, + *plugin_args, ) result.stdout.re_match_lines("2 snapshots passed") assert result.ret == 0 -def test_run_both_files_by_node_2(run_testcases, plugin_args_fails_xdist): +def test_run_both_files_by_node_2(run_testcases, plugin_args): testdir, testcases = run_testcases result = testdir.runpytest( "-v", @@ -118,7 +118,7 @@ def test_run_both_files_by_node_2(run_testcases, plugin_args_fails_xdist): "syrupy.extensions.single_file.SingleFileSnapshotExtension", "test_1.py::test_b", "test_2.py::test_a", - *plugin_args_fails_xdist, + *plugin_args, ) result.stdout.re_match_lines("2 snapshots passed") assert result.ret == 0 diff --git a/tests/integration/test_snapshot_skipped.py b/tests/integration/test_snapshot_skipped.py index 1e276093..9763dd47 100644 --- a/tests/integration/test_snapshot_skipped.py +++ b/tests/integration/test_snapshot_skipped.py @@ -44,31 +44,31 @@ def run_testcases(testdir, testcases): return testdir, testcases -def test_mark_skipped_snapshots(run_testcases, plugin_args_fails_xdist): +def test_mark_skipped_snapshots(run_testcases, plugin_args): testdir, testcases = run_testcases pyfile_content = "\n\n".join([testcases["used"], testcases["mark-skipped"]]) testdir.makepyfile(test_file=pyfile_content) - result = testdir.runpytest("-v", *plugin_args_fails_xdist) + result = testdir.runpytest("-v", *plugin_args) result.stdout.re_match_lines(r"1 snapshot passed\.$") assert result.ret == 0 -def test_raise_skipped_snapshots(run_testcases, plugin_args_fails_xdist): +def test_raise_skipped_snapshots(run_testcases, plugin_args): testdir, testcases = run_testcases pyfile_content = "\n\n".join([testcases["used"], testcases["raise-skipped"]]) testdir.makepyfile(test_file=pyfile_content) - result = testdir.runpytest("-v", *plugin_args_fails_xdist) + result = testdir.runpytest("-v", *plugin_args) result.stdout.re_match_lines(r"1 snapshot passed\.$") assert result.ret == 0 -def test_skipped_snapshots_update(run_testcases, plugin_args_fails_xdist): +def test_skipped_snapshots_update(run_testcases, plugin_args): testdir, testcases = run_testcases pyfile_content = "\n\n".join([testcases["used"], testcases["raise-skipped"]]) testdir.makepyfile(test_file=pyfile_content) - result = testdir.runpytest("-v", "--snapshot-update", *plugin_args_fails_xdist) + result = testdir.runpytest("-v", "--snapshot-update", *plugin_args) result.stdout.re_match_lines(r"1 snapshot passed\.$") assert result.ret == 0 diff --git a/tests/integration/test_snapshot_use_extension.py b/tests/integration/test_snapshot_use_extension.py index cfe0df26..d528a5f7 100644 --- a/tests/integration/test_snapshot_use_extension.py +++ b/tests/integration/test_snapshot_use_extension.py @@ -104,9 +104,9 @@ def test_unsaved_snapshots(testdir, testcases_initial): assert result.ret == 1 -def test_failed_snapshots(testdir, testcases_initial, plugin_args_fails_xdist): +def test_failed_snapshots(testdir, testcases_initial, plugin_args): testdir.makepyfile(test_file=testcases_initial["failed"]) - result = testdir.runpytest("-v", "--snapshot-update", *plugin_args_fails_xdist) + result = testdir.runpytest("-v", "--snapshot-update", *plugin_args) result.stdout.re_match_lines((r"2 snapshots failed\.")) assert result.ret == 1 @@ -118,22 +118,18 @@ def test_generated_snapshots(generate_snapshots): assert result.ret == 0 -def test_unmatched_snapshots( - generate_snapshots, testcases_updated, plugin_args_fails_xdist -): +def test_unmatched_snapshots(generate_snapshots, testcases_updated, plugin_args): testdir = generate_snapshots[1] testdir.makepyfile(test_file=testcases_updated["passed"]) - result = testdir.runpytest("-v", *plugin_args_fails_xdist) + result = testdir.runpytest("-v", *plugin_args) result.stdout.re_match_lines((r"1 snapshot failed\. 2 snapshots unused\.")) assert result.ret == 1 -def test_updated_snapshots( - generate_snapshots, testcases_updated, plugin_args_fails_xdist -): +def test_updated_snapshots(generate_snapshots, testcases_updated, plugin_args): testdir = generate_snapshots[1] testdir.makepyfile(test_file=testcases_updated["passed"]) - result = testdir.runpytest("-v", "--snapshot-update", *plugin_args_fails_xdist) + result = testdir.runpytest("-v", "--snapshot-update", *plugin_args) result.stdout.re_match_lines((r"1 snapshot updated\. 2 unused snapshots deleted\.")) assert result.ret == 0 diff --git a/tests/integration/test_xfail.py b/tests/integration/test_xfail.py index 4dee1ea1..fc5ab6f8 100644 --- a/tests/integration/test_xfail.py +++ b/tests/integration/test_xfail.py @@ -1,4 +1,4 @@ -def test_no_failure_printed_if_all_failures_xfailed(testdir, plugin_args): +def test_no_failure_printed_if_all_failures_xfailed(testdir, plugin_args_fails_xdist): testdir.makepyfile( test_file=( """ @@ -10,7 +10,7 @@ def test_a(snapshot): """ ) ) - result = testdir.runpytest("-v", *plugin_args) + result = testdir.runpytest("-v", *plugin_args_fails_xdist) result.stdout.no_re_match_line((r".*snapshot failed*")) assert result.ret == 0 @@ -38,7 +38,7 @@ def test_b(snapshot): assert result.ret == 1 -def test_failure_printed_if_xfail_does_not_run(testdir, plugin_args_fails_xdist): +def test_failure_printed_if_xfail_does_not_run(testdir, plugin_args): testdir.makepyfile( test_file=( """ @@ -50,7 +50,7 @@ def test_a(snapshot): """ ) ) - result = testdir.runpytest("-v", *plugin_args_fails_xdist) + result = testdir.runpytest("-v", *plugin_args) result.stdout.re_match_lines((r".*1 snapshot failed*")) result.stdout.no_re_match_line((r".*1 snapshot xfailed*")) assert result.ret == 1 From 2f514db2e838527aeaf5af5b3f9600679825825b Mon Sep 17 00:00:00 2001 From: epenet <6771947+epenet@users.noreply.github.com> Date: Mon, 21 Oct 2024 14:15:04 +0200 Subject: [PATCH 3/4] Fix typing --- src/syrupy/data.py | 4 ++-- src/syrupy/report.py | 4 ++-- src/syrupy/session.py | 8 ++++---- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/syrupy/data.py b/src/syrupy/data.py index 97b83608..f47f26c2 100644 --- a/src/syrupy/data.py +++ b/src/syrupy/data.py @@ -125,10 +125,10 @@ def __iter__(self) -> Iterator["SnapshotCollection"]: def __contains__(self, key: str) -> bool: return key in self._snapshot_collections - def serialize(self) -> dict[str, Any]: + def serialize(self) -> Dict[str, Any]: return {k: [c.name for c in v] for k, v in self._snapshot_collections.items()} - def merge_serialized(self, data: dict[str, Any]) -> None: + def merge_serialized(self, data: Dict[str, Any]) -> None: for location, names in data.items(): snapshot_collection = SnapshotCollection(location=location) for name in names: diff --git a/src/syrupy/report.py b/src/syrupy/report.py index b04eb3cd..e2555515 100644 --- a/src/syrupy/report.py +++ b/src/syrupy/report.py @@ -508,7 +508,7 @@ def _ran_items_match_location(self, snapshot_location: str) -> bool: for item in self.ran_items ) - def serialize(self) -> dict[str, Any]: + def serialize(self) -> Dict[str, Any]: return { "discovered": self.discovered.serialize(), "created": self.created.serialize(), @@ -531,7 +531,7 @@ def serialize(self) -> dict[str, Any]: }, } - def merge_serialized(self, data: dict[str, Any]) -> None: + def merge_serialized(self, data: Dict[str, Any]) -> None: self.discovered.merge_serialized(data["discovered"]) self.created.merge_serialized(data["created"]) self.failed.merge_serialized(data["failed"]) diff --git a/src/syrupy/session.py b/src/syrupy/session.py index 050231c8..75ee9422 100644 --- a/src/syrupy/session.py +++ b/src/syrupy/session.py @@ -49,13 +49,13 @@ class ItemStatus(Enum): class _FakePytestObject: - def __init__(self, collected_item: dict[str, str]) -> None: + def __init__(self, collected_item: Dict[str, str]) -> None: self.__module__ = collected_item["modulename"] self.__name__ = collected_item["methodname"] class _FakePytestItem: - def __init__(self, collected_item: dict[str, str]) -> None: + def __init__(self, collected_item: Dict[str, str]) -> None: self.nodeid = collected_item["nodeid"] self.name = collected_item["name"] self.path = Path(collected_item["path"]) @@ -143,7 +143,7 @@ def ran_item( except ValueError: pass # if we don't understand the outcome, leave the item as "not run" - def _merge_collected_items(self, collected_items: list[dict[str, str]]) -> None: + def _merge_collected_items(self, collected_items: List[Dict[str, str]]) -> None: for collected_item in collected_items: custom_item = _FakePytestItem(collected_item) if not any( @@ -152,7 +152,7 @@ def _merge_collected_items(self, collected_items: list[dict[str, str]]) -> None: ): self._collected_items.add(custom_item) # type: ignore[arg-type] - def _merge_selected_items(self, selected_items: dict[str, str]) -> None: + def _merge_selected_items(self, selected_items: Dict[str, str]) -> None: for key, selected_item in selected_items.items(): if key in self._selected_items: status = ItemStatus(selected_item) From 85138e3b12292fc92e3af50ca875ce42fb61b9fe Mon Sep 17 00:00:00 2001 From: epenet <6771947+epenet@users.noreply.github.com> Date: Mon, 21 Oct 2024 14:17:34 +0200 Subject: [PATCH 4/4] Fix f-string --- src/syrupy/session.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/syrupy/session.py b/src/syrupy/session.py index 75ee9422..722365ca 100644 --- a/src/syrupy/session.py +++ b/src/syrupy/session.py @@ -176,8 +176,9 @@ def finish(self) -> int: worker_count = os.getenv("PYTEST_XDIST_WORKER_COUNT") with open(".pytest_syrupy_worker_count", "w", encoding="utf-8") as f: f.write(worker_count) # type: ignore[arg-type] + worker_name = os.getenv("PYTEST_XDIST_WORKER") with open( - f".pytest_syrupy_{os.getenv("PYTEST_XDIST_WORKER")}_result", + f".pytest_syrupy_{worker_name}_result", "w", encoding="utf-8", ) as f: