diff --git a/tests/test-addremove-similar.t b/tests/test-addremove-similar.t
--- a/tests/test-addremove-similar.t
+++ b/tests/test-addremove-similar.t
@@ -57,7 +57,7 @@ comparing two empty files caused ZeroDiv
 
 should be sorted by path for stable result
 
-  $ for i in `python $TESTDIR/seq.py 0 9`; do
+  $ for i in `$PYTHON $TESTDIR/seq.py 0 9`; do
   >     cp small-file $i
   > done
   $ rm small-file
@@ -88,7 +88,7 @@ should be sorted by path for stable resu
 pick one from many identical files
 
   $ cp 0 a
-  $ rm `python $TESTDIR/seq.py 0 9`
+  $ rm `$PYTHON $TESTDIR/seq.py 0 9`
   $ hg addremove
   removing 0
   removing 1
@@ -107,11 +107,11 @@ pick one from many identical files
 pick one from many similar files
 
   $ cp 0 a
-  $ for i in `python $TESTDIR/seq.py 0 9`; do
+  $ for i in `$PYTHON $TESTDIR/seq.py 0 9`; do
   >     echo $i >> $i
   > done
   $ hg commit -m 'make them slightly different'
-  $ rm `python $TESTDIR/seq.py 0 9`
+  $ rm `$PYTHON $TESTDIR/seq.py 0 9`
   $ hg addremove -s50
   removing 0
   removing 1
diff --git a/tests/test-archive.t b/tests/test-archive.t
--- a/tests/test-archive.t
+++ b/tests/test-archive.t
@@ -105,7 +105,7 @@ invalid arch type should give 404
   > except util.urlerr.httperror as e:
   >     sys.stderr.write(str(e) + '\n')
   > EOF
-  $ python getarchive.py "$TIP" gz | gunzip | tar tf - 2>/dev/null
+  $ $PYTHON getarchive.py "$TIP" gz | gunzip | tar tf - 2>/dev/null
   test-archive-1701ef1f1510/.hg_archival.txt
   test-archive-1701ef1f1510/.hgsub
   test-archive-1701ef1f1510/.hgsubstate
@@ -113,7 +113,7 @@ invalid arch type should give 404
   test-archive-1701ef1f1510/baz/bletch
   test-archive-1701ef1f1510/foo
   test-archive-1701ef1f1510/subrepo/sub
-  $ python getarchive.py "$TIP" bz2 | bunzip2 | tar tf - 2>/dev/null
+  $ $PYTHON getarchive.py "$TIP" bz2 | bunzip2 | tar tf - 2>/dev/null
   test-archive-1701ef1f1510/.hg_archival.txt
   test-archive-1701ef1f1510/.hgsub
   test-archive-1701ef1f1510/.hgsubstate
@@ -121,7 +121,7 @@ invalid arch type should give 404
   test-archive-1701ef1f1510/baz/bletch
   test-archive-1701ef1f1510/foo
   test-archive-1701ef1f1510/subrepo/sub
-  $ python getarchive.py "$TIP" zip > archive.zip
+  $ $PYTHON getarchive.py "$TIP" zip > archive.zip
   $ unzip -t archive.zip
   Archive:  archive.zip
       testing: test-archive-1701ef1f1510/.hg_archival.txt*OK (glob)
@@ -135,19 +135,19 @@ invalid arch type should give 404
 
 test that we can download single directories and files
 
-  $ python getarchive.py "$TIP" gz baz | gunzip | tar tf - 2>/dev/null
+  $ $PYTHON getarchive.py "$TIP" gz baz | gunzip | tar tf - 2>/dev/null
   test-archive-1701ef1f1510/baz/bletch
-  $ python getarchive.py "$TIP" gz foo | gunzip | tar tf - 2>/dev/null
+  $ $PYTHON getarchive.py "$TIP" gz foo | gunzip | tar tf - 2>/dev/null
   test-archive-1701ef1f1510/foo
 
 test that we detect file patterns that match no files
 
-  $ python getarchive.py "$TIP" gz foobar
+  $ $PYTHON getarchive.py "$TIP" gz foobar
   HTTP Error 404: file(s) not found: foobar
 
 test that we reject unsafe patterns
 
-  $ python getarchive.py "$TIP" gz relre:baz
+  $ $PYTHON getarchive.py "$TIP" gz relre:baz
   HTTP Error 404: file(s) not found: relre:baz
 
   $ killdaemons.py
@@ -231,7 +231,7 @@ rename them afterwards.
   $ sleep 1
   $ hg archive -t tgz tip.tar.gz
   $ mv tip.tar.gz tip2.tar.gz
-  $ python md5comp.py tip1.tar.gz tip2.tar.gz
+  $ $PYTHON md5comp.py tip1.tar.gz tip2.tar.gz
   True
 
   $ hg archive -t zip -p /illegal test.zip
@@ -364,12 +364,12 @@ configured as GMT.
 
   $ hg -R repo archive --prefix tar-extracted archive.tar
   $ (TZ=UTC-3; export TZ; tar xf archive.tar)
-  $ python show_mtime.py tar-extracted/a
+  $ $PYTHON show_mtime.py tar-extracted/a
   456789012
 
   $ hg -R repo archive --prefix zip-extracted archive.zip
   $ (TZ=UTC-3; export TZ; unzip -q archive.zip)
-  $ python show_mtime.py zip-extracted/a
+  $ $PYTHON show_mtime.py zip-extracted/a
   456789012
 
   $ cd ..
diff --git a/tests/test-bad-pull.t b/tests/test-bad-pull.t
--- a/tests/test-bad-pull.t
+++ b/tests/test-bad-pull.t
@@ -7,7 +7,7 @@
   $ test -d copy
   [1]
 
-  $ python "$TESTDIR/dumbhttp.py" -p $HGPORT --pid dumb.pid
+  $ $PYTHON "$TESTDIR/dumbhttp.py" -p $HGPORT --pid dumb.pid
   $ cat dumb.pid >> $DAEMON_PIDS
   $ hg clone http://localhost:$HGPORT/foo copy2
   abort: HTTP Error 404: * (glob)
diff --git a/tests/test-basic.t b/tests/test-basic.t
--- a/tests/test-basic.t
+++ b/tests/test-basic.t
@@ -60,7 +60,7 @@ Verify that updating to revision 0 via c
   > EOF
   $ hg up null
   0 files updated, 0 files merged, 1 files removed, 0 files unresolved
-  $ python ./update_to_rev0.py
+  $ $PYTHON ./update_to_rev0.py
   1 files updated, 0 files merged, 0 files removed, 0 files unresolved
   $ hg identify -n
   0
diff --git a/tests/test-bisect.t b/tests/test-bisect.t
--- a/tests/test-bisect.t
+++ b/tests/test-bisect.t
@@ -463,12 +463,12 @@ test bisecting command
   $ chmod +x script.py
   $ hg bisect -r
   $ hg up -qr tip
-  $ hg bisect --command "python \"$TESTTMP/script.py\" and some parameters"
+  $ hg bisect --command "$PYTHON \"$TESTTMP/script.py\" and some parameters"
   changeset 31:58c80a7c8a40: good
   abort: cannot bisect (no known bad revisions)
   [255]
   $ hg up -qr 0
-  $ hg bisect --command "python \"$TESTTMP/script.py\" and some parameters"
+  $ hg bisect --command "$PYTHON \"$TESTTMP/script.py\" and some parameters"
   changeset 0:b99c7b9c8e11: bad
   changeset 15:e7fa0811edb0: good
   changeset 7:03750880c6b5: good
diff --git a/tests/test-blackbox.t b/tests/test-blackbox.t
--- a/tests/test-blackbox.t
+++ b/tests/test-blackbox.t
@@ -172,7 +172,7 @@ log rotation
   $ sed -e 's/\(.*test1.*\)/#\1/; s#\(.*commit2.*\)#os.rmdir(".hg/blackbox.log")\
   > os.rename(".hg/blackbox.log-", ".hg/blackbox.log")\
   > \1#' $TESTDIR/test-dispatch.py > ../test-dispatch.py
