|
import ast |
|
import json |
|
import textwrap |
|
from pathlib import Path |
|
|
|
|
|
def iter_namespace_pkgs(namespace): |
|
parts = namespace.split(".") |
|
for i in range(len(parts)): |
|
yield ".".join(parts[: i + 1]) |
|
|
|
|
|
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) |
|
|
|
script = textwrap.dedent( |
|
"""\ |
|
import setuptools |
|
args = {args} |
|
setuptools.setup(**args) |
|
""" |
|
).format(args=args) |
|
setup_py.write_text(script, encoding='utf-8') |
|
|
|
ns_pkg_dir = Path(src_dir, namespace.replace(".", "/")) |
|
ns_pkg_dir.mkdir(parents=True) |
|
|
|
for ns in namespaces: |
|
pkg_init = src_dir / ns.replace(".", "/") / '__init__.py' |
|
pkg_init.write_text(tmpl, encoding='utf-8') |
|
|
|
pkg_mod = ns_pkg_dir / (rest + '.py') |
|
some_functionality = 'name = {rest!r}'.format(**locals()) |
|
pkg_mod.write_text(some_functionality, encoding='utf-8') |
|
return src_dir |
|
|
|
|
|
def build_pep420_namespace_package(tmpdir, name): |
|
src_dir = tmpdir / name |
|
src_dir.mkdir() |
|
pyproject = src_dir / "pyproject.toml" |
|
namespace, _, rest = name.rpartition(".") |
|
script = f"""\ |
|
[build-system] |
|
requires = ["setuptools"] |
|
build-backend = "setuptools.build_meta" |
|
|
|
[project] |
|
name = "{name}" |
|
version = "3.14159" |
|
""" |
|
pyproject.write_text(textwrap.dedent(script), encoding='utf-8') |
|
ns_pkg_dir = Path(src_dir, namespace.replace(".", "/")) |
|
ns_pkg_dir.mkdir(parents=True) |
|
pkg_mod = ns_pkg_dir / (rest + ".py") |
|
some_functionality = f"name = {rest!r}" |
|
pkg_mod.write_text(some_functionality, encoding='utf-8') |
|
return src_dir |
|
|
|
|
|
def make_site_dir(target): |
|
""" |
|
Add a sitecustomize.py module in target to cause |
|
target to be added to site dirs such that .pth files |
|
are processed there. |
|
""" |
|
sc = target / 'sitecustomize.py' |
|
target_str = str(target) |
|
tmpl = '__import__("site").addsitedir({target_str!r})' |
|
sc.write_text(tmpl.format(**locals()), encoding='utf-8') |
|
|