Skip to content

Commit 3bae487

Browse files
committed
Add support for Conan v2
1 parent 728bf22 commit 3bae487

File tree

10 files changed

+107
-53
lines changed

10 files changed

+107
-53
lines changed

.github/workflows/test_package.yml

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,14 @@ jobs:
88
matrix:
99
os: [windows-latest, ubuntu-latest, macos-latest]
1010
embedded-py: [3.9.8, 3.11.5]
11+
conan:
12+
- version: 1
13+
args: lumicks/testing --build=missing
14+
- version: 2
15+
args: --user=lumicks --channel=testing --build=missing
16+
name: "${{ matrix.os }}, ${{ matrix.embedded-py }}, v${{ matrix.conan.version }}"
1117
env:
12-
create_pck: conan create . lumicks/testing -o embedded_python-core:version=${{ matrix.embedded-py }} --build=missing
18+
create_pck: conan create . ${{ matrix.conan.args }} -o embedded_python-core/*:version=${{ matrix.embedded-py }}
1319
steps:
1420
- if: runner.os == 'Windows' # `pylake` git clone goes over the limit
1521
run: git config --system core.longpaths true
@@ -18,24 +24,28 @@ jobs:
1824
uses: actions/setup-python@v5
1925
with:
2026
python-version: "3.11"
21-
- name: Set up CXX/C env
22-
if: ${{ matrix.os == 'macos-latest' }}
27+
- if: runner.os == 'macOS'
28+
name: Set up CC/CXX env
2329
run: |
2430
echo CC=/usr/bin/clang >> $GITHUB_ENV
2531
echo CXX=/usr/bin/clang++ >> $GITHUB_ENV
26-
- name: Install Conan
32+
- if: matrix.conan.version == '1'
33+
name: Install Conan v1
2734
run: |
2835
python -m pip install conan==1.64.0
29-
conan config set general.revisions_enabled=True
3036
conan profile new default --detect
31-
conan profile update settings.compiler.cppstd=17 default
37+
- if: matrix.conan.version == '2'
38+
name: Install Conan v2
39+
run: |
40+
python -m pip install conan==2.2.3
41+
conan profile detect
3242
- name: Test core
33-
run: conan create ./core lumicks/testing -o embedded_python-core:version=${{ matrix.embedded-py }} --build=missing
43+
run: conan create ./core ${{ matrix.conan.args }} -o embedded_python-core/*:version=${{ matrix.embedded-py }}
3444
- name: Test baseline
3545
run: ${{ env.create_pck }}
3646
- name: Test with numpy env
37-
run: ${{ env.create_pck }} -o test_embedded_python:env=numpy
47+
run: ${{ env.create_pck }} -o test_embedded_python/*:env=numpy
3848
- name: Test with nbconvert env
39-
run: ${{ env.create_pck }} -o test_embedded_python:env=nbconvert
49+
run: ${{ env.create_pck }} -o test_embedded_python/*:env=nbconvert
4050
- name: Test with pylake env
41-
run: ${{ env.create_pck }} -o test_embedded_python:env=pylake
51+
run: ${{ env.create_pck }} -o test_embedded_python/*:env=pylake

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,4 @@
11
*.pyc
22
__pycache__/
3+
*/test_package/build
4+
CMakeUserPresets.json

changelog.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
## v1.9.0 | In development
44

5+
- Added support for Conan v2.
56
- Removed the obsolete `openssl_variant` option.
67
- Removed redundant `embedded_python:version` option. Use `embedded_python-core:version`.
78

conanfile.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ class EmbeddedPython(ConanFile):
3535
exports_sources = "embedded_python.cmake"
3636

3737
def requirements(self):
38-
self.requires(f"embedded_python-core/1.2.2@{self.user}/{self.channel}")
38+
self.requires(f"embedded_python-core/1.3.0@{self.user}/{self.channel}")
3939

4040
@property
4141
def pyversion(self):

core/conanfile.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
1-
import io
21
import os
2+
import subprocess
33
import sys
44
import shutil
55
import pathlib
66
from conan import ConanFile
7+
from conan.errors import ConanInvalidConfiguration
78
from conan.tools import files, scm
89

