Lately, I’ve been working more with the Python programming language. I’ve used Python some in the past, but this time I really want to get a deeper understanding of the language and its ecosystem. To get up to speed, I’ve been reading Dead Simple Python by Jason McDonald. It’s an excellent book for developers who already know how to program but want to learn Python, along with its ecosystem and common best practices.
One topic that can be convoluted is project setup. I expected to find a simple command-line utility like python init
, something I could quickly use to spin up a project structure. There are some utilities that do this job for you, such as Poetry and UV.
However, for the sake of understanding, I really wanted to work with the basic tooling available: more hands-on work with pip
and virtual environments
, and craft my setup from there. Setting up a basic project with these tools, however, can involve a lot of tedious steps.
The aforementioned book does a great job of detailing how and what to set up as you create basic to sophisticated projects. There’s also plenty of material on the internet that describes different project setups and approaches.
So, I decided to automate the process and share what I have so far…
The Python Project Initializer Script
Here’s the link to a repo that contains the script I created:
init_python_project.sh.
This script automates the creation of a very simple Python project with a virtual environment, a few tools for linting, formatting, and testing, and a program entry point.
Script Breakdown:
This script automates the setup of a basic Python project, providing everything you need to get started quickly and efficiently. Here’s a breakdown of what it’s doing:
1. Create the Project Directory
The script begins by asking for a project name and creating a directory with that name. This directory serves as the root of your new project.
if ! mkdir "$PROJECT_NAME"; then
echo "Error: Failed to create project directory."
exit 1
fi
cd "$PROJECT_NAME" || exit
This ensures that the project directory is created successfully, and the script exits gracefully if an error occurs.
2. Set Up a Virtual Environment
A virtual environment isolates dependencies for your project, preventing conflicts with system-wide Python packages or other projects.
"$PYTHON_VERSION" -m venv .venv
source .venv/bin/activate
Virtual Environment Creation:
python3 -m venv .venv
sets up an isolated environment within a .venv/
directory. When using vscode with python tools, opening the project directory will automatically pickup the virtual environment.Activation: Activating the environment ensures all dependencies installed via
pip
are scoped to this project.
3. Initialize Dependencies
The script installs a few handy tools for development:
Black: A code formatter that enforces a consistent style.
Flake8: A linting tool for catching style and syntax issues.
pytest: The most common Python testing framework.
pip install --upgrade pip
pip install black flake8 pytest
This ensures that your project starts with tools for formatting, linting, and testing.
4. Create a pyproject.toml
File
The script generates a pyproject.toml
file, a standardized way to configure Python tools and projects. This file simplifies configuration and avoids cluttering the project with multiple tool-specific files.
Example contents for pyproject.toml
:
[tool.black]
line-length = 88
target-version = ['py38']
[tool.flake8]
max-line-length = 88
exclude = [".venv", "venv", "tests/"]
[tool.black]
: Configures Black to format code with a line length of 88 characters, targeting Python 3.8.[tool.flake8]
: Configures Flake8 to match the same line length and exclude directories likevenv
andtests
.
By centralizing configurations in pyproject.toml
, you maintain a clean and modern setup.
5. Generate a requirements.txt
File
To help with reproducibility, the script uses pip freeze
to list installed dependencies and lock them into a requirements.txt
file.
pip freeze > requirements.txt
This makes it easy for others (or future you) to recreate the same environment using:
pip install -r requirements.txt
6. Create Basic Project Files and Structure
The script scaffolds a simple, functional Python project structure. The resulting directory looks like this:
<project-name>/
├── .git/
├── .gitignore
├── .venv/
├── LICENSE.md
├── pyproject.toml
├── README.md
├── requirements.txt
├── <project-name>.py # root level entry point
├── <project-name>/
│ ├── __init__.py
│ └── __main__.py # Entry point for the application
└── tests/ # Tests directory
├── __init__.py
└── test_placeholder.py # Placeholder test file
This structure provides a clean starting point for a simple project.
7. Set Up Git
The script also initializes a Git repository and sets up a .gitignore
file for version control.
How to Use the Script
You can clone or simply download the script file. Then make it executable and run it with the filename like so:
chmod +x ./init_python_project.sh
./init_python_project.sh
This will create a project in the same directory as the script.
Make the Script Available Anywhere
What I do is add the script in a location where my PATH
variable will pick it up. I’m running a Mac with Zsh as my shell. Here’s how you can do it:
Move the Script to a Directory in Your
PATH
A common location for user scripts is~/bin
or/usr/local/bin
. you can move the script into that directory.
mv init_python_project.sh ~/bin/
Add the Directory to Your
PATH
If~/bin
isn’t already in yourPATH
, add it in your ZSH configuration file (~/.zshrc
):
# look for a line like this, it may be commented-out
export PATH="$HOME/bin:$PATH"
Then reload your ZSH configuration:
source ~/.zshrc
Call the Script from Anywhere
Now you can use the script from any directory:
init_python_project.sh
This makes it convenient to spin up a new Python project in any directory.
Why Automate?
By automating all of these steps, this script allowed me to learn a lot about Python’s tooling and ecosystem while saving the time and hassle of manually setting up each new project.
It’s a great foundation for small projects and can easily be extended as my needs grow.
Grab the script here and let me know how it works for you! Feel free to add issues, submit pull requests for improvements, or fork the repo for your own needs.