Repository: conan-io/conan
Pull request #16575 (2024-07-01 07:57:01)

Fix unexpected error when a recipe performs package_id erasure and is used as a compatibility candidate
Changelog: Bugfix: Fix unexpected error when a recipe performs `package_id()` `info` erasure and is used as a compatibility candidate
Docs: Omit


See https://github.com/conan-io/conan-center-index/pull/24476#discussion_r1660586014


Patch:
diff --git a/conans/client/graph/graph_binaries.py b/conans/client/graph/graph_binaries.py
index fc1980d99..b589a3c2f 100644
--- a/conans/client/graph/graph_binaries.py
+++ b/conans/client/graph/graph_binaries.py
@@ -134,9 +134,13 @@ class GraphBinariesAnalyzer(object):
                                   f"compatible package '{pkg_id}': {diff}")
             # So they are available in package_info() method
             conanfile.info = compatible_pkg  # Redefine current
+
+            # TODO: Improve this interface
+            # The package_id method might have modified the settings to erase information,
+            # ensure we allow those new values
+            conanfile.settings = conanfile.settings.copy_conaninfo_settings()
             conanfile.settings.update_values(compatible_pkg.settings.values_list)
             # Trick to allow mutating the options (they were freeze=True)
-            # TODO: Improve this interface
             conanfile.options = conanfile.options.copy_conaninfo_options()
             conanfile.options.update_options(compatible_pkg.options)
 
diff --git a/conans/model/settings.py b/conans/model/settings.py
index 347ab40a5..f0735f901 100644
--- a/conans/model/settings.py
+++ b/conans/model/settings.py
@@ -61,9 +61,9 @@ class SettingsItem:
         """ deepcopy, recursive
         This function adds "ANY" to lists, to allow the ``package_id()`` method to modify some of
         values, but not all, just the "final" values without subsettings.
-        We cannot let usres manipulate to random strings
+        We cannot let users manipulate to random strings
         things that contain subsettings like ``compiler``, because that would leave the thing
-        in a undefined state, with some now inconsistent subsettings, that cannot be accessed
+        in an undefined state, with some now inconsistent subsettings, that cannot be accessed
         anymore. So with this change the options are:
         - If you need more "binary-compatible" descriptions of a compiler, lets say like
         "gcc_or_clang", then you need to add that string to settings.yml. And add the subsettings


Test patch:
diff --git a/test/integration/package_id/compatible_test.py b/test/integration/package_id/compatible_test.py
index a931701fc..4f2865f7b 100644
--- a/test/integration/package_id/compatible_test.py
+++ b/test/integration/package_id/compatible_test.py
@@ -401,6 +401,37 @@ class TestNewCompatibility:
         c.run("install --requires=pdfium/2020.9 -pr=myprofile -s build_type=Debug")
         assert "missing. Using compatible package" in c.out
 
+    def test_compatibility_erase_package_id(self):
+        c = TestClient()
+        conanfile = textwrap.dedent("""
+            from conan import ConanFile
+
+            class PdfiumConan(ConanFile):
+                name = "diligent-core"
+                version = "1.0"
+                settings = "compiler"
+                options = {"foo": ["no"]}
+
+                def package_id(self):
+                    self.info.settings.compiler.runtime = "foobar"
+                    self.info.options.foo = "yes"
+            """)
+        profile = textwrap.dedent("""
+            [settings]
+            os = Windows
+            compiler=msvc
+            compiler.version=192
+            compiler.runtime=dynamic
+            build_type=Release
+            arch=x86_64
+            """)
+        c.save({"conanfile.py": conanfile,
+                "myprofile": profile})
+
+        c.run("create . -pr:a=myprofile -s compiler.cppstd=20")
+        c.run("install --requires=diligent-core/1.0 -pr:a=myprofile -s compiler.cppstd=17")
+        assert "ERROR: Invalid setting 'foobar' is not a valid 'settings.compiler.runtime' value." not in c.out
+
     def test_compatibility_msvc_and_cppstd(self):
         """msvc 194 would not find compatible packages built with same version but different cppstd
         due to an issue in the msvc fallback compatibility rule."""