Repository: conan-io/conan
Pull request: resolve version ranges for editables too
Changelog: Feature: Allow ``version-ranges`` to resolve to editable packages too.
Docs: Omit

Close https://github.com/conan-io/conan/issues/14507

Problem statement:
[question] Editables not considered for version ranges
### What is your question?

Say you have two packages pa and pb where pb uses pa via a version range. (E. g. `self.requires("pa/[>1.0]")`)
You can now create the packages pa (version 1.0.0) and pb (version 2.0.0).
Now I want to make changes to pa and test those changes with pb. So I increase the version of pa to e. g. 1.0.1 and put it in "editable" mode. Then I have a `pa/1.0.0` in the local cache and a `pa/1.0.1` in the list of editables.
When I now recreate package pb, it still uses pa/1.0.0 from the cache instead of the newer editable package. If I delete pa/1.0.0 from the cache and try to recreate pb, I get an error message: `ERROR: Package 'pa/[>1.0]' not resolved: Version range '>1.0' from requirement 'pa/[>1.0], Traits: ... required by 'pb/2.0.0' could not be resolved.` even though there is a `pa/1.0.1` in the editables list.
When I change the recipe of pb to  `self.requires("pa/1.0.1")` then the editable pa package is used as expected.

Question is: Am I missing something or do version ranges ignore the editable packages alltogether?

Depending on the answer, feel free to change the type of this issue to "bug report" or "featue request". 😃 

(I am using Conan version 2.0.9, btw.)

### Have you read the CONTRIBUTING guide?

- [X] I've read the CONTRIBUTING guide

Hints from issue discussion:
Ok, after some experimenting, I did find two workarounds:

When I capture pb in a lockfile (`conan lock create .`) and then add the editable version of pa to the lockfile (`conan lock add --requires pa/1.0.1`) then I can create a pb binary package which uses the editable package without modifying the pb recipe.

Also, when I create a `conanfile.txt` that contains both, pb/2.0.0 and the editable pa/1.0.1 and then install that `conanfile.txt` with `--build missing` I also get a pb package that uses the pa editable version.

Still, wouldn't it be more "natural" if version ranges would take the editables into account on their own?

Commit message: resolve version ranges for editables too

Patch to review:
diff --git a/conans/client/graph/range_resolver.py b/conans/client/graph/range_resolver.py
index 6c0ea17d33a..0d374fc928e 100644
--- a/conans/client/graph/range_resolver.py
+++ b/conans/client/graph/range_resolver.py
@@ -54,6 +54,7 @@ def _resolve_local(self, search_ref, version_range):
             # TODO: This is still necessary to filter user/channel, until search_recipes is fixed
             local_found = [ref for ref in local_found if ref.user == search_ref.user
                            and ref.channel == search_ref.channel]
+            local_found.extend(self._cache.editable_packages.edited_refs)
             self._cached_cache[pattern] = local_found
         if local_found:
             return self._resolve_version(version_range, local_found, self._resolve_prereleases)
diff --git a/conans/test/integration/editable/test_editable_ranges.py b/conans/test/integration/editable/test_editable_ranges.py
new file mode 100644
index 00000000000..cdf77a6a14f
--- /dev/null
+++ b/conans/test/integration/editable/test_editable_ranges.py
@@ -0,0 +1,27 @@
+from conans.test.assets.genconanfile import GenConanfile
+from conans.test.utils.tools import TestClient
+
+
+def test_editable_ranges():
+    c = TestClient()
+    c.save({"dep/conanfile.py": GenConanfile("dep"),
+            "dep2/conanfile.py": GenConanfile("dep", "0.2"),
+            "app/conanfile.py": GenConanfile("app", "0.1").with_requires("dep/[>=0.1]")})
+    c.run("editable add dep --version=0.1")
+    c.run("install app")
+    c.assert_listed_require({"dep/0.1": "Editable"})
+    assert "dep/[>=0.1]: dep/0.1" in c.out
+
+    # new version, uses new one
+    c.run("editable add dep2")
+    c.run("install app")
+    c.assert_listed_require({"dep/0.2": "Editable"})
+    assert "dep/[>=0.1]: dep/0.2" in c.out
+    assert "dep/0.1" not in c.out
+
+    # If a newer one is in cache, it resolves to cache
+    c.run("create dep --version=0.3")
+    c.run("install app")
+    c.assert_listed_require({"dep/0.3": "Cache"})
+    assert "dep/[>=0.1]: dep/0.3" in c.out
+    assert "dep/0.1" not in c.out


Code review comments:
diff_hunk: @@ -54,6 +54,7 @@ def _resolve_local(self, search_ref, version_range):
             # TODO: This is still necessary to filter user/channel, until search_recipes is fixed
             local_found = [ref for ref in local_found if ref.user == search_ref.user
                            and ref.channel == search_ref.channel]
+            local_found.extend(self._cache.editable_packages.edited_refs)
path: conans/client/graph/range_resolver.py
text: @user1:
Does edited_refs not need the filtering done in the line above this one?

@author:
Yes, it does, I will extend the tests and fix this, very good catch!

@author:
Fixed, please re-review