Search code examples
pythonpiptox

tox refuses to use deps setting in py38 and various pip problems


I have a Django project that i'm trying to set up unit testing with tox in.
here is the directory structure:

+ djangoProject
|
+-.github
+-.pytest
+-.tox
+- api
+- blog
+- djangoProject
+- templates
|
+ .gitignore
+ manage.py
+ pyproject.toml
+ requirements.txt
+ requirements_dev.txt
+ setup.cfg
+ tox.ini

Here are the various config files
tox.ini:

[tox]
minversion = 3.8.0
envlist = py38, py39, py310, flake8
isolated_build = true

[testenv]
setenv =
    PYTHONPATH = {toxinidir}
deps =
    -r{toxinidir}/requirements_dev.txt
commands =
    pytest --basetemp={envtmpdir}

[testenv:flake8]
basepython = python3.8
deps = flake8
commands = flake8

pyproject.toml:

[build-system]
requires = ["setuptools>=42.0", "wheel"]
build-backend = "setuptools.build_meta"

[tool.pytest.ini_options]
testpaths = [
    "api",
    "blog",
    "djangoProject"
]
DJANGO_SETTINGS_MODULE = "djangoProject.settings"
python_files = "tests.py test_*.py *_tests.py"

setup.cfg:

[options]
packages =
    api
    blog
    djangoProject
    templates

[flake8]
max-line-length = 210
exclude =
    .git,
    .github,
    .pytest_cache,
    __pycache__,
    docs/source/conf.py,
    old,
    build,
    dist,
    venv,
    migrations

requirements_dev.txt:

Django~=4.0.3
djangorestframework~=3.13.1
django-gravatar2~=1.4.4
psycopg2~=2.9.3
beautifulsoup4~=4.10.0
pytest-django~=4.5.2
tox~=3.24.5
flake8~=4.0.1

I'm developing on Pycharm and Linux Mint 20.3 (in a HyperV VM)

Here is the output when I try to run tox:

(venv) dafrandle@linux-mint-VM:\~/PycharmProjects/djangoProject$ tox
py38 inst-nodeps: /home/dafrandle/PycharmProjects/djangoProject/.tox/.tmp/package/1/UNKNOWN-0.0.0.tar.gz
ERROR: invocation failed (exit code 1), logfile: /home/dafrandle/PycharmProjects/djangoProject/.tox/py38/log/py38-10.log
=============================================================================================================== log start ===============================================================================================================
Processing ./.tox/.tmp/package/1/UNKNOWN-0.0.0.tar.gz
Installing build dependencies: started
Installing build dependencies: finished with status 'done'
Getting requirements to build wheel: started
Getting requirements to build wheel: finished with status 'error'
error: subprocess-exited-with-error
 
× Getting requirements to build wheel did not run successfully.
│ exit code: 1
╰─\> \[6 lines of output\]
No parent package detected, impossible to derive `name`
running egg_info
writing UNKNOWN.egg-info/PKG-INFO
writing dependency_links to UNKNOWN.egg-info/dependency_links.txt
writing top-level names to UNKNOWN.egg-info/top_level.txt
error: package directory 'templates' does not exist
\[end of output\]
 
note: This error originates from a subprocess, and is likely not a problem with pip.
error: subprocess-exited-with-error
 
× Getting requirements to build wheel did not run successfully.
│ exit code: 1
╰─\> See above for output.
 
note: This error originates from a subprocess, and is likely not a problem with pip.
 
