diff options
| -rw-r--r-- | Lib/packaging/config.py | 25 | ||||
| -rw-r--r-- | Lib/packaging/create.py | 36 | ||||
| -rw-r--r-- | Lib/packaging/tests/test_command_build_py.py | 18 | ||||
| -rw-r--r-- | Lib/packaging/tests/test_command_sdist.py | 1 | ||||
| -rw-r--r-- | Lib/packaging/tests/test_config.py | 37 | ||||
| -rw-r--r-- | Lib/packaging/tests/test_create.py | 25 | ||||
| -rw-r--r-- | Misc/NEWS | 4 | 
7 files changed, 99 insertions, 47 deletions
| diff --git a/Lib/packaging/config.py b/Lib/packaging/config.py index 366faea4ed..ab026a83b6 100644 --- a/Lib/packaging/config.py +++ b/Lib/packaging/config.py @@ -20,7 +20,6 @@ def _check_name(name, packages):      if '.' not in name:          return      parts = name.split('.') -    modname = parts[-1]      parent = '.'.join(parts[:-1])      if parent not in packages:          # we could log a warning instead of raising, but what's the use @@ -227,13 +226,25 @@ class Config:                  self.dist.scripts = [self.dist.scripts]              self.dist.package_data = {} +            # bookkeeping for the loop below +            firstline = True +            prev = None +              for line in files.get('package_data', []): -                data = line.split('=') -                if len(data) != 2: -                    raise ValueError('invalid line for package_data: %s ' -                                     '(misses "=")' % line) -                key, value = data -                self.dist.package_data[key.strip()] = value.strip() +                if '=' in line: +                    # package name -- file globs or specs +                    key, value = line.split('=') +                    prev = self.dist.package_data[key.strip()] = value.split() +                elif firstline: +                    # invalid continuation on the first line +                    raise PackagingOptionError( +                        'malformed package_data first line: %r (misses "=")' % +                        line) +                else: +                    # continuation, add to last seen package name +                    prev.extend(line.split()) + +                firstline = False              self.dist.data_files = []              for data in files.get('data_files', []): diff --git a/Lib/packaging/create.py b/Lib/packaging/create.py index 5abe47b37d..3d45ca9f90 100644 --- a/Lib/packaging/create.py +++ b/Lib/packaging/create.py @@ -287,6 +287,7 @@ class MainProgram:              # optional string entries              if 'keywords' in self.data and self.data['keywords']: +                # XXX shoud use comma to separate, not space                  fp.write('keywords = %s\n' % ' '.join(self.data['keywords']))              for name in ('home_page', 'author', 'author_email',                           'maintainer', 'maintainer_email', 'description-file'): @@ -306,17 +307,29 @@ class MainProgram:                  fp.write('%s = ' % name)                  fp.write(''.join('    %s\n' % val                                   for val in self.data[name]).lstrip()) +              fp.write('\n[files]\n') -            for name in ('packages', 'modules', 'scripts', -                         'package_data', 'extra_files'): + +            for name in ('packages', 'modules', 'scripts', 'extra_files'):                  if not(name in self.data and self.data[name]):                      continue                  fp.write('%s = %s\n'                           % (name, '\n    '.join(self.data[name]).strip())) -            fp.write('\nresources =\n') -            for src, dest in self.data['resources']: -                fp.write('    %s = %s\n' % (src, dest)) -            fp.write('\n') + +            if self.data.get('package_data'): +                fp.write('package_data =\n') +                for pkg, spec in sorted(self.data['package_data'].items()): +                    # put one spec per line, indented under the package name +                    indent = ' ' * (len(pkg) + 7) +                    spec = ('\n' + indent).join(spec) +                    fp.write('    %s = %s\n' % (pkg, spec)) +                fp.write('\n') + +            if self.data.get('resources'): +                fp.write('resources =\n') +                for src, dest in self.data['resources']: +                    fp.write('    %s = %s\n' % (src, dest)) +                fp.write('\n')          os.chmod(_FILENAME, 0o644)          logger.info('Wrote "%s".' % _FILENAME) @@ -349,7 +362,6 @@ class MainProgram:                        ('long_description', 'description'),                        ('url', 'home_page'),                        ('platforms', 'platform'), -                      # backport only for 2.5+                        ('provides', 'provides-dist'),                        ('obsoletes', 'obsoletes-dist'),                        ('requires', 'requires-dist')) @@ -385,14 +397,8 @@ class MainProgram:                                   for src in srcs]                          data['resources'].extend(files) -            # 2.2 package_data -> extra_files -            package_dirs = dist.package_dir or {} -            for package, extras in dist.package_data.items() or []: -                package_dir = package_dirs.get(package, package) -                for file_ in extras: -                    if package_dir: -                        file_ = package_dir + '/' + file_ -                    data['extra_files'].append(file_) +            # 2.2 package_data +            data['package_data'] = dist.package_data.copy()              # Use README file if its content is the desciption              if "description" in data: diff --git a/Lib/packaging/tests/test_command_build_py.py b/Lib/packaging/tests/test_command_build_py.py index f7f26dafe9..0599bf23bf 100644 --- a/Lib/packaging/tests/test_command_build_py.py +++ b/Lib/packaging/tests/test_command_build_py.py @@ -24,11 +24,17 @@ class BuildPyTestCase(support.TempdirManager,              f.write("# Pretend this is a package.")          finally:              f.close() +        # let's have two files to make sure globbing works          f = open(os.path.join(pkg_dir, "README.txt"), "w")          try:              f.write("Info about this package")          finally:              f.close() +        f = open(os.path.join(pkg_dir, "HACKING.txt"), "w") +        try: +            f.write("How to contribute") +        finally: +            f.close()          destination = self.mkdtemp() @@ -42,7 +48,7 @@ class BuildPyTestCase(support.TempdirManager,              convert_2to3_doctests=None,              use_2to3=False)          dist.packages = ["pkg"] -        dist.package_data = {"pkg": ["README.txt"]} +        dist.package_data = {"pkg": ["*.txt"]}          dist.package_dir = sources          cmd = build_py(dist) @@ -55,15 +61,19 @@ class BuildPyTestCase(support.TempdirManager,          # This makes sure the list of outputs includes byte-compiled          # files for Python modules but not for package data files          # (there shouldn't *be* byte-code files for those!). -        # -        self.assertEqual(len(cmd.get_outputs()), 3) +        # FIXME the test below is not doing what the comment above says, and +        # if it did it would show a code bug: if we add a demo.py file to +        # package_data, it gets byte-compiled! +        outputs = cmd.get_outputs() +        self.assertEqual(len(outputs), 4, outputs)          pkgdest = os.path.join(destination, "pkg")          files = os.listdir(pkgdest)          pycache_dir = os.path.join(pkgdest, "__pycache__")          self.assertIn("__init__.py", files)          self.assertIn("README.txt", files) +        self.assertIn("HACKING.txt", files)          pyc_files = os.listdir(pycache_dir) -        self.assertIn("__init__.%s.pyc" % imp.get_tag(), pyc_files) +        self.assertEqual(["__init__.%s.pyc" % imp.get_tag()], pyc_files)      def test_empty_package_dir(self):          # See SF 1668596/1720897. diff --git a/Lib/packaging/tests/test_command_sdist.py b/Lib/packaging/tests/test_command_sdist.py index 47c455e146..d9747189d1 100644 --- a/Lib/packaging/tests/test_command_sdist.py +++ b/Lib/packaging/tests/test_command_sdist.py @@ -73,7 +73,6 @@ class SDistTestCase(support.TempdirManager,                          'author_email': 'xxx'}          dist = Distribution(metadata)          dist.packages = ['somecode'] -        dist.include_package_data = True          cmd = sdist(dist)          cmd.dist_dir = 'dist'          return dist, cmd diff --git a/Lib/packaging/tests/test_config.py b/Lib/packaging/tests/test_config.py index 613d493916..0d76b29a04 100644 --- a/Lib/packaging/tests/test_config.py +++ b/Lib/packaging/tests/test_config.py @@ -66,11 +66,15 @@ scripts =    bin/taunt  package_data = -  cheese = data/templates/* +  cheese = data/templates/* doc/* +      doc/images/*.png +  extra_files = %(extra-files)s  # Replaces MANIFEST.in +# FIXME no, it's extra_files +# (but sdist_extra is a better name, should use it)  sdist_extra =    include THANKS HACKING    recursive-include examples *.txt *.py @@ -96,6 +100,17 @@ setup_hooks = %(setup-hooks)s  sub_commands = foo  """ +SETUP_CFG_PKGDATA_BUGGY_1 = """ +[files] +package_data = foo.* +""" + +SETUP_CFG_PKGDATA_BUGGY_2 = """ +[files] +package_data = +    foo.* +""" +  # Can not be merged with SETUP_CFG else install_dist  # command will fail when trying to compile C sources  # TODO use a DummyCommand to mock build_ext @@ -276,13 +291,14 @@ class ConfigTestCase(support.TempdirManager,          self.assertEqual(dist.packages, ['one', 'two', 'three'])          self.assertEqual(dist.py_modules, ['haven']) -        self.assertEqual(dist.package_data, {'cheese': 'data/templates/*'}) -        self.assertEqual( +        self.assertEqual(dist.package_data, +                         {'cheese': ['data/templates/*', 'doc/*', +                                     'doc/images/*.png']}) +        self.assertEqual(dist.data_files,              {'bm/b1.gif': '{icon}/b1.gif',               'bm/b2.gif': '{icon}/b2.gif',               'Cfg/data.CFG': '{config}/baBar/data.CFG', -             'init_script': '{script}/JunGle/init_script'}, -             dist.data_files) +             'init_script': '{script}/JunGle/init_script'})          self.assertEqual(dist.package_dir, 'src') @@ -293,8 +309,8 @@ class ConfigTestCase(support.TempdirManager,          # this file would be __main__.Foo when run as "python test_config.py".          # The name FooBarBazTest should be unique enough to prevent          # collisions. -        self.assertEqual('FooBarBazTest', -                         dist.get_command_obj('foo').__class__.__name__) +        self.assertEqual(dist.get_command_obj('foo').__class__.__name__, +                         'FooBarBazTest')          # did the README got loaded ?          self.assertEqual(dist.metadata['description'], 'yeah') @@ -304,6 +320,13 @@ class ConfigTestCase(support.TempdirManager,          d = new_compiler(compiler='d')          self.assertEqual(d.description, 'D Compiler') +        # check error reporting for invalid package_data value +        self.write_file('setup.cfg', SETUP_CFG_PKGDATA_BUGGY_1) +        self.assertRaises(PackagingOptionError, self.get_dist) + +        self.write_file('setup.cfg', SETUP_CFG_PKGDATA_BUGGY_2) +        self.assertRaises(PackagingOptionError, self.get_dist) +      def test_multiple_description_file(self):          self.write_setup({'description-file': 'README  CHANGES'})          self.write_file('README', 'yeah') diff --git a/Lib/packaging/tests/test_create.py b/Lib/packaging/tests/test_create.py index 07824b1aa8..76bc3316b4 100644 --- a/Lib/packaging/tests/test_create.py +++ b/Lib/packaging/tests/test_create.py @@ -116,7 +116,6 @@ class CreateTestCase(support.TempdirManager,                package_data={                    'babar': ['Pom', 'Flora', 'Alexander'],                    'me': ['dady', 'mumy', 'sys', 'bro'], -                  '':  ['setup.py', 'README'],                    'pyxfoil': ['fengine.so'],                             },                scripts=['my_script', 'bin/run'], @@ -150,16 +149,15 @@ class CreateTestCase(support.TempdirManager,                  mymodule              scripts = my_script                  bin/run -            extra_files = Martinique/Lamentin/dady -                Martinique/Lamentin/mumy -                Martinique/Lamentin/sys -                Martinique/Lamentin/bro -                setup.py -                README -                Pom -                Flora -                Alexander -                pyxfoil/fengine.so +            package_data = +                babar = Pom +                        Flora +                        Alexander +                me = dady +                     mumy +                     sys +                     bro +                pyxfoil = fengine.so              resources =                  README.rst = {doc} @@ -217,8 +215,9 @@ ho, baby!              [files]              packages = pyxfoil -            extra_files = pyxfoil/fengine.so -                pyxfoil/babar.so +            package_data = +                pyxfoil = fengine.so +                          babar.so              resources =                  README.rst = {doc} @@ -466,6 +466,10 @@ Core and Builtins  Library  ------- +- Issue #13712: pysetup create should not convert package_data to extra_files. + +- Issue #11805: package_data in setup.cfg should allow more than one value. +  - Issue #13933: IDLE auto-complete did not work with some imported    module, like hashlib.  (Patch by Roger Serwy) | 
