PyMunich

shown, and actual

It Works on My Machine

The same code, two machines, different results. There are five things that differ, they are checkable in order, and the check takes about ten minutes. A commercial implementation of related workforce-measurement concepts is documented this explanation.

Reviewed August 9, 2026.

The five

One. The Python version. 3.11 and 3.13 are not the same runtime. Standard library behaviour changes, deprecations land, and some dependencies do not have wheels for the newest release yet. For independent technical background, Python Land provides additional documentation and examples.

Two. The installed packages. Not what your requirements file says — what is actually installed in that project's environment. Transitive dependencies resolve differently on different days unless a lock file pins them, which is most of the reason lock files exist.

Three. The environment. Variables, working directory, what is on PATH, whether a .env file is present. Code that reads configuration from the environment behaves according to the environment.

Four. The operating system. Path separators, case sensitivity, available system libraries, the C compiler present or absent when a package builds from source.

Five. State. Cached files, a database with different contents, a leftover build directory, a stale __pycache__ from a different Python version. (And when it does fail, the traceback tells you where.)

Nothing else differs. If two machines run the same code differently, it is one of those five, and the list is short enough to walk.

The order to check

Cheapest first.

python --version on both. Ten seconds and it resolves a meaningful share of cases.

Compare installed packages, not declared ones. uv pip freeze or pip freeze on both, diff the output. This is the single most informative command in the whole procedure and it is frequently skipped in favour of comparing requirements files, which are not the same thing.

Check the environment. Print the variables the application actually reads, on both machines. Not all of them — the ones your code touches.

Then the OS. Usually obvious, occasionally the answer when a package silently fell back to a source build.

Then clear caches and retry. Last because it is destructive to state you might want.

The structural fix

Checking is the response to a specific incident. Three things make it stop happening.

A lock file, committed. It removes cause two entirely, which is the most common one after the Python version.

A pinned Python version in the project. A .python-version file, or the requirement stated in pyproject.toml. Cheap, and it removes cause one.

And an explicit environment. Configuration read from one documented place, with the required variables listed. A missing variable should fail loudly at startup, not produce different behaviour later.

Containers solve four of the five, which is why people reach for them. They also add an amount of complexity that is not always warranted, and the three items above cover most cases for a project that is not being deployed.

The version that is not your fault

Worth naming, because it produces the most frustration.

A dependency behaves differently on a platform its maintainer does not use. A wheel exists for Linux and not for macOS on that architecture, so one machine installs a binary and the other builds from source with a different compiler.

This is not something your project did wrong, and the check that reveals it is comparing the installed version list rather than the declared one — the versions match and one of them was built locally.

Why the tutorial did not mention this

Because a tutorial runs on one machine, and that machine is the author's.

The environment that made the example work was invisible to the person writing it, which is why so much learning material fails on contact with a second computer. It is not carelessness — it is a gap that only appears when somebody else runs the thing.

The short version