From 00b4fb1aef3feb77f9db0cd05bfeb02d1fa1cf75 Mon Sep 17 00:00:00 2001 From: Anderson Bravalheri Date: Mon, 4 Apr 2022 20:42:07 +0100 Subject: [PATCH 1/3] Simplify auto-discovered package_dir If the directory follows a src-layout-ish, try harder to make `package_dir` in the form `{"": "src"}`. This might be later important for PEP 660 (e.g. when composing pth files or symlinking the toplevel packages). --- setuptools/config/expand.py | 27 ++++++++++++++++++++-- setuptools/tests/config/test_expand.py | 32 +++++++++++++++++++++++++- 2 files changed, 56 insertions(+), 3 deletions(-) diff --git a/setuptools/config/expand.py b/setuptools/config/expand.py index ff9b2c9bdf..156d747369 100644 --- a/setuptools/config/expand.py +++ b/setuptools/config/expand.py @@ -312,8 +312,12 @@ def find_packages( where = kwargs.pop('where', ['.']) packages: List[str] = [] fill_package_dir = {} if fill_package_dir is None else fill_package_dir + find = list(unique_everseen(always_iterable(where))) - for path in unique_everseen(always_iterable(where)): + if len(find) == 1 and all(not _same_path(find[0], x) for x in (".", root_dir)): + fill_package_dir.setdefault("", find[0]) + + for path in find: package_path = _nest_path(root_dir, path) pkgs = PackageFinder.find(package_path, **kwargs) packages.extend(pkgs) @@ -326,8 +330,27 @@ def find_packages( return packages +def _same_path(p1: _Path, p2: _Path) -> bool: + """Differs from os.path.samefile because it does not require paths to exist. + Purely string based (no comparison between i-nodes). + >>> _same_path("a/b", "./a/b") + True + >>> _same_path("a/b", "a/./b") + True + >>> _same_path("a/b", "././a/b") + True + >>> _same_path("a/b", "./a/b/c/..") + True + >>> _same_path("a/b", "../a/b/c") + False + >>> _same_path("a", "a/b") + False + """ + return os.path.normpath(p1) == os.path.normpath(p2) + + def _nest_path(parent: _Path, path: _Path) -> str: - path = parent if path == "." else os.path.join(parent, path) + path = parent if path in {".", ""} else os.path.join(parent, path) return os.path.normpath(path) diff --git a/setuptools/tests/config/test_expand.py b/setuptools/tests/config/test_expand.py index 3a59edbb74..15053c8f24 100644 --- a/setuptools/tests/config/test_expand.py +++ b/setuptools/tests/config/test_expand.py @@ -130,7 +130,7 @@ def test_resolve_class(tmp_path, package_dir, file, module, return_value): ({}, {"pkg", "other", "dir1", "dir1.dir2"}), # default value for `namespaces` ] ) -def test_find_packages(tmp_path, monkeypatch, args, pkgs): +def test_find_packages(tmp_path, args, pkgs): files = { "pkg/__init__.py", "other/__init__.py", @@ -153,3 +153,33 @@ def test_find_packages(tmp_path, monkeypatch, args, pkgs): ] assert set(expand.find_packages(where=where, **args)) == pkgs + + +@pytest.mark.parametrize( + "files, where, expected_package_dir", + [ + (["pkg1/__init__.py", "pkg1/other.py"], ["."], {}), + (["pkg1/__init__.py", "pkg2/__init__.py"], ["."], {}), + (["src/pkg1/__init__.py", "src/pkg1/other.py"], ["src"], {"": "src"}), + (["src/pkg1/__init__.py", "src/pkg2/__init__.py"], ["src"], {"": "src"}), + ( + ["src1/pkg1/__init__.py", "src2/pkg2/__init__.py"], + ["src1", "src2"], + {"pkg1": "src1/pkg1", "pkg2": "src2/pkg2"}, + ), + ( + ["src/pkg1/__init__.py", "pkg2/__init__.py"], + ["src", "."], + {"pkg1": "src/pkg1"}, + ), + ], +) +def test_fill_package_dir(tmp_path, files, where, expected_package_dir): + write_files({k: "" for k in files}, tmp_path) + pkg_dir = {} + kwargs = {"root_dir": tmp_path, "fill_package_dir": pkg_dir, "namespaces": False} + pkgs = expand.find_packages(where=where, **kwargs) + assert set(pkg_dir.items()) == set(expected_package_dir.items()) + for pkg in pkgs: + pkg_path = find_package_path(pkg, pkg_dir, tmp_path) + assert os.path.exists(pkg_path) From f565df599f5d513bfde355f111bd84e426325f9b Mon Sep 17 00:00:00 2001 From: Anderson Bravalheri Date: Tue, 5 Apr 2022 10:49:29 +0100 Subject: [PATCH 2/3] Add news fragment --- changelog.d/3249.misc.rst | 1 + 1 file changed, 1 insertion(+) create mode 100644 changelog.d/3249.misc.rst diff --git a/changelog.d/3249.misc.rst b/changelog.d/3249.misc.rst new file mode 100644 index 0000000000..3ef85049f5 --- /dev/null +++ b/changelog.d/3249.misc.rst @@ -0,0 +1 @@ +Simplified ``package_dir`` obtained via auto-discovery. From dc6b21b040e31e036c613e8ea88e33a3aee3401d Mon Sep 17 00:00:00 2001 From: Anderson Bravalheri Date: Tue, 5 Apr 2022 10:51:16 +0100 Subject: [PATCH 3/3] Rename variable --- setuptools/config/expand.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/setuptools/config/expand.py b/setuptools/config/expand.py index 156d747369..da55d4eeb6 100644 --- a/setuptools/config/expand.py +++ b/setuptools/config/expand.py @@ -312,12 +312,12 @@ def find_packages( where = kwargs.pop('where', ['.']) packages: List[str] = [] fill_package_dir = {} if fill_package_dir is None else fill_package_dir - find = list(unique_everseen(always_iterable(where))) + search = list(unique_everseen(always_iterable(where))) - if len(find) == 1 and all(not _same_path(find[0], x) for x in (".", root_dir)): - fill_package_dir.setdefault("", find[0]) + if len(search) == 1 and all(not _same_path(search[0], x) for x in (".", root_dir)): + fill_package_dir.setdefault("", search[0]) - for path in find: + for path in search: package_path = _nest_path(root_dir, path) pkgs = PackageFinder.find(package_path, **kwargs) packages.extend(pkgs)