Skip to content

Commit b951973

Browse files
authored
Release capture resources between CLI runs (#739)
1 parent 6341071 commit b951973

3 files changed

Lines changed: 21 additions & 3 deletions

File tree

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@ releases are available on [PyPI](https://pypi.org/project/pytask) and
77

88
## Unreleased
99

10+
- {pull}`739` closes file descriptors for the capture manager between CLI runs and
11+
disposes stale database engines to prevent hitting OS file descriptor limits in
12+
large test runs.
1013
- {pull}`725` fixes the pickle node hash test by accounting for Python 3.14's
1114
default pickle protocol.
1215
- {pull}`726` adapts the interactive debugger integration to Python 3.14's

src/_pytask/capture.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@
5757
from types import TracebackType
5858

5959
from _pytask.node_protocols import PTask
60+
from _pytask.session import Session
6061

6162

6263
@hookimpl
@@ -109,6 +110,14 @@ def pytask_post_parse(config: dict[str, Any]) -> None:
109110
capman.suspend()
110111

111112

113+
@hookimpl
114+
def pytask_unconfigure(session: Session) -> None:
115+
"""Stop capturing and release file descriptors."""
116+
capman = session.config["pm"].get_plugin("capturemanager")
117+
if isinstance(capman, CaptureManager):
118+
capman.stop_capturing()
119+
120+
112121
# Copied from pytest with slightly modified docstrings.
113122

114123

src/_pytask/database_utils.py

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414
from _pytask.dag_utils import node_and_neighbors
1515

1616
if TYPE_CHECKING:
17+
from sqlalchemy.engine import Engine
18+
1719
from _pytask.node_protocols import PNode
1820
from _pytask.node_protocols import PTask
1921
from _pytask.session import Session
@@ -29,6 +31,7 @@
2931

3032

3133
DatabaseSession = sessionmaker()
34+
_ENGINE: Engine | None = None
3235

3336

3437
class BaseTable(DeclarativeBase):
@@ -47,9 +50,12 @@ class State(BaseTable):
4750

4851
def create_database(url: str) -> None:
4952
"""Create the database."""
50-
engine = create_engine(url)
51-
BaseTable.metadata.create_all(bind=engine)
52-
DatabaseSession.configure(bind=engine)
53+
global _ENGINE # noqa: PLW0603
54+
if _ENGINE is not None:
55+
_ENGINE.dispose()
56+
_ENGINE = create_engine(url)
57+
BaseTable.metadata.create_all(bind=_ENGINE)
58+
DatabaseSession.configure(bind=_ENGINE)
5359

5460

5561
def _create_or_update_state(first_key: str, second_key: str, hash_: str) -> None:

0 commit comments

Comments
 (0)