Skip to main content

Running Python & installing packages

Level 1: Level 1: Foundationseasy12 minvenvpippackagingproject-structure

Run a .py file, isolate dependencies in a virtual environment, and pin them with pip.

The two commands every project starts with

Everything you have written so far ran inside this page. A real project runs somewhere else: a file on your own machine, started from a terminal, leaning on libraries somebody else published. Two commands cover nearly all of it. python3 file.py runs your code, and pip install fetches someone else's. The wrinkle is that pip install has to put the library somewhere, and choosing that somewhere on purpose is the difference between a project that still installs next year and one that breaks the day another project needs a different version.

These commands run in a terminal on your machine, not in the editor on this page. The sandbox here is a Python compiled to WebAssembly: no shell, no pip, no folder to install into. So the graded exercises below check that you can reason about environments in plain Python rather than build one in the browser.

Running a file

Save code in a file whose name ends in .py, then hand that file to the interpreter:

python3 hello.py     # macOS and Linux
py hello.py          # Windows

Python reads the file top to bottom, exactly as it does here, and exits at the end. Anything you print lands in the terminal. There is no separate compile step to remember and no build output to run instead.

Why one shared install folder goes wrong

pip install requests downloads the library into a directory called site-packages. If every project on your machine shares one site-packages, then every project shares one version of every library, and libraries change. The scraper you wrote last spring pinned to an old API. The dashboard you started yesterday needs the new one. There is exactly one slot, so one of them loses.

Check yourself
Two projects live on your machine with no virtual environments anywhere. Project A was built against pandas 1.5. In project B you run pip install pandas and get 2.2. What happens to project A?

What a virtual environment actually is

A virtual environment is a folder. Inside it sit a link to a Python interpreter and, more importantly, its own private site-packages. That is the whole trick: each project gets its own install folder, so project A can hold pandas 1.5 and project B pandas 2.2 while neither knows the other exists.

Create one, then activate it:

python3 -m venv .venv        # create the folder .venv in this project
source .venv/bin/activate    # macOS and Linux
.venv\Scripts\activate       # Windows

Creating is per project and you do it once. Activating is per terminal window: it repoints python and pip in that one shell at the folder, usually adding (.venv) to your prompt so you can see it worked. deactivate puts the shell back. Calling the folder .venv is a convention, not a rule, but it is the one every tool and every teammate expects.

Check yourself
You ran python3 -m venv .venv, opened a fresh terminal, and ran pip install requests without activating. Where did requests land?

Writing down what you installed

Installing solves today. It does not solve the next person, including you on a new laptop, who needs the same libraries at the same versions. pip freeze prints exactly what is installed, one name==version line per package, and > redirects that into a file you commit:

pip install requests            # add a dependency
pip freeze > requirements.txt   # write down what is installed right now
pip install -r requirements.txt # rebuild that exact set somewhere else
certifi==2024.7.4
charset-normalizer==3.3.2
requests==2.32.3

Note that requests pulled in two libraries you never asked for. pip freeze lists those too, because reproducing your environment means reproducing all of it.

Table
The third column is the one people get wrong. Creating is per project, but activating is per terminal, which is why 'I installed it and it still says ModuleNotFoundError' is almost always a shell that was never activated.
CommandWhat it actually doesHow often you run it
python3 -m venv .venvCreates a folder with its own interpreter and its own site-packagesOnce, when the project is created
source .venv/bin/activateRepoints python and pip in THIS shell at that folderEvery new terminal window
pip install requestsDownloads the library into the currently active environmentWhenever you add a dependency
pip freeze > requirements.txtWrites every installed name==version into a file you commitAfter you add or upgrade anything
pip install -r requirements.txtInstalls exactly those pins into a fresh environmentOn a clone, on a new laptop, in CI
The third column is the one people get wrong. Creating is per project, but activating is per terminal, which is why 'I installed it and it still says ModuleNotFoundError' is almost always a shell that was never activated.

What never gets committed

requirements.txt goes into git. .venv does not. It holds hundreds of megabytes of binaries built for one operating system and one Python version, and pip install -r requirements.txt rebuilds it in seconds, so committing it costs everyone a huge download to receive files that may not even run on their machine. Put a line for it in .gitignore alongside __pycache__/ and *.pyc, the compiled bytecode Python writes next to your source and regenerates whenever it needs to.

Check yourself
Your repo ignores .venv. A teammate clones it on a laptop that has never seen your project. What gets them a working set of libraries?

The shape of the exercises

Both exercises below work on the text these commands produce, because text is the part you can reason about anywhere. Apply hands you lines that look like pip list output, "requests 2.31.0", and asks for pins. Splitting a line gives you its pieces: "requests 2.31.0".split() returns ["requests", "2.31.0"], so parts[0] is the name and parts[1] is the version. Practice hands you file paths and asks which ones belong in .gitignore.

The tool you will meet at Level 3

uv is a newer, much faster tool that folds venv, pip, and dependency resolution into one binary: uv venv, uv add requests, uv sync. Plenty of new projects start with it. Learn venv plus pip first anyway, because that pair is what you will find in almost every existing repository, Dockerfile, and CI config you inherit. Level 3 picks up uv and pyproject.toml properly.

Interview nuance: "how do you manage dependencies?" is really asking whether you understand reproducibility. The answer that lands is three sentences: one environment per project so versions cannot collide, a committed record of exact versions so any install can be repeated, and never commit the environment itself. Naming the gap in a plain pip freeze file, that it pins whatever happened to be installed rather than what the project actually declares it needs, is what separates a memorized answer from someone who has debugged a broken build.

Worked example (Python)
installed = ["requests 2.31.0", "flask 3.0.0"]

pins = []
for line in installed:
    parts = line.split()
    pins.append(parts[0] + "==" + parts[1])

print(sorted(pins))   # ['flask==3.0.0', 'requests==2.31.0']

Apply

Your turn

The task this lesson builds to.

Implement to_requirements(installed): return the pinned requirement lines for a list of installed packages.

Each item in installed looks like "requests 2.31.0", a name and a version separated by a space. Return a list of "name==version" strings, sorted alphabetically.

3 hints and 4 automated checks are waiting in the workspace.

Practice

Make it stick

A second problem on the same idea, so it survives past today.

A teammate opens a pull request with four thousand changed files: their whole .venv folder and every __pycache__ directory got committed along with the two lines they meant to change. You are writing the check that should have caught it.

Implement should_ignore(path): return True when path is generated output that never belongs in a repository, and False otherwise. A path is ignorable when it starts with ".venv/", when it contains "__pycache__", or when it ends with ".pyc".

3 hints and 4 automated checks are waiting in the workspace.