Repository: charmed-kubernetes/pytest-operator (language: python)

Issue:
Installation pulls in an older version of `charmcraft`
Was doing some testing with `pytest-operator` and `tox` earlier today and noticed that it pulls in version `0.7.0` of `charmcraft` rather than the latest `1.0.0`.

This is my tox env:

```ini
[testenv:integration]
deps =
    juju
    pytest
    pytest-operator 
    ipdb
commands = pytest -v --tb native --show-capture=no --log-cli-level=INFO -s {posargs:tests/integration}
```

And contents of venv:

```
ls .tox/integration/lib/python3.9/site-packages | grep charmcra
drwxrwxr-x    - jon jon 28 May 15:39 -- charmcraft
drwxrwxr-x    - jon jon 28 May 15:39 -- charmcraft-0.7.0.dist-info
```

Thanks! :)



Discussion / hints:
I don't know how this could have happened because the dependency [isn't pinned](https://github.com/charmed-kubernetes/pytest-operator/blob/main/setup.py#L34) and [charmcraft on PyPI is 1.0.0](https://pypi.org/project/charmcraft/).  That said, I think we want to treat charmcraft the same way we do the Juju client and just use the snap. Thus, the dependency would be removed and shifted to [charmed-kubernetes/actions-operator](https://github.com/charmed-kubernetes/actions-operator).
Yeh, I agree, pretty weird!
I confirmed that it tries to use 1.0.0 and below and for some reason will only accept 0.7.0. My best guess is a dependency version conflict between libjuju and charmcraft after 0.7.0, since libjuju has some more restrictive dependency specifications but I'm really not sure and couldn't find the actual conflict.  Regardless, I think it's better to switch to the snap than keep trying to track this down.

Fix patch:
diff --git a/setup.py b/setup.py
index 1aa253d..2225401 100644
--- a/setup.py
+++ b/setup.py
@@ -30,8 +30,6 @@
         "pytest-asyncio",
         "pyyaml",
         "juju",
-        "charm-tools",
-        "charmcraft",
         "jinja2",
     ],
     entry_points={
diff --git a/tox.ini b/tox.ini
index edd57b8..f23e6e3 100644
--- a/tox.ini
+++ b/tox.ini
@@ -8,8 +8,7 @@ setenv =
     PYTHONBREAKPOINT=ipdb.set_trace
 passenv = HOME
 deps =
-    # Until 2.8.6 is released
-    https://github.com/juju/python-libjuju/archive/master.zip#egg=juju
+    juju
      -e {toxinidir}
 
 [testenv:lint]


Test patch:
diff --git a/pytest_operator/plugin.py b/pytest_operator/plugin.py
index 995e59d..792489f 100644
--- a/pytest_operator/plugin.py
+++ b/pytest_operator/plugin.py
@@ -51,12 +51,29 @@ def pytest_addoption(parser):
 
 def pytest_configure(config):
     config.addinivalue_line("markers", "abort_on_fail")
+    # These need to be fixed in libjuju and just clutter things up for tests using this.
+    config.addinivalue_line(
+        "filterwarnings", "ignore:The loop argument:DeprecationWarning"
+    )
+    config.addinivalue_line(
+        "filterwarnings", r"ignore:'with \(yield from lock\)':DeprecationWarning"
+    )
 
 
 @pytest.fixture(scope="session")
-def check_deps(autouse=True):
+def tmp_path_factory(request):
+    # Override temp path factory to create temp dirs under Tox env so that
+    # confined snaps (e.g., charmcraft) can access them.
+    return pytest.TempPathFactory(
+        given_basetemp=Path(os.environ["TOX_ENV_DIR"]) / "tmp" / "pytest",
+        trace=request.config.trace.get("tmpdir"),
+        _ispytest=True,
+    )
+
+
+def check_deps():
     missing = []
-    for dep in ("juju", "charm-build", "charmcraft"):
+    for dep in ("juju", "charm", "charmcraft"):
         res = subprocess.run(["which", dep])
         if res.returncode != 0:
             missing.append(dep)
@@ -122,6 +139,7 @@ def abort_on_fail(request, ops_test):
 @pytest.fixture(scope="module")
 @pytest.mark.asyncio
 async def ops_test(request, tmp_path_factory):
+    check_deps()
     ops_test = OpsTest(request, tmp_path_factory)
     await ops_test._setup_model()
     yield ops_test
@@ -255,7 +273,8 @@ async def _cleanup_model(self):
         await self.dump_model()
 
         if not self.keep_model:
-            controller = await self.model.get_controller()
+            controller = Controller()
+            await controller.connect(self.controller_name)
             # Forcibly destroy machines in case any units are in error.
             for machine in self.model.machines.values():
                 log.info(f"Destroying machine {machine.id}")
@@ -298,7 +317,7 @@ async def build_charm(self, charm_path):
         charm_name = yaml.safe_load(metadata_path.read_text())["name"]
         if layer_path.exists():
             # Handle older, reactive framework charms.
-            cmd = ["charm-build", "-F", charm_abs]
+            cmd = ["charm", "build", "-F", charm_abs]
         else:
             # Handle newer, operator framework charms.
             cmd = ["charmcraft", "build", "-f", charm_abs]
diff --git a/tests/test_pytest_operator.py b/tests/test_pytest_operator.py
index 5fed88c..6a37ef7 100644
--- a/tests/test_pytest_operator.py
+++ b/tests/test_pytest_operator.py
@@ -1,4 +1,5 @@
 import logging
+import os
 from pathlib import Path
 
 import pytest
@@ -56,6 +57,11 @@ async def test_func(ops_test):
     assert ops_test.model
 
 
+def test_tmp_path(ops_test):
+    tox_env_dir = Path(os.environ["TOX_ENV_DIR"]).resolve()
+    assert ops_test.tmp_path.relative_to(tox_env_dir)
+
+
 @pytest.mark.abort_on_fail(abort_on_xfail=True)
 def test_abort():
     pytest.xfail("abort")