Python Project Layout

From NovaOrdis Knowledge Base
Jump to navigation Jump to search

Internal

Overview

A typical Python project layout, which allows for code written in other programming languages as well, is similar to:

.
├─ .gitignore
├─ requirements.txt
├─ run
├─ src
│   └─ mypackage
│       ├─  __init__.py
│       ├─  __main__.py 
│       └─ VERSION
├─ tests
│   └─ mypackage
│       ├─  
│           
└─ venv # created automatically upon virtual environment initialization
      ├─ bin
      ...

Start with an empty requirements.txt file, it can be expanded incrementally.

Initialize the Virtual Environment

Initialize the virtual environment following the manual procedure described here:

Python Virtual Environment | Virtual Environment Creation

Update pip and, if requirements.txt has declared dependencies, install them:

Python Virtual Environment | Virtual Environments and pip

Add __main__.py

Add the initial __main__.py:

.
└─ src
    └─ mypackage
        └─ __main__.py 

def main():
    print('.x')


main()

Add the run script

Expand requirements.txt


Setting a Manual Project

A project set up this way will be compatible with PyCharm. Also see:

Simple PyCharm Project

Add the dependencies to requirements.txt. For more details, see:

requirements.txt

Initialize the virtual environment:

cd ${PROJECT_HOME}
python3 -m venv venv
venv/bin/pip install -r ./requirements.txt

For more details on virtual environments, see:

Virtual Environment

.gitignore

venv/
__pycache__/
idea/

Bash Wrapper

TODO: reconcile with Calling Python from bash | Running_a_Python_Program_with_a_Bash_Wrapper.

#!/usr/bin/env bash

function main() {
  manage_venv "$@"
  PYTHONPATH="$(dirname $0)/src"
  export PYTHONPATH
  "$(dirname $0)/venv/bin/python3" -m gpm "$@"
}

#
# If the virtual environment does not exist, create it based on requirements.txt.
# If it does exist, recreate if '--force-init' is present among options.
#
function manage_venv() {
  force_init=false
  while [[ -n $1 ]]; do
    if [[ $1 == '--force-init' ]]; then
      force_init=true
    fi
    shift
  done
  if [[ -d $(dirname $0)/venv ]]; then
    if ${force_init}; then
      rm -rf "$(dirname $0)/venv"
    else
      return 0
    fi
  fi
  echo "initializing venv ..."
  python3 --version 1>/dev/null 2>&1 || { echo "python3 not in PATH" 1>&2; exit 1; }
  python3 -m venv "$(dirname $0)/venv"
  "$(dirname $0)/venv/bin/pip" install -r "$(dirname $0)/requirements.txt"
}

main "$@"

TODO

Process this: PEP 517 – A build-system independent format for source trees https://peps.python.org/pep-0517/