910
required_conan_version = ">=1.59.0"
@@ -12,7 +13,7 @@
1213
# noinspection PyUnresolvedReferences
1314
class EmbeddedPythonCore(ConanFile):
1415
name = "embedded_python-core"
15-
version = "1.2.2" # of the Conan package, `options.version` is the Python version
16+
version = "1.3.0" # of the Conan package, `options.version` is the Python version
1617
license = "PSFL"
1718
description = "The core embedded Python (no extra pip packages)"
1819
topics = "embedded", "python"
@@ -154,9 +155,8 @@ def _patch_libpython_path(self, dst):
154155
return
155156

156157
exe = dst / f"python{self.short_pyversion}"
157-
buffer = io.StringIO()
158-
self.run(f"otool -L {exe}", output=buffer)
159-
lines = buffer.getvalue().strip().split("\n")[1:]
158+
p = subprocess.run(["otool", "-L", str(exe)], check=True, text=True, capture_output=True)
159+
lines = str(p.stdout).strip().split("\n")[1:]
160160
libraries = [line.split()[0] for line in lines]
161161
hardcoded_libraries = [lib for lib in libraries if lib.startswith(str(dst))]
162162
for lib in hardcoded_libraries:

core/embedded_python_tools.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import os
22
import shutil
33
import pathlib
4-
from conan.tools.files import copy
4+
from conan.tools import files
55

66

77
def _symlink_compat(conanfile, src, dst):
@@ -12,7 +12,7 @@ def _symlink_compat(conanfile, src, dst):
1212
try:
1313
_winapi.CreateJunction(str(src), str(dst))
1414
except OSError:
15-
copy(conanfile, "*", src, dst)
15+
files.copy(conanfile, "*", src, dst)
1616
else:
1717
os.symlink(src, dst)
1818

@@ -56,7 +56,7 @@ def imports(self):
5656
_symlink_compat(conanfile, src, dst)
5757

5858
bin = pathlib.Path(bin).absolute()
59-
copy(conanfile, "python*.dll", src, bin, keep_path=False)
60-
copy(conanfile, "libpython*.so*", src / "lib", bin, keep_path=False)
61-
copy(conanfile, "libpython*.dylib", src / "lib", bin, keep_path=False)
62-
copy(conanfile, "python*.zip", src, bin, keep_path=False)
59+
files.copy(conanfile, "python*.dll", src, bin, keep_path=False)
60+
files.copy(conanfile, "libpython*.so*", src / "lib", bin, keep_path=False)
61+
files.copy(conanfile, "libpython*.dylib", src / "lib", bin, keep_path=False)
62+
files.copy(conanfile, "python*.zip", src, bin, keep_path=False)

core/test_package/CMakeLists.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@ project(test_package)
44
find_package(embedded_python-core)
55

66
message(STATUS "Python_EXECUTABLE: ${Python_EXECUTABLE}")
7-
if(NOT Python_EXECUTABLE MATCHES "embedded_python-core")
8-
message(FATAL_ERROR "CMake failed to find the correct Python")
7+
if(NOT Python_EXECUTABLE MATCHES "${EXPECTED_PYTHON_CORE_PATH}")
8+
message(FATAL_ERROR "CMake failed to find the correct Python: ${EXPECTED_PYTHON_CORE_PATH}")
99
endif()
1010

1111
add_executable(test_package src/main.cpp)

core/test_package/conanfile.py

Lines changed: 25 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,22 @@
1+
import sys
12
import pathlib
2-
from io import StringIO
3+
import subprocess
4+
import conan
35
from conan import ConanFile
4-
from conan.tools.cmake import CMake, CMakeToolchain
6+
from conan.tools.cmake import CMake, CMakeToolchain, cmake_layout
57

68

79
# noinspection PyUnresolvedReferences
810
class TestEmbeddedPythonCore(ConanFile):
911
name = "test_embedded_python"
1012
settings = "os", "compiler", "build_type", "arch"
11-
generators = "CMakeDeps"
12-
default_options = {"embedded_python-core:version": "3.11.3"}
13+
generators = "CMakeDeps", "VirtualRunEnv"
14+
default_options = {"embedded_python-core/*:version": "3.11.3"}
1315
test_type = "explicit"
1416

17+
def layout(self):
18+
cmake_layout(self)
19+
1520
def requirements(self):
1621
self.requires(self.tested_reference_str)
1722

@@ -22,11 +27,13 @@ def generate(self):
2227
tc.generate()
2328

2429
def build(self):
30+
sys.path.append(str(self._core_package_path))
31+
2532
import embedded_python_tools
2633

