axio-tools-docker 0.8.0__tar.gz → 0.9.1__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.
- {axio_tools_docker-0.8.0 → axio_tools_docker-0.9.1}/PKG-INFO +71 -20
- {axio_tools_docker-0.8.0 → axio_tools_docker-0.9.1}/README.md +70 -19
- axio_tools_docker-0.9.1/conftest.py +28 -0
- {axio_tools_docker-0.8.0 → axio_tools_docker-0.9.1}/pyproject.toml +6 -2
- {axio_tools_docker-0.8.0 → axio_tools_docker-0.9.1}/src/axio_tools_docker/sandbox.py +133 -144
- axio_tools_docker-0.9.1/tests/__init__.py +0 -0
- {axio_tools_docker-0.8.0 → axio_tools_docker-0.9.1}/tests/test_integration.py +119 -161
- {axio_tools_docker-0.8.0 → axio_tools_docker-0.9.1}/tests/test_sandbox.py +80 -4
- {axio_tools_docker-0.8.0 → axio_tools_docker-0.9.1}/.github/workflows/publish.yml +0 -0
- {axio_tools_docker-0.8.0 → axio_tools_docker-0.9.1}/.github/workflows/tests.yml +0 -0
- {axio_tools_docker-0.8.0 → axio_tools_docker-0.9.1}/.gitignore +0 -0
- {axio_tools_docker-0.8.0 → axio_tools_docker-0.9.1}/LICENSE +0 -0
- {axio_tools_docker-0.8.0 → axio_tools_docker-0.9.1}/Makefile +0 -0
- {axio_tools_docker-0.8.0 → axio_tools_docker-0.9.1}/src/axio_tools_docker/__init__.py +0 -0
- {axio_tools_docker-0.8.0 → axio_tools_docker-0.9.1}/src/axio_tools_docker/py.typed +0 -0
- {axio_tools_docker-0.8.0 → axio_tools_docker-0.9.1}/uv.lock +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: axio-tools-docker
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.9.1
|
|
4
4
|
Summary: Docker sandbox tools for Axio
|
|
5
5
|
Project-URL: Homepage, https://github.com/mosquito/axio-agent
|
|
6
6
|
Project-URL: Repository, https://github.com/mosquito/axio-agent
|
|
@@ -22,7 +22,7 @@ Docker sandbox tools for [axio](https://github.com/mosquito/axio-agent).
|
|
|
22
22
|
|
|
23
23
|
`DockerSandbox` is an async context manager that spins up an isolated Docker
|
|
24
24
|
container on entry and removes it on exit. Inside the context it exposes six
|
|
25
|
-
`axio` tools
|
|
25
|
+
`axio` tools - the same `shell`, `write_file`, `read_file`, `list_files`,
|
|
26
26
|
`run_python`, and `patch_file` as `axio-tools-local`, but every operation runs
|
|
27
27
|
inside the container, never on the host.
|
|
28
28
|
|
|
@@ -35,7 +35,7 @@ docker info # should succeed
|
|
|
35
35
|
```
|
|
36
36
|
|
|
37
37
|
The package talks to the Docker Engine API directly via
|
|
38
|
-
[aiodocker](https://aiodocker.readthedocs.io/)
|
|
38
|
+
[aiodocker](https://aiodocker.readthedocs.io/) - the `docker` CLI is not
|
|
39
39
|
required.
|
|
40
40
|
|
|
41
41
|
## Installation
|
|
@@ -46,7 +46,7 @@ pip install axio-tools-docker
|
|
|
46
46
|
|
|
47
47
|
## Quick start
|
|
48
48
|
|
|
49
|
-
<!-- name: test_readme_usage;
|
|
49
|
+
<!-- name: test_readme_usage; fixtures: docker -->
|
|
50
50
|
```python
|
|
51
51
|
import asyncio
|
|
52
52
|
from axio.agent import Agent
|
|
@@ -71,7 +71,7 @@ asyncio.run(main())
|
|
|
71
71
|
|
|
72
72
|
## Sandbox tools
|
|
73
73
|
|
|
74
|
-
These mirror `axio-tools-local` exactly
|
|
74
|
+
These mirror `axio-tools-local` exactly - same names and field schemas:
|
|
75
75
|
|
|
76
76
|
| Tool | Description |
|
|
77
77
|
|---|---|
|
|
@@ -88,9 +88,18 @@ The container is created on `__aenter__` and removed on `__aexit__` (`docker rm
|
|
|
88
88
|
Cleanup runs even when the body raises an exception:
|
|
89
89
|
|
|
90
90
|
```python
|
|
91
|
+
from axio_tools_docker import DockerSandbox
|
|
92
|
+
from axio import Agent
|
|
93
|
+
|
|
91
94
|
async def run(ctx):
|
|
95
|
+
agent = Agent(
|
|
96
|
+
system="You are a coding assistant. Use the sandbox tools to run code safely.",
|
|
97
|
+
tools=ctx.sandbox.tools,
|
|
98
|
+
)
|
|
99
|
+
|
|
92
100
|
async with DockerSandbox(image="alpine:latest") as sandbox:
|
|
93
101
|
await agent.run("...", ctx)
|
|
102
|
+
|
|
94
103
|
# container removed here (unless remove=False)
|
|
95
104
|
```
|
|
96
105
|
|
|
@@ -106,9 +115,10 @@ The running container's ID is available as `sandbox.container_id` inside the
|
|
|
106
115
|
|
|
107
116
|
## Named containers and reuse
|
|
108
117
|
|
|
109
|
-
Pass `name=` to give the container a fixed name. If a
|
|
110
|
-
|
|
111
|
-
one
|
|
118
|
+
Pass `name=` to give the container a fixed name. If a container with that name
|
|
119
|
+
already exists, the sandbox starts it if needed and attaches instead of creating
|
|
120
|
+
a new one. Attached containers are never removed on exit - regardless of
|
|
121
|
+
`remove`:
|
|
112
122
|
|
|
113
123
|
```python
|
|
114
124
|
import asyncio
|
|
@@ -126,37 +136,76 @@ asyncio.run(first_session())
|
|
|
126
136
|
asyncio.run(second_session())
|
|
127
137
|
```
|
|
128
138
|
|
|
139
|
+
## Named volumes
|
|
140
|
+
|
|
141
|
+
Named volumes are managed by the Docker daemon and persist across container
|
|
142
|
+
restarts. Use them to share state between sandbox sessions:
|
|
143
|
+
|
|
144
|
+
<!-- name: test_readme_example; fixtures: docker -->
|
|
145
|
+
```python
|
|
146
|
+
import asyncio
|
|
147
|
+
from axio_tools_docker import DockerSandbox
|
|
148
|
+
|
|
149
|
+
async def main() -> None:
|
|
150
|
+
async with DockerSandbox(
|
|
151
|
+
image="python:3.12-alpine",
|
|
152
|
+
named_volumes={"/data": "my-project-data"},
|
|
153
|
+
) as sb:
|
|
154
|
+
await sb.write_file("/data/state.json", '{"count": 1}')
|
|
155
|
+
# Container removed, volume survives.
|
|
156
|
+
|
|
157
|
+
async with DockerSandbox(
|
|
158
|
+
image="python:3.12-alpine",
|
|
159
|
+
named_volumes={"/data": "my-project-data"},
|
|
160
|
+
volumes_remove=True, # delete the volume on exit
|
|
161
|
+
) as sb:
|
|
162
|
+
raw = await sb.read_file_bytes("/data/state.json")
|
|
163
|
+
assert raw.decode() == '{"count": 1}'
|
|
164
|
+
|
|
165
|
+
asyncio.run(main())
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
Docker creates the volume automatically if it does not exist yet.
|
|
169
|
+
|
|
129
170
|
## Configuration
|
|
130
171
|
|
|
131
|
-
<!-- name: test_readme_config -->
|
|
172
|
+
<!-- name: test_readme_config; fixtures: docker -->
|
|
132
173
|
```python
|
|
174
|
+
import os
|
|
133
175
|
from axio_tools_docker import DockerSandbox
|
|
134
176
|
|
|
135
177
|
sandbox = DockerSandbox(
|
|
136
|
-
"unix:///var/run/docker.sock",
|
|
178
|
+
os.getenv("DOCKER_HOST", "unix:///var/run/docker.sock"), # Docker daemon URL, optional
|
|
137
179
|
image="python:3.12-slim",
|
|
138
|
-
memory="512m",
|
|
139
|
-
cpus="2.0",
|
|
140
|
-
network=False,
|
|
180
|
+
memory="512m", # memory limit: "256m", "1g", …
|
|
181
|
+
cpus="2.0", # CPU limit
|
|
182
|
+
network=False, # False=none, True=default, str=explicit mode
|
|
141
183
|
workdir="/workspace",
|
|
142
|
-
volumes={"/workspace": "/tmp/host-dir"},
|
|
184
|
+
volumes={"/workspace": "/tmp/host-dir"}, # {container_path: host_path}
|
|
185
|
+
named_volumes={"/data": "my-project-data"}, # named Docker volumes
|
|
186
|
+
volumes_remove=False, # remove named volumes on exit
|
|
143
187
|
env={"PYTHONPATH": "/app"},
|
|
144
188
|
user="nobody",
|
|
145
189
|
name="my-agent-sandbox",
|
|
146
190
|
remove=False,
|
|
147
|
-
read_only=True,
|
|
148
|
-
shm_size="64m",
|
|
149
|
-
cap_add=["NET_ADMIN"],
|
|
150
|
-
cap_drop=["ALL"],
|
|
191
|
+
read_only=True, # read-only root filesystem
|
|
192
|
+
shm_size="64m", # /dev/shm size
|
|
193
|
+
cap_add=["NET_ADMIN"], # add Linux capabilities
|
|
194
|
+
cap_drop=["ALL"], # drop Linux capabilities
|
|
151
195
|
privileged=False,
|
|
152
196
|
ulimits={"nofile": (1024, 65536), "nproc": 512},
|
|
153
197
|
tmpfs={"/tmp": "size=128m,mode=1777"},
|
|
154
|
-
ports={8080: 8080},
|
|
198
|
+
ports={8080: 8080}, # {container_port: host_port}
|
|
155
199
|
platform="linux/amd64",
|
|
156
200
|
extra_hosts={"host.docker.internal": "host-gateway"},
|
|
157
201
|
devices=["/dev/net/tun", "/dev/sda:/dev/xvda:r"],
|
|
158
202
|
dns=["8.8.8.8", "1.1.1.1"],
|
|
159
203
|
)
|
|
204
|
+
|
|
205
|
+
assert sandbox.image == "python:3.12-slim"
|
|
206
|
+
assert sandbox.memory == "512m"
|
|
207
|
+
assert sandbox.cpus == "2.0"
|
|
208
|
+
assert sandbox.network == False
|
|
160
209
|
```
|
|
161
210
|
|
|
162
211
|
| Parameter | Type | Default | Description |
|
|
@@ -168,6 +217,8 @@ sandbox = DockerSandbox(
|
|
|
168
217
|
| `network` | `bool \| str` | `False` | Network mode. `False` → `none`. `True` → Docker default. String → explicit `NetworkMode` (e.g. `"host"`, `"bridge"`, `"my-net"`). |
|
|
169
218
|
| `workdir` | `str` | `"/workspace"` | Working directory inside the container. |
|
|
170
219
|
| `volumes` | `dict[str, str]` | `{}` | Bind mounts as `{container_path: host_path}`. |
|
|
220
|
+
| `named_volumes` | `dict[str, str]` | `{}` | Named Docker volumes as `{container_path: volume_name}`. Created automatically if absent. |
|
|
221
|
+
| `volumes_remove` | `bool` | `False` | Remove named volumes on exit. No effect when attached to an existing container. |
|
|
171
222
|
| `env` | `dict[str, str]` | `{}` | Environment variables passed to all commands. |
|
|
172
223
|
| `user` | `str` | `""` | User to run as (e.g. `"nobody"`, `"1000"`). |
|
|
173
224
|
| `name` | `str` | `""` | Container name. Attaches to existing container if found; creates new one otherwise. |
|
|
@@ -176,7 +227,7 @@ sandbox = DockerSandbox(
|
|
|
176
227
|
| `shm_size` | `str` | `""` | `/dev/shm` size (e.g. `"64m"`). Useful for PyTorch / shared-memory IPC. |
|
|
177
228
|
| `cap_add` | `list[str]` | `[]` | Linux capabilities to add (e.g. `["NET_ADMIN", "SYS_PTRACE"]`). |
|
|
178
229
|
| `cap_drop` | `list[str]` | `[]` | Linux capabilities to drop (e.g. `["ALL"]`). |
|
|
179
|
-
| `privileged` | `bool` | `False` | Extended privileges
|
|
230
|
+
| `privileged` | `bool` | `False` | Extended privileges - full capability set and device access. Use with care. |
|
|
180
231
|
| `ulimits` | `dict[str, int \| tuple[int, int]]` | `{}` | Resource limits. `{"nofile": 1024}` → soft=hard=1024. `{"nofile": (1024, 65536)}` → soft/hard split. |
|
|
181
232
|
| `tmpfs` | `dict[str, str]` | `{}` | Tmpfs mounts as `{path: options}` (e.g. `{"/tmp": "size=128m,mode=1777"}`). |
|
|
182
233
|
| `ports` | `dict[int, int]` | `{}` | Port bindings as `{container_port: host_port}`. Only meaningful when `network != False`. |
|
|
@@ -8,7 +8,7 @@ Docker sandbox tools for [axio](https://github.com/mosquito/axio-agent).
|
|
|
8
8
|
|
|
9
9
|
`DockerSandbox` is an async context manager that spins up an isolated Docker
|
|
10
10
|
container on entry and removes it on exit. Inside the context it exposes six
|
|
11
|
-
`axio` tools
|
|
11
|
+
`axio` tools - the same `shell`, `write_file`, `read_file`, `list_files`,
|
|
12
12
|
`run_python`, and `patch_file` as `axio-tools-local`, but every operation runs
|
|
13
13
|
inside the container, never on the host.
|
|
14
14
|
|
|
@@ -21,7 +21,7 @@ docker info # should succeed
|
|
|
21
21
|
```
|
|
22
22
|
|
|
23
23
|
The package talks to the Docker Engine API directly via
|
|
24
|
-
[aiodocker](https://aiodocker.readthedocs.io/)
|
|
24
|
+
[aiodocker](https://aiodocker.readthedocs.io/) - the `docker` CLI is not
|
|
25
25
|
required.
|
|
26
26
|
|
|
27
27
|
## Installation
|
|
@@ -32,7 +32,7 @@ pip install axio-tools-docker
|
|
|
32
32
|
|
|
33
33
|
## Quick start
|
|
34
34
|
|
|
35
|
-
<!-- name: test_readme_usage;
|
|
35
|
+
<!-- name: test_readme_usage; fixtures: docker -->
|
|
36
36
|
```python
|
|
37
37
|
import asyncio
|
|
38
38
|
from axio.agent import Agent
|
|
@@ -57,7 +57,7 @@ asyncio.run(main())
|
|
|
57
57
|
|
|
58
58
|
## Sandbox tools
|
|
59
59
|
|
|
60
|
-
These mirror `axio-tools-local` exactly
|
|
60
|
+
These mirror `axio-tools-local` exactly - same names and field schemas:
|
|
61
61
|
|
|
62
62
|
| Tool | Description |
|
|
63
63
|
|---|---|
|
|
@@ -74,9 +74,18 @@ The container is created on `__aenter__` and removed on `__aexit__` (`docker rm
|
|
|
74
74
|
Cleanup runs even when the body raises an exception:
|
|
75
75
|
|
|
76
76
|
```python
|
|
77
|
+
from axio_tools_docker import DockerSandbox
|
|
78
|
+
from axio import Agent
|
|
79
|
+
|
|
77
80
|
async def run(ctx):
|
|
81
|
+
agent = Agent(
|
|
82
|
+
system="You are a coding assistant. Use the sandbox tools to run code safely.",
|
|
83
|
+
tools=ctx.sandbox.tools,
|
|
84
|
+
)
|
|
85
|
+
|
|
78
86
|
async with DockerSandbox(image="alpine:latest") as sandbox:
|
|
79
87
|
await agent.run("...", ctx)
|
|
88
|
+
|
|
80
89
|
# container removed here (unless remove=False)
|
|
81
90
|
```
|
|
82
91
|
|
|
@@ -92,9 +101,10 @@ The running container's ID is available as `sandbox.container_id` inside the
|
|
|
92
101
|
|
|
93
102
|
## Named containers and reuse
|
|
94
103
|
|
|
95
|
-
Pass `name=` to give the container a fixed name. If a
|
|
96
|
-
|
|
97
|
-
one
|
|
104
|
+
Pass `name=` to give the container a fixed name. If a container with that name
|
|
105
|
+
already exists, the sandbox starts it if needed and attaches instead of creating
|
|
106
|
+
a new one. Attached containers are never removed on exit - regardless of
|
|
107
|
+
`remove`:
|
|
98
108
|
|
|
99
109
|
```python
|
|
100
110
|
import asyncio
|
|
@@ -112,37 +122,76 @@ asyncio.run(first_session())
|
|
|
112
122
|
asyncio.run(second_session())
|
|
113
123
|
```
|
|
114
124
|
|
|
125
|
+
## Named volumes
|
|
126
|
+
|
|
127
|
+
Named volumes are managed by the Docker daemon and persist across container
|
|
128
|
+
restarts. Use them to share state between sandbox sessions:
|
|
129
|
+
|
|
130
|
+
<!-- name: test_readme_example; fixtures: docker -->
|
|
131
|
+
```python
|
|
132
|
+
import asyncio
|
|
133
|
+
from axio_tools_docker import DockerSandbox
|
|
134
|
+
|
|
135
|
+
async def main() -> None:
|
|
136
|
+
async with DockerSandbox(
|
|
137
|
+
image="python:3.12-alpine",
|
|
138
|
+
named_volumes={"/data": "my-project-data"},
|
|
139
|
+
) as sb:
|
|
140
|
+
await sb.write_file("/data/state.json", '{"count": 1}')
|
|
141
|
+
# Container removed, volume survives.
|
|
142
|
+
|
|
143
|
+
async with DockerSandbox(
|
|
144
|
+
image="python:3.12-alpine",
|
|
145
|
+
named_volumes={"/data": "my-project-data"},
|
|
146
|
+
volumes_remove=True, # delete the volume on exit
|
|
147
|
+
) as sb:
|
|
148
|
+
raw = await sb.read_file_bytes("/data/state.json")
|
|
149
|
+
assert raw.decode() == '{"count": 1}'
|
|
150
|
+
|
|
151
|
+
asyncio.run(main())
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
Docker creates the volume automatically if it does not exist yet.
|
|
155
|
+
|
|
115
156
|
## Configuration
|
|
116
157
|
|
|
117
|
-
<!-- name: test_readme_config -->
|
|
158
|
+
<!-- name: test_readme_config; fixtures: docker -->
|
|
118
159
|
```python
|
|
160
|
+
import os
|
|
119
161
|
from axio_tools_docker import DockerSandbox
|
|
120
162
|
|
|
121
163
|
sandbox = DockerSandbox(
|
|
122
|
-
"unix:///var/run/docker.sock",
|
|
164
|
+
os.getenv("DOCKER_HOST", "unix:///var/run/docker.sock"), # Docker daemon URL, optional
|
|
123
165
|
image="python:3.12-slim",
|
|
124
|
-
memory="512m",
|
|
125
|
-
cpus="2.0",
|
|
126
|
-
network=False,
|
|
166
|
+
memory="512m", # memory limit: "256m", "1g", …
|
|
167
|
+
cpus="2.0", # CPU limit
|
|
168
|
+
network=False, # False=none, True=default, str=explicit mode
|
|
127
169
|
workdir="/workspace",
|
|
128
|
-
volumes={"/workspace": "/tmp/host-dir"},
|
|
170
|
+
volumes={"/workspace": "/tmp/host-dir"}, # {container_path: host_path}
|
|
171
|
+
named_volumes={"/data": "my-project-data"}, # named Docker volumes
|
|
172
|
+
volumes_remove=False, # remove named volumes on exit
|
|
129
173
|
env={"PYTHONPATH": "/app"},
|
|
130
174
|
user="nobody",
|
|
131
175
|
name="my-agent-sandbox",
|
|
132
176
|
remove=False,
|
|
133
|
-
read_only=True,
|
|
134
|
-
shm_size="64m",
|
|
135
|
-
cap_add=["NET_ADMIN"],
|
|
136
|
-
cap_drop=["ALL"],
|
|
177
|
+
read_only=True, # read-only root filesystem
|
|
178
|
+
shm_size="64m", # /dev/shm size
|
|
179
|
+
cap_add=["NET_ADMIN"], # add Linux capabilities
|
|
180
|
+
cap_drop=["ALL"], # drop Linux capabilities
|
|
137
181
|
privileged=False,
|
|
138
182
|
ulimits={"nofile": (1024, 65536), "nproc": 512},
|
|
139
183
|
tmpfs={"/tmp": "size=128m,mode=1777"},
|
|
140
|
-
ports={8080: 8080},
|
|
184
|
+
ports={8080: 8080}, # {container_port: host_port}
|
|
141
185
|
platform="linux/amd64",
|
|
142
186
|
extra_hosts={"host.docker.internal": "host-gateway"},
|
|
143
187
|
devices=["/dev/net/tun", "/dev/sda:/dev/xvda:r"],
|
|
144
188
|
dns=["8.8.8.8", "1.1.1.1"],
|
|
145
189
|
)
|
|
190
|
+
|
|
191
|
+
assert sandbox.image == "python:3.12-slim"
|
|
192
|
+
assert sandbox.memory == "512m"
|
|
193
|
+
assert sandbox.cpus == "2.0"
|
|
194
|
+
assert sandbox.network == False
|
|
146
195
|
```
|
|
147
196
|
|
|
148
197
|
| Parameter | Type | Default | Description |
|
|
@@ -154,6 +203,8 @@ sandbox = DockerSandbox(
|
|
|
154
203
|
| `network` | `bool \| str` | `False` | Network mode. `False` → `none`. `True` → Docker default. String → explicit `NetworkMode` (e.g. `"host"`, `"bridge"`, `"my-net"`). |
|
|
155
204
|
| `workdir` | `str` | `"/workspace"` | Working directory inside the container. |
|
|
156
205
|
| `volumes` | `dict[str, str]` | `{}` | Bind mounts as `{container_path: host_path}`. |
|
|
206
|
+
| `named_volumes` | `dict[str, str]` | `{}` | Named Docker volumes as `{container_path: volume_name}`. Created automatically if absent. |
|
|
207
|
+
| `volumes_remove` | `bool` | `False` | Remove named volumes on exit. No effect when attached to an existing container. |
|
|
157
208
|
| `env` | `dict[str, str]` | `{}` | Environment variables passed to all commands. |
|
|
158
209
|
| `user` | `str` | `""` | User to run as (e.g. `"nobody"`, `"1000"`). |
|
|
159
210
|
| `name` | `str` | `""` | Container name. Attaches to existing container if found; creates new one otherwise. |
|
|
@@ -162,7 +213,7 @@ sandbox = DockerSandbox(
|
|
|
162
213
|
| `shm_size` | `str` | `""` | `/dev/shm` size (e.g. `"64m"`). Useful for PyTorch / shared-memory IPC. |
|
|
163
214
|
| `cap_add` | `list[str]` | `[]` | Linux capabilities to add (e.g. `["NET_ADMIN", "SYS_PTRACE"]`). |
|
|
164
215
|
| `cap_drop` | `list[str]` | `[]` | Linux capabilities to drop (e.g. `["ALL"]`). |
|
|
165
|
-
| `privileged` | `bool` | `False` | Extended privileges
|
|
216
|
+
| `privileged` | `bool` | `False` | Extended privileges - full capability set and device access. Use with care. |
|
|
166
217
|
| `ulimits` | `dict[str, int \| tuple[int, int]]` | `{}` | Resource limits. `{"nofile": 1024}` → soft=hard=1024. `{"nofile": (1024, 65536)}` → soft/hard split. |
|
|
167
218
|
| `tmpfs` | `dict[str, str]` | `{}` | Tmpfs mounts as `{path: options}` (e.g. `{"/tmp": "size=128m,mode=1777"}`). |
|
|
168
219
|
| `ports` | `dict[int, int]` | `{}` | Port bindings as `{container_port: host_port}`. Only meaningful when `network != False`. |
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
"""Pytest configuration for axio-tools-docker."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import asyncio
|
|
6
|
+
import os
|
|
7
|
+
|
|
8
|
+
import aiodocker
|
|
9
|
+
import pytest
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
@pytest.fixture(scope="session")
|
|
13
|
+
def docker() -> str:
|
|
14
|
+
docker_url = os.getenv("DOCKER_HOST", "unix:///var/run/docker.sock")
|
|
15
|
+
|
|
16
|
+
async def _probe() -> bool:
|
|
17
|
+
# noinspection PyBroadException
|
|
18
|
+
try:
|
|
19
|
+
async with aiodocker.Docker(url=docker_url) as client:
|
|
20
|
+
await client.system.info()
|
|
21
|
+
return True
|
|
22
|
+
except Exception:
|
|
23
|
+
return False
|
|
24
|
+
|
|
25
|
+
if not asyncio.run(_probe()):
|
|
26
|
+
pytest.skip("Skipping due to missing Docker daemon")
|
|
27
|
+
|
|
28
|
+
return docker_url
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "axio-tools-docker"
|
|
3
|
-
version = "0.
|
|
3
|
+
version = "0.9.1"
|
|
4
4
|
description = "Docker sandbox tools for Axio"
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
requires-python = ">=3.12"
|
|
@@ -24,6 +24,7 @@ testpaths = ["tests", "README.md"]
|
|
|
24
24
|
|
|
25
25
|
[tool.ruff]
|
|
26
26
|
line-length = 119
|
|
27
|
+
output-format = "concise"
|
|
27
28
|
target-version = "py312"
|
|
28
29
|
|
|
29
30
|
[tool.ruff.lint]
|
|
@@ -33,6 +34,10 @@ select = ["E", "F", "I", "UP"]
|
|
|
33
34
|
strict = true
|
|
34
35
|
python_version = "3.12"
|
|
35
36
|
|
|
37
|
+
[[tool.mypy.overrides]]
|
|
38
|
+
module = "aiodocker.*"
|
|
39
|
+
follow_imports = "skip"
|
|
40
|
+
|
|
36
41
|
[dependency-groups]
|
|
37
42
|
dev = [
|
|
38
43
|
"pytest>=8",
|
|
@@ -43,4 +48,3 @@ dev = [
|
|
|
43
48
|
"markdown-pytest>=0.6.0",
|
|
44
49
|
"aiodocker>=0.26",
|
|
45
50
|
]
|
|
46
|
-
|