openlang

Most install bugs are just the wrong interpreter

Most "I installed it but the import fails" reports come down to pip belonging to a different Python than the one running the code. pip install uses whichever pip is first on PATH. python -m pip install uses the interpreter you just named. That one habit removes a whole family of confusion, and python -m pip --version prints which interpreter it's attached to.

The second habit is one virtual environment per project, made with python -m venv .venv. Activation is a convenience that mostly edits PATH. You can skip it and call .venv/bin/python directly on Linux and macOS, which is also what scripts and editors should do.

What a venv doesn't give you is a reproducible install. It isolates packages from the system, but a requirements file with loose versions still resolves differently a while later. For that you need pinned versions with hashes, or something like Nix that pins the interpreter as well. I go back and forth on whether the extra machinery is worth it for small projects, and mostly I just pin versions and leave it there.

后续讨论 2

顺着彼此的依据读下去
  1. 固定链接

    The no-activation habit has one gap, and cron is where it shows, since nothing there ever sources an activate script. The interpreter you name is fine. /srv/proj/.venv/bin/python job.py runs against the venv's packages, and sys.prefix differs from sys.base_prefix, the venv docs' own test.

    A child started by name is another matter. If job.py starts a second step with subprocess.run(["python3", "step2.py"]), that one can die on an import. Calling the venv interpreter by full path doesn't put .venv/bin on PATH, and cron's PATH is tiny, so python3 resolves to the system one.

    import shutil, subprocess, sys
    
    print(sys.prefix != sys.base_prefix)   # True
    print(shutil.which("python3"))         # /usr/bin/python3
    subprocess.run([sys.executable, "step2.py"], check=True)

    sys.executable avoids that. So activation is optional for the interpreter you name, and anything that looks a command up by name still goes through PATH. I write the full path and sys.executable now.

同一个问题的其他角度

  1. Launching the consumer on a stopped event

    Got a question about a supervisor rule that treats a stopped process as a finished one, and a tiny repro makes the problem ob…

    回复 17最近活动 bashpython
  2. What does a --hash line actually pin?

    A requirements file with --hash on every line installs cleanly on my laptop and fails with a hash mismatch in a fresh Linux c…

    回复 8最近活动 python
  3. After the Kotlin DSL move, subprojects can no longer find implementation

    Moving an old multi-project build from the Groovy DSL to the Kotlin DSL. The root build.gradle had this block. The root I con…

    回复 2最近活动 kotlingroovy