Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Compare folders correctly when folder path contains symbolic links (Fixes #9452) #9453

Closed
wants to merge 4 commits into from

Conversation

fohrloop
Copy link
Contributor

@fohrloop fohrloop commented Jan 13, 2021

Fixes #9452

@fohrloop fohrloop changed the title Fixes https://github.com/pypa/pip/issues/9452 Compare folders correctly when folder path contains symbolic links (Fixes #9452) Jan 13, 2021
@BrownTruck
Copy link
Contributor

Hello!

I am an automated bot and I have noticed that this pull request is not currently able to be merged. If you are able to either merge the master branch into this pull request or rebase this pull request against master then it will be eligible for code review and hopefully merging!

@BrownTruck BrownTruck added the needs rebase or merge PR has conflicts with current master label Feb 23, 2021
@pradyunsg pradyunsg added the S: awaiting response Waiting for a response/more information label Apr 2, 2021
@pradyunsg
Copy link
Member

Hi there! Could you update this PR, and add a test for the usecase you're thinking of?

@fohrloop
Copy link
Contributor Author

fohrloop commented Apr 2, 2021

Hi! Yes I could. I tried to just set up the development environment for pip as described here, using a fresh copy of the pypa:main branch. Unfortunately I have not been very lucky with it. I am using Windows.

Here is an example. I run the tox with --exitfirst argument for pytest, since running all the tests takes multiple minutes and most of the tests are failing. I'm running inside a fresh virtual environment created to <project_root>/venv with python -m venv venv. The python used to create the virtual environment is 3.8.5 64-bit from Python.org, installed to C:\Python\Python385-64, and that folder can be found in the PATH environmental variable.

tox output
(venv) PS C:\repos\pip> tox -e py38 -- -n auto --exitfirst
GLOB sdist-make: C:\repos\pip\setup.py
py38 recreate: C:\repos\pip\.tox\py38
py38 installdeps: -rC:\repos\pip/tools/requirements/tests.txt
py38 inst: C:\repos\pip\.tox\.tmp\package\2\pip-21.1.dev0.zip
py38 installed: apipkg==1.5,atomicwrites==1.4.0,attrs==20.3.0,cffi==1.14.5,colorama==0.4.4,coverage==5.5,cryptography==3.4.7,execnet==1.8.0,freezegun==1.1.0,iniconfig==1.1.1,packaging==20.9,pip @ file:///C:/repos/pip/.tox/.tmp/package/2/pip-21.1.dev0.zip,pluggy==0.13.1,pretend==1.0.9,py==1.10.0,pycparser==2.20,pyparsing==2.4.7,pytest==6.2.2,pytest-cov==2.11.1,pytest-forked==1.3.0,pytest-rerunfailures==9.1.1,pytest-xdist==2.2.1,python-dateutil==2.8.1,scripttest==1.3,setuptools==54.1.2,six==1.15.0,toml==0.10.2,virtualenv==16.7.10,Werkzeug==1.0.1,wheel==0.36.2
py38 run-test-pre: PYTHONHASHSEED='578'
py38 run-test-pre: commands[0] | python -c 'import shutil, sys; shutil.rmtree(sys.argv[1], ignore_errors=True)' 'C:\repos\pip/tests/data/common_wheels'
py38 run-test-pre: commands[1] | python 'C:\repos\pip/tools/tox_pip.py' wheel -w 'C:\repos\pip/tests/data/common_wheels' -r 'C:\repos\pip/tools/requirements/tests-common_wheels.txt'
Collecting setuptools>=40.8.0
Using cached setuptools-54.2.0-py3-none-any.whl (785 kB)
Collecting wheel
Using cached wheel-0.36.2-py2.py3-none-any.whl (35 kB)
Collecting coverage>=4.4
Using cached coverage-5.5-cp38-cp38-win_amd64.whl (211 kB)
Saved c:\repos\pip\tests\data\common_wheels\coverage-5.5-cp38-cp38-win_amd64.whl
Saved c:\repos\pip\tests\data\common_wheels\wheel-0.36.2-py2.py3-none-any.whl
Saved c:\repos\pip\tests\data\common_wheels\setuptools-54.2.0-py3-none-any.whl
py38 run-test: commands[0] | pytest -n auto --exitfirst
===================================================================== test session starts =====================================================================
platform win32 -- Python 3.8.5, pytest-6.2.2, py-1.10.0, pluggy-0.13.1
cachedir: .tox\py38\.pytest_cache
rootdir: C:\repos\pip, configfile: setup.cfg
plugins: cov-2.11.1, forked-1.3.0, rerunfailures-9.1.1, xdist-2.2.1
gw0 [2149] / gw1 [2149] / gw2 [2149] / gw3 [2149] / gw4 [2149] / gw5 [2149] / gw6 [2149] / gw7 [2149]
....E
=========================================================================== ERRORS ============================================================================
___________________________________________________ ERROR at setup of test_build_env_allow_only_one_install ___________________________________________________
[gw4] win32 -- Python 3.8.5 c:\repos\pip\.tox\py38\scripts\python.exe

request = <SubRequest 'virtualenv_template' for <Function test_build_env_allow_only_one_install>>
tmpdir_factory = TempdirFactory(_tmppath_factory=TempPathFactory(_given_basetemp=WindowsPath('C:/Users/niko/AppData/Local/Temp/pytest-o...t at 0x0000027410B3E8E0>, _basetemp=WindowsPath('C:/Users/niko/AppData/Local/Temp/pytest-of-niko/pytest-4/popen-gw4')))
pip_src = Path('C:\\Users\\niko\\AppData\\Local\\Temp\\pytest-of-niko\\pytest-4\\popen-gw4\\pip_src0\\pip_src')
setuptools_install = Path('C:\\Users\\niko\\AppData\\Local\\Temp\\pytest-of-niko\\pytest-4\\popen-gw4\\setuptools0\\install')
coverage_install = Path('C:\\Users\\niko\\AppData\\Local\\Temp\\pytest-of-niko\\pytest-4\\popen-gw4\\coverage0\\install')

  @pytest.fixture(scope="session")
  def virtualenv_template(
      request, tmpdir_factory, pip_src, setuptools_install, coverage_install
  ):

      if request.config.getoption("--use-venv"):
          venv_type = "venv"
      else:
          venv_type = "virtualenv"

      # Create the virtual environment
      tmpdir = Path(str(tmpdir_factory.mktemp("virtualenv")))
>       venv = VirtualEnvironment(tmpdir.joinpath("venv_orig"), venv_type=venv_type)

tests\conftest.py:342:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
tests\lib\venv.py:27: in __init__
  self._create()
tests\lib\venv.py:58: in _create
  _virtualenv.create_environment(
.tox\py38\lib\site-packages\virtualenv.py:1161: in create_environment
  install_python(home_dir, lib_dir, inc_dir, bin_dir, site_packages=site_packages, clear=clear, symlink=symlink)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

home_dir = 'C:\\Users\\niko\\AppData\\Local\\Temp\\pytest-of-niko\\pytest-4\\popen-gw4\\virtualenv0\\venv_orig'
lib_dir = 'C:\\Users\\niko\\AppData\\Local\\Temp\\pytest-of-niko\\pytest-4\\popen-gw4\\virtualenv0\\venv_orig\\Lib'
inc_dir = 'C:\\Users\\niko\\AppData\\Local\\Temp\\pytest-of-niko\\pytest-4\\popen-gw4\\virtualenv0\\venv_orig\\Include'
bin_dir = 'C:\\Users\\niko\\AppData\\Local\\Temp\\pytest-of-niko\\pytest-4\\popen-gw4\\virtualenv0\\venv_orig\\Scripts', site_packages = False, clear = False   
symlink = True

  def install_python(home_dir, lib_dir, inc_dir, bin_dir, site_packages, clear, symlink=True):
      """Install just the base environment, no distutils patches etc"""
      if sys.executable.startswith(bin_dir):
          print("Please use the *system* python to run this script")
          return

      if clear:
          rm_tree(lib_dir)
          # FIXME: why not delete it?
          # Maybe it should delete everything with #!/path/to/venv/python in it
          logger.notify("Not deleting %s", bin_dir)

      if hasattr(sys, "real_prefix"):
          logger.notify("Using real prefix %r", sys.real_prefix)
          prefix = sys.real_prefix
      elif hasattr(sys, "base_prefix"):
          logger.notify("Using base prefix %r", sys.base_prefix)
          prefix = sys.base_prefix
      else:
          prefix = sys.prefix
      prefix = os.path.abspath(prefix)
      mkdir(lib_dir)
      fix_lib64(lib_dir, symlink)
      stdlib_dirs = [os.path.dirname(os.__file__)]
      if IS_WIN:
          stdlib_dirs.append(join(os.path.dirname(stdlib_dirs[0]), "DLLs"))
      elif IS_DARWIN:
          stdlib_dirs.append(join(stdlib_dirs[0], "site-packages"))
      if hasattr(os, "symlink"):
          logger.info("Symlinking Python bootstrap modules")
      else:
          logger.info("Copying Python bootstrap modules")
      logger.indent += 2
      try:
          # copy required files...
          for stdlib_dir in stdlib_dirs:
              copy_required_files(stdlib_dir, lib_dir, symlink)
          # ...and modules
          copy_required_modules(home_dir, symlink)
          copy_license(prefix, home_dir, lib_dir, symlink)
      finally:
          logger.indent -= 2
      # ...copy tcl/tk
      if IS_WIN:
          copy_tcltk(prefix, home_dir, symlink)
      mkdir(join(lib_dir, "site-packages"))
      import site

      site_filename = site.__file__
      if site_filename.endswith(".pyc") or site_filename.endswith(".pyo"):
          site_filename = site_filename[:-1]
      elif site_filename.endswith("$py.class"):
          site_filename = site_filename.replace("$py.class", ".py")
      site_filename_dst = change_prefix(site_filename, home_dir)
      site_dir = os.path.dirname(site_filename_dst)
      writefile(site_filename_dst, SITE_PY)
      writefile(join(site_dir, "orig-prefix.txt"), prefix)
      site_packages_filename = join(site_dir, "no-global-site-packages.txt")
      if not site_packages:
          writefile(site_packages_filename, "")

      if IS_PYPY or IS_WIN:
          standard_lib_include_dir = join(prefix, "include")
      else:
          standard_lib_include_dir = join(prefix, "include", PY_VERSION + ABI_FLAGS)
      if os.path.exists(standard_lib_include_dir):
          copy_include_dir(standard_lib_include_dir, inc_dir, symlink)
      else:
          logger.debug("No include dir %s", standard_lib_include_dir)

      platform_include_dir = distutils.sysconfig.get_python_inc(plat_specific=1)
      if platform_include_dir != standard_lib_include_dir:
          platform_include_dest = distutils.sysconfig.get_python_inc(plat_specific=1, prefix=home_dir)
          if platform_include_dir == platform_include_dest:
              # Do platinc_dest manually due to a CPython bug;
              # not http://bugs.python.org/issue3386 but a close cousin
              platform_include_dest = subst_path(platform_include_dir, prefix, home_dir)
          if platform_include_dest:
              # PyPy's stdinc_dir and prefix are relative to the original binary
              # (traversing virtualenvs), whereas the platinc_dir is relative to
              # the inner virtualenv and ignores the prefix argument.
              # This seems more evolved than designed.
              copy_include_dir(platform_include_dir, platform_include_dest, symlink)

      # pypy never uses exec_prefix, just ignore it
      if os.path.realpath(sys.exec_prefix) != os.path.realpath(prefix) and not IS_PYPY:
          if IS_WIN:
              exec_dir = join(sys.exec_prefix, "lib")
          else:
              exec_dir = join(sys.exec_prefix, "lib", PY_VERSION)
          copy_required_files(exec_dir, lib_dir, symlink)

      mkdir(bin_dir)
      py_executable = join(bin_dir, os.path.basename(sys.executable))
      if "Python.framework" in prefix or "Python3.framework" in prefix:
          # OS X framework builds cause validation to break
          # https://github.com/pypa/virtualenv/issues/322
          if os.environ.get("__PYVENV_LAUNCHER__"):
              del os.environ["__PYVENV_LAUNCHER__"]
          if re.search(r"/Python(?:-32|-64)*$", py_executable):
              # The name of the python executable is not quite what
              # we want, rename it.
              py_executable = os.path.join(os.path.dirname(py_executable), "python")

      logger.notify("New %s executable in %s", EXPECTED_EXE, py_executable)
      pc_build_dir = os.path.dirname(sys.executable)
      pyd_pth = os.path.join(lib_dir, "site-packages", "virtualenv_builddir_pyd.pth")
      if IS_WIN and os.path.exists(os.path.join(pc_build_dir, "build.bat")):
          logger.notify("Detected python running from build directory %s", pc_build_dir)
          logger.notify("Writing .pth file linking to build directory for *.pyd files")
          writefile(pyd_pth, pc_build_dir)
      else:
          if os.path.exists(pyd_pth):
              logger.info("Deleting %s (not Windows env or not build directory python)", pyd_pth)
              os.unlink(pyd_pth)

      if sys.executable != py_executable:
          # FIXME: could I just hard link?
          executable = sys.executable
          shutil.copyfile(executable, py_executable)
          make_exe(py_executable)
          if IS_WIN or IS_CYGWIN:
              python_w = os.path.join(os.path.dirname(sys.executable), "pythonw.exe")
              if os.path.exists(python_w):
                  logger.info("Also created pythonw.exe")
                  shutil.copyfile(python_w, os.path.join(os.path.dirname(py_executable), "pythonw.exe"))
              python_d = os.path.join(os.path.dirname(sys.executable), "python_d.exe")
              python_d_dest = os.path.join(os.path.dirname(py_executable), "python_d.exe")
              if os.path.exists(python_d):
                  logger.info("Also created python_d.exe")
                  shutil.copyfile(python_d, python_d_dest)
              elif os.path.exists(python_d_dest):
                  logger.info("Removed python_d.exe as it is no longer at the source")
                  os.unlink(python_d_dest)

              # we need to copy the DLL to enforce that windows will load the correct one.
              # may not exist if we are cygwin.
              if IS_PYPY:
                  py_executable_dll_s = [("libpypy-c.dll", "libpypy_d-c.dll")]
              else:
                  py_executable_dll_s = [
                      ("python{}.dll".format(sys.version_info[0]), "python{}_d.dll".format(sys.version_info[0])),
                      (
                          "python{}{}.dll".format(sys.version_info[0], sys.version_info[1]),
                          "python{}{}_d.dll".format(sys.version_info[0], sys.version_info[1]),
                      ),
                  ]

              for py_executable_dll, py_executable_dll_d in py_executable_dll_s:
                  python_dll = os.path.join(os.path.dirname(sys.executable), py_executable_dll)
                  python_dll_d = os.path.join(os.path.dirname(sys.executable), py_executable_dll_d)
                  python_dll_d_dest = os.path.join(os.path.dirname(py_executable), py_executable_dll_d)
                  if os.path.exists(python_dll):
                      logger.info("Also created %s", py_executable_dll)
                      shutil.copyfile(python_dll, os.path.join(os.path.dirname(py_executable), py_executable_dll))
                  if os.path.exists(python_dll_d):
                      logger.info("Also created %s", py_executable_dll_d)
                      shutil.copyfile(python_dll_d, python_dll_d_dest)
                  elif os.path.exists(python_dll_d_dest):
                      logger.info("Removed %s as the source does not exist", python_dll_d_dest)
                      os.unlink(python_dll_d_dest)
          if IS_PYPY:
              # make a symlink python --> pypy-c
              python_executable = os.path.join(os.path.dirname(py_executable), "python")
              if IS_WIN or IS_CYGWIN:
                  python_executable += ".exe"
              logger.info("Also created executable %s", python_executable)
              copyfile(py_executable, python_executable, symlink)

              if IS_WIN:
                  for name in ["libexpat.dll", "libeay32.dll", "ssleay32.dll", "sqlite3.dll", "tcl85.dll", "tk85.dll"]:
                      src = join(prefix, name)
                      if os.path.exists(src):
                          copyfile(src, join(bin_dir, name), symlink)

                  for d in sys.path:
                      if d.endswith("lib_pypy"):
                          break
                  else:
                      logger.fatal("Could not find lib_pypy in sys.path")
                      raise SystemExit(3)
                  logger.info("Copying lib_pypy")
                  copyfile(d, os.path.join(home_dir, "lib_pypy"), symlink)

      if os.path.splitext(os.path.basename(py_executable))[0] != EXPECTED_EXE:
          secondary_exe = os.path.join(os.path.dirname(py_executable), EXPECTED_EXE)
          py_executable_ext = os.path.splitext(py_executable)[1]
          if py_executable_ext.lower() == ".exe":
              # python2.4 gives an extension of '.4' :P
              secondary_exe += py_executable_ext
          if os.path.exists(secondary_exe):
              logger.warn(
                  "Not overwriting existing {} script {} (you must use {})".format(
                      EXPECTED_EXE, secondary_exe, py_executable
                  )
              )
          else:
              logger.notify("Also creating executable in %s", secondary_exe)
              shutil.copyfile(sys.executable, secondary_exe)
              make_exe(secondary_exe)

      if ".framework" in prefix:
          original_python = None
          if "Python.framework" in prefix or "Python3.framework" in prefix:
              logger.debug("MacOSX Python framework detected")
              # Make sure we use the embedded interpreter inside
              # the framework, even if sys.executable points to
              # the stub executable in ${sys.prefix}/bin
              # See http://groups.google.com/group/python-virtualenv/
              #                              browse_thread/thread/17cab2f85da75951
              original_python = os.path.join(prefix, "Resources/Python.app/Contents/MacOS/Python")
          if "EPD" in prefix:
              logger.debug("EPD framework detected")
              original_python = os.path.join(prefix, "bin/python")
          shutil.copy(original_python, py_executable)

          # Copy the framework's dylib into the virtual
          # environment
          virtual_lib = os.path.join(home_dir, ".Python")

          if os.path.exists(virtual_lib):
              os.unlink(virtual_lib)
          lib_name = "Python3" if "Python3.framework" in prefix else "Python"
          copyfile(os.path.join(prefix, lib_name), virtual_lib, symlink)

          # And then change the install_name of the copied python executable
          search = (
              "@executable_path/../../../../Python3" if "Python3.framework" in prefix else os.path.join(prefix, lib_name)
          )
          # noinspection PyBroadException
          try:
              mach_o_change(py_executable, search, "@executable_path/../.Python")
          except Exception:
              e = sys.exc_info()[1]
              logger.warn("Could not call mach_o_change: %s. " "Trying to call install_name_tool instead.", e)
              try:
                  call_subprocess(["install_name_tool", "-change", search, "@executable_path/../.Python", py_executable])
              except Exception:
                  logger.fatal("Could not call install_name_tool -- you must " "have Apple's development tools installed")
                  raise

      if not IS_WIN:
          # Ensure that 'python', 'pythonX' and 'pythonX.Y' all exist
          py_exe_version_major = "python{}".format(sys.version_info[0])
          py_exe_version_major_minor = "python{}.{}".format(sys.version_info[0], sys.version_info[1])
          py_exe_no_version = "python"
          required_symlinks = [py_exe_no_version, py_exe_version_major, py_exe_version_major_minor]

          py_executable_base = os.path.basename(py_executable)

          if py_executable_base in required_symlinks:
              # Don't try to symlink to yourself.
              required_symlinks.remove(py_executable_base)

          for pth in required_symlinks:
              full_pth = join(bin_dir, pth)
              if os.path.exists(full_pth):
                  os.unlink(full_pth)
              if symlink:
                  os.symlink(py_executable_base, full_pth)
              else:
                  copyfile(py_executable, full_pth, symlink)

      cmd = [
          py_executable,
          "-c",
          "import sys;out=sys.stdout;" 'getattr(out, "buffer", out).write(sys.prefix.encode("utf-8"))',
      ]
      logger.info('Testing executable with %s %s "%s"', *cmd)
      try:
          proc = subprocess.Popen(cmd, stdout=subprocess.PIPE)
          proc_stdout, proc_stderr = proc.communicate()
      except OSError:
          e = sys.exc_info()[1]
          if e.errno == errno.EACCES:
              logger.fatal("ERROR: The executable {} could not be run: {}".format(py_executable, e))
              sys.exit(100)
          else:
              raise e

      proc_stdout = proc_stdout.strip().decode("utf-8")
      # normalize paths using realpath to ensure that a virtualenv correctly identifies itself even
      # when addressed over a symlink
      proc_stdout = os.path.normcase(os.path.realpath(proc_stdout))
      norm_home_dir = os.path.normcase(os.path.realpath(home_dir))
      if hasattr(norm_home_dir, "decode"):
          norm_home_dir = norm_home_dir.decode(sys.getfilesystemencoding())
      if proc_stdout != norm_home_dir:
          logger.fatal("ERROR: The executable %s is not functioning", py_executable)
          logger.fatal("ERROR: It thinks sys.prefix is {!r} (should be {!r})".format(proc_stdout, norm_home_dir))
          logger.fatal("ERROR: virtualenv is not compatible with this system or executable")
          if IS_WIN:
              logger.fatal(
                  "Note: some Windows users have reported this error when they "
                  'installed Python for "Only this user" or have multiple '
                  "versions of Python installed. Copying the appropriate "
                  "PythonXX.dll to the virtualenv Scripts/ directory may fix "
                  "this problem."
              )
>           sys.exit(100)
E           SystemExit: 100

.tox\py38\lib\site-packages\virtualenv.py:1711: SystemExit
-------------------------------------------------------------------- Captured stdout setup -------------------------------------------------------------------- 
ERROR: The executable C:\Users\niko\AppData\Local\Temp\pytest-of-niko\pytest-4\popen-gw4\virtualenv0\venv_orig\Scripts\python.exe is not functioning
ERROR: It thinks sys.prefix is 'c:\\repos\\pip' (should be 'c:\\users\\niko\\appdata\\local\\temp\\pytest-of-niko\\pytest-4\\popen-gw4\\virtualenv0\\venv_orig')ERROR: virtualenv is not compatible with this system or executable
Note: some Windows users have reported this error when they installed Python for "Only this user" or have multiple versions of Python installed. Copying the appropriate PythonXX.dll to the virtualenv Scripts/ directory may fix this problem.
-------------------------------------------------------------------- Captured stderr setup -------------------------------------------------------------------- 
No pyvenv.cfg file
====================================================================== warnings summary ======================================================================= 
.tox\py38\lib\site-packages\pip\_vendor\packaging\version.py:127: 1080 warnings
c:\repos\pip\.tox\py38\lib\site-packages\pip\_vendor\packaging\version.py:127: DeprecationWarning: Creating a LegacyVersion has been deprecated and will be removed in the next major release
  warnings.warn(

-- Docs: https://docs.pytest.org/en/stable/warnings.html
=================================================================== short test summary info =================================================================== 
ERROR tests/functional/test_build_env.py::test_build_env_allow_only_one_install - SystemExit: 100
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! xdist.dsession.Interrupted: stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 
========================================================= 4 passed, 1080 warnings, 1 error in 43.74s ==========================================================

It says specifically that

ERROR: virtualenv is not compatible with this system or executable
Note: some Windows users have reported this error when they installed Python for "Only this user" or have multiple versions of Python installed. Copying the appropriate PythonXX.dll to the virtualenv Scripts/ directory may fix this problem.

I tried copying C:\Python\Python385-64\python38.dll to <project_root>/venv/Scripts/python38.dll but the same error persists. It seems that the C:\Users\niko\AppData\Local\Temp\pytest-of-niko\pytest-5\popen-gw6\virtualenv0\venv_orig\Scripts\python.exe is automatically removed by tox so I cannot try to run it directly to see whats wrong.

It also said

-------------------------------------------------------------------- Captured stderr setup -------------------------------------------------------------------- 
No pyvenv.cfg file

Which I don't understand. Where it is checking for pyvenv.cfg? At least <project_root>/venv/pyvenv.cfg does exist.

Is it possible to setup the development environment, and run the tests on Windows?

@fohrloop
Copy link
Contributor Author

fohrloop commented Apr 2, 2021

Adding to the previous. I decided to check what is happening when the error is raised. As seen in the example tox output, the error happens at file .tox\py38\lib\site-packages\virtualenv.py, at function install_python(). I set a breakpoint() to that file just before sys.exit(100), so that I can check what the python.exe looks like. The python.exe that tox creates is located (in this case), at

C:\Users\niko\AppData\Local\Temp\pytest-of-niko\pytest-8\virtualenv0\venv_orig\Scripts\python.exe

Now I understand what the note about missing pyvenv.cfg file was. Running the temporary python.exe leads to:

PS C:\Users\niko\AppData\Local\Temp\pytest-of-niko\pytest-8\virtualenv0\venv_orig\Scripts> .\python.exe
No pyvenv.cfg file

This explains why (almost) all the tests will fail. Usually, when a virtual environment is created, there is also a pyvenv.cfg file. When using the built-in venv module, the location is ./venv/pyvenv.cfg. If I create a file to

C:\Users\niko\AppData\Local\Temp\pytest-of-niko\pytest-8\virtualenv0\venv_orig\pyvenv.cfg

or

C:\Users\niko\AppData\Local\Temp\pytest-of-niko\pytest-8\virtualenv0\venv_orig\Scripts\pyvenv.cfg

with contents

home = C:\Python\Python385-64
include-system-site-packages = false
version = 3.8.5

the temporary python.exe will run without problems:

PS C:\Users\niko\AppData\Local\Temp\pytest-of-niko\pytest-8\virtualenv0\venv_orig\Scripts> .\python.exe
Python 3.8.5 (tags/v3.8.5:580fbb0, Jul 20 2020, 15:57:54) [MSC v.1924 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>>

Now there is a question to be answered: Why tox creates python virtual environments without a pyvenv.cfg?

@fohrloop
Copy link
Contributor Author

fohrloop commented Apr 2, 2021

Digging down the problem. So, the tox -e py38 -- --exitfirst will run

tests/functional/test_build_env.py::test_build_env_allow_only_one_install 

which will fail, precisely here:

    @pytest.fixture(scope="session")
    def virtualenv_template(
        request, tmpdir_factory, pip_src, setuptools_install, coverage_install
    ):

        if request.config.getoption("--use-venv"):
            venv_type = "venv"
        else:
            venv_type = "virtualenv"

        # Create the virtual environment
        tmpdir = Path(str(tmpdir_factory.mktemp("virtualenv")))
>       venv = VirtualEnvironment(tmpdir.joinpath("venv_orig"), venv_type=venv_type)

tests\conftest.py:342:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
tests\lib\venv.py:27: in __init__
    self._create()
tests\lib\venv.py:58: in _create
    _virtualenv.create_environment(
.tox\py38\lib\site-packages\virtualenv.py:1161: in create_environment
    install_python(home_dir, lib_dir, inc_dir, bin_dir, site_packages=site_packages, clear=clear, symlink=symlink)

in other words, the script fails when running VirtualEnvironment(tmpdir.joinpath("venv_orig"), venv_type=venv_type). The arguments for VirtualEnvironment are:

 tmpdir.joinpath("venv_orig") = C:\Users\niko\AppData\Local\Temp\pytest-of-niko\pytest-9\virtualenv0\venv_orig
 venv_type = virtualenv

Luckily, the venv_type can be set from virtualenv to venv with the --use-venv flag. After running the tests with

 tox -e py38 -- --use-venv -n auto --exitfirst

I finally started to get reasonable output! 🎉 The used (non-working) .tox\py38\lib\site-packages\virtualenv.py was version 16.7.10, if that helps someone in the future.

@fohrloop
Copy link
Contributor Author

fohrloop commented Apr 2, 2021

Seems that this commit d08f968, which was the latest commit on pip:main branch few hours ago has some test fails on my machine. Should I use some other branch as the starting point?

tox output
PS C:\repos\pip> tox -e py38 -- --use-venv -n auto
GLOB sdist-make: C:\repos\pip\setup.py
py38 inst-nodeps: C:\repos\pip\.tox\.tmp\package\2\pip-21.1.dev0.zip
py38 installed: apipkg==1.5,atomicwrites==1.4.0,attrs==20.3.0,cffi==1.14.5,colorama==0.4.4,coverage==5.5,cryptography==3.4.7,execnet==1.8.0,freezegun==1.1.0,iniconfig==1.1.1,packaging==20.9,pip @ file:///C:/repos/pip/.tox/.tmp/package/2/pip-21.1.dev0.zip,pluggy==0.13.1,pretend==1.0.9,py==1.10.0,pycparser==2.20,pyparsing==2.4.7,pytest==6.2.2,pytest-cov==2.11.1,pytest-forked==1.3.0,pytest-rerunfailures==9.1.1,pytest-xdist==2.2.1,python-dateutil==2.8.1,scripttest==1.3,setuptools==47.1.0,six==1.15.0,toml==0.10.2,virtualenv==16.7.10,Werkzeug==1.0.1,wheel==0.36.2
py38 run-test-pre: PYTHONHASHSEED='528'
py38 run-test-pre: commands[0] | python -c 'import shutil, sys; shutil.rmtree(sys.argv[1], ignore_errors=True)' 'C:\repos\pip/tests/data/common_wheels'
py38 run-test-pre: commands[1] | python 'C:\repos\pip/tools/tox_pip.py' wheel -w 'C:\repos\pip/tests/data/common_wheels' -r 'C:\repos\pip/tools/requirements/tests-common_wheels.txt'
Collecting setuptools>=40.8.0
  Using cached setuptools-54.2.0-py3-none-any.whl (785 kB)
Collecting wheel
  Using cached wheel-0.36.2-py2.py3-none-any.whl (35 kB)
Collecting coverage>=4.4
  Using cached coverage-5.5-cp38-cp38-win_amd64.whl (211 kB)
Saved c:\repos\pip\tests\data\common_wheels\coverage-5.5-cp38-cp38-win_amd64.whl
Saved c:\repos\pip\tests\data\common_wheels\wheel-0.36.2-py2.py3-none-any.whl
Saved c:\repos\pip\tests\data\common_wheels\setuptools-54.2.0-py3-none-any.whl
py38 run-test: commands[0] | pytest --use-venv -n auto
===================================================================== test session starts =====================================================================
platform win32 -- Python 3.8.5, pytest-6.2.2, py-1.10.0, pluggy-0.13.1
cachedir: .tox\py38\.pytest_cache
rootdir: C:\repos\pip, configfile: setup.cfg
plugins: cov-2.11.1, forked-1.3.0, rerunfailures-9.1.1, xdist-2.2.1
gw0 [2149] / gw1 [2149] / gw2 [2149] / gw3 [2149] / gw4 [2149] / gw5 [2149] / gw6 [2149] / gw7 [2149]
s......................................................s................................................................s......ss...........s........... [  7%] 
.......s..............s.........xss............ss..s.s.ss...........................s....s...................s........................................... [ 14%]...........x...........X.X..............x........s............x................s....s....................s.............X.....s.....ss.s...ss...s........ [ 21%] 
s................s...........................sssssssss....s..s...s............................................................................ss.....s... [ 28%]....................................................................................s..............................................................F.... [ 35%]
F..F..............s.........................................................................................ss......................X..................F [ 42%]
..F..............................................s.ss...........................................ss...................................................... [ 49%] 
......................................................................................................................................................... [ 56%]........................................s........s.s.............ss.....................................s................................................ [ 63%].....ss.......................................s............................................................................s............................ [ 70%] 
....ssssss..........................................ss.........................................................................s........................ [ 77%] 
........................................s...............................s.....................................x.x.............x......................... [ 85%] 
......x.................................................................s..s..................................................................sssssss... [ 92%] 
..............ssssssss.........sss.........................s..................X...................s.s.s...........................................s..... [ 99%]
.........x..x....                                                                                                                                        [100%]
========================================================================== FAILURES ===========================================================================
__________________________________________________________________ test_log_command_success ___________________________________________________________________
[gw5] win32 -- Python 3.8.5 c:\repos\pip\.tox\py38\scripts\python.exe

fixed_time = None, tmpdir = Path('C:\\Users\\niko\\AppData\\Local\\Temp\\pytest-of-niko\\pytest-11\\popen-gw5\\test_log_command_success0')

    def test_log_command_success(fixed_time, tmpdir):
        """Test the --log option logs when command succeeds."""
        cmd = FakeCommand()
        log_path = tmpdir.joinpath('log')
        cmd.main(['fake', '--log', log_path])
        with open(log_path) as f:
>           assert f.read().rstrip() == '2019-01-17T06:00:37,040 fake'
E           AssertionError: assert '2019-01-17T08:00:37,040 fake' == '2019-01-17T06:00:37,040 fake'
E             - 2019-01-17T06:00:37,040 fake
E             ?             ^
E             + 2019-01-17T08:00:37,040 fake
E             ?             ^

tests\unit\test_base_command.py:105: AssertionError
-------------------------------------------------------------------- Captured stdout call --------------------------------------------------------------------- 
fake
___________________________________________________________________ test_log_command_error ____________________________________________________________________ 
[gw5] win32 -- Python 3.8.5 c:\repos\pip\.tox\py38\scripts\python.exe

fixed_time = None, tmpdir = Path('C:\\Users\\niko\\AppData\\Local\\Temp\\pytest-of-niko\\pytest-11\\popen-gw5\\test_log_command_error0')

    def test_log_command_error(fixed_time, tmpdir):
        """Test the --log option logs when command fails."""
        cmd = FakeCommand(error=True)
        log_path = tmpdir.joinpath('log')
        cmd.main(['fake', '--log', log_path])
        with open(log_path) as f:
>           assert f.read().startswith('2019-01-17T06:00:37,040 fake')
E           assert False
E            +  where False = <built-in method startswith of str object at 0x000001DE11822A60>('2019-01-17T06:00:37,040 fake')
E            +    where <built-in method startswith of str object at 0x000001DE11822A60> = '2019-01-17T08:00:37,040 fake\n2019-01-17T08:00:37,040 ERROR: Exception:\n2019-01-17T08:00:37,040 Traceback (most rece...nd.py", line 27, in run_func\n2019-01-17T08:00:37,040     raise SystemExit(1)\n2019-01-17T08:00:37,040 SystemExit: 1\n'.startswith
E            +      where '2019-01-17T08:00:37,040 fake\n2019-01-17T08:00:37,040 ERROR: Exception:\n2019-01-17T08:00:37,040 Traceback (most rece...nd.py", line 
27, in run_func\n2019-01-17T08:00:37,040     raise SystemExit(1)\n2019-01-17T08:00:37,040 SystemExit: 1\n' = <built-in method read of _io.TextIOWrapper object at 0x000001DE144EF110>()
E            +        where <built-in method read of _io.TextIOWrapper object at 0x000001DE144EF110> = <_io.TextIOWrapper name=Path('C:\\Users\\niko\\AppData\\Local\\Temp\\pytest-of-niko\\pytest-11\\popen-gw5\\test_log_command_error0\\log') mode='r' encoding='cp1252'>.read

tests\unit\test_base_command.py:114: AssertionError
-------------------------------------------------------------------- Captured stdout call --------------------------------------------------------------------- 
fake
-------------------------------------------------------------------- Captured stderr call --------------------------------------------------------------------- 
ERROR: Exception:
Traceback (most recent call last):
  File "c:\repos\pip\.tox\py38\lib\site-packages\pip\_internal\cli\base_command.py", line 180, in _main
    status = self.run(options, args)
  File "C:\repos\pip\tests\unit\test_base_command.py", line 40, in run
    return self.run_func()
  File "C:\repos\pip\tests\unit\test_base_command.py", line 27, in run_func
    raise SystemExit(1)
SystemExit: 1
---------------------------------------------------------------------- Captured log call ---------------------------------------------------------------------- 
DEBUG    pip._internal.configuration:configuration.py:281 For variant 'global', will try loading 'C:\ProgramData\pip\pip.ini'
DEBUG    pip._internal.configuration:configuration.py:281 For variant 'user', will try loading 'C:\Users\niko\AppData\Local\Temp\pytest-of-niko\pytest-11\popen-gw5\test_log_command_error0\home\pip\pip.ini'
DEBUG    pip._internal.configuration:configuration.py:281 For variant 'user', will try loading 'C:\Users\niko\AppData\Local\Temp\pytest-of-niko\pytest-11\popen-gw5\test_raise_broken_stdout0\home\AppData\Roaming\pip\pip.ini'
DEBUG    pip._internal.configuration:configuration.py:281 For variant 'site', will try loading 'c:\repos\pip\.tox\py38\pip.ini'
DEBUG    pip._internal.cli.parser:parser.py:199 Ignoring configuration key ':env:.use-feature' as it's value is empty.
DEBUG    pip._internal.cli.parser:parser.py:199 Ignoring configuration key ':env:.use-deprecated' as it's value is empty.
_________________________________________________________________ test_log_file_command_error _________________________________________________________________ 
[gw5] win32 -- Python 3.8.5 c:\repos\pip\.tox\py38\scripts\python.exe

fixed_time = None, tmpdir = Path('C:\\Users\\niko\\AppData\\Local\\Temp\\pytest-of-niko\\pytest-11\\popen-gw5\\test_log_file_command_error0')

    def test_log_file_command_error(fixed_time, tmpdir):
        """Test the --log-file option logs (when there's an error)."""
        cmd = FakeCommand(error=True)
        log_file_path = tmpdir.joinpath('log_file')
        cmd.main(['fake', '--log-file', log_file_path])
        with open(log_file_path) as f:
>           assert f.read().startswith('2019-01-17T06:00:37,040 fake')
E           assert False
E            +  where False = <built-in method startswith of str object at 0x000001DE118251C0>('2019-01-17T06:00:37,040 fake')
E            +    where <built-in method startswith of str object at 0x000001DE118251C0> = '2019-01-17T08:00:37,040 fake\n2019-01-17T08:00:37,040 ERROR: Exception:\n2019-01-17T08:00:37,040 Traceback (most rece...nd.py", line 27, in run_func\n2019-01-17T08:00:37,040     raise SystemExit(1)\n2019-01-17T08:00:37,040 SystemExit: 1\n'.startswith
E            +      where '2019-01-17T08:00:37,040 fake\n2019-01-17T08:00:37,040 ERROR: Exception:\n2019-01-17T08:00:37,040 Traceback (most rece...nd.py", line 
27, in run_func\n2019-01-17T08:00:37,040     raise SystemExit(1)\n2019-01-17T08:00:37,040 SystemExit: 1\n' = <built-in method read of _io.TextIOWrapper object at 0x000001DE144EF930>()
E            +        where <built-in method read of _io.TextIOWrapper object at 0x000001DE144EF930> = <_io.TextIOWrapper name=Path('C:\\Users\\niko\\AppData\\Local\\Temp\\pytest-of-niko\\pytest-11\\popen-gw5\\test_log_file_command_error0\\log_file') mode='r' encoding='cp1252'>.read

tests\unit\test_base_command.py:123: AssertionError
-------------------------------------------------------------------- Captured stdout call --------------------------------------------------------------------- 
fake
-------------------------------------------------------------------- Captured stderr call --------------------------------------------------------------------- 
ERROR: Exception:
Traceback (most recent call last):
  File "c:\repos\pip\.tox\py38\lib\site-packages\pip\_internal\cli\base_command.py", line 180, in _main
    status = self.run(options, args)
  File "C:\repos\pip\tests\unit\test_base_command.py", line 40, in run
    return self.run_func()
  File "C:\repos\pip\tests\unit\test_base_command.py", line 27, in run_func
    raise SystemExit(1)
SystemExit: 1
---------------------------------------------------------------------- Captured log call ---------------------------------------------------------------------- 
DEBUG    pip._internal.configuration:configuration.py:281 For variant 'global', will try loading 'C:\ProgramData\pip\pip.ini'
DEBUG    pip._internal.configuration:configuration.py:281 For variant 'user', will try loading 'C:\Users\niko\AppData\Local\Temp\pytest-of-niko\pytest-11\popen-gw5\test_log_file_command_error0\home\pip\pip.ini'
DEBUG    pip._internal.configuration:configuration.py:281 For variant 'user', will try loading 'C:\Users\niko\AppData\Local\Temp\pytest-of-niko\pytest-11\popen-gw5\test_raise_broken_stdout0\home\AppData\Roaming\pip\pip.ini'
DEBUG    pip._internal.configuration:configuration.py:281 For variant 'site', will try loading 'c:\repos\pip\.tox\py38\pip.ini'
DEBUG    pip._internal.cli.parser:parser.py:199 Ignoring configuration key ':env:.use-feature' as it's value is empty.
DEBUG    pip._internal.cli.parser:parser.py:199 Ignoring configuration key ':env:.use-deprecated' as it's value is empty.
____________________ TestIndentingFormatter.test_format_with_timestamp[INFO-2019-01-17T06:00:37,040 hello\n2019-01-17T06:00:37,040 world] _____________________
[gw7] win32 -- Python 3.8.5 c:\repos\pip\.tox\py38\scripts\python.exe

self = <tests.unit.test_logging.TestIndentingFormatter object at 0x0000020548CDC6D0>, level_name = 'INFO'
expected = '2019-01-17T06:00:37,040 hello\n2019-01-17T06:00:37,040 world', utc = None

    @pytest.mark.parametrize('level_name, expected', [
        ('INFO',
         '2019-01-17T06:00:37,040 hello\n'
         '2019-01-17T06:00:37,040 world'),
        ('WARNING',
         '2019-01-17T06:00:37,040 WARNING: hello\n'
         '2019-01-17T06:00:37,040 world'),
    ])
    def test_format_with_timestamp(self, level_name, expected, utc):
        record = self.make_record('hello\nworld', level_name=level_name)
        f = IndentingFormatter(fmt="%(message)s", add_timestamp=True)
>       assert f.format(record) == expected
E       AssertionError: assert '2019-01-17T0...:37,040 world' == '2019-01-17T0...:37,040 world'
E         - 2019-01-17T06:00:37,040 hello
E         ?             ^
E         + 2019-01-17T08:00:37,040 hello
E         ?             ^
E         - 2019-01-17T06:00:37,040 world
E         ?             ^
E         + 2019-01-17T08:00:37,040 world...
E
E         ...Full output truncated (2 lines hidden), use '-vv' to show

tests\unit\test_logging.py:61: AssertionError
______________ TestIndentingFormatter.test_format_with_timestamp[WARNING-2019-01-17T06:00:37,040 WARNING: hello\n2019-01-17T06:00:37,040 world] _______________ 
[gw7] win32 -- Python 3.8.5 c:\repos\pip\.tox\py38\scripts\python.exe

self = <tests.unit.test_logging.TestIndentingFormatter object at 0x0000020548CEEE20>, level_name = 'WARNING'
expected = '2019-01-17T06:00:37,040 WARNING: hello\n2019-01-17T06:00:37,040 world', utc = None

    @pytest.mark.parametrize('level_name, expected', [
        ('INFO',
         '2019-01-17T06:00:37,040 hello\n'
         '2019-01-17T06:00:37,040 world'),
        ('WARNING',
         '2019-01-17T06:00:37,040 WARNING: hello\n'
         '2019-01-17T06:00:37,040 world'),
    ])
    def test_format_with_timestamp(self, level_name, expected, utc):
        record = self.make_record('hello\nworld', level_name=level_name)
        f = IndentingFormatter(fmt="%(message)s", add_timestamp=True)
>       assert f.format(record) == expected
E       AssertionError: assert '2019-01-17T0...:37,040 world' == '2019-01-17T0...:37,040 world'
E         - 2019-01-17T06:00:37,040 WARNING: hello
E         ?             ^
E         + 2019-01-17T08:00:37,040 WARNING: hello
E         ?             ^
E         - 2019-01-17T06:00:37,040 world
E         ?             ^
E         + 2019-01-17T08:00:37,040 world...
E
E         ...Full output truncated (2 lines hidden), use '-vv' to show

tests\unit\test_logging.py:61: AssertionError
====================================================================== warnings summary ======================================================================= 
.tox\py38\lib\site-packages\pip\_vendor\packaging\version.py:127: 1080 warnings
tests/functional/test_uninstall.py: 60 warnings
tests/unit/test_req.py: 480 warnings
tests/unit/test_finder.py: 2 warnings
tests/functional/test_pep517.py: 2 warnings
  c:\repos\pip\.tox\py38\lib\site-packages\pip\_vendor\packaging\version.py:127: DeprecationWarning: Creating a LegacyVersion has been deprecated and will be removed in the next major release
    warnings.warn(

tests/functional/test_install_wheel.py::test_wheel_install_fails_with_badly_encoded_metadata
  c:\python\python385-64\lib\zipfile.py:1517: UserWarning: Duplicate name: 'simple-0.1.0.dist-info/METADATA'
    return self._open_to_write(zinfo, force_zip64=force_zip64)

tests/unit/test_operations_prepare.py::Test_unpack_url::test_unpack_url_thats_a_dir
tests/unit/test_operations_prepare.py::test_unpack_url_excludes_expected_dirs[.nox]
tests/unit/test_operations_prepare.py::test_unpack_url_excludes_expected_dirs[.tox]
  c:\repos\pip\.tox\py38\lib\site-packages\pip\_internal\operations\prepare.py:218: PipDeprecationWarning: DEPRECATION: A future pip version will change local packages to be built in-place without first copying to a temporary directory. We recommend you use --use-feature=in-tree-build to test your packages with this new behavior before it becomes the default.
   pip 21.3 will remove support for this functionality. You can find discussion regarding this at https://github.com/pypa/pip/issues/7555.
    deprecated(

tests/unit/test_req_file.py::TestParseRequirements::test_install_requirements_with_options
  c:\repos\pip\.tox\py38\lib\site-packages\pip\_internal\req\req_file.py:193: UserWarning: Disabling all use of wheels due to the use of --build-option / --global-option / --install-option.
    cmdoptions.check_install_build_global(options, line.opts)

tests/unit/test_finder.py::test_finder_only_installs_data_require
  c:\repos\pip\.tox\py38\lib\site-packages\pip\_vendor\packaging\specifiers.py:283: DeprecationWarning: Creating a LegacyVersion has been deprecated and will be removed in the next major release
    warnings.warn(

-- Docs: https://docs.pytest.org/en/stable/warnings.html
=================================================================== short test summary info ===================================================================
SKIPPED [1] tests\functional\test_build_env.py:168: Incompatible with test venv
SKIPPED [1] tests\functional\test_configuration.py:21: Can't modify underlying file for any mode
SKIPPED [1] tests\functional\test_freeze.py:446: Mercurial is not available
SKIPPED [1] tests\functional\test_freeze.py:488: Bazaar is not available
SKIPPED [1] tests\functional\test_freeze.py:764: Incompatible with test venv
SKIPPED [1] tests\functional\test_freeze.py:352: Mercurial is not available
SKIPPED [1] tests\functional\test_install.py:356: Mercurial is not available
SKIPPED [1] tests\functional\test_install.py:345: Mercurial is not available
SKIPPED [2] tests\functional\test_freeze.py:525: Mercurial is not available
SKIPPED [1] tests\functional\test_freeze.py:797: Incompatible with test venv
SKIPPED [1] tests\functional\test_freeze.py:194: Subversion Admin is not available
SKIPPED [1] tests\functional\test_install.py:123: Incompatible with test venv
SKIPPED [1] tests\functional\test_install.py:528: Fails on new resolver
SKIPPED [1] tests\functional\test_install.py:261: Subversion Admin is not available
SKIPPED [1] tests\functional\test_install.py:380: Bazaar is not available
SKIPPED [1] tests\functional\test_install.py:369: Bazaar is not available
SKIPPED [1] tests\functional\test_install.py:597: condition: sys.platform == 'win32'
SKIPPED [1] tests\functional\test_install.py:755: Mercurial is not available
SKIPPED [1] tests\functional\test_install.py:1778: Incompatible with test venv
SKIPPED [1] tests\functional\test_install_user.py:106: Incompatible with test venv
SKIPPED [1] tests\functional\test_install_user.py:67: Incompatible with test venv
SKIPPED [1] tests\functional\test_install_user.py:163: Incompatible with test venv
SKIPPED [1] tests\functional\test_install_vcs_git.py:448: condition: sys.platform == 'win32'
SKIPPED [1] tests\functional\test_install_user.py:33: Incompatible with test venv
SKIPPED [1] tests\functional\test_install_user.py:232: Incompatible with test venv
SKIPPED [1] tests\functional\test_install_user.py:131: Incompatible with test venv
SKIPPED [1] tests\functional\test_install_reqs.py:162: Subversion Admin is not available
SKIPPED [1] tests\functional\test_install_reqs.py:287: Incompatible with test venv
SKIPPED [1] tests\functional\test_install_user.py:48: Subversion Admin is not available
SKIPPED [1] tests\functional\test_list.py:110: Incompatible with test venv
SKIPPED [1] tests\functional\test_install_wheel.py:328: Incompatible with test venv
SKIPPED [1] tests\functional\test_search.py:58: pip search test skipped
SKIPPED [1] tests\functional\test_search.py:72: Warehouse search behavior is different and no longer returns multiple results. See https://github.com/pypa/warehouse/issues/3717 for more information.
SKIPPED [1] tests\functional\test_search.py:93: pip search test skipped
SKIPPED [1] tests\functional\test_search.py:102: pip search test skipped
SKIPPED [1] tests\functional\test_search.py:116: pip search test skipped
SKIPPED [1] tests\functional\test_search.py:130: pip search test skipped
SKIPPED [1] tests\functional\test_search.py:140: pip search test skipped
SKIPPED [1] tests\functional\test_search.py:150: pip search test skipped
SKIPPED [1] tests\functional\test_search.py:179: pip search test skipped
SKIPPED [1] tests\functional\test_list.py:521: Incompatible with test venv
SKIPPED [1] tests\functional\test_wheel.py:306: The empty extension module does not work on Win
SKIPPED [1] tests\functional\test_install_user.py:194: Incompatible with test venv
SKIPPED [1] tests\unit\test_compat.py:21: condition: sys.platform == 'win32'
SKIPPED [1] tests\unit\test_compat.py:33: condition: not hasattr(os, 'O_NOFOLLOW')
SKIPPED [1] tests\unit\test_configuration.py:52: condition: sys.platform == 'win32'
SKIPPED [1] tests\unit\test_collector.py:276: condition: sys.platform == 'win32'
SKIPPED [1] tests\functional\test_uninstall.py:479: condition: sys.platform == 'win32'
SKIPPED [1] tests\unit\test_locations.py:99: Incompatible with venv
SKIPPED [1] tests\unit\test_locations.py:118: Incompatible with venv
SKIPPED [1] tests\unit\test_network_cache.py:33: condition: sys.platform == 'win32'
SKIPPED [1] tests\unit\test_network_cache.py:42: condition: sys.platform == 'win32'
SKIPPED [1] tests\unit\test_network_cache.py:49: condition: sys.platform == 'win32'
SKIPPED [1] tests\unit\test_operations_prepare.py:105: condition: sys.platform == 'win32'
SKIPPED [1] tests\unit\test_operations_prepare.py:124: condition: sys.platform == 'win32'
SKIPPED [1] tests\unit\test_req_install.py:17: condition: sys.platform == 'win32'
SKIPPED [1] tests\unit\test_req_uninstall.py:170: condition: sys.platform == 'win32'
SKIPPED [1] tests\unit\test_req_uninstall.py:196: condition: sys.platform == 'win32'
SKIPPED [1] tests\unit\test_req_uninstall.py:310: condition: sys.platform == 'win32'
SKIPPED [1] tests\unit\test_req_uninstall.py:342: condition: sys.platform == 'win32'
SKIPPED [1] tests\unit\test_urls.py:20: condition: sys.platform == 'win32'
SKIPPED [1] tests\unit\test_utils.py:587: condition: sys.platform == 'win32'
SKIPPED [1] tests\unit\test_utils.py:594: condition: sys.platform == 'win32'
SKIPPED [1] tests\functional\test_list.py:127: Incompatible with test venv
SKIPPED [1] tests\unit\test_utils.py:437: condition: sys.platform == 'win32'
SKIPPED [5] tests\unit\test_utils_filesystem.py:32: condition: sys.platform == 'win32'
SKIPPED [1] tests\unit\test_utils_filesystem.py:47: condition: sys.platform == 'win32'
SKIPPED [1] tests\unit\test_utils_subprocess.py:401: locale.getpreferredencoding() is not UTF-8
SKIPPED [1] tests\unit\test_utils_temp_dir.py:20: condition: sys.platform == 'win32'
SKIPPED [1] tests\unit\test_vcs.py:19: Subversion is only required under Travis
SKIPPED [1] tests\unit\test_vcs.py:425: Subversion Admin is not available
SKIPPED [1] tests\unit\test_vcs_mercurial.py:13: Mercurial is not available
SKIPPED [2] tests\unit\test_collector.py:299: condition: sys.platform == 'win32'
SKIPPED [1] tests\functional\test_uninstall_user.py:16: Incompatible with test venv
SKIPPED [2] tests\functional\test_uninstall_user.py: Incompatible with test venv
SKIPPED [1] tests\functional\test_vcs_bazaar.py:21: Bazaar is only required under Travis
SKIPPED [1] tests\functional\test_vcs_bazaar.py:29: Bazaar is not available
SKIPPED [1] tests\functional\test_vcs_bazaar.py:46: Bazaar is not available
SKIPPED [1] tests\functional\test_vcs_bazaar.py:71: Bazaar is not available
SKIPPED [1] tests\functional\test_new_resolver_user.py:9: Incompatible with test venv
SKIPPED [1] tests\functional\test_new_resolver_user.py:22: Incompatible with test venv
SKIPPED [1] tests\functional\test_new_resolver_user.py:47: Incompatible with test venv
SKIPPED [1] tests\functional\test_new_resolver_user.py:79: Incompatible with test venv
SKIPPED [1] tests\functional\test_new_resolver_user.py:121: Incompatible with test venv
SKIPPED [1] tests\functional\test_new_resolver_user.py:151: Incompatible with test venv
SKIPPED [1] tests\functional\test_new_resolver_user.py:183: Incompatible with test venv
SKIPPED [1] tests\functional\test_no_color.py:33: Unable to capture output using script: script --flush --quiet --return /tmp/pip-test-no-color.txt --command "pip uninstall  noSuchPackage"
SKIPPED [1] tests\functional\test_vcs_mercurial.py:7: Mercurial is not available
SKIPPED [1] tests\functional\test_vcs_subversion.py:8: Subversion Admin is not available
SKIPPED [1] tests\functional\test_vcs_subversion.py:20: Subversion Admin is not available
SKIPPED [1] tests\functional\test_wheel.py:123: condition: sys.platform == 'win32'
SKIPPED [1] tests\functional\test_uninstall.py:315: Subversion Admin is not available
SKIPPED [1] tests\functional\test_requests.py:4: Skipped
SKIPPED [1] tests\functional\test_uninstall.py:381: Subversion Admin is not available
SKIPPED [1] tests\unit\test_compat.py:13: condition: not hasattr(os, 'O_NOFOLLOW')
XFAIL tests/functional/test_freeze.py::test_freeze_exclude_editable
  xfail means editable is not in output
XFAIL tests/functional/test_install_cleanup.py::test_no_clean_option_blocks_cleaning_after_install
  The --build option was removed
XFAIL tests/functional/test_install_reqs.py::test_install_distribution_union_conflicting_extras
XFAIL tests/functional/test_install_extras.py::test_install_extra_merging[[extra1,extra2]-1.0]
XFAIL tests/unit/test_wheel.py::TestInstallUnpackedWheel::test_invalid_entrypoints_fail[console_scripts-hello = hello]
XFAIL tests/unit/test_wheel.py::TestInstallUnpackedWheel::test_invalid_entrypoints_fail[gui_scripts-hello = hello:]
XFAIL tests/unit/test_wheel.py::TestInstallUnpackedWheel::test_invalid_entrypoints_fail[console_scripts-hello = hello:]
XFAIL tests/unit/test_wheel.py::TestInstallUnpackedWheel::test_invalid_entrypoints_fail[gui_scripts-hello = hello]
XFAIL tests/functional/test_new_resolver.py::test_new_resolver_check_wheel_version_normalized[file_dot-meta_dash]
XFAIL tests/functional/test_new_resolver.py::test_new_resolver_check_wheel_version_normalized[file_underscore-meta_dash]
XPASS tests/functional/test_install_extras.py::test_install_extra_merging[[extra1]-2.0]
XPASS tests/functional/test_install_reqs.py::test_respect_order_in_requirements_file Unclear what this guarantee is for.
XPASS tests/functional/test_install_extras.py::test_install_extra_merging[[extra2]-1.0]
XPASS tests/unit/test_models_wheel.py::TestWheelFile::test_supported_multiarch_darwin packaging.tags changed behaviour in this area, and @pradyunsg decided as the release manager that this behaviour change is less critical than Big Sur support for pip 20.3. See https://github.com/pypa/packaging/pull/361 for further discussion.
XPASS tests/functional/test_wheel.py::test_no_clean_option_blocks_cleaning_after_wheel The --build option was removed
FAILED tests/unit/test_base_command.py::test_log_command_success - AssertionError: assert '2019-01-17T08:00:37,040 fake' == '2019-01-17T06:00:37,040 fake'
FAILED tests/unit/test_base_command.py::test_log_command_error - assert False
FAILED tests/unit/test_base_command.py::test_log_file_command_error - assert False
FAILED tests/unit/test_logging.py::TestIndentingFormatter::test_format_with_timestamp[INFO-2019-01-17T06:00:37,040 hello\n2019-01-17T06:00:37,040 world] - As...FAILED tests/unit/test_logging.py::TestIndentingFormatter::test_format_with_timestamp[WARNING-2019-01-17T06:00:37,040 WARNING: hello\n2019-01-17T06:00:37,040 world]
================================ 5 failed, 2027 passed, 102 skipped, 10 xfailed, 5 xpassed, 1630 warnings in 813.00s (0:13:32) ================================
ERROR: InvocationError for command 'C:\repos\pip\.tox\py38\Scripts\pytest.EXE' --use-venv -n auto (exited with code 1)
___________________________________________________________________________ summary ___________________________________________________________________________
ERROR:   py38: commands failed

@pradyunsg
Copy link
Member

pradyunsg commented Apr 3, 2021

@np-8 Thanks for posting the analysis here! This is super useful to know about, especially as I'm investigating #8273 right now. ^>^

Could you file a new bug report with the latest failures? Based on a quick look, this seems like bugs in the test suite that we should track and address. :)

@fohrloop
Copy link
Contributor Author

fohrloop commented Apr 3, 2021

Here you are! :) I try to create a test for the #9452 after running tests is possible without failures on some branch.

Comment on lines +547 to +548
link_pointer = normalize_path(os.path.normcase(fh.readline().strip()))
assert (link_pointer == dist_path), (
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

At this point, it’s probably better to use Path.resolve(strict=False) instead. These various path string functions should be removed eventually.

Copy link
Contributor Author

@fohrloop fohrloop May 9, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't have so much familiarity with the internals of pip so I really am not the best person to comment. Anyway, I did some testing on the Path.resolve with a folder that is also symlinked on Windows. C:\cases\myproj points to C:\Users\niko\Dropbox\myproj.

In [1]: from pathlib import Path

In [2]: mypath = Path(r'C:\cases\myproj')

In [3]: mypath.resolve()
Out[3]: WindowsPath('C:/Users/niko/Dropbox/myproj')

In [4]: mypath.resolve(strict=True)
Out[4]: WindowsPath('C:/Users/niko/Dropbox/myproj')

In [5]: mypath.resolve(strict=False)
Out[5]: WindowsPath('C:/Users/niko/Dropbox/myproj')

Did not see any difference with strict=True or strict=False. Which lines / objects you would change to use Path.resolve?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wanted something like

pathlib.Path(link_pointer).resolve(strict=False) == pathlib.Path(fh.readline().strip()).resolve(strict=False)

or

The difference between strict=False and True (the default) is only when the target does not exist; by default a FileNotFoundError is thrown in strict mode.

@pradyunsg
Copy link
Member

Closing since this has bitrotten.

@pradyunsg pradyunsg closed this Feb 25, 2022
@github-actions github-actions bot locked as resolved and limited conversation to collaborators Mar 13, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
needs rebase or merge PR has conflicts with current master S: awaiting response Waiting for a response/more information
Projects
None yet
Development

Successfully merging this pull request may close these issues.

AssertionError: Egg-link <package> does not match .. when using symbolic links
4 participants