2734
embedded_python_tools.symlink_import(self, dst="bin/python")
2835
cmake = CMake(self)
29-
cmake.configure()
36+
cmake.configure(variables={"EXPECTED_PYTHON_CORE_PATH": self._core_package_path.as_posix()})
3037
cmake.build()
3138

3239
@property
@@ -36,6 +43,13 @@ def _py_exe(self):
3643
else:
3744
return pathlib.Path(self.build_folder, "bin/python/bin/python3")
3845

46+
@property
47+
def _core_package_path(self):
48+
if conan.__version__.startswith("2"):
49+
return pathlib.Path(self.dependencies["embedded_python-core"].package_folder)
50+
else:
51+
return pathlib.Path(self.deps_cpp_info["embedded_python-core"].rootpath)
52+
3953
def _test_stdlib(self):
4054
"""Ensure that Python runs and built the optional stdlib modules"""
4155
self.run(f'{self._py_exe} -c "import sys; print(sys.version);"')
@@ -46,9 +60,10 @@ def _test_libpython_path(self):
4660
if self.settings.os != "Macos":
4761
return
4862

49-
buffer = StringIO()
50-
self.run(f"otool -L {self._py_exe}", run_environment=True, output=buffer)
51-
lines = buffer.getvalue().strip().split("\n")[1:]
63+
p = subprocess.run(
64+
["otool", "-L", str(self._py_exe)], check=True, text=True, capture_output=True
65+
)
66+
lines = str(p.stdout).strip().split("\n")[1:]
5267
libraries = [line.split()[0] for line in lines]
5368
candidates = [lib for lib in libraries if "libpython" in lib]
5469
assert candidates, f"libpython dependency not found in 'otool' output: {libraries}"
@@ -57,12 +72,11 @@ def _test_libpython_path(self):
5772

5873
def _test_embed(self):
5974
"""Ensure that everything is available to compile and link to the embedded Python"""
60-
self.run(pathlib.Path("bin", "test_package"), run_environment=True)
75+
self.run(pathlib.Path("bin", "test_package"), env="conanrun")
6176

6277
def _test_licenses(self):
6378
"""Ensure that the license file is included"""
64-
license_dir = pathlib.Path(self.deps_cpp_info["embedded_python-core"].rootpath, "licenses")
65-
file = license_dir / "LICENSE.txt"
79+
file = self._core_package_path / "licenses/LICENSE.txt"
6680
print(f"{file}: {file.stat().st_size}")
6781

6882
def test(self):

test_package/CMakeLists.txt

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,15 @@ project(test_package)
44
find_package(embedded_python)
55

66
message(STATUS "Python_EXECUTABLE: ${Python_EXECUTABLE}")
7-
if(NOT Python_EXECUTABLE MATCHES "embedded_python-core")
8-
message(FATAL_ERROR "CMake failed to find the correct Python")
7+
if(NOT Python_EXECUTABLE MATCHES "${EXPECTED_PYTHON_CORE_PATH}")
8+
message(FATAL_ERROR "CMake failed to find the correct Python: ${EXPECTED_PYTHON_CORE_PATH}")
99
endif()
1010
message(STATUS "EmbeddedPython_EXECUTABLE: ${EmbeddedPython_EXECUTABLE}")
11-
if(EmbeddedPython_EXECUTABLE MATCHES "embedded_python-core")
12-
message(FATAL_ERROR "CMake found the `-core` package instead of the full environment")
11+
if(EmbeddedPython_EXECUTABLE MATCHES "${EXPECTED_PYTHON_CORE_PATH}")
12+
message(FATAL_ERROR "CMake found the `-core` package instead of the full environment: ${EXPECTED_PYTHON_PATH}")
1313
endif()
14-
if(NOT EmbeddedPython_EXECUTABLE MATCHES "embedded_python")
15-
message(FATAL_ERROR "CMake failed to find the correct Python")
14+
if(NOT EmbeddedPython_EXECUTABLE MATCHES "${EXPECTED_PYTHON_PATH}")
15+
message(FATAL_ERROR "CMake failed to find the correct Python: ${EXPECTED_PYTHON_PATH}")
1616
endif()
1717

1818
add_executable(test_package ../core/test_package/src/main.cpp)

test_package/conanfile.py

