This page describes the directory layout and the application structure of GeniePy.

Project Layout

The initial directory structure looks as follows:

~/W/p/geniepy/code main ❯ tree -L 1 .
.
├── app
├── docker-compose.yml
├── Dockerfile
├── .env
├── fly.toml
├── heroku.yml
├── .github
├── .gitignore
├── .gitlab-ci.yml
├── Makefile
├── .pre-commit-config.yaml
├── pyproject.toml
├── README.md
├── render.yaml
├── requirements.in
├── requirements.txt
├── sample.env
├── secrets
├── setup.cfg
└── .test.env

app

The app directory contains all the application source code. We'll talk about this in detail in a later section.

docker-compose.yml

As mentioned before, we're using docker-compose for local development.

docker-compose.yml specifies the containers to start. The default configuration GeniePy ships includes 4 containers:

  1. app: container that runs the main Starlette/Uvicorn application listening on port 9001
  2. postgres: PostgreSQL container that the app container connects to for persisting data
  3. app_test: similar to the app container, but only used for running tests
  4. postgres_test: similar to the postgres` container, but only used for hosting the test database

The main application and test containers have beeen separated to isolate containers from each other in local development.

Dockerfile

This Dockerfile defines the container image for the Starlette / Uvicorn application.

The same file is used for both local development (using docker-compose) as well as to deploy the application to cloud services.

.env

An .env file is not shipped with the GeniePy distribution but instead needs to be specified by you. GeniePy instead ships a sample.env which you can use as an starting point, adjusting values as you see fit.

The purpose of this file is to store environment variables for app.

The docker-compose configuration for this container looks something like:

app:
  build: ./
  ports:
    - "9001:9001"
  command: uvicorn app.main:instance --host 0.0.0.0 --port 9001 --reload
  volumes:
      - ./app:/home/user/app
      - ./pyproject.toml:/home/user/pyproject.toml
      - ./secrets:/home/user/secrets
      - ./setup.cfg:/home/user/setup.cfg
  env_file: .env

The last line is how we tell docker-compose to take the key/value pairs inside .env and make them available as environment variables in the app container.

fly.toml

GeniePy supports Fly.io as one of the deployment targets.

Fly.io allows developers to configure their application stacks using TOML configuration files. We've added an initial configuration to fly.toml which you're welcome to extend if you use this deployment target.

heroku.yml

GeniePy supports Heroku as one of the deployment targets.

Heroku allows developers to deploy their applications inside containers. We've included an initial build configuration to heroku.yml that lets Heroku know how to build the application.

If you choose Heroku as your deployment target, you're welcome to extend this file depending on your application's needs.

.github

GeniePy support Github Actions as one of the Continuous Integration targets.

This directory contains the workflow definitions that will enable continuous testing for your application, if you've chosen Github as the source code hosting service.

.gitignore

A .gitignore file specifies which files inside the project directory should not be checked into Git.

.gitlab-ci.yml

GeniePy support Gitlab CI as one of the Continuous Integration targets.

This directory contains the workflow definitions that will enable continuous testing for your application, if you've chosen Gitlab as the source code hosting service.

Makefile

Make is a build automation tool that also acts as a great task runner.

In Makefile we've defined shortcuts for commands that are often run when developing code locally.

Since the local development environment is based on docker-compose, some of the commands (and their sequences) might be tricky to memorize. For instance, running tests locally involves first running database migrations on the test database and then running pytest. The full set of commands looks as follows:

$ docker-compose exec app_test alembic -c app/alembic.ini upgrade head
$ docker-compose exec app_test pytest

Alternatively, you can run make test which will execute all that for you.

.pre-commit-config.yaml

We use the pre-commit framework for managing Git's pre-commit hooks.

This YAML file specifies pre-commit's configuration.

pyproject.toml

pyproject.toml is a new standard introduced by the Python developers to specify build system information for Python projects.

This file also supports adding configuration for different Python tools. This is also what GeniePy uses this file for.

At the time of this writing, GeniePy specifies the configuration for isort in this file under a tool.isort table.

README.md

This file contains the project's README. We've left the file empty so you can fill it up with details about your project.

render.yaml

GeniePy supports Render as one of the deployment targets.

Render supports the Infrastructure as Code philosophy by letting users define their services inside a render.yaml file. We've specified the base configuration in this file, which you're welcome to extend if you are deploying your app on Render.

requirements.in

GeniePy uses pip-tools to help you keep your project's dependencies fresh.

requirements.in specifies the project's (first-level) dependencies pinned to their exact versions. The contents of this file are specified in the requirements.txt file format which pip understands.

Using this file as input, the pip-compile CLI bundled in pip-tools helps us generate the entire dependency tree with all the dependencies pinned to their exact versions.

requirements.txt

The requirements.txt file contains the entire dependency tree of our project.

This file is auto-generated using the pip-compile CLI, and as such, should NOT be edited by hand.

If you have adjusted requirements.in and would like to have requirements.txt reflect the change, please run make pip-compile.

sample.env

This file acts as a starting point for the environment variables for your application.

If you're initializing a new application, copy this file to .env and edit .env to have your application reflect the changes.

secrets

At times it's necessary to share sensitive files between the host machine and the application container, without having to check them in to Git. One very important use case is if you're working with Google Cloud and would like to pass on the Service Account JSON file to the container.

The secrets directory is there for exactly this reason. Any files that you add to this directory will be visible inside the same directory on the app container.

setup.cfg

The setup.cfg file is another way to store configuration for Python tools. GeniePy stores the flake8 configuration in this file.

.test.env

The .test.env file contains environment variables for the app_test container. Normally you should not need to edit this file.