nmk-python 1.11.0__py3-none-any.whl → 1.12.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -67,35 +67,23 @@ class NmkPythonProjectTemplate(NmkBaseProjectTemplate):
67
67
 
68
68
  def handle_dependencies(self, packages: list[str]) -> dict[str, NmkConfigType]:
69
69
  # Iterate on packages
70
- config_items: dict[str, NmkConfigType] = {}
71
- simple_refs: list[str] = []
72
- file_refs: list[str] = []
70
+ other_refs: list[str] = []
73
71
  dep_refs: list[str] = []
72
+
73
+ # Pre-filter non-dev dependencies
74
74
  for package in packages:
75
75
  # Check for dependency groups (no group means it's a regular dependency, otherwise it's a dev dependency)
76
76
  if ":" not in package:
77
77
  dep_refs.append(package)
78
- # Dev dependencies
79
78
  else:
80
- package = package.split(":")[-1] # Ignore dependency groups, if any (e.g. `dev:package` -> `package`)
81
- if "." in package:
82
- package_path = Path(package)
83
- if package_path.is_absolute() and package_path.is_file():
84
- file_refs.append(package)
85
- elif (Path.cwd() / package).is_file():
86
- file_refs.append(f"${{PROJECTDIR}}/{package}")
87
- else:
88
- simple_refs.append(package)
89
- else:
90
- simple_refs.append(package)
79
+ other_refs.append(package)
80
+
81
+ # Delegate to normal processing
82
+ config_items: dict[str, NmkConfigType] = super().handle_dependencies(other_refs)
91
83
 
92
84
  # Build settings
93
- if dep_refs:
85
+ if dep_refs: # pragma: no branch
94
86
  config_items["pythonPackageRequirements"] = dep_refs
95
- if simple_refs:
96
- config_items["venvPkgDeps"] = simple_refs
97
- if file_refs:
98
- config_items["venvArchiveDeps"] = file_refs
99
87
 
100
88
  return config_items
101
89
 
@@ -39,11 +39,6 @@ class UvBuildBackend(PythonBuildBackend):
39
39
  # Name for wheel sub-directory
40
40
  wheel_sub_dir = "wheel_dist"
41
41
 
42
- # Check for (experimental) uv-build backend
43
- if self._model.config["pythonUseUvBuildBackend"].value:
44
- # Prepare project version (without updating the venv)
45
- self._env_backend.subprocess(["version", "--active", "--no-sync", wheel_version], cwd=build_dir)
46
-
47
42
  # Delegate to uv
48
43
  build_args = ["build", "--wheel", "--out-dir", wheel_sub_dir]
49
44
  self._env_backend.subprocess(build_args, cwd=build_dir)
nmk_python/build.py CHANGED
@@ -4,6 +4,7 @@ Python package build module
4
4
 
5
5
  import importlib.metadata
6
6
  import json
7
+ import os
7
8
  import shutil
8
9
  from fnmatch import fnmatch
9
10
  from itertools import product
@@ -17,6 +18,7 @@ from nmk.model.model import NmkModel
17
18
  from nmk.model.resolver import NmkDictConfigResolver, NmkListConfigResolver, NmkStrConfigResolver
18
19
  from nmk.utils import is_windows
19
20
  from packaging.requirements import Requirement
21
+ from packaging.version import Version
20
22
  from tomlkit import loads
21
23
  from tomlkit.toml_file import TOMLFile
22
24
 
@@ -67,7 +69,7 @@ class PackageBuilder(NmkTaskBuilder):
67
69
  project_root = project_path.parent
68
70
  for source_dir in map(Path, source_dirs):
69
71
  shutil.copytree(source_dir, build_path / source_dir.relative_to(project_root))
70
- for candidate in filter(lambda p: p.is_file(), map(Path, [project_path, version_file, project_root / "README.md", project_root / "LICENSE"])):
72
+ for candidate in filter(lambda p: p.is_file(), map(Path, [project_path, project_root / "README.md", project_root / "LICENSE"])):
71
73
  dest = build_path / candidate.relative_to(project_root)
72
74
  dest.parent.mkdir(parents=True, exist_ok=True)
73
75
  shutil.copyfile(candidate, dest)
