wexample-runner 9.4.0__tar.gz → 9.5.0__tar.gz

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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: wexample-runner
3
- Version: 9.4.0
3
+ Version: 9.5.0
4
4
  Summary: Executes commands across local, SSH, and Docker environments through a unified runner interface with lifecycle management (build, start, stop, destroy)
5
5
  Author-Email: weeger <contact@wexample.com>
6
6
  License: MIT
@@ -10,7 +10,7 @@ Classifier: Operating System :: OS Independent
10
10
  Project-URL: homepage, https://github.com/wexample/python-runner
11
11
  Requires-Python: >=3.10
12
12
  Requires-Dist: paramiko>=3.0.0
13
- Requires-Dist: wexample-helpers>=20.0.0
13
+ Requires-Dist: wexample-helpers>=20.2.0
14
14
  Provides-Extra: dev
15
15
  Requires-Dist: pytest; extra == "dev"
16
16
  Requires-Dist: pytest-cov; extra == "dev"
@@ -18,7 +18,7 @@ Description-Content-Type: text/markdown
18
18
 
19
19
  # runner
20
20
 
21
- Version: 9.4.0
21
+ Version: 9.5.0
22
22
 
23
23
  `wexample-runner` gives Python ≥ 3.10 code a single `execute(cmd)` call that runs shell commands on the local machine via subprocess, on a remote server over SSH (paramiko), or inside a Docker container — without the caller branching on the target environment. Every runner follows the same `build / start / stop / destroy` lifecycle and returns a `RunnerResult` dataclass carrying `stdout`, `stderr`, and `exit_code`. It targets developers who automate operations across mixed execution environments and want one interface that works regardless of where the command lands.
24
24
 
@@ -238,7 +238,7 @@ Visit the [Wexample Suite documentation](https://docs.wexample.com) for the comp
238
238
  ## Dependencies
239
239
 
240
240
  - paramiko: >=3.0.0
241
- - wexample-helpers: >=20.0.0
241
+ - wexample-helpers: >=20.2.0
242
242
 
243
243
  ## Versioning & Compatibility Policy
244
244
 
@@ -1,6 +1,6 @@
1
1
  # runner
2
2
 
3
- Version: 9.4.0
3
+ Version: 9.5.0
4
4
 
5
5
  `wexample-runner` gives Python ≥ 3.10 code a single `execute(cmd)` call that runs shell commands on the local machine via subprocess, on a remote server over SSH (paramiko), or inside a Docker container — without the caller branching on the target environment. Every runner follows the same `build / start / stop / destroy` lifecycle and returns a `RunnerResult` dataclass carrying `stdout`, `stderr`, and `exit_code`. It targets developers who automate operations across mixed execution environments and want one interface that works regardless of where the command lands.
6
6
 
@@ -220,7 +220,7 @@ Visit the [Wexample Suite documentation](https://docs.wexample.com) for the comp
220
220
  ## Dependencies
221
221
 
222
222
  - paramiko: >=3.0.0
223
- - wexample-helpers: >=20.0.0
223
+ - wexample-helpers: >=20.2.0
224
224
 
225
225
  ## Versioning & Compatibility Policy
226
226
 
@@ -6,7 +6,7 @@ build-backend = "pdm.backend"
6
6
 
7
7
  [project]
8
8
  name = "wexample-runner"
9
- version = "9.4.0"
9
+ version = "9.5.0"
10
10
  description = "Executes commands across local, SSH, and Docker environments through a unified runner interface with lifecycle management (build, start, stop, destroy)"
11
11
  authors = [
12
12
  { name = "weeger", email = "contact@wexample.com" },
@@ -19,7 +19,7 @@ classifiers = [
19
19
  ]
20
20
  dependencies = [
21
21
  "paramiko>=3.0.0",
22
- "wexample-helpers>=20.0.0",
22
+ "wexample-helpers>=20.2.0",
23
23
  ]
24
24
 
25
25
  [project.readme]
@@ -74,6 +74,19 @@ class DockerRunner(AbstractDockerRunner):
74
74
  if docker_image_exists(self.image_name):
75
75
  docker_remove_image(self.image_name)
76
76
 
77
+ def dispose(self) -> None:
78
+ """Remove the container, keeping the image to start from next time.
79
+
80
+ Forced rather than stopped first: the container idles on `tail -f`, which
81
+ ignores the stop signal and would hold every exit for docker's 10s grace.
82
+ Never raises — it runs as the process exits.
83
+ """
84
+ from wexample_helpers.helper.shell import shell_run
85
+
86
+ shell_run(
87
+ cmd=["docker", "rm", "-f", self.container_name], capture=True, check=False
88
+ )
89
+
77
90
  def start(self) -> None:
78
91
  import os
79
92
 
@@ -88,6 +101,8 @@ class DockerRunner(AbstractDockerRunner):
88
101
  if not docker_container_is_running(self.container_name):
89
102
  docker_start_container(self.container_name)
90
103
  else:
104
+ import atexit
105
+
91
106
  user = f"{os.getuid()}:{os.getgid()}"
92
107
  docker_run_container(
93
108
  self.container_name,
@@ -95,6 +110,9 @@ class DockerRunner(AbstractDockerRunner):
95
110
  volumes=self.volumes,
96
111
  user=user,
97
112
  )
113
+ # A container this process created is removed when it exits, and
114
+ # only that one: another process may still be using one it found.
115
+ atexit.register(self.dispose)
98
116
 
99
117
  def stop(self) -> None:
100
118
  from wexample_helpers.helper.docker import (