Assuming that you just want to capture the output, the most efficient invocation should be:
cp = subprocess.run(["wsl", "-e", "date"], capture_output=True)
date = cp.stdout
By specifying -e, you skip the shell entirely, which avoids the overhead of the shell starting up.
If you really do want to force it to run within fish:
cp = subprocess.run(["wsl", "-e", "fish", "-c", "date"], capture_output=True)
date = cp.stdout
More detail:
If fish is your default shell, then you really don't need to specify it as an argument to the wsl command. You can see this by trying the following in PowerShell or CMD:
wsl ps -eH
PID TTY TIME CMD
1 ? 00:00:00 init
21 ? 00:00:00 init
22 ? 00:00:00 init
23 pts/0 00:00:00 fish
30 pts/0 00:00:00 ps
Note that the ps command, although run without fish on the WSL command-line, still runs under the default shell.
However, you don't have to. If a command doesn't need the shell, you can run it directly without going through a shell (avoids overhead) via:
wsl -e ps -ef
PID TTY TIME CMD
1 ? 00:00:00 init
11 ? 00:00:00 init
12 ? 00:00:00 init
13 pts/0 00:00:00 ps
You'll notice that no shell is running. This is the variation I recommended above with the ["wsl","-e","date"] in Python.
Let's say that fish isn't your default shell, and yet you do want it to run.
wsl -e fish -c "ps -eH"
PID TTY TIME CMD
1 ? 00:00:00 init
20 ? 00:00:00 init
21 ? 00:00:00 init
22 pts/0 00:00:00 fish
29 pts/0 00:00:00 ps
But don't do wsl fish "ps -eH" (or wsl fish -c date). That will run fish within fish, which is very wasteful:
PID TTY TIME CMD
1 ? 00:00:00 init
11 ? 00:00:00 init
12 ? 00:00:00 init
13 pts/0 00:00:00 fish
20 pts/0 00:00:00 fish
22 pts/0 00:00:00 ps