-  $ python $TESTDIR/blackbox-readonly-dispatch.py
+  $ $PYTHON $TESTDIR/blackbox-readonly-dispatch.py
   running: add foo
   result: 0
   running: commit -m commit1 -d 2000-01-01 foo
diff --git a/tests/test-bookmarks-pushpull.t b/tests/test-bookmarks-pushpull.t
--- a/tests/test-bookmarks-pushpull.t
+++ b/tests/test-bookmarks-pushpull.t
@@ -203,7 +203,7 @@ divergent bookmarks
 
 (test that too many divergence of bookmark)
 
-  $ python $TESTDIR/seq.py 1 100 | while read i; do hg bookmarks -r 000000000000 "X@${i}"; done
+  $ $PYTHON $TESTDIR/seq.py 1 100 | while read i; do hg bookmarks -r 000000000000 "X@${i}"; done
   $ hg pull ../a
   pulling from ../a
   searching for changes
@@ -231,7 +231,7 @@ divergent bookmarks
      @1                        2:0d2164f0ce0d
      @foo                      2:0d2164f0ce0d
 
-  $ python $TESTDIR/seq.py 1 100 | while read i; do hg bookmarks -d "X@${i}"; done
+  $ $PYTHON $TESTDIR/seq.py 1 100 | while read i; do hg bookmarks -d "X@${i}"; done
   $ hg bookmarks -d "@1"
 
   $ hg push -f ../a
diff --git a/tests/test-bundle2-remote-changegroup.t b/tests/test-bundle2-remote-changegroup.t
--- a/tests/test-bundle2-remote-changegroup.t
+++ b/tests/test-bundle2-remote-changegroup.t
@@ -74,7 +74,7 @@ Create an extension to test bundle2 remo
 
 Start a simple HTTP server to serve bundles
 
-  $ python "$TESTDIR/dumbhttp.py" -p $HGPORT --pid dumb.pid
+  $ $PYTHON "$TESTDIR/dumbhttp.py" -p $HGPORT --pid dumb.pid
   $ cat dumb.pid >> $DAEMON_PIDS
 
   $ cat >> $HGRCPATH << EOF
diff --git a/tests/test-censor.t b/tests/test-censor.t
--- a/tests/test-censor.t
+++ b/tests/test-censor.t
@@ -304,7 +304,7 @@ Can re-add file after being deleted + ce
 
 Can censor after revlog has expanded to no longer permit inline storage
 
-  $ for x in `python $TESTDIR/seq.py 0 50000`
+  $ for x in `$PYTHON $TESTDIR/seq.py 0 50000`
   > do
   >   echo "Password: hunter$x" >> target
   > done
diff --git a/tests/test-check-config.t b/tests/test-check-config.t
--- a/tests/test-check-config.t
+++ b/tests/test-check-config.t
@@ -23,7 +23,7 @@ Sanity check check-config.py
 
   $ cd "$TESTDIR"/..
 
-  $ python contrib/check-config.py < $TESTTMP/files
+  $ $PYTHON contrib/check-config.py < $TESTTMP/files
   undocumented: ui.doesnotexist (str)
   undocumented: ui.missingbool1 (bool) [True]
   undocumented: ui.missingbool2 (bool)
@@ -32,7 +32,7 @@ Sanity check check-config.py
 New errors are not allowed. Warnings are strongly discouraged.
 
   $ hg files "set:(**.py or **.txt) - tests/**" | sed 's|\\|/|g' |
-  >   python contrib/check-config.py
+  >   $PYTHON contrib/check-config.py
               limit = ui.configwith(fraction, 'profiling', 'showmin', 0.05)
   
   conflict on profiling.showmin: ('with', '0.05') != ('with', '0.005')
diff --git a/tests/test-check-help.t b/tests/test-check-help.t
--- a/tests/test-check-help.t
+++ b/tests/test-check-help.t
@@ -24,5 +24,5 @@ Check if ":hg:`help TOPIC`" is valid:
 (use "xargs -n1 -t" to see which help commands are executed)
 
   $ hg files 'glob:{hgdemandimport,hgext,mercurial}/**/*.py' | sed 's|\\|/|g' \
-  > | xargs python "$TESTTMP/scanhelptopics.py" \
+  > | xargs $PYTHON "$TESTTMP/scanhelptopics.py" \
   > | xargs -n1 hg help > /dev/null
diff --git a/tests/test-check-py3-compat.t b/tests/test-check-py3-compat.t
--- a/tests/test-check-py3-compat.t
+++ b/tests/test-check-py3-compat.t
@@ -3,7 +3,7 @@
   $ . "$TESTDIR/helpers-testrepo.sh"
   $ cd "$TESTDIR"/..
 
-  $ hg files 'set:(**.py)' | sed 's|\\|/|g' | xargs python contrib/check-py3-compat.py
+  $ hg files 'set:(**.py)' | sed 's|\\|/|g' | xargs $PYTHON contrib/check-py3-compat.py
   contrib/python-zstandard/setup.py not using absolute_import
   contrib/python-zstandard/setup_zstd.py not using absolute_import
   contrib/python-zstandard/tests/common.py not using absolute_import
diff --git a/tests/test-chg.t b/tests/test-chg.t
--- a/tests/test-chg.t
+++ b/tests/test-chg.t
@@ -89,7 +89,7 @@ enable pager extension globally, but spa
   > [extensions]
   > pager =
   > [pager]
-  > pager = python $TESTTMP/fakepager.py
+  > pager = $PYTHON $TESTTMP/fakepager.py
   > EOF
   $ chg version > /dev/null
   $ touch foo
diff --git a/tests/test-clone-cgi.t b/tests/test-clone-cgi.t
--- a/tests/test-clone-cgi.t
+++ b/tests/test-clone-cgi.t
@@ -27,7 +27,7 @@ try hgweb request
   $ . "$TESTDIR/cgienv"
   $ QUERY_STRING="cmd=changegroup&roots=0000000000000000000000000000000000000000"; export QUERY_STRING
   $ python hgweb.cgi >page1 2>&1
-  $ python "$TESTDIR/md5sum.py" page1
+  $ $PYTHON "$TESTDIR/md5sum.py" page1
   1f424bb22ec05c3c6bc866b6e67efe43  page1
 
 make sure headers are sent even when there is no body
diff --git a/tests/test-clone.t b/tests/test-clone.t
--- a/tests/test-clone.t
+++ b/tests/test-clone.t
@@ -524,7 +524,7 @@ iterable in addbranchrevs()
   > hg.clone(myui, {}, repo, dest="ua")
   > EOF
 
-  $ python simpleclone.py
+  $ $PYTHON simpleclone.py
   updating to branch default
   3 files updated, 0 files merged, 0 files removed, 0 files unresolved
 
@@ -538,7 +538,7 @@ iterable in addbranchrevs()
   > hg.clone(myui, {}, repo, dest="ua", branch=["stable",])
   > EOF
 
-  $ python branchclone.py
+  $ $PYTHON branchclone.py
   adding changesets
   adding manifests
   adding file changes
diff --git a/tests/test-clonebundles.t b/tests/test-clonebundles.t
--- a/tests/test-clonebundles.t
+++ b/tests/test-clonebundles.t
@@ -69,7 +69,7 @@ Server is not running aborts
 
 Server returns 404
 
-  $ python $TESTDIR/dumbhttp.py -p $HGPORT1 --pid http.pid
+  $ $PYTHON $TESTDIR/dumbhttp.py -p $HGPORT1 --pid http.pid
   $ cat http.pid >> $DAEMON_PIDS
   $ hg clone http://localhost:$HGPORT running-404
   applying clone bundle from http://localhost:$HGPORT1/bundle.hg
diff --git a/tests/test-commit-interactive.t b/tests/test-commit-interactive.t
--- a/tests/test-commit-interactive.t
+++ b/tests/test-commit-interactive.t
@@ -909,7 +909,7 @@ This tests that translated help message 
   >     sys.stdout.write(''.join(escape(c) for c in l))
   > EOF
 
-  $ hg commit -i --encoding cp932 2>&1 <<EOF | python $TESTTMP/escape.py | grep '^y - '
+  $ hg commit -i --encoding cp932 2>&1 <<EOF | $PYTHON $TESTTMP/escape.py | grep '^y - '
   > ?
   > q
   > EOF
diff --git a/tests/test-convert-bzr-ghosts.t b/tests/test-convert-bzr-ghosts.t
--- a/tests/test-convert-bzr-ghosts.t
+++ b/tests/test-convert-bzr-ghosts.t
@@ -21,7 +21,7 @@ ghost revisions
   $ bzr add -q somefile
   $ bzr commit -q -m 'Initial layout setup'
   $ echo morecontent >> somefile
-  $ python ../../ghostcreator.py 'Commit with ghost revision' ghostrev
+  $ $PYTHON ../../ghostcreator.py 'Commit with ghost revision' ghostrev
   $ cd ..
   $ hg convert source source-hg
   initializing destination source-hg repository
diff --git a/tests/test-convert-bzr-treeroot.t b/tests/test-convert-bzr-treeroot.t
--- a/tests/test-convert-bzr-treeroot.t
+++ b/tests/test-convert-bzr-treeroot.t
@@ -20,7 +20,7 @@ change the id of the tree root
   $ echo content > file
   $ bzr add -q file
   $ bzr commit -q -m 'Initial add'
-  $ python ../../treeset.py 'Changed root' new
+  $ $PYTHON ../../treeset.py 'Changed root' new
   $ cd ..
   $ hg convert source source-hg
   initializing destination source-hg repository
diff --git a/tests/test-convert-bzr.t b/tests/test-convert-bzr.t
--- a/tests/test-convert-bzr.t
+++ b/tests/test-convert-bzr.t
@@ -129,10 +129,10 @@ merge
   $ bzr branch -q source source-improve
   $ cd source
   $ echo more >> a
-  $ python ../helper.py 'Editing a' 100
+  $ $PYTHON ../helper.py 'Editing a' 100
   $ cd ../source-improve
   $ echo content3 >> b
-  $ python ../helper.py 'Editing b' 200
+  $ $PYTHON ../helper.py 'Editing b' 200
   $ cd ../source
   $ bzr merge -q ../source-improve
   $ bzr commit -q -m 'Merged improve branch'
diff --git a/tests/test-convert-clonebranches.t b/tests/test-convert-clonebranches.t
--- a/tests/test-convert-clonebranches.t
+++ b/tests/test-convert-clonebranches.t
@@ -40,7 +40,7 @@ Miss perl... sometimes
 convert
 
   $ hg convert -v --config convert.hg.clonebranches=1 source dest |
-  >     python filter.py
+  >     $PYTHON filter.py
   3 adda
   2 changea
   1 addb
@@ -73,7 +73,7 @@ Add a merge with both parents and child 
 incremental conversion
 
   $ hg convert -v --config convert.hg.clonebranches=1 source dest |
-  >     python filter.py
+  >     $PYTHON filter.py
   2 c1
   pulling from branch0 into branch1
   4 changesets found
diff --git a/tests/test-convert-hg-source.t b/tests/test-convert-hg-source.t
--- a/tests/test-convert-hg-source.t
+++ b/tests/test-convert-hg-source.t
@@ -130,7 +130,7 @@ check shamap LF and CRLF handling
   >          for i, l in enumerate(file(sys.argv[1]))]
   > file(sys.argv[1], 'wb').write(''.join(lines))
   > EOF
-  $ python rewrite.py new/.hg/shamap
+  $ $PYTHON rewrite.py new/.hg/shamap
   $ cd orig
   $ hg up -qC 1
   $ echo foo >> foo
diff --git a/tests/test-convert-svn-sink.t b/tests/test-convert-svn-sink.t
--- a/tests/test-convert-svn-sink.t
+++ b/tests/test-convert-svn-sink.t
@@ -10,7 +10,7 @@
   >        if [ $2 -gt 0 ]; then
   >            limit="--limit=$2"
   >        fi
-  >        svn log --xml -v $limit | python "$TESTDIR/svnxml.py"
+  >        svn log --xml -v $limit | $PYTHON "$TESTDIR/svnxml.py"
   >     )
   > }
 
diff --git a/tests/test-debugcommands.t b/tests/test-debugcommands.t
--- a/tests/test-debugcommands.t
+++ b/tests/test-debugcommands.t
@@ -142,7 +142,7 @@ Test internal debugstacktrace command
   >     dst('hi ...\\nfrom h hidden in g', 1, depth=2)
   > f()
   > EOF
-  $ python debugstacktrace.py
+  $ $PYTHON debugstacktrace.py
   stacktrace at:
    debugstacktrace.py:10 in * (glob)
    debugstacktrace.py:3  in f
diff --git a/tests/test-diff-binary-file.t b/tests/test-diff-binary-file.t
--- a/tests/test-diff-binary-file.t
+++ b/tests/test-diff-binary-file.t
@@ -83,7 +83,7 @@ Test text mode with extended git-style d
   > path = sys.argv[1]
   > open(path, 'wb').write('\x00\x01\x02\x03')
   > EOF
-  $ python writebin.py binfile.bin
+  $ $PYTHON writebin.py binfile.bin
   $ hg add binfile.bin
   $ hg ci -m 'add binfile.bin'
 
diff --git a/tests/test-eol.t b/tests/test-eol.t
--- a/tests/test-eol.t
+++ b/tests/test-eol.t
@@ -69,7 +69,7 @@ Set up helpers
   >     echo '% a.txt'
   >     cat a.txt
   >     hg diff
-  >     python ../switch-eol.py $1 a.txt
+  >     $PYTHON ../switch-eol.py $1 a.txt
   >     echo '% hg diff only reports a single changed line:'
   >     hg diff
   >     echo "% reverting back to $1 format"
diff --git a/tests/test-fileset-generated.t b/tests/test-fileset-generated.t
--- a/tests/test-fileset-generated.t
+++ b/tests/test-fileset-generated.t
@@ -2,15 +2,15 @@
 
 Set up history and working copy
 
-  $ python $TESTDIR/generate-working-copy-states.py state 2 1
+  $ $PYTHON $TESTDIR/generate-working-copy-states.py state 2 1
   $ hg addremove -q --similarity 0
   $ hg commit -m first
 
-  $ python $TESTDIR/generate-working-copy-states.py state 2 2
+  $ $PYTHON $TESTDIR/generate-working-copy-states.py state 2 2
   $ hg addremove -q --similarity 0
   $ hg commit -m second
 
-  $ python $TESTDIR/generate-working-copy-states.py state 2 wc
+  $ $PYTHON $TESTDIR/generate-working-copy-states.py state 2 wc
   $ hg addremove -q --similarity 0
   $ hg forget *_*_*-untracked
   $ rm *_*_missing-*
diff --git a/tests/test-gendoc.t b/tests/test-gendoc.t
--- a/tests/test-gendoc.t
+++ b/tests/test-gendoc.t
@@ -8,7 +8,7 @@ Test document extraction
   $ { echo C; ls "$TESTDIR/../i18n"/*.po | sort; } | while read PO; do
   >     LOCALE=`basename "$PO" .po`
   >     echo "% extracting documentation from $LOCALE"
-  >     LANGUAGE=$LOCALE python "$TESTDIR/../doc/gendoc.py" >> gendoc-$LOCALE.txt 2> /dev/null || exit
+  >     LANGUAGE=$LOCALE $PYTHON "$TESTDIR/../doc/gendoc.py" >> gendoc-$LOCALE.txt 2> /dev/null || exit
   > 
   >     if [ $LOCALE != C ]; then
   >         if [ ! -f $TESTDIR/test-gendoc-$LOCALE.t ]; then
diff --git a/tests/test-hardlinks.t b/tests/test-hardlinks.t
--- a/tests/test-hardlinks.t
+++ b/tests/test-hardlinks.t
@@ -10,7 +10,7 @@
 
   $ nlinksdir()
   > {
-  >     find "$@" -type f | python $TESTTMP/nlinks.py
+  >     find "$@" -type f | $PYTHON $TESTTMP/nlinks.py
   > }
 
 Some implementations of cp can't create hardlinks (replaces 'cp -al' on Linux):
@@ -23,7 +23,7 @@ Some implementations of cp can't create 
 
   $ linkcp()
   > {
-  >     python $TESTTMP/linkcp.py $1 $2
+  >     $PYTHON $TESTTMP/linkcp.py $1 $2
   > }
 
 Prepare repo r1:
diff --git a/tests/test-help.t b/tests/test-help.t
--- a/tests/test-help.t
+++ b/tests/test-help.t
@@ -1867,7 +1867,7 @@ Compression engines listed in `hg help b
 Test usage of section marks in help documents
 
   $ cd "$TESTDIR"/../doc
-  $ python check-seclevel.py
+  $ $PYTHON check-seclevel.py
   $ cd $TESTTMP
 
 #if serve
diff --git a/tests/test-hgignore.t b/tests/test-hgignore.t
--- a/tests/test-hgignore.t
+++ b/tests/test-hgignore.t
@@ -19,7 +19,7 @@ Issue562: .hgignore requires newline at 
   > f.close()
   > EOF
 
-  $ python makeignore.py
+  $ $PYTHON makeignore.py
 
 Should display baz only:
 
diff --git a/tests/test-hgweb-no-path-info.t b/tests/test-hgweb-no-path-info.t
--- a/tests/test-hgweb-no-path-info.t
+++ b/tests/test-hgweb-no-path-info.t
@@ -70,7 +70,7 @@ should be used from d74fc8dec2b4 onward 
   > env['QUERY_STRING'] = 'style=raw'
   > process(hgwebdir({'repo': '.'}))
   > EOF
-  $ python request.py
+  $ $PYTHON request.py
   ---- STATUS
   200 Script output follows
   ---- HEADERS
diff --git a/tests/test-hgweb-no-request-uri.t b/tests/test-hgweb-no-request-uri.t
--- a/tests/test-hgweb-no-request-uri.t
+++ b/tests/test-hgweb-no-request-uri.t
@@ -81,7 +81,7 @@ should be used from d74fc8dec2b4 onward 
   > env['QUERY_STRING'] = 'style=raw'
   > process(hgwebdir({'repo': '.'}))
   > EOF
-  $ python request.py
+  $ $PYTHON request.py
   ---- STATUS
   200 Script output follows
   ---- HEADERS
diff --git a/tests/test-hgweb-non-interactive.t b/tests/test-hgweb-non-interactive.t
--- a/tests/test-hgweb-non-interactive.t
+++ b/tests/test-hgweb-non-interactive.t
@@ -76,7 +76,7 @@ by the WSGI standard and strictly implem
   > with i._obtainrepo() as repo:
   >     print sorted([x for x in repo.ui.environ if x.startswith('wsgi')])
   > EOF
-  $ python request.py
+  $ $PYTHON request.py
   ---- STATUS
   200 Script output follows
   ---- HEADERS
diff --git a/tests/test-i18n.t b/tests/test-i18n.t
--- a/tests/test-i18n.t
+++ b/tests/test-i18n.t
@@ -45,6 +45,6 @@ Check Mercurial specific translation pro
 tool itself by doctest
 
   $ cd "$TESTDIR"/../i18n
-  $ python check-translation.py *.po
-  $ python check-translation.py --doctest
+  $ $PYTHON check-translation.py *.po
+  $ $PYTHON check-translation.py --doctest
   $ cd $TESTTMP
diff --git a/tests/test-impexp-branch.t b/tests/test-impexp-branch.t
--- a/tests/test-impexp-branch.t
+++ b/tests/test-impexp-branch.t
@@ -30,12 +30,12 @@
   $ hg export 1 > ../r1.patch
   $ cd ..
 
-  $ if python findbranch.py < r0.patch; then
+  $ if $PYTHON findbranch.py < r0.patch; then
   >     echo "Export of default branch revision has Branch header" 1>&2
   >     exit 1
   > fi
 
-  $ if python findbranch.py < r1.patch; then
+  $ if $PYTHON findbranch.py < r1.patch; then
   >     :  # Do nothing
   > else
   >     echo "Export of branch revision is missing Branch header" 1>&2
diff --git a/tests/test-import-context.t b/tests/test-import-context.t
--- a/tests/test-import-context.t
+++ b/tests/test-import-context.t
@@ -26,10 +26,10 @@ Initialize the test repository
 
   $ hg init repo
   $ cd repo
-  $ python ../writepatterns.py a 0 5A 1B 5C 1D
-  $ python ../writepatterns.py b 1 1A 1B
-  $ python ../writepatterns.py c 1 5A
-  $ python ../writepatterns.py d 1 5A 1B
+  $ $PYTHON ../writepatterns.py a 0 5A 1B 5C 1D
+  $ $PYTHON ../writepatterns.py b 1 1A 1B
+  $ $PYTHON ../writepatterns.py c 1 5A
+  $ $PYTHON ../writepatterns.py d 1 5A 1B
   $ hg add
   adding a
   adding b
@@ -114,13 +114,13 @@ Add file, missing a last end of line
 
 What's in a
 
-  $ python ../cat.py a
+  $ $PYTHON ../cat.py a
   'A\nA\nA\nA\nA\nE\nC\nC\nC\nC\nC\nF\nF\n'
-  $ python ../cat.py newnoeol
+  $ $PYTHON ../cat.py newnoeol
   'a\nb'
-  $ python ../cat.py c
+  $ $PYTHON ../cat.py c
   'A\nA\nA\nA\nA\nB\nB\n'
-  $ python ../cat.py d
+  $ $PYTHON ../cat.py d
   'A\nA\nA\nA\n'
 
   $ cd ..
diff --git a/tests/test-import-eol.t b/tests/test-import-eol.t
--- a/tests/test-import-eol.t
+++ b/tests/test-import-eol.t
@@ -29,7 +29,7 @@ Test different --eol values
   $ hg ci -Am adda
   adding .hgignore
   adding a
-  $ python ../makepatch.py
+  $ $PYTHON ../makepatch.py
 
 
 invalid eol
diff --git a/tests/test-import.t b/tests/test-import.t
--- a/tests/test-import.t
+++ b/tests/test-import.t
@@ -64,7 +64,7 @@ regardless of the commit message in the 
   added 1 changesets with 2 changes to 2 files
   updating to branch default
   2 files updated, 0 files merged, 0 files removed, 0 files unresolved
-  $ HGEDITOR=cat hg --config ui.patch='python ../dummypatch.py' --cwd b import --edit ../exported-tip.patch
+  $ HGEDITOR=cat hg --config ui.patch='$PYTHON ../dummypatch.py' --cwd b import --edit ../exported-tip.patch
   applying ../exported-tip.patch
   second change
   
@@ -294,7 +294,7 @@ plain diff in email, subject, message bo
   added 1 changesets with 2 changes to 2 files
   updating to branch default
   2 files updated, 0 files merged, 0 files removed, 0 files unresolved
-  $ python mkmsg.py diffed-tip.patch msg.patch
+  $ $PYTHON mkmsg.py diffed-tip.patch msg.patch
   $ hg --cwd b import ../msg.patch
   applying ../msg.patch
   $ hg --cwd b tip | grep email
@@ -356,7 +356,7 @@ hg export in email, should use patch hea
   added 1 changesets with 2 changes to 2 files
   updating to branch default
   2 files updated, 0 files merged, 0 files removed, 0 files unresolved
-  $ python mkmsg.py exported-tip.patch msg.patch
+  $ $PYTHON mkmsg.py exported-tip.patch msg.patch
   $ cat msg.patch | hg --cwd b import -
   applying patch from stdin
   $ hg --cwd b tip | grep second
@@ -387,7 +387,7 @@ plain diff in email, [PATCH] subject, me
   added 1 changesets with 2 changes to 2 files
   updating to branch default
   2 files updated, 0 files merged, 0 files removed, 0 files unresolved
-  $ python mkmsg2.py diffed-tip.patch msg.patch
+  $ $PYTHON mkmsg2.py diffed-tip.patch msg.patch
   $ cat msg.patch | hg --cwd b import -
   applying patch from stdin
   $ hg --cwd b tip --template '{desc}\n'
diff --git a/tests/test-imports-checker.t b/tests/test-imports-checker.t
--- a/tests/test-imports-checker.t
+++ b/tests/test-imports-checker.t
@@ -124,7 +124,7 @@ Run additional tests for the import chec
   > from mercurial.node import hex
   > EOF
 
-  $ python "$import_checker" testpackage*/*.py testpackage/subpackage/*.py
+  $ $PYTHON "$import_checker" testpackage*/*.py testpackage/subpackage/*.py
   testpackage/importalias.py:2: ui module must be "as" aliased to uimod
   testpackage/importfromalias.py:2: ui from testpackage must be "as" aliased to uimod
   testpackage/importfromrelative.py:2: import should be relative: testpackage.unsorted
diff --git a/tests/test-inherit-mode.t b/tests/test-inherit-mode.t
--- a/tests/test-inherit-mode.t
+++ b/tests/test-inherit-mode.t
@@ -45,7 +45,7 @@ before commit
 store can be written by the group, other files cannot
 store is setgid
 
-  $ python ../printmodes.py .
+  $ $PYTHON ../printmodes.py .
   00700 ./.hg/
   00600 ./.hg/00changelog.i
   00600 ./.hg/requires
@@ -61,7 +61,7 @@ files created in .hg can be written by t
 (in particular, store/**, dirstate, branch cache file, undo files)
 new directories are setgid
 
-  $ python ../printmodes.py .
+  $ $PYTHON ../printmodes.py .
   00700 ./.hg/
   00600 ./.hg/00changelog.i
   00770 ./.hg/cache/
@@ -98,7 +98,7 @@ new directories are setgid
 before push
 group can write everything
 
-  $ python ../printmodes.py ../push
+  $ $PYTHON ../printmodes.py ../push
   00770 ../push/.hg/
   00660 ../push/.hg/00changelog.i
   00660 ../push/.hg/requires
@@ -110,7 +110,7 @@ group can write everything
 after push
 group can still write everything
 
-  $ python ../printmodes.py ../push
+  $ $PYTHON ../printmodes.py ../push
   00770 ../push/.hg/
   00660 ../push/.hg/00changelog.i
   00770 ../push/.hg/cache/
@@ -146,8 +146,8 @@ just check that directories have the sam
   $ mkdir dir
   $ touch dir/file
   $ hg ci -qAm 'add dir/file'
-  $ storemode=`python ../mode.py .hg/store`
-  $ dirmode=`python ../mode.py .hg/store/data/dir`
+  $ storemode=`$PYTHON ../mode.py .hg/store`
+  $ dirmode=`$PYTHON ../mode.py .hg/store/data/dir`
   $ if [ "$storemode" != "$dirmode" ]; then
   >  echo "$storemode != $dirmode"
   > fi
diff --git a/tests/test-install.t b/tests/test-install.t
--- a/tests/test-install.t
+++ b/tests/test-install.t
@@ -159,7 +159,7 @@ path variables are expanded (~ is the sa
   >     print('  %s' % f)
   > EOF
 
-  $ python wixxml.py help
+  $ $PYTHON wixxml.py help
   Not installed:
     help/common.txt
     help/hg-ssh.8.txt
@@ -168,7 +168,7 @@ path variables are expanded (~ is the sa
     help/hgrc.5.txt
   Not tracked:
 
-  $ python wixxml.py templates
+  $ $PYTHON wixxml.py templates
   Not installed:
   Not tracked:
 
diff --git a/tests/test-issue4074.t b/tests/test-issue4074.t
--- a/tests/test-issue4074.t
+++ b/tests/test-issue4074.t
@@ -16,12 +16,12 @@ A script to generate nasty diff worst-ca
 
 Check in a big file:
 
-  $ python ../s.py > a
+  $ $PYTHON ../s.py > a
   $ hg ci -qAm0
 
 Modify it:
 
-  $ python ../s.py > a
+  $ $PYTHON ../s.py > a
 
 Time a check-in, should never take more than 10 seconds user time:
 
diff --git a/tests/test-mactext.t b/tests/test-mactext.t
--- a/tests/test-mactext.t
+++ b/tests/test-mactext.t
@@ -24,7 +24,7 @@
   $ hg add f
   $ hg ci -m 1
 
-  $ python unix2mac.py f
+  $ $PYTHON unix2mac.py f
   $ hg ci -m 2
   attempt to commit or push text file(s) using CR line endings
   in dea860dc51ec: f
@@ -32,7 +32,7 @@
   rollback completed
   abort: pretxncommit.cr hook failed
   [255]
-  $ hg cat f | python print.py
+  $ hg cat f | $PYTHON print.py
   hello<LF>
-  $ cat f | python print.py
+  $ cat f | $PYTHON print.py
   hello<CR>
diff --git a/tests/test-merge-force.t b/tests/test-merge-force.t
--- a/tests/test-merge-force.t
+++ b/tests/test-merge-force.t
@@ -10,26 +10,26 @@ remote content, then finally forgotten.
 
 Create base changeset
 
-  $ python $TESTDIR/generate-working-copy-states.py state 3 1
+  $ $PYTHON $TESTDIR/generate-working-copy-states.py state 3 1
   $ hg addremove -q --similarity 0
   $ hg commit -qm 'base'
 
 Create remote changeset
 
-  $ python $TESTDIR/generate-working-copy-states.py state 3 2
+  $ $PYTHON $TESTDIR/generate-working-copy-states.py state 3 2
   $ hg addremove -q --similarity 0
   $ hg commit -qm 'remote'
 
 Create local changeset
 
   $ hg update -q 0
-  $ python $TESTDIR/generate-working-copy-states.py state 3 3
+  $ $PYTHON $TESTDIR/generate-working-copy-states.py state 3 3
   $ hg addremove -q --similarity 0
   $ hg commit -qm 'local'
 
 Set up working directory
 
-  $ python $TESTDIR/generate-working-copy-states.py state 3 wc
+  $ $PYTHON $TESTDIR/generate-working-copy-states.py state 3 wc
   $ hg addremove -q --similarity 0
   $ hg forget *_*_*_*-untracked
   $ rm *_*_*_missing-*
@@ -286,7 +286,7 @@ missing_missing_content3_missing-tracked
 the remote side did not touch the file
 
   $ checkstatus() {
-  >   for f in `python $TESTDIR/generate-working-copy-states.py filelist 3`
+  >   for f in `$PYTHON $TESTDIR/generate-working-copy-states.py filelist 3`
   >   do
   >     echo
   >     hg status -A $f
@@ -667,7 +667,7 @@ the remote side did not touch the file
   missing_missing_missing_missing-untracked: * (glob)
   <missing>
 
-  $ for f in `python $TESTDIR/generate-working-copy-states.py filelist 3`
+  $ for f in `$PYTHON $TESTDIR/generate-working-copy-states.py filelist 3`
   > do
   >   if test -f ${f}.orig
   >   then
@@ -784,7 +784,7 @@ Set up working directory again
 
   $ hg -q update --clean 2
   $ hg --config extensions.purge= purge
-  $ python $TESTDIR/generate-working-copy-states.py state 3 wc
+  $ $PYTHON $TESTDIR/generate-working-copy-states.py state 3 wc
   $ hg addremove -q --similarity 0
   $ hg forget *_*_*_*-untracked
   $ rm *_*_*_missing-*
diff --git a/tests/test-merge-symlinks.t b/tests/test-merge-symlinks.t
--- a/tests/test-merge-symlinks.t
+++ b/tests/test-merge-symlinks.t
@@ -36,7 +36,7 @@ a file, once as a link. Bundle was gener
 Merge them and display *_ISLINK vars
 merge heads
 
-  $ hg merge --tool="python ../echo.py"
+  $ hg merge --tool="$PYTHON ../echo.py"
   merging l
   HG_FILE l
   HG_MY_ISLINK 1
@@ -52,7 +52,7 @@ merge working directory
   $ hg up -C 2
   1 files updated, 0 files merged, 1 files removed, 0 files unresolved
   $ hg copy l l2
-  $ HGMERGE="python ../echo.py" hg up 3
+  $ HGMERGE="$PYTHON ../echo.py" hg up 3
   merging l2
   HG_FILE l2
   HG_MY_ISLINK 1
diff --git a/tests/test-mq-eol.t b/tests/test-mq-eol.t
--- a/tests/test-mq-eol.t
+++ b/tests/test-mq-eol.t
@@ -48,7 +48,7 @@ Test different --eol values
   $ hg ci -Am adda
   adding .hgignore
   adding a
-  $ python ../makepatch.py
+  $ $PYTHON ../makepatch.py
   $ hg qimport eol.diff
   adding eol.diff to series file
 
@@ -85,7 +85,7 @@ force LF
   applying eol.diff
   now at: eol.diff
   $ hg qrefresh
-  $ python ../cateol.py .hg/patches/eol.diff
+  $ $PYTHON ../cateol.py .hg/patches/eol.diff
   # HG changeset patch<LF>
   # Parent  0d0bf99a8b7a3842c6f8ef09e34f69156c4bd9d0<LF>
   test message<LF>
@@ -106,7 +106,7 @@ force LF
   +d<CR><LF>
   +z<LF>
   \ No newline at end of file<LF>
-  $ python ../cateol.py a
+  $ $PYTHON ../cateol.py a
   a<CR><LF>
   y<CR><LF>
   c<CR><LF>
@@ -121,7 +121,7 @@ push again forcing LF and compare revisi
   $ hg --config patch.eol='CRLF' qpush
   applying eol.diff
   now at: eol.diff
-  $ python ../cateol.py a
+  $ $PYTHON ../cateol.py a
   a<CR><LF>
   y<CR><LF>
   c<CR><LF>
@@ -136,7 +136,7 @@ push again without LF and compare revisi
   $ hg qpush
   applying eol.diff
   now at: eol.diff
-  $ python ../cateol.py a
+  $ $PYTHON ../cateol.py a
   a<CR><LF>
   y<CR><LF>
   c<CR><LF>
diff --git a/tests/test-mq-missingfiles.t b/tests/test-mq-missingfiles.t
--- a/tests/test-mq-missingfiles.t
+++ b/tests/test-mq-missingfiles.t
@@ -23,11 +23,11 @@ future qrefresh.
 
   $ hg init normal
   $ cd normal
-  $ python ../writelines.py b 10 'a\n'
+  $ $PYTHON ../writelines.py b 10 'a\n'
   $ hg ci -Am addb
   adding b
   $ echo a > a
-  $ python ../writelines.py b 2 'b\n' 10 'a\n' 2 'c\n'
+  $ $PYTHON ../writelines.py b 2 'b\n' 10 'a\n' 2 'c\n'
   $ echo c > c
   $ hg add a c
   $ hg qnew -f changeb
@@ -82,7 +82,7 @@ Test missing renamed file
   $ hg up -qC 0
   $ echo a > a
   $ hg mv b bb
-  $ python ../writelines.py bb 2 'b\n' 10 'a\n' 2 'c\n'
+  $ $PYTHON ../writelines.py bb 2 'b\n' 10 'a\n' 2 'c\n'
   $ echo c > c
   $ hg add a c
   $ hg qnew changebb
@@ -129,11 +129,11 @@ Test missing renamed file
 
   $ hg init git
   $ cd git
-  $ python ../writelines.py b 1 '\x00'
+  $ $PYTHON ../writelines.py b 1 '\x00'
   $ hg ci -Am addb
   adding b
   $ echo a > a
-  $ python ../writelines.py b 1 '\x01' 1 '\x00'
+  $ $PYTHON ../writelines.py b 1 '\x01' 1 '\x00'
   $ echo c > c
   $ hg add a c
   $ hg qnew -f changeb
diff --git a/tests/test-mq-qimport.t b/tests/test-mq-qimport.t
--- a/tests/test-mq-qimport.t
+++ b/tests/test-mq-qimport.t
@@ -151,10 +151,10 @@ qimport -f
 
 build diff with CRLF
 
-  $ python ../writelines.py b 5 'a\n' 5 'a\r\n'
+  $ $PYTHON ../writelines.py b 5 'a\n' 5 'a\r\n'
   $ hg ci -Am addb
   adding b
-  $ python ../writelines.py b 2 'a\n' 10 'b\n' 2 'a\r\n'
+  $ $PYTHON ../writelines.py b 2 'a\n' 10 'b\n' 2 'a\r\n'
   $ hg diff > b.diff
   $ hg up -C
   1 files updated, 0 files merged, 0 files removed, 0 files unresolved
diff --git a/tests/test-mq.t b/tests/test-mq.t
--- a/tests/test-mq.t
+++ b/tests/test-mq.t
@@ -1137,9 +1137,9 @@ create a git binary patch
   > path = sys.argv[1]
   > open(path, 'wb').write('BIN\x00ARY')
   > EOF
-  $ python writebin.py bucephalus
+  $ $PYTHON writebin.py bucephalus
 
-  $ python "$TESTDIR/md5sum.py" bucephalus
+  $ $PYTHON "$TESTDIR/md5sum.py" bucephalus
   8ba2a2f3e77b55d03051ff9c24ad65e7  bucephalus
   $ hg add bucephalus
   $ hg qnew -f --git addbucephalus
@@ -1158,7 +1158,7 @@ check binary patches can be popped and p
   applying addbucephalus
   now at: addbucephalus
   $ test -f bucephalus
-  $ python "$TESTDIR/md5sum.py" bucephalus
+  $ $PYTHON "$TESTDIR/md5sum.py" bucephalus
   8ba2a2f3e77b55d03051ff9c24ad65e7  bucephalus
 
 
diff --git a/tests/test-pager-legacy.t b/tests/test-pager-legacy.t
--- a/tests/test-pager-legacy.t
+++ b/tests/test-pager-legacy.t
@@ -14,7 +14,7 @@ pager was running.
   > [extensions]
   > pager=
   > [pager]
-  > pager = python $TESTTMP/fakepager.py
+  > pager = $PYTHON $TESTTMP/fakepager.py
   > EOF
 
   $ hg init repo
@@ -22,7 +22,7 @@ pager was running.
   $ echo a >> a
   $ hg add a
   $ hg ci -m 'add a'
-  $ for x in `python $TESTDIR/seq.py 1 10`; do
+  $ for x in `$PYTHON $TESTDIR/seq.py 1 10`; do
   >   echo a $x >> a
   >   hg ci -m "modify a $x"
   > done
diff --git a/tests/test-pager.t b/tests/test-pager.t
--- a/tests/test-pager.t
+++ b/tests/test-pager.t
@@ -16,7 +16,7 @@ pager was running.
   > formatted = yes
   > color = no
   > [pager]
-  > pager = python $TESTTMP/fakepager.py
+  > pager = $PYTHON $TESTTMP/fakepager.py
   > EOF
 
   $ hg init repo
@@ -24,7 +24,7 @@ pager was running.
   $ echo a >> a
   $ hg add a
   $ hg ci -m 'add a'
-  $ for x in `python $TESTDIR/seq.py 1 10`; do
+  $ for x in `$PYTHON $TESTDIR/seq.py 1 10`; do
   >   echo a $x >> a
   >   hg ci -m "modify a $x"
   > done
diff --git a/tests/test-parseindex.t b/tests/test-parseindex.t
--- a/tests/test-parseindex.t
+++ b/tests/test-parseindex.t
@@ -53,7 +53,7 @@ We approximate that by reducing the read
   > for r in cl:
   >     print short(cl.node(r))
   > EOF
-  $ python test.py
+  $ $PYTHON test.py
   2 revisions:
   7c31755bf9b5
   26333235a41c
@@ -167,13 +167,13 @@ Test corrupted p1/p2 fields that could c
   >         print inst
   > EOF
 
-  $ python test.py limit/.hg/store
+  $ $PYTHON test.py limit/.hg/store
   reachableroots: parent out of range
   compute_phases_map_sets: parent out of range
   index_headrevs: parent out of range
   find_gca_candidates: parent out of range
   find_deepest: parent out of range
-  $ python test.py segv/.hg/store
+  $ $PYTHON test.py segv/.hg/store
   reachableroots: parent out of range
   compute_phases_map_sets: parent out of range
   index_headrevs: parent out of range
diff --git a/tests/test-patch-offset.t b/tests/test-patch-offset.t
--- a/tests/test-patch-offset.t
+++ b/tests/test-patch-offset.t
@@ -23,7 +23,7 @@ the patch.  So all the patch hunks need 
 within this file.  If the offset isn't tracked then the hunks can be
 applied to the wrong lines of this file.
 
-  $ python ../writepatterns.py a 34X 10A 1B 10A 1C 10A 1B 10A 1D 10A 1B 10A 1E 10A 1B 10A
+  $ $PYTHON ../writepatterns.py a 34X 10A 1B 10A 1C 10A 1B 10A 1D 10A 1B 10A 1E 10A 1B 10A
   $ hg commit -Am adda
   adding a
 
@@ -76,7 +76,7 @@ import patch
 
 compare imported changes against reference file
 
-  $ python ../writepatterns.py aref 34X 10A 1B 1a 9A 1C 10A 1B 10A 1D 10A 1B 1a 9A 1E 10A 1B 1a 9A
+  $ $PYTHON ../writepatterns.py aref 34X 10A 1B 1a 9A 1C 10A 1B 10A 1D 10A 1B 1a 9A 1E 10A 1B 1a 9A
   $ diff aref a
 
   $ cd ..
diff --git a/tests/test-patch.t b/tests/test-patch.t
--- a/tests/test-patch.t
+++ b/tests/test-patch.t
@@ -6,7 +6,7 @@
   > EOF
 
   $ echo "[ui]" >> $HGRCPATH
-  $ echo "patch=python ../patchtool.py" >> $HGRCPATH
+  $ echo "patch=$PYTHON ../patchtool.py" >> $HGRCPATH
 
   $ hg init a
   $ cd a
diff --git a/tests/test-patchbomb-tls.t b/tests/test-patchbomb-tls.t
--- a/tests/test-patchbomb-tls.t
+++ b/tests/test-patchbomb-tls.t
@@ -5,7 +5,7 @@ Set up SMTP server:
   $ CERTSDIR="$TESTDIR/sslcerts"
   $ cat "$CERTSDIR/priv.pem" "$CERTSDIR/pub.pem" >> server.pem
 
-  $ python "$TESTDIR/dummysmtpd.py" -p $HGPORT --pid-file a.pid -d \
+  $ $PYTHON "$TESTDIR/dummysmtpd.py" -p $HGPORT --pid-file a.pid -d \
   > --tls smtps --certificate `pwd`/server.pem
   listening at localhost:$HGPORT (?)
   $ cat a.pid >> $DAEMON_PIDS
diff --git a/tests/test-patchbomb.t b/tests/test-patchbomb.t
--- a/tests/test-patchbomb.t
+++ b/tests/test-patchbomb.t
@@ -22,7 +22,7 @@ Mercurial-patchbomb/.* -> Mercurial-patc
   >     skipblank = False
   >     print l,
   > EOF
-  $ FILTERBOUNDARY="python `pwd`/prune-blank-after-boundary.py"
+  $ FILTERBOUNDARY="$PYTHON `pwd`/prune-blank-after-boundary.py"
   $ echo "[format]" >> $HGRCPATH
   $ echo "usegeneraldelta=yes" >> $HGRCPATH
   $ echo "[extensions]" >> $HGRCPATH
diff --git a/tests/test-push-warn.t b/tests/test-push-warn.t
--- a/tests/test-push-warn.t
+++ b/tests/test-push-warn.t
@@ -418,7 +418,7 @@ multiple new heads but also doesn't repo
   adding c
   created new head
 
-  $ for i in `python $TESTDIR/seq.py 3`; do hg -R h up -q 0; echo $i > h/b; hg -R h ci -qAm$i; done
+  $ for i in `$PYTHON $TESTDIR/seq.py 3`; do hg -R h up -q 0; echo $i > h/b; hg -R h ci -qAm$i; done
 
   $ hg -R i push h
   pushing to h
diff --git a/tests/test-relink.t b/tests/test-relink.t
--- a/tests/test-relink.t
+++ b/tests/test-relink.t
@@ -93,8 +93,8 @@ relink
 
 check hardlinks
 
-  $ python arelinked.py repo/.hg/store/data/a.i clone/.hg/store/data/a.i
+  $ $PYTHON arelinked.py repo/.hg/store/data/a.i clone/.hg/store/data/a.i
   repo/.hg/store/data/a.i == clone/.hg/store/data/a.i
-  $ python arelinked.py repo/.hg/store/data/b.i clone/.hg/store/data/b.i
+  $ $PYTHON arelinked.py repo/.hg/store/data/b.i clone/.hg/store/data/b.i
   repo/.hg/store/data/b.i != clone/.hg/store/data/b.i
 
diff --git a/tests/test-repair-strip.t b/tests/test-repair-strip.t
--- a/tests/test-repair-strip.t
+++ b/tests/test-repair-strip.t
@@ -21,7 +21,7 @@
   >   hg verify
   >   echo % journal contents
   >   if [ -f .hg/store/journal ]; then
-  >       cat .hg/store/journal | python $TESTTMP/dumpjournal.py
+  >       cat .hg/store/journal | $PYTHON $TESTTMP/dumpjournal.py
   >   else
   >       echo "(no journal)"
   >   fi
diff --git a/tests/test-revert.t b/tests/test-revert.t
--- a/tests/test-revert.t
+++ b/tests/test-revert.t
@@ -495,7 +495,7 @@ Write the python script to disk
 
 check list of planned files
 
-  $ python $TESTDIR/generate-working-copy-states.py filelist 2
+  $ $PYTHON $TESTDIR/generate-working-copy-states.py filelist 2
   content1_content1_content1-tracked
   content1_content1_content1-untracked
   content1_content1_content3-tracked
@@ -550,7 +550,7 @@ Generate appropriate repo state
 
 Generate base changeset
 
-  $ python $TESTDIR/generate-working-copy-states.py state 2 1
+  $ $PYTHON $TESTDIR/generate-working-copy-states.py state 2 1
   $ hg addremove --similarity 0
   adding content1_content1_content1-tracked
   adding content1_content1_content1-untracked
@@ -597,7 +597,7 @@ Generate base changeset
 
 (create a simple text version of the content)
 
-  $ python ../dircontent.py > ../content-base.txt
+  $ $PYTHON ../dircontent.py > ../content-base.txt
   $ cat ../content-base.txt
   content1 content1_content1_content1-tracked
   content1 content1_content1_content1-untracked
@@ -622,7 +622,7 @@ Generate base changeset
 
 Create parent changeset
 
-  $ python $TESTDIR/generate-working-copy-states.py state 2 2
+  $ $PYTHON $TESTDIR/generate-working-copy-states.py state 2 2
   $ hg addremove --similarity 0
   removing content1_missing_content1-tracked
   removing content1_missing_content1-untracked
@@ -661,7 +661,7 @@ Create parent changeset
 
 (create a simple text version of the content)
 
-  $ python ../dircontent.py > ../content-parent.txt
+  $ $PYTHON ../dircontent.py > ../content-parent.txt
   $ cat ../content-parent.txt
   content1 content1_content1_content1-tracked
   content1 content1_content1_content1-untracked
@@ -686,7 +686,7 @@ Create parent changeset
 
 Setup working directory
 
-  $ python $TESTDIR/generate-working-copy-states.py state 2 wc
+  $ $PYTHON $TESTDIR/generate-working-copy-states.py state 2 wc
   $ hg addremove --similarity 0
   adding content1_missing_content1-tracked
   adding content1_missing_content1-untracked
@@ -754,7 +754,7 @@ Setup working directory
 
 (create a simple text version of the content)
 
-  $ python ../dircontent.py > ../content-wc.txt
+  $ $PYTHON ../dircontent.py > ../content-wc.txt
   $ cat ../content-wc.txt
   content1 content1_content1_content1-tracked
   content1 content1_content1_content1-untracked
@@ -818,7 +818,7 @@ Compare resulting directory with revert 
 The diff is filtered to include change only. The only difference should be
 additional `.orig` backup file when applicable.
 
-  $ python ../dircontent.py > ../content-parent-all.txt
+  $ $PYTHON ../dircontent.py > ../content-parent-all.txt
   $ cd ..
   $ diff -U 0 -- content-parent.txt content-parent-all.txt | grep _
   +content3 content1_content1_content3-tracked.orig
@@ -875,7 +875,7 @@ Compare resulting directory with revert 
 The diff is filtered to include change only. The only difference should be
 additional `.orig` backup file when applicable.
 
-  $ python ../dircontent.py > ../content-base-all.txt
+  $ $PYTHON ../dircontent.py > ../content-base-all.txt
   $ cd ..
   $ diff -U 0 -- content-base.txt content-base-all.txt | grep _
   +content3 content1_content1_content3-tracked.orig
@@ -902,7 +902,7 @@ Test revert to parent content with expli
 revert all files individually and check the output
 (output is expected to be different than in the --all case)
 
-  $ for file in `python $TESTDIR/generate-working-copy-states.py filelist 2`; do
+  $ for file in `$PYTHON $TESTDIR/generate-working-copy-states.py filelist 2`; do
   >   echo '### revert for:' $file;
   >   hg revert $file;
   >   echo
@@ -979,7 +979,7 @@ revert all files individually and check 
 check resulting directory against the --all run
 (There should be no difference)
 
-  $ python ../dircontent.py > ../content-parent-explicit.txt
+  $ $PYTHON ../dircontent.py > ../content-parent-explicit.txt
   $ cd ..
   $ diff -U 0 -- content-parent-all.txt content-parent-explicit.txt | grep _
   [1]
@@ -995,7 +995,7 @@ Test revert to "base" content with expli
 revert all files individually and check the output
 (output is expected to be different than in the --all case)
 
-  $ for file in `python $TESTDIR/generate-working-copy-states.py filelist 2`; do
+  $ for file in `$PYTHON $TESTDIR/generate-working-copy-states.py filelist 2`; do
   >   echo '### revert for:' $file;
   >   hg revert $file --rev 'desc(base)';
   >   echo
@@ -1072,7 +1072,7 @@ revert all files individually and check 
 check resulting directory against the --all run
 (There should be no difference)
 
-  $ python ../dircontent.py > ../content-base-explicit.txt
+  $ $PYTHON ../dircontent.py > ../content-base-explicit.txt
   $ cd ..
   $ diff -U 0 -- content-base-all.txt content-base-explicit.txt | grep _
   [1]
diff --git a/tests/test-setdiscovery.t b/tests/test-setdiscovery.t
--- a/tests/test-setdiscovery.t
+++ b/tests/test-setdiscovery.t
@@ -363,9 +363,9 @@ Issue 4438 - test coverage for 3ef893520
 #if false
 generate new bundles:
   $ hg init r1
-  $ for i in `python $TESTDIR/seq.py 101`; do hg -R r1 up -qr null && hg -R r1 branch -q b$i && hg -R r1 ci -qmb$i; done
+  $ for i in `$PYTHON $TESTDIR/seq.py 101`; do hg -R r1 up -qr null && hg -R r1 branch -q b$i && hg -R r1 ci -qmb$i; done
   $ hg clone -q r1 r2
-  $ for i in `python $TESTDIR/seq.py 10`; do hg -R r1 up -qr null && hg -R r1 branch -q c$i && hg -R r1 ci -qmc$i; done
+  $ for i in `$PYTHON $TESTDIR/seq.py 10`; do hg -R r1 up -qr null && hg -R r1 branch -q c$i && hg -R r1 ci -qmc$i; done
   $ hg -R r2 branch -q r2change && hg -R r2 ci -qmr2change
   $ hg -R r1 bundle -qa $TESTDIR/bundles/issue4438-r1.hg
   $ hg -R r2 bundle -qa $TESTDIR/bundles/issue4438-r2.hg
diff --git a/tests/test-simple-update.t b/tests/test-simple-update.t
--- a/tests/test-simple-update.t
+++ b/tests/test-simple-update.t
@@ -77,7 +77,7 @@ update with worker processes
   > [worker]
   > numcpus = 4
   > EOF
-  $ for i in `python $TESTDIR/seq.py 1 100`; do
+  $ for i in `$PYTHON $TESTDIR/seq.py 1 100`; do
   >   echo $i > $i
   > done
   $ hg ci -qAm 'add 100 files'
diff --git a/tests/test-static-http.t b/tests/test-static-http.t
--- a/tests/test-static-http.t
+++ b/tests/test-static-http.t
@@ -9,7 +9,7 @@
 This server doesn't do range requests so it's basically only good for
 one pull
 
-  $ python "$TESTDIR/dumbhttp.py" -p $HGPORT --pid dumb.pid
+  $ $PYTHON "$TESTDIR/dumbhttp.py" -p $HGPORT --pid dumb.pid
   $ cat dumb.pid >> $DAEMON_PIDS
   $ hg init remote
   $ cd remote
diff --git a/tests/test-status-rev.t b/tests/test-status-rev.t
--- a/tests/test-status-rev.t
+++ b/tests/test-status-rev.t
@@ -5,7 +5,7 @@ combined correctly with the dirstate sta
 
 First commit
 
-  $ python $TESTDIR/generate-working-copy-states.py state 2 1
+  $ $PYTHON $TESTDIR/generate-working-copy-states.py state 2 1
   $ hg addremove --similarity 0
   adding content1_content1_content1-tracked
   adding content1_content1_content1-untracked
@@ -31,7 +31,7 @@ First commit
 
 Second commit
 
-  $ python $TESTDIR/generate-working-copy-states.py state 2 2
+  $ $PYTHON $TESTDIR/generate-working-copy-states.py state 2 2
   $ hg addremove --similarity 0
   removing content1_missing_content1-tracked
   removing content1_missing_content1-untracked
@@ -49,7 +49,7 @@ Second commit
 
 Working copy
 
-  $ python $TESTDIR/generate-working-copy-states.py state 2 wc
+  $ $PYTHON $TESTDIR/generate-working-copy-states.py state 2 wc
   $ hg addremove --similarity 0
   adding content1_missing_content1-tracked
   adding content1_missing_content1-untracked
diff --git a/tests/test-tools.t b/tests/test-tools.t
--- a/tests/test-tools.t
+++ b/tests/test-tools.t
@@ -44,10 +44,10 @@ Tests of the file helper tool
 #endif
 
 #if no-windows
-  $ python $TESTDIR/seq.py 10 > bar
+  $ $PYTHON $TESTDIR/seq.py 10 > bar
 #else
 Convert CRLF -> LF for consistency
-  $ python $TESTDIR/seq.py 10 | sed "s/$//" > bar
+  $ $PYTHON $TESTDIR/seq.py 10 | sed "s/$//" > bar
 #endif
 
 #if unix-permissions symlink
diff --git a/tests/test-win32text.t b/tests/test-win32text.t
--- a/tests/test-win32text.t
+++ b/tests/test-win32text.t
@@ -28,7 +28,7 @@ commit should succeed
   updating to branch default
   1 files updated, 0 files merged, 0 files removed, 0 files unresolved
   $ cp .hg/hgrc ../zoz/.hg
-  $ python unix2dos.py f
+  $ $PYTHON unix2dos.py f
 
 commit should fail
 
@@ -102,7 +102,7 @@ and now for something completely differe
 
   $ mkdir d
   $ echo hello > d/f2
-  $ python unix2dos.py d/f2
+  $ $PYTHON unix2dos.py d/f2
   $ hg add d/f2
   $ hg ci -m 3
   attempt to commit or push text file(s) using CRLF line endings
@@ -181,7 +181,7 @@ and now for something completely differe
   adding dupe/b (glob)
   adding dupe/c (glob)
   adding dupe/d (glob)
-  $ python unix2dos.py dupe/b dupe/c dupe/d
+  $ $PYTHON unix2dos.py dupe/b dupe/c dupe/d
   $ hg -R dupe ci -m a dupe/a
   $ hg -R dupe ci -m b/c dupe/[bc]
   $ hg -R dupe ci -m d dupe/d