1# -*- coding: utf8 -*- 2 3"""Tests for distutils.dist.""" 4import os 5import StringIO 6import sys 7import unittest 8import warnings 9import textwrap 10 11from distutils.dist import Distribution, fix_help_options, DistributionMetadata 12from distutils.cmd import Command 13import distutils.dist 14from test.test_support import TESTFN, captured_stdout, run_unittest 15from distutils.tests import support 16 17class test_dist(Command): 18 """Sample distutils extension command.""" 19 20 user_options = [ 21 ("sample-option=", "S", "help text"), 22 ] 23 24 def initialize_options(self): 25 self.sample_option = None 26 27 28class TestDistribution(Distribution): 29 """Distribution subclasses that avoids the default search for 30 configuration files. 31 32 The ._config_files attribute must be set before 33 .parse_config_files() is called. 34 """ 35 36 def find_config_files(self): 37 return self._config_files 38 39 40class DistributionTestCase(support.TempdirManager, 41 support.LoggingSilencer, 42 support.EnvironGuard, 43 unittest.TestCase): 44 45 def setUp(self): 46 super(DistributionTestCase, self).setUp() 47 self.argv = sys.argv, sys.argv[:] 48 del sys.argv[1:] 49 50 def tearDown(self): 51 sys.argv = self.argv[0] 52 sys.argv[:] = self.argv[1] 53 super(DistributionTestCase, self).tearDown() 54 55 def create_distribution(self, configfiles=()): 56 d = TestDistribution() 57 d._config_files = configfiles 58 d.parse_config_files() 59 d.parse_command_line() 60 return d 61 62 def test_debug_mode(self): 63 with open(TESTFN, "w") as f: 64 f.write("[global]") 65 f.write("command_packages = foo.bar, splat") 66 67 files = [TESTFN] 68 sys.argv.append("build") 69 70 with captured_stdout() as stdout: 71 self.create_distribution(files) 72 stdout.seek(0) 73 self.assertEqual(stdout.read(), '') 74 distutils.dist.DEBUG = True 75 try: 76 with captured_stdout() as stdout: 77 self.create_distribution(files) 78 stdout.seek(0) 79 self.assertEqual(stdout.read(), '') 80 finally: 81 distutils.dist.DEBUG = False 82 83 def test_command_packages_unspecified(self): 84 sys.argv.append("build") 85 d = self.create_distribution() 86 self.assertEqual(d.get_command_packages(), ["distutils.command"]) 87 88 def test_command_packages_cmdline(self): 89 from distutils.tests.test_dist import test_dist 90 sys.argv.extend(["--command-packages", 91 "foo.bar,distutils.tests", 92 "test_dist", 93 "-Ssometext", 94 ]) 95 d = self.create_distribution() 96 # let's actually try to load our test command: 97 self.assertEqual(d.get_command_packages(), 98 ["distutils.command", "foo.bar", "distutils.tests"]) 99 cmd = d.get_command_obj("test_dist") 100 self.assertTrue(isinstance(cmd, test_dist)) 101 self.assertEqual(cmd.sample_option, "sometext") 102 103 def test_command_packages_configfile(self): 104 sys.argv.append("build") 105 self.addCleanup(os.unlink, TESTFN) 106 f = open(TESTFN, "w") 107 try: 108 print >>f, "[global]" 109 print >>f, "command_packages = foo.bar, splat" 110 finally: 111 f.close() 112 113 d = self.create_distribution([TESTFN]) 114 self.assertEqual(d.get_command_packages(), 115 ["distutils.command", "foo.bar", "splat"]) 116 117 # ensure command line overrides config: 118 sys.argv[1:] = ["--command-packages", "spork", "build"] 119 d = self.create_distribution([TESTFN]) 120 self.assertEqual(d.get_command_packages(), 121 ["distutils.command", "spork"]) 122 123 # Setting --command-packages to '' should cause the default to 124 # be used even if a config file specified something else: 125 sys.argv[1:] = ["--command-packages", "", "build"] 126 d = self.create_distribution([TESTFN]) 127 self.assertEqual(d.get_command_packages(), ["distutils.command"]) 128 129 def test_write_pkg_file(self): 130 # Check DistributionMetadata handling of Unicode fields 131 tmp_dir = self.mkdtemp() 132 my_file = os.path.join(tmp_dir, 'f') 133 klass = Distribution 134 135 dist = klass(attrs={'author': u'Mister Café', 136 'name': 'my.package', 137 'maintainer': u'Café Junior', 138 'description': u'Café torréfié', 139 'long_description': u'Héhéhé'}) 140 141 142 # let's make sure the file can be written 143 # with Unicode fields. they are encoded with 144 # PKG_INFO_ENCODING 145 dist.metadata.write_pkg_file(open(my_file, 'w')) 146 147 # regular ascii is of course always usable 148 dist = klass(attrs={'author': 'Mister Cafe', 149 'name': 'my.package', 150 'maintainer': 'Cafe Junior', 151 'description': 'Cafe torrefie', 152 'long_description': 'Hehehe'}) 153 154 my_file2 = os.path.join(tmp_dir, 'f2') 155 dist.metadata.write_pkg_file(open(my_file, 'w')) 156 157 def test_empty_options(self): 158 # an empty options dictionary should not stay in the 159 # list of attributes 160 klass = Distribution 161 162 # catching warnings 163 warns = [] 164 def _warn(msg): 165 warns.append(msg) 166 167 old_warn = warnings.warn 168 warnings.warn = _warn 169 try: 170 dist = klass(attrs={'author': 'xxx', 171 'name': 'xxx', 172 'version': 'xxx', 173 'url': 'xxxx', 174 'options': {}}) 175 finally: 176 warnings.warn = old_warn 177 178 self.assertEqual(len(warns), 0) 179 180 def test_finalize_options(self): 181 182 attrs = {'keywords': 'one,two', 183 'platforms': 'one,two'} 184 185 dist = Distribution(attrs=attrs) 186 dist.finalize_options() 187 188 # finalize_option splits platforms and keywords 189 self.assertEqual(dist.metadata.platforms, ['one', 'two']) 190 self.assertEqual(dist.metadata.keywords, ['one', 'two']) 191 192 def test_get_command_packages(self): 193 dist = Distribution() 194 self.assertEqual(dist.command_packages, None) 195 cmds = dist.get_command_packages() 196 self.assertEqual(cmds, ['distutils.command']) 197 self.assertEqual(dist.command_packages, 198 ['distutils.command']) 199 200 dist.command_packages = 'one,two' 201 cmds = dist.get_command_packages() 202 self.assertEqual(cmds, ['distutils.command', 'one', 'two']) 203 204 205 def test_announce(self): 206 # make sure the level is known 207 dist = Distribution() 208 args = ('ok',) 209 kwargs = {'level': 'ok2'} 210 self.assertRaises(ValueError, dist.announce, args, kwargs) 211 212 def test_find_config_files_disable(self): 213 # Ticket #1180: Allow user to disable their home config file. 214 temp_home = self.mkdtemp() 215 if os.name == 'posix': 216 user_filename = os.path.join(temp_home, ".pydistutils.cfg") 217 else: 218 user_filename = os.path.join(temp_home, "pydistutils.cfg") 219 220 with open(user_filename, 'w') as f: 221 f.write('[distutils]\n') 222 223 def _expander(path): 224 return temp_home 225 226 old_expander = os.path.expanduser 227 os.path.expanduser = _expander 228 try: 229 d = distutils.dist.Distribution() 230 all_files = d.find_config_files() 231 232 d = distutils.dist.Distribution(attrs={'script_args': 233 ['--no-user-cfg']}) 234 files = d.find_config_files() 235 finally: 236 os.path.expanduser = old_expander 237 238 # make sure --no-user-cfg disables the user cfg file 239 self.assertEqual(len(all_files)-1, len(files)) 240 241 242class MetadataTestCase(support.TempdirManager, support.EnvironGuard, 243 unittest.TestCase): 244 245 def setUp(self): 246 super(MetadataTestCase, self).setUp() 247 self.argv = sys.argv, sys.argv[:] 248 249 def tearDown(self): 250 sys.argv = self.argv[0] 251 sys.argv[:] = self.argv[1] 252 super(MetadataTestCase, self).tearDown() 253 254 def test_simple_metadata(self): 255 attrs = {"name": "package", 256 "version": "1.0"} 257 dist = Distribution(attrs) 258 meta = self.format_metadata(dist) 259 self.assertTrue("Metadata-Version: 1.0" in meta) 260 self.assertTrue("provides:" not in meta.lower()) 261 self.assertTrue("requires:" not in meta.lower()) 262 self.assertTrue("obsoletes:" not in meta.lower()) 263 264 def test_provides(self): 265 attrs = {"name": "package", 266 "version": "1.0", 267 "provides": ["package", "package.sub"]} 268 dist = Distribution(attrs) 269 self.assertEqual(dist.metadata.get_provides(), 270 ["package", "package.sub"]) 271 self.assertEqual(dist.get_provides(), 272 ["package", "package.sub"]) 273 meta = self.format_metadata(dist) 274 self.assertTrue("Metadata-Version: 1.1" in meta) 275 self.assertTrue("requires:" not in meta.lower()) 276 self.assertTrue("obsoletes:" not in meta.lower()) 277 278 def test_provides_illegal(self): 279 self.assertRaises(ValueError, Distribution, 280 {"name": "package", 281 "version": "1.0", 282 "provides": ["my.pkg (splat)"]}) 283 284 def test_requires(self): 285 attrs = {"name": "package", 286 "version": "1.0", 287 "requires": ["other", "another (==1.0)"]} 288 dist = Distribution(attrs) 289 self.assertEqual(dist.metadata.get_requires(), 290 ["other", "another (==1.0)"]) 291 self.assertEqual(dist.get_requires(), 292 ["other", "another (==1.0)"]) 293 meta = self.format_metadata(dist) 294 self.assertTrue("Metadata-Version: 1.1" in meta) 295 self.assertTrue("provides:" not in meta.lower()) 296 self.assertTrue("Requires: other" in meta) 297 self.assertTrue("Requires: another (==1.0)" in meta) 298 self.assertTrue("obsoletes:" not in meta.lower()) 299 300 def test_requires_illegal(self): 301 self.assertRaises(ValueError, Distribution, 302 {"name": "package", 303 "version": "1.0", 304 "requires": ["my.pkg (splat)"]}) 305 306 def test_obsoletes(self): 307 attrs = {"name": "package", 308 "version": "1.0", 309 "obsoletes": ["other", "another (<1.0)"]} 310 dist = Distribution(attrs) 311 self.assertEqual(dist.metadata.get_obsoletes(), 312 ["other", "another (<1.0)"]) 313 self.assertEqual(dist.get_obsoletes(), 314 ["other", "another (<1.0)"]) 315 meta = self.format_metadata(dist) 316 self.assertTrue("Metadata-Version: 1.1" in meta) 317 self.assertTrue("provides:" not in meta.lower()) 318 self.assertTrue("requires:" not in meta.lower()) 319 self.assertTrue("Obsoletes: other" in meta) 320 self.assertTrue("Obsoletes: another (<1.0)" in meta) 321 322 def test_obsoletes_illegal(self): 323 self.assertRaises(ValueError, Distribution, 324 {"name": "package", 325 "version": "1.0", 326 "obsoletes": ["my.pkg (splat)"]}) 327 328 def format_metadata(self, dist): 329 sio = StringIO.StringIO() 330 dist.metadata.write_pkg_file(sio) 331 return sio.getvalue() 332 333 def test_custom_pydistutils(self): 334 # fixes #2166 335 # make sure pydistutils.cfg is found 336 if os.name == 'posix': 337 user_filename = ".pydistutils.cfg" 338 else: 339 user_filename = "pydistutils.cfg" 340 341 temp_dir = self.mkdtemp() 342 user_filename = os.path.join(temp_dir, user_filename) 343 f = open(user_filename, 'w') 344 try: 345 f.write('.') 346 finally: 347 f.close() 348 349 try: 350 dist = Distribution() 351 352 # linux-style 353 if sys.platform in ('linux', 'darwin'): 354 os.environ['HOME'] = temp_dir 355 files = dist.find_config_files() 356 self.assertTrue(user_filename in files) 357 358 # win32-style 359 if sys.platform == 'win32': 360 # home drive should be found 361 os.environ['HOME'] = temp_dir 362 files = dist.find_config_files() 363 self.assertTrue(user_filename in files, 364 '%r not found in %r' % (user_filename, files)) 365 finally: 366 os.remove(user_filename) 367 368 def test_fix_help_options(self): 369 help_tuples = [('a', 'b', 'c', 'd'), (1, 2, 3, 4)] 370 fancy_options = fix_help_options(help_tuples) 371 self.assertEqual(fancy_options[0], ('a', 'b', 'c')) 372 self.assertEqual(fancy_options[1], (1, 2, 3)) 373 374 def test_show_help(self): 375 # smoke test, just makes sure some help is displayed 376 dist = Distribution() 377 sys.argv = [] 378 dist.help = 1 379 dist.script_name = 'setup.py' 380 with captured_stdout() as s: 381 dist.parse_command_line() 382 383 output = [line for line in s.getvalue().split('\n') 384 if line.strip() != ''] 385 self.assertTrue(len(output) > 0) 386 387 def test_long_description(self): 388 long_desc = textwrap.dedent("""\ 389 example:: 390 We start here 391 and continue here 392 and end here.""") 393 attrs = {"name": "package", 394 "version": "1.0", 395 "long_description": long_desc} 396 397 dist = distutils.dist.Distribution(attrs) 398 meta = self.format_metadata(dist) 399 meta = meta.replace('\n' + 8 * ' ', '\n') 400 self.assertTrue(long_desc in meta) 401 402 def test_read_metadata(self): 403 attrs = {"name": "package", 404 "version": "1.0", 405 "long_description": "desc", 406 "description": "xxx", 407 "download_url": "http://example.com", 408 "keywords": ['one', 'two'], 409 "requires": ['foo']} 410 411 dist = Distribution(attrs) 412 metadata = dist.metadata 413 414 # write it then reloads it 415 PKG_INFO = StringIO.StringIO() 416 metadata.write_pkg_file(PKG_INFO) 417 PKG_INFO.seek(0) 418 metadata.read_pkg_file(PKG_INFO) 419 420 self.assertEqual(metadata.name, "package") 421 self.assertEqual(metadata.version, "1.0") 422 self.assertEqual(metadata.description, "xxx") 423 self.assertEqual(metadata.download_url, 'http://example.com') 424 self.assertEqual(metadata.keywords, ['one', 'two']) 425 self.assertEqual(metadata.platforms, ['UNKNOWN']) 426 self.assertEqual(metadata.obsoletes, None) 427 self.assertEqual(metadata.requires, ['foo']) 428 429def test_suite(): 430 suite = unittest.TestSuite() 431 suite.addTest(unittest.makeSuite(DistributionTestCase)) 432 suite.addTest(unittest.makeSuite(MetadataTestCase)) 433 return suite 434 435if __name__ == "__main__": 436 run_unittest(test_suite()) 437