Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,10 @@ def prepare_no_build_isolation(self) -> None:

@pytest.fixture
def isolated(tmp_path: Path, pep518_wheelhouse: Path) -> VEnv:
"""Isolated virtual environment.

To control build isolation, see :py:func:`isolate`
"""
path = tmp_path / "venv"
return VEnv(path, wheelhouse=pep518_wheelhouse)

Expand Down Expand Up @@ -212,6 +216,13 @@ def package(
tmp_path_factory: pytest.TempPathFactory,
monkeypatch: pytest.MonkeyPatch,
) -> PackageInfo:
"""Get the test package.

Parameterize this fixture with the package name in the tests/packages directory.
(Use ``indirect=True`` to pass the parameterization value to the fixture instead of
directly to the test function.)
https://docs.pytest.org/en/stable/example/parametrize.html#indirect-parametrization
"""
pkg_name = request.param
assert isinstance(pkg_name, str)
package = PackageInfo(pkg_name, tmp_path_factory.mktemp("pkg"))
Expand Down Expand Up @@ -256,12 +267,18 @@ def package_simple_pyproject_ext(

@dataclasses.dataclass(frozen=True)
class Isolate:
"""Selection for build isolation."""

state: bool
flags: list[str]


@pytest.fixture(params=[True, False], ids=["isolated", "not_isolated"])
def isolate(request: pytest.FixtureRequest, isolated: VEnv) -> Isolate:
"""Control build isolation.

For an isolated virtual environment, see :py:func:`isolated`
"""
isolate_request = request.param
assert isinstance(isolate_request, bool)
if not isolate_request:
Expand Down
52 changes: 52 additions & 0 deletions tests/packages/cmake_generated/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
cmake_minimum_required(VERSION 3.15)

project(
${SKBUILD_PROJECT_NAME}
LANGUAGES CXX
VERSION 1.2.3)

# Generate files at config time (configure_file) and at build time
# (add_custom_command) Note that bundling a generated file with sdist is out of
# scope for now. Note: cmake_generated/nested1/generated.py should try to open
# both generated and static files.
configure_file(src/cmake_generated/nested1/generated.py.in generated.py)
# We always expect the install phase to run, so the build tree layout can be
# different than the package layout.
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/generated.py
DESTINATION ${SKBUILD_PROJECT_NAME}/nested1)

file(
GENERATE
OUTPUT configured_file
CONTENT "value written by cmake file generation")
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/configured_file
DESTINATION ${SKBUILD_PROJECT_NAME})

set(OUTPUT_FILE "${CMAKE_CURRENT_BINARY_DIR}/generated_data")
set(FILE_CONTENT "value written by cmake custom_command")
set(GENERATE_SCRIPT "file(WRITE \"${OUTPUT_FILE}\" \"${FILE_CONTENT}\")")
add_custom_command(
OUTPUT "${OUTPUT_FILE}"
COMMAND "${CMAKE_COMMAND}" -P
"${CMAKE_CURRENT_BINARY_DIR}/generate_file.cmake"
DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/generate_file.cmake"
COMMENT "Generating ${OUTPUT_FILE} using CMake scripting at build time"
VERBATIM)
file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/generate_file.cmake"
"${GENERATE_SCRIPT}")
add_custom_target(generate_file ALL DEPENDS "${OUTPUT_FILE}")
install(FILES "${OUTPUT_FILE}" DESTINATION ${SKBUILD_PROJECT_NAME}/namespace1)

add_library(pkg MODULE src/cmake_generated/pkg.cpp)
include(GenerateExportHeader)
generate_export_header(pkg)
target_include_directories(pkg PRIVATE ${CMAKE_CURRENT_BINARY_DIR})

if(NOT WIN32)
# Explicitly set the bundle extension to .so
set_target_properties(pkg PROPERTIES SUFFIX ".so")
endif()

# Set the library name to "pkg", regardless of the OS convention.
set_target_properties(pkg PROPERTIES PREFIX "")
install(TARGETS pkg DESTINATION ${SKBUILD_PROJECT_NAME})
24 changes: 24 additions & 0 deletions tests/packages/cmake_generated/pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
[build-system]
requires = ["scikit-build-core"]
build-backend = "scikit_build_core.build"

[project]
name = "cmake_generated"
dynamic = ["version"]

