Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow access to extension_properties for dependencies #17659

Merged
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
4 changes: 4 additions & 0 deletions conan/internal/model/conanfile_interface.py
Original file line number Diff line number Diff line change
Expand Up @@ -138,3 +138,7 @@ def homepage(self):
@property
def url(self):
return self._conanfile.url

@property
def extension_properties(self):
return getattr(self._conanfile, "extension_properties", {})
63 changes: 62 additions & 1 deletion test/integration/package_id/test_validate.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import json
import os
import platform
import re
import textwrap
import unittest
Expand All @@ -8,7 +10,7 @@
from conan.cli.exit_codes import ERROR_INVALID_CONFIGURATION, ERROR_GENERAL
from conans.client.graph.graph import BINARY_INVALID
from conan.test.assets.genconanfile import GenConanfile
from conans.util.files import save
from conans.util.files import save, load
from conan.test.utils.tools import TestClient, NO_SETTINGS_PACKAGE_ID


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

@pytest.mark.skipif(platform.system() == "Windows", reason="Needs at least 3 cppstd values available, msvc 191 does not")
def test_extension_properties_cppstd_compat_non_transitiveness(self):
"""
The cppstd_compat is not transitive, so if a recipe has cppstd_compat=False,
its dependencies will still be checked for compatibility
"""
tc = TestClient()
tc.save({"dep/conanfile.py": GenConanfile("dep", "1.0").with_setting("compiler"),
"lib/conanfile.py": GenConanfile("lib", "1.0")
.with_setting("compiler")
.with_class_attribute('extension_properties = {"compatibility_cppstd": False}')
.with_requirement("dep/1.0"),
"app/conanfile.py": GenConanfile("app", "1.0")
.with_setting("compiler")
.with_requirement("lib/1.0")})
tc.run("create dep -s=compiler.cppstd=20")
tc.run("create lib -s=compiler.cppstd=17")
tc.run("create app -s=compiler.cppstd=14", assert_error=True)

tc.run("install --requires=app/1.0 -s=compiler.cppstd=11", assert_error=True)
assert "dep/1.0: Found compatible package" in tc.out
assert "ERROR: Missing binary: app/1.0" in tc.out

def test_extension_properties_make_transitive(self):
"""
The cppstd_compat is not transitive, so if a recipe has cppstd_compat=False,
its dependencies will still be checked for compatibility
"""
tc = TestClient()
tc.save({"lib/conanfile.py": GenConanfile("lib", "1.0").with_setting("compiler"),
"dep/conanfile.py": GenConanfile("dep", "1.0")
.with_setting("compiler")
.with_class_attribute('extension_properties = {"compatibility_cppstd": False}')
.with_requirement("lib/1.0"),
"conanfile.py": GenConanfile("app", "1.0")
.with_setting("compiler")
.with_requirement("dep/1.0")})
tc.run("create lib -s=compiler.cppstd=17")
tc.run("create dep -s=compiler.cppstd=14")
tc.run("create . -s=compiler.cppstd=14")

compat_path = os.path.join(tc.cache_folder, "extensions/plugins/compatibility/compatibility.py")
compat_contents = load(compat_path)

transitive_expansions = textwrap.indent(textwrap.dedent("""
extension_properties = getattr(conanfile, "extension_properties", {}).copy()
for dep in conanfile.dependencies.values():
if not dep.extension_properties.get("compatibility_cppstd", True):
extension_properties["compatibility_cppstd"] = False
"""), " ")

compat_contents = compat_contents.replace('extension_properties = getattr(conanfile, "extension_properties", {})', transitive_expansions)
save(compat_path, compat_contents)

tc.run("install --requires=app/1.0 -s=compiler.cppstd=17", assert_error=True)

assert "Missing prebuilt package for 'app/1.0', 'dep/1.0'" in tc.out



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