summaryrefslogtreecommitdiff
path: root/setuptools/command
diff options
context:
space:
mode:
authorAnderson Bravalheri <andersonbravalheri@gmail.com>2022-05-19 10:48:10 +0100
committerAnderson Bravalheri <andersonbravalheri@gmail.com>2022-06-15 16:43:42 +0100
commite36951eb0afaf61a845672d060324ab3e90190d1 (patch)
treeee886414c04d6365c360c9d9f5dbda3fb6d34ecd /setuptools/command
parent2bddfdffbcb2fc76092d2d6029669f1bb96a742a (diff)
parent92ba2c8c4a34f40d480ee35509afc1a58f0a5f7a (diff)
downloadpython-setuptools-git-e36951eb0afaf61a845672d060324ab3e90190d1.tar.gz
Merge branch 'upstream/main' into build-editable-aggregate
Diffstat (limited to 'setuptools/command')
-rw-r--r--setuptools/command/build.py24
-rw-r--r--setuptools/command/build_py.py62
-rw-r--r--setuptools/command/dist_info.py3
3 files changed, 85 insertions, 4 deletions
diff --git a/setuptools/command/build.py b/setuptools/command/build.py
new file mode 100644
index 00000000..12a43622
--- /dev/null
+++ b/setuptools/command/build.py
@@ -0,0 +1,24 @@
+from distutils.command.build import build as _build
+import warnings
+
+from setuptools import SetuptoolsDeprecationWarning
+
+
+_ORIGINAL_SUBCOMMANDS = {"build_py", "build_clib", "build_ext", "build_scripts"}
+
+
+class build(_build):
+ # copy to avoid sharing the object with parent class
+ sub_commands = _build.sub_commands[:]
+
+ def run(self):
+ subcommands = {cmd[0] for cmd in _build.sub_commands}
+ if subcommands - _ORIGINAL_SUBCOMMANDS:
+ msg = """
+ It seems that you are using `distutils.command.build` to add
+ new subcommands. Using `distutils` directly is considered deprecated,
+ please use `setuptools.command.build`.
+ """
+ warnings.warn(msg, SetuptoolsDeprecationWarning)
+ self.sub_commands = _build.sub_commands
+ super().run()
diff --git a/setuptools/command/build_py.py b/setuptools/command/build_py.py
index c3fdc092..2fced3d6 100644
--- a/setuptools/command/build_py.py
+++ b/setuptools/command/build_py.py
@@ -1,3 +1,4 @@
+from functools import partial
from glob import glob
from distutils.util import convert_path
import distutils.command.build_py as orig
@@ -8,6 +9,9 @@ import io
import distutils.errors
import itertools
import stat
+import warnings
+from pathlib import Path
+from setuptools._deprecation_warning import SetuptoolsDeprecationWarning
from setuptools.extern.more_itertools import unique_everseen
@@ -98,7 +102,7 @@ class build_py(orig.build_py):
package,
src_dir,
)
- globs_expanded = map(glob, patterns)
+ globs_expanded = map(partial(glob, recursive=True), patterns)
# flatten the expanded globs into an iterable of matches
globs_matches = itertools.chain.from_iterable(globs_expanded)
glob_files = filter(os.path.isfile, globs_matches)
@@ -129,6 +133,7 @@ class build_py(orig.build_py):
src_dirs[assert_relative(self.get_package_dir(package))] = package
self.run_command('egg_info')
+ check = _IncludePackageDataAbuse()
ei_cmd = self.get_finalized_command('egg_info')
for path in ei_cmd.filelist.files:
d, f = os.path.split(assert_relative(path))
@@ -139,8 +144,13 @@ class build_py(orig.build_py):
d, df = os.path.split(d)
f = os.path.join(df, f)
if d in src_dirs:
- if path.endswith('.py') and f == oldf:
- continue # it's a module, not data
+ if f == oldf:
+ if check.is_module(f):
+ continue # it's a module, not data
+ else:
+ importable = check.importable_subpackage(src_dirs[d], f)
+ if importable:
+ check.warn(importable)
mf.setdefault(src_dirs[d], []).append(path)
def get_data_files(self):
@@ -240,3 +250,49 @@ def assert_relative(path):
% path
)
raise DistutilsSetupError(msg)
+
+
+class _IncludePackageDataAbuse:
+ """Inform users that package or module is included as 'data file'"""
+
+ MESSAGE = """\
+ Installing {importable!r} as data is deprecated, please list it in `packages`.
+ !!\n\n
+ ############################
+ # Package would be ignored #
+ ############################
+ Python recognizes {importable!r} as an importable package,
+ but it is not listed in the `packages` configuration of setuptools.
+
+ {importable!r} has been automatically added to the distribution only
+ because it may contain data files, but this behavior is likely to change
+ in future versions of setuptools (and therefore is considered deprecated).
+
+ Please make sure that {importable!r} is included as a package by using
+ the `packages` configuration field or the proper discovery methods
+ (for example by using `find_namespace_packages(...)`/`find_namespace:`
+ instead of `find_packages(...)`/`find:`).
+
+ You can read more about "package discovery" and "data files" on setuptools
+ documentation page.
+ \n\n!!
+ """
+
+ def __init__(self):
+ self._already_warned = set()
+
+ def is_module(self, file):
+ return file.endswith(".py") and file[:-len(".py")].isidentifier()
+
+ def importable_subpackage(self, parent, file):
+ pkg = Path(file).parent
+ parts = list(itertools.takewhile(str.isidentifier, pkg.parts))
+ if parts:
+ return ".".join([parent, *parts])
+ return None
+
+ def warn(self, importable):
+ if importable not in self._already_warned:
+ msg = textwrap.dedent(self.MESSAGE).format(importable=importable)
+ warnings.warn(msg, SetuptoolsDeprecationWarning, stacklevel=2)
+ self._already_warned.add(importable)
diff --git a/setuptools/command/dist_info.py b/setuptools/command/dist_info.py
index 8b8509f3..ca540ad1 100644
--- a/setuptools/command/dist_info.py
+++ b/setuptools/command/dist_info.py
@@ -54,7 +54,8 @@ def _version(version: str) -> str:
try:
return str(packaging.version.Version(v)).replace("-", "_")
except packaging.version.InvalidVersion:
- msg = f"""!!\n\n
+ msg = f"""Invalid version: {version!r}.
+ !!\n\n
###################
# Invalid version #
###################