Keep your development environments clean.
pydiner
is a template for a generic Python project which:
- runs code in Docker containers which self-destruct.
- never reads or modifies files outside of its repository.
- never installs software outside of its own Docker images.
- never uses or modifies other Pythons, Anaconda, or virtualenvs.
- updates
requirements.txt
with pinned versions of all pip installs.
These rules are intended to avoid dependency hell.
To start a new project:
- Create a Git repo from this template.
- Delete any files and folders you don't want.
- Edit the
Dockerfile
to choose a Python version. - Edit
requirements.txt
to choose Python packages. - Open a terminal,
cd
to this folder, and run this command:
./kitchen
This should print a help message for the kitchen
script.
The kitchen
script defines shell functions which run common Docker commands.
# Bake a Docker image named pydiner:monty
./kitchen bake monty
# Run Python in an interactive pydiner:monty container
./kitchen runit monty python
# Same as above, but with the current working directory mounted as /context
./kitchen serve monty python
# Run tests in an interactive pydiner:monty container
./kitchen runit monty python -m test
# Same as above, but use pytest to run tests
./kitchen runit monty pytest
# Freeze requirements.txt and rebuild pydiner:monty
./kitchen freeze monty
# Delete the image, its containers, and any leftovers
./kitchen eightysix monty
Typing ./kitchen
before each command is optional if the kitchen
script is sourced.
./kitchen bake
builds (or updates) a Docker image with copies of files from the build context.
- Edit
requirements.txt
to specify which Python packages should be installed. - Edit
.dockerignore
to declare file patterns which should never be copied. - Edit
Dockerfile
to choose which non-ignored files are copied into images.
The default image name is pydiner:latest
.
./kitchen runit
runs a new interactive container from a previously-baked image.
- Inside a container,
baked-in
copies of files are in the/context
folder. - Modifying files inside the container does not affect the original files.
- Type
exit
to exit the container. It should then self-destruct.
./kitchen serve
runs a container with the current folder mounted as /context
.
- Processes inside the container can modify or delete mounted files.
- Changes to mounted files will be visible inside and outside the container.
- Any files baked into
/context
will be obscured by thefresh
mounted files.
./kitchen freeze
pins Python packages to ensure reproducible builds.
- The first time an image is baked,
pip
installs packages automatically. - If an image is frozen, then baking it again uses the same package versions.
- Freezing an image will overwrite
requirements.txt
.
This repo contains examples of common project files:
- bin/ contains example scripts.
- etc/ contains example configuration files.
- src/ contains an example Python package.
- test/ is an executable package which runs tests.
- var/ contains files output by the executables.
pydiner
has exactly one dependency:
Windows users may need to edit the kitchen
script for path compatibility.
Caution: Remember to cd
to this folder before using kitchen
functions.
Bake a pydiner:latest
image, freeze it, and serve bash
.
[+] Building 0.9s (11/11) FINISHED docker:desktop-linux
=> [internal] load .dockerignore 0.0s
=> => transferring context: 138B 0.0s
=> [internal] load build definition from Dockerfile 0.0s
=> => transferring dockerfile: 539B 0.0s
=> [internal] load metadata for docker.io/library/python:3.12.0 0.7s
=> [1/6] FROM docker.io/library/python:3.12.0@sha256:7b8d65a924f596eb65306214f5 0.0s
=> [internal] load build context 0.0s
=> => transferring context: 10.84kB 0.0s
=> CACHED [2/6] RUN apt-get -y update && apt-get -y install less tree vim 0.0s
=> CACHED [3/6] COPY requirements.txt /tmp 0.0s
=> CACHED [4/6] RUN pip install --upgrade pip && pip install --requirement /tmp 0.0s
=> [5/6] COPY [., /context] 0.0s
=> [6/6] WORKDIR /context 0.0s
...
root@pydiner:/context#
From the inside, a container looks like a Linux machine.
root@pydiner:/context# which python
/usr/local/bin/python
root@pydiner:/context# grep PRETTY_NAME /etc/os-release
PRETTY_NAME="Debian GNU/Linux 12 (bookworm)"
root@pydiner:/context#
Python can import packages from the src/
folder without hacking sys.path:
root@pydiner:/context# python
Python 3.12.0 (main, Nov 1 2023, 12:56:53) [GCC 12.2.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import pydiner
>>> pydiner.echo("Hello, World!")
2023-11-02 23:00:27 Hello, World!
>>> exit()
root@pydiner:/context#
Scripts in /context/bin
are already on the system PATH.
root@pydiner:/context# scrambled -o example.txt eggs
2023-11-02 23:05:33 Read parameters from /context/etc/default
2023-11-02 23:05:33 Calculate 24 permutations of 'eggs'
2023-11-02 23:05:33 Write output to /context/var/example.txt
root@pydiner:/context#
Don't. Use it as a template for a new repository.
Press CTRL-D or type exit
to exit a container.
Not if you create a USER
. See the Dockerfile reference for details.
Yes, but not with the kitchen
script. See the Docker run reference.
None. Programs stop immediately when something goes wrong.
None, but it has been tested with pytest to ensure compatibility.
None. utensils.achtung()
prints to STDERR
. utensils.echo()
prints to STDOUT
.