From 88cc6c5b98090b4e1232cd628f79f52d85913e3b Mon Sep 17 00:00:00 2001 From: Anderson Bravalheri Date: Wed, 6 Sep 2023 13:22:40 +0100 Subject: [PATCH] Allow tests to build pkgutil legacy namespaces --- setuptools/tests/namespaces.py | 37 +++++++++++++++-------- setuptools/tests/test_editable_install.py | 15 +++++++-- 2 files changed, 37 insertions(+), 15 deletions(-) diff --git a/setuptools/tests/namespaces.py b/setuptools/tests/namespaces.py index 276157f3a9..85540d3b82 100644 --- a/setuptools/tests/namespaces.py +++ b/setuptools/tests/namespaces.py @@ -1,3 +1,5 @@ +import ast +import json import textwrap @@ -7,23 +9,36 @@ def iter_namespace_pkgs(namespace): yield ".".join(parts[:i+1]) -def build_namespace_package(tmpdir, name, version="1.0"): +def build_namespace_package(tmpdir, name, version="1.0", impl="pkg_resources"): src_dir = tmpdir / name src_dir.mkdir() setup_py = src_dir / 'setup.py' namespace, _, rest = name.rpartition('.') namespaces = list(iter_namespace_pkgs(namespace)) + setup_args = { + "name": name, + "version": version, + "packages": namespaces, + } + + if impl == "pkg_resources": + tmpl = '__import__("pkg_resources").declare_namespace(__name__)' + setup_args["namespace_packages"] = namespaces + elif impl == "pkgutil": + tmpl = '__path__ = __import__("pkgutil").extend_path(__path__, __name__)' + else: + raise ValueError(f"Cannot recognise {impl=} when creating namespaces") + + args = json.dumps(setup_args, indent=4) + assert ast.literal_eval(args) # ensure it is valid Python + script = textwrap.dedent( - """ + """\ import setuptools - setuptools.setup( - name={name!r}, - version={version!r}, - namespace_packages={namespaces!r}, - packages={namespaces!r}, - ) + args = {args} + setuptools.setup(**args) """ - ).format(**locals()) + ).format(args=args) setup_py.write_text(script, encoding='utf-8') ns_pkg_dir = src_dir / namespace.replace(".", "/") @@ -31,9 +46,7 @@ def build_namespace_package(tmpdir, name, version="1.0"): for ns in namespaces: pkg_init = src_dir / ns.replace(".", "/") / '__init__.py' - tmpl = '__import__("pkg_resources").declare_namespace(__name__)' - decl = tmpl.format(**locals()) - pkg_init.write_text(decl, encoding='utf-8') + pkg_init.write_text(tmpl, encoding='utf-8') pkg_mod = ns_pkg_dir / (rest + '.py') some_functionality = 'name = {rest!r}'.format(**locals()) diff --git a/setuptools/tests/test_editable_install.py b/setuptools/tests/test_editable_install.py index 165d93ed2f..12716fd5e1 100644 --- a/setuptools/tests/test_editable_install.py +++ b/setuptools/tests/test_editable_install.py @@ -261,8 +261,17 @@ def test_nspkg_file_is_unique(self, tmp_path, monkeypatch): files = list(installation_dir.glob("*-nspkg.pth")) assert len(files) == len(examples) + @pytest.mark.parametrize( + "impl", + ( + "pkg_resources", + # "pkgutil", => does not work + ) + ) @pytest.mark.parametrize("ns", ("myns.n",)) - def test_namespace_package_importable(self, venv, tmp_path, ns, editable_opts): + def test_namespace_package_importable( + self, venv, tmp_path, ns, impl, editable_opts + ): """ Installing two packages sharing the same namespace, one installed naturally using pip or `--single-version-externally-managed` @@ -275,8 +284,8 @@ def test_namespace_package_importable(self, venv, tmp_path, ns, editable_opts): requires = ["setuptools"] build-backend = "setuptools.build_meta" """ - pkg_A = namespaces.build_namespace_package(tmp_path, f"{ns}.pkgA") - pkg_B = namespaces.build_namespace_package(tmp_path, f"{ns}.pkgB") + pkg_A = namespaces.build_namespace_package(tmp_path, f"{ns}.pkgA", impl=impl) + pkg_B = namespaces.build_namespace_package(tmp_path, f"{ns}.pkgB", impl=impl) (pkg_A / "pyproject.toml").write_text(build_system, encoding="utf-8") (pkg_B / "pyproject.toml").write_text(build_system, encoding="utf-8") # use pip to install to the target directory