Set up a venv and avoid breaking the system Python
Task
Create a virtual environment, install a dependency into it, and record it reproducibly -- and see the guard that now stops you damaging the system interpreter. Then meet the KeyError-versus-None distinction that crashes scripts reading other people's JSON.
Steps
- Confirm which Python you have:
python3 --version,which python3, and note whether a barepythoneven exists. - Try to install into the system Python:
pip3 install requests. On a recent system observe theexternally-managed-environmentrefusal, and explain what damage it is preventing. - Create a virtual environment:
python3 -m venv ~/.venvs/lab, activate it, and confirmpythonandpipnow point inside it. - Install a dependency into the venv and confirm it imports.
- Record it:
pip freeze > requirements.txt, then rebuild the environment on a fresh venv withpip install -r requirements.txtand confirm it matches. - Write a tiny script demonstrating the dict trap:
d["missing"]raises KeyError and stops the script, whiled.get("missing")returns None. Show both against a small parsed-JSON structure. - Guard an importable module with
if __name__ == "__main__":and prove that importing it does not run its work.
Verify
source ~/.venvs/lab/bin/activate
python -c 'import sys; print(sys.prefix)' | grep -q '.venvs/lab' && echo "inside the venv"
python -c 'import requests; print("import ok")'
python - <<'PY'
d = {"a": 1}
try:
d["missing"]; print("no error -- wrong")
except KeyError:
print("KeyError as expected")
print("get returns:", d.get("missing"))
PY
sys.prefix pointing inside the venv is the confirmation that you are isolated from the system Python. The KeyError versus None output is the distinction behind a large share of crashes in scripts that read JSON they did not produce.
Notes
sudo pip install into the system Python can overwrite a library dnf itself depends on, with no record in the RPM database, and the breakage surfaces later during an unrelated update. PEP 668's refusal is a guard, not an obstacle -- the flag that defeats it is named --break-system-packages for a reason.