test_config.py 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897
  1. import contextlib
  2. import configparser
  3. import pytest
  4. from distutils.errors import DistutilsOptionError, DistutilsFileError
  5. from mock import patch
  6. from setuptools.dist import Distribution, _Distribution
  7. from setuptools.config import ConfigHandler, read_configuration
  8. from .textwrap import DALS
  9. class ErrConfigHandler(ConfigHandler):
  10. """Erroneous handler. Fails to implement required methods."""
  11. def make_package_dir(name, base_dir, ns=False):
  12. dir_package = base_dir
  13. for dir_name in name.split('/'):
  14. dir_package = dir_package.mkdir(dir_name)
  15. init_file = None
  16. if not ns:
  17. init_file = dir_package.join('__init__.py')
  18. init_file.write('')
  19. return dir_package, init_file
  20. def fake_env(
  21. tmpdir, setup_cfg, setup_py=None,
  22. encoding='ascii', package_path='fake_package'):
  23. if setup_py is None:
  24. setup_py = (
  25. 'from setuptools import setup\n'
  26. 'setup()\n'
  27. )
  28. tmpdir.join('setup.py').write(setup_py)
  29. config = tmpdir.join('setup.cfg')
  30. config.write(setup_cfg.encode(encoding), mode='wb')
  31. package_dir, init_file = make_package_dir(package_path, tmpdir)
  32. init_file.write(
  33. 'VERSION = (1, 2, 3)\n'
  34. '\n'
  35. 'VERSION_MAJOR = 1'
  36. '\n'
  37. 'def get_version():\n'
  38. ' return [3, 4, 5, "dev"]\n'
  39. '\n'
  40. )
  41. return package_dir, config
  42. @contextlib.contextmanager
  43. def get_dist(tmpdir, kwargs_initial=None, parse=True):
  44. kwargs_initial = kwargs_initial or {}
  45. with tmpdir.as_cwd():
  46. dist = Distribution(kwargs_initial)
  47. dist.script_name = 'setup.py'
  48. parse and dist.parse_config_files()
  49. yield dist
  50. def test_parsers_implemented():
  51. with pytest.raises(NotImplementedError):
  52. handler = ErrConfigHandler(None, {})
  53. handler.parsers
  54. class TestConfigurationReader:
  55. def test_basic(self, tmpdir):
  56. _, config = fake_env(
  57. tmpdir,
  58. '[metadata]\n'
  59. 'version = 10.1.1\n'
  60. 'keywords = one, two\n'
  61. '\n'
  62. '[options]\n'
  63. 'scripts = bin/a.py, bin/b.py\n'
  64. )
  65. config_dict = read_configuration('%s' % config)
  66. assert config_dict['metadata']['version'] == '10.1.1'
  67. assert config_dict['metadata']['keywords'] == ['one', 'two']
  68. assert config_dict['options']['scripts'] == ['bin/a.py', 'bin/b.py']
  69. def test_no_config(self, tmpdir):
  70. with pytest.raises(DistutilsFileError):
  71. read_configuration('%s' % tmpdir.join('setup.cfg'))
  72. def test_ignore_errors(self, tmpdir):
  73. _, config = fake_env(
  74. tmpdir,
  75. '[metadata]\n'
  76. 'version = attr: none.VERSION\n'
  77. 'keywords = one, two\n'
  78. )
  79. with pytest.raises(ImportError):
  80. read_configuration('%s' % config)
  81. config_dict = read_configuration(
  82. '%s' % config, ignore_option_errors=True)
  83. assert config_dict['metadata']['keywords'] == ['one', 'two']
  84. assert 'version' not in config_dict['metadata']
  85. config.remove()
  86. class TestMetadata:
  87. def test_basic(self, tmpdir):
  88. fake_env(
  89. tmpdir,
  90. '[metadata]\n'
  91. 'version = 10.1.1\n'
  92. 'description = Some description\n'
  93. 'long_description_content_type = text/something\n'
  94. 'long_description = file: README\n'
  95. 'name = fake_name\n'
  96. 'keywords = one, two\n'
  97. 'provides = package, package.sub\n'
  98. 'license = otherlic\n'
  99. 'download_url = http://test.test.com/test/\n'
  100. 'maintainer_email = test@test.com\n'
  101. )
  102. tmpdir.join('README').write('readme contents\nline2')
  103. meta_initial = {
  104. # This will be used so `otherlic` won't replace it.
  105. 'license': 'BSD 3-Clause License',
  106. }
  107. with get_dist(tmpdir, meta_initial) as dist:
  108. metadata = dist.metadata
  109. assert metadata.version == '10.1.1'
  110. assert metadata.description == 'Some description'
  111. assert metadata.long_description_content_type == 'text/something'
  112. assert metadata.long_description == 'readme contents\nline2'
  113. assert metadata.provides == ['package', 'package.sub']
  114. assert metadata.license == 'BSD 3-Clause License'
  115. assert metadata.name == 'fake_name'
  116. assert metadata.keywords == ['one', 'two']
  117. assert metadata.download_url == 'http://test.test.com/test/'
  118. assert metadata.maintainer_email == 'test@test.com'
  119. def test_license_cfg(self, tmpdir):
  120. fake_env(
  121. tmpdir,
  122. DALS("""
  123. [metadata]
  124. name=foo
  125. version=0.0.1
  126. license=Apache 2.0
  127. """)
  128. )
  129. with get_dist(tmpdir) as dist:
  130. metadata = dist.metadata
  131. assert metadata.name == "foo"
  132. assert metadata.version == "0.0.1"
  133. assert metadata.license == "Apache 2.0"
  134. def test_file_mixed(self, tmpdir):
  135. fake_env(
  136. tmpdir,
  137. '[metadata]\n'
  138. 'long_description = file: README.rst, CHANGES.rst\n'
  139. '\n'
  140. )
  141. tmpdir.join('README.rst').write('readme contents\nline2')
  142. tmpdir.join('CHANGES.rst').write('changelog contents\nand stuff')
  143. with get_dist(tmpdir) as dist:
  144. assert dist.metadata.long_description == (
  145. 'readme contents\nline2\n'
  146. 'changelog contents\nand stuff'
  147. )
  148. def test_file_sandboxed(self, tmpdir):
  149. fake_env(
  150. tmpdir,
  151. '[metadata]\n'
  152. 'long_description = file: ../../README\n'
  153. )
  154. with get_dist(tmpdir, parse=False) as dist:
  155. with pytest.raises(DistutilsOptionError):
  156. dist.parse_config_files() # file: out of sandbox
  157. def test_aliases(self, tmpdir):
  158. fake_env(
  159. tmpdir,
  160. '[metadata]\n'
  161. 'author-email = test@test.com\n'
  162. 'home-page = http://test.test.com/test/\n'
  163. 'summary = Short summary\n'
  164. 'platform = a, b\n'
  165. 'classifier =\n'
  166. ' Framework :: Django\n'
  167. ' Programming Language :: Python :: 3.5\n'
  168. )
  169. with get_dist(tmpdir) as dist:
  170. metadata = dist.metadata
  171. assert metadata.author_email == 'test@test.com'
  172. assert metadata.url == 'http://test.test.com/test/'
  173. assert metadata.description == 'Short summary'
  174. assert metadata.platforms == ['a', 'b']
  175. assert metadata.classifiers == [
  176. 'Framework :: Django',
  177. 'Programming Language :: Python :: 3.5',
  178. ]
  179. def test_multiline(self, tmpdir):
  180. fake_env(
  181. tmpdir,
  182. '[metadata]\n'
  183. 'name = fake_name\n'
  184. 'keywords =\n'
  185. ' one\n'
  186. ' two\n'
  187. 'classifiers =\n'
  188. ' Framework :: Django\n'
  189. ' Programming Language :: Python :: 3.5\n'
  190. )
  191. with get_dist(tmpdir) as dist:
  192. metadata = dist.metadata
  193. assert metadata.keywords == ['one', 'two']
  194. assert metadata.classifiers == [
  195. 'Framework :: Django',
  196. 'Programming Language :: Python :: 3.5',
  197. ]
  198. def test_dict(self, tmpdir):
  199. fake_env(
  200. tmpdir,
  201. '[metadata]\n'
  202. 'project_urls =\n'
  203. ' Link One = https://example.com/one/\n'
  204. ' Link Two = https://example.com/two/\n'
  205. )
  206. with get_dist(tmpdir) as dist:
  207. metadata = dist.metadata
  208. assert metadata.project_urls == {
  209. 'Link One': 'https://example.com/one/',
  210. 'Link Two': 'https://example.com/two/',
  211. }
  212. def test_version(self, tmpdir):
  213. package_dir, config = fake_env(
  214. tmpdir,
  215. '[metadata]\n'
  216. 'version = attr: fake_package.VERSION\n'
  217. )
  218. sub_a = package_dir.mkdir('subpkg_a')
  219. sub_a.join('__init__.py').write('')
  220. sub_a.join('mod.py').write('VERSION = (2016, 11, 26)')
  221. sub_b = package_dir.mkdir('subpkg_b')
  222. sub_b.join('__init__.py').write('')
  223. sub_b.join('mod.py').write(
  224. 'import third_party_module\n'
  225. 'VERSION = (2016, 11, 26)'
  226. )
  227. with get_dist(tmpdir) as dist:
  228. assert dist.metadata.version == '1.2.3'
  229. config.write(
  230. '[metadata]\n'
  231. 'version = attr: fake_package.get_version\n'
  232. )
  233. with get_dist(tmpdir) as dist:
  234. assert dist.metadata.version == '3.4.5.dev'
  235. config.write(
  236. '[metadata]\n'
  237. 'version = attr: fake_package.VERSION_MAJOR\n'
  238. )
  239. with get_dist(tmpdir) as dist:
  240. assert dist.metadata.version == '1'
  241. config.write(
  242. '[metadata]\n'
  243. 'version = attr: fake_package.subpkg_a.mod.VERSION\n'
  244. )
  245. with get_dist(tmpdir) as dist:
  246. assert dist.metadata.version == '2016.11.26'
  247. config.write(
  248. '[metadata]\n'
  249. 'version = attr: fake_package.subpkg_b.mod.VERSION\n'
  250. )
  251. with get_dist(tmpdir) as dist:
  252. assert dist.metadata.version == '2016.11.26'
  253. def test_version_file(self, tmpdir):
  254. _, config = fake_env(
  255. tmpdir,
  256. '[metadata]\n'
  257. 'version = file: fake_package/version.txt\n'
  258. )
  259. tmpdir.join('fake_package', 'version.txt').write('1.2.3\n')
  260. with get_dist(tmpdir) as dist:
  261. assert dist.metadata.version == '1.2.3'
  262. tmpdir.join('fake_package', 'version.txt').write('1.2.3\n4.5.6\n')
  263. with pytest.raises(DistutilsOptionError):
  264. with get_dist(tmpdir) as dist:
  265. dist.metadata.version
  266. def test_version_with_package_dir_simple(self, tmpdir):
  267. _, config = fake_env(
  268. tmpdir,
  269. '[metadata]\n'
  270. 'version = attr: fake_package_simple.VERSION\n'
  271. '[options]\n'
  272. 'package_dir =\n'
  273. ' = src\n',
  274. package_path='src/fake_package_simple'
  275. )
  276. with get_dist(tmpdir) as dist:
  277. assert dist.metadata.version == '1.2.3'
  278. def test_version_with_package_dir_rename(self, tmpdir):
  279. _, config = fake_env(
  280. tmpdir,
  281. '[metadata]\n'
  282. 'version = attr: fake_package_rename.VERSION\n'
  283. '[options]\n'
  284. 'package_dir =\n'
  285. ' fake_package_rename = fake_dir\n',
  286. package_path='fake_dir'
  287. )
  288. with get_dist(tmpdir) as dist:
  289. assert dist.metadata.version == '1.2.3'
  290. def test_version_with_package_dir_complex(self, tmpdir):
  291. _, config = fake_env(
  292. tmpdir,
  293. '[metadata]\n'
  294. 'version = attr: fake_package_complex.VERSION\n'
  295. '[options]\n'
  296. 'package_dir =\n'
  297. ' fake_package_complex = src/fake_dir\n',
  298. package_path='src/fake_dir'
  299. )
  300. with get_dist(tmpdir) as dist:
  301. assert dist.metadata.version == '1.2.3'
  302. def test_unknown_meta_item(self, tmpdir):
  303. fake_env(
  304. tmpdir,
  305. '[metadata]\n'
  306. 'name = fake_name\n'
  307. 'unknown = some\n'
  308. )
  309. with get_dist(tmpdir, parse=False) as dist:
  310. dist.parse_config_files() # Skip unknown.
  311. def test_usupported_section(self, tmpdir):
  312. fake_env(
  313. tmpdir,
  314. '[metadata.some]\n'
  315. 'key = val\n'
  316. )
  317. with get_dist(tmpdir, parse=False) as dist:
  318. with pytest.raises(DistutilsOptionError):
  319. dist.parse_config_files()
  320. def test_classifiers(self, tmpdir):
  321. expected = set([
  322. 'Framework :: Django',
  323. 'Programming Language :: Python :: 3',
  324. 'Programming Language :: Python :: 3.5',
  325. ])
  326. # From file.
  327. _, config = fake_env(
  328. tmpdir,
  329. '[metadata]\n'
  330. 'classifiers = file: classifiers\n'
  331. )
  332. tmpdir.join('classifiers').write(
  333. 'Framework :: Django\n'
  334. 'Programming Language :: Python :: 3\n'
  335. 'Programming Language :: Python :: 3.5\n'
  336. )
  337. with get_dist(tmpdir) as dist:
  338. assert set(dist.metadata.classifiers) == expected
  339. # From list notation
  340. config.write(
  341. '[metadata]\n'
  342. 'classifiers =\n'
  343. ' Framework :: Django\n'
  344. ' Programming Language :: Python :: 3\n'
  345. ' Programming Language :: Python :: 3.5\n'
  346. )
  347. with get_dist(tmpdir) as dist:
  348. assert set(dist.metadata.classifiers) == expected
  349. def test_deprecated_config_handlers(self, tmpdir):
  350. fake_env(
  351. tmpdir,
  352. '[metadata]\n'
  353. 'version = 10.1.1\n'
  354. 'description = Some description\n'
  355. 'requires = some, requirement\n'
  356. )
  357. with pytest.deprecated_call():
  358. with get_dist(tmpdir) as dist:
  359. metadata = dist.metadata
  360. assert metadata.version == '10.1.1'
  361. assert metadata.description == 'Some description'
  362. assert metadata.requires == ['some', 'requirement']
  363. def test_interpolation(self, tmpdir):
  364. fake_env(
  365. tmpdir,
  366. '[metadata]\n'
  367. 'description = %(message)s\n'
  368. )
  369. with pytest.raises(configparser.InterpolationMissingOptionError):
  370. with get_dist(tmpdir):
  371. pass
  372. def test_non_ascii_1(self, tmpdir):
  373. fake_env(
  374. tmpdir,
  375. '[metadata]\n'
  376. 'description = éàïôñ\n',
  377. encoding='utf-8'
  378. )
  379. with get_dist(tmpdir):
  380. pass
  381. def test_non_ascii_3(self, tmpdir):
  382. fake_env(
  383. tmpdir,
  384. '\n'
  385. '# -*- coding: invalid\n'
  386. )
  387. with get_dist(tmpdir):
  388. pass
  389. def test_non_ascii_4(self, tmpdir):
  390. fake_env(
  391. tmpdir,
  392. '# -*- coding: utf-8\n'
  393. '[metadata]\n'
  394. 'description = éàïôñ\n',
  395. encoding='utf-8'
  396. )
  397. with get_dist(tmpdir) as dist:
  398. assert dist.metadata.description == 'éàïôñ'
  399. def test_not_utf8(self, tmpdir):
  400. """
  401. Config files encoded not in UTF-8 will fail
  402. """
  403. fake_env(
  404. tmpdir,
  405. '# vim: set fileencoding=iso-8859-15 :\n'
  406. '[metadata]\n'
  407. 'description = éàïôñ\n',
  408. encoding='iso-8859-15'
  409. )
  410. with pytest.raises(UnicodeDecodeError):
  411. with get_dist(tmpdir):
  412. pass
  413. class TestOptions:
  414. def test_basic(self, tmpdir):
  415. fake_env(
  416. tmpdir,
  417. '[options]\n'
  418. 'zip_safe = True\n'
  419. 'use_2to3 = 1\n'
  420. 'include_package_data = yes\n'
  421. 'package_dir = b=c, =src\n'
  422. 'packages = pack_a, pack_b.subpack\n'
  423. 'namespace_packages = pack1, pack2\n'
  424. 'use_2to3_fixers = your.fixers, or.here\n'
  425. 'use_2to3_exclude_fixers = one.here, two.there\n'
  426. 'convert_2to3_doctests = src/tests/one.txt, src/two.txt\n'
  427. 'scripts = bin/one.py, bin/two.py\n'
  428. 'eager_resources = bin/one.py, bin/two.py\n'
  429. 'install_requires = docutils>=0.3; pack ==1.1, ==1.3; hey\n'
  430. 'tests_require = mock==0.7.2; pytest\n'
  431. 'setup_requires = docutils>=0.3; spack ==1.1, ==1.3; there\n'
  432. 'dependency_links = http://some.com/here/1, '
  433. 'http://some.com/there/2\n'
  434. 'python_requires = >=1.0, !=2.8\n'
  435. 'py_modules = module1, module2\n'
  436. )
  437. with get_dist(tmpdir) as dist:
  438. assert dist.zip_safe
  439. assert dist.use_2to3
  440. assert dist.include_package_data
  441. assert dist.package_dir == {'': 'src', 'b': 'c'}
  442. assert dist.packages == ['pack_a', 'pack_b.subpack']
  443. assert dist.namespace_packages == ['pack1', 'pack2']
  444. assert dist.use_2to3_fixers == ['your.fixers', 'or.here']
  445. assert dist.use_2to3_exclude_fixers == ['one.here', 'two.there']
  446. assert dist.convert_2to3_doctests == ([
  447. 'src/tests/one.txt', 'src/two.txt'])
  448. assert dist.scripts == ['bin/one.py', 'bin/two.py']
  449. assert dist.dependency_links == ([
  450. 'http://some.com/here/1',
  451. 'http://some.com/there/2'
  452. ])
  453. assert dist.install_requires == ([
  454. 'docutils>=0.3',
  455. 'pack==1.1,==1.3',
  456. 'hey'
  457. ])
  458. assert dist.setup_requires == ([
  459. 'docutils>=0.3',
  460. 'spack ==1.1, ==1.3',
  461. 'there'
  462. ])
  463. assert dist.tests_require == ['mock==0.7.2', 'pytest']
  464. assert dist.python_requires == '>=1.0, !=2.8'
  465. assert dist.py_modules == ['module1', 'module2']
  466. def test_multiline(self, tmpdir):
  467. fake_env(
  468. tmpdir,
  469. '[options]\n'
  470. 'package_dir = \n'
  471. ' b=c\n'
  472. ' =src\n'
  473. 'packages = \n'
  474. ' pack_a\n'
  475. ' pack_b.subpack\n'
  476. 'namespace_packages = \n'
  477. ' pack1\n'
  478. ' pack2\n'
  479. 'use_2to3_fixers = \n'
  480. ' your.fixers\n'
  481. ' or.here\n'
  482. 'use_2to3_exclude_fixers = \n'
  483. ' one.here\n'
  484. ' two.there\n'
  485. 'convert_2to3_doctests = \n'
  486. ' src/tests/one.txt\n'
  487. ' src/two.txt\n'
  488. 'scripts = \n'
  489. ' bin/one.py\n'
  490. ' bin/two.py\n'
  491. 'eager_resources = \n'
  492. ' bin/one.py\n'
  493. ' bin/two.py\n'
  494. 'install_requires = \n'
  495. ' docutils>=0.3\n'
  496. ' pack ==1.1, ==1.3\n'
  497. ' hey\n'
  498. 'tests_require = \n'
  499. ' mock==0.7.2\n'
  500. ' pytest\n'
  501. 'setup_requires = \n'
  502. ' docutils>=0.3\n'
  503. ' spack ==1.1, ==1.3\n'
  504. ' there\n'
  505. 'dependency_links = \n'
  506. ' http://some.com/here/1\n'
  507. ' http://some.com/there/2\n'
  508. )
  509. with get_dist(tmpdir) as dist:
  510. assert dist.package_dir == {'': 'src', 'b': 'c'}
  511. assert dist.packages == ['pack_a', 'pack_b.subpack']
  512. assert dist.namespace_packages == ['pack1', 'pack2']
  513. assert dist.use_2to3_fixers == ['your.fixers', 'or.here']
  514. assert dist.use_2to3_exclude_fixers == ['one.here', 'two.there']
  515. assert dist.convert_2to3_doctests == (
  516. ['src/tests/one.txt', 'src/two.txt'])
  517. assert dist.scripts == ['bin/one.py', 'bin/two.py']
  518. assert dist.dependency_links == ([
  519. 'http://some.com/here/1',
  520. 'http://some.com/there/2'
  521. ])
  522. assert dist.install_requires == ([
  523. 'docutils>=0.3',
  524. 'pack==1.1,==1.3',
  525. 'hey'
  526. ])
  527. assert dist.setup_requires == ([
  528. 'docutils>=0.3',
  529. 'spack ==1.1, ==1.3',
  530. 'there'
  531. ])
  532. assert dist.tests_require == ['mock==0.7.2', 'pytest']
  533. def test_package_dir_fail(self, tmpdir):
  534. fake_env(
  535. tmpdir,
  536. '[options]\n'
  537. 'package_dir = a b\n'
  538. )
  539. with get_dist(tmpdir, parse=False) as dist:
  540. with pytest.raises(DistutilsOptionError):
  541. dist.parse_config_files()
  542. def test_package_data(self, tmpdir):
  543. fake_env(
  544. tmpdir,
  545. '[options.package_data]\n'
  546. '* = *.txt, *.rst\n'
  547. 'hello = *.msg\n'
  548. '\n'
  549. '[options.exclude_package_data]\n'
  550. '* = fake1.txt, fake2.txt\n'
  551. 'hello = *.dat\n'
  552. )
  553. with get_dist(tmpdir) as dist:
  554. assert dist.package_data == {
  555. '': ['*.txt', '*.rst'],
  556. 'hello': ['*.msg'],
  557. }
  558. assert dist.exclude_package_data == {
  559. '': ['fake1.txt', 'fake2.txt'],
  560. 'hello': ['*.dat'],
  561. }
  562. def test_packages(self, tmpdir):
  563. fake_env(
  564. tmpdir,
  565. '[options]\n'
  566. 'packages = find:\n'
  567. )
  568. with get_dist(tmpdir) as dist:
  569. assert dist.packages == ['fake_package']
  570. def test_find_directive(self, tmpdir):
  571. dir_package, config = fake_env(
  572. tmpdir,
  573. '[options]\n'
  574. 'packages = find:\n'
  575. )
  576. dir_sub_one, _ = make_package_dir('sub_one', dir_package)
  577. dir_sub_two, _ = make_package_dir('sub_two', dir_package)
  578. with get_dist(tmpdir) as dist:
  579. assert set(dist.packages) == set([
  580. 'fake_package', 'fake_package.sub_two', 'fake_package.sub_one'
  581. ])
  582. config.write(
  583. '[options]\n'
  584. 'packages = find:\n'
  585. '\n'
  586. '[options.packages.find]\n'
  587. 'where = .\n'
  588. 'include =\n'
  589. ' fake_package.sub_one\n'
  590. ' two\n'
  591. )
  592. with get_dist(tmpdir) as dist:
  593. assert dist.packages == ['fake_package.sub_one']
  594. config.write(
  595. '[options]\n'
  596. 'packages = find:\n'
  597. '\n'
  598. '[options.packages.find]\n'
  599. 'exclude =\n'
  600. ' fake_package.sub_one\n'
  601. )
  602. with get_dist(tmpdir) as dist:
  603. assert set(dist.packages) == set(
  604. ['fake_package', 'fake_package.sub_two'])
  605. def test_find_namespace_directive(self, tmpdir):
  606. dir_package, config = fake_env(
  607. tmpdir,
  608. '[options]\n'
  609. 'packages = find_namespace:\n'
  610. )
  611. dir_sub_one, _ = make_package_dir('sub_one', dir_package)
  612. dir_sub_two, _ = make_package_dir('sub_two', dir_package, ns=True)
  613. with get_dist(tmpdir) as dist:
  614. assert set(dist.packages) == {
  615. 'fake_package', 'fake_package.sub_two', 'fake_package.sub_one'
  616. }
  617. config.write(
  618. '[options]\n'
  619. 'packages = find_namespace:\n'
  620. '\n'
  621. '[options.packages.find]\n'
  622. 'where = .\n'
  623. 'include =\n'
  624. ' fake_package.sub_one\n'
  625. ' two\n'
  626. )
  627. with get_dist(tmpdir) as dist:
  628. assert dist.packages == ['fake_package.sub_one']
  629. config.write(
  630. '[options]\n'
  631. 'packages = find_namespace:\n'
  632. '\n'
  633. '[options.packages.find]\n'
  634. 'exclude =\n'
  635. ' fake_package.sub_one\n'
  636. )
  637. with get_dist(tmpdir) as dist:
  638. assert set(dist.packages) == {
  639. 'fake_package', 'fake_package.sub_two'
  640. }
  641. def test_extras_require(self, tmpdir):
  642. fake_env(
  643. tmpdir,
  644. '[options.extras_require]\n'
  645. 'pdf = ReportLab>=1.2; RXP\n'
  646. 'rest = \n'
  647. ' docutils>=0.3\n'
  648. ' pack ==1.1, ==1.3\n'
  649. )
  650. with get_dist(tmpdir) as dist:
  651. assert dist.extras_require == {
  652. 'pdf': ['ReportLab>=1.2', 'RXP'],
  653. 'rest': ['docutils>=0.3', 'pack==1.1,==1.3']
  654. }
  655. assert dist.metadata.provides_extras == set(['pdf', 'rest'])
  656. def test_entry_points(self, tmpdir):
  657. _, config = fake_env(
  658. tmpdir,
  659. '[options.entry_points]\n'
  660. 'group1 = point1 = pack.module:func, '
  661. '.point2 = pack.module2:func_rest [rest]\n'
  662. 'group2 = point3 = pack.module:func2\n'
  663. )
  664. with get_dist(tmpdir) as dist:
  665. assert dist.entry_points == {
  666. 'group1': [
  667. 'point1 = pack.module:func',
  668. '.point2 = pack.module2:func_rest [rest]',
  669. ],
  670. 'group2': ['point3 = pack.module:func2']
  671. }
  672. expected = (
  673. '[blogtool.parsers]\n'
  674. '.rst = some.nested.module:SomeClass.some_classmethod[reST]\n'
  675. )
  676. tmpdir.join('entry_points').write(expected)
  677. # From file.
  678. config.write(
  679. '[options]\n'
  680. 'entry_points = file: entry_points\n'
  681. )
  682. with get_dist(tmpdir) as dist:
  683. assert dist.entry_points == expected
  684. def test_data_files(self, tmpdir):
  685. fake_env(
  686. tmpdir,
  687. '[options.data_files]\n'
  688. 'cfg =\n'
  689. ' a/b.conf\n'
  690. ' c/d.conf\n'
  691. 'data = e/f.dat, g/h.dat\n'
  692. )
  693. with get_dist(tmpdir) as dist:
  694. expected = [
  695. ('cfg', ['a/b.conf', 'c/d.conf']),
  696. ('data', ['e/f.dat', 'g/h.dat']),
  697. ]
  698. assert sorted(dist.data_files) == sorted(expected)
  699. def test_python_requires_simple(self, tmpdir):
  700. fake_env(
  701. tmpdir,
  702. DALS("""
  703. [options]
  704. python_requires=>=2.7
  705. """),
  706. )
  707. with get_dist(tmpdir) as dist:
  708. dist.parse_config_files()
  709. def test_python_requires_compound(self, tmpdir):
  710. fake_env(
  711. tmpdir,
  712. DALS("""
  713. [options]
  714. python_requires=>=2.7,!=3.0.*
  715. """),
  716. )
  717. with get_dist(tmpdir) as dist:
  718. dist.parse_config_files()
  719. def test_python_requires_invalid(self, tmpdir):
  720. fake_env(
  721. tmpdir,
  722. DALS("""
  723. [options]
  724. python_requires=invalid
  725. """),
  726. )
  727. with pytest.raises(Exception):
  728. with get_dist(tmpdir) as dist:
  729. dist.parse_config_files()
  730. saved_dist_init = _Distribution.__init__
  731. class TestExternalSetters:
  732. # During creation of the setuptools Distribution() object, we call
  733. # the init of the parent distutils Distribution object via
  734. # _Distribution.__init__ ().
  735. #
  736. # It's possible distutils calls out to various keyword
  737. # implementations (i.e. distutils.setup_keywords entry points)
  738. # that may set a range of variables.
  739. #
  740. # This wraps distutil's Distribution.__init__ and simulates
  741. # pbr or something else setting these values.
  742. def _fake_distribution_init(self, dist, attrs):
  743. saved_dist_init(dist, attrs)
  744. # see self._DISTUTUILS_UNSUPPORTED_METADATA
  745. setattr(dist.metadata, 'long_description_content_type',
  746. 'text/something')
  747. # Test overwrite setup() args
  748. setattr(dist.metadata, 'project_urls', {
  749. 'Link One': 'https://example.com/one/',
  750. 'Link Two': 'https://example.com/two/',
  751. })
  752. return None
  753. @patch.object(_Distribution, '__init__', autospec=True)
  754. def test_external_setters(self, mock_parent_init, tmpdir):
  755. mock_parent_init.side_effect = self._fake_distribution_init
  756. dist = Distribution(attrs={
  757. 'project_urls': {
  758. 'will_be': 'ignored'
  759. }
  760. })
  761. assert dist.metadata.long_description_content_type == 'text/something'
  762. assert dist.metadata.project_urls == {
  763. 'Link One': 'https://example.com/one/',
  764. 'Link Two': 'https://example.com/two/',
  765. }