Skip to content

Commit

Permalink
Merge pull request #2712 from darkvertex/data_files_glob_directive
Browse files Browse the repository at this point in the history
Implement #1681 (globbing support for `[options.data_files]`)
  • Loading branch information
jaraco committed Aug 26, 2021
2 parents 0c302d2 + 353f3fc commit 78b975b
Show file tree
Hide file tree
Showing 4 changed files with 67 additions and 1 deletion.
1 change: 1 addition & 0 deletions changelog.d/2712.change.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Added implicit globbing support for `[options.data_files]` values.
1 change: 1 addition & 0 deletions docs/userguide/declarative_config.rst
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ boilerplate code in some cases.
site.d/00_default.conf
host.d/00_default.conf
data = data/img/logo.png, data/svg/icon.svg
fonts = data/fonts/*.ttf, data/fonts/*.otf
Metadata and options are set in the config sections of the same name.

Expand Down
31 changes: 30 additions & 1 deletion setuptools/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
from collections import defaultdict
from functools import partial
from functools import wraps
from glob import iglob
import contextlib

from distutils.errors import DistutilsOptionError, DistutilsFileError
Expand Down Expand Up @@ -255,6 +256,34 @@ def _parse_list(cls, value, separator=','):

return [chunk.strip() for chunk in value if chunk.strip()]

@classmethod
def _parse_list_glob(cls, value, separator=','):
"""Equivalent to _parse_list() but expands any glob patterns using glob().
However, unlike with glob() calls, the results remain relative paths.
:param value:
:param separator: List items separator character.
:rtype: list
"""
glob_characters = ('*', '?', '[', ']', '{', '}')
values = cls._parse_list(value, separator=separator)
expanded_values = []
for value in values:

# Has globby characters?
if any(char in value for char in glob_characters):
# then expand the glob pattern while keeping paths *relative*:
expanded_values.extend(sorted(
os.path.relpath(path, os.getcwd())
for path in iglob(os.path.abspath(value))))

else:
# take the value as-is:
expanded_values.append(value)

return expanded_values

@classmethod
def _parse_dict(cls, value):
"""Represents value as a dict.
Expand Down Expand Up @@ -711,5 +740,5 @@ def parse_section_data_files(self, section_options):
:param dict section_options:
"""
parsed = self._parse_section_to_dict(section_options, self._parse_list)
parsed = self._parse_section_to_dict(section_options, self._parse_list_glob)
self['data_files'] = [(k, v) for k, v in parsed.items()]
35 changes: 35 additions & 0 deletions setuptools/tests/test_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -893,6 +893,41 @@ def test_data_files(self, tmpdir):
]
assert sorted(dist.data_files) == sorted(expected)

def test_data_files_globby(self, tmpdir):
fake_env(
tmpdir,
'[options.data_files]\n'
'cfg =\n'
' a/b.conf\n'
' c/d.conf\n'
'data = *.dat\n'
'icons = \n'
' *.ico\n'
'audio = \n'
' *.wav\n'
' sounds.db\n'
)

# Create dummy files for glob()'s sake:
tmpdir.join('a.dat').write('')
tmpdir.join('b.dat').write('')
tmpdir.join('c.dat').write('')
tmpdir.join('a.ico').write('')
tmpdir.join('b.ico').write('')
tmpdir.join('c.ico').write('')
tmpdir.join('beep.wav').write('')
tmpdir.join('boop.wav').write('')
tmpdir.join('sounds.db').write('')

with get_dist(tmpdir) as dist:
expected = [
('cfg', ['a/b.conf', 'c/d.conf']),
('data', ['a.dat', 'b.dat', 'c.dat']),
('icons', ['a.ico', 'b.ico', 'c.ico']),
('audio', ['beep.wav', 'boop.wav', 'sounds.db']),
]
assert sorted(dist.data_files) == sorted(expected)

def test_python_requires_simple(self, tmpdir):
fake_env(
tmpdir,
Expand Down

0 comments on commit 78b975b

Please sign in to comment.