PageRenderTime 42ms CodeModel.GetById 11ms RepoModel.GetById 0ms app.codeStats 0ms

/tests/functional/test_uninstall.py

https://gitlab.com/mayakarya/pip
Python | 430 lines | 413 code | 7 blank | 10 comment | 0 complexity | 58a4be2a4a18580c604fb317ebc89b6d MD5 | raw file
  1. from __future__ import with_statement
  2. import textwrap
  3. import os
  4. import sys
  5. import pytest
  6. import pretend
  7. from os.path import join, normpath
  8. from tempfile import mkdtemp
  9. from tests.lib import assert_all_changes, pyversion
  10. from tests.lib.local_repos import local_repo, local_checkout
  11. from pip.req import InstallRequirement
  12. from pip.utils import rmtree
  13. @pytest.mark.network
  14. def test_simple_uninstall(script):
  15. """
  16. Test simple install and uninstall.
  17. """
  18. result = script.pip('install', 'INITools==0.2')
  19. assert join(script.site_packages, 'initools') in result.files_created, (
  20. sorted(result.files_created.keys())
  21. )
  22. # the import forces the generation of __pycache__ if the version of python
  23. # supports it
  24. script.run('python', '-c', "import initools")
  25. result2 = script.pip('uninstall', 'INITools', '-y')
  26. assert_all_changes(result, result2, [script.venv / 'build', 'cache'])
  27. def test_simple_uninstall_distutils(script):
  28. """
  29. Test simple install and uninstall.
  30. """
  31. script.scratch_path.join("distutils_install").mkdir()
  32. pkg_path = script.scratch_path / 'distutils_install'
  33. pkg_path.join("setup.py").write(textwrap.dedent("""
  34. from distutils.core import setup
  35. setup(
  36. name='distutils-install',
  37. version='0.1',
  38. )
  39. """))
  40. result = script.run('python', pkg_path / 'setup.py', 'install')
  41. result = script.pip('list', '--format=legacy')
  42. assert "distutils-install (0.1)" in result.stdout
  43. script.pip('uninstall', 'distutils_install', '-y', expect_stderr=True)
  44. result2 = script.pip('list', '--format=legacy')
  45. assert "distutils-install (0.1)" not in result2.stdout
  46. @pytest.mark.network
  47. def test_uninstall_with_scripts(script):
  48. """
  49. Uninstall an easy_installed package with scripts.
  50. """
  51. result = script.run('easy_install', 'PyLogo', expect_stderr=True)
  52. easy_install_pth = script.site_packages / 'easy-install.pth'
  53. pylogo = sys.platform == 'win32' and 'pylogo' or 'PyLogo'
  54. assert(pylogo in result.files_updated[easy_install_pth].bytes)
  55. result2 = script.pip('uninstall', 'pylogo', '-y')
  56. assert_all_changes(
  57. result,
  58. result2,
  59. [script.venv / 'build', 'cache', easy_install_pth],
  60. )
  61. @pytest.mark.network
  62. def test_uninstall_easy_install_after_import(script):
  63. """
  64. Uninstall an easy_installed package after it's been imported
  65. """
  66. result = script.run('easy_install', 'INITools==0.2', expect_stderr=True)
  67. # the import forces the generation of __pycache__ if the version of python
  68. # supports it
  69. script.run('python', '-c', "import initools")
  70. result2 = script.pip('uninstall', 'INITools', '-y')
  71. assert_all_changes(
  72. result,
  73. result2,
  74. [
  75. script.venv / 'build',
  76. 'cache',
  77. script.site_packages / 'easy-install.pth',
  78. ]
  79. )
  80. @pytest.mark.network
  81. def test_uninstall_namespace_package(script):
  82. """
  83. Uninstall a distribution with a namespace package without clobbering
  84. the namespace and everything in it.
  85. """
  86. result = script.pip('install', 'pd.requires==0.0.3', expect_error=True)
  87. assert join(script.site_packages, 'pd') in result.files_created, (
  88. sorted(result.files_created.keys())
  89. )
  90. result2 = script.pip('uninstall', 'pd.find', '-y', expect_error=True)
  91. assert join(script.site_packages, 'pd') not in result2.files_deleted, (
  92. sorted(result2.files_deleted.keys())
  93. )
  94. assert join(script.site_packages, 'pd', 'find') in result2.files_deleted, (
  95. sorted(result2.files_deleted.keys())
  96. )
  97. def test_uninstall_overlapping_package(script, data):
  98. """
  99. Uninstalling a distribution that adds modules to a pre-existing package
  100. should only remove those added modules, not the rest of the existing
  101. package.
  102. See: GitHub issue #355 (pip uninstall removes things it didn't install)
  103. """
  104. parent_pkg = data.packages.join("parent-0.1.tar.gz")
  105. child_pkg = data.packages.join("child-0.1.tar.gz")
  106. result1 = script.pip('install', parent_pkg, expect_error=False)
  107. assert join(script.site_packages, 'parent') in result1.files_created, (
  108. sorted(result1.files_created.keys())
  109. )
  110. result2 = script.pip('install', child_pkg, expect_error=False)
  111. assert join(script.site_packages, 'child') in result2.files_created, (
  112. sorted(result2.files_created.keys())
  113. )
  114. assert normpath(
  115. join(script.site_packages, 'parent/plugins/child_plugin.py')
  116. ) in result2.files_created, sorted(result2.files_created.keys())
  117. # The import forces the generation of __pycache__ if the version of python
  118. # supports it
  119. script.run('python', '-c', "import parent.plugins.child_plugin, child")
  120. result3 = script.pip('uninstall', '-y', 'child', expect_error=False)
  121. assert join(script.site_packages, 'child') in result3.files_deleted, (
  122. sorted(result3.files_created.keys())
  123. )
  124. assert normpath(
  125. join(script.site_packages, 'parent/plugins/child_plugin.py')
  126. ) in result3.files_deleted, sorted(result3.files_deleted.keys())
  127. assert join(script.site_packages, 'parent') not in result3.files_deleted, (
  128. sorted(result3.files_deleted.keys())
  129. )
  130. # Additional check: uninstalling 'child' should return things to the
  131. # previous state, without unintended side effects.
  132. assert_all_changes(result2, result3, [])
  133. def test_uninstall_entry_point(script):
  134. """
  135. Test uninstall package with two or more entry points in the same section,
  136. whose name contain a colon.
  137. """
  138. script.scratch_path.join("ep_install").mkdir()
  139. pkg_path = script.scratch_path / 'ep_install'
  140. pkg_path.join("setup.py").write(textwrap.dedent("""
  141. from setuptools import setup
  142. setup(
  143. name='ep-install',
  144. version='0.1',
  145. entry_points={"pip_test.ep":
  146. ["ep:name1 = distutils_install",
  147. "ep:name2 = distutils_install"]
  148. }
  149. )
  150. """))
  151. result = script.pip('install', pkg_path)
  152. result = script.pip('list', '--format=legacy')
  153. assert "ep-install (0.1)" in result.stdout
  154. script.pip('uninstall', 'ep_install', '-y')
  155. result2 = script.pip('list', '--format=legacy')
  156. assert "ep-install (0.1)" not in result2.stdout
  157. @pytest.mark.network
  158. def test_uninstall_console_scripts(script):
  159. """
  160. Test uninstalling a package with more files (console_script entry points,
  161. extra directories).
  162. """
  163. args = ['install']
  164. args.append('discover')
  165. result = script.pip(*args, **{"expect_error": True})
  166. assert script.bin / 'discover' + script.exe in result.files_created, (
  167. sorted(result.files_created.keys())
  168. )
  169. result2 = script.pip('uninstall', 'discover', '-y', expect_error=True)
  170. assert_all_changes(result, result2, [script.venv / 'build', 'cache'])
  171. @pytest.mark.network
  172. def test_uninstall_easy_installed_console_scripts(script):
  173. """
  174. Test uninstalling package with console_scripts that is easy_installed.
  175. """
  176. args = ['easy_install']
  177. args.append('discover')
  178. result = script.run(*args, **{"expect_stderr": True})
  179. assert script.bin / 'discover' + script.exe in result.files_created, (
  180. sorted(result.files_created.keys())
  181. )
  182. result2 = script.pip('uninstall', 'discover', '-y')
  183. assert_all_changes(
  184. result,
  185. result2,
  186. [
  187. script.venv / 'build',
  188. 'cache',
  189. script.site_packages / 'easy-install.pth',
  190. ]
  191. )
  192. @pytest.mark.network
  193. def test_uninstall_editable_from_svn(script, tmpdir):
  194. """
  195. Test uninstalling an editable installation from svn.
  196. """
  197. result = script.pip(
  198. 'install', '-e',
  199. '%s#egg=initools-dev' % local_checkout(
  200. 'svn+http://svn.colorstudy.com/INITools/trunk',
  201. tmpdir.join("cache"),
  202. ),
  203. )
  204. result.assert_installed('INITools')
  205. result2 = script.pip('uninstall', '-y', 'initools')
  206. assert (script.venv / 'src' / 'initools' in result2.files_after)
  207. assert_all_changes(
  208. result,
  209. result2,
  210. [
  211. script.venv / 'src',
  212. script.venv / 'build',
  213. script.site_packages / 'easy-install.pth'
  214. ],
  215. )
  216. @pytest.mark.network
  217. def test_uninstall_editable_with_source_outside_venv(script, tmpdir):
  218. """
  219. Test uninstalling editable install from existing source outside the venv.
  220. """
  221. cache_dir = tmpdir.join("cache")
  222. try:
  223. temp = mkdtemp()
  224. tmpdir = join(temp, 'pip-test-package')
  225. _test_uninstall_editable_with_source_outside_venv(
  226. script,
  227. tmpdir,
  228. cache_dir,
  229. )
  230. finally:
  231. rmtree(temp)
  232. def _test_uninstall_editable_with_source_outside_venv(
  233. script, tmpdir, cache_dir):
  234. result = script.run(
  235. 'git', 'clone',
  236. local_repo(
  237. 'git+git://github.com/pypa/pip-test-package',
  238. cache_dir,
  239. ),
  240. tmpdir,
  241. expect_stderr=True,
  242. )
  243. result2 = script.pip('install', '-e', tmpdir)
  244. assert join(
  245. script.site_packages, 'pip-test-package.egg-link'
  246. ) in result2.files_created, list(result2.files_created.keys())
  247. result3 = script.pip('uninstall', '-y',
  248. 'pip-test-package', expect_error=True)
  249. assert_all_changes(
  250. result,
  251. result3,
  252. [script.venv / 'build', script.site_packages / 'easy-install.pth'],
  253. )
  254. @pytest.mark.network
  255. def test_uninstall_from_reqs_file(script, tmpdir):
  256. """
  257. Test uninstall from a requirements file.
  258. """
  259. script.scratch_path.join("test-req.txt").write(
  260. textwrap.dedent("""
  261. -e %s#egg=initools-dev
  262. # and something else to test out:
  263. PyLogo<0.4
  264. """) %
  265. local_checkout(
  266. 'svn+http://svn.colorstudy.com/INITools/trunk',
  267. tmpdir.join("cache")
  268. )
  269. )
  270. result = script.pip('install', '-r', 'test-req.txt')
  271. script.scratch_path.join("test-req.txt").write(
  272. textwrap.dedent("""
  273. # -f, -i, and --extra-index-url should all be ignored by uninstall
  274. -f http://www.example.com
  275. -i http://www.example.com
  276. --extra-index-url http://www.example.com
  277. -e %s#egg=initools-dev
  278. # and something else to test out:
  279. PyLogo<0.4
  280. """) %
  281. local_checkout(
  282. 'svn+http://svn.colorstudy.com/INITools/trunk',
  283. tmpdir.join("cache")
  284. )
  285. )
  286. result2 = script.pip('uninstall', '-r', 'test-req.txt', '-y')
  287. assert_all_changes(
  288. result,
  289. result2,
  290. [
  291. script.venv / 'build',
  292. script.venv / 'src',
  293. script.scratch / 'test-req.txt',
  294. script.site_packages / 'easy-install.pth',
  295. ],
  296. )
  297. def test_uninstall_as_egg(script, data):
  298. """
  299. Test uninstall package installed as egg.
  300. """
  301. to_install = data.packages.join("FSPkg")
  302. result = script.pip('install', to_install, '--egg', expect_error=False)
  303. fspkg_folder = script.site_packages / 'fspkg'
  304. egg_folder = script.site_packages / 'FSPkg-0.1.dev0-py%s.egg' % pyversion
  305. assert fspkg_folder not in result.files_created, str(result.stdout)
  306. assert egg_folder in result.files_created, str(result)
  307. result2 = script.pip('uninstall', 'FSPkg', '-y')
  308. assert_all_changes(
  309. result,
  310. result2,
  311. [
  312. script.venv / 'build',
  313. 'cache',
  314. script.site_packages / 'easy-install.pth',
  315. ],
  316. )
  317. def test_uninstallpathset_no_paths(caplog):
  318. """
  319. Test UninstallPathSet logs notification when there are no paths to
  320. uninstall
  321. """
  322. from pip.req.req_uninstall import UninstallPathSet
  323. from pkg_resources import get_distribution
  324. test_dist = get_distribution('pip')
  325. uninstall_set = UninstallPathSet(test_dist)
  326. uninstall_set.remove() # with no files added to set
  327. assert (
  328. "Can't uninstall 'pip'. No files were found to uninstall."
  329. in caplog.text()
  330. )
  331. def test_uninstall_non_local_distutils(caplog, monkeypatch, tmpdir):
  332. einfo = tmpdir.join("thing-1.0.egg-info")
  333. with open(einfo, "wb"):
  334. pass
  335. dist = pretend.stub(
  336. key="thing",
  337. project_name="thing",
  338. egg_info=einfo,
  339. location=einfo,
  340. _provider=pretend.stub(),
  341. )
  342. get_dist = pretend.call_recorder(lambda x: dist)
  343. monkeypatch.setattr("pip._vendor.pkg_resources.get_distribution", get_dist)
  344. req = InstallRequirement.from_line("thing")
  345. req.uninstall()
  346. assert os.path.exists(einfo)
  347. def test_uninstall_wheel(script, data):
  348. """
  349. Test uninstalling a wheel
  350. """
  351. package = data.packages.join("simple.dist-0.1-py2.py3-none-any.whl")
  352. result = script.pip('install', package, '--no-index')
  353. dist_info_folder = script.site_packages / 'simple.dist-0.1.dist-info'
  354. assert dist_info_folder in result.files_created
  355. result2 = script.pip('uninstall', 'simple.dist', '-y')
  356. assert_all_changes(result, result2, [])
  357. def test_uninstall_setuptools_develop_install(script, data):
  358. """Try uninstall after setup.py develop followed of setup.py install"""
  359. pkg_path = data.packages.join("FSPkg")
  360. script.run('python', 'setup.py', 'develop',
  361. expect_stderr=True, cwd=pkg_path)
  362. script.run('python', 'setup.py', 'install',
  363. expect_stderr=True, cwd=pkg_path)
  364. list_result = script.pip('list', '--format=legacy')
  365. assert "FSPkg (0.1.dev0, " in list_result.stdout
  366. # Uninstall both develop and install
  367. uninstall = script.pip('uninstall', 'FSPkg', '-y')
  368. assert any(filename.endswith('.egg')
  369. for filename in uninstall.files_deleted.keys())
  370. uninstall2 = script.pip('uninstall', 'FSPkg', '-y')
  371. assert join(
  372. script.site_packages, 'FSPkg.egg-link'
  373. ) in uninstall2.files_deleted, list(uninstall2.files_deleted.keys())
  374. list_result2 = script.pip('list', '--format=legacy')
  375. assert "FSPkg" not in list_result2.stdout