Skip to content

Commit 204667c

Browse files
feat: expose the Juju version via Model objects (canonical#1563)
Charm code currently needs to do `JujuVersion.from_environ()` to get the Juju version. This isn't very 'ops-y' - we expose all the other Juju state through the `Model` object, and it also means that charms instantiate `JujuVersion` objects multiple times - even though the framework has actually done this already when parsing the Juju environment variables. This PR exposes the Juju version via `Model.juju_version`, and deprecates the `JujuVersion.from_environ()` method (actual removal will presumably be in 3.0, a long time off). This also centralises all the Juju environment variable processing in the `JujuContext` object.
1 parent e6f435e commit 204667c

File tree

4 files changed

+31
-4
lines changed

4 files changed

+31
-4
lines changed

ops/jujuversion.py

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
import os
1818
import re
19+
import warnings
1920
from functools import total_ordering
2021
from typing import Union
2122

@@ -100,7 +101,15 @@ def __lt__(self, other: Union[str, 'JujuVersion']) -> bool:
100101

101102
@classmethod
102103
def from_environ(cls) -> 'JujuVersion':
103-
"""Build a version from the ``JUJU_VERSION`` environment variable."""
104+
"""Build a version from the ``JUJU_VERSION`` environment variable.
105+
106+
.. deprecated:: 2.19.0 Use :meth:`Model.juju_version` instead.
107+
"""
108+
warnings.warn(
109+
'JujuVersion.from_environ() is deprecated, use self.model.juju_version instead',
110+
DeprecationWarning,
111+
stacklevel=2,
112+
)
104113
v = os.environ.get('JUJU_VERSION')
105114
if v is None:
106115
v = '0.0.0'

ops/model.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,11 @@ def uuid(self) -> str:
218218
"""
219219
return self._backend.model_uuid
220220

221+
@property
222+
def juju_version(self) -> 'ops.JujuVersion':
223+
"""Return the version of Juju that is running the model."""
224+
return self._backend._juju_context.version
225+
221226
def get_unit(self, unit_name: str) -> 'Unit':
222227
"""Get an arbitrary unit by name.
223228

test/test_jujuversion.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -46,15 +46,18 @@ def test_parsing(vs: str, major: int, minor: int, tag: str, patch: int, build: i
4646
@unittest.mock.patch('os.environ', new={})
4747
def test_from_environ():
4848
# JUJU_VERSION is not set
49-
v = ops.JujuVersion.from_environ()
49+
with pytest.deprecated_call():
50+
v = ops.JujuVersion.from_environ()
5051
assert v == ops.JujuVersion('0.0.0')
5152

5253
os.environ['JUJU_VERSION'] = 'no'
5354
with pytest.raises(RuntimeError, match='not a valid Juju version'):
54-
ops.JujuVersion.from_environ()
55+
with pytest.deprecated_call():
56+
ops.JujuVersion.from_environ()
5557

5658
os.environ['JUJU_VERSION'] = '2.8.0'
57-
v = ops.JujuVersion.from_environ()
59+
with pytest.deprecated_call():
60+
v = ops.JujuVersion.from_environ()
5861
assert v == ops.JujuVersion('2.8.0')
5962

6063

test/test_model.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1146,6 +1146,16 @@ def test_push_path_unnamed(self, getpwuid: mock.MagicMock, getgrgid: mock.MagicM
11461146
container.push_path(push_path, '/')
11471147
assert container.exists('/src.txt'), 'push_path failed: file "src.txt" missing'
11481148

1149+
def test_juju_version_from_model(self):
1150+
version = '3.6.2'
1151+
context = _JujuContext.from_dict({'JUJU_VERSION': version})
1152+
backend = _ModelBackend('myapp/0', juju_context=context)
1153+
model = ops.Model(ops.CharmMeta(), backend)
1154+
assert model.juju_version == version
1155+
assert isinstance(model.juju_version, ops.JujuVersion)
1156+
# Make sure it's not being loaded from the environment.
1157+
assert JujuVersion.from_environ() == '0.0.0'
1158+
11491159

11501160
class PushPullCase:
11511161
"""Test case for table-driven tests."""

0 commit comments

Comments
 (0)