blob: 5e804c27a61d7925787fb16a0682755a95d48379 [file] [log] [blame]
Tarek Ziade1231a4e2011-05-19 13:07:25 +02001"""Tests for packaging.util."""
2import os
3import sys
4import time
5import logging
6import tempfile
7import subprocess
8from io import StringIO
9
10from packaging.tests import support, unittest
Éric Araujo36050302011-06-10 23:52:26 +020011from packaging.tests.test_config import SETUP_CFG
Tarek Ziade1231a4e2011-05-19 13:07:25 +020012from packaging.errors import (
13 PackagingPlatformError, PackagingByteCompileError, PackagingFileError,
14 PackagingExecError, InstallationException)
15from packaging import util
Éric Araujo36050302011-06-10 23:52:26 +020016from packaging.dist import Distribution
Tarek Ziade1231a4e2011-05-19 13:07:25 +020017from packaging.util import (
Éric Araujo95fc53f2011-09-01 05:11:29 +020018 convert_path, change_root, split_quoted, strtobool,
Tarek Ziade1231a4e2011-05-19 13:07:25 +020019 get_compiler_versions, _MAC_OS_X_LD_VERSION, byte_compile, find_packages,
20 spawn, get_pypirc_path, generate_pypirc, read_pypirc, resolve_name, iglob,
21 RICH_GLOB, egginfo_to_distinfo, is_setuptools, is_distutils, is_packaging,
Éric Araujoce5fe832011-07-08 16:27:12 +020022 get_install_method, cfg_to_args, encode_multipart)
Tarek Ziade1231a4e2011-05-19 13:07:25 +020023
24
25PYPIRC = """\
26[distutils]
27index-servers =
28 pypi
29 server1
30
31[pypi]
32username:me
33password:xxxx
34
35[server1]
36repository:http://example.com
37username:tarek
38password:secret
39"""
40
41PYPIRC_OLD = """\
42[server-login]
43username:tarek
44password:secret
45"""
46
47WANTED = """\
48[distutils]
49index-servers =
50 pypi
51
52[pypi]
53username:tarek
54password:xxx
55"""
56
Éric Araujoce5fe832011-07-08 16:27:12 +020057EXPECTED_MULTIPART_OUTPUT = [
58 b'---x',
59 b'Content-Disposition: form-data; name="username"',
60 b'',
61 b'wok',
62 b'---x',
63 b'Content-Disposition: form-data; name="password"',
64 b'',
65 b'secret',
66 b'---x',
67 b'Content-Disposition: form-data; name="picture"; filename="wok.png"',
68 b'',
69 b'PNG89',
70 b'---x--',
71 b'',
72]
73
Tarek Ziade1231a4e2011-05-19 13:07:25 +020074
75class FakePopen:
76 test_class = None
77
Victor Stinnerf9668032011-05-20 00:12:10 +020078 def __init__(self, args, bufsize=0, executable=None,
79 stdin=None, stdout=None, stderr=None,
80 preexec_fn=None, close_fds=False,
81 shell=False, cwd=None, env=None, universal_newlines=False,
82 startupinfo=None, creationflags=0,
83 restore_signals=True, start_new_session=False,
84 pass_fds=()):
Tarek Ziade94449612011-05-21 10:37:58 +020085 if isinstance(args, str):
86 args = args.split()
87 self.cmd = args[0]
Tarek Ziade1231a4e2011-05-19 13:07:25 +020088 exes = self.test_class._exes
89 if self.cmd not in exes:
90 # we don't want to call the system, returning an empty
91 # output so it doesn't match
92 self.stdout = StringIO()
93 self.stderr = StringIO()
94 else:
95 self.stdout = StringIO(exes[self.cmd])
96 self.stderr = StringIO()
97
Victor Stinner9904b222011-05-21 02:20:36 +020098 def communicate(self, input=None, timeout=None):
99 return self.stdout.read(), self.stderr.read()
100
Tarek Ziade94449612011-05-21 10:37:58 +0200101 def wait(self, timeout=None):
102 return 0
103
Tarek Ziade1231a4e2011-05-19 13:07:25 +0200104
105class UtilTestCase(support.EnvironRestorer,
106 support.TempdirManager,
107 support.LoggingCatcher,
108 unittest.TestCase):
109
Éric Araujo36050302011-06-10 23:52:26 +0200110 restore_environ = ['HOME', 'PLAT']
Tarek Ziade1231a4e2011-05-19 13:07:25 +0200111
112 def setUp(self):
113 super(UtilTestCase, self).setUp()
Éric Araujo36050302011-06-10 23:52:26 +0200114 self.addCleanup(os.chdir, os.getcwd())
115 tempdir = self.mkdtemp()
116 self.rc = os.path.join(tempdir, '.pypirc')
117 os.environ['HOME'] = tempdir
118 os.chdir(tempdir)
Tarek Ziade1231a4e2011-05-19 13:07:25 +0200119 # saving the environment
120 self.name = os.name
121 self.platform = sys.platform
122 self.version = sys.version
123 self.sep = os.sep
124 self.join = os.path.join
125 self.isabs = os.path.isabs
126 self.splitdrive = os.path.splitdrive
Tarek Ziade1231a4e2011-05-19 13:07:25 +0200127
128 # patching os.uname
129 if hasattr(os, 'uname'):
130 self.uname = os.uname
131 self._uname = os.uname()
132 else:
133 self.uname = None
134 self._uname = None
135 os.uname = self._get_uname
136
137 # patching POpen
138 self.old_find_executable = util.find_executable
139 util.find_executable = self._find_executable
140 self._exes = {}
141 self.old_popen = subprocess.Popen
142 self.old_stdout = sys.stdout
143 self.old_stderr = sys.stderr
144 FakePopen.test_class = self
145 subprocess.Popen = FakePopen
146
147 def tearDown(self):
148 # getting back the environment
149 os.name = self.name
150 sys.platform = self.platform
151 sys.version = self.version
152 os.sep = self.sep
153 os.path.join = self.join
154 os.path.isabs = self.isabs
155 os.path.splitdrive = self.splitdrive
156 if self.uname is not None:
157 os.uname = self.uname
158 else:
159 del os.uname
Tarek Ziade1231a4e2011-05-19 13:07:25 +0200160 util.find_executable = self.old_find_executable
161 subprocess.Popen = self.old_popen
162 sys.old_stdout = self.old_stdout
163 sys.old_stderr = self.old_stderr
164 super(UtilTestCase, self).tearDown()
165
166 def _set_uname(self, uname):
167 self._uname = uname
168
169 def _get_uname(self):
170 return self._uname
171
172 def test_convert_path(self):
173 # linux/mac
174 os.sep = '/'
175
176 def _join(path):
177 return '/'.join(path)
178 os.path.join = _join
179
180 self.assertEqual(convert_path('/home/to/my/stuff'),
181 '/home/to/my/stuff')
182
183 # win
184 os.sep = '\\'
185
186 def _join(*path):
187 return '\\'.join(path)
188 os.path.join = _join
189
190 self.assertRaises(ValueError, convert_path, '/home/to/my/stuff')
191 self.assertRaises(ValueError, convert_path, 'home/to/my/stuff/')
192
193 self.assertEqual(convert_path('home/to/my/stuff'),
194 'home\\to\\my\\stuff')
195 self.assertEqual(convert_path('.'),
196 os.curdir)
197
198 def test_change_root(self):
199 # linux/mac
200 os.name = 'posix'
201
202 def _isabs(path):
203 return path[0] == '/'
204 os.path.isabs = _isabs
205
206 def _join(*path):
207 return '/'.join(path)
208 os.path.join = _join
209
210 self.assertEqual(change_root('/root', '/old/its/here'),
211 '/root/old/its/here')
212 self.assertEqual(change_root('/root', 'its/here'),
213 '/root/its/here')
214
215 # windows
216 os.name = 'nt'
217
218 def _isabs(path):
219 return path.startswith('c:\\')
220 os.path.isabs = _isabs
221
222 def _splitdrive(path):
223 if path.startswith('c:'):
224 return '', path.replace('c:', '')
225 return '', path
226 os.path.splitdrive = _splitdrive
227
228 def _join(*path):
229 return '\\'.join(path)
230 os.path.join = _join
231
232 self.assertEqual(change_root('c:\\root', 'c:\\old\\its\\here'),
233 'c:\\root\\old\\its\\here')
234 self.assertEqual(change_root('c:\\root', 'its\\here'),
235 'c:\\root\\its\\here')
236
237 # BugsBunny os (it's a great os)
238 os.name = 'BugsBunny'
239 self.assertRaises(PackagingPlatformError,
240 change_root, 'c:\\root', 'its\\here')
241
242 # XXX platforms to be covered: os2, mac
243
244 def test_split_quoted(self):
245 self.assertEqual(split_quoted('""one"" "two" \'three\' \\four'),
246 ['one', 'two', 'three', 'four'])
247
248 def test_strtobool(self):
249 yes = ('y', 'Y', 'yes', 'True', 't', 'true', 'True', 'On', 'on', '1')
250 no = ('n', 'no', 'f', 'false', 'off', '0', 'Off', 'No', 'N')
251
252 for y in yes:
253 self.assertTrue(strtobool(y))
254
255 for n in no:
256 self.assertFalse(strtobool(n))
257
Tarek Ziade1231a4e2011-05-19 13:07:25 +0200258 def test_find_exe_version(self):
259 # the ld version scheme under MAC OS is:
260 # ^@(#)PROGRAM:ld PROJECT:ld64-VERSION
261 #
262 # where VERSION is a 2-digit number for major
263 # revisions. For instance under Leopard, it's
264 # currently 77
265 #
266 # Dots are used when branching is done.
267 #
268 # The SnowLeopard ld64 is currently 95.2.12
269
270 for output, version in (('@(#)PROGRAM:ld PROJECT:ld64-77', '77'),
271 ('@(#)PROGRAM:ld PROJECT:ld64-95.2.12',
272 '95.2.12')):
273 result = _MAC_OS_X_LD_VERSION.search(output)
274 self.assertEqual(result.group(1), version)
275
276 def _find_executable(self, name):
277 if name in self._exes:
278 return name
279 return None
280
281 def test_get_compiler_versions(self):
282 # get_versions calls distutils.spawn.find_executable on
283 # 'gcc', 'ld' and 'dllwrap'
284 self.assertEqual(get_compiler_versions(), (None, None, None))
285
286 # Let's fake we have 'gcc' and it returns '3.4.5'
287 self._exes['gcc'] = 'gcc (GCC) 3.4.5 (mingw special)\nFSF'
288 res = get_compiler_versions()
289 self.assertEqual(str(res[0]), '3.4.5')
290
291 # and let's see what happens when the version
292 # doesn't match the regular expression
293 # (\d+\.\d+(\.\d+)*)
294 self._exes['gcc'] = 'very strange output'
295 res = get_compiler_versions()
296 self.assertEqual(res[0], None)
297
298 # same thing for ld
299 if sys.platform != 'darwin':
300 self._exes['ld'] = 'GNU ld version 2.17.50 20060824'
301 res = get_compiler_versions()
302 self.assertEqual(str(res[1]), '2.17.50')
303 self._exes['ld'] = '@(#)PROGRAM:ld PROJECT:ld64-77'
304 res = get_compiler_versions()
305 self.assertEqual(res[1], None)
306 else:
307 self._exes['ld'] = 'GNU ld version 2.17.50 20060824'
308 res = get_compiler_versions()
309 self.assertEqual(res[1], None)
310 self._exes['ld'] = '@(#)PROGRAM:ld PROJECT:ld64-77'
311 res = get_compiler_versions()
312 self.assertEqual(str(res[1]), '77')
313
314 # and dllwrap
315 self._exes['dllwrap'] = 'GNU dllwrap 2.17.50 20060824\nFSF'
316 res = get_compiler_versions()
317 self.assertEqual(str(res[2]), '2.17.50')
318 self._exes['dllwrap'] = 'Cheese Wrap'
319 res = get_compiler_versions()
320 self.assertEqual(res[2], None)
321
322 @unittest.skipUnless(hasattr(sys, 'dont_write_bytecode'),
323 'sys.dont_write_bytecode not supported')
324 def test_dont_write_bytecode(self):
325 # makes sure byte_compile raise a PackagingError
326 # if sys.dont_write_bytecode is True
327 old_dont_write_bytecode = sys.dont_write_bytecode
328 sys.dont_write_bytecode = True
329 try:
330 self.assertRaises(PackagingByteCompileError, byte_compile, [])
331 finally:
332 sys.dont_write_bytecode = old_dont_write_bytecode
333
334 def test_newer(self):
335 self.assertRaises(PackagingFileError, util.newer, 'xxx', 'xxx')
336 self.newer_f1 = self.mktempfile()
337 time.sleep(1)
338 self.newer_f2 = self.mktempfile()
339 self.assertTrue(util.newer(self.newer_f2.name, self.newer_f1.name))
340
341 def test_find_packages(self):
342 # let's create a structure we want to scan:
343 #
344 # pkg1
345 # __init__
346 # pkg2
347 # __init__
348 # pkg3
349 # __init__
350 # pkg6
351 # __init__
352 # pkg4 <--- not a pkg
353 # pkg8
354 # __init__
355 # pkg5
356 # __init__
357 #
358 root = self.mkdtemp()
359 pkg1 = os.path.join(root, 'pkg1')
360 os.mkdir(pkg1)
361 self.write_file(os.path.join(pkg1, '__init__.py'))
362 os.mkdir(os.path.join(pkg1, 'pkg2'))
363 self.write_file(os.path.join(pkg1, 'pkg2', '__init__.py'))
364 os.mkdir(os.path.join(pkg1, 'pkg3'))
365 self.write_file(os.path.join(pkg1, 'pkg3', '__init__.py'))
366 os.mkdir(os.path.join(pkg1, 'pkg3', 'pkg6'))
367 self.write_file(os.path.join(pkg1, 'pkg3', 'pkg6', '__init__.py'))
368 os.mkdir(os.path.join(pkg1, 'pkg4'))
369 os.mkdir(os.path.join(pkg1, 'pkg4', 'pkg8'))
370 self.write_file(os.path.join(pkg1, 'pkg4', 'pkg8', '__init__.py'))
371 pkg5 = os.path.join(root, 'pkg5')
372 os.mkdir(pkg5)
373 self.write_file(os.path.join(pkg5, '__init__.py'))
374
375 res = find_packages([root], ['pkg1.pkg2'])
376 self.assertEqual(set(res), set(['pkg1', 'pkg5', 'pkg1.pkg3',
377 'pkg1.pkg3.pkg6']))
378
379 def test_resolve_name(self):
380 self.assertIs(str, resolve_name('builtins.str'))
381 self.assertEqual(
382 UtilTestCase.__name__,
383 resolve_name("packaging.tests.test_util.UtilTestCase").__name__)
384 self.assertEqual(
385 UtilTestCase.test_resolve_name.__name__,
386 resolve_name("packaging.tests.test_util.UtilTestCase."
387 "test_resolve_name").__name__)
388
389 self.assertRaises(ImportError, resolve_name,
390 "packaging.tests.test_util.UtilTestCaseNot")
391 self.assertRaises(ImportError, resolve_name,
392 "packaging.tests.test_util.UtilTestCase."
393 "nonexistent_attribute")
394
395 def test_import_nested_first_time(self):
396 tmp_dir = self.mkdtemp()
397 os.makedirs(os.path.join(tmp_dir, 'a', 'b'))
398 self.write_file(os.path.join(tmp_dir, 'a', '__init__.py'), '')
399 self.write_file(os.path.join(tmp_dir, 'a', 'b', '__init__.py'), '')
400 self.write_file(os.path.join(tmp_dir, 'a', 'b', 'c.py'),
401 'class Foo: pass')
402
403 try:
404 sys.path.append(tmp_dir)
405 resolve_name("a.b.c.Foo")
406 # assert nothing raised
407 finally:
408 sys.path.remove(tmp_dir)
409
410 @unittest.skipIf(sys.version < '2.6', 'requires Python 2.6 or higher')
411 def test_run_2to3_on_code(self):
412 content = "print 'test'"
413 converted_content = "print('test')"
414 file_handle = self.mktempfile()
415 file_name = file_handle.name
416 file_handle.write(content)
417 file_handle.flush()
418 file_handle.seek(0)
419 from packaging.util import run_2to3
420 run_2to3([file_name])
421 new_content = "".join(file_handle.read())
422 file_handle.close()
423 self.assertEqual(new_content, converted_content)
424
425 @unittest.skipIf(sys.version < '2.6', 'requires Python 2.6 or higher')
426 def test_run_2to3_on_doctests(self):
427 # to check if text files containing doctests only get converted.
428 content = ">>> print 'test'\ntest\n"
429 converted_content = ">>> print('test')\ntest\n\n"
430 file_handle = self.mktempfile()
431 file_name = file_handle.name
432 file_handle.write(content)
433 file_handle.flush()
434 file_handle.seek(0)
435 from packaging.util import run_2to3
436 run_2to3([file_name], doctests_only=True)
437 new_content = "".join(file_handle.readlines())
438 file_handle.close()
439 self.assertEqual(new_content, converted_content)
440
441 @unittest.skipUnless(os.name in ('nt', 'posix'),
442 'runs only under posix or nt')
443 def test_spawn(self):
Tarek Ziade94449612011-05-21 10:37:58 +0200444 # no patching of Popen here
445 subprocess.Popen = self.old_popen
Tarek Ziade1231a4e2011-05-19 13:07:25 +0200446 tmpdir = self.mkdtemp()
447
448 # creating something executable
449 # through the shell that returns 1
450 if os.name == 'posix':
451 exe = os.path.join(tmpdir, 'foo.sh')
452 self.write_file(exe, '#!/bin/sh\nexit 1')
453 os.chmod(exe, 0o777)
454 else:
455 exe = os.path.join(tmpdir, 'foo.bat')
456 self.write_file(exe, 'exit 1')
457
458 os.chmod(exe, 0o777)
459 self.assertRaises(PackagingExecError, spawn, [exe])
460
461 # now something that works
462 if os.name == 'posix':
463 exe = os.path.join(tmpdir, 'foo.sh')
464 self.write_file(exe, '#!/bin/sh\nexit 0')
465 os.chmod(exe, 0o777)
466 else:
467 exe = os.path.join(tmpdir, 'foo.bat')
468 self.write_file(exe, 'exit 0')
469
470 os.chmod(exe, 0o777)
471 spawn([exe]) # should work without any error
472
473 def test_server_registration(self):
474 # This test makes sure we know how to:
475 # 1. handle several sections in .pypirc
476 # 2. handle the old format
477
478 # new format
479 self.write_file(self.rc, PYPIRC)
480 config = read_pypirc()
481
482 config = sorted(config.items())
483 expected = [('password', 'xxxx'), ('realm', 'pypi'),
484 ('repository', 'http://pypi.python.org/pypi'),
485 ('server', 'pypi'), ('username', 'me')]
486 self.assertEqual(config, expected)
487
488 # old format
489 self.write_file(self.rc, PYPIRC_OLD)
490 config = read_pypirc()
491 config = sorted(config.items())
492 expected = [('password', 'secret'), ('realm', 'pypi'),
493 ('repository', 'http://pypi.python.org/pypi'),
494 ('server', 'server-login'), ('username', 'tarek')]
495 self.assertEqual(config, expected)
496
497 def test_server_empty_registration(self):
498 rc = get_pypirc_path()
499 self.assertFalse(os.path.exists(rc))
500 generate_pypirc('tarek', 'xxx')
501 self.assertTrue(os.path.exists(rc))
502 with open(rc) as f:
503 content = f.read()
504 self.assertEqual(content, WANTED)
505
Éric Araujo36050302011-06-10 23:52:26 +0200506 def test_cfg_to_args(self):
507 opts = {'description-file': 'README', 'extra-files': '',
Éric Araujo643cb732011-06-11 00:33:38 +0200508 'setup-hooks': 'packaging.tests.test_config.version_hook'}
Éric Araujo043f5ae2011-06-12 22:04:58 +0200509 self.write_file('setup.cfg', SETUP_CFG % opts, encoding='utf-8')
Éric Araujo36050302011-06-10 23:52:26 +0200510 self.write_file('README', 'loooong description')
511
512 args = cfg_to_args()
513 # use Distribution to get the contents of the setup.cfg file
514 dist = Distribution()
515 dist.parse_config_files()
516 metadata = dist.metadata
517
518 self.assertEqual(args['name'], metadata['Name'])
519 # + .dev1 because the test SETUP_CFG also tests a hook function in
520 # test_config.py for appending to the version string
521 self.assertEqual(args['version'] + '.dev1', metadata['Version'])
522 self.assertEqual(args['author'], metadata['Author'])
523 self.assertEqual(args['author_email'], metadata['Author-Email'])
524 self.assertEqual(args['maintainer'], metadata['Maintainer'])
525 self.assertEqual(args['maintainer_email'],
526 metadata['Maintainer-Email'])
527 self.assertEqual(args['description'], metadata['Summary'])
528 self.assertEqual(args['long_description'], metadata['Description'])
529 self.assertEqual(args['classifiers'], metadata['Classifier'])
530 self.assertEqual(args['requires'], metadata['Requires-Dist'])
531 self.assertEqual(args['provides'], metadata['Provides-Dist'])
532
533 self.assertEqual(args['package_dir'].get(''), dist.package_dir)
534 self.assertEqual(args['packages'], dist.packages)
535 self.assertEqual(args['scripts'], dist.scripts)
536 self.assertEqual(args['py_modules'], dist.py_modules)
537
Éric Araujoce5fe832011-07-08 16:27:12 +0200538 def test_encode_multipart(self):
539 fields = [('username', 'wok'), ('password', 'secret')]
540 files = [('picture', 'wok.png', b'PNG89')]
541 content_type, body = encode_multipart(fields, files, b'-x')
542 self.assertEqual(b'multipart/form-data; boundary=-x', content_type)
543 self.assertEqual(EXPECTED_MULTIPART_OUTPUT, body.split(b'\r\n'))
544
Tarek Ziade1231a4e2011-05-19 13:07:25 +0200545
546class GlobTestCaseBase(support.TempdirManager,
547 support.LoggingCatcher,
548 unittest.TestCase):
549
550 def build_files_tree(self, files):
551 tempdir = self.mkdtemp()
552 for filepath in files:
553 is_dir = filepath.endswith('/')
554 filepath = os.path.join(tempdir, *filepath.split('/'))
555 if is_dir:
556 dirname = filepath
557 else:
558 dirname = os.path.dirname(filepath)
559 if dirname and not os.path.exists(dirname):
560 os.makedirs(dirname)
561 if not is_dir:
562 self.write_file(filepath, 'babar')
563 return tempdir
564
565 @staticmethod
566 def os_dependent_path(path):
567 path = path.rstrip('/').split('/')
568 return os.path.join(*path)
569
570 def clean_tree(self, spec):
571 files = []
572 for path, includes in spec.items():
573 if includes:
574 files.append(self.os_dependent_path(path))
575 return files
576
577
578class GlobTestCase(GlobTestCaseBase):
579
Tarek Ziadefabc3082011-05-23 18:47:27 +0200580 def setUp(self):
581 super(GlobTestCase, self).setUp()
582 self.cwd = os.getcwd()
583
584 def tearDown(self):
585 os.chdir(self.cwd)
586 super(GlobTestCase, self).tearDown()
587
Tarek Ziade1231a4e2011-05-19 13:07:25 +0200588 def assertGlobMatch(self, glob, spec):
589 """"""
590 tempdir = self.build_files_tree(spec)
591 expected = self.clean_tree(spec)
Tarek Ziade1231a4e2011-05-19 13:07:25 +0200592 os.chdir(tempdir)
593 result = list(iglob(glob))
594 self.assertCountEqual(expected, result)
595
596 def test_regex_rich_glob(self):
597 matches = RICH_GLOB.findall(
598 r"babar aime les {fraises} est les {huitres}")
599 self.assertEqual(["fraises", "huitres"], matches)
600
601 def test_simple_glob(self):
602 glob = '*.tp?'
603 spec = {'coucou.tpl': True,
604 'coucou.tpj': True,
605 'Donotwant': False}
606 self.assertGlobMatch(glob, spec)
607
608 def test_simple_glob_in_dir(self):
Victor Stinnere1e3b12972011-05-20 00:33:39 +0200609 glob = os.path.join('babar', '*.tp?')
Tarek Ziade1231a4e2011-05-19 13:07:25 +0200610 spec = {'babar/coucou.tpl': True,
611 'babar/coucou.tpj': True,
612 'babar/toto.bin': False,
613 'Donotwant': False}
614 self.assertGlobMatch(glob, spec)
615
616 def test_recursive_glob_head(self):
Victor Stinnere1e3b12972011-05-20 00:33:39 +0200617 glob = os.path.join('**', 'tip', '*.t?l')
Tarek Ziade1231a4e2011-05-19 13:07:25 +0200618 spec = {'babar/zaza/zuzu/tip/coucou.tpl': True,
619 'babar/z/tip/coucou.tpl': True,
620 'babar/tip/coucou.tpl': True,
621 'babar/zeop/tip/babar/babar.tpl': False,
622 'babar/z/tip/coucou.bin': False,
623 'babar/toto.bin': False,
624 'zozo/zuzu/tip/babar.tpl': True,
625 'zozo/tip/babar.tpl': True,
626 'Donotwant': False}
627 self.assertGlobMatch(glob, spec)
628
629 def test_recursive_glob_tail(self):
Victor Stinnere1e3b12972011-05-20 00:33:39 +0200630 glob = os.path.join('babar', '**')
Tarek Ziade1231a4e2011-05-19 13:07:25 +0200631 spec = {'babar/zaza/': True,
632 'babar/zaza/zuzu/': True,
633 'babar/zaza/zuzu/babar.xml': True,
634 'babar/zaza/zuzu/toto.xml': True,
635 'babar/zaza/zuzu/toto.csv': True,
636 'babar/zaza/coucou.tpl': True,
637 'babar/bubu.tpl': True,
638 'zozo/zuzu/tip/babar.tpl': False,
639 'zozo/tip/babar.tpl': False,
640 'Donotwant': False}
641 self.assertGlobMatch(glob, spec)
642
643 def test_recursive_glob_middle(self):
Victor Stinnere1e3b12972011-05-20 00:33:39 +0200644 glob = os.path.join('babar', '**', 'tip', '*.t?l')
Tarek Ziade1231a4e2011-05-19 13:07:25 +0200645 spec = {'babar/zaza/zuzu/tip/coucou.tpl': True,
646 'babar/z/tip/coucou.tpl': True,
647 'babar/tip/coucou.tpl': True,
648 'babar/zeop/tip/babar/babar.tpl': False,
649 'babar/z/tip/coucou.bin': False,
650 'babar/toto.bin': False,
651 'zozo/zuzu/tip/babar.tpl': False,
652 'zozo/tip/babar.tpl': False,
653 'Donotwant': False}
654 self.assertGlobMatch(glob, spec)
655
656 def test_glob_set_tail(self):
Victor Stinnere1e3b12972011-05-20 00:33:39 +0200657 glob = os.path.join('bin', '*.{bin,sh,exe}')
Tarek Ziade1231a4e2011-05-19 13:07:25 +0200658 spec = {'bin/babar.bin': True,
659 'bin/zephir.sh': True,
660 'bin/celestine.exe': True,
661 'bin/cornelius.bat': False,
662 'bin/cornelius.xml': False,
663 'toto/yurg': False,
664 'Donotwant': False}
665 self.assertGlobMatch(glob, spec)
666
667 def test_glob_set_middle(self):
Victor Stinnere1e3b12972011-05-20 00:33:39 +0200668 glob = os.path.join('xml', '{babar,toto}.xml')
Tarek Ziade1231a4e2011-05-19 13:07:25 +0200669 spec = {'xml/babar.xml': True,
670 'xml/toto.xml': True,
671 'xml/babar.xslt': False,
672 'xml/cornelius.sgml': False,
673 'xml/zephir.xml': False,
674 'toto/yurg.xml': False,
675 'Donotwant': False}
676 self.assertGlobMatch(glob, spec)
677
678 def test_glob_set_head(self):
Victor Stinnere1e3b12972011-05-20 00:33:39 +0200679 glob = os.path.join('{xml,xslt}', 'babar.*')
Tarek Ziade1231a4e2011-05-19 13:07:25 +0200680 spec = {'xml/babar.xml': True,
681 'xml/toto.xml': False,
682 'xslt/babar.xslt': True,
683 'xslt/toto.xslt': False,
684 'toto/yurg.xml': False,
685 'Donotwant': False}
686 self.assertGlobMatch(glob, spec)
687
688 def test_glob_all(self):
Victor Stinnere1e3b12972011-05-20 00:33:39 +0200689 dirs = '{%s,%s}' % (os.path.join('xml', '*'),
690 os.path.join('xslt', '**'))
691 glob = os.path.join(dirs, 'babar.xml')
Tarek Ziade1231a4e2011-05-19 13:07:25 +0200692 spec = {'xml/a/babar.xml': True,
693 'xml/b/babar.xml': True,
694 'xml/a/c/babar.xml': False,
695 'xslt/a/babar.xml': True,
696 'xslt/b/babar.xml': True,
697 'xslt/a/c/babar.xml': True,
698 'toto/yurg.xml': False,
699 'Donotwant': False}
700 self.assertGlobMatch(glob, spec)
701
702 def test_invalid_glob_pattern(self):
703 invalids = [
704 'ppooa**',
705 'azzaeaz4**/',
706 '/**ddsfs',
707 '**##1e"&e',
708 'DSFb**c009',
709 '{',
710 '{aaQSDFa',
711 '}',
712 'aQSDFSaa}',
713 '{**a,',
714 ',**a}',
715 '{a**,',
716 ',b**}',
717 '{a**a,babar}',
718 '{bob,b**z}',
719 ]
Tarek Ziade1231a4e2011-05-19 13:07:25 +0200720 for pattern in invalids:
Éric Araujoed5d2f12011-06-17 15:47:41 +0200721 self.assertRaises(ValueError, iglob, pattern)
Tarek Ziade1231a4e2011-05-19 13:07:25 +0200722
723
724class EggInfoToDistInfoTestCase(support.TempdirManager,
725 support.LoggingCatcher,
726 unittest.TestCase):
727
728 def get_metadata_file_paths(self, distinfo_path):
729 req_metadata_files = ['METADATA', 'RECORD', 'INSTALLER']
730 metadata_file_paths = []
731 for metadata_file in req_metadata_files:
732 path = os.path.join(distinfo_path, metadata_file)
733 metadata_file_paths.append(path)
734 return metadata_file_paths
735
736 def test_egginfo_to_distinfo_setuptools(self):
737 distinfo = 'hello-0.1.1-py3.3.dist-info'
738 egginfo = 'hello-0.1.1-py3.3.egg-info'
739 dirs = [egginfo]
740 files = ['hello.py', 'hello.pyc']
741 extra_metadata = ['dependency_links.txt', 'entry_points.txt',
742 'not-zip-safe', 'PKG-INFO', 'top_level.txt',
743 'SOURCES.txt']
744 for f in extra_metadata:
745 files.append(os.path.join(egginfo, f))
746
747 tempdir, record_file = self.build_dist_tree(files, dirs)
748 distinfo_path = os.path.join(tempdir, distinfo)
749 egginfo_path = os.path.join(tempdir, egginfo)
750 metadata_file_paths = self.get_metadata_file_paths(distinfo_path)
751
752 egginfo_to_distinfo(record_file)
753 # test that directories and files get created
754 self.assertTrue(os.path.isdir(distinfo_path))
755 self.assertTrue(os.path.isdir(egginfo_path))
756
757 for mfile in metadata_file_paths:
758 self.assertTrue(os.path.isfile(mfile))
759
760 def test_egginfo_to_distinfo_distutils(self):
761 distinfo = 'hello-0.1.1-py3.3.dist-info'
762 egginfo = 'hello-0.1.1-py3.3.egg-info'
763 # egginfo is a file in distutils which contains the metadata
764 files = ['hello.py', 'hello.pyc', egginfo]
765
766 tempdir, record_file = self.build_dist_tree(files, dirs=[])
767 distinfo_path = os.path.join(tempdir, distinfo)
768 egginfo_path = os.path.join(tempdir, egginfo)
769 metadata_file_paths = self.get_metadata_file_paths(distinfo_path)
770
771 egginfo_to_distinfo(record_file)
772 # test that directories and files get created
773 self.assertTrue(os.path.isdir(distinfo_path))
774 self.assertTrue(os.path.isfile(egginfo_path))
775
776 for mfile in metadata_file_paths:
777 self.assertTrue(os.path.isfile(mfile))
778
779 def build_dist_tree(self, files, dirs):
780 tempdir = self.mkdtemp()
781 record_file_path = os.path.join(tempdir, 'RECORD')
782 file_paths, dir_paths = ([], [])
783 for d in dirs:
784 path = os.path.join(tempdir, d)
785 os.makedirs(path)
786 dir_paths.append(path)
787 for f in files:
788 path = os.path.join(tempdir, f)
Victor Stinner21a9c742011-05-19 15:51:27 +0200789 with open(path, 'w') as _f:
790 _f.write(f)
Tarek Ziade1231a4e2011-05-19 13:07:25 +0200791 file_paths.append(path)
792
Victor Stinner21a9c742011-05-19 15:51:27 +0200793 with open(record_file_path, 'w') as record_file:
794 for fpath in file_paths:
795 record_file.write(fpath + '\n')
796 for dpath in dir_paths:
797 record_file.write(dpath + '\n')
Tarek Ziade1231a4e2011-05-19 13:07:25 +0200798
799 return (tempdir, record_file_path)
800
801
802class PackagingLibChecks(support.TempdirManager,
803 support.LoggingCatcher,
804 unittest.TestCase):
805
806 def setUp(self):
807 super(PackagingLibChecks, self).setUp()
808 self._empty_dir = self.mkdtemp()
809
810 def test_empty_package_is_not_based_on_anything(self):
811 self.assertFalse(is_setuptools(self._empty_dir))
812 self.assertFalse(is_distutils(self._empty_dir))
813 self.assertFalse(is_packaging(self._empty_dir))
814
815 def test_setup_py_importing_setuptools_is_setuptools_based(self):
816 self.assertTrue(is_setuptools(self._setuptools_setup_py_pkg()))
817
818 def test_egg_info_dir_and_setup_py_is_setuptools_based(self):
819 self.assertTrue(is_setuptools(self._setuptools_egg_info_pkg()))
820
821 def test_egg_info_and_non_setuptools_setup_py_is_setuptools_based(self):
822 self.assertTrue(is_setuptools(self._egg_info_with_no_setuptools()))
823
824 def test_setup_py_not_importing_setuptools_is_not_setuptools_based(self):
825 self.assertFalse(is_setuptools(self._random_setup_py_pkg()))
826
827 def test_setup_py_importing_distutils_is_distutils_based(self):
828 self.assertTrue(is_distutils(self._distutils_setup_py_pkg()))
829
830 def test_pkg_info_file_and_setup_py_is_distutils_based(self):
831 self.assertTrue(is_distutils(self._distutils_pkg_info()))
832
833 def test_pkg_info_and_non_distutils_setup_py_is_distutils_based(self):
834 self.assertTrue(is_distutils(self._pkg_info_with_no_distutils()))
835
836 def test_setup_py_not_importing_distutils_is_not_distutils_based(self):
837 self.assertFalse(is_distutils(self._random_setup_py_pkg()))
838
839 def test_setup_cfg_with_no_metadata_section_is_not_packaging_based(self):
840 self.assertFalse(is_packaging(self._setup_cfg_with_no_metadata_pkg()))
841
842 def test_setup_cfg_with_valid_metadata_section_is_packaging_based(self):
843 self.assertTrue(is_packaging(self._valid_setup_cfg_pkg()))
844
845 def test_setup_cfg_and_invalid_setup_cfg_is_not_packaging_based(self):
846 self.assertFalse(is_packaging(self._invalid_setup_cfg_pkg()))
847
848 def test_get_install_method_with_setuptools_pkg(self):
849 path = self._setuptools_setup_py_pkg()
850 self.assertEqual("setuptools", get_install_method(path))
851
852 def test_get_install_method_with_distutils_pkg(self):
853 path = self._distutils_pkg_info()
854 self.assertEqual("distutils", get_install_method(path))
855
856 def test_get_install_method_with_packaging_pkg(self):
857 path = self._valid_setup_cfg_pkg()
858 self.assertEqual("packaging", get_install_method(path))
859
860 def test_get_install_method_with_unknown_pkg(self):
861 path = self._invalid_setup_cfg_pkg()
862 self.assertRaises(InstallationException, get_install_method, path)
863
864 def test_is_setuptools_logs_setup_py_text_found(self):
865 is_setuptools(self._setuptools_setup_py_pkg())
Tarek Ziadeb1b6e132011-05-30 12:07:49 +0200866 expected = ['setup.py file found.',
867 'No egg-info directory found.',
868 'Found setuptools text in setup.py.']
869 self.assertEqual(expected, self.get_logs(logging.DEBUG))
Tarek Ziade1231a4e2011-05-19 13:07:25 +0200870
871 def test_is_setuptools_logs_setup_py_text_not_found(self):
872 directory = self._random_setup_py_pkg()
873 is_setuptools(directory)
Tarek Ziadeb1b6e132011-05-30 12:07:49 +0200874 expected = ['setup.py file found.', 'No egg-info directory found.',
875 'No setuptools text found in setup.py.']
876 self.assertEqual(expected, self.get_logs(logging.DEBUG))
Tarek Ziade1231a4e2011-05-19 13:07:25 +0200877
878 def test_is_setuptools_logs_egg_info_dir_found(self):
879 is_setuptools(self._setuptools_egg_info_pkg())
Tarek Ziadeb1b6e132011-05-30 12:07:49 +0200880 expected = ['setup.py file found.', 'Found egg-info directory.']
881 self.assertEqual(expected, self.get_logs(logging.DEBUG))
Tarek Ziade1231a4e2011-05-19 13:07:25 +0200882
883 def test_is_distutils_logs_setup_py_text_found(self):
884 is_distutils(self._distutils_setup_py_pkg())
Tarek Ziadeb1b6e132011-05-30 12:07:49 +0200885 expected = ['setup.py file found.',
886 'No PKG-INFO file found.',
887 'Found distutils text in setup.py.']
888 self.assertEqual(expected, self.get_logs(logging.DEBUG))
Tarek Ziade1231a4e2011-05-19 13:07:25 +0200889
890 def test_is_distutils_logs_setup_py_text_not_found(self):
891 directory = self._random_setup_py_pkg()
892 is_distutils(directory)
Tarek Ziadeb1b6e132011-05-30 12:07:49 +0200893 expected = ['setup.py file found.', 'No PKG-INFO file found.',
894 'No distutils text found in setup.py.']
895 self.assertEqual(expected, self.get_logs(logging.DEBUG))
Tarek Ziade1231a4e2011-05-19 13:07:25 +0200896
897 def test_is_distutils_logs_pkg_info_file_found(self):
898 is_distutils(self._distutils_pkg_info())
Tarek Ziadeb1b6e132011-05-30 12:07:49 +0200899 expected = ['setup.py file found.', 'PKG-INFO file found.']
900 self.assertEqual(expected, self.get_logs(logging.DEBUG))
Tarek Ziade1231a4e2011-05-19 13:07:25 +0200901
902 def test_is_packaging_logs_setup_cfg_found(self):
903 is_packaging(self._valid_setup_cfg_pkg())
Tarek Ziadeb1b6e132011-05-30 12:07:49 +0200904 expected = ['setup.cfg file found.']
905 self.assertEqual(expected, self.get_logs(logging.DEBUG))
Tarek Ziade1231a4e2011-05-19 13:07:25 +0200906
907 def test_is_packaging_logs_setup_cfg_not_found(self):
908 is_packaging(self._empty_dir)
Tarek Ziadeb1b6e132011-05-30 12:07:49 +0200909 expected = ['No setup.cfg file found.']
910 self.assertEqual(expected, self.get_logs(logging.DEBUG))
Tarek Ziade1231a4e2011-05-19 13:07:25 +0200911
912 def _write_setuptools_setup_py(self, directory):
913 self.write_file((directory, 'setup.py'),
914 "from setuptools import setup")
915
916 def _write_distutils_setup_py(self, directory):
917 self.write_file([directory, 'setup.py'],
918 "from distutils.core import setup")
919
920 def _write_packaging_setup_cfg(self, directory):
921 self.write_file([directory, 'setup.cfg'],
922 ("[metadata]\n"
923 "name = mypackage\n"
924 "version = 0.1.0\n"))
925
926 def _setuptools_setup_py_pkg(self):
927 tmp = self.mkdtemp()
928 self._write_setuptools_setup_py(tmp)
929 return tmp
930
931 def _distutils_setup_py_pkg(self):
932 tmp = self.mkdtemp()
933 self._write_distutils_setup_py(tmp)
934 return tmp
935
936 def _valid_setup_cfg_pkg(self):
937 tmp = self.mkdtemp()
938 self._write_packaging_setup_cfg(tmp)
939 return tmp
940
941 def _setuptools_egg_info_pkg(self):
942 tmp = self.mkdtemp()
943 self._write_setuptools_setup_py(tmp)
944 tempfile.mkdtemp(suffix='.egg-info', dir=tmp)
945 return tmp
946
947 def _distutils_pkg_info(self):
948 tmp = self._distutils_setup_py_pkg()
949 self.write_file([tmp, 'PKG-INFO'], '')
950 return tmp
951
952 def _setup_cfg_with_no_metadata_pkg(self):
953 tmp = self.mkdtemp()
954 self.write_file([tmp, 'setup.cfg'],
955 ("[othersection]\n"
956 "foo = bar\n"))
957 return tmp
958
959 def _invalid_setup_cfg_pkg(self):
960 tmp = self.mkdtemp()
961 self.write_file([tmp, 'setup.cfg'],
962 ("[metadata]\n"
963 "name = john\n"
964 "last_name = doe\n"))
965 return tmp
966
967 def _egg_info_with_no_setuptools(self):
968 tmp = self._random_setup_py_pkg()
969 tempfile.mkdtemp(suffix='.egg-info', dir=tmp)
970 return tmp
971
972 def _pkg_info_with_no_distutils(self):
973 tmp = self._random_setup_py_pkg()
974 self.write_file([tmp, 'PKG-INFO'], '')
975 return tmp
976
977 def _random_setup_py_pkg(self):
978 tmp = self.mkdtemp()
979 self.write_file((tmp, 'setup.py'), "from mypackage import setup")
980 return tmp
981
982
983def test_suite():
984 suite = unittest.makeSuite(UtilTestCase)
985 suite.addTest(unittest.makeSuite(GlobTestCase))
986 suite.addTest(unittest.makeSuite(EggInfoToDistInfoTestCase))
987 suite.addTest(unittest.makeSuite(PackagingLibChecks))
988 return suite
989
990
991if __name__ == "__main__":
992 unittest.main(defaultTest="test_suite")