<commit_before>@echo off
:##############################################################################
:#                                                                            #
:#  Filename        python.bat                                                #
:#                                                                            #
:#  Description     Run python.exe, even when it's not in the PATH            #
:#                                                                            #
:#  Notes 	    The default instance of Python is considered to be        #
:#		    the one associated with the .py file extension in         #
:#		    the registry; Not necessarily the one in the PATH.        #
:#                                                                            #
:#  History                                                                   #
:#   2017-01-16 JFL Created this file.                                        #
:#   2019-09-30 JFL Added option -X.                                          #
:#   2019-10-01 JFL Added options --, -# and -l.                              #
:#   2019-10-02 JFL Use DisableDelayedExpansion to avoid issues w. ! in args. #
:#                  Added option -V.                                          #
:#   2019-11-29 JFL Make the python instance number inheritable.              #
:#   2020-02-27 JFL Search python.exe in more locations.                      #
:#   2021-02-25 JFL Added option -d to enabled debugging.                     #
:#                  Removed a dependency on my VMs host drive configuration.  #
:#                  Use short names to compare instances reliably.            #
:#                                                                            #
:#          Copyright 2019 Hewlett Packard Enterprise Development LP         #
:# Licensed under the Apache 2.0 license  www.apache.org/licenses/LICENSE-2.0 #
:##############################################################################

setlocal EnableExtensions DisableDelayedExpansion
set "VERSION=2021-02-25"
set "SCRIPT=%~nx0"		&:# Script name
set "SNAME=%~n0"		&:# Script name, without its extension
set "SPATH=%~dp0"		&:# Script path
set "SPATH=%SPATH:~0,-1%"	&:# Script path, without the trailing \
set "SFULL=%~f0"		&:# Script full pathname
set ^"ARG0=%0^"			&:# Script invokation name
set ^"ARGS=%*^"			&:# Argument line

call :debug.off
goto :main

:debug.off
set "DEBUG=0"
goto :debug.common
:debug.on
set "DEBUG=1"
:debug.common
set "ECHO.D=if %DEBUG%==1 echo"
set "ECHOVARS.D=if %DEBUG%==1 call :EchoVars"
exit /b

:EchoVars	%1=VARNAME %2=VARNAME %3=VARNAME ...
setlocal EnableExtensions EnableDelayedExpansion
:EchoVars.loop
if "%~1"=="" endlocal & goto :eof
%>DEBUGOUT% echo %INDENT%set "%~1=!%~1!"
if defined LOGFILE %>>LOGFILE% echo %INDENT%set "%~1=!%~1!"
shift
goto EchoVars.loop

:# Get the first (#0) trailing argument
:GetArg0 %1=VARNAME %2=ARG0 %3... ignored
set "%~1=%~2"
exit /b

:# Get the Nth trailing argument
:GetArgN %1=VARNAME %2=N %3=ARG0 %4=ARG1 ...
setlocal DisableDelayedExpansion
set "VAR=%~1"
for /l %%n in (1,1,%~2) do shift
endlocal & set "%VAR%=%~3"
exit /b

:# Append an element to a list. The list is walkable using a for %%e in (!LIST!) ...
:lappend %1=LISTNAME %2=value
if defined %~1 (
  call set %%~1=%%%1%% %%2
) else (
  set %~1=%2
)
exit /b

:# Get the Nth element of a list.
:lindex %1=LISTNAME %2=index %3=VARNAME
call call :GetArgN %%3 %%2 %%%~1%%
exit /b

:# Get the command line used to open a given file type
:GetOpenCommand %1=type %2=VARNAME
set "%~2="
for /f "delims== tokens=2" %%c in ('ftype %~1 2^>NUL') do set "%~2=%%c"
exit /b

:# Get the default python.exe executable
:GetPythonExe %1=VARNAME
%ECHO.D% :GetPythonExe %1
call :GetOpenCommand Python.File %1
if defined %~1 call call :GetArg0 %%1 %%%~1%%
%ECHOVARS.D% %1
exit /b

