Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions newsfragments/5093.bugfix.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
Fixed a Windows-only false ``Package '...' is absent from the `packages`
configuration`` warning (and the resulting misclassification of the file as
package data) that occurred when an ``Extension`` source path written with
forward slashes (the documented, portable form) lived inside a subpackage:
manifest paths and package directories are now normalized before comparison.
6 changes: 4 additions & 2 deletions setuptools/command/build_py.py
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,9 @@ def analyze_manifest(self) -> None:
src_dirs: dict[str, str] = {}
for package in self.packages or ():
# Locate package source directory
src_dirs[assert_relative(self.get_package_dir(package))] = package
src_dirs[
os.path.normpath(assert_relative(self.get_package_dir(package)))
] = package

if (
self.existing_egg_info_dir
Expand All @@ -198,7 +200,7 @@ def analyze_manifest(self) -> None:

check = _IncludePackageDataAbuse()
for path in self._filter_build_files(files, egg_info_dir):
d, f = os.path.split(assert_relative(path))
d, f = os.path.split(assert_relative(os.path.normpath(path)))
prev = None
oldf = f
while d and d != prev and d not in src_dirs:
Expand Down
66 changes: 66 additions & 0 deletions setuptools/tests/test_build_py.py
Original file line number Diff line number Diff line change
Expand Up @@ -479,3 +479,69 @@ def get_outputs(build_py):
os.path.relpath(x, build_dir).replace(os.sep, "/")
for x in build_py.get_outputs()
}


def test_analyze_manifest_mixed_separators(tmpdir_cwd):
"""
A subpackage source path written with forward slashes (the documented,
portable form for ``Extension`` sources) must not be misclassified as
package data of the parent package on Windows due to a separator mismatch
between manifest paths and package dirs.

Regression test for #5093.
"""
jaraco.path.build({
"setup.cfg": DALS(
"""
[metadata]
name = mypkg
version = 42

[options]
include_package_data = True
packages =
mypkg
mypkg.lib
"""
),
"mypkg": {
"__init__.py": "",
"lib": {"__init__.py": "", "say.pyx": "# dummy"},
},
"MANIFEST.in": DALS(
"""
recursive-include mypkg *.pyx
prune dist
prune build
prune *.egg-info
"""
),
})
from setuptools.extension import Extension

dist = Distribution({"script_name": "%PEP 517%"})
dist.parse_config_files()
dist.ext_modules = [Extension("mypkg.lib.say", ["mypkg/lib/say.pyx"])]

egg_info = dist.get_command_obj("egg_info")
dist.run_command("egg_info")

build_py = dist.get_command_obj("build_py")
build_py.finalize_options()
build_py.existing_egg_info_dir = egg_info.egg_info

with warnings.catch_warnings(record=True) as caught:
warnings.simplefilter("always")
build_py.analyze_manifest()

offending = [
w
for w in caught
if issubclass(w.category, SetuptoolsDeprecationWarning)
and "mypkg.lib" in str(w.message)
and "absent" in str(w.message)
]
assert not offending, (
"Subpackage whose extension source is written in Unix form was "
"misclassified as data of the parent package (mixed path separators)"
)