6

I installed the earlier version (3.11.2) normally using apt package manager and the later version (3.12) manually from source. When I execute python scripts like so:

./python_script.py

The script uses the earlier version instead of the later one. I would like to leave the default shebang line #!/usr/bin/env python3 at the beginning of the script alone for portability reasons.

Here is a sample test script.

#!/usr/bin/env python3

import sys

def main():
  print(sys.version)

main()

enter image description here

EDIT: With the above configuration, I'm thinking at this point the quickest fix (probably not the best because of future consequences, please see well explained answers and comments from the community below) is to change the target of the python3 symlink in /etc/alternatives to /usr/local/bin/python3.12 where my python3.12 binary is stored.

enter image description here

EDIT2: As seen in the second screenshot, I was able to get ./myscript.py to use the python version I wanted (3.12) by verifying that the /usr/local/bin directory is before the /usr/bin directory in my PATH environment variable and renaming the python3.12 binary in /usr/local/bin/ to python3.

5
  • 5
    I use pyenv (github.com/pyenv/pyenv) for this. It makes it very easy to install and select different versions of python. Commented Nov 5, 2023 at 22:34
  • I highly recommend pyenv
    – Hieu Thai
    Commented Nov 6, 2023 at 12:30
  • It’s nice to see good answers being essentially ignored :-/. I’ve updated my answer to try to explain why your quickest fix is a really bad idea. Commented Nov 13, 2023 at 12:25
  • Well, I put /usr/local/bin containing my own python3.12 built binary before /usr/bin the system default in the PATH (See picture above). As you can see, when I run ./myscript.py the interpreter still uses the 3.11.2 system version of python. I must be missing something :-/ ?
    – siralbert
    Commented Nov 13, 2023 at 20:57
  • Figured it out, had to rename python3.12 to python3 in the /usr/local/bin directory (See second screenshot added above)
    – siralbert
    Commented Nov 14, 2023 at 0:44

4 Answers 4

16

Since you’re using env python3, the default version of Python will be determined by whichever version of python3 is first in the PATH variable. You can thus choose which version is used by constructing your PATH variable appropriately: if you want the system default, ensure /usr/bin appears before any other directory containing python3, and if you want your own build of Python, ensure the directory containing that version of python3 appears before /usr/bin.

Your proposed solution is one of the worst you could apply at this point. Given the situation shown in your screenshot, you haven’t broken your system yet: system Python scripts, which specify #!/usr/bin/python3 in their shebang, can still find the modules they expect. If you change /usr/bin/python3 to point to Python 3.12, those scripts will lose access to the 3.11 modules installed on your system; in particular, python3-apt. This is liable to have unfortunate consequences.

Since you are specifying #!/usr/bin/env python3 in your own scripts, and can therefore rely on PATH, I still think a PATH-based approach is better in your circumstances. You can even change PATH everywhere, to point to your python3 first, without breaking system Python scripts (since they don’t rely on PATH to find Python).

1
  • Stephen, I added another screenshot and edit above which shows that I was able to use my own build of python by using the PATH-based approach that you suggested. Running, ./myscript.py uses the 3.12 intepreter instead of the 3.11.2 one. If I missed anything or did something incorrectly or shouldn't have let me know.
    – siralbert
    Commented Nov 14, 2023 at 0:39
10

To complement @StephenKitt's fine answer, on Debian-based systems, you may be able to install packages for more than one version of python concurrently. For instance here on Ubuntu 22.04, I have 3.10 and 3.11 installed:

$ aptitude search -F%p '~i ~n "^python[0-9.]*$"'
python3
python3.10
python3.11

The python3 package depends on python3.10 and the python3 executable is a symlink to python3.10.