:# Get a list of all python.exe executables
:GetAllPythonExe %1=LISTNAME
setlocal EnableDelayedExpansion
set "SEARCHDRIVES=C:"		&:# List of drives where to search for python.exe.
if not "%HOMEDRIVE%"=="C:" set "SEARCHDRIVES=%HOMEDRIVE% %SEARCHDRIVES%" &:# Prepend the home drive, if it's different.
for /f "tokens=1" %%d in ('net use ^| findstr /C:"\\vmware-host\Shared Folders\\"') do ( :# And append VM host drives, if any.
  if exist "%%d%ProgramFiles:~2%" set "SEARCHDRIVES=!SEARCHDRIVES! %%d"
)
%ECHOVARS.D% SEARCHDRIVES
set "SHORT_LIST=" &:# List of instances found. Used to avoid reporting one twice.
set "LIST=" &:# List of instances found.
:# List first the default instance
call :GetPythonExe PYTHON
if defined PYTHON (
  for %%p in ("%PYTHON%") do call :lappend SHORT_LIST "%%~sp"
  call :lappend LIST "%PYTHON%"
)
:# Then look for other instances in well known places
for %%d in (%SEARCHDRIVES%) do (
  rem :# The default install dir is %LOCALAPPDATA%\Programs\Python\Python%VER% for the current user,
  rem :# Or %ProgramFiles%\Python%VER% or %ProgramFiles(x86)%\Python%VER% for all users.
  for %%p in ("" "%ProgramFiles:~2%" "%ProgramFiles(x86):~2%" "%LOCALAPPDATA:~2%\Programs") do (
    for %%y in ("Python" "Python\Python" "Microsoft Visual Studio\Shared\Python") do (
      for /d %%b in ("%%d%%~p\%%~y*") do (
        %ECHO.D% :# Looking in %%b
	for %%x in ("%%~b\python.exe") do if exist "%%~x" (
	  set "FOUND=" &:# Avoid duplications, for example with the default instance
	  for %%s in (!SHORT_LIST!) do if not defined FOUND if /i "%%~sx"=="%%~s" set "FOUND=1"
	  if not defined FOUND call :lappend SHORT_LIST "%%~sx" & call :lappend LIST "%%~fx"
	)
      )
    )
  )
)
endlocal & set %~1=%LIST%
exit /b

:# List python.exe instances
:list
setlocal EnableDelayedExpansion
call :GetAllPythonExe LIST
set "N=0"
for %%e in (!LIST!) do (
  echo #!N! %%~e
  set /a "N+=1"
)
endlocal
exit /b

:#----------------------------------------------------------------------------#
:# Main routine

:usage
echo.
echo %SCRIPT% - Run python.exe, even when it's not in the PATH
echo.<commit_msg>Restructured the instances enumeration to output the same list as PySetup.bat.<commit_after>@echo off
:##############################################################################
:#                                                                            #
:#  Filename        python.bat                                                #
:#                                                                            #
:#  Description     Run python.exe, even when it's not in the PATH            #
:#                                                                            #
:#  Notes 	    The default instance of Python is considered to be        #
:#		    the one associated with the .py file extension in         #
:#		    the registry; Not necessarily the one in the PATH.        #
:#                                                                            #
:#  History                                                                   #
:#   2017-01-16 JFL Created this file.                                        #
:#   2019-09-30 JFL Added option -X.                                          #
:#   2019-10-01 JFL Added options --, -# and -l.                              #
:#   2019-10-02 JFL Use DisableDelayedExpansion to avoid issues w. ! in args. #
:#                  Added option -V.                                          #
:#   2019-11-29 JFL Make the python instance number inheritable.              #
:#   2020-02-27 JFL Search python.exe in more locations.                      #
:#   2021-02-25 JFL Added option -d to enabled debugging.                     #
:#                  Removed a dependency on my VMs host drive configuration.  #
:#                  Use short names to compare instances reliably.            #
:#   2021-03-02 JFL Restructured the instances enumeration like in PySetup.bat.
:#   2021-03-04 JFL Synchronized changes with pip.bat.			      #
:#                                                                            #
:#          Copyright 2019 Hewlett Packard Enterprise Development LP         #
:# Licensed under the Apache 2.0 license  www.apache.org/licenses/LICENSE-2.0 #
:##############################################################################

setlocal EnableExtensions DisableDelayedExpansion
set "VERSION=2021-03-04"
set "SCRIPT=%~nx0"		&:# Script name
set "SNAME=%~n0"		&:# Script name, without its extension
set "SPATH=%~dp0"		&:# Script path
set "SPATH=%SPATH:~0,-1%"	&:# Script path, without the trailing \
set "SFULL=%~f0"		&:# Script full pathname
set ^"ARG0=%0^"			&:# Script invokation name
set ^"ARGS=%*^"			&:# Argument line

call :debug.off
goto :main

:debug.off
set "DEBUG=0"
set "ECHO.D=echo >NUL"
set "ECHOVARS.D=echo >NUL"
goto :debug.common
:debug.on
set "DEBUG=1"
set "ECHO.D=echo"
set "ECHOVARS.D=call :EchoVars"
:debug.common
set "FUNCTION=call %ECHO.D% call %%0 %%*&setlocal"
exit /b

:EchoVars	%1=VARNAME %2=VARNAME %3=VARNAME ...
setlocal EnableExtensions EnableDelayedExpansion
:EchoVars.loop
if "%~1"=="" endlocal & goto :eof
%>DEBUGOUT% echo %INDENT%set "%~1=!%~1!"
if defined LOGFILE %>>LOGFILE% echo %INDENT%set "%~1=!%~1!"
shift
goto EchoVars.loop

:# Get the first (#0) trailing argument
:GetArg0 %1=VARNAME %2=ARG0 %3... ignored
set "%~1=%~2"
exit /b

:# Get the Nth trailing argument
:GetArgN %1=VARNAME %2=N %3=ARG0 %4=ARG1 ...
setlocal DisableDelayedExpansion
set "VAR=%~1"
for /l %%n in (1,1,%~2) do shift
endlocal & set "%VAR%=%~3"
exit /b

:# Append an element to a list. The list is walkable using a for %%e in (!LIST!) ...
:lappend %1=LISTNAME %2=value
if defined %~1 (
  call set %%~1=%%%1%% %%2
) else (
  set %~1=%2
)
exit /b

:# Get the Nth element of a list.
:lindex %1=LISTNAME %2=index %3=VARNAME
call call :GetArgN %%3 %%2 %%%~1%%
exit /b

:# Get the command line used to open a given file type
:GetOpenCommand %1=type %2=VARNAME
set "%~2="
for /f "delims== tokens=2" %%c in ('ftype %~1 2^>NUL') do set "%~2=%%c"
exit /b

:# Get the default python.exe executable
:GetPythonExe %1=VARNAME
%ECHO.D% call :GetPythonExe %1
call :GetOpenCommand Python.File %1
if defined %~1 call call :GetArg0 %%1 %%%~1%%
%ECHOVARS.D% %1
exit /b

:# Get a list of all python.exe executables
:GetAllPythonExe %1=LISTNAME
%FUNCTION% EnableDelayedExpansion
set "LIST=" &:# List of instances found.

:# First list the default instance
call :GetPythonExe DEFAULT
set "SHORT_DEFAULT=" &:# Short version of the same, used to avoid reporting it twice.
if defined DEFAULT for %%p in ("!DEFAULT!") do (
  set "SHORT_DEFAULT=%%~sp"
  call :lappend LIST "%%~fp"
)

:# Then list py.exe if it's not the default
if defined DEFAULT for %%p in ("%DEFAULT%") do if not "%%~nxp"=="py.exe" (
  for %%x in (py.exe) do set "PY=%%~$PATH:x"
  if defined PY for %%p in ("!PY!") do (
    call :lappend LIST "%%~fp"
  )
)

:# Then list all instances that match the requested criteria
call :GetAllPythonDirs ALL_DIRS
for %%d in (%ALL_DIRS%) do (
  for %%p in ("%%~d\python.exe") do (
    if not "%%~sp"=="%SHORT_DEFAULT%" (
      call :lappend LIST "%%~fp"
    )
  )
)

endlocal & set %~1=%LIST%
%ECHOVARS.D% %~1
exit /b

:# Get a list of all python.exe installation directories in well known places
:GetAllPythonDirs %1=LISTNAME
%FUNCTION% EnableDelayedExpansion
set "LISTNAME=%~1"
set "DRIVES=C:"		&:# List of drives where to search for python.exe
if not "%HOMEDRIVE%"=="C:" set "DRIVES=%HOMEDRIVE% %DRIVES%" &:# Prepend the home drive, if it's different
for /f "tokens=1" %%d in ('net use ^| findstr /C:"\\vmware-host\Shared Folders\\"') do ( :# And append VM host drives, if any
  if exist "%%d%ProgramFiles:~2%" set "DRIVES=!DRIVES! %%d"
)
%ECHOVARS.D% DRIVES
set "LIST="
if not defined ProgramFiles(x86) set "ProgramFiles(x86)=%ProgramFiles% (x86)" &:# For x86 VMs searching on amd64 hosts
for %%d in (%DRIVES%) do (
  rem :# The default install dir is %LOCALAPPDATA%\Programs\Python\Python%VER% for the current user,
  rem :# Or %ProgramFiles%\Python%VER% or %ProgramFiles(x86)%\Python%VER% for all users.
  for %%p in ("" "%ProgramFiles:~2%" "%ProgramFiles(x86):~2%" "%LOCALAPPDATA:~2%\Programs") do (
    for %%y in ("Python" "Python\Python" "Microsoft Visual Studio\Shared\Python") do (
      for /d %%b in ("%%d%%~p\%%~y*") do (
	%ECHO.D% :# Looking in %%~b
	for %%x in ("%%~b\python.exe") do if exist "%%~x" (
	  if defined LISTNAME (
	    call :lappend LIST "%%~b"
	  ) else (
	    set "B=%%~b"
	    echo !B!
	  )
	)
      )
    )
  )
)
if defined LISTNAME (
  set SET_RESULT=set %LISTNAME%=%LIST%
  %ECHO.D% !SET_RESULT!
) else (
  set SET_RESULT=rem
)
endlocal & %SET_RESULT%
exit /b

:# List python.exe instances
:list
%FUNCTION% EnableDelayedExpansion
call :GetAllPythonExe ALL_PYTHON
set "N=0"
set ^"PY_VER_ARCH_CMD=import sys, os; print (sys.version.split()[0]+\" \"+os.environ[\"PROCESSOR_ARCHITECTURE\"])^"
for %%e in (!ALL_PYTHON!) do (
  set "PY_VER=" & set "PY_ARCH="
  for /f "tokens=1,2" %%v in ('^"%%e -c "!PY_VER_ARCH_CMD!" 2^>NUL^"') do set "PY_VER=%%v" & set "PY_ARCH=%%w"
  if defined PY_VER if defined PY_ARCH (
    set "INDEX_=!N!       "
    set "PY_VER_=!PY_VER!       "
    set "PY_ARCH_=!PY_ARCH!       "
    echo #!INDEX_:~0,3! !PY_VER_:~0,8! !PY_ARCH_:~0,7! %%~e
    set /a "N+=1"
  )
)
endlocal
exit /b

:#----------------------------------------------------------------------------#
:# Main routine

:usage
echo.
echo %SCRIPT% - Run python.exe, even when it's not in the PATH
echo.
{'fraction_non_alphanumeric': 0.17465907387981416, 'fraction_numerical': 0.02585044208002398, 'mean_word_length': 2.3094470617406397, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 14, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 52, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3050728', 'n_tokens_mistral': 4708, 'n_tokens_neox': 4287, 'n_words': 1386}