Repository: canonical/charmcraft

Issue:
Strict dependencies prevents charm from building
### Bug Description

`ModuleNotFoundError: No module named 'markupsafe'` when building charm with `charm-strict-dependencies: true`

### To Reproduce

```
git clone https://github.com/canonical/mysql-router-operator
git checkout with-hashes
tox run -e pack-wrapper
mv requirements-last-build.txt requirements.txt
charmcraft pack
```

### Environment

Ubuntu 22.04

### charmcraft.yaml

```shell
# Copyright 2022 Canonical Ltd.
# See LICENSE file for licensing details.

type: charm
bases:
  # Whenever "bases" is changed:
  # - Update tests/integration/conftest.py::pytest_configure()
  # - Update .github/workflow/ci.yaml integration-test matrix
  - build-on:
      - name: "ubuntu"
        channel: "20.04"
    run-on:
      - name: "ubuntu"
        channel: "20.04"
  - build-on:
      - name: "ubuntu"
        channel: "22.04"
    run-on:
      - name: "ubuntu"
        channel: "22.04"
parts:
  charm:
    override-pull: |
      craftctl default
      if [[ ! -f requirements.txt ]]
      then
          echo 'ERROR: Use "tox run -e build" instead of calling "charmcraft pack" directly' >&2
          exit 1
      fi
    charm-strict-dependencies: true
    charm-entrypoint: src/machine_charm.py
```


### Relevant log output
[charmcraft-20240103-154031.230848.log](https://github.com/canonical/charmcraft/files/13820882/charmcraft-20240103-154031.230848.log)



Discussion:
lengau: @mattculler we only need to do so if the version of pip that's added in the venv is older than the minimum version that supports our needed feature set (as is the case on focal, for example). But we're checking the pip version before running that command.

Patch:
diff --git a/charmcraft/charm_builder.py b/charmcraft/charm_builder.py
index 40a0bb76..47bd9c94 100644
--- a/charmcraft/charm_builder.py
+++ b/charmcraft/charm_builder.py
@@ -243,6 +243,7 @@ class CharmBuilder:
                     [
                         pip_cmd,
                         "install",
+                        "--force-reinstall",
                         f"pip@{KNOWN_GOOD_PIP_URL}",
                     ]
                 )


Test patch:
diff --git a/tests/test_charm_builder.py b/tests/test_charm_builder.py
index 52f3093b..b8a3ebec 100644
--- a/tests/test_charm_builder.py
+++ b/tests/test_charm_builder.py
@@ -732,7 +732,7 @@ def test_build_dependencies_virtualenv(
 
     assert mock.mock_calls == [
         call(["python3", "-m", "venv", str(tmp_path / const.STAGING_VENV_DIRNAME)]),
-        call([pip_cmd, "install", f"pip@{KNOWN_GOOD_PIP_URL}"]),
+        call([pip_cmd, "install", "--force-reinstall", f"pip@{KNOWN_GOOD_PIP_URL}"]),
         *extra_pip_calls,
     ]
 
@@ -771,7 +771,7 @@ def test_build_dependencies_virtualenv_multiple(tmp_path, assert_output):
     pip_cmd = str(charm_builder._find_venv_bin(tmp_path / const.STAGING_VENV_DIRNAME, "pip"))
     assert mock.mock_calls == [
         call(["python3", "-m", "venv", str(tmp_path / const.STAGING_VENV_DIRNAME)]),
-        call([pip_cmd, "install", f"pip@{KNOWN_GOOD_PIP_URL}"]),
+        call([pip_cmd, "install", "--force-reinstall", f"pip@{KNOWN_GOOD_PIP_URL}"]),
         call(
             [
                 pip_cmd,
diff --git a/tests/unit/utils/test_package.py b/tests/unit/utils/test_package.py
index 8bfe73af..693ce959 100644
--- a/tests/unit/utils/test_package.py
+++ b/tests/unit/utils/test_package.py
@@ -131,7 +131,14 @@ def test_get_pip_command(
 
 @pytest.mark.parametrize(
     ("pip_cmd", "stdout", "expected"),
-    [("pip", "pip 22.0.2 from /usr/lib/python3/dist-packages/pip (python 3.10)\n", (22, 0, 2))],
+    [
+        ("pip", "pip 22.0.2 from /usr/lib/python3/dist-packages/pip (python 3.10)\n", (22, 0, 2)),
+        (
+            "venv/bin/pip",
+            "pip 20.0.2 from /root/venv/lib/python3.8/site-packages/pip (python 3.8)",
+            (20, 0, 2),
+        ),
+    ],
 )
 def test_get_pip_version_success(
     fake_process,