[tool.scikit-build]
# Bundling a generated file in the sdist is not supported at this time.
# sdist.cmake = false
wheel.license-files = []
wheel.exclude = ["**.cpp", "**.in"]

[tool.scikit-build.metadata.version]
provider = "scikit_build_core.metadata.regex"
input = "CMakeLists.txt"
regex = 'project\([^)]+ VERSION (?P<value>[0-9.]+)'

[[tool.scikit-build.generate]]
path = "cmake_generated/_version.py"
template = '''
__version__ = "${version}"
'''
75 changes: 75 additions & 0 deletions tests/packages/cmake_generated/src/cmake_generated/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
"""Package that includes several non-Python non-module files.

Support some test cases aimed at testing our ability to find generated files
and static package data files in editable installations.

We are exercising the importlib machinery to find files that
are generated in different phases of the build and in different parts of
the package layout to check that the redirection works correctly in an
editable installation.

The test package includes raw data files and shared object libraries that
are accessed via `ctypes`.

We test files (generated and static)

* at the top level of the package,
* in subpackages, and
* in a namespace package.

We test access

* from modules at the same level as the files,
* one level above and below, and
* from parallel subpackages.
"""

import ctypes
import sys
from importlib.resources import as_file, files, read_text

try:
from ._version import __version__ # type: ignore[import-not-found]
except ImportError:
__version__ = None


def get_static_data():
return read_text("cmake_generated", "static_data").rstrip()


def get_configured_data():
return files("cmake_generated").joinpath("configured_file").read_text().rstrip()


def get_namespace_static_data():
if sys.version_info[0:2] == (3, 9):
return (
files("cmake_generated")
.joinpath("namespace1/static_data")
.read_text()
.rstrip()
)
# (except in Python 3.9) read_text is able to handle a namespace subpackage directly, though `files()` is not.
return read_text("cmake_generated.namespace1", "static_data").rstrip()


def get_namespace_generated_data():
# Note that `files("cmake_generated.namespace1")` doesn't work.
# Ref https://github.com/python/importlib_resources/issues/262
return (
files("cmake_generated")
.joinpath("namespace1/generated_data")
.read_text()
.rstrip()
)


def ctypes_function():
if sys.platform == "win32":
lib_suffix = "dll"
else:
lib_suffix = "so"
with as_file(files("cmake_generated").joinpath(f"pkg.{lib_suffix}")) as lib_path:
lib = ctypes.cdll.LoadLibrary(str(lib_path))
return lib.func
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
static value in namespace package
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
from importlib.resources import read_text


def get_static_data():
return read_text("cmake_generated.nested1", "static_data").rstrip()
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
"""Try to open both generated and static files from various parts of the package."""
import sys
from importlib.resources import files, read_text
from types import ModuleType

from .. import __version__

try:
from .. import nested2
except ImportError as e:
nested2 = None
import_error = e.msg
else:
import_error = None

def cmake_generated_static_data():
return read_text("cmake_generated", "static_data").rstrip()

def cmake_generated_nested_static_data():
return files("cmake_generated.nested1").joinpath("static_data").read_text().rstrip()

def cmake_generated_namespace_static_data():
# Note that `files("cmake_generated.namespace1")` doesn't work.
# Ref https://github.com/python/importlib_resources/issues/262
return files("cmake_generated").joinpath("namespace1/static_data").read_text().rstrip()

def get_configured_data():
return files("cmake_generated").joinpath("configured_file").read_text().rstrip()

def cmake_generated_namespace_generated_data():
if sys.version_info[0:2] == (3, 9):
return files("cmake_generated").joinpath("namespace1/generated_data").read_text().rstrip()
else:
# (except in Python 3.9) read_text is able to handle a namespace subpackage directly, though `files()` is not.
return read_text("cmake_generated.namespace1","generated_data").rstrip()

nested_data = "success"

def nested2_check():
if import_error is not None:
return import_error
assert isinstance(nested2, ModuleType)
return "success"
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
static value in subpackage 1
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
def nested1_generated_check():
# noinspection PyUnresolvedReferences
from ..nested1.generated import nested_data # type: ignore[import-not-found]

return nested_data
3 changes: 3 additions & 0 deletions tests/packages/cmake_generated/src/cmake_generated/pkg.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#include "pkg_export.h"

extern "C" PKG_EXPORT int func() {return 42;}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
static value in top-level package
Loading
Loading