Lines changed: 39 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
1-
import pathlib
21
import sys
3-
from io import StringIO
2+
import pathlib
3+
import subprocess
4+
import conan
45
from conan import ConanFile
5-
from conan.tools.cmake import CMake, CMakeToolchain
6+
from conan.tools.cmake import CMake, CMakeToolchain, cmake_layout
67

78
project_root = pathlib.Path(__file__).parent
89

@@ -16,13 +17,33 @@ def _read_env(name):
1617
class TestEmbeddedPython(ConanFile):
1718
name = "test_embedded_python"
1819
settings = "os", "compiler", "build_type", "arch"
19-
generators = "CMakeDeps"
20+
generators = "CMakeDeps", "VirtualRunEnv"
2021
options = {"env": [None, "ANY"]}
2122
default_options = {
2223
"env": None,
23-
"embedded_python-core:version": "3.11.5",
24+
"embedded_python-core/*:version": "3.11.5",
2425
}
2526

27+
@property
28+
def _core_package_path(self):
29+
if conan.__version__.startswith("2"):
30+
return pathlib.Path(self.dependencies["embedded_python-core"].package_folder)
31+
else:
32+
return pathlib.Path(self.deps_cpp_info["embedded_python-core"].rootpath)
33+
34+
@property
35+
def _package_path(self):
36+
if conan.__version__.startswith("2"):
37+
return pathlib.Path(self.dependencies["embedded_python"].package_folder)
38+
else:
39+
return pathlib.Path(self.deps_cpp_info["embedded_python"].rootpath)
40+
41+
def layout(self):
42+
cmake_layout(self)
43+
44+
def requirements(self):
45+
self.requires(self.tested_reference_str)
46+
2647
def configure(self):
2748
if self.options.env:
2849
self.options["embedded_python"].packages = _read_env(self.options.env)
@@ -34,12 +55,19 @@ def generate(self):
3455
tc.generate()
3556

3657
def build(self):
58+
sys.path.append(str(self._package_path))
59+
3760
import embedded_python_tools
3861

3962
embedded_python_tools.symlink_import(self, dst="bin/python")
4063

4164
cmake = CMake(self)
42-
cmake.configure()
65+
cmake.configure(
66+
variables={
67+
"EXPECTED_PYTHON_CORE_PATH": self._core_package_path.as_posix(),
68+
"EXPECTED_PYTHON_PATH": self._package_path.as_posix(),
69+
}
70+
)
4371
cmake.build()
4472

4573
def _test_env(self):
@@ -52,16 +80,15 @@ def _test_env(self):
5280
self.run(f'{python_exe} -c "import sys; print(sys.version);"')
5381

5482
name = str(self.options.env) if self.options.env else "baseline"
55-
self.run(f"{python_exe} {project_root / name / 'test.py'}", run_environment=True)
83+
self.run(f"{python_exe} {project_root / name / 'test.py'}", env="conanrun")
5684

5785
def _test_libpython_path(self):
5886
if self.settings.os != "Macos":
5987
return
6088

6189
python_exe = str(pathlib.Path("./bin/python/bin/python3").resolve())
62-
buffer = StringIO()
63-
self.run(f"otool -L {python_exe}", run_environment=True, output=buffer)
64-
lines = buffer.getvalue().strip().split("\n")[1:]
90+
p = subprocess.run(["otool", "-L", python_exe], check=True, text=True, capture_output=True)
91+
lines = str(p.stdout).strip().split("\n")[1:]
6592
libraries = [line.split()[0] for line in lines]
6693
candidates = [lib for lib in libraries if "libpython" in lib]
6794
assert candidates, f"libpython dependency not found in 'otool' output: {libraries}"
@@ -71,11 +98,11 @@ def _test_libpython_path(self):
7198

7299
def _test_embed(self):
73100
"""Ensure that everything is available to compile and link to the embedded Python"""
74-
self.run(pathlib.Path("bin", "test_package"), run_environment=True)
101+
self.run(pathlib.Path("bin", "test_package"), env="conanrun")
75102

76103
def _test_licenses(self):
77104
"""Ensure that the licenses have been gathered"""
78-
license_dir = pathlib.Path(self.deps_cpp_info["embedded_python"].rootpath, "licenses")
105+
license_dir = self._package_path / "licenses"
79106
license_files = [license_dir / "LICENSE.txt"]
80107
if self.options.env:
81108
license_files += [license_dir / "package_licenses.txt"]

0 commit comments

Comments
 (0)