test_spawn.py 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141
  1. """Tests for distutils.spawn."""
  2. import os
  3. import stat
  4. import sys
  5. import unittest.mock as mock
  6. from distutils.errors import DistutilsExecError
  7. from distutils.spawn import find_executable, spawn
  8. from distutils.tests import support
  9. import path
  10. import pytest
  11. from test.support import unix_shell
  12. from .compat import py39 as os_helper
  13. class TestSpawn(support.TempdirManager):
  14. @pytest.mark.skipif("os.name not in ('nt', 'posix')")
  15. def test_spawn(self):
  16. tmpdir = self.mkdtemp()
  17. # creating something executable
  18. # through the shell that returns 1
  19. if sys.platform != 'win32':
  20. exe = os.path.join(tmpdir, 'foo.sh')
  21. self.write_file(exe, f'#!{unix_shell}\nexit 1')
  22. else:
  23. exe = os.path.join(tmpdir, 'foo.bat')
  24. self.write_file(exe, 'exit 1')
  25. os.chmod(exe, 0o777)
  26. with pytest.raises(DistutilsExecError):
  27. spawn([exe])
  28. # now something that works
  29. if sys.platform != 'win32':
  30. exe = os.path.join(tmpdir, 'foo.sh')
  31. self.write_file(exe, f'#!{unix_shell}\nexit 0')
  32. else:
  33. exe = os.path.join(tmpdir, 'foo.bat')
  34. self.write_file(exe, 'exit 0')
  35. os.chmod(exe, 0o777)
  36. spawn([exe]) # should work without any error
  37. def test_find_executable(self, tmp_path):
  38. program_path = self._make_executable(tmp_path, '.exe')
  39. program = program_path.name
  40. program_noeext = program_path.with_suffix('').name
  41. filename = str(program_path)
  42. tmp_dir = path.Path(tmp_path)
  43. # test path parameter
  44. rv = find_executable(program, path=tmp_dir)
  45. assert rv == filename
  46. if sys.platform == 'win32':
  47. # test without ".exe" extension
  48. rv = find_executable(program_noeext, path=tmp_dir)
  49. assert rv == filename
  50. # test find in the current directory
  51. with tmp_dir:
  52. rv = find_executable(program)
  53. assert rv == program
  54. # test non-existent program
  55. dont_exist_program = "dontexist_" + program
  56. rv = find_executable(dont_exist_program, path=tmp_dir)
  57. assert rv is None
  58. # PATH='': no match, except in the current directory
  59. with os_helper.EnvironmentVarGuard() as env:
  60. env['PATH'] = ''
  61. with (
  62. mock.patch(
  63. 'distutils.spawn.os.confstr', return_value=tmp_dir, create=True
  64. ),
  65. mock.patch('distutils.spawn.os.defpath', tmp_dir),
  66. ):
  67. rv = find_executable(program)
  68. assert rv is None
  69. # look in current directory
  70. with tmp_dir:
  71. rv = find_executable(program)
  72. assert rv == program
  73. # PATH=':': explicitly looks in the current directory
  74. with os_helper.EnvironmentVarGuard() as env:
  75. env['PATH'] = os.pathsep
  76. with (
  77. mock.patch('distutils.spawn.os.confstr', return_value='', create=True),
  78. mock.patch('distutils.spawn.os.defpath', ''),
  79. ):
  80. rv = find_executable(program)
  81. assert rv is None
  82. # look in current directory
  83. with tmp_dir:
  84. rv = find_executable(program)
  85. assert rv == program
  86. # missing PATH: test os.confstr("CS_PATH") and os.defpath
  87. with os_helper.EnvironmentVarGuard() as env:
  88. env.pop('PATH', None)
  89. # without confstr
  90. with (
  91. mock.patch(
  92. 'distutils.spawn.os.confstr', side_effect=ValueError, create=True
  93. ),
  94. mock.patch('distutils.spawn.os.defpath', tmp_dir),
  95. ):
  96. rv = find_executable(program)
  97. assert rv == filename
  98. # with confstr
  99. with (
  100. mock.patch(
  101. 'distutils.spawn.os.confstr', return_value=tmp_dir, create=True
  102. ),
  103. mock.patch('distutils.spawn.os.defpath', ''),
  104. ):
  105. rv = find_executable(program)
  106. assert rv == filename
  107. @staticmethod
  108. def _make_executable(tmp_path, ext):
  109. # Give the temporary program a suffix regardless of platform.
  110. # It's needed on Windows and not harmful on others.
  111. program = tmp_path.joinpath('program').with_suffix(ext)
  112. program.write_text("", encoding='utf-8')
  113. program.chmod(stat.S_IXUSR)
  114. return program
  115. def test_spawn_missing_exe(self):
  116. with pytest.raises(DistutilsExecError) as ctx:
  117. spawn(['does-not-exist'])
  118. assert "command 'does-not-exist' failed" in str(ctx.value)