From 2bdcede71d51966ccabd7be2f8d0565b2545e5ff Mon Sep 17 00:00:00 2001 From: Kevin Deldycke Date: Tue, 20 Aug 2024 20:15:41 +0400 Subject: [PATCH] Explicitely declare package-wide elements --- extra_platforms/__init__.py | 232 +++++++++++++++++++++++++++++++++++- tests/test_platforms.py | 46 +++++++ 2 files changed, 275 insertions(+), 3 deletions(-) diff --git a/extra_platforms/__init__.py b/extra_platforms/__init__.py index 52e70524..60820a7e 100644 --- a/extra_platforms/__init__.py +++ b/extra_platforms/__init__.py @@ -41,9 +41,115 @@ def cache(user_function): # XXX Exposing everything at package level motivates platforms and groups to have a # unique and unambiguous ID. This constraint is enforced at the data-level and checked # in unittests. -from .detection import * -from .groups import * -from .platforms import * +from .detection import ( # noqa: E402 + is_aix, + is_altlinux, + is_amzn, + is_android, + is_arch, + is_buildroot, + is_centos, + is_cloudlinux, + is_cygwin, + is_debian, + is_exherbo, + is_fedora, + is_freebsd, + is_gentoo, + is_guix, + is_hurd, + is_ibm_powerkvm, + is_kvmibm, + is_linuxmint, + is_macos, + is_mageia, + is_mandriva, + is_midnightbsd, + is_netbsd, + is_openbsd, + is_opensuse, + is_oracle, + is_parallels, + is_pidora, + is_raspbian, + is_rhel, + is_rocky, + is_scientific, + is_slackware, + is_sles, + is_solaris, + is_sunos, + is_ubuntu, + is_unknown_linux, + is_windows, + is_wsl1, + is_wsl2, + is_xenserver, +) +from .groups import ( # noqa: E402 + ALL_GROUPS, + ALL_LINUX, + ALL_PLATFORMS, + ALL_WINDOWS, + BSD, + BSD_WITHOUT_MACOS, + EXTRA_GROUPS, + LINUX_LAYERS, + NON_OVERLAPPING_GROUPS, + OTHER_UNIX, + SYSTEM_V, + UNIX, + UNIX_LAYERS, + UNIX_WITHOUT_MACOS, + Group, + reduce, +) +from .platforms import ( # noqa: E402 + AIX, + ALTLINUX, + AMZN, + ANDROID, + ARCH, + BUILDROOT, + CENTOS, + CLOUDLINUX, + CYGWIN, + DEBIAN, + EXHERBO, + FEDORA, + FREEBSD, + GENTOO, + GUIX, + HURD, + IBM_POWERKVM, + KVMIBM, + LINUXMINT, + MACOS, + MAGEIA, + MANDRIVA, + MIDNIGHTBSD, + NETBSD, + OPENBSD, + OPENSUSE, + ORACLE, + PARALLELS, + PIDORA, + RASPBIAN, + RHEL, + ROCKY, + SCIENTIFIC, + SLACKWARE, + SLES, + SOLARIS, + SUNOS, + UBUNTU, + UNKNOWN_LINUX, + WINDOWS, + WSL1, + WSL2, + XENSERVER, + Platform, +) # XXX Not imported at package level so dependency on Pytest can stay optional. # from .pytest import * @@ -92,3 +198,123 @@ def current_os() -> Platform: CURRENT_OS_ID: str = current_os().id CURRENT_OS_LABEL: str = current_os().name """Constants about the current platform.""" + + +__all__ = [ + "AIX", # noqa: F405 + "ALL_GROUPS", # noqa: F405 + "ALL_LINUX", # noqa: F405 + "ALL_OS_LABELS", # noqa: F405 + "ALL_PLATFORMS", # noqa: F405 + "ALL_WINDOWS", # noqa: F405 + "ALTLINUX", # noqa: F405 + "AMZN", # noqa: F405 + "ANDROID", # noqa: F405 + "ARCH", # noqa: F405 + "BSD", # noqa: F405 + "BSD_WITHOUT_MACOS", # noqa: F405 + "BUILDROOT", # noqa: F405 + "CENTOS", # noqa: F405 + "CLOUDLINUX", # noqa: F405 + "current_os", # noqa: F405 + "CURRENT_OS_ID", # noqa: F405 + "CURRENT_OS_LABEL", # noqa: F405 + "CYGWIN", # noqa: F405 + "DEBIAN", # noqa: F405 + "EXHERBO", # noqa: F405 + "EXTRA_GROUPS", # noqa: F405 + "FEDORA", # noqa: F405 + "FREEBSD", # noqa: F405 + "GENTOO", # noqa: F405 + "Group", # noqa: F405 + "GUIX", # noqa: F405 + "HURD", # noqa: F405 + "IBM_POWERKVM", # noqa: F405 + "is_aix", # noqa: F405 + "is_altlinux", # noqa: F405 + "is_amzn", # noqa: F405 + "is_android", # noqa: F405 + "is_arch", # noqa: F405 + "is_buildroot", # noqa: F405 + "is_centos", # noqa: F405 + "is_cloudlinux", # noqa: F405 + "is_cygwin", # noqa: F405 + "is_debian", # noqa: F405 + "is_exherbo", # noqa: F405 + "is_fedora", # noqa: F405 + "is_freebsd", # noqa: F405 + "is_gentoo", # noqa: F405 + "is_guix", # noqa: F405 + "is_hurd", # noqa: F405 + "is_ibm_powerkvm", # noqa: F405 + "is_kvmibm", # noqa: F405 + "is_linuxmint", # noqa: F405 + "is_macos", # noqa: F405 + "is_mageia", # noqa: F405 + "is_mandriva", # noqa: F405 + "is_midnightbsd", # noqa: F405 + "is_netbsd", # noqa: F405 + "is_openbsd", # noqa: F405 + "is_opensuse", # noqa: F405 + "is_oracle", # noqa: F405 + "is_parallels", # noqa: F405 + "is_pidora", # noqa: F405 + "is_raspbian", # noqa: F405 + "is_rhel", # noqa: F405 + "is_rocky", # noqa: F405 + "is_scientific", # noqa: F405 + "is_slackware", # noqa: F405 + "is_sles", # noqa: F405 + "is_solaris", # noqa: F405 + "is_sunos", # noqa: F405 + "is_ubuntu", # noqa: F405 + "is_unknown_linux", # noqa: F405 + "is_windows", # noqa: F405 + "is_wsl1", # noqa: F405 + "is_wsl2", # noqa: F405 + "is_xenserver", # noqa: F405 + "KVMIBM", # noqa: F405 + "LINUX_LAYERS", # noqa: F405 + "LINUXMINT", # noqa: F405 + "MACOS", # noqa: F405 + "MAGEIA", # noqa: F405 + "MANDRIVA", # noqa: F405 + "MIDNIGHTBSD", # noqa: F405 + "NETBSD", # noqa: F405 + "NON_OVERLAPPING_GROUPS", # noqa: F405 + "OPENBSD", # noqa: F405 + "OPENSUSE", # noqa: F405 + "ORACLE", # noqa: F405 + "OTHER_UNIX", # noqa: F405 + "PARALLELS", # noqa: F405 + "PIDORA", # noqa: F405 + "Platform", # noqa: F405 + "RASPBIAN", # noqa: F405 + "reduce", # noqa: F405 + "RHEL", # noqa: F405 + "ROCKY", # noqa: F405 + "SCIENTIFIC", # noqa: F405 + "SLACKWARE", # noqa: F405 + "SLES", # noqa: F405 + "SOLARIS", # noqa: F405 + "SUNOS", # noqa: F405 + "SYSTEM_V", # noqa: F405 + "UBUNTU", # noqa: F405 + "UNIX", # noqa: F405 + "UNIX_LAYERS", # noqa: F405 + "UNIX_WITHOUT_MACOS", # noqa: F405 + "UNKNOWN_LINUX", # noqa: F405 + "WINDOWS", # noqa: F405 + "WSL1", # noqa: F405 + "WSL2", # noqa: F405 + "XENSERVER", # noqa: F405 +] +"""Expose all package-wide elements. + +.. note:: + The content of ``__all__`` is checked and enforced in unittests. + +.. todo:: + Test ruff __all__ formatting capabilities. And if good enough, remove ``__all__`` + checks in unittests. +""" diff --git a/tests/test_platforms.py b/tests/test_platforms.py index a8c4ff50..fd6b17d5 100644 --- a/tests/test_platforms.py +++ b/tests/test_platforms.py @@ -25,6 +25,7 @@ import pytest +import extra_platforms from extra_platforms import ( AIX, ALL_GROUPS, @@ -146,6 +147,51 @@ ) +def test_module_root_declarations(): + def fetch_module_implements(module) -> set[str]: + """Fetch all methods, classes and constants implemented locally in a module's file.""" + members = set() + tree = ast.parse(Path(inspect.getfile(module)).read_bytes()) + for node in tree.body: + if isinstance(node, ast.Assign): + for target in node.targets: + members.add(target.id) + elif isinstance(node, ast.AnnAssign): + members.add(node.target.id) + elif isinstance(node, ast.FunctionDef): + members.add(node.name) + elif isinstance(node, ast.ClassDef): + members.add(node.name) + return {m for m in members if not m.startswith("_")} + + detection_members = fetch_module_implements(detection_module) + groups_members = fetch_module_implements(groups_module) + platforms_members = fetch_module_implements(platforms_module) + root_members = fetch_module_implements(extra_platforms) + + # Check all members are exposed at the module root. + tree = ast.parse(Path(inspect.getfile(extra_platforms)).read_bytes()) + extra_platforms_members = [] + for node in tree.body: + if isinstance(node, ast.Assign): + for target in node.targets: + if target.id == "__all__": + for element in node.value.elts: + extra_platforms_members.append(element.s) + + assert detection_members <= set(extra_platforms_members) + assert groups_members <= set(extra_platforms_members) + assert platforms_members <= set(extra_platforms_members) + + expected_members = sorted( + detection_members.union(groups_members) + .union(platforms_members) + .union(root_members), + key=lambda m: (m.lower(), m), + ) + assert expected_members == extra_platforms_members + + def test_mutual_exclusion(): """Only directly tests OSes on which the test suite is running via GitHub actions."""