Skip to content

Commit eebcd02

Browse files
authored
Allow access to extension_properties for dependencies (#17659)
* Test to show that extension_properties.compatibibility_cppstd is not transitive * Lowerbound cppstd 14 for msvc * Skip for windows * Oops * Let users access dependencies extension_properties * Better initial test * Use more widespread cppstds
1 parent db922a4 commit eebcd02

2 files changed

Lines changed: 66 additions & 1 deletion

File tree

conan/internal/model/conanfile_interface.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,3 +138,7 @@ def homepage(self):
138138
@property
139139
def url(self):
140140
return self._conanfile.url
141+
142+
@property
143+
def extension_properties(self):
144+
return getattr(self._conanfile, "extension_properties", {})

test/integration/package_id/test_validate.py

Lines changed: 62 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
import json
2+
import os
3+
import platform
24
import re
35
import textwrap
46
import unittest
@@ -8,7 +10,7 @@
810
from conan.cli.exit_codes import ERROR_INVALID_CONFIGURATION, ERROR_GENERAL
911
from conans.client.graph.graph import BINARY_INVALID
1012
from conan.test.assets.genconanfile import GenConanfile
11-
from conans.util.files import save
13+
from conans.util.files import save, load
1214
from conan.test.utils.tools import TestClient, NO_SETTINGS_PACKAGE_ID
1315

1416

@@ -698,6 +700,65 @@ def compatibility(self):
698700
assert "compiler.cppstd=14" in client.out
699701
assert "compiler.cppstd=17" not in client.out
700702

703+
@pytest.mark.skipif(platform.system() == "Windows", reason="Needs at least 3 cppstd values available, msvc 191 does not")
704+
def test_extension_properties_cppstd_compat_non_transitiveness(self):
705+
"""
706+
The cppstd_compat is not transitive, so if a recipe has cppstd_compat=False,
707+
its dependencies will still be checked for compatibility
708+
"""
709+
tc = TestClient()
710+
tc.save({"dep/conanfile.py": GenConanfile("dep", "1.0").with_setting("compiler"),
711+
"lib/conanfile.py": GenConanfile("lib", "1.0")
712+
.with_setting("compiler")
713+
.with_class_attribute('extension_properties = {"compatibility_cppstd": False}')
714+
.with_requirement("dep/1.0"),
715+
"app/conanfile.py": GenConanfile("app", "1.0")
716+
.with_setting("compiler")
717+
.with_requirement("lib/1.0")})
718+
tc.run("create dep -s=compiler.cppstd=20")
719+
tc.run("create lib -s=compiler.cppstd=17")
720+
tc.run("create app -s=compiler.cppstd=14", assert_error=True)
721+
722+
tc.run("install --requires=app/1.0 -s=compiler.cppstd=11", assert_error=True)
723+
assert "dep/1.0: Found compatible package" in tc.out
724+
assert "ERROR: Missing binary: app/1.0" in tc.out
725+
726+
def test_extension_properties_make_transitive(self):
727+
"""
728+
The cppstd_compat is not transitive, so if a recipe has cppstd_compat=False,
729+
its dependencies will still be checked for compatibility
730+
"""
731+
tc = TestClient()
732+
tc.save({"lib/conanfile.py": GenConanfile("lib", "1.0").with_setting("compiler"),
733+
"dep/conanfile.py": GenConanfile("dep", "1.0")
734+
.with_setting("compiler")
735+
.with_class_attribute('extension_properties = {"compatibility_cppstd": False}')
736+
.with_requirement("lib/1.0"),
737+
"conanfile.py": GenConanfile("app", "1.0")
738+
.with_setting("compiler")
739+
.with_requirement("dep/1.0")})
740+
tc.run("create lib -s=compiler.cppstd=17")
741+
tc.run("create dep -s=compiler.cppstd=14")
742+
tc.run("create . -s=compiler.cppstd=14")
743+
744+
compat_path = os.path.join(tc.cache_folder, "extensions/plugins/compatibility/compatibility.py")
745+
compat_contents = load(compat_path)
746+
747+
transitive_expansions = textwrap.indent(textwrap.dedent("""
748+
extension_properties = getattr(conanfile, "extension_properties", {}).copy()
749+
for dep in conanfile.dependencies.values():
750+
if not dep.extension_properties.get("compatibility_cppstd", True):
751+
extension_properties["compatibility_cppstd"] = False
752+
"""), " ")
753+
754+
compat_contents = compat_contents.replace('extension_properties = getattr(conanfile, "extension_properties", {})', transitive_expansions)
755+
save(compat_path, compat_contents)
756+
757+
tc.run("install --requires=app/1.0 -s=compiler.cppstd=17", assert_error=True)
758+
759+
assert "Missing prebuilt package for 'app/1.0', 'dep/1.0'" in tc.out
760+
761+
701762

702763
class TestCompatibleSettingsTarget(unittest.TestCase):
703764
""" aims to be a very close to real use case of tool being used across different settings_target

0 commit comments

Comments
 (0)