pytest-neon 3.0.0__py3-none-any.whl → 3.0.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
pytest_neon/__init__.py CHANGED
@@ -9,7 +9,7 @@ from pytest_neon.plugin import (
9
9
  neon_engine,
10
10
  )
11
11
 
12
- __version__ = "3.0.0"
12
+ __version__ = "3.0.1"
13
13
  __all__ = [
14
14
  "NeonBranch",
15
15
  "neon_apply_migrations",
pytest_neon/plugin.py CHANGED
@@ -577,6 +577,7 @@ class XdistCoordinator:
577
577
  def __init__(self, tmp_path_factory: pytest.TempPathFactory):
578
578
  self.worker_id = _get_xdist_worker_id()
579
579
  self.is_xdist = self.worker_id != "main"
580
+ self._worker_count: int | None = None
580
581
 
581
582
  if self.is_xdist:
582
583
  root_tmp_dir = tmp_path_factory.getbasetemp().parent
@@ -584,6 +585,21 @@ class XdistCoordinator:
584
585
  else:
585
586
  self._lock_dir = None
586
587
 
588
+ def _get_worker_count(self) -> int:
589
+ """Get the total number of xdist workers."""
590
+ if self._worker_count is not None:
591
+ return self._worker_count
592
+
593
+ # PYTEST_XDIST_WORKER_COUNT is set by xdist
594
+ count_str = os.environ.get("PYTEST_XDIST_WORKER_COUNT")
595
+ if count_str:
596
+ self._worker_count = int(count_str)
597
+ else:
598
+ # Fallback: count from worker ID pattern (gw0, gw1, etc.)
599
+ # This shouldn't happen in normal xdist runs
600
+ self._worker_count = 1
601
+ return self._worker_count
602
+
587
603
  def coordinate_resource(
588
604
  self,
589
605
  resource_name: str,
@@ -642,6 +658,53 @@ class XdistCoordinator:
642
658
  signal_file = self._lock_dir / f"neon_{signal_name}"
643
659
  signal_file.write_text("done")
644
660
 
661
+ def signal_worker_done(self) -> None:
662
+ """Signal that this worker has completed all tests."""
663
+ if not self.is_xdist or self._lock_dir is None:
664
+ return
665
+
666
+ done_file = self._lock_dir / f"neon_worker_done_{self.worker_id}"
667
+ done_file.write_text("done")
668
+
669
+ def wait_for_all_workers_done(self, timeout: float = 300) -> None:
670
+ """
671
+ Wait for all xdist workers to signal completion.
672
+
673
+ This ensures the branch isn't deleted while other workers are still
674
+ running tests.
675
+
676
+ Args:
677
+ timeout: Maximum time to wait in seconds (default: 5 minutes)
678
+ """
679
+ if not self.is_xdist or self._lock_dir is None:
680
+ return
681
+
682
+ worker_count = self._get_worker_count()
683
+ waited = 0.0
684
+ poll_interval = 0.5
685
+
686
+ while waited < timeout:
687
+ done_count = 0
688
+ for i in range(worker_count):
689
+ done_file = self._lock_dir / f"neon_worker_done_gw{i}"
690
+ if done_file.exists():
691
+ done_count += 1
692
+
693
+ if done_count >= worker_count:
694
+ return
695
+
696
+ time.sleep(poll_interval)
697
+ waited += poll_interval
698
+
699
+ # Timeout - log warning but proceed with cleanup anyway
700
+ # This prevents infinite hangs if a worker crashes
701
+ warnings.warn(
702
+ f"Timeout waiting for all workers to complete after {timeout}s. "
703
+ f"Only {done_count}/{worker_count} workers signaled completion. "
704
+ f"Proceeding with branch cleanup.",
705
+ stacklevel=2,
706
+ )
707
+
645
708
 
646
709
  class EnvironmentManager:
647
710
  """Manages DATABASE_URL environment variable lifecycle."""
@@ -870,6 +933,10 @@ def _neon_test_branch(
870
933
  This creates a single branch with expiry that all tests share.
871
934
  The first worker creates the branch, others reuse it.
872
935
 
936
+ Branch cleanup is coordinated so the creator waits for ALL workers
937
+ to complete before deleting the branch, preventing connection errors
938
+ for workers that finish later.
939
+
873
940
  Yields:
874
941
  Tuple of (branch, is_creator) where is_creator indicates if this
875
942
  worker created the branch (and should run migrations/cleanup).
@@ -893,7 +960,13 @@ def _neon_test_branch(
893
960
  yield branch, is_creator
894
961
  finally:
895
962
  env_manager.restore()
963
+ # Signal that this worker is done with all tests
964
+ _neon_xdist_coordinator.signal_worker_done()
965
+
896
966
  if is_creator:
967
+ # Wait for all other workers to finish before deleting the branch
968
+ # This prevents "endpoint not found" errors for slower workers
969
+ _neon_xdist_coordinator.wait_for_all_workers_done()
897
970
  _neon_branch_manager.delete_branch(branch.branch_id)
898
971
 
899
972
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pytest-neon
3
- Version: 3.0.0
3
+ Version: 3.0.1
4
4
  Summary: Pytest plugin for Neon database branch isolation in tests
5
5
  Project-URL: Homepage, https://github.com/ZainRizvi/pytest-neon
6
6
  Project-URL: Repository, https://github.com/ZainRizvi/pytest-neon
@@ -0,0 +1,8 @@
1
+ pytest_neon/__init__.py,sha256=VNFVMj2RGnWj_CYynDMxIoPZ8XSKcN6v_lT94pAlYgg,404
2
+ pytest_neon/plugin.py,sha256=9wL17R95Wcu2fTti_MGNe4y66BZmcGs86qwgZ4GHD1c,42825
3
+ pytest_neon/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
4
+ pytest_neon-3.0.1.dist-info/METADATA,sha256=U1j8ZiEFOTSl_h4VNmnf7YKywXZ_mb7l8DEjzeUgE-s,10706
5
+ pytest_neon-3.0.1.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
6
+ pytest_neon-3.0.1.dist-info/entry_points.txt,sha256=5U88Idj_G8-PSDb9VF3OwYFbGLHnGOo_GxgYvi0dtXw,37
7
+ pytest_neon-3.0.1.dist-info/licenses/LICENSE,sha256=aKKp_Ex4WBHTByY4BhXJ181dzB_qYhi2pCUmZ7Spn_0,1067
8
+ pytest_neon-3.0.1.dist-info/RECORD,,
@@ -1,8 +0,0 @@
1
- pytest_neon/__init__.py,sha256=W6OIAvx3sB2jfKCZaUUK1XcQPBxtWCnaYQCRn5NQhuA,404
2
- pytest_neon/plugin.py,sha256=ADH8on2MMI7jIKdk9mQDKbk59ypMwGNuh4_NsYNTphQ,40114
3
- pytest_neon/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
4
- pytest_neon-3.0.0.dist-info/METADATA,sha256=F68tFRyHHx6C5eKTXjq_bUMRtmR_Q0LcVrlKm8CwLHs,10706
5
- pytest_neon-3.0.0.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
6
- pytest_neon-3.0.0.dist-info/entry_points.txt,sha256=5U88Idj_G8-PSDb9VF3OwYFbGLHnGOo_GxgYvi0dtXw,37
7
- pytest_neon-3.0.0.dist-info/licenses/LICENSE,sha256=aKKp_Ex4WBHTByY4BhXJ181dzB_qYhi2pCUmZ7Spn_0,1067
8
- pytest_neon-3.0.0.dist-info/RECORD,,