@@ -266,12 +268,14 @@ class DepsMetadataBuilder(NmkTaskBuilder):
266
268
  Generate python dependencies metadata file
267
269
  """
268
270
 
269
- def build(self, root_name: str, local_deps: list[str]): # pyright: ignore[reportIncompatibleMethodOverride]
271
+ def build(self, root_name: str, local_deps: list[str], constraints: list[str], fail_on_error: bool): # pyright: ignore[reportIncompatibleMethodOverride]
270
272
  """
271
273
  Generate python dependencies metadata file
272
274
 
273
275
  :param root_name: name of the root package
274
276
  :param local_deps: list of workspace local dependencies patterns
277
+ :param constraints: list of package constraints (may contain comments) to be checked against found dependencies
278
+ :param fail_on_error: if there are mismatches between actual dependencies and constraints, and if true, and the build in error
275
279
  """
276
280
 
277
281
  # Normalization implementation
@@ -325,6 +329,40 @@ class DepsMetadataBuilder(NmkTaskBuilder):
325
329
  )
326
330
  )
327
331
 
332
+ # Check constraints vs external deps if any
333
+ filtered_constraints = [line for line in constraints if not line.startswith("# ")]
334
+ if filtered_constraints and output_data[_EXTERNAL_DEPS_KEY]: # pragma: no branch
335
+ try:
336
+ self._check_constraints(filtered_constraints, output_data[_EXTERNAL_DEPS_KEY], fail_on_error)
337
+ except Exception as e:
338
+ # Touch output file to force task to be retriggered on next build
339
+ input_state = self.main_input.stat()
340
+ os.utime(self.main_output, (input_state.st_atime, input_state.st_mtime))
341
+ raise e
342
+
343
+ def _check_constraints(self, constraints: list[str], deps: dict[str, str], fail_on_error: bool):
344
+ # Build all requirements
345
+ all_reqs = {r[0].name: r for r in [(Requirement(line), line) for line in constraints]}
346
+
347
+ # Count errors
348
+ errors = 0
349
+
350
+ # Browse dependencies
351
+ for name, version in deps.items():
352
+ # Check missing constraint on actual dependency
353
+ if name not in all_reqs:
354
+ self.logger.warning(f"Found dependency with missing constraint: {name}")
355
+ errors += 1
356
+ continue
357
+
358
+ # Check mismatch version
359
+ req, req_line = all_reqs[name]
360
+ if Version(version) not in req.specifier:
361
+ self.logger.warning(f"Found dependency with constraint mismatch: {name} ({version}) vs '{req_line}'")
362
+ errors += 1
363
+
364
+ assert (errors == 0) or not fail_on_error, f"{errors} error(s) found while checking dependencies vs constraints"
365
+
328
366
 
329
367
  class PythonIgnoredLockfileResolver(NmkListConfigResolver):
330
368
  """
@@ -338,8 +376,8 @@ class PythonIgnoredLockfileResolver(NmkListConfigResolver):
338
376
 
339
377
  # Ignore uv.lock file if using uv env backend and project is not locked
340
378
  if not self.model.env_backend.is_locked and self.model.env_backend.name == "uv":
341
- return ["uv.lock"] # pragma: no cover
342
- return []
379
+ return ["uv.lock"]
380
+ return [] # pragma: no cover
343
381
 
344
382
 
345
383
  class PythonMergedConstraintsResolver(NmkListConfigResolver):
nmk_python/build.yml CHANGED
@@ -78,7 +78,7 @@ config:
78
78
  with:
79
79
  user: __token__
80
80
  password: ${{ secrets.pypi_password }}
81
- packages_dir: ${r!pythonArtifacts}
81
+ packages_dir: ${r!pythonBuildDir}/wheel_dist
82
82
 
83
83
  # Wheel install arguments (for pip backend)
84
84
  pythonWheelPipInstallArgs:
@@ -121,6 +121,9 @@ config:
121
121
  constraints: ${pythonConstraints}
122
122
  constraints_files: ${pythonConstraintsFiles}
123
123
 
124
+ # Constraints check mode (strict or not)
125
+ pythonConstraintsStrictCheck: false
126
+
124
127
  tasks:
