Python virtual environments (python -m venv) are not magic: they are a specific directory layout plus pyvenv.cfg that controls where Python imports and where pip installs.
When installs land in the “wrong” place or imports behave inconsistently, the evidence is inside .venv/.
This guide maps each folder and file (Scripts/bin, site-packages, .dist-info, pyvenv.cfg) to the behavior it drives, so you can debug environment issues by inspection.
Virtual environment structure on Linux/macOS
A typical environment looks like this:
.venv/
├── pyvenv.cfg
├── bin/
├── include/
└── lib/
└── python3.12/
└── site-packages/
What each part does
- pyvenv.cfg: declares the environment and base Python.
- bin/: executables and scripts like python and pip.
- include/: headers for compiling native extensions.
- site-packages/: where code installed by pip lives.
What changes on Windows?
The logic is the same, but paths differ:
.venv/
├── pyvenv.cfg
├── Scripts/
└── Lib/
└── site-packages/
Key difference: Scripts/ is the Windows equivalent of bin/.
pyvenv.cfg: the file in control
Real example:
home = C:\Python312
include-system-site-packages = false
version = 3.12.4
What matters most:
- home points to the base interpreter
- include-system-site-packages controls isolation
If set to true, your environment can see global packages. Useful in edge cases, risky by default.
bin/Scripts: why pip installs in the right place
Inside the environment, pip is not magic. It is a script that invokes the environment Python.
That is why this pattern is so safe:
python -m pip install requests
Instead of trusting whichever pip is in PATH, you force interpreter-installer consistency.
site-packages and .dist-info: your best debugging source
When you install a library, you usually get two things:
- The package itself (importable source)
- Its .dist-info directory (metadata)
Conceptual example:
site-packages/
├── requests/
└── requests-2.32.0.dist-info/
Inside .dist-info you will find files like:
- METADATA: version, dependencies, authors
- RECORD: list of installed files
- INSTALLER: who installed it (for example, pip)
When uninstall fails, RECORD often explains why.
Inspect installed packages from Python
from importlib.metadata import version, distributions
print("requests:", version("requests"))
for dist in distributions():
print(dist.metadata["Name"], dist.version)
This technique is gold for quick audits of Python environments.
Common problem: moving a .venv between machines
A virtual environment is not portable across different systems.
Reasons:
- absolute paths in scripts
- platform-specific compiled binaries
- architecture and ABI differences
Practical rule: never copy .venv between machines. Recreate it from pyproject.toml/lock file or requirements.
Mini anatomy checklist for troubleshooting
When an environment “breaks,” check this first:
- Does pyvenv.cfg exist?
- Do python and pip point to the same environment?
- Does site-packages contain the expected package?
- Are there version conflicts in .dist-info?
This checklist solves a large percentage of import and install issues.
Common mistakes
- Deleting or editing
pyvenv.cfgmanually, then wondering why the environment no longer behaves like a venv. - Running
pip/pythonfrom different locations (Scripts/bin vs system PATH), so installs go to one interpreter and your code runs on another. - Trying to “fix” installs by deleting random folders in
site-packages/(especially.dist-info/), which can leave the environment inconsistent. - Moving or copying
.venv/between machines/OSes and expecting it to remain valid.
Pro tip: visibility into orphaned environments
Across many repos, old .venv/ directories pile up and you stop knowing what is safe to delete. KillPy can scan for environments and list likely-orphaned ones so you can clean up after verifying they are unused.
Conclusion
Understanding the anatomy of Python virtual environments changes how you debug:
- you know where to look
- you understand what pip is doing
- you detect inconsistencies before production
The natural next step is pyproject.toml: how to declare modern dependencies and build reproducible projects.
What is the weirdest venv/virtualenv symptom you have had to debug (wrong pip, broken imports, uninstall failures)? Share it in the comments with your OS, and I will point you to the exact file(s) to inspect.
Previous
If you have not read the fundamentals yet:
→ https://dev.to/tlaloces/python-venv-explained-stop-breaking-dependencies-4k9k
Next
In the next step, we move from inspecting environments to defining them:
→ pyproject.toml: Modern Python Dependency Management (coming next)
Top comments (0)