I finally found a solution to have Python command use the venv of the project when calling them from Make.
Use .ONESHELL and a macro¶
By default, make runs each line of a recipe in a different subshell. .ONESHELL makes make run a whole recipe in a single shell.
The alternative is to activate the venv with every single python command, eg.: . venv/bin/activate && pip install -r requirements.txt.
.ONESHELL:
VENV_DIR=.venv
ACTIVATE_VENV:=. $(VENV_DIR)/bin/activate
install: 
    python3 -m venv "$(VENV_DIR)"
    $(ACTIVATE_VENV)
    pip install --upgrade --requirement requirements.txt
run: install
    $(ACTIVATE_VENV)
    python foo.my
Sources
- stackoverflow: effect and usage of .ONESHELL
- stackoverflow: using a macro to factor activation code
Tracking requirements.txt changes¶
The above can be combined with appropriate makefile usage as to prime venv only once, and then track changes to requirements.txt.
# use .ONESHELL to activate venv and use it across a recipe without adding it before each command (source: https://stackoverflow.com/a/55404948)
.ONESHELL:
VENV_DIR=.venv
# source: https://stackoverflow.com/a/73837995
ACTIVATE_VENV:=. $(VENV_DIR)/bin/activate
$(VENV_DIR)/touchfile: requirements.txt
    test -d "$(VENV_DIR)" || python3 -m venv "$(VENV_DIR)"
    $(ACTIVATE_VENV)
    pip install --upgrade --requirement requirements.txt
    touch "$(VENV_DIR)/touchfile"
venv: $(VENV_DIR)/touchfile
venvclean:
    rm -rf $(VENV_DIR)
Sources
- stackoverflow: using a touch file