125
128
  # Python editable install
126
129
  py.editable:
@@ -154,6 +157,8 @@ tasks:
154
157
  params:
155
158
  root_name: ${pythonPackage}
156
159
  local_deps: ${pythonLocalDepsPatterns}
160
+ constraints: ${pythonMergedConstraints}
161
+ fail_on_error: ${pythonConstraintsStrictCheck}
157
162
 
158
163
  # Python wheel build
159
164
  py.build:
nmk_python/version.py CHANGED
@@ -59,7 +59,7 @@ class PythonSupportedVersionsResolver(NmkListConfigResolver):
59
59
  assert len(min_split) == len(max_split), prefix + "not the same segments count"
60
60
  assert len(min_split) == 2, prefix + "can only deal with X.Y versions (2 segments expected)"
61
61
  assert min_split[0] == max_split[0], prefix + "can't deal with different major versions"
62
- assert max_split[1] > min_split[1], prefix + "max isn't greater than min"
62
+ assert max_split[1] >= min_split[1], prefix + "max isn't greater than min"
63
63
 
64
64
  # Also verifies current runtime is in range
65
65
  p_ver = platform.python_version()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: nmk-python
3
- Version: 1.11.0
3
+ Version: 1.12.1
4
4
  Summary: Python plugin for nmk build system
5
5
  Author: The dynod project
6
6
  Maintainer: The dynod project
@@ -1,7 +1,7 @@
1
1
  nmk_python/__init__.py,sha256=EouCWXbAeObby1vOCx0Vx_WaGC2fEEFDMCen3JZt4TU,446
2
2
  nmk_python/badges.yml,sha256=LzElZecCXKxdF-oPkvIwfnbQlOcAM_zUj6MelClmAug,749
3
- nmk_python/build.py,sha256=kcixJP5-YgKBKJ-gVtHpvyI3WvjmVHgwEgL9e3OJBNU,14860
4
- nmk_python/build.yml,sha256=p_ziFqTxNqPn6hvLyHtutVJVVmlXqbkr7TbFo64_45w,6336
3
+ nmk_python/build.py,sha256=V2CiDI-srmFriYR7XuKJWZPuuBAv7LYX8drMz06jmug,16828
4
+ nmk_python/build.yml,sha256=nsHgL_2zrWKDV2bkiSMKZTtU_FKVCDXXRThajKylcsw,6527
5
5
  nmk_python/doc.yml,sha256=12amAlYylH7JAHaqBIOoEZ_LrXY_bPNKuHrrwUkIj8w,932
6
6
  nmk_python/files.py,sha256=K6Y-XKXuf8jh4x333Qgj6G1MyB-BgZ5Kd2-XCZhsfR4,2000
7
7
  nmk_python/files.yml,sha256=jlp87gW9rTASUnsy7id7VWanaMUMN_py82bMa2adniM,813
@@ -11,15 +11,15 @@ nmk_python/ruff.py,sha256=TBmn5nFflcFRvjj36JtJGJ-GYHOK6XfhK9Jp-2dO5_E,1557
11
11
  nmk_python/ruff.yml,sha256=L3vSTLGI3ZP46D64VxenhF9Gz3lo5-J9cRwgKBrVl48,2732
12
12
  nmk_python/tests.py,sha256=p2dl41eZW8cpUMOa2DXi3CN3iVQEnElC88Ke89PRyy8,1597
13
13
  nmk_python/tests.yml,sha256=by_Ml1JXjgt1-J96AMp-6gwhISVFVylRZowUvaMkfpk,1636
14
- nmk_python/version.py,sha256=w15Zk7_TgqEsVSFN7Ql71-5gO5yOXoIYRdI_QlvMjYI,2738
14
+ nmk_python/version.py,sha256=ivSff_1l-u-rSACF91s58zX_EUzl0ate_JcX_l7dSQk,2739
15
15
  nmk_python/version.yml,sha256=D_rUnEzjEtCmCgUhfaDPSsANaRkcDW7aZgPX6GZOUIk,1159
16
16
  nmk_python/_buildenv/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