================================================================================================================ log end ================================================================================================================
py39 create: /home/dafrandle/PycharmProjects/djangoProject/.tox/py39
py39 installdeps: -r/home/dafrandle/PycharmProjects/djangoProject/requirements_dev.txt
ERROR: invocation failed (exit code 1), logfile: /home/dafrandle/PycharmProjects/djangoProject/.tox/py39/log/py39-1.log
=============================================================================================================== log start ===============================================================================================================
Collecting Django\~=4.0.3
Using cached Django-4.0.3-py3-none-any.whl (8.0 MB)
Collecting djangorestframework\~=3.13.1
Using cached djangorestframework-3.13.1-py3-none-any.whl (958 kB)
Collecting django-gravatar2\~=1.4.4
Using cached django_gravatar2-1.4.4-py2.py3-none-any.whl (7.9 kB)
Collecting psycopg2\~=2.9.3
Using cached psycopg2-2.9.3.tar.gz (380 kB)
Preparing metadata (setup.py): started
Preparing metadata (setup.py): finished with status 'done'
Collecting beautifulsoup4\~=4.10.0
Using cached beautifulsoup4-4.10.0-py3-none-any.whl (97 kB)
Collecting pytest-django\~=4.5.2
Using cached pytest_django-4.5.2-py3-none-any.whl (20 kB)
Collecting tox\~=3.24.5
Using cached tox-3.24.5-py2.py3-none-any.whl (85 kB)
Collecting flake8\~=4.0.1
Using cached flake8-4.0.1-py2.py3-none-any.whl (64 kB)
Collecting asgiref\<4,\>=3.4.1
Using cached asgiref-3.5.0-py3-none-any.whl (22 kB)
Collecting sqlparse\>=0.2.2
Using cached sqlparse-0.4.2-py3-none-any.whl (42 kB)
Collecting pytz
Using cached pytz-2022.1-py2.py3-none-any.whl (503 kB)
Collecting soupsieve\>1.2
Using cached soupsieve-2.3.1-py3-none-any.whl (37 kB)
Collecting pytest\>=5.4.0
Using cached pytest-7.1.1-py3-none-any.whl (297 kB)
Collecting virtualenv!=20.0.0,!=20.0.1,!=20.0.2,!=20.0.3,!=20.0.4,!=20.0.5,!=20.0.6,!=20.0.7,\>=16.0.0
Using cached virtualenv-20.14.0-py2.py3-none-any.whl (8.8 MB)
Collecting six\>=1.14.0
Using cached six-1.16.0-py2.py3-none-any.whl (11 kB)
Collecting toml\>=0.9.4
Using cached toml-0.10.2-py2.py3-none-any.whl (16 kB)
Collecting packaging\>=14
Using cached packaging-21.3-py3-none-any.whl (40 kB)
Collecting py\>=1.4.17
Using cached py-1.11.0-py2.py3-none-any.whl (98 kB)
Collecting filelock\>=3.0.0
Using cached filelock-3.6.0-py3-none-any.whl (10.0 kB)
Collecting pluggy\>=0.12.0
Using cached pluggy-1.0.0-py2.py3-none-any.whl (13 kB)
Collecting pycodestyle\<2.9.0,\>=2.8.0
Using cached pycodestyle-2.8.0-py2.py3-none-any.whl (42 kB)
Collecting mccabe\<0.7.0,\>=0.6.0
Using cached mccabe-0.6.1-py2.py3-none-any.whl (8.6 kB)
Collecting pyflakes\<2.5.0,\>=2.4.0
Using cached pyflakes-2.4.0-py2.py3-none-any.whl (69 kB)
Collecting pyparsing!=3.0.5,\>=2.0.2
Using cached pyparsing-3.0.7-py3-none-any.whl (98 kB)
Collecting tomli\>=1.0.0
Using cached tomli-2.0.1-py3-none-any.whl (12 kB)
Collecting iniconfig
Using cached iniconfig-1.1.1-py2.py3-none-any.whl (5.0 kB)
Collecting attrs\>=19.2.0
Using cached attrs-21.4.0-py2.py3-none-any.whl (60 kB)
Collecting distlib\<1,\>=0.3.1
Using cached distlib-0.3.4-py2.py3-none-any.whl (461 kB)
Collecting platformdirs\<3,\>=2
Using cached platformdirs-2.5.1-py3-none-any.whl (14 kB)
Building wheels for collected packages: psycopg2
Building wheel for psycopg2 (setup.py): started
Building wheel for psycopg2 (setup.py): finished with status 'error'
error: subprocess-exited-with-error
 