$ zstat +link --  ${(v)commands[(I)python[0-9.]#]}
/usr/bin/python3 python3.10
/usr/bin/python3.10
/usr/bin/python3.11

Do not change that symlink manually. python versions are often incompatible between each other, and python modules are not shared between python versions, so changing that python3 symlink will break the scripts that have a #! /usr/bin/env python3 or #! /usr/bin/python3 (or #! /bin/python3 as /bin is often a symlink to /usr/bin nowadays) and expect python3 to be 3.10 and have access to the python modules installed for 3.10.

So if you need to invoke a script that needs a different installed version of python, and you can't change the shebang to #! /usr/bin/python3.12, either just invoke it as:

python3.12 /path/to/that-file.py

Or create a:

mkdir ~/.python3-is-python3.12
ln -s /usr/bin/python3.12 ~/.python3-is-python3.12/python3

And put ~/.python3-is-python3.12 ahead in your $PATH but only for the invocation of that script, setting it globally would likely break other scripts that use #! /usr/bin/env python3 and expect python3 to be the system's default python3.

1
  • 2
    For what it's worth, the strategy of injecting directories into your $PATH as described in this answer is more or less what pyenv does in a more user-friendly way.
    – David Z
    Commented Nov 6, 2023 at 1:06
10

I know this questions only asks about the apt package manager, and the other answers cover that aspect very well.

But if you are working with several different python projects, all requiring different python versions and/or different dependencies, I would strongly recommend using a virtual environment (venv) to manage the python versions and the dependencies of your projects.

To install a virtual environment for a project, e.g. for 3.11, In the project's main directory, run:

python3.11 -m venv venv

This will create a directory named venv containing the virtual environment.

Then, to use the environment, type:

. venv/bin/activate

From that point on, in the current shell you will be able to run python and pip without the version number, and the correct environment will be used. To get out of the environment, type deactivate.

In the new environment you will have only the pip dependencies that you installed inside it, so you won't have any dependency mismatches between projects. You will also be able to easily create the requirements.txt file for the project with pip freeze > requirements.txt after you have installed the dependencies.

0
-2

Since you're using Debian (or one of its derivatives), you could consider using the update-alternatives utility.

For example to set the default to your 3.12 version residing in (for example) /usr/local/bin/:

sudo update-alternatives --install /usr/bin/python3 python3 /usr/local/bin/python3.12 10

The response should be something like this (I've not actually installed Python 3.12):

update-alternatives: using /usr/local/bin/python3.12 to provide /usr/bin/python3 (python3) in auto mode

See man update-alternatives for details, and other options.

13
  • 2
    No, update-alternatives isn’t made for this. I know it’s an extremely popular idea, but Python packages in Debian and derivatives do not use update-alternatives and setting this up is a common way of breaking the system (especially in Ubuntu or derivatives where some essential tools rely on Python). Commented Nov 5, 2023 at 19:43
  • 4
    For our discussion, the key part in the man page is this: “When each package providing a file with a particular functionality is installed, changed or removed, update-alternatives is called to update information about that file in the alternatives system.” The alternatives system is set up by packages which participate in it; the system administrator’s involvement is supposed to stop at choosing between available alternatives. Attempting to use alternatives with packages which don’t use the alternatives system is a recipe for disaster. Commented Nov 5, 2023 at 22:14
  • 1
    Leaving aside whether one version of Python can replace another, using update-alternatives for python3 involves replacing a packaged file (/usr/bin/python3), which is a bad idea in general. Look at the output of dpkg -S /usr/bin/vi /usr/bin/python3: the former is an actual alternative, and isn’t owned by any package; the latter isn’t an alternative, it’s owned by python3-minimal. The first rule for users of packaged distributions is that you don’t touch packaged files in /usr. Commented Nov 6, 2023 at 6:37
  • 3
    As far as Python 3.11 and 3.12 being alternatives is concerned, they aren’t: there are breaking changes between 3.11 and 3.12, and system-installed Python 3.11 modules aren’t automatically made available on 3.12. Thus a package expecting /usr/bin/python3 to be Python 3.11 is liable to break if it’s another version of Python. The Python tools in Debian allow packages to be built for multiple Python versions, but that’s decided when the package is built, it can’t be added by the administrator after the fact (except by rebuilding). Commented Nov 6, 2023 at 6:41
  • 1
    @Seamus Python 3.11 and Python 3.12 are not alternatives. They are NOT 100% compatible with each other (easy example, Python 3.12 dropped four modules from the standard library that were present in Python 3.11, and PEP 701 being implemented in 3.12 means that you can do things in 3.12 with f-strings that you can’t in 3.11). And, on top of that, system-wide site-packages (third party modules) are installed per-version on Debian systems, so the system-wide modules may not be the same between the two versions. Commented Nov 6, 2023 at 14:09

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .