+ 02.03.2024 Szukanie ścieżek do plików .exe * Python Launcher for Windows * Instalacja kolejnej wersji Python w Windows

Wyszukiwanie dostępnych wersji Pythona w Windows

W SKRÓCIE

Reguły, które zamierzam sobie stosować:

  1. Uruchamianie plików *.py jako skryptów Windows przez py.exe tj. Python Launcher for Windows, głównie z opcją wynikającą z pierwszeństwa na liście ścieżek do python.exe w zmiennej środowiskowej PATH.
  2. Używanie w pierwszym wierszu pliku *.py: #!/usr/bin/env python - właśnie celu korzystania z PATH (na końcu nie może być żadnych cyfr - tylko samo python)
  3. W “Edytuj zmienne środowiskowe systemu” należy po instalacji kolejnej wersji Pythona przenieść ścieżki do Python.exe z Path - system do Path - użytkownika, żeby umożliwić sobie wygodniejszą ich modyfikację. - Zdaje się, że w nowszych wersjach ścieżka już od razu jest w Path - użytkownika.
  4. Na pierwszym miejscu w Path - użytkownika wpisuję %PY_PTH%, a zmienną środowiskową PY_PTH ustawiam domyślnie na .venv\Scripts np. poleceniem setx PY_PTH .venv\Scripts (to daje ścieżkę względną w Path). W ten sposób skrypt uruchamiany z miejsca, gdzie jest wygenerowane środowisko wirtualne będzie wywoływał python.exe właśnie z tego środowiska. Dla doraźnej potrzeby można zmieniać PY_PTH na inną ścieżkę.
  5. W Path - użytkownika_ poniżej %PY_PTH% umieszczam ścieżkę do wybranego python.exe, który ma być uruchamiany, gdy nie korzystam ze środowiska wirtualnego. Można też dodać do Path folder Scripts.
  6. Na sam koniec Path - użytkownika przenoszę
    %USERPROFILE%\AppData\Local\Microsoft\WindowsApps,
    żeby się nie włączał sklep Microsoft po wywołaniu python.exe
  7. Środowsko wirtualne generuję w miejscu (tj. folderze) skryptu *.py za pomocą:
    ścieżka\do\wzorcowego\python.exe -m venv .venv
    .venv\Scripts\python -m pip install --upgrade pip setuptools wheel
    setx PY_PTH .venv\Scripts
    

    Przy takich ustawieniach nie jest potrzebna aktywacja środowiska wirtualnego. Będzie się włączało to, które jest w folderze wywoływanego skryptu.
    Ostatnie polecenie jest zbędne, gdy nie zmienialiśmy PY_PTH.


Szukanie plików “.exe” dostępnych poprzez PATH

where /t "$path:python.exe"

/t - można pominąć; wtedy nie wyświetla się rozmiar i data pliku. Albo where /t python.exe w jakimś folderze gdzie nie ma “python.exe”:

Przeszukiwanie w głąb całych folderów

where /r "C:\\" /t python.exe

Uwaga - to chwilę trwa. Tu po /r jest nazwa foldera, od którego zaczyna się szukanie - chyba powinno się stosować podwójne \\ np. dla całego dysku: C

Znalezioną ścieżkę “python.exe” można trwale zapamiętać w PATH (w menu START zacznij pisać “Edytuj zmienne środowiskowe dla konta” lub “… dla systemu”). Wtedy python lub python mójSkrypt.py będzie wywoływało właśnie tą wersję. Można też modyfikować PATH tuż przed wywołaniem python w linii poleceń lub w pliku *.cmd. Jeśli używamy tekstów UTF-8 (np. w nazwach plików) to warto na początek włączyć to kodowanie w linii poleceń: chcp 65001.

Gdy mamy swoje moduły, używane w różnych projektach to można dodać
set PYTHONPATH=%PYTHONPATH%;C:\My_python_lib



Python Launcher for Windows

Od wersji 3.3 wraz z instalacją Pythona jest instalowany program py.exe oraz pyw.exe, np. C:\Windows\py.exe, który pozwala na kompilację wprost poprzez uruchamianie pliku *.py. W pierwszym wierszu naszego skryptu *.py można wpisać np. #!python3.7-64 lub #!/usr/bin/python3.7-64 (w Windows /usr/bin/ jest pomijany).

Natomiast specjalne znaczenie ma #!/usr/bin/env python - wg. dokumentacji następuje tu przeszukiwanie ścieżki PATH w celu uruchomienia pierwszego(?) napotkanego Python.exe . Jest to również przydatna opcja do uruchamiania środowiska wirtualnego (Uwaga - niestety nie można wpisać np. #!/usr/bin/env python3, i to pomimo tego, że python3.exe jest znajdywalny w PATH. Gdy tylko użyjemy jakichś cyfr, to sposób uruchamiania ignoruje /usr/bin/env i działa wg. reguły poszukiwania wersji determinowanej przez te cyfry.

Aby przetestować który kompilator się uruchamia można przygotować sobie testowy plik v.py:

#!/usr/bin/env python
import sys
input('\n'.join(['',sys.executable,sys.version,'','nacisnij Enter']))

Lista wersji kompilatorów do wyboru m.in za pomocą #!....:

py -0p

py bez parametrów wywołuje swój domyślny kompilator python.exe - oznaczany na liście gwiazdką. Ale gdy uruchamiamy jakiś plik z pierwszym wierszem #!…, to to ustawienie ma priorytet. Generalnie wywołanie z py może dawać całkiem inne efekty niż z python (wyszukany w PATH).

Sprawdzenie aktualnej obsługi pliku *.py - skopiuj do linii poleceń:

for /f "tokens=2 delims==" %i in ('assoc .py') do (ftype %i)

Można też znaleźć bardziej rozbudowane wersje takiego sprawdzania: FOR /F "tokens=2* delims==" %G IN ('assoc .py') DO for /f "tokens=2* delims==" %a in ('ftype %G') do @echo %a

Przypisanie aplikacji do rozszerzenia “.py” w linii poleceń administratora (cmd[Ctrl+Shift+Enter] ):

ASSOC .py=Python.File
FTYPE Python.File="C:\WINDOWS\py.exe" "%L" %*

Jest to już zrobione jak w tym przykładzie, jeśli instalowaliśmy jakikolwiek pakiet PYTHONa 3.3+.

Uwaga - jeśli dodaliśmy swoją obsługę plików *.py (poprzez “Otwórz za pomocą”), to ten nasz wybór będzie miał priorytet nad powyższą konfiguracją. Aby to naprawić należy wybierać do uruchomienia *.py aplikację Python z ikoną rakiety py32.png. Wybieranie wprost “C:\WINDOWS\py.exe” jest błędem.

Ewentualnie, aby uruchamiać skrypt podając samą nazwę bez wpisywania rozszerzenia “.py” można jeszcze dodać set PATHEXT=.PY;%PATHEXT%
lub trwale zmodyfikować PATHEXT w “Edytuj zmienne…”.

Więcej inf. o aktualnym stanie konfiguracji, np. z pliku %LocalAppData%\py.ini uzyskamy włączając PYLAUNCH_DEBUG :
set PYLAUNCH_DEBUG=1 & py -0p . Następnie można uruchamiać plik testowy v.py z rożnymi opcjami w #!…

Przykładowy wynik działania opcji PYLAUNCH_DEBUG dla #!/usr/bin/env python w pliku v.py z kodowaniem utf-8-BOM:

  File 'C:\Users\user\AppData\Local\py.ini' non-existent  
  File 'C:\Windows\py.ini' non-existent  
  Called with command line: "C:\test\v.py"  
  maybe_handle_shebang: read 112 bytes  
  maybe_handle_shebang: BOM found, code page 65001  
  parse_shebang: found command: python  
  searching PATH for python executable  
  Python on path: C:\Kompil\Python36-32\python.exe  
  ...


set PY_PYTHON=3 & set PY_PYTHON3=3.6-32 - ustala domyślną wersję dla uruchamianych *.py. Równoważny zapis w py.ini:

[defaults]
python=3
python3=3.6-32

Skutecznie działa również set PY_PYTHON=3.6-32, lub trwale pamiętane setx PY_PYTHON 3.6-32 i ma pierwszeństwo nad py.ini. Działanie zmiennych jest takie samo (?) jak dane w py.ini po pominięciu PY_. https://docs.python.org/3.5/using/windows.html#shebang-lines. W py.ini może być np. tylko:

[defaults]
python=3.11-64

Z linii poleceń można dopisać tekst do swojego py.ini (modyfikacja działa od razu i nie trzeba restartu aplikacji np. cmd albo N++ jak w przypadku SetX): (echo:[defaults]&echo:python=3.11-64)>%LocalAppData%\py.ini
Sprawdzenie: type %LocalAppData%\py.ini

W środowisku wirtualnym (zob.^) regułą nadrzędną jest wywołanie aktywowanego kompilatora Python.exe.

Można tu jeszcze wspomnieć o wymyślaniu własnych poleceń wpisywanych w py.ini, które można używać w #!….,tylko należy pamiętać, że nie mogą zaczynać się od python.


Można wyświetlić ścieżki PATH w linii poleceń wstawiając łamanie wierszy: echo:%PATH:;=; & echo:%
Uwaga - Path jest składana z 2 części, które w “Edytuj zmienne…” widzimy jako - Path - system (priorytetowa) i Path - użytkownika. Warto je sobie uporządkować jak opisano na początku artykułu. Można też wyświelić aktualny stan środowiska wykonując w oknie cmd polecenia:

echo:&echo|set /p="*** %computername%  %date%  " & for /f "tokens=1,2,* " %G in ('reg query "HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\Environment"') do @echo setx /m %G "%I
echo:&echo|set /p="*** %username%              " & for /f "tokens=1,2,* " %G in ('reg query "HKCU\Environment"') do @echo setx %G "%I

… albo wykonując skrypt get_environment.cmd:

@echo off
echo|set /p="*** %computername%  %date%  "
for /f "tokens=1,2,* " %%G in (
'reg query "HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\Environment"'
) do echo setx /m %%G "%%I
echo|set /p="*** %username%              "
for /f "tokens=1,2,* " %%G in (
'reg query "HKCU\Environment"'
) do echo setx %%G "%%I

Zauważ, że w poleceniach setx mamy celowo niezamknięty cudzysłów " ("%%I).


Instalacja kolejnej wersji Python w Windows

1 . Uruchom: cmd /k py -0p

  • aby ustalić położenie obecnie używanego kompilatora Python.exe (i obok zainstalować nowszą wersję).

2 . Tu jest dobry moment aby zapamiętać zainstalowane globalnie biblioteki przez pip install ...: py -m pip freeze

  • ale część z nich jest zainstalowana jako pochodna innych instalacji, więc może lepiej sobie zapamiętywać sukcesywnie w pliku kolejne doinstalowane moduły, albo skorzystać ze skryptu:
Python pip_install_list.py ...
. . .
# Lista modułów zainstalowanych przez `pip install`
import subprocess # https://stackoverflow.com/questions/4760215/
import re
py = 'py' # py='c:\Kompil\Python39\python'
pip_freeze = subprocess.run([py,'-m','pip','freeze'], capture_output=True, text=True).stdout 
# 'rauth==0.7.3\nrequests==2.25.1\n...
modules = [re.sub(r'==.+$', '', m) for m in pip_freeze.split()] # bez `==v.x.y`
# ['rauth','requests',...
print('\n'.join([f'''py -m pip install {m}''' for m in modules]))
####################################################
#Wyszukanie modułów głównych z pominięciem zależnych (to trochę trwa!)
mGl = set()
for m in modules:
  print(f''' === {m} === ''')
  pip_show = subprocess.run([py,'-m','pip','show', m], capture_output=True, text=True).stdout
#  print('-.-.-\n',pip_show)
# -.-.-
# Name: requests
# ...
# Requires: certifi, chardet, idna, urllib3
# Required-by: rauth
# ...
# Zdarzają się błędy, które raczej nie dotyczą wiersza 'Requires: ...
# UnicodeDecodeError: 'utf-8' codec can't decode byte 0xe3 ...
  if not pip_show: continue # >>>>>>>>
  match = re.search(r'^Requires: (.*)$[\r\n]+^Required-by: (.*)$', pip_show, flags=re.MULTILINE)
  if match: # np. match[1] -> 'certifi, chardet, idna, urllib3', match[2] -> 'rauth'
    print(match[0]) # 'Requires: certifi, chardet, idna, urllib3\nRequired-by: rauth'
    if match[2] == '':
      mGl.add(m) 

print('\n  ',"Moduły nadrzędne:")
print('\n'.join([f'''py -m pip install {m}''' for m in mGl]))
PowerShell pip_install_list.ps1 ...
. . .
# Lista modułów zainstalowanych przez `pip install` (bez `==v.x.y`)
($m = (py -m pip freeze).Split("`n") | foreach { $_ -replace '==.+$', ''})
# Instalacja wszystkich modułów - spis:
# $m | foreach {"py -m pip install $($_)"}

###################################################
#Wyszukanie modułów głównych z pominięciem zależnych (to trochę trwa!)
$mGl = @{}
foreach ($k in $m) {
  $k
  $v = (py -m pip show $k) | Select-String "^Required-by"
  if ($v.ToString().Length -le "Required-by: ".Length) {
    $mGl[$k] = $v
  }
}
# $mGl["rauth"]   -> "Required-by: " (tzn. główny moduł)
# $mGl["requests"]-> "Required-by: rauth" (moduł zależny - sam się zainstaluje)
"Instalacja modułów głównych - spis"
$mGl.keys | foreach {"py -m pip install $($_)"}

3 . https://www.python.org/

  • Download

4 . ➜ Install Now ...

  • [✓] Add python.exe to PATH
  • ➜ Customize installation
    • [✓][✓] py launcher [_] for all…
    • [_] [✓] [✓] [✓] [_] [_] [_]
    • Customize install location [C:\Kompil\Python\Python311]
      (wygodnie jest używać klarownej lokalizacji)

5 . W zmiennych środowiskowych użytkownika - PATH - %PY_PTH% na pierwsze miejsce; usuwam ścieżki do starszych wersji Python.

  1. Uruchom cmd. Uruchom kontrolnie py -0p, potem py, exit().

7 . py -m pip install --upgrade pip setuptools wheel

8 . Odtwarzam potrzebne py -m pip install ... z listy z p.2


#!/usr/bin/env python - uruchamianie w Linux. Po zalogowaniu na root:
_ cd /usr/bin/
_ unlink python
_ ln -sv /usr/bin/python3 python
albo w ~/.bashrc dopisać:
_ alias python=python3
i potem uruchomić
_ source ~/.bashrc


Zob. też