× python setup.py bdist_wheel did not run successfully.
│ exit code: 1
╰─\> \[38 lines of output\]
running bdist_wheel
running build
running build_py
creating build
creating build/lib.linux-x86_64-3.9
creating build/lib.linux-x86_64-3.9/psycopg2
copying lib/\_json.py -\> build/lib.linux-x86_64-3.9/psycopg2
copying lib/\_range.py -\> build/lib.linux-x86_64-3.9/psycopg2
copying lib/errors.py -\> build/lib.linux-x86_64-3.9/psycopg2
copying lib/\_ipaddress.py -\> build/lib.linux-x86_64-3.9/psycopg2
copying lib/extras.py -\> build/lib.linux-x86_64-3.9/psycopg2
copying lib/pool.py -\> build/lib.linux-x86_64-3.9/psycopg2
copying lib/__init__.py -\> build/lib.linux-x86_64-3.9/psycopg2
copying lib/errorcodes.py -\> build/lib.linux-x86_64-3.9/psycopg2
copying lib/tz.py -\> build/lib.linux-x86_64-3.9/psycopg2
copying lib/extensions.py -\> build/lib.linux-x86_64-3.9/psycopg2
copying lib/sql.py -\> build/lib.linux-x86_64-3.9/psycopg2
running build_ext
building 'psycopg2.\_psycopg' extension
creating build/temp.linux-x86_64-3.9
creating build/temp.linux-x86_64-3.9/psycopg
x86_64-linux-gnu-gcc -pthread -Wno-unused-result -Wsign-compare -DNDEBUG -g -fwrapv -O2 -Wall -g -fstack-protector-strong -Wformat -Werror=format-security -fPIC "-DPSYCOPG_VERSION=2.9.3 (dt dec pq3 ext lo64)" -DPSYCOPG_DEBUG=1 -DPG_VERSION_NUM=120009 -DHAVE_LO64=1 -DPSYCOPG_DEBUG=1 -I/home/dafrandle/PycharmProjects/djangoProject/.tox/py39/include -I/usr/include/python3.9 -I. -I/usr/include/postgresql -I/usr/include/postgresql/12/server -I/usr/include/libxml2 -I/usr/include/mit-krb5 -c psycopg/adapter_asis.c -o build/temp.linux-x86_64-3.9/psycopg/adapter_asis.o -Wdeclaration-after-statement
In file included from psycopg/adapter_asis.c:28:
./psycopg/psycopg.h:35:10: fatal error: Python.h: No such file or directory
35 | #include \<Python.h\>
|          ^\~\~\~\~\~\~\~\~\~
compilation terminated.
 
      It appears you are missing some prerequisite to build the package from source.
      
      You may install a binary package by installing 'psycopg2-binary' from PyPI.
      If you want to install psycopg2 from source, please install the packages
      required for the build and try again.
      
      For further information please check the 'doc/src/install.rst' file (also at
      <https://www.psycopg.org/docs/install.html>).
      
      error: command '/usr/bin/x86_64-linux-gnu-gcc' failed with exit code 1
      [end of output]
 
note: This error originates from a subprocess, and is likely not a problem with pip.
ERROR: Failed building wheel for psycopg2
Running setup.py clean for psycopg2
Failed to build psycopg2
Installing collected packages: pytz, mccabe, iniconfig, django-gravatar2, distlib, tomli, toml, sqlparse, soupsieve, six, pyparsing, pyflakes, pycodestyle, py, psycopg2, pluggy, platformdirs, filelock, attrs, asgiref, virtualenv, packaging, flake8, Django, beautifulsoup4, tox, pytest, djangorestframework, pytest-django
Running setup.py install for psycopg2: started
Running setup.py install for psycopg2: finished with status 'error'
error: subprocess-exited-with-error
 
× Running setup.py install for psycopg2 did not run successfully.
│ exit code: 1
╰─\> \[40 lines of output\]
running install
/home/dafrandle/PycharmProjects/djangoProject/.tox/py39/lib/python3.9/site-packages/setuptools/command/install.py:34: SetuptoolsDeprecationWarning: setup.py install is deprecated. Use build and pip and other standards-based tools.
warnings.warn(
running build
running build_py
creating build
creating build/lib.linux-x86_64-3.9
creating build/lib.linux-x86_64-3.9/psycopg2
copying lib/\_json.py -\> build/lib.linux-x86_64-3.9/psycopg2
copying lib/\_range.py -\> build/lib.linux-x86_64-3.9/psycopg2
copying lib/errors.py -\> build/lib.linux-x86_64-3.9/psycopg2
copying lib/\_ipaddress.py -\> build/lib.linux-x86_64-3.9/psycopg2
copying lib/extras.py -\> build/lib.linux-x86_64-3.9/psycopg2
copying lib/pool.py -\> build/lib.linux-x86_64-3.9/psycopg2
copying lib/__init__.py -\> build/lib.linux-x86_64-3.9/psycopg2
copying lib/errorcodes.py -\> build/lib.linux-x86_64-3.9/psycopg2
copying lib/tz.py -\> build/lib.linux-x86_64-3.9/psycopg2
copying lib/extensions.py -\> build/lib.linux-x86_64-3.9/psycopg2
copying lib/sql.py -\> build/lib.linux-x86_64-3.9/psycopg2
running build_ext
building 'psycopg2.\_psycopg' extension
creating build/temp.linux-x86_64-3.9
creating build/temp.linux-x86_64-3.9/psycopg
x86_64-linux-gnu-gcc -pthread -Wno-unused-result -Wsign-compare -DNDEBUG -g -fwrapv -O2 -Wall -g -fstack-protector-strong -Wformat -Werror=format-security -fPIC "-DPSYCOPG_VERSION=2.9.3 (dt dec pq3 ext lo64)" -DPSYCOPG_DEBUG=1 -DPG_VERSION_NUM=120009 -DHAVE_LO64=1 -DPSYCOPG_DEBUG=1 -I/home/dafrandle/PycharmProjects/djangoProject/.tox/py39/include -I/usr/include/python3.9 -I. -I/usr/include/postgresql -I/usr/include/postgresql/12/server -I/usr/include/libxml2 -I/usr/include/mit-krb5 -c psycopg/adapter_asis.c -o build/temp.linux-x86_64-3.9/psycopg/adapter_asis.o -Wdeclaration-after-statement
In file included from psycopg/adapter_asis.c:28:
./psycopg/psycopg.h:35:10: fatal error: Python.h: No such file or directory
35 | #include \<Python.h\>
|          ^\~\~\~\~\~\~\~\~\~
compilation terminated.
 
      It appears you are missing some prerequisite to build the package from source.
      
      You may install a binary package by installing 'psycopg2-binary' from PyPI.
      If you want to install psycopg2 from source, please install the packages
      required for the build and try again.
      
      For further information please check the 'doc/src/install.rst' file (also at
      <https://www.psycopg.org/docs/install.html>).
      
      error: command '/usr/bin/x86_64-linux-gnu-gcc' failed with exit code 1
      [end of output]
 
note: This error originates from a subprocess, and is likely not a problem with pip.
error: legacy-install-failure
 
× Encountered error while trying to install package.
╰─\> psycopg2
 
note: This is an issue with the package mentioned above, not pip.
hint: See above for output from the failure.
 
================================================================================================================ log end ================================================================================================================
ERROR: could not install deps \[-r/home/dafrandle/PycharmProjects/djangoProject/requirements_dev.txt\]; v = InvocationError('/home/dafrandle/PycharmProjects/djangoProject/.tox/py39/bin/python -m pip install -r/home/dafrandle/PycharmProjects/djangoProject/requirements_dev.txt', 1)
py310 create: /home/dafrandle/PycharmProjects/djangoProject/.tox/py310
py310 installdeps: -r/home/dafrandle/PycharmProjects/djangoProject/requirements_dev.txt
ERROR: invocation failed (exit code 1), logfile: /home/dafrandle/PycharmProjects/djangoProject/.tox/py310/log/py310-1.log
=============================================================================================================== log start ===============================================================================================================
Traceback (most recent call last):
File "/usr/lib/python3.10/runpy.py", line 196, in \_run_module_as_main
return \_run_code(code, main_globals, None,
File "/usr/lib/python3.10/runpy.py", line 86, in \_run_code
exec(code, run_globals)
File "/home/dafrandle/PycharmProjects/djangoProject/.tox/py310/lib/python3.10/site-packages/pip/__main__.py", line 29, in \<module\>
from pip.\_internal.cli.main import main as \_main
File "/home/dafrandle/PycharmProjects/djangoProject/.tox/py310/lib/python3.10/site-packages/pip/\_internal/cli/main.py", line 9, in \<module\>
from pip.\_internal.cli.autocompletion import autocomplete
File "/home/dafrandle/PycharmProjects/djangoProject/.tox/py310/lib/python3.10/site-packages/pip/\_internal/cli/autocompletion.py", line 10, in \<module\>
from pip.\_internal.cli.main_parser import create_main_parser
File "/home/dafrandle/PycharmProjects/djangoProject/.tox/py310/lib/python3.10/site-packages/pip/\_internal/cli/main_parser.py", line 8, in \<module\>
from pip.\_internal.cli import cmdoptions
File "/home/dafrandle/PycharmProjects/djangoProject/.tox/py310/lib/python3.10/site-packages/pip/\_internal/cli/cmdoptions.py", line 23, in \<module\>
from pip.\_internal.cli.parser import ConfigOptionParser
File "/home/dafrandle/PycharmProjects/djangoProject/.tox/py310/lib/python3.10/site-packages/pip/\_internal/cli/parser.py", line 12, in \<module\>
from pip.\_internal.configuration import Configuration, ConfigurationError
File "/home/dafrandle/PycharmProjects/djangoProject/.tox/py310/lib/python3.10/site-packages/pip/\_internal/configuration.py", line 26, in \<module\>
from pip.\_internal.utils.logging import getLogger
File "/home/dafrandle/PycharmProjects/djangoProject/.tox/py310/lib/python3.10/site-packages/pip/\_internal/utils/logging.py", line 27, in \<module\>
from pip.\_internal.utils.misc import ensure_dir
File "/home/dafrandle/PycharmProjects/djangoProject/.tox/py310/lib/python3.10/site-packages/pip/\_internal/utils/misc.py", line 39, in \<module\>
from pip.\_internal.locations import get_major_minor_version
File "/home/dafrandle/PycharmProjects/djangoProject/.tox/py310/lib/python3.10/site-packages/pip/\_internal/locations/__init__.py", line 14, in \<module\>
from . import \_distutils, \_sysconfig
File "/home/dafrandle/PycharmProjects/djangoProject/.tox/py310/lib/python3.10/site-packages/pip/\_internal/locations/\_distutils.py", line 9, in \<module\>
from distutils.cmd import Command as DistutilsCommand
ModuleNotFoundError: No module named 'distutils.cmd'
 
================================================================================================================ log end ================================================================================================================
ERROR: could not install deps \[-r/home/dafrandle/PycharmProjects/djangoProject/requirements_dev.txt\]; v = InvocationError('/home/dafrandle/PycharmProjects/djangoProject/.tox/py310/bin/python -m pip install -r/home/dafrandle/PycharmProjects/djangoProject/requirements_dev.txt', 1)
flake8 inst-nodeps: /home/dafrandle/PycharmProjects/djangoProject/.tox/.tmp/package/1/UNKNOWN-0.0.0.tar.gz
ERROR: invocation failed (exit code 1), logfile: /home/dafrandle/PycharmProjects/djangoProject/.tox/flake8/log/flake8-7.log
=============================================================================================================== log start ===============================================================================================================
Processing ./.tox/.tmp/package/1/UNKNOWN-0.0.0.tar.gz
Installing build dependencies: started
Installing build dependencies: finished with status 'done'
Getting requirements to build wheel: started
Getting requirements to build wheel: finished with status 'error'
error: subprocess-exited-with-error
 
× Getting requirements to build wheel did not run successfully.
│ exit code: 1
╰─\> \[6 lines of output\]
No parent package detected, impossible to derive `name`
running egg_info
writing UNKNOWN.egg-info/PKG-INFO
writing dependency_links to UNKNOWN.egg-info/dependency_links.txt
writing top-level names to UNKNOWN.egg-info/top_level.txt
error: package directory 'templates' does not exist
\[end of output\]
 
note: This error originates from a subprocess, and is likely not a problem with pip.
error: subprocess-exited-with-error
 
× Getting requirements to build wheel did not run successfully.
│ exit code: 1
╰─\> See above for output.
 
note: This error originates from a subprocess, and is likely not a problem with pip.
 
================================================================================================================ log end ================================================================================================================
\___\_ summary \___\_
ERROR:   py38: InvocationError for command /home/dafrandle/PycharmProjects/djangoProject/.tox/py38/bin/python -m pip install --no-deps -U .tox/.tmp/package/1/UNKNOWN-0.0.0.tar.gz (exited with code 1)
ERROR:   py39: could not install deps \[-r/home/dafrandle/PycharmProjects/djangoProject/requirements_dev.txt\]; v = InvocationError('/home/dafrandle/PycharmProjects/djangoProject/.tox/py39/bin/python -m pip install -r/home/dafrandle/PycharmProjects/djangoProject/requirements_dev.txt', 1)
ERROR:   py310: could not install deps \[-r/home/dafrandle/PycharmProjects/djangoProject/requirements_dev.txt\]; v = InvocationError('/home/dafrandle/PycharmProjects/djangoProject/.tox/py310/bin/python -m pip install -r/home/dafrandle/PycharmProjects/djangoProject/requirements_dev.txt', 1)
ERROR:   flake8: InvocationError for command /home/dafrandle/PycharmProjects/djangoProject/.tox/flake8/bin/python -m pip install --no-deps -U .tox/.tmp/package/1/UNKNOWN-0.0.0.tar.gz (exited with code 1)

their is multiple problems here

1: both py38 envs don't use my requirements and instead run pip with --no-deps and goes after some file that doesn't exist
2: in py38 envs the wheel fails to build - this is probably because of #1 but I'm not sure.
3: In all other envs the wheel for psycopg2 fails to build and it also fails to install using setup.py

I have tried removing lines from the tox.ini to get a different output to try and locate the issue if it was in the ini files but found nothing.

when I add things to my project with pip manually or using PyCharm's package manger inclduing psycopg2 it all works fine so I don't know why it wont work in tox

I don't know what I'm doing wrong

I was working off this tutorial video: https://www.youtube.com/watch?v=DhUpxWjOhME

it's not for a Django project but everything before the tox part I was able to get running fine


Solution

  • The problem is well described in the error log:

    building 'psycopg2.\_psycopg' extension
    creating build/temp.linux-x86_64-3.9
    creating build/temp.linux-x86_64-3.9/psycopg
    x86_64-linux-gnu-gcc -pthread -Wno-unused-result -Wsign-compare -DNDEBUG -g -fwrapv -O2 -Wall -g -fstack-protector-strong -Wformat -Werror=format-security -fPIC "-DPSYCOPG_VERSION=2.9.3 (dt dec pq3 ext lo64)" -DPSYCOPG_DEBUG=1 -DPG_VERSION_NUM=120009 -DHAVE_LO64=1 -DPSYCOPG_DEBUG=1 -I/home/dafrandle/PycharmProjects/djangoProject/.tox/py39/include -I/usr/include/python3.9 -I. -I/usr/include/postgresql -I/usr/include/postgresql/12/server -I/usr/include/libxml2 -I/usr/include/mit-krb5 -c psycopg/adapter_asis.c -o build/temp.linux-x86_64-3.9/psycopg/adapter_asis.o -Wdeclaration-after-statement
    In file included from psycopg/adapter_asis.c:28:
    ./psycopg/psycopg.h:35:10: fatal error: Python.h: No such file or directory
    35 | #include \<Python.h\>
    |          ^\~\~\~\~\~\~\~\~\~
    compilation terminated.
     
          It appears you are missing some prerequisite to build the package from source.
          
          You may install a binary package by installing 'psycopg2-binary' from PyPI.
          If you want to install psycopg2 from source, please install the packages
          required for the build and try again.
          
          For further information please check the 'doc/src/install.rst' file (also at
          <https://www.psycopg.org/docs/install.html>).
          
          error: command '/usr/bin/x86_64-linux-gnu-gcc' failed with exit code 1
          [end of output]
     
    note: This error originates from a subprocess, and is likely not a problem with pip.
    ERROR: Failed building wheel for psycopg2
    Running setup.py clean for psycopg2
    Failed to build psycopg2
    Installing collected packages: pytz, mccabe, iniconfig, django-gravatar2, distlib, tomli, toml, sqlparse, soupsieve, six, pyparsing, pyflakes, pycodestyle, py, psycopg2, pluggy, platformdirs, filelock, attrs, asgiref, virtualenv, packaging, flake8, Django, beautifulsoup4, tox, pytest, djangorestframework, pytest-django
    Running setup.py install for psycopg2: started
    Running setup.py install for psycopg2: finished with status 'error'
    error: subprocess-exited-with-error
     
    × Running setup.py install for psycopg2 did not run successfully.
    │ exit code: 1
    ╰─\> \[40 lines of output\]
    

    So you fail to build the psycopg2 package, because...

    In file included from psycopg/adapter_asis.c:28:
    ./psycopg/psycopg.h:35:10: fatal error: Python.h: No such file or directory
    35 | #include \<Python.h\>
    

    ... pip tries to install the source package, which needs some compilation step for this the mentioned header file is missing.

    When I try to reproduce the issue...

    pip install psycopg2
    Collecting psycopg2
      Downloading psycopg2-2.9.3.tar.gz (380 kB)
    ...
    

    You clearly see, that psycopg2 is downloaded as source and not as wheel.

    So this is not a tox issue, but rather the project does not provide a pre-compiled wheel, and your environment is missing the necessary requirements.

    There is the question left why this would work in your PyCharm environment. This is nothing I can say for sure, but one possible issue could be that your PyCharm is running in a different environment than tox - as you mentioned you are working in a VM environment. So this is something you need to figure out yourself.