From 1ea265ca73a49e9676fe464452915950eabe2f0c Mon Sep 17 00:00:00 2001 From: Stamatis Katsaounis Date: Mon, 11 Aug 2025 17:22:15 +0300 Subject: [PATCH 1/2] feat: track snap version --- lib/charms/operator_libs_linux/v2/snap.py | 13 ++++++- tests/unit/test_snap.py | 42 ++++++++++++----------- 2 files changed, 34 insertions(+), 21 deletions(-) diff --git a/lib/charms/operator_libs_linux/v2/snap.py b/lib/charms/operator_libs_linux/v2/snap.py index 4370eb12..0cdaf4f6 100644 --- a/lib/charms/operator_libs_linux/v2/snap.py +++ b/lib/charms/operator_libs_linux/v2/snap.py @@ -109,7 +109,7 @@ # Increment this PATCH version before using `charmcraft publish-lib` or reset # to 0 if you are raising the major API version -LIBPATCH = 13 +LIBPATCH = 14 PYDEPS = ["opentelemetry-api"] @@ -149,6 +149,7 @@ class _SnapDict(TypedDict, total=True): name: str channel: str revision: str + version: str confinement: str apps: NotRequired[list[dict[str, JSONType]] | None] @@ -308,6 +309,7 @@ class Snap: - state: a `SnapState` representation of its install status - channel: "stable", "candidate", "beta", and "edge" are common - revision: a string representing the snap's revision + - version: a string representing the snap's version - confinement: "classic", "strict", or "devmode" """ @@ -317,6 +319,7 @@ def __init__( state: SnapState, channel: str, revision: str, + version: str, confinement: str, apps: list[dict[str, JSONType]] | None = None, cohort: str | None = None, @@ -325,6 +328,7 @@ def __init__( self._state = state self._channel = channel self._revision = revision + self._version = version self._confinement = confinement self._cohort = cohort or "" self._apps = apps or [] @@ -749,6 +753,11 @@ def revision(self) -> str: """Returns the revision for a snap.""" return self._revision + @property + def version(self) -> str: + """Returns the version for a snap.""" + return self._version + @property def channel(self) -> str: """Returns the channel for a snap.""" @@ -1046,6 +1055,7 @@ def _load_installed_snaps(self) -> None: state=SnapState.Latest, channel=i["channel"], revision=i["revision"], + version=i["version"], confinement=i["confinement"], apps=i.get("apps"), ) @@ -1065,6 +1075,7 @@ def _load_info(self, name: str) -> Snap: state=SnapState.Available, channel=info["channel"], revision=info["revision"], + version=info["version"], confinement=info["confinement"], apps=None, ) diff --git a/tests/unit/test_snap.py b/tests/unit/test_snap.py index 88e3fe12..b4bf1f61 100644 --- a/tests/unit/test_snap.py +++ b/tests/unit/test_snap.py @@ -326,12 +326,12 @@ def test_raises_error_if_snap_not_running(self, mock_exists): self.assertIn("snapd is not running", ctx.exception.message) def test_can_compare_snap_equality(self): - foo1 = snap.Snap("foo", snap.SnapState.Present, "stable", "1", "classic") - foo2 = snap.Snap("foo", snap.SnapState.Present, "stable", "1", "classic") + foo1 = snap.Snap("foo", snap.SnapState.Present, "stable", "1", "v42", "classic") + foo2 = snap.Snap("foo", snap.SnapState.Present, "stable", "1", "v42", "classic") self.assertEqual(foo1, foo2) def test_snap_magic_methods(self): - foo = snap.Snap("foo", snap.SnapState.Present, "stable", "1", "classic") + foo = snap.Snap("foo", snap.SnapState.Present, "stable", "1", "v42", "classic") self.assertEqual(hash(foo), hash((foo._name, foo._revision))) str(foo) # ensure custom __str__ doesn't error repr(foo) # ensure custom __repr__ doesn't error @@ -339,7 +339,7 @@ def test_snap_magic_methods(self): @patch("charms.operator_libs_linux.v2.snap.subprocess.check_output") def test_can_run_snap_commands(self, mock_subprocess: MagicMock): mock_subprocess.return_value = 0 - foo = snap.Snap("foo", snap.SnapState.Present, "stable", "1", "classic") + foo = snap.Snap("foo", snap.SnapState.Present, "stable", "1", "v42", "classic") self.assertEqual(foo.present, True) foo.state = snap.SnapState.Present mock_subprocess.assert_not_called() @@ -384,6 +384,7 @@ def test_refresh_revision_devmode_cohort_args(self, mock_subprocess: MagicMock): state=snap.SnapState.Present, channel="stable", revision="1", + version="v42", confinement="devmode", apps=None, cohort="A", @@ -418,7 +419,7 @@ def test_refresh_revision_devmode_cohort_args(self, mock_subprocess: MagicMock): @patch("charms.operator_libs_linux.v2.snap.subprocess.check_output") def test_no_subprocess_when_not_installed(self, mock_subprocess: MagicMock): """Don't call out to snap when ensuring an uninstalled state when not installed.""" - foo = snap.Snap("foo", snap.SnapState.Present, "stable", "1", "classic") + foo = snap.Snap("foo", snap.SnapState.Present, "stable", "1", "v42", "classic") not_installed_states = (snap.SnapState.Absent, snap.SnapState.Available) for _state in not_installed_states: foo._state = _state @@ -429,7 +430,7 @@ def test_no_subprocess_when_not_installed(self, mock_subprocess: MagicMock): @patch("charms.operator_libs_linux.v2.snap.subprocess.check_output") def test_can_run_snap_commands_devmode(self, mock_check_output: MagicMock): mock_check_output.return_value = 0 - foo = snap.Snap("foo", snap.SnapState.Present, "stable", "1", "devmode") + foo = snap.Snap("foo", snap.SnapState.Present, "stable", "1", "v42", "devmode") self.assertEqual(foo.present, True) foo.ensure(snap.SnapState.Absent) @@ -470,7 +471,7 @@ def test_can_run_snap_commands_devmode(self, mock_check_output: MagicMock): @patch("charms.operator_libs_linux.v2.snap.subprocess.run") def test_can_run_snap_daemon_commands(self, mock_subprocess): mock_subprocess.return_value = MagicMock() - foo = snap.Snap("foo", snap.SnapState.Latest, "stable", "1", "classic") + foo = snap.Snap("foo", snap.SnapState.Latest, "stable", "1", "v42", "classic") foo.start(["bar", "baz"], enable=True) mock_subprocess.assert_called_with( @@ -533,14 +534,14 @@ def test_can_run_snap_daemon_commands(self, mock_subprocess): side_effect=CalledProcessError(returncode=1, cmd=""), ) def test_snap_daemon_commands_raise_snap_error(self, mock_subprocess: MagicMock): - foo = snap.Snap("foo", snap.SnapState.Latest, "stable", "1", "classic") + foo = snap.Snap("foo", snap.SnapState.Latest, "stable", "1", "v42", "classic") with self.assertRaises(snap.SnapError): foo.start(["bad", "arguments"], enable=True) @patch("charms.operator_libs_linux.v2.snap.subprocess.run") def test_snap_connect(self, mock_subprocess): mock_subprocess.return_value = MagicMock() - foo = snap.Snap("foo", snap.SnapState.Latest, "stable", "1", "classic") + foo = snap.Snap("foo", snap.SnapState.Latest, "stable", "1", "v42", "classic") foo.connect(plug="bar", slot="baz") mock_subprocess.assert_called_with( @@ -572,14 +573,14 @@ def test_snap_connect(self, mock_subprocess): ) def test_snap_connect_raises_snap_error(self, mock_subprocess: MagicMock): """Ensure that a SnapError is raised when Snap.connect is called with bad arguments.""" - foo = snap.Snap("foo", snap.SnapState.Latest, "stable", "1", "classic") + foo = snap.Snap("foo", snap.SnapState.Latest, "stable", "1", "v42", "classic") with self.assertRaises(snap.SnapError): foo.connect(plug="bad", slot="argument") @patch("charms.operator_libs_linux.v2.snap.subprocess.check_output") def test_snap_hold_timedelta(self, mock_check_output: MagicMock): mock_check_output.return_value = 0 - foo = snap.Snap("foo", snap.SnapState.Latest, "stable", "1", "classic") + foo = snap.Snap("foo", snap.SnapState.Latest, "stable", "1", "v42", "classic") foo.hold(duration=datetime.timedelta(hours=72)) mock_check_output.assert_called_with( @@ -596,7 +597,7 @@ def test_snap_hold_timedelta(self, mock_check_output: MagicMock): @patch("charms.operator_libs_linux.v2.snap.subprocess.check_output") def test_snap_hold_forever(self, mock_subprocess: MagicMock): mock_subprocess.return_value = 0 - foo = snap.Snap("foo", snap.SnapState.Latest, "stable", "1", "classic") + foo = snap.Snap("foo", snap.SnapState.Latest, "stable", "1", "v42", "classic") foo.hold() mock_subprocess.assert_called_with( @@ -613,7 +614,7 @@ def test_snap_hold_forever(self, mock_subprocess: MagicMock): @patch("charms.operator_libs_linux.v2.snap.subprocess.check_output") def test_snap_unhold(self, mock_subprocess: MagicMock): mock_subprocess.return_value = 0 - foo = snap.Snap("foo", snap.SnapState.Latest, "stable", "1", "classic") + foo = snap.Snap("foo", snap.SnapState.Latest, "stable", "1", "v42", "classic") foo.unhold() mock_subprocess.assert_called_with( @@ -682,6 +683,7 @@ def test_refresh_classic( state=snap.SnapState.Present, channel='stable', revision='1', + version='v42', confinement=confinement, apps=None, cohort='A', @@ -1130,7 +1132,7 @@ def fake_snap(command: str, optargs: Iterable[str] | None) -> str: return json.dumps({}) raise snap.SnapError("Bad arguments:", command, optargs) - foo = snap.Snap("foo", snap.SnapState.Latest, "stable", "1", "classic") + foo = snap.Snap("foo", snap.SnapState.Latest, "stable", "1", "v42", "classic") foo._snap = MagicMock(side_effect=fake_snap) keys_and_values: dict[str, Any] = { "key_w_string_value": "string", @@ -1154,7 +1156,7 @@ def fake_snap(command: str, optargs: Iterable[str] | None) -> str: @patch("charms.operator_libs_linux.v2.snap.SnapClient._put_snap_conf") def test_snap_set_typed(self, put_snap_conf): - foo = snap.Snap("foo", snap.SnapState.Present, "stable", "1", "classic") + foo = snap.Snap("foo", snap.SnapState.Present, "stable", "1", "v42", "classic") config = {"n": 42, "s": "string", "d": {"nested": True}} @@ -1163,7 +1165,7 @@ def test_snap_set_typed(self, put_snap_conf): @patch("charms.operator_libs_linux.v2.snap.SnapClient._put_snap_conf") def test_snap_set_untyped(self, put_snap_conf): - foo = snap.Snap("foo", snap.SnapState.Present, "stable", "1", "classic") + foo = snap.Snap("foo", snap.SnapState.Present, "stable", "1", "v42", "classic") config = {"n": 42, "s": "string", "d": {"nested": True}} @@ -1177,7 +1179,7 @@ def test_snap_set_untyped(self, put_snap_conf): side_effect=lambda *args, **kwargs: "", # pyright: ignore[reportUnknownLambdaType] ) def test_snap_unset(self, mock_subprocess: MagicMock): - foo = snap.Snap("foo", snap.SnapState.Present, "stable", "1", "classic") + foo = snap.Snap("foo", snap.SnapState.Present, "stable", "1", "v42", "classic") key: str = "test_key" self.assertEqual(foo.unset(key), "") mock_subprocess.assert_called_with( @@ -1315,7 +1317,7 @@ def test_install_local_called_process_error(self, mock_subprocess: MagicMock): @patch("charms.operator_libs_linux.v2.snap.subprocess.run") def test_alias(self, mock_run: MagicMock): - foo = snap.Snap("foo", snap.SnapState.Latest, "stable", "1", "classic") + foo = snap.Snap("foo", snap.SnapState.Latest, "stable", "1", "v42", "classic") foo.alias("bar", "baz") mock_run.assert_called_once_with( ["snap", "alias", "foo.bar", "baz"], @@ -1339,7 +1341,7 @@ def test_alias_raises_snap_error(self, mock_run: MagicMock): mock_run.side_effect = CalledProcessError( returncode=1, cmd=["snap", "alias", "foo.bar", "baz"] ) - foo = snap.Snap("foo", snap.SnapState.Latest, "stable", "1", "classic") + foo = snap.Snap("foo", snap.SnapState.Latest, "stable", "1", "v42", "classic") with self.assertRaises(snap.SnapError): foo.alias("bar", "baz") mock_run.assert_any_call( @@ -1352,7 +1354,7 @@ def test_alias_raises_snap_error(self, mock_run: MagicMock): @patch("charms.operator_libs_linux.v2.snap.subprocess.check_output") def test_held(self, mock_subprocess: MagicMock): - foo = snap.Snap("foo", snap.SnapState.Latest, "stable", "1", "classic") + foo = snap.Snap("foo", snap.SnapState.Latest, "stable", "1", "v42", "classic") mock_subprocess.return_value = {} self.assertEqual(foo.held, False) mock_subprocess.return_value = {"hold:": "key isn't checked"} From 17c550c164904a714fbf612f50cdf6bbc38ac2df Mon Sep 17 00:00:00 2001 From: Stamatis Katsaounis Date: Tue, 12 Aug 2025 10:43:38 +0300 Subject: [PATCH 2/2] updates as per review suggestions --- lib/charms/operator_libs_linux/v2/snap.py | 21 +++++----- tests/integration/test_snap.py | 13 ++++-- tests/unit/test_snap.py | 48 ++++++++++++----------- 3 files changed, 46 insertions(+), 36 deletions(-) diff --git a/lib/charms/operator_libs_linux/v2/snap.py b/lib/charms/operator_libs_linux/v2/snap.py index 0cdaf4f6..a706c166 100644 --- a/lib/charms/operator_libs_linux/v2/snap.py +++ b/lib/charms/operator_libs_linux/v2/snap.py @@ -309,8 +309,8 @@ class Snap: - state: a `SnapState` representation of its install status - channel: "stable", "candidate", "beta", and "edge" are common - revision: a string representing the snap's revision - - version: a string representing the snap's version - confinement: "classic", "strict", or "devmode" + - version: a string representing the snap's version, if set by the snap author """ def __init__( @@ -319,19 +319,20 @@ def __init__( state: SnapState, channel: str, revision: str, - version: str, confinement: str, apps: list[dict[str, JSONType]] | None = None, cohort: str | None = None, + *, + version: str | None = None, ) -> None: self._name = name self._state = state self._channel = channel self._revision = revision - self._version = version self._confinement = confinement self._cohort = cohort or "" self._apps = apps or [] + self._version = version self._snap_client = SnapClient() def __eq__(self, other: object) -> bool: @@ -753,11 +754,6 @@ def revision(self) -> str: """Returns the revision for a snap.""" return self._revision - @property - def version(self) -> str: - """Returns the version for a snap.""" - return self._version - @property def channel(self) -> str: """Returns the channel for a snap.""" @@ -792,6 +788,11 @@ def held(self) -> bool: info = self._snap("info") return "hold:" in info + @property + def version(self) -> str | None: + """Returns the version for a snap.""" + return self._version + class _UnixSocketConnection(http.client.HTTPConnection): """Implementation of HTTPConnection that connects to a named Unix socket.""" @@ -1055,9 +1056,9 @@ def _load_installed_snaps(self) -> None: state=SnapState.Latest, channel=i["channel"], revision=i["revision"], - version=i["version"], confinement=i["confinement"], apps=i.get("apps"), + version=i.get("version"), ) self._snap_map[snap.name] = snap @@ -1075,9 +1076,9 @@ def _load_info(self, name: str) -> Snap: state=SnapState.Available, channel=info["channel"], revision=info["revision"], - version=info["version"], confinement=info["confinement"], apps=None, + version=info.get("version"), ) diff --git a/tests/integration/test_snap.py b/tests/integration/test_snap.py index 787b7fa6..2ad73f2e 100644 --- a/tests/integration/test_snap.py +++ b/tests/integration/test_snap.py @@ -204,12 +204,14 @@ def test_snap_ensure_revision(): ["snap", "info", "juju"], capture_output=True, encoding="utf-8" ).stdout.split("\n") + edge_version = None edge_revision = None for line in snap_info_juju: - match = re.search(r"3/stable.*\((\d+)\)", line) + match = re.search(r"3/stable:\s+([^\s]+).+\((\d+)\)", line) if match: - edge_revision = match.group(1) + edge_version = match.group(1) + edge_revision = match.group(2) break assert edge_revision is not None @@ -226,10 +228,13 @@ def test_snap_ensure_revision(): assert "installed" in snap_info_juju for line in snap_info_juju.split("\n"): if "installed" in line: - match = re.search(r"installed.*\((\d+)\)", line) + match = re.search(r"installed:\s+([^\s]+).+\((\d+)\)", line) assert match is not None - assert match.group(1) == edge_revision + assert match.group(1) == edge_version + assert match.group(2) == edge_revision + + assert juju.version == edge_version def test_snap_start(): diff --git a/tests/unit/test_snap.py b/tests/unit/test_snap.py index b4bf1f61..a98c93f4 100644 --- a/tests/unit/test_snap.py +++ b/tests/unit/test_snap.py @@ -291,6 +291,7 @@ def test_can_lazy_load_snap_info(self, mock_exists, m): self.assertEqual(result.channel, "stable") self.assertEqual(result.confinement, "strict") self.assertEqual(result.revision, "233") + self.assertEqual(result.version, "7.78.0") @patch("os.path.isfile") def test_can_load_installed_snap_info(self, mock_exists): @@ -326,12 +327,17 @@ def test_raises_error_if_snap_not_running(self, mock_exists): self.assertIn("snapd is not running", ctx.exception.message) def test_can_compare_snap_equality(self): - foo1 = snap.Snap("foo", snap.SnapState.Present, "stable", "1", "v42", "classic") - foo2 = snap.Snap("foo", snap.SnapState.Present, "stable", "1", "v42", "classic") + foo1 = snap.Snap("foo", snap.SnapState.Present, "stable", "1", "classic", version="v42") + foo2 = snap.Snap("foo", snap.SnapState.Present, "stable", "1", "classic") self.assertEqual(foo1, foo2) + def test_can_compare_snap_inequality(self): + foo1 = snap.Snap("foo", snap.SnapState.Present, "stable", "1", "classic", version="v42") + foo2 = snap.Snap("foo", snap.SnapState.Present, "stable", "2", "classic", version="v42") + self.assertNotEqual(foo1, foo2) + def test_snap_magic_methods(self): - foo = snap.Snap("foo", snap.SnapState.Present, "stable", "1", "v42", "classic") + foo = snap.Snap("foo", snap.SnapState.Present, "stable", "1", "classic") self.assertEqual(hash(foo), hash((foo._name, foo._revision))) str(foo) # ensure custom __str__ doesn't error repr(foo) # ensure custom __repr__ doesn't error @@ -339,7 +345,7 @@ def test_snap_magic_methods(self): @patch("charms.operator_libs_linux.v2.snap.subprocess.check_output") def test_can_run_snap_commands(self, mock_subprocess: MagicMock): mock_subprocess.return_value = 0 - foo = snap.Snap("foo", snap.SnapState.Present, "stable", "1", "v42", "classic") + foo = snap.Snap("foo", snap.SnapState.Present, "stable", "1", "classic") self.assertEqual(foo.present, True) foo.state = snap.SnapState.Present mock_subprocess.assert_not_called() @@ -384,7 +390,6 @@ def test_refresh_revision_devmode_cohort_args(self, mock_subprocess: MagicMock): state=snap.SnapState.Present, channel="stable", revision="1", - version="v42", confinement="devmode", apps=None, cohort="A", @@ -419,7 +424,7 @@ def test_refresh_revision_devmode_cohort_args(self, mock_subprocess: MagicMock): @patch("charms.operator_libs_linux.v2.snap.subprocess.check_output") def test_no_subprocess_when_not_installed(self, mock_subprocess: MagicMock): """Don't call out to snap when ensuring an uninstalled state when not installed.""" - foo = snap.Snap("foo", snap.SnapState.Present, "stable", "1", "v42", "classic") + foo = snap.Snap("foo", snap.SnapState.Present, "stable", "1", "classic") not_installed_states = (snap.SnapState.Absent, snap.SnapState.Available) for _state in not_installed_states: foo._state = _state @@ -430,7 +435,7 @@ def test_no_subprocess_when_not_installed(self, mock_subprocess: MagicMock): @patch("charms.operator_libs_linux.v2.snap.subprocess.check_output") def test_can_run_snap_commands_devmode(self, mock_check_output: MagicMock): mock_check_output.return_value = 0 - foo = snap.Snap("foo", snap.SnapState.Present, "stable", "1", "v42", "devmode") + foo = snap.Snap("foo", snap.SnapState.Present, "stable", "1", "devmode") self.assertEqual(foo.present, True) foo.ensure(snap.SnapState.Absent) @@ -471,7 +476,7 @@ def test_can_run_snap_commands_devmode(self, mock_check_output: MagicMock): @patch("charms.operator_libs_linux.v2.snap.subprocess.run") def test_can_run_snap_daemon_commands(self, mock_subprocess): mock_subprocess.return_value = MagicMock() - foo = snap.Snap("foo", snap.SnapState.Latest, "stable", "1", "v42", "classic") + foo = snap.Snap("foo", snap.SnapState.Latest, "stable", "1", "classic") foo.start(["bar", "baz"], enable=True) mock_subprocess.assert_called_with( @@ -534,14 +539,14 @@ def test_can_run_snap_daemon_commands(self, mock_subprocess): side_effect=CalledProcessError(returncode=1, cmd=""), ) def test_snap_daemon_commands_raise_snap_error(self, mock_subprocess: MagicMock): - foo = snap.Snap("foo", snap.SnapState.Latest, "stable", "1", "v42", "classic") + foo = snap.Snap("foo", snap.SnapState.Latest, "stable", "1", "classic") with self.assertRaises(snap.SnapError): foo.start(["bad", "arguments"], enable=True) @patch("charms.operator_libs_linux.v2.snap.subprocess.run") def test_snap_connect(self, mock_subprocess): mock_subprocess.return_value = MagicMock() - foo = snap.Snap("foo", snap.SnapState.Latest, "stable", "1", "v42", "classic") + foo = snap.Snap("foo", snap.SnapState.Latest, "stable", "1", "classic") foo.connect(plug="bar", slot="baz") mock_subprocess.assert_called_with( @@ -573,14 +578,14 @@ def test_snap_connect(self, mock_subprocess): ) def test_snap_connect_raises_snap_error(self, mock_subprocess: MagicMock): """Ensure that a SnapError is raised when Snap.connect is called with bad arguments.""" - foo = snap.Snap("foo", snap.SnapState.Latest, "stable", "1", "v42", "classic") + foo = snap.Snap("foo", snap.SnapState.Latest, "stable", "1", "classic") with self.assertRaises(snap.SnapError): foo.connect(plug="bad", slot="argument") @patch("charms.operator_libs_linux.v2.snap.subprocess.check_output") def test_snap_hold_timedelta(self, mock_check_output: MagicMock): mock_check_output.return_value = 0 - foo = snap.Snap("foo", snap.SnapState.Latest, "stable", "1", "v42", "classic") + foo = snap.Snap("foo", snap.SnapState.Latest, "stable", "1", "classic") foo.hold(duration=datetime.timedelta(hours=72)) mock_check_output.assert_called_with( @@ -597,7 +602,7 @@ def test_snap_hold_timedelta(self, mock_check_output: MagicMock): @patch("charms.operator_libs_linux.v2.snap.subprocess.check_output") def test_snap_hold_forever(self, mock_subprocess: MagicMock): mock_subprocess.return_value = 0 - foo = snap.Snap("foo", snap.SnapState.Latest, "stable", "1", "v42", "classic") + foo = snap.Snap("foo", snap.SnapState.Latest, "stable", "1", "classic") foo.hold() mock_subprocess.assert_called_with( @@ -614,7 +619,7 @@ def test_snap_hold_forever(self, mock_subprocess: MagicMock): @patch("charms.operator_libs_linux.v2.snap.subprocess.check_output") def test_snap_unhold(self, mock_subprocess: MagicMock): mock_subprocess.return_value = 0 - foo = snap.Snap("foo", snap.SnapState.Latest, "stable", "1", "v42", "classic") + foo = snap.Snap("foo", snap.SnapState.Latest, "stable", "1", "classic") foo.unhold() mock_subprocess.assert_called_with( @@ -683,7 +688,6 @@ def test_refresh_classic( state=snap.SnapState.Present, channel='stable', revision='1', - version='v42', confinement=confinement, apps=None, cohort='A', @@ -1132,7 +1136,7 @@ def fake_snap(command: str, optargs: Iterable[str] | None) -> str: return json.dumps({}) raise snap.SnapError("Bad arguments:", command, optargs) - foo = snap.Snap("foo", snap.SnapState.Latest, "stable", "1", "v42", "classic") + foo = snap.Snap("foo", snap.SnapState.Latest, "stable", "1", "classic") foo._snap = MagicMock(side_effect=fake_snap) keys_and_values: dict[str, Any] = { "key_w_string_value": "string", @@ -1156,7 +1160,7 @@ def fake_snap(command: str, optargs: Iterable[str] | None) -> str: @patch("charms.operator_libs_linux.v2.snap.SnapClient._put_snap_conf") def test_snap_set_typed(self, put_snap_conf): - foo = snap.Snap("foo", snap.SnapState.Present, "stable", "1", "v42", "classic") + foo = snap.Snap("foo", snap.SnapState.Present, "stable", "1", "classic") config = {"n": 42, "s": "string", "d": {"nested": True}} @@ -1165,7 +1169,7 @@ def test_snap_set_typed(self, put_snap_conf): @patch("charms.operator_libs_linux.v2.snap.SnapClient._put_snap_conf") def test_snap_set_untyped(self, put_snap_conf): - foo = snap.Snap("foo", snap.SnapState.Present, "stable", "1", "v42", "classic") + foo = snap.Snap("foo", snap.SnapState.Present, "stable", "1", "classic") config = {"n": 42, "s": "string", "d": {"nested": True}} @@ -1179,7 +1183,7 @@ def test_snap_set_untyped(self, put_snap_conf): side_effect=lambda *args, **kwargs: "", # pyright: ignore[reportUnknownLambdaType] ) def test_snap_unset(self, mock_subprocess: MagicMock): - foo = snap.Snap("foo", snap.SnapState.Present, "stable", "1", "v42", "classic") + foo = snap.Snap("foo", snap.SnapState.Present, "stable", "1", "classic") key: str = "test_key" self.assertEqual(foo.unset(key), "") mock_subprocess.assert_called_with( @@ -1317,7 +1321,7 @@ def test_install_local_called_process_error(self, mock_subprocess: MagicMock): @patch("charms.operator_libs_linux.v2.snap.subprocess.run") def test_alias(self, mock_run: MagicMock): - foo = snap.Snap("foo", snap.SnapState.Latest, "stable", "1", "v42", "classic") + foo = snap.Snap("foo", snap.SnapState.Latest, "stable", "1", "classic") foo.alias("bar", "baz") mock_run.assert_called_once_with( ["snap", "alias", "foo.bar", "baz"], @@ -1341,7 +1345,7 @@ def test_alias_raises_snap_error(self, mock_run: MagicMock): mock_run.side_effect = CalledProcessError( returncode=1, cmd=["snap", "alias", "foo.bar", "baz"] ) - foo = snap.Snap("foo", snap.SnapState.Latest, "stable", "1", "v42", "classic") + foo = snap.Snap("foo", snap.SnapState.Latest, "stable", "1", "classic") with self.assertRaises(snap.SnapError): foo.alias("bar", "baz") mock_run.assert_any_call( @@ -1354,7 +1358,7 @@ def test_alias_raises_snap_error(self, mock_run: MagicMock): @patch("charms.operator_libs_linux.v2.snap.subprocess.check_output") def test_held(self, mock_subprocess: MagicMock): - foo = snap.Snap("foo", snap.SnapState.Latest, "stable", "1", "v42", "classic") + foo = snap.Snap("foo", snap.SnapState.Latest, "stable", "1", "classic") mock_subprocess.return_value = {} self.assertEqual(foo.held, False) mock_subprocess.return_value = {"hold:": "key isn't checked"}