Skip to content

Commit dfb6409

Browse files
bonzinidcbaker
authored andcommitted
cargo: change init-time computation to lazy properties
Make the dataclasses closer to the TypedDicts. Signed-off-by: Paolo Bonzini <[email protected]>
1 parent 752c360 commit dfb6409

File tree

4 files changed

+44
-33
lines changed

4 files changed

+44
-33
lines changed

mesonbuild/cargo/interpreter.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -263,7 +263,7 @@ def _create_dependencies(self, pkg: PackageState, build: builder.Builder) -> T.L
263263
def _create_system_dependency(self, name: str, dep: SystemDependency, build: builder.Builder) -> T.List[mparser.BaseNode]:
264264
# TODO: handle feature_overrides
265265
kw = {
266-
'version': build.array([build.string(s) for s in dep.version]),
266+
'version': build.array([build.string(s) for s in dep.meson_version]),
267267
'required': build.bool(not dep.optional),
268268
}
269269
varname = f'{fixup_meson_varname(name)}_system_dep'
@@ -290,7 +290,7 @@ def _create_system_dependency(self, name: str, dep: SystemDependency, build: bui
290290
def _create_dependency(self, dep: Dependency, build: builder.Builder) -> T.List[mparser.BaseNode]:
291291
pkg = self._dep_package(dep)
292292
kw = {
293-
'version': build.array([build.string(s) for s in dep.version]),
293+
'version': build.array([build.string(s) for s in dep.meson_version]),
294294
}
295295
# Lookup for this dependency with the features we want in default_options kwarg.
296296
#

mesonbuild/cargo/manifest.py

Lines changed: 24 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@
1010
import typing as T
1111

1212
from . import version
13+
from ..mesonlib import MesonException, lazy_property
1314
from .. import mlog
14-
from ..mesonlib import MesonException
1515

1616
if T.TYPE_CHECKING:
1717
from typing_extensions import Protocol, Self
@@ -65,7 +65,6 @@ def _raw_to_dataclass(raw: T.Mapping[str, object], cls: T.Type[_DI],
6565
:param data: The raw data to look at
6666
:param cls: The Dataclass derived type that will be created
6767
:param msg: the header for the error message. Usually something like "In N structure".
68-
:param convert_version: whether to convert the version field to a Meson compatible one.
6968
:return: The original data structure, but with all unknown keys removed.
7069
"""
7170
new_dict = {}
@@ -120,10 +119,9 @@ class Package:
120119
autotests: bool = True
121120
autobenches: bool = True
122121

123-
api: str = dataclasses.field(init=False)
124-
125-
def __post_init__(self) -> None:
126-
self.api = version.api(self.version)
122+
@lazy_property
123+
def api(self) -> str:
124+
return version.api(self.version)
127125

128126
@classmethod
129127
def from_raw(cls, raw_pkg: raw.Package) -> Self:
@@ -137,7 +135,7 @@ class SystemDependency:
137135
"""
138136

139137
name: str
140-
version: T.List[str]
138+
version: str = ''
141139
optional: bool = False
142140
feature: T.Optional[str] = None
143141
# TODO: convert values to dataclass
@@ -146,18 +144,18 @@ class SystemDependency:
146144
@classmethod
147145
def from_raw(cls, name: str, raw: T.Union[T.Dict[str, T.Any], str]) -> SystemDependency:
148146
if isinstance(raw, str):
149-
return cls(name, SystemDependency.convert_version(raw))
147+
raw = {'version': raw}
150148
name = raw.get('name', name)
151-
version = SystemDependency.convert_version(raw.get('version', ''))
149+
version = raw.get('version', '')
152150
optional = raw.get('optional', False)
153151
feature = raw.get('feature')
154152
# Everything else are overrides when certain features are enabled.
155153
feature_overrides = {k: v for k, v in raw.items() if k not in {'name', 'version', 'optional', 'feature'}}
156154
return cls(name, version, optional, feature, feature_overrides)
157155

158-
@staticmethod
159-
def convert_version(version: T.Optional[str]) -> T.List[str]:
160-
vers = version.split(',') if version else []
156+
@lazy_property
157+
def meson_version(self) -> T.List[str]:
158+
vers = self.version.split(',') if self.version else []
161159
result: T.List[str] = []
162160
for v in vers:
163161
v = v.strip()
@@ -175,7 +173,7 @@ class Dependency:
175173
"""Representation of a Cargo Dependency Entry."""
176174

177175
package: str
178-
version: T.List[str]
176+
version: str = ''
179177
registry: T.Optional[str] = None
180178
git: T.Optional[str] = None
181179
branch: T.Optional[str] = None
@@ -185,28 +183,30 @@ class Dependency:
185183
default_features: bool = True
186184
features: T.List[str] = dataclasses.field(default_factory=list)
187185

188-
api: str = dataclasses.field(init=False)
186+
@lazy_property
187+
def meson_version(self) -> T.List[str]:
188+
return version.convert(self.version)
189189

190-
def __post_init__(self) -> None:
190+
@lazy_property
191+
def api(self) -> str:
191192
# Extract wanted API version from version constraints.
192193
api = set()
193-
for v in self.version:
194+
for v in self.meson_version:
194195
if v.startswith(('>=', '==')):
195196
api.add(version.api(v[2:].strip()))
196197
elif v.startswith('='):
197198
api.add(version.api(v[1:].strip()))
198199
if not api:
199-
self.api = '0'
200+
return '0'
200201
elif len(api) == 1:
201-
self.api = api.pop()
202+
return api.pop()
202203
else:
203204
raise MesonException(f'Cannot determine minimum API version from {self.version}.')
204205

205206
@classmethod
206207
def from_raw_dict(cls, name: str, raw_dep: raw.Dependency) -> Dependency:
207208
raw_dep.setdefault('package', name)
208-
return _raw_to_dataclass(raw_dep, cls, f'Dependency entry {name}',
209-
version=version.convert)
209+
return _raw_to_dataclass(raw_dep, cls, f'Dependency entry {name}')
210210

211211
@classmethod
212212
def from_raw(cls, name: str, raw_depv: raw.DependencyV) -> Dependency:
@@ -344,7 +344,6 @@ class Manifest:
344344
dependencies: T.Dict[str, Dependency] = dataclasses.field(default_factory=dict)
345345
dev_dependencies: T.Dict[str, Dependency] = dataclasses.field(default_factory=dict)
346346
build_dependencies: T.Dict[str, Dependency] = dataclasses.field(default_factory=dict)
347-
system_dependencies: T.Dict[str, SystemDependency] = dataclasses.field(init=False)
348347
lib: T.Optional[Library] = None
349348
bin: T.List[Binary] = dataclasses.field(default_factory=list)
350349
test: T.List[Test] = dataclasses.field(default_factory=list)
@@ -357,7 +356,10 @@ class Manifest:
357356

358357
def __post_init__(self) -> None:
359358
self.features.setdefault('default', [])
360-
self.system_dependencies = {k: SystemDependency.from_raw(k, v) for k, v in self.package.metadata.get('system-deps', {}).items()}
359+
360+
@lazy_property
361+
def system_dependencies(self) -> T.Dict[str, SystemDependency]:
362+
return {k: SystemDependency.from_raw(k, v) for k, v in self.package.metadata.get('system-deps', {}).items()}
361363

362364
@classmethod
363365
def from_raw(cls, raw: raw.Manifest, path: str = '') -> Self:

mesonbuild/cargo/version.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ def convert(cargo_ver: str) -> T.List[str]:
2727
"""
2828
# Cleanup, just for safety
2929
cargo_ver = cargo_ver.strip()
30+
if not cargo_ver:
31+
return []
3032
cargo_vers = [c.strip() for c in cargo_ver.split(',')]
3133

3234
out: T.List[str] = []

unittests/cargotests.py

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -299,28 +299,34 @@ def test_cargo_toml_dependencies(self) -> None:
299299

300300
self.assertEqual(len(manifest.dependencies), 6)
301301
self.assertEqual(manifest.dependencies['gtk'].package, 'gtk4')
302-
self.assertEqual(manifest.dependencies['gtk'].version, ['>= 0.9', '< 0.10'])
302+
self.assertEqual(manifest.dependencies['gtk'].version, '0.9')
303+
self.assertEqual(manifest.dependencies['gtk'].meson_version, ['>= 0.9', '< 0.10'])
303304
self.assertEqual(manifest.dependencies['gtk'].api, '0.9')
304305
self.assertEqual(manifest.dependencies['num-complex'].package, 'num-complex')
305-
self.assertEqual(manifest.dependencies['num-complex'].version, ['>= 0.4', '< 0.5'])
306-
self.assertEqual(manifest.dependencies['num-complex'].api, '0.4')
306+
self.assertEqual(manifest.dependencies['num-complex'].version, '0.4')
307+
self.assertEqual(manifest.dependencies['num-complex'].meson_version, ['>= 0.4', '< 0.5'])
307308
self.assertEqual(manifest.dependencies['rayon'].package, 'rayon')
308-
self.assertEqual(manifest.dependencies['rayon'].version, ['>= 1.0', '< 2'])
309+
self.assertEqual(manifest.dependencies['rayon'].version, '1.0')
310+
self.assertEqual(manifest.dependencies['rayon'].meson_version, ['>= 1.0', '< 2'])
309311
self.assertEqual(manifest.dependencies['rayon'].api, '1')
310312
self.assertEqual(manifest.dependencies['once_cell'].package, 'once_cell')
311-
self.assertEqual(manifest.dependencies['once_cell'].version, ['>= 1', '< 2'])
313+
self.assertEqual(manifest.dependencies['once_cell'].version, '1')
314+
self.assertEqual(manifest.dependencies['once_cell'].meson_version, ['>= 1', '< 2'])
312315
self.assertEqual(manifest.dependencies['once_cell'].api, '1')
313316
self.assertEqual(manifest.dependencies['async-channel'].package, 'async-channel')
314-
self.assertEqual(manifest.dependencies['async-channel'].version, ['>= 2.0', '< 3'])
317+
self.assertEqual(manifest.dependencies['async-channel'].version, '2.0')
318+
self.assertEqual(manifest.dependencies['async-channel'].meson_version, ['>= 2.0', '< 3'])
315319
self.assertEqual(manifest.dependencies['async-channel'].api, '2')
316320
self.assertEqual(manifest.dependencies['zerocopy'].package, 'zerocopy')
317-
self.assertEqual(manifest.dependencies['zerocopy'].version, ['>= 0.7', '< 0.8'])
321+
self.assertEqual(manifest.dependencies['zerocopy'].version, '0.7')
322+
self.assertEqual(manifest.dependencies['zerocopy'].meson_version, ['>= 0.7', '< 0.8'])
318323
self.assertEqual(manifest.dependencies['zerocopy'].features, ['derive'])
319324
self.assertEqual(manifest.dependencies['zerocopy'].api, '0.7')
320325

321326
self.assertEqual(len(manifest.dev_dependencies), 1)
322327
self.assertEqual(manifest.dev_dependencies['gir-format-check'].package, 'gir-format-check')
323-
self.assertEqual(manifest.dev_dependencies['gir-format-check'].version, ['>= 0.1', '< 0.2'])
328+
self.assertEqual(manifest.dev_dependencies['gir-format-check'].version, '^0.1')
329+
self.assertEqual(manifest.dev_dependencies['gir-format-check'].meson_version, ['>= 0.1', '< 0.2'])
324330
self.assertEqual(manifest.dev_dependencies['gir-format-check'].api, '0.1')
325331

326332
def test_cargo_toml_targets(self) -> None:
@@ -371,7 +377,8 @@ def test_cargo_toml_system_deps(self) -> None:
371377

372378
self.assertEqual(len(manifest.system_dependencies), 1)
373379
self.assertEqual(manifest.system_dependencies['pango'].name, 'pango')
374-
self.assertEqual(manifest.system_dependencies['pango'].version, ['>=1.40'])
380+
self.assertEqual(manifest.system_dependencies['pango'].version, '1.40')
381+
self.assertEqual(manifest.system_dependencies['pango'].meson_version, ['>=1.40'])
375382
self.assertEqual(manifest.system_dependencies['pango'].optional, False)
376383
self.assertEqual(manifest.system_dependencies['pango'].feature, None)
377384

0 commit comments

Comments
 (0)