Our Dockerfile uses a base image and multi-stage builds to allow for creation of a testing and development image that is separate from the production image, which does not contain any test files. NOTE: Adding a Python package in requirements.txt will require rebuilding to ensure the new package is contained in the image.
To build the testing and development Docker image for the program, run the following command:
docker build --target test -t llcsim:dev .This command builds the Docker image using the test stage from the Dockerfile and tags it as llcsim with the dev version.
The image can be run in a container which will be removed on exit using the following command:
docker run --rm -it llcsim:dev bashNOTE: Do not use this for development or any persistent changes to code. The container is ephemeral and is best suited for troubleshooting and automated testing purposes only.
This image will run the tests automatically using the following command:
docker run --rm -it llcsim:devTo build the production Docker image, run the following command:
docker build --target production -t llcsim:latest .This command builds the production Docker image and tags it as llcsim with the latest version.
After building the image, you can run the container using the command:
docker run --rm llcsim:latestThis will run main.py and exit. The --rm flag ensures that the container is removed after it exits.
To start the development environment, use the following command:
docker compose up -d dev && docker compose exec dev bashThis command does two things:
- Starts the
devservice in detached mode (-d), allowing you to run it in the background. - Executes a bash shell in the running
devcontainer, where you can run the program.
Once inside the container, you can execute your main program using:
python main.pyYou can run tests using the following:
python -m unittestThis runs all the tests. Run specific tests with the following:
python -m unittest tests.utils.test_cache_loggerExample of running a specific test file - in this case, the the test_cache_logger.py file in /tests/utils.
It may sometimes be helpful to rebuild to remove any stale images:
docker compose build --no-cacheAfter exiting the shell, the dev container will still be running because it was started with a command that keeps it alive. You can stop this container by running:
docker compose downOr you can connect to the shell again using docker compose exec dev bash.
If you want to run the main program directly using docker compose and let the container exit upon completion, you can use:
docker compose up appIn this case, the container will run the app service defined in the docker-compose.yml file, execute the program, and then stop when the program finishes.
The compose.yml services may be extended in the future to support a test service, which could be used in a Github Actions environment.
We use Black for formatting, Flake8 for linting, and isort to maintain consistent dependency import ordering and formatting. This section explains how to run each tool on the src directory to check code quality, and how to apply changes if any issues are found.
Black is used to automatically format Python code to adhere to a consistent style.
- Check Only: To check if there are any formatting issues without modifying files, run:
black --check src/or for additional detail:
black --diff src/- Apply Formatting: To automatically format all files in the
srcdirectory, run:
black src/- Overriding Automated Formatting: If there are specific lines or code blocks where you need to override Black’s automated formatting, you can use
# fmt: offand# fmt: oncomments. Black will skip formatting for code between these markers.
# fmt: off
example = [
"This", "is", "a", "long", "list", "that", "we", "want", "to", "format",
"manually", "for", "readability", "even", "though", "Black", "would",
"normally", "format", "it", "differently"
]
# fmt: onPlace # fmt: off before the code you want to exclude from formatting, and # fmt: on after it. Use these sparingly, as consistent formatting across the codebase is preferred. See the Black documentation for more details.
Flake8 is used to identify potential errors, code style issues, and other coding standard violations.
Note: Flake8 does not modify files, so the following command is sufficient to identify any issues that need to be manually addressed.
flake8 src/isort is used to organize imports in Python files.
- Check Only: To check for import order issues without making any changes, run:
isort --check-only src/- Sort Imports: To automatically sort and organize imports in all Python files within
src, run:
isort src/The pre-commit hook in /scripts/hooks will run on any invocation of git commit, and will prevent the commit from completing if any of the pre-commit checks fail. The script currently runs black, isort, and flake8, all in check-only modes to prevent files from being automatically modified. After addressing any issues, you can stage the updated files and retry the commit.
To install the pre-commit hook, you can either run the installation script located at scripts/install_git_hooks.py, or manually copy the pre-commit script from scripts/hooks to your .git/hooks directory.