We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
[FR] Auto-include license files in source distributions
### What's the problem this feature will solve?

License files are only included in the source distribution if they are specified in either `license_file`, `license_files` or `MANIFEST.in`. `wheel` automatically adds a few common glob patterns if the `license_files` option isn't specified. https://wheel.readthedocs.io/en/stable/user_guide.html#including-license-files-in-the-generated-wheel-file

The result is a situation where a license file is included in the wheel, but not in the source distribution.

### Describe the solution you'd like

Match the behavior of `wheel` and include the most common glob patterns automatically if neither `license_file` nor `license_files` is specified.

### Alternative Solutions

 --

### Additional context

PR that originally added support for `license_files`: https://github.com/pypa/setuptools/pull/1767
Commit that added glob patterns in `wheel`: https://github.com/pypa/wheel/commit/59976ab294e1b118f42cab404d95df66ed55f7e4


### Code of Conduct

- [X] I agree to follow the PSF Code of Conduct

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `setuptools/command/sdist.py`
Content:
```
1 from distutils import log
2 import distutils.command.sdist as orig
3 import os
4 import sys
5 import io
6 import contextlib
7 
8 from setuptools.extern import ordered_set
9 
10 from .py36compat import sdist_add_defaults
11 
12 import pkg_resources
13 
14 _default_revctrl = list
15 
16 
17 def walk_revctrl(dirname=''):
18     """Find all files under revision control"""
19     for ep in pkg_resources.iter_entry_points('setuptools.file_finders'):
20         for item in ep.load()(dirname):
21             yield item
22 
23 
24 class sdist(sdist_add_defaults, orig.sdist):
25     """Smart sdist that finds anything supported by revision control"""
26 
27     user_options = [
28         ('formats=', None,
29          "formats for source distribution (comma-separated list)"),
30         ('keep-temp', 'k',
31          "keep the distribution tree around after creating " +
32          "archive file(s)"),
33         ('dist-dir=', 'd',
34          "directory to put the source distribution archive(s) in "
35          "[default: dist]"),
36     ]
37 
38     negative_opt = {}
39 
40     README_EXTENSIONS = ['', '.rst', '.txt', '.md']
41     READMES = tuple('README{0}'.format(ext) for ext in README_EXTENSIONS)
42 
43     def run(self):
44         self.run_command('egg_info')
45         ei_cmd = self.get_finalized_command('egg_info')
46         self.filelist = ei_cmd.filelist
47         self.filelist.append(os.path.join(ei_cmd.egg_info, 'SOURCES.txt'))
48         self.check_readme()
49 
50         # Run sub commands
51         for cmd_name in self.get_sub_commands():
52             self.run_command(cmd_name)
53 
54         self.make_distribution()
55 
56         dist_files = getattr(self.distribution, 'dist_files', [])
57         for file in self.archive_files:
58             data = ('sdist', '', file)
59             if data not in dist_files:
60                 dist_files.append(data)
61 
62     def initialize_options(self):
63         orig.sdist.initialize_options(self)
64 
65         self._default_to_gztar()
66 
67     def _default_to_gztar(self):
68         # only needed on Python prior to 3.6.
69         if sys.version_info >= (3, 6, 0, 'beta', 1):
70             return
71         self.formats = ['gztar']
72 
73     def make_distribution(self):
74         """
75         Workaround for #516
76         """
77         with self._remove_os_link():
78             orig.sdist.make_distribution(self)
79 
80     @staticmethod
81     @contextlib.contextmanager
82     def _remove_os_link():
83         """
84         In a context, remove and restore os.link if it exists
85         """
86 
87         class NoValue:
88             pass
89 
90         orig_val = getattr(os, 'link', NoValue)
91         try:
92             del os.link
93         except Exception:
94             pass
95         try:
96             yield
97         finally:
98             if orig_val is not NoValue:
99                 setattr(os, 'link', orig_val)
100 
101     def _add_defaults_optional(self):
102         super()._add_defaults_optional()
103         if os.path.isfile('pyproject.toml'):
104             self.filelist.append('pyproject.toml')
105 
106     def _add_defaults_python(self):
107         """getting python files"""
108         if self.distribution.has_pure_modules():
109             build_py = self.get_finalized_command('build_py')
110             self.filelist.extend(build_py.get_source_files())
111             self._add_data_files(self._safe_data_files(build_py))
112 
113     def _safe_data_files(self, build_py):
114         """
115         Extracting data_files from build_py is known to cause
116         infinite recursion errors when `include_package_data`
117         is enabled, so suppress it in that case.
118         """
119         if self.distribution.include_package_data:
120             return ()
121         return build_py.data_files
122 
123     def _add_data_files(self, data_files):
124         """
125         Add data files as found in build_py.data_files.
126         """
127         self.filelist.extend(
128             os.path.join(src_dir, name)
129             for _, src_dir, _, filenames in data_files
130             for name in filenames
131         )
132 
133     def _add_defaults_data_files(self):
134         try:
135             super()._add_defaults_data_files()
136         except TypeError:
137             log.warn("data_files contains unexpected objects")
138 
139     def check_readme(self):
140         for f in self.READMES:
141             if os.path.exists(f):
142                 return
143         else:
144             self.warn(
145                 "standard file not found: should have one of " +
146                 ', '.join(self.READMES)
147             )
148 
149     def make_release_tree(self, base_dir, files):
150         orig.sdist.make_release_tree(self, base_dir, files)
151 
152         # Save any egg_info command line options used to create this sdist
153         dest = os.path.join(base_dir, 'setup.cfg')
154         if hasattr(os, 'link') and os.path.exists(dest):
155             # unlink and re-copy, since it might be hard-linked, and
156             # we don't want to change the source version
157             os.unlink(dest)
158             self.copy_file('setup.cfg', dest)
159 
160         self.get_finalized_command('egg_info').save_version_info(dest)
161 
162     def _manifest_is_not_generated(self):
163         # check for special comment used in 2.7.1 and higher
164         if not os.path.isfile(self.manifest):
165             return False
166 
167         with io.open(self.manifest, 'rb') as fp:
168             first_line = fp.readline()
169         return (first_line !=
170                 '# file GENERATED by distutils, do NOT edit\n'.encode())
171 
172     def read_manifest(self):
173         """Read the manifest file (named by 'self.manifest') and use it to
174         fill in 'self.filelist', the list of files to include in the source
175         distribution.
176         """
177         log.info("reading manifest file '%s'", self.manifest)
178         manifest = open(self.manifest, 'rb')
179         for line in manifest:
180             # The manifest must contain UTF-8. See #303.
181             try:
182                 line = line.decode('UTF-8')
183             except UnicodeDecodeError:
184                 log.warn("%r not UTF-8 decodable -- skipping" % line)
185                 continue
186             # ignore comments and blank lines
187             line = line.strip()
188             if line.startswith('#') or not line:
189                 continue
190             self.filelist.append(line)
191         manifest.close()
192 
193     def check_license(self):
194         """Checks if license_file' or 'license_files' is configured and adds any
195         valid paths to 'self.filelist'.
196         """
197 
198         files = ordered_set.OrderedSet()
199 
200         opts = self.distribution.get_option_dict('metadata')
201 
202         # ignore the source of the value
203         _, license_file = opts.get('license_file', (None, None))
204 
205         if license_file is None:
206             log.debug("'license_file' option was not specified")
207         else:
208             files.add(license_file)
209 
210         try:
211             files.update(self.distribution.metadata.license_files)
212         except TypeError:
213             log.warn("warning: 'license_files' option is malformed")
214 
215         for f in files:
216             if not os.path.exists(f):
217                 log.warn(
218                     "warning: Failed to find the configured license file '%s'",
219                     f)
220                 files.remove(f)
221 
222         self.filelist.extend(files)
223
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/setuptools/command/sdist.py b/setuptools/command/sdist.py
--- a/setuptools/command/sdist.py
+++ b/setuptools/command/sdist.py
@@ -4,6 +4,7 @@
 import sys
 import io
 import contextlib
+from glob import iglob
 
 from setuptools.extern import ordered_set
 
@@ -194,29 +195,41 @@
         """Checks if license_file' or 'license_files' is configured and adds any
         valid paths to 'self.filelist'.
         """
-
-        files = ordered_set.OrderedSet()
-
         opts = self.distribution.get_option_dict('metadata')
 
-        # ignore the source of the value
-        _, license_file = opts.get('license_file', (None, None))
-
-        if license_file is None:
-            log.debug("'license_file' option was not specified")
-        else:
-            files.add(license_file)
-
+        files = ordered_set.OrderedSet()
         try:
-            files.update(self.distribution.metadata.license_files)
+            license_files = self.distribution.metadata.license_files
         except TypeError:
             log.warn("warning: 'license_files' option is malformed")
-
-        for f in files:
-            if not os.path.exists(f):
-                log.warn(
-                    "warning: Failed to find the configured license file '%s'",
-                    f)
-                files.remove(f)
-
-        self.filelist.extend(files)
+            license_files = ordered_set.OrderedSet()
+        patterns = license_files if isinstance(license_files, ordered_set.OrderedSet) \
+            else ordered_set.OrderedSet(license_files)
+
+        if 'license_file' in opts:
+            log.warn(
+                "warning: the 'license_file' option is deprecated, "
+                "use 'license_files' instead")
+            patterns.append(opts['license_file'][1])
+
+        if 'license_file' not in opts and 'license_files' not in opts:
+            # Default patterns match the ones wheel uses
+            # See https://wheel.readthedocs.io/en/stable/user_guide.html
+            # -> 'Including license files in the generated wheel file'
+            patterns = ('LICEN[CS]E*', 'COPYING*', 'NOTICE*', 'AUTHORS*')
+
+        for pattern in patterns:
+            for path in iglob(pattern):
+                if path.endswith('~'):
+                    log.debug(
+                        "ignoring license file '%s' as it looks like a backup",
+                        path)
+                    continue
+
+                if path not in files and os.path.isfile(path):
+                    log.info(
+                        "adding license file '%s' (matched pattern '%s')",
+                        path, pattern)
+                    files.add(path)
+
+        self.filelist.extend(sorted(files))

{"golden_diff": "diff --git a/setuptools/command/sdist.py b/setuptools/command/sdist.py\n--- a/setuptools/command/sdist.py\n+++ b/setuptools/command/sdist.py\n@@ -4,6 +4,7 @@\n import sys\n import io\n import contextlib\n+from glob import iglob\n \n from setuptools.extern import ordered_set\n \n@@ -194,29 +195,41 @@\n         \"\"\"Checks if license_file' or 'license_files' is configured and adds any\n         valid paths to 'self.filelist'.\n         \"\"\"\n-\n-        files = ordered_set.OrderedSet()\n-\n         opts = self.distribution.get_option_dict('metadata')\n \n-        # ignore the source of the value\n-        _, license_file = opts.get('license_file', (None, None))\n-\n-        if license_file is None:\n-            log.debug(\"'license_file' option was not specified\")\n-        else:\n-            files.add(license_file)\n-\n+        files = ordered_set.OrderedSet()\n         try:\n-            files.update(self.distribution.metadata.license_files)\n+            license_files = self.distribution.metadata.license_files\n         except TypeError:\n             log.warn(\"warning: 'license_files' option is malformed\")\n-\n-        for f in files:\n-            if not os.path.exists(f):\n-                log.warn(\n-                    \"warning: Failed to find the configured license file '%s'\",\n-                    f)\n-                files.remove(f)\n-\n-        self.filelist.extend(files)\n+            license_files = ordered_set.OrderedSet()\n+        patterns = license_files if isinstance(license_files, ordered_set.OrderedSet) \\\n+            else ordered_set.OrderedSet(license_files)\n+\n+        if 'license_file' in opts:\n+            log.warn(\n+                \"warning: the 'license_file' option is deprecated, \"\n+                \"use 'license_files' instead\")\n+            patterns.append(opts['license_file'][1])\n+\n+        if 'license_file' not in opts and 'license_files' not in opts:\n+            # Default patterns match the ones wheel uses\n+            # See https://wheel.readthedocs.io/en/stable/user_guide.html\n+            # -> 'Including license files in the generated wheel file'\n+            patterns = ('LICEN[CS]E*', 'COPYING*', 'NOTICE*', 'AUTHORS*')\n+\n+        for pattern in patterns:\n+            for path in iglob(pattern):\n+                if path.endswith('~'):\n+                    log.debug(\n+                        \"ignoring license file '%s' as it looks like a backup\",\n+                        path)\n+                    continue\n+\n+                if path not in files and os.path.isfile(path):\n+                    log.info(\n+                        \"adding license file '%s' (matched pattern '%s')\",\n+                        path, pattern)\n+                    files.add(path)\n+\n+        self.filelist.extend(sorted(files))\n", "issue": "[FR] Auto-include license files in source distributions\n### What's the problem this feature will solve?\n\nLicense files are only included in the source distribution if they are specified in either `license_file`, `license_files` or `MANIFEST.in`. `wheel` automatically adds a few common glob patterns if the `license_files` option isn't specified. https://wheel.readthedocs.io/en/stable/user_guide.html#including-license-files-in-the-generated-wheel-file\r\n\r\nThe result is a situation where a license file is included in the wheel, but not in the source distribution.\n\n### Describe the solution you'd like\n\nMatch the behavior of `wheel` and include the most common glob patterns automatically if neither `license_file` nor `license_files` is specified.\n\n### Alternative Solutions\n\n --\n\n### Additional context\n\nPR that originally added support for `license_files`: https://github.com/pypa/setuptools/pull/1767\r\nCommit that added glob patterns in `wheel`: https://github.com/pypa/wheel/commit/59976ab294e1b118f42cab404d95df66ed55f7e4\r\n\n\n### Code of Conduct\n\n- [X] I agree to follow the PSF Code of Conduct\n", "before_files": [{"content": "from distutils import log\nimport distutils.command.sdist as orig\nimport os\nimport sys\nimport io\nimport contextlib\n\nfrom setuptools.extern import ordered_set\n\nfrom .py36compat import sdist_add_defaults\n\nimport pkg_resources\n\n_default_revctrl = list\n\n\ndef walk_revctrl(dirname=''):\n    \"\"\"Find all files under revision control\"\"\"\n    for ep in pkg_resources.iter_entry_points('setuptools.file_finders'):\n        for item in ep.load()(dirname):\n            yield item\n\n\nclass sdist(sdist_add_defaults, orig.sdist):\n    \"\"\"Smart sdist that finds anything supported by revision control\"\"\"\n\n    user_options = [\n        ('formats=', None,\n         \"formats for source distribution (comma-separated list)\"),\n        ('keep-temp', 'k',\n         \"keep the distribution tree around after creating \" +\n         \"archive file(s)\"),\n        ('dist-dir=', 'd',\n         \"directory to put the source distribution archive(s) in \"\n         \"[default: dist]\"),\n    ]\n\n    negative_opt = {}\n\n    README_EXTENSIONS = ['', '.rst', '.txt', '.md']\n    READMES = tuple('README{0}'.format(ext) for ext in README_EXTENSIONS)\n\n    def run(self):\n        self.run_command('egg_info')\n        ei_cmd = self.get_finalized_command('egg_info')\n        self.filelist = ei_cmd.filelist\n        self.filelist.append(os.path.join(ei_cmd.egg_info, 'SOURCES.txt'))\n        self.check_readme()\n\n        # Run sub commands\n        for cmd_name in self.get_sub_commands():\n            self.run_command(cmd_name)\n\n        self.make_distribution()\n\n        dist_files = getattr(self.distribution, 'dist_files', [])\n        for file in self.archive_files:\n            data = ('sdist', '', file)\n            if data not in dist_files:\n                dist_files.append(data)\n\n    def initialize_options(self):\n        orig.sdist.initialize_options(self)\n\n        self._default_to_gztar()\n\n    def _default_to_gztar(self):\n        # only needed on Python prior to 3.6.\n        if sys.version_info >= (3, 6, 0, 'beta', 1):\n            return\n        self.formats = ['gztar']\n\n    def make_distribution(self):\n        \"\"\"\n        Workaround for #516\n        \"\"\"\n        with self._remove_os_link():\n            orig.sdist.make_distribution(self)\n\n    @staticmethod\n    @contextlib.contextmanager\n    def _remove_os_link():\n        \"\"\"\n        In a context, remove and restore os.link if it exists\n        \"\"\"\n\n        class NoValue:\n            pass\n\n        orig_val = getattr(os, 'link', NoValue)\n        try:\n            del os.link\n        except Exception:\n            pass\n        try:\n            yield\n        finally:\n            if orig_val is not NoValue:\n                setattr(os, 'link', orig_val)\n\n    def _add_defaults_optional(self):\n        super()._add_defaults_optional()\n        if os.path.isfile('pyproject.toml'):\n            self.filelist.append('pyproject.toml')\n\n    def _add_defaults_python(self):\n        \"\"\"getting python files\"\"\"\n        if self.distribution.has_pure_modules():\n            build_py = self.get_finalized_command('build_py')\n            self.filelist.extend(build_py.get_source_files())\n            self._add_data_files(self._safe_data_files(build_py))\n\n    def _safe_data_files(self, build_py):\n        \"\"\"\n        Extracting data_files from build_py is known to cause\n        infinite recursion errors when `include_package_data`\n        is enabled, so suppress it in that case.\n        \"\"\"\n        if self.distribution.include_package_data:\n            return ()\n        return build_py.data_files\n\n    def _add_data_files(self, data_files):\n        \"\"\"\n        Add data files as found in build_py.data_files.\n        \"\"\"\n        self.filelist.extend(\n            os.path.join(src_dir, name)\n            for _, src_dir, _, filenames in data_files\n            for name in filenames\n        )\n\n    def _add_defaults_data_files(self):\n        try:\n            super()._add_defaults_data_files()\n        except TypeError:\n            log.warn(\"data_files contains unexpected objects\")\n\n    def check_readme(self):\n        for f in self.READMES:\n            if os.path.exists(f):\n                return\n        else:\n            self.warn(\n                \"standard file not found: should have one of \" +\n                ', '.join(self.READMES)\n            )\n\n    def make_release_tree(self, base_dir, files):\n        orig.sdist.make_release_tree(self, base_dir, files)\n\n        # Save any egg_info command line options used to create this sdist\n        dest = os.path.join(base_dir, 'setup.cfg')\n        if hasattr(os, 'link') and os.path.exists(dest):\n            # unlink and re-copy, since it might be hard-linked, and\n            # we don't want to change the source version\n            os.unlink(dest)\n            self.copy_file('setup.cfg', dest)\n\n        self.get_finalized_command('egg_info').save_version_info(dest)\n\n    def _manifest_is_not_generated(self):\n        # check for special comment used in 2.7.1 and higher\n        if not os.path.isfile(self.manifest):\n            return False\n\n        with io.open(self.manifest, 'rb') as fp:\n            first_line = fp.readline()\n        return (first_line !=\n                '# file GENERATED by distutils, do NOT edit\\n'.encode())\n\n    def read_manifest(self):\n        \"\"\"Read the manifest file (named by 'self.manifest') and use it to\n        fill in 'self.filelist', the list of files to include in the source\n        distribution.\n        \"\"\"\n        log.info(\"reading manifest file '%s'\", self.manifest)\n        manifest = open(self.manifest, 'rb')\n        for line in manifest:\n            # The manifest must contain UTF-8. See #303.\n            try:\n                line = line.decode('UTF-8')\n            except UnicodeDecodeError:\n                log.warn(\"%r not UTF-8 decodable -- skipping\" % line)\n                continue\n            # ignore comments and blank lines\n            line = line.strip()\n            if line.startswith('#') or not line:\n                continue\n            self.filelist.append(line)\n        manifest.close()\n\n    def check_license(self):\n        \"\"\"Checks if license_file' or 'license_files' is configured and adds any\n        valid paths to 'self.filelist'.\n        \"\"\"\n\n        files = ordered_set.OrderedSet()\n\n        opts = self.distribution.get_option_dict('metadata')\n\n        # ignore the source of the value\n        _, license_file = opts.get('license_file', (None, None))\n\n        if license_file is None:\n            log.debug(\"'license_file' option was not specified\")\n        else:\n            files.add(license_file)\n\n        try:\n            files.update(self.distribution.metadata.license_files)\n        except TypeError:\n            log.warn(\"warning: 'license_files' option is malformed\")\n\n        for f in files:\n            if not os.path.exists(f):\n                log.warn(\n                    \"warning: Failed to find the configured license file '%s'\",\n                    f)\n                files.remove(f)\n\n        self.filelist.extend(files)\n", "path": "setuptools/command/sdist.py"}], "after_files": [{"content": "from distutils import log\nimport distutils.command.sdist as orig\nimport os\nimport sys\nimport io\nimport contextlib\nfrom glob import iglob\n\nfrom setuptools.extern import ordered_set\n\nfrom .py36compat import sdist_add_defaults\n\nimport pkg_resources\n\n_default_revctrl = list\n\n\ndef walk_revctrl(dirname=''):\n    \"\"\"Find all files under revision control\"\"\"\n    for ep in pkg_resources.iter_entry_points('setuptools.file_finders'):\n        for item in ep.load()(dirname):\n            yield item\n\n\nclass sdist(sdist_add_defaults, orig.sdist):\n    \"\"\"Smart sdist that finds anything supported by revision control\"\"\"\n\n    user_options = [\n        ('formats=', None,\n         \"formats for source distribution (comma-separated list)\"),\n        ('keep-temp', 'k',\n         \"keep the distribution tree around after creating \" +\n         \"archive file(s)\"),\n        ('dist-dir=', 'd',\n         \"directory to put the source distribution archive(s) in \"\n         \"[default: dist]\"),\n    ]\n\n    negative_opt = {}\n\n    README_EXTENSIONS = ['', '.rst', '.txt', '.md']\n    READMES = tuple('README{0}'.format(ext) for ext in README_EXTENSIONS)\n\n    def run(self):\n        self.run_command('egg_info')\n        ei_cmd = self.get_finalized_command('egg_info')\n        self.filelist = ei_cmd.filelist\n        self.filelist.append(os.path.join(ei_cmd.egg_info, 'SOURCES.txt'))\n        self.check_readme()\n\n        # Run sub commands\n        for cmd_name in self.get_sub_commands():\n            self.run_command(cmd_name)\n\n        self.make_distribution()\n\n        dist_files = getattr(self.distribution, 'dist_files', [])\n        for file in self.archive_files:\n            data = ('sdist', '', file)\n            if data not in dist_files:\n                dist_files.append(data)\n\n    def initialize_options(self):\n        orig.sdist.initialize_options(self)\n\n        self._default_to_gztar()\n\n    def _default_to_gztar(self):\n        # only needed on Python prior to 3.6.\n        if sys.version_info >= (3, 6, 0, 'beta', 1):\n            return\n        self.formats = ['gztar']\n\n    def make_distribution(self):\n        \"\"\"\n        Workaround for #516\n        \"\"\"\n        with self._remove_os_link():\n            orig.sdist.make_distribution(self)\n\n    @staticmethod\n    @contextlib.contextmanager\n    def _remove_os_link():\n        \"\"\"\n        In a context, remove and restore os.link if it exists\n        \"\"\"\n\n        class NoValue:\n            pass\n\n        orig_val = getattr(os, 'link', NoValue)\n        try:\n            del os.link\n        except Exception:\n            pass\n        try:\n            yield\n        finally:\n            if orig_val is not NoValue:\n                setattr(os, 'link', orig_val)\n\n    def _add_defaults_optional(self):\n        super()._add_defaults_optional()\n        if os.path.isfile('pyproject.toml'):\n            self.filelist.append('pyproject.toml')\n\n    def _add_defaults_python(self):\n        \"\"\"getting python files\"\"\"\n        if self.distribution.has_pure_modules():\n            build_py = self.get_finalized_command('build_py')\n            self.filelist.extend(build_py.get_source_files())\n            self._add_data_files(self._safe_data_files(build_py))\n\n    def _safe_data_files(self, build_py):\n        \"\"\"\n        Extracting data_files from build_py is known to cause\n        infinite recursion errors when `include_package_data`\n        is enabled, so suppress it in that case.\n        \"\"\"\n        if self.distribution.include_package_data:\n            return ()\n        return build_py.data_files\n\n    def _add_data_files(self, data_files):\n        \"\"\"\n        Add data files as found in build_py.data_files.\n        \"\"\"\n        self.filelist.extend(\n            os.path.join(src_dir, name)\n            for _, src_dir, _, filenames in data_files\n            for name in filenames\n        )\n\n    def _add_defaults_data_files(self):\n        try:\n            super()._add_defaults_data_files()\n        except TypeError:\n            log.warn(\"data_files contains unexpected objects\")\n\n    def check_readme(self):\n        for f in self.READMES:\n            if os.path.exists(f):\n                return\n        else:\n            self.warn(\n                \"standard file not found: should have one of \" +\n                ', '.join(self.READMES)\n            )\n\n    def make_release_tree(self, base_dir, files):\n        orig.sdist.make_release_tree(self, base_dir, files)\n\n        # Save any egg_info command line options used to create this sdist\n        dest = os.path.join(base_dir, 'setup.cfg')\n        if hasattr(os, 'link') and os.path.exists(dest):\n            # unlink and re-copy, since it might be hard-linked, and\n            # we don't want to change the source version\n            os.unlink(dest)\n            self.copy_file('setup.cfg', dest)\n\n        self.get_finalized_command('egg_info').save_version_info(dest)\n\n    def _manifest_is_not_generated(self):\n        # check for special comment used in 2.7.1 and higher\n        if not os.path.isfile(self.manifest):\n            return False\n\n        with io.open(self.manifest, 'rb') as fp:\n            first_line = fp.readline()\n        return (first_line !=\n                '# file GENERATED by distutils, do NOT edit\\n'.encode())\n\n    def read_manifest(self):\n        \"\"\"Read the manifest file (named by 'self.manifest') and use it to\n        fill in 'self.filelist', the list of files to include in the source\n        distribution.\n        \"\"\"\n        log.info(\"reading manifest file '%s'\", self.manifest)\n        manifest = open(self.manifest, 'rb')\n        for line in manifest:\n            # The manifest must contain UTF-8. See #303.\n            try:\n                line = line.decode('UTF-8')\n            except UnicodeDecodeError:\n                log.warn(\"%r not UTF-8 decodable -- skipping\" % line)\n                continue\n            # ignore comments and blank lines\n            line = line.strip()\n            if line.startswith('#') or not line:\n                continue\n            self.filelist.append(line)\n        manifest.close()\n\n    def check_license(self):\n        \"\"\"Checks if license_file' or 'license_files' is configured and adds any\n        valid paths to 'self.filelist'.\n        \"\"\"\n        opts = self.distribution.get_option_dict('metadata')\n\n        files = ordered_set.OrderedSet()\n        try:\n            license_files = self.distribution.metadata.license_files\n        except TypeError:\n            log.warn(\"warning: 'license_files' option is malformed\")\n            license_files = ordered_set.OrderedSet()\n        patterns = license_files if isinstance(license_files, ordered_set.OrderedSet) \\\n            else ordered_set.OrderedSet(license_files)\n\n        if 'license_file' in opts:\n            log.warn(\n                \"warning: the 'license_file' option is deprecated, \"\n                \"use 'license_files' instead\")\n            patterns.append(opts['license_file'][1])\n\n        if 'license_file' not in opts and 'license_files' not in opts:\n            # Default patterns match the ones wheel uses\n            # See https://wheel.readthedocs.io/en/stable/user_guide.html\n            # -> 'Including license files in the generated wheel file'\n            patterns = ('LICEN[CS]E*', 'COPYING*', 'NOTICE*', 'AUTHORS*')\n\n        for pattern in patterns:\n            for path in iglob(pattern):\n                if path.endswith('~'):\n                    log.debug(\n                        \"ignoring license file '%s' as it looks like a backup\",\n                        path)\n                    continue\n\n                if path not in files and os.path.isfile(path):\n                    log.info(\n                        \"adding license file '%s' (matched pattern '%s')\",\n                        path, pattern)\n                    files.add(path)\n\n        self.filelist.extend(sorted(files))\n", "path": "setuptools/command/sdist.py"}]}