|
1 | 1 | # Project overview
|
2 | 2 |
|
| 3 | +**ds_pycontain** is a python package which provides an abstraction over the docker API and provide Python REPL running in a docker container. |
| 4 | + |
| 5 | +Supported functionality covers: |
| 6 | +- Building docker images from Dockerfiles |
| 7 | +- Pulling docker images from dockerhub (or similar) |
| 8 | +- Running docker containers to execute a one-off command |
| 9 | +- Running docker containers to execute a long-running process and communicate with it |
| 10 | +- Run python commands in a container and get the result. |
| 11 | + |
| 12 | +## Motivation |
| 13 | + |
| 14 | +Main motivation is to allow to orchestrate running unsafe code or commands in isolated environment. |
3 | 15 | The docker API is quite complicated and not well documented or typed.
|
4 | 16 | This project aims to provide a higher level abstraction over the docker API.
|
5 | 17 |
|
6 |
| -Main motivation is to allow to orchestrate running unsafe code or commands in isolated environment. |
| 18 | +What is also provided is **a python REPL running in a docker container**. |
| 19 | + |
| 20 | +This might be useful to improve security for execution of LLM models/agents generated code, which generally should not be trusted. |
| 21 | + |
| 22 | +## Example code snippets |
| 23 | + |
| 24 | +### Execute commands in container running in the background: |
| 25 | + |
| 26 | +Below is a short snippet showcasing how to run docker container in the background and execute commands in it. |
| 27 | + |
| 28 | +```python |
| 29 | + from ds_pycontain import DockerContainer, DockerImage, get_docker_client |
| 30 | + |
| 31 | + client = get_docker_client() |
| 32 | + |
| 33 | + # This will fetch the image from dockerhub if it is not already present |
| 34 | + # with the "latest" tag. Then container is started and commands are run |
| 35 | + with DockerContainer(DockerImage.from_tag("alpine")) as container: |
| 36 | + ret_code, output = container.run("touch /animal.txt") |
| 37 | + assert ret_code == 0 |
| 38 | + |
| 39 | + ret_code, output = container.run("ls /") |
| 40 | + assert ret_code == 0 |
| 41 | + assert cast(bytes, output).find(b"animal.txt") >= 0 |
| 42 | +``` |
| 43 | + |
| 44 | +### Docker images |
| 45 | + |
| 46 | +Images can be pulled from dockerhub or built from dockerfile. |
| 47 | + |
| 48 | +```python |
| 49 | +from ds_pycontain import DockerImage |
| 50 | + |
| 51 | +# pull or use alpine:latest |
| 52 | +image = DockerImage.from_tag("alpine") |
| 53 | +# use provided tag to pull/use the image |
| 54 | +image = DockerImage.from_tag("python", tag="3.9-slim") |
| 55 | +# use this dockerfile to build a new local image |
| 56 | +image = DockerImage.from_dockerfile("example/Dockerfile") |
| 57 | +# you can provide a directory path which contains Dockerfile, set custom image name |
| 58 | +image = DockerImage.from_dockerfile("path/to/dir_with_Dockerfile/", name="cow") |
| 59 | +``` |
| 60 | + |
| 61 | +### Python REPL running in docker container |
| 62 | + |
| 63 | +Running Python code in docker container is rather easy with this package. |
| 64 | + |
| 65 | +```python |
| 66 | + from ds_pycontain.python_dockerized_repl import PythonContainerREPL |
| 67 | + |
| 68 | + # To start python REPL in container it is easy, |
| 69 | + # just be aware that it will take some time to start the container |
| 70 | + # and ports might be allocated by OS, so use different port/retry |
| 71 | + # if you get error. |
| 72 | + repl = PythonContainerREPL(port=7121) |
| 73 | + |
| 74 | + # You can run python commands in the container |
| 75 | + # and it will keep state between commands. |
| 76 | + out1 = repl.exec("x = [1, 2, 3]") |
| 77 | + assert out1 == "" |
| 78 | + # Eval returns string representation of the python command |
| 79 | + # as it would be in python REPL: |
| 80 | + out2 = repl.eval("len(x)") |
| 81 | + assert out2 == "3" |
| 82 | + |
| 83 | + # Exec returns captured standard output (stdout) |
| 84 | + # so it won't return anything in this case: |
| 85 | + out3 = repl.exec("len(x)") |
| 86 | + assert out3 == "" |
| 87 | + # but exec with print works: |
| 88 | + out4 = repl.exec("print(len(x))") |
| 89 | + assert out4 == "3\n" |
| 90 | + |
| 91 | + # You can also get error messages if code is wrong: |
| 92 | + err = repl.exec("print(x") |
| 93 | + assert "SyntaxError" in err |
| 94 | +``` |
0 commit comments