148 lines
4.6 KiB
Python
148 lines
4.6 KiB
Python
from __future__ import annotations
|
|
|
|
import importlib
|
|
import shutil
|
|
import subprocess
|
|
import sys
|
|
import tarfile
|
|
import zipfile
|
|
from dataclasses import dataclass
|
|
from enum import Enum
|
|
from pathlib import Path, PurePosixPath
|
|
|
|
import pytest
|
|
from packaging.specifiers import SpecifierSet
|
|
from packaging.utils import canonicalize_name, parse_wheel_filename
|
|
from packaging.version import Version
|
|
|
|
import dlp_io
|
|
|
|
try:
|
|
import tomllib
|
|
except ModuleNotFoundError: # Python 3.9-3.10
|
|
import tomli as tomllib
|
|
|
|
|
|
PROJECT_ROOT = Path(__file__).resolve().parents[1]
|
|
|
|
|
|
class DynamicField(Enum):
|
|
VERSION = "version"
|
|
|
|
|
|
class PackageName(Enum):
|
|
DLP_IO = canonicalize_name("dlp-io")
|
|
|
|
|
|
class PackageClassifier(Enum):
|
|
WINDOWS = "Operating System :: Microsoft :: Windows"
|
|
|
|
|
|
@dataclass(frozen=True)
|
|
class BuiltDistributions:
|
|
wheel: Path
|
|
sdist: Path
|
|
|
|
|
|
def _load_pyproject() -> dict:
|
|
with (PROJECT_ROOT / "pyproject.toml").open("rb") as file:
|
|
return tomllib.load(file)
|
|
|
|
|
|
@pytest.fixture(scope="module")
|
|
def built_distributions(tmp_path_factory: pytest.TempPathFactory) -> BuiltDistributions:
|
|
root = tmp_path_factory.mktemp("dlp-io-build")
|
|
source = root / "source"
|
|
source.mkdir()
|
|
shutil.copy2(PROJECT_ROOT / "pyproject.toml", source)
|
|
shutil.copy2(PROJECT_ROOT / "MANIFEST.in", source)
|
|
shutil.copytree(PROJECT_ROOT / "dlp_io", source / "dlp_io")
|
|
shutil.copytree(PROJECT_ROOT / "docs", source / "docs")
|
|
|
|
dist = root / "dist"
|
|
completed = subprocess.run(
|
|
[
|
|
sys.executable,
|
|
"-m",
|
|
"build",
|
|
"--no-isolation",
|
|
"--outdir",
|
|
str(dist),
|
|
],
|
|
cwd=source,
|
|
check=False,
|
|
capture_output=True,
|
|
)
|
|
assert completed.returncode == 0
|
|
|
|
wheels = tuple(dist.glob("*.whl"))
|
|
sdists = tuple(dist.glob("*.tar.gz"))
|
|
assert len(wheels) == 1
|
|
assert len(sdists) == 1
|
|
return BuiltDistributions(wheel=wheels[0], sdist=sdists[0])
|
|
|
|
|
|
def test_pyproject_declares_structured_public_package_contract() -> None:
|
|
config = _load_pyproject()
|
|
project = config["project"]
|
|
setuptools = config["tool"]["setuptools"]
|
|
|
|
assert PackageName(canonicalize_name(project["name"])) is PackageName.DLP_IO
|
|
assert SpecifierSet(project["requires-python"]) == SpecifierSet(">=3.9")
|
|
assert {DynamicField(item) for item in project["dynamic"]} == {
|
|
DynamicField.VERSION
|
|
}
|
|
known_classifier_values = {item.value for item in PackageClassifier}
|
|
known_classifiers = {
|
|
PackageClassifier(item)
|
|
for item in project["classifiers"]
|
|
if item in known_classifier_values
|
|
}
|
|
assert PackageClassifier.WINDOWS in known_classifiers
|
|
assert {Path(item) for item in setuptools["packages"]} == {Path("dlp_io")}
|
|
assert {Path(item) for item in setuptools["package-data"]["dlp_io"]} == {
|
|
Path("py.typed")
|
|
}
|
|
|
|
version_ref = config["tool"]["setuptools"]["dynamic"]["version"]["attr"]
|
|
module_name, attribute_name = version_ref.rsplit(".", 1)
|
|
declared_version = getattr(importlib.import_module(module_name), attribute_name)
|
|
assert Version(declared_version) == Version(dlp_io.__version__)
|
|
|
|
|
|
def test_wheel_contains_only_installable_dlp_io_runtime(
|
|
built_distributions: BuiltDistributions,
|
|
) -> None:
|
|
name, version, build, tags = parse_wheel_filename(built_distributions.wheel.name)
|
|
with zipfile.ZipFile(built_distributions.wheel) as archive:
|
|
members = {PurePosixPath(item) for item in archive.namelist()}
|
|
|
|
assert PackageName(name) is PackageName.DLP_IO
|
|
assert version == Version(dlp_io.__version__)
|
|
assert build == ()
|
|
assert tags
|
|
assert PurePosixPath("dlp_io/__init__.py") in members
|
|
assert PurePosixPath("dlp_io/py.typed") in members
|
|
member_roots = {Path(item.parts[0]) for item in members}
|
|
assert member_roots.isdisjoint({Path("tests"), Path("Lib")})
|
|
assert PurePosixPath(".env") not in members
|
|
|
|
|
|
def test_sdist_contains_package_sources_and_public_readme_only(
|
|
built_distributions: BuiltDistributions,
|
|
) -> None:
|
|
with tarfile.open(built_distributions.sdist, mode="r:gz") as archive:
|
|
members = {
|
|
PurePosixPath(*PurePosixPath(item.name).parts[1:])
|
|
for item in archive.getmembers()
|
|
if item.isfile()
|
|
}
|
|
|
|
assert PurePosixPath("pyproject.toml") in members
|
|
assert PurePosixPath("docs/DLP_IO_LIBRARY.md") in members
|
|
assert PurePosixPath("dlp_io/__init__.py") in members
|
|
member_roots = {Path(item.parts[0]) for item in members}
|
|
assert Path("tests") not in member_roots
|
|
assert PurePosixPath("README.md") not in members
|
|
assert PurePosixPath(".env") not in members
|