Skip to main content

Someone wanted to learn this too, so Grasp built them a personal learning path.

You can keep exploring this one or create your own

Creating Reproducible Python Environments and Dependency Pins

Hello! Last lesson, you created a Linux project under WSL2 and confirmed that VS Code could run run.py with Linux Python. That established where your batch-processing code runs. Now you’ll control which packages it runs with.

By the end of this lesson, your batch-sales project will have an isolated Python environment, a file recording exact dependency versions, and a second environment built from that file. The final check matters: a dependency list is only useful if it can actually recreate a working setup.


Why a project needs its own environment

Python includes modules you can use without installing anything—for example, csv and json, which you’ll use in the next lesson. Other capabilities come from third-party packages. Suppose one project needs an older release of a package while another needs a newer one. Installing both into the shared system Python creates a conflict.

A virtual environment gives a project its own location for installed packages. It is created using a particular Python installation, but it does not package an entire independent operating system or make your project independent of that Python version. Isolation keeps one project’s packages from interfering with another’s; pinning records the versions you chose so they can be installed again.

Watch Tech With Tim’s Python Virtual Environments – Full Tutorial for Beginners for the complete create–install–record–recreate workflow.

Python Virtual Environments - Full Tutorial for Beginners

Tech With Tim demonstrates why environments prevent project conflicts and how a requirements file lets someone rebuild one.

Watch the motivation, then environment creation and package installation. Finish with record and replay. The demonstrator names the environment differently and shows commands for multiple operating systems; for this project, use the WSL/Linux commands below and name its directory .venv.

The Python Packaging User Guide is a useful command reference. Its recommendation to keep the environment out of version control is particularly important when you later share a project.

Install packages in a virtual environment using pip and venv - Python Packaging User Guide

Read the Python Packaging User Guide’s explanation of where a virtual environment lives, how activation works, and what belongs in version control.

Under “Create and Use Virtual Environments,” read the subsections “Create a new virtual environment,” “Activate a virtual environment,” and “Deactivate a virtual environment.” In “Create a new virtual environment,” start at the explanation that names the folder; continue through the note that says to exclude the environment. In “Activate a virtual environment,” focus on why the shell finds the environment’s Python and pip first; read “Deactivate a virtual environment” for how to leave it.


Create and verify .venv in WSL

Open the WSL-connected VS Code window from last lesson and use its Ubuntu terminal—not PowerShell. Return to the existing project and confirm your location:

cd ~/projects/batch-sales
pwd
python3 --version

pwd should begin with /home/. Keep note of the Python version printed here: your requirements file will record package versions, not the Python version needed to run them.

On Ubuntu, the system Python may be installed without the component required to create virtual environments. Install it with Ubuntu’s package manager:

sudo apt update
sudo apt install python3-venv

Now create and activate the environment:

python3 -m venv .venv
source .venv/bin/activate

Activation changes this terminal’s search path so python and pip refer to .venv. Verify the actual paths rather than relying only on the (.venv) prompt:

command -v python
python -c "import sys; print(sys.executable)"
python -m pip --version

The Python paths should be under /home/.../batch-sales/.venv/bin/, and the pip output should refer to .venv too. If python3 -m venv .venv reports that ensurepip is unavailable, follow Ubuntu’s message about the required python3-venv package (or the version-specific python3.x-venv package it names), then retry creating the environment.

Use python -m pip for package commands throughout this lesson: it explicitly runs pip with the python interpreter you just checked. Inside the activated environment, your existing script should still work:

python run.py

Its interpreter line should now point into .venv, unlike the system-Python path you saw last lesson.

In VS Code, use Python: Select Interpreter and choose the interpreter at batch-sales/.venv/bin/python. An already-open terminal may not change when you select an interpreter in the editor; activate .venv in that terminal yourself and check its path again. When you open a fresh terminal later, reactivate the environment with source .venv/bin/activate if needed. deactivate leaves the environment in the current terminal; it does not delete it.


Install a package and record exact versions

For a small, free installation example, use requests, a package for making HTTP requests. You do not need it for next lesson’s CSV and JSON files; here it gives you a realistic dependency to install and verify.

With .venv active, run:

python -m pip install requests
python -c "import requests; print(requests.__version__)"
python -m pip freeze

The import confirms that this interpreter can find requests. The freeze output will probably contain several packages you did not name in the install command. Those are transitive dependencies: packages that requests itself needs.

Save the installed versions to a requirements file:

python -m pip freeze > requirements.txt

The > writes pip’s output into requirements.txt, replacing that file if it already exists. Open it in VS Code. A line such as requests==2.32.3 means “install exactly this release”; your actual version may differ. Do not replace the generated version with the example.

Read pip’s Repeatable Installs documentation for the distinction between naming a package and pinning a complete set of installed dependencies.

Repeatable Installs - pip documentation v26.1.2

Pip’s documentation explains what the == pins mean, why pip freeze includes transitive dependencies, and the limits of this kind of repeatability.

Read the whole “Pinning the package versions” subsection. Begin where it explains that pins guard against new releases. Continue through the paragraph that says a freeze-generated file includes transitive dependencies, and stop at the end of this subsection, just before “Hash-checking.” Notice that pinning versions is a useful level of repeatability, not a guarantee that every machine has an identical Python runtime or identical downloaded files.

Before you freeze a real project, start with a clean environment and install only packages the project needs. pip freeze records what is installed, not which packages your code genuinely uses. When you intentionally add or update a dependency later, regenerate the file and review what changed rather than upgrading everything without checking.

The .venv directory contains local installed files and should not be committed to Git; requirements.txt should be kept with the project. Create or edit .gitignore in the project root to include these lines, preserving any entries already there:

.venv/
.venv-replay/
__pycache__/

The second entry is for the temporary verification environment you’ll make next.


Prove the file can recreate the environment

Imagine opening this project on a clean machine. You would create an environment and install from requirements.txt, rather than copy someone else’s .venv directory. You can test that process locally without disturbing your working environment.

First leave .venv, then build a second environment in the project:

deactivate
python3 -m venv .venv-replay
.venv-replay/bin/python -m pip install -r requirements.txt

The -r tells pip to read package specifications from the file. Calling .venv-replay/bin/python directly makes it unambiguous which environment receives the installation, even though it is not activated.

Verify both the import and the installed versions:

.venv-replay/bin/python -c "import requests; print(requests.__version__)"
.venv-replay/bin/python -m pip freeze

Compare the second freeze output with requirements.txt. For this small project, the package names and versions should match. If installation fails, check that you are in batch-sales, that requirements.txt exists, and that the install command uses .venv-replay/bin/python rather than system Python. Package downloads also require an internet connection; they do not require a cloud account.

You can keep .venv-replay while inspecting it, or remove it later—it contains no project source code. To resume work in the original environment, run:

source .venv/bin/activate
python run.py

For someone else to repeat this setup, they also need a compatible Python version. Record the output of python3 --version in your project setup notes alongside the instruction to create a virtual environment and run python -m pip install -r requirements.txt. Version pins make installation substantially more predictable, but they do not by themselves lock the operating system, Python runtime, or downloaded package files.


Conclusion

You now have two complementary pieces: .venv isolates the packages used while you work, and requirements.txt records their exact installed versions. Rebuilding those versions in .venv-replay demonstrated that the file is an installation plan, not merely a list. Keep environment directories out of Git, keep the requirements file with your code, and check the interpreter path whenever a package seems to have “disappeared.”

Next, you’ll use this project to read and write CSV and JSON while preserving the data types your pipeline expects.

Can't find a good explanation? Sign up and we'll make it for you

Sign up