17
- nmk_python/_buildenv/template.py,sha256=avDeQuMSYHTiTwAgLbrpTPZ6bSaEqjCZDkcpzFxNt88,4568
17
+ nmk_python/_buildenv/template.py,sha256=-yugMcl93gcKfPKrLYTmIMOEIoNvVWGVnqkY3-z4JF8,3922
18
18
  nmk_python/backends/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
19
19
  nmk_python/backends/build_backend.py,sha256=WO0wZaxGdPna4K2yK7pNLtZX3cKf6atLLa00931N43Y,1400
20
20
  nmk_python/backends/factory.py,sha256=NMYByORffwSSIjeNMLkOnwh6x1xhJQVhoV-0rSooq6Q,953
21
21
  nmk_python/backends/pip_build_backend.py,sha256=4MGYghBeMjZhUlKTwE0svSHArYwOAaK1I6_gmeNnwaI,1698
22
- nmk_python/backends/uv_build_backend.py,sha256=cIQwKVsYWHlVQCmHWjjoC-3aRmWiHK55VSGexQbn_vw,1963
22
+ nmk_python/backends/uv_build_backend.py,sha256=gpM1L5FuJ5CF-OkRORnAbZHACPNhjkoO1sKZtdAhpf0,1671
23
23
  nmk_python/templates/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
24
24
  nmk_python/templates/build.toml.jinja,sha256=D-RYPUGiqkYUKyQt_dP_tNFU-83eer7bnv57k4pMmIw,2137
25
25
  nmk_python/templates/pytest.toml.jinja,sha256=zQ3SRWnF23Omxm7zInE54j0l3OyjXSOn5pQ5Pak8Boo,641
@@ -30,9 +30,9 @@ nmk_python/templates/src/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZ
30
30
  nmk_python/templates/src/__init__.py.jinja,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
31
31
  nmk_python/templates/src/sample.py.jinja,sha256=OOTps7EjviwYFCIb5GpMHcidxhBY5NLQVlcFLqxuxNU,227
32
32
  nmk_python/templates/src/test_sample.py.jinja,sha256=u-ShBoKDF3se9KvgQ1SzO4NwymjqNowwURF4Q1oR3wo,221
33
- nmk_python-1.11.0.dist-info/licenses/LICENSE,sha256=PROo9EW7wP6jmSr_90OluItAsIB411b_CAqEBioMKpI,1074
34
- nmk_python-1.11.0.dist-info/METADATA,sha256=U8SM11IYPXQVPE-ajBZtYmcV2yllVRn62A_4YifjWhw,3205
35
- nmk_python-1.11.0.dist-info/WHEEL,sha256=K260EYznzXsJYBQGqmI8VTxEdiZYNvDZwW9cBh9-_MA,91
36
- nmk_python-1.11.0.dist-info/entry_points.txt,sha256=QLXIIXl6wODHDnVkh7KuiLv_XzfFtNfdWwpxyB675ak,88
37
- nmk_python-1.11.0.dist-info/top_level.txt,sha256=MCb5w_hoOZ0kk3Dajxrd9Pz6lZ3pyuS6TQCRA3vddTo,11
38
- nmk_python-1.11.0.dist-info/RECORD,,
33
+ nmk_python-1.12.1.dist-info/licenses/LICENSE,sha256=PROo9EW7wP6jmSr_90OluItAsIB411b_CAqEBioMKpI,1074
34
+ nmk_python-1.12.1.dist-info/METADATA,sha256=kODo2u7iSzu4SF_YRJYprLfxncTzvvM5qZGLIhRqaZ0,3205
35
+ nmk_python-1.12.1.dist-info/WHEEL,sha256=YVMoNqKzERt-wjUZwJ33xBGAwnFl-4cqbYkTtWa4itE,91
36
+ nmk_python-1.12.1.dist-info/entry_points.txt,sha256=QLXIIXl6wODHDnVkh7KuiLv_XzfFtNfdWwpxyB675ak,88
37
+ nmk_python-1.12.1.dist-info/top_level.txt,sha256=MCb5w_hoOZ0kk3Dajxrd9Pz6lZ3pyuS6TQCRA3vddTo,11
38
+ nmk_python-1.12.1.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (83.0.0)
2
+ Generator: setuptools (84.0.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5