nmk-python 1.6.0__py3-none-any.whl → 1.7.0__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.
- nmk_python/backends/__init__.py +0 -0
- nmk_python/backends/build_backend.py +54 -0
- nmk_python/backends/factory.py +32 -0
- nmk_python/backends/pip_build_backend.py +53 -0
- nmk_python/backends/uv_build_backend.py +56 -0
- nmk_python/build.py +84 -49
- nmk_python/build.yml +25 -9
- nmk_python/files.py +7 -4
- nmk_python/files.yml +23 -20
- nmk_python/project.yml +28 -26
- nmk_python/templates/build.toml.jinja +15 -5
- nmk_python/version.yml +0 -1
- {nmk_python-1.6.0.dist-info → nmk_python-1.7.0.dist-info}/METADATA +1 -1
- nmk_python-1.7.0.dist-info/RECORD +31 -0
- nmk_python-1.6.0.dist-info/RECORD +0 -26
- {nmk_python-1.6.0.dist-info → nmk_python-1.7.0.dist-info}/WHEEL +0 -0
- {nmk_python-1.6.0.dist-info → nmk_python-1.7.0.dist-info}/licenses/LICENSE +0 -0
- {nmk_python-1.6.0.dist-info → nmk_python-1.7.0.dist-info}/top_level.txt +0 -0
|
File without changes
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Python build backend definition module
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from abc import ABC, abstractmethod
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
|
|
8
|
+
from nmk.model.model import NmkModel
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class PythonBuildBackend(ABC):
|
|
12
|
+
"""
|
|
13
|
+
Python build backend interface
|
|
14
|
+
|
|
15
|
+
:param model: NmkModel instance
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
def __init__(self, model: NmkModel):
|
|
19
|
+
self._model = model
|
|
20
|
+
self._env_backend = model.env_backend
|
|
21
|
+
|
|
22
|
+
@abstractmethod
|
|
23
|
+
def install_editable(self): # pragma: no cover
|
|
24
|
+
"""
|
|
25
|
+
Install current project as editable package
|
|
26
|
+
"""
|
|
27
|
+
pass
|
|
28
|
+
|
|
29
|
+
@abstractmethod
|
|
30
|
+
def install_wheel(self, wheel_path: Path): # pragma: no cover
|
|
31
|
+
"""
|
|
32
|
+
Install current project built wheel
|
|
33
|
+
"""
|
|
34
|
+
pass
|
|
35
|
+
|
|
36
|
+
@abstractmethod
|
|
37
|
+
def build_wheel(self, build_dir: Path, built_wheel_name: str, wheel_version: str) -> Path: # pragma: no cover
|
|
38
|
+
"""
|
|
39
|
+
Build current project wheel
|
|
40
|
+
|
|
41
|
+
:param build_dir: temporary build folder
|
|
42
|
+
:param built_wheel_name: name of the built wheel file
|
|
43
|
+
:return: path to built wheel
|
|
44
|
+
"""
|
|
45
|
+
pass
|
|
46
|
+
|
|
47
|
+
@abstractmethod
|
|
48
|
+
def uninstall_wheel(self, wheel_name: str): # pragma: no cover
|
|
49
|
+
"""
|
|
50
|
+
Uninstall specified wheel
|
|
51
|
+
|
|
52
|
+
:param wheel_name: name of the wheel to uninstall
|
|
53
|
+
"""
|
|
54
|
+
pass
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Build backend factory definition module
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from nmk.model.model import NmkModel
|
|
6
|
+
|
|
7
|
+
from .build_backend import PythonBuildBackend
|
|
8
|
+
from .pip_build_backend import PipBuildBackend
|
|
9
|
+
from .uv_build_backend import UvBuildBackend
|
|
10
|
+
|
|
11
|
+
# Supported backends mapping
|
|
12
|
+
_SUPPORTED_BACKENDS = {"pip": PipBuildBackend, "legacy": PipBuildBackend, "uv": UvBuildBackend}
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class BuildBackendFactory:
|
|
16
|
+
"""
|
|
17
|
+
Python build backend factory
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
@staticmethod
|
|
21
|
+
def create(model: NmkModel) -> PythonBuildBackend:
|
|
22
|
+
"""
|
|
23
|
+
Create a python build backend, from provided environment backend
|
|
24
|
+
|
|
25
|
+
:param model: NmkModel instance
|
|
26
|
+
:return: Python build backend instance
|
|
27
|
+
"""
|
|
28
|
+
|
|
29
|
+
# Check for supported backend
|
|
30
|
+
env_backend_name = model.env_backend.name
|
|
31
|
+
assert env_backend_name in _SUPPORTED_BACKENDS, f"Unsupported backend for python build: {env_backend_name}"
|
|
32
|
+
return _SUPPORTED_BACKENDS[env_backend_name](model)
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Pip build backend module.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import sys
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
from typing import cast
|
|
8
|
+
|
|
9
|
+
from nmk.utils import run_with_logs
|
|
10
|
+
|
|
11
|
+
from .build_backend import PythonBuildBackend
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class PipBuildBackend(PythonBuildBackend):
|
|
15
|
+
"""
|
|
16
|
+
Pip build backend implementation
|
|
17
|
+
|
|
18
|
+
:param model: NmkModel instance
|
|
19
|
+
"""
|
|
20
|
+
|
|
21
|
+
def install_editable(self):
|
|
22
|
+
# Prepare install args
|
|
23
|
+
install_args = ["install", "-e", "."]
|
|
24
|
+
|
|
25
|
+
# Add extra args from model config
|
|
26
|
+
install_args += cast(list[str], self._model.config["pythonEditablePipInstallArgs"].value)
|
|
27
|
+
|
|
28
|
+
# Delegate to subprocess
|
|
29
|
+
self._env_backend.subprocess(install_args, cwd=self._env_backend.project_path)
|
|
30
|
+
|
|
31
|
+
def install_wheel(self, wheel_path: Path):
|
|
32
|
+
# Prepare install args
|
|
33
|
+
install_args = ["install", str(wheel_path)]
|
|
34
|
+
|
|
35
|
+
# Add extra args from model config
|
|
36
|
+
install_args += cast(list[str], self._model.config["pythonWheelPipInstallArgs"].value)
|
|
37
|
+
|
|
38
|
+
# Delegate to subprocess
|
|
39
|
+
self._env_backend.subprocess(install_args, cwd=self._env_backend.project_path)
|
|
40
|
+
|
|
41
|
+
def build_wheel(self, build_dir: Path, built_wheel_name: str, wheel_version: str) -> Path:
|
|
42
|
+
# Delegate to build module
|
|
43
|
+
run_with_logs([sys.executable, "-m", "build", "--wheel", "--skip-dependency-check", "--no-isolation"], cwd=build_dir)
|
|
44
|
+
|
|
45
|
+
# Return built wheel path
|
|
46
|
+
return build_dir / "dist" / built_wheel_name
|
|
47
|
+
|
|
48
|
+
def uninstall_wheel(self, wheel_name: str):
|
|
49
|
+
# Prepare uninstall args
|
|
50
|
+
uninstall_args = ["uninstall", "--yes", wheel_name]
|
|
51
|
+
|
|
52
|
+
# Delegate to subprocess
|
|
53
|
+
self._env_backend.subprocess(uninstall_args, cwd=self._env_backend.project_path)
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Uv build backend module.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
from typing import cast
|
|
7
|
+
|
|
8
|
+
from .build_backend import PythonBuildBackend
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class UvBuildBackend(PythonBuildBackend):
|
|
12
|
+
"""
|
|
13
|
+
Uv build backend implementation
|
|
14
|
+
|
|
15
|
+
:param model: NmkModel instance
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
def install_editable(self):
|
|
19
|
+
# Prepare install args
|
|
20
|
+
install_args = ["sync"]
|
|
21
|
+
|
|
22
|
+
# Add extra args from model config
|
|
23
|
+
install_args += cast(list[str], self._model.config["pythonEditableUvInstallArgs"].value)
|
|
24
|
+
|
|
25
|
+
# Delegate to subprocess
|
|
26
|
+
self._env_backend.subprocess(install_args, cwd=self._env_backend.project_path)
|
|
27
|
+
|
|
28
|
+
def install_wheel(self, wheel_path: Path):
|
|
29
|
+
# Prepare install args
|
|
30
|
+
install_args = ["pip", "install", str(wheel_path)]
|
|
31
|
+
|
|
32
|
+
# Add extra args from model config
|
|
33
|
+
install_args += cast(list[str], self._model.config["pythonWheelUvInstallArgs"].value)
|
|
34
|
+
|
|
35
|
+
# Delegate to subprocess
|
|
36
|
+
self._env_backend.subprocess(install_args, cwd=self._env_backend.project_path)
|
|
37
|
+
|
|
38
|
+
def build_wheel(self, build_dir: Path, built_wheel_name: str, wheel_version: str) -> Path:
|
|
39
|
+
# Name for wheel sub-directory
|
|
40
|
+
wheel_sub_dir = "wheel_dist"
|
|
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
|
+
# Delegate to uv
|
|
48
|
+
build_args = ["build", "--wheel", "--out-dir", wheel_sub_dir]
|
|
49
|
+
self._env_backend.subprocess(build_args, cwd=build_dir)
|
|
50
|
+
|
|
51
|
+
# Return built wheel path
|
|
52
|
+
return build_dir / wheel_sub_dir / built_wheel_name
|
|
53
|
+
|
|
54
|
+
def uninstall_wheel(self, wheel_name: str):
|
|
55
|
+
# Same as setup
|
|
56
|
+
self._env_backend.upgrade(full=False, only_deps=True)
|
nmk_python/build.py
CHANGED
|
@@ -3,34 +3,39 @@ Python package build module
|
|
|
3
3
|
"""
|
|
4
4
|
|
|
5
5
|
import shutil
|
|
6
|
-
import sys
|
|
7
|
-
from logging import Logger
|
|
8
6
|
from pathlib import Path
|
|
9
7
|
|
|
8
|
+
from nmk.logs import NmkLogWrapper
|
|
10
9
|
from nmk.model.builder import NmkTaskBuilder
|
|
11
|
-
from nmk.model.
|
|
12
|
-
from nmk.model.resolver import NmkListConfigResolver, NmkStrConfigResolver
|
|
13
|
-
from nmk.utils import is_windows
|
|
14
|
-
|
|
15
|
-
from
|
|
16
|
-
from tomlkit.toml_file import TOMLFile
|
|
10
|
+
from nmk.model.model import NmkModel
|
|
11
|
+
from nmk.model.resolver import NmkDictConfigResolver, NmkListConfigResolver, NmkStrConfigResolver
|
|
12
|
+
from nmk.utils import is_windows
|
|
13
|
+
|
|
14
|
+
from nmk_python.backends.factory import BuildBackendFactory
|
|
17
15
|
|
|
18
16
|
|
|
19
17
|
# Install filter for Windows
|
|
20
|
-
def _can_install(name: str, logger:
|
|
18
|
+
def _can_install(name: str, logger: NmkLogWrapper) -> bool:
|
|
21
19
|
# On Windows, refuse to install nmk package while running nmk (wont' work)
|
|
22
|
-
if is_windows() and name
|
|
23
|
-
logger.warning("Can't install
|
|
20
|
+
if is_windows() and name in ["nmk", "buildenv"]:
|
|
21
|
+
logger.warning(f"Can't install {name} while running {name}!")
|
|
24
22
|
return False
|
|
25
23
|
return True
|
|
26
24
|
|
|
27
25
|
|
|
26
|
+
# Get python package from model
|
|
27
|
+
def _python_package(model: NmkModel) -> str:
|
|
28
|
+
cfg = model.config.get("pythonPackage")
|
|
29
|
+
assert cfg is not None and isinstance(cfg.value, str), "Can't read pythonPackage from model"
|
|
30
|
+
return cfg.value
|
|
31
|
+
|
|
32
|
+
|
|
28
33
|
class PackageBuilder(NmkTaskBuilder):
|
|
29
34
|
"""
|
|
30
35
|
Python package builder
|
|
31
36
|
"""
|
|
32
37
|
|
|
33
|
-
def build(self, project_file: str, version_file: str, source_dirs: list[str], artifacts_dir: str, build_dir: str, extra_resources: dict[str, str]):
|
|
38
|
+
def build(self, project_file: str, version_file: str, source_dirs: list[str], artifacts_dir: str, build_dir: str, extra_resources: dict[str, str]): # pyright: ignore[reportIncompatibleMethodOverride]
|
|
34
39
|
"""
|
|
35
40
|
Delegate to python build module, from a temporary build folder
|
|
36
41
|
|
|
@@ -49,21 +54,14 @@ class PackageBuilder(NmkTaskBuilder):
|
|
|
49
54
|
build_path.mkdir(exist_ok=True, parents=True)
|
|
50
55
|
|
|
51
56
|
# Copy source folders and various project files
|
|
52
|
-
|
|
57
|
+
project_path = Path(project_file)
|
|
58
|
+
project_root = project_path.parent
|
|
53
59
|
for source_dir in map(Path, source_dirs):
|
|
54
60
|
shutil.copytree(source_dir, build_path / source_dir.relative_to(project_root))
|
|
55
|
-
for candidate in filter(lambda p: p.is_file(), map(Path, [
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
build_project = build_path / Path(project_file).name
|
|
60
|
-
build_version = build_path / Path(version_file).name
|
|
61
|
-
with build_project.open() as f:
|
|
62
|
-
project_doc = loads(f.read())
|
|
63
|
-
dyn_table = project_doc.get("tool").get("setuptools").get("dynamic")
|
|
64
|
-
dyn_table["version"] = {"file": build_version.name}
|
|
65
|
-
project_output = TOMLFile(build_project)
|
|
66
|
-
project_output.write(project_doc)
|
|
61
|
+
for candidate in filter(lambda p: p.is_file(), map(Path, [project_path, version_file, project_root / "README.md", project_root / "LICENSE"])):
|
|
62
|
+
dest = build_path / candidate.relative_to(project_root)
|
|
63
|
+
dest.parent.mkdir(parents=True, exist_ok=True)
|
|
64
|
+
shutil.copyfile(candidate, dest)
|
|
67
65
|
|
|
68
66
|
# Handle extra resources
|
|
69
67
|
for src, dst in extra_resources.items():
|
|
@@ -90,18 +88,17 @@ class PackageBuilder(NmkTaskBuilder):
|
|
|
90
88
|
for wheel in artifacts_path.glob("*.whl"):
|
|
91
89
|
wheel.unlink()
|
|
92
90
|
|
|
93
|
-
#
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
91
|
+
# Read version from file
|
|
92
|
+
wheel_version = Path(version_file).read_text().splitlines()[0]
|
|
93
|
+
|
|
94
|
+
# Delegate to build backend
|
|
95
|
+
built_wheel = BuildBackendFactory.create(self.model).build_wheel(
|
|
96
|
+
build_dir=build_path, built_wheel_name=self.main_output.name, wheel_version=wheel_version
|
|
98
97
|
)
|
|
98
|
+
assert built_wheel.is_file(), f"Expected built wheel not found: {built_wheel}"
|
|
99
99
|
|
|
100
100
|
# Copy wheel to artifacts folder
|
|
101
|
-
|
|
102
|
-
built_wheel = build_path / "dist" / target_wheel.name
|
|
103
|
-
assert built_wheel.is_file(), f"Expected built wheel not found: {built_wheel}"
|
|
104
|
-
shutil.copyfile(built_wheel, target_wheel)
|
|
101
|
+
shutil.copyfile(built_wheel, self.main_output)
|
|
105
102
|
|
|
106
103
|
|
|
107
104
|
class PythonModuleResolver(NmkStrConfigResolver):
|
|
@@ -113,27 +110,30 @@ class PythonModuleResolver(NmkStrConfigResolver):
|
|
|
113
110
|
"""
|
|
114
111
|
Return module name from package (i.e. wheel) name
|
|
115
112
|
"""
|
|
116
|
-
return self.model.
|
|
113
|
+
return _python_package(self.model).replace("-", "_")
|
|
117
114
|
|
|
118
115
|
|
|
119
|
-
class Installer(
|
|
116
|
+
class Installer(NmkTaskBuilder):
|
|
120
117
|
"""
|
|
121
118
|
Install built wheel in venv
|
|
122
119
|
"""
|
|
123
120
|
|
|
124
|
-
def build(self, name: str, pip_args: list[str], to_remove: str):
|
|
121
|
+
def build(self, name: str, wheel: str, pip_args: list[str] | None = None, to_remove: str = ""): # pyright: ignore[reportIncompatibleMethodOverride]
|
|
125
122
|
"""
|
|
126
123
|
Install wheel in venv
|
|
127
124
|
|
|
128
125
|
:param name: wheel name to be installed
|
|
129
|
-
:param
|
|
126
|
+
:param wheel: wheel path to be installed
|
|
127
|
+
:param pip_args: pip command line arguments; deprecated, not used anymore
|
|
130
128
|
:param to_remove: stamp file to be removed
|
|
131
129
|
"""
|
|
132
130
|
|
|
133
131
|
# Check if wheel can be installed
|
|
134
132
|
if _can_install(name, self.logger):
|
|
135
|
-
#
|
|
136
|
-
|
|
133
|
+
# Delegate to build backend
|
|
134
|
+
old_packages = self.model.env_backend.installed_packages
|
|
135
|
+
BuildBackendFactory.create(self.model).install_wheel(wheel_path=Path(wheel))
|
|
136
|
+
self.model.env_backend.print_updates(old_packages)
|
|
137
137
|
|
|
138
138
|
# Remove stamp file
|
|
139
139
|
Path(to_remove).unlink(missing_ok=True)
|
|
@@ -144,7 +144,7 @@ class Uninstaller(NmkTaskBuilder):
|
|
|
144
144
|
Uninstall current project wheel from venv
|
|
145
145
|
"""
|
|
146
146
|
|
|
147
|
-
def build(self, name: str):
|
|
147
|
+
def build(self, name: str): # pyright: ignore[reportIncompatibleMethodOverride]
|
|
148
148
|
"""
|
|
149
149
|
Uninstall wheel from venv
|
|
150
150
|
|
|
@@ -153,8 +153,10 @@ class Uninstaller(NmkTaskBuilder):
|
|
|
153
153
|
:param name: wheel name to be uninstalled
|
|
154
154
|
"""
|
|
155
155
|
|
|
156
|
-
#
|
|
157
|
-
|
|
156
|
+
# Delegate to build backend
|
|
157
|
+
old_packages = self.model.env_backend.installed_packages
|
|
158
|
+
BuildBackendFactory.create(self.model).uninstall_wheel(wheel_name=name)
|
|
159
|
+
self.model.env_backend.print_updates(old_packages)
|
|
158
160
|
|
|
159
161
|
|
|
160
162
|
class EditableBuilder(NmkTaskBuilder):
|
|
@@ -162,17 +164,19 @@ class EditableBuilder(NmkTaskBuilder):
|
|
|
162
164
|
Install python project in editable mode
|
|
163
165
|
"""
|
|
164
166
|
|
|
165
|
-
def build(self, pip_args: list[str]):
|
|
167
|
+
def build(self, pip_args: list[str] | None = None): # pyright: ignore[reportIncompatibleMethodOverride]
|
|
166
168
|
"""
|
|
167
169
|
Install project in venv as editable package
|
|
168
170
|
|
|
169
|
-
:param pip_args: pip command line arguments
|
|
171
|
+
:param pip_args: pip command line arguments; deprecated, not used anymore
|
|
170
172
|
"""
|
|
171
173
|
|
|
172
174
|
# Check if project can be installed in editable mode
|
|
173
|
-
if _can_install(self.model
|
|
174
|
-
# Delegate to
|
|
175
|
-
|
|
175
|
+
if _can_install(_python_package(self.model), self.logger):
|
|
176
|
+
# Delegate to build backend
|
|
177
|
+
old_packages = self.model.env_backend.installed_packages
|
|
178
|
+
BuildBackendFactory.create(self.model).install_editable()
|
|
179
|
+
self.model.env_backend.print_updates(old_packages)
|
|
176
180
|
|
|
177
181
|
# Touch stamp file
|
|
178
182
|
self.main_output.touch()
|
|
@@ -183,8 +187,39 @@ class PythonOptionalDepsResolver(NmkListConfigResolver):
|
|
|
183
187
|
Python optional deps resolver
|
|
184
188
|
"""
|
|
185
189
|
|
|
186
|
-
def get_value(self, name: str, groups: dict[str, list[str]]) -> list[str]:
|
|
190
|
+
def get_value(self, name: str, groups: dict[str, list[str]]) -> list[str]: # pyright: ignore[reportIncompatibleMethodOverride]
|
|
187
191
|
"""
|
|
188
192
|
Turn dependency options deps dict into a merged list of dependencies
|
|
189
193
|
"""
|
|
190
194
|
return sorted(list(set(dependency for deps in groups.values() for dependency in deps)))
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
class PythonDevDepsResolver(NmkListConfigResolver):
|
|
198
|
+
"""
|
|
199
|
+
Python development deps resolver
|
|
200
|
+
"""
|
|
201
|
+
|
|
202
|
+
def get_value(self, name: str, package_deps: list[str], all_deps: list[str]) -> list[str]: # pyright: ignore[reportIncompatibleMethodOverride]
|
|
203
|
+
"""
|
|
204
|
+
Return development dependencies (all deps minus package deps)
|
|
205
|
+
"""
|
|
206
|
+
return sorted(list(set(all_deps) - set(package_deps)))
|
|
207
|
+
|
|
208
|
+
|
|
209
|
+
class PythonArchiveDepsResolver(NmkDictConfigResolver):
|
|
210
|
+
"""
|
|
211
|
+
Python archive dependencies resolver
|
|
212
|
+
"""
|
|
213
|
+
|
|
214
|
+
def get_value(self, name: str, archives: list[str]) -> dict[str, str]: # pyright: ignore[reportIncompatibleMethodOverride]
|
|
215
|
+
"""
|
|
216
|
+
Return archive dependencies mapping (python package name -> wheel path)
|
|
217
|
+
"""
|
|
218
|
+
|
|
219
|
+
# Iterate on existing archives paths
|
|
220
|
+
out: dict[str, str] = {}
|
|
221
|
+
for dep in filter(lambda p: p.is_file() and "-" in p.name, map(Path, archives)):
|
|
222
|
+
# Extract package name from wheel file name
|
|
223
|
+
dep_name = dep.name.split("-")[0].replace("_", "-")
|
|
224
|
+
out[dep_name] = str(dep.resolve()).replace("\\", "\\\\") # Escape backslashes for Windows paths
|
|
225
|
+
return out
|
nmk_python/build.yml
CHANGED
|
@@ -36,6 +36,19 @@ config:
|
|
|
36
36
|
# Python package dependencies
|
|
37
37
|
pythonPackageRequirements: []
|
|
38
38
|
|
|
39
|
+
# Python development dependencies
|
|
40
|
+
pythonDevRequirements:
|
|
41
|
+
__resolver__: nmk_python.build.PythonDevDepsResolver
|
|
42
|
+
params:
|
|
43
|
+
package_deps: ${pythonPackageRequirements}
|
|
44
|
+
all_deps: ${venvPkgDeps}
|
|
45
|
+
|
|
46
|
+
# Archive related requirements
|
|
47
|
+
pythonArchiveRequirements:
|
|
48
|
+
__resolver__: nmk_python.build.PythonArchiveDepsResolver
|
|
49
|
+
params:
|
|
50
|
+
archives: ${venvArchiveDeps}
|
|
51
|
+
|
|
39
52
|
# Also install in venv all dependencies
|
|
40
53
|
venvPkgDeps:
|
|
41
54
|
- ${pythonPackageRequirements}
|
|
@@ -63,16 +76,22 @@ config:
|
|
|
63
76
|
password: ${{ secrets.pypi_password }}
|
|
64
77
|
packages_dir: ${r!pythonArtifacts}
|
|
65
78
|
|
|
66
|
-
# Wheel install arguments
|
|
67
|
-
|
|
79
|
+
# Wheel install arguments (for pip backend)
|
|
80
|
+
pythonWheelPipInstallArgs:
|
|
68
81
|
- --force-reinstall # force reinstall because otherwise install will be skipped if version didn't changed
|
|
69
82
|
- --no-deps # but skip dependencies to avoid reinstalling everything (deps are already installed by py.venv task)
|
|
70
83
|
|
|
71
|
-
# Editable install arguments
|
|
72
|
-
|
|
84
|
+
# Editable install arguments (for pip backend)
|
|
85
|
+
pythonEditablePipInstallArgs:
|
|
73
86
|
- --no-deps # skip dependencies to avoid reinstalling everything
|
|
74
87
|
- --no-build-isolation # disable dependencies install when building for "editable" mode
|
|
75
88
|
|
|
89
|
+
# Wheel install arguments (for uv backend)
|
|
90
|
+
pythonWheelUvInstallArgs: []
|
|
91
|
+
|
|
92
|
+
# Editable install arguments (for uv backend)
|
|
93
|
+
pythonEditableUvInstallArgs: []
|
|
94
|
+
|
|
76
95
|
# Type checking mode for Pyright; may be off, basic, standard, strict
|
|
77
96
|
pythonTypeCheckingMode: strict
|
|
78
97
|
|
|
@@ -96,9 +115,7 @@ tasks:
|
|
|
96
115
|
input:
|
|
97
116
|
- ${pythonProjectFile}
|
|
98
117
|
builder: nmk_python.build.EditableBuilder
|
|
99
|
-
|
|
100
|
-
pip_args:
|
|
101
|
-
- ${pythonEditableInstallArgs}
|
|
118
|
+
|
|
102
119
|
|
|
103
120
|
# Python wheel build
|
|
104
121
|
py.build:
|
|
@@ -139,8 +156,7 @@ tasks:
|
|
|
139
156
|
builder: nmk_python.build.Installer
|
|
140
157
|
params:
|
|
141
158
|
name: ${pythonPackage}
|
|
142
|
-
|
|
143
|
-
- ${pythonWheelInstallArgs}
|
|
159
|
+
wheel: ${pythonWheel}
|
|
144
160
|
to_remove: ${pythonEditableStamp}
|
|
145
161
|
|
|
146
162
|
# Python module clean
|
nmk_python/files.py
CHANGED
|
@@ -2,7 +2,9 @@
|
|
|
2
2
|
Python files resolvers
|
|
3
3
|
"""
|
|
4
4
|
|
|
5
|
+
from abc import abstractmethod
|
|
5
6
|
from pathlib import Path
|
|
7
|
+
from typing import cast
|
|
6
8
|
|
|
7
9
|
from nmk.model.resolver import NmkListConfigResolver
|
|
8
10
|
|
|
@@ -12,6 +14,7 @@ class FilesFinder(NmkListConfigResolver):
|
|
|
12
14
|
Shared logic for files resolution
|
|
13
15
|
"""
|
|
14
16
|
|
|
17
|
+
@abstractmethod
|
|
15
18
|
def find_in_folders(self) -> list[str]: # pragma: no cover
|
|
16
19
|
"""
|
|
17
20
|
Folders to be browsed (to be overridden)
|
|
@@ -38,7 +41,7 @@ class PythonFilesFinder(FilesFinder):
|
|
|
38
41
|
"""
|
|
39
42
|
Python source folders
|
|
40
43
|
"""
|
|
41
|
-
return self.model.config["pythonSrcFolders"].value
|
|
44
|
+
return cast(list[str], self.model.config["pythonSrcFolders"].value)
|
|
42
45
|
|
|
43
46
|
def get_value(self, name: str) -> list[Path]:
|
|
44
47
|
"""
|
|
@@ -50,8 +53,8 @@ class PythonFilesFinder(FilesFinder):
|
|
|
50
53
|
all_files = set(super().get_value(name))
|
|
51
54
|
|
|
52
55
|
# Remove generated and test ones
|
|
53
|
-
all_files -= {Path(p) for p in self.model.config["pythonTestSrcFiles"].value}
|
|
54
|
-
all_files -= {Path(p) for p in self.model.config["pythonGeneratedSrcFiles"].value}
|
|
56
|
+
all_files -= {Path(p) for p in cast(list[str], self.model.config["pythonTestSrcFiles"].value)}
|
|
57
|
+
all_files -= {Path(p) for p in cast(list[str], self.model.config["pythonGeneratedSrcFiles"].value)}
|
|
55
58
|
|
|
56
59
|
return list(all_files)
|
|
57
60
|
|
|
@@ -63,4 +66,4 @@ class PythonTestFilesFinder(FilesFinder):
|
|
|
63
66
|
"""
|
|
64
67
|
Python tests source folders
|
|
65
68
|
"""
|
|
66
|
-
return [self.model.config["pythonTestSources"].value]
|
|
69
|
+
return [cast(str, self.model.config["pythonTestSources"].value)]
|
nmk_python/files.yml
CHANGED
|
@@ -1,27 +1,30 @@
|
|
|
1
1
|
config:
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
2
|
+
# Folder(s) for Python sources
|
|
3
|
+
pythonSrcFolders:
|
|
4
|
+
- ${sourceDir}
|
|
5
5
|
|
|
6
|
-
|
|
7
|
-
|
|
6
|
+
# Package holding test code
|
|
7
|
+
pythonTestPackage: tests
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
|
|
9
|
+
# Root folder for test sources
|
|
10
|
+
pythonTestSources: ${sourceDir}/${pythonTestPackage}
|
|
11
11
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
12
|
+
# Found Python test source files
|
|
13
|
+
pythonTestSrcFiles:
|
|
14
|
+
__resolver__: nmk_python.files.PythonTestFilesFinder
|
|
15
15
|
|
|
16
|
-
|
|
17
|
-
|
|
16
|
+
# Generated Python source files (to let other plugins contribute)
|
|
17
|
+
pythonGeneratedSrcFiles: []
|
|
18
18
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
19
|
+
# Found Python source files (that are neither generated not test ones)
|
|
20
|
+
pythonFoundSrcFiles:
|
|
21
|
+
__resolver__: nmk_python.files.PythonFilesFinder
|
|
22
22
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
23
|
+
# All Python source files
|
|
24
|
+
pythonSrcFiles:
|
|
25
|
+
- ${pythonFoundSrcFiles}
|
|
26
|
+
- ${pythonTestSrcFiles}
|
|
27
|
+
- ${pythonGeneratedSrcFiles}
|
|
28
|
+
|
|
29
|
+
# State if using uv build backend (experimental)
|
|
30
|
+
pythonUseUvBuildBackend: false
|
nmk_python/project.yml
CHANGED
|
@@ -1,32 +1,34 @@
|
|
|
1
1
|
config:
|
|
2
|
-
|
|
3
|
-
|
|
2
|
+
# Generated project file
|
|
3
|
+
pythonProjectFile: ${PROJECTDIR}/pyproject.toml
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
5
|
+
# Paths to pyproject.toml fragments to be merged
|
|
6
|
+
pythonProjectFileFragments: []
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
|
|
8
|
+
# Contributed project items from yml files
|
|
9
|
+
pythonProjectFileItems: {}
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
11
|
+
# Require VSCode specific extension for toml support
|
|
12
|
+
vscodeExtensionsNames:
|
|
13
|
+
- tamasfe.even-better-toml
|
|
14
|
+
|
|
15
|
+
# Input file for venv refresh is project file (overrides nmk-base default)
|
|
16
|
+
venvUpdateInput: ${pythonProjectFile}
|
|
14
17
|
|
|
15
18
|
tasks:
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
plugin_name: nmk-python
|
|
19
|
+
py.project:
|
|
20
|
+
description: Generate python project file
|
|
21
|
+
emoji: ":snake:.:toolbox:"
|
|
22
|
+
input:
|
|
23
|
+
- ${pythonProjectFileFragments}
|
|
24
|
+
- ${pythonVersionStamp}
|
|
25
|
+
output:
|
|
26
|
+
- ${pythonProjectFile}
|
|
27
|
+
deps:
|
|
28
|
+
- py.version
|
|
29
|
+
appendToDeps: py.venv # Project file must be generated before venv is refreshed
|
|
30
|
+
builder: nmk_base.common.TomlFileBuilder
|
|
31
|
+
params:
|
|
32
|
+
fragment_files: ${pythonProjectFileFragments}
|
|
33
|
+
items: ${pythonProjectFileItems}
|
|
34
|
+
plugin_name: nmk-python
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
[build-system]
|
|
2
|
-
requires = ["setuptools"]
|
|
3
|
-
build-backend = "setuptools.build_meta"
|
|
2
|
+
requires = ["{% if pythonUseUvBuildBackend %}uv_build>=0.9.18,<0.10.0{% else %}setuptools{% endif %}"]
|
|
3
|
+
build-backend = "{% if pythonUseUvBuildBackend %}uv_build{% else %}setuptools.build_meta{% endif %}"
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "{{ pythonPackage }}"
|
|
7
|
-
dynamic = ["version"]
|
|
7
|
+
{% if pythonUseUvBuildBackend %}version = "0.0.0"{% else %}dynamic = ["version"]{% endif %}
|
|
8
8
|
authors = [
|
|
9
9
|
{name="{{ projectAuthor }}"},
|
|
10
10
|
]
|
|
@@ -20,7 +20,17 @@ dependencies = [{% for req in pythonPackageRequirements %}
|
|
|
20
20
|
"{{ req }}",{% endfor %}
|
|
21
21
|
]
|
|
22
22
|
|
|
23
|
-
[
|
|
23
|
+
[dependency-groups]
|
|
24
|
+
dev = [{% for req in pythonDevRequirements %}
|
|
25
|
+
"{{ req }}",{% endfor %}{% for req in pythonArchiveRequirements %}
|
|
26
|
+
"{{ req }}@{{ pythonArchiveRequirements[req] }}",{% endfor %}
|
|
27
|
+
]
|
|
28
|
+
|
|
29
|
+
{% if pythonUseUvBuildBackend %}[tool.uv.build-backend]
|
|
30
|
+
module-root = "{{pythonSrcFolders[0]}}"
|
|
31
|
+
wheel-exclude = [{% for module in pythonBuildExcludedModules %}{% if loop.index > 1 %},{% endif %}"{{module}}"{% endfor %}]
|
|
32
|
+
|
|
33
|
+
{% else %}[tool.setuptools.packages.find]
|
|
24
34
|
where = [{% for path in pythonSrcFolders %}"{{path}}",{% endfor %}]
|
|
25
35
|
exclude = [{% for module in pythonBuildExcludedModules %}{% if loop.index > 1 %},{% endif %}"{{module}}"{% endfor %}]
|
|
26
36
|
namespaces = false
|
|
@@ -31,7 +41,7 @@ namespaces = false
|
|
|
31
41
|
[tool.setuptools.dynamic.version]
|
|
32
42
|
file = "{{ pythonVersionStamp }}"
|
|
33
43
|
|
|
34
|
-
[tool.distutils.bdist_wheel]
|
|
44
|
+
{% endif %}[tool.distutils.bdist_wheel]
|
|
35
45
|
plat-name = "{{ pythonPackagePlatform }}"
|
|
36
46
|
|
|
37
47
|
[tool.pyright]
|
nmk_python/version.yml
CHANGED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
nmk_python/__init__.py,sha256=EouCWXbAeObby1vOCx0Vx_WaGC2fEEFDMCen3JZt4TU,446
|
|
2
|
+
nmk_python/badges.yml,sha256=LzElZecCXKxdF-oPkvIwfnbQlOcAM_zUj6MelClmAug,749
|
|
3
|
+
nmk_python/build.py,sha256=gxyDjQdbwcxSk2INF7gnMqWRaa9G8gtrSsqWbgM-Uqg,8558
|
|
4
|
+
nmk_python/build.yml,sha256=CDGwrg2KKgdP1uDozQZIVaolxyEWKkb2ETbz0kBRkIQ,5544
|
|
5
|
+
nmk_python/doc.yml,sha256=12amAlYylH7JAHaqBIOoEZ_LrXY_bPNKuHrrwUkIj8w,932
|
|
6
|
+
nmk_python/files.py,sha256=K6Y-XKXuf8jh4x333Qgj6G1MyB-BgZ5Kd2-XCZhsfR4,2000
|
|
7
|
+
nmk_python/files.yml,sha256=jlp87gW9rTASUnsy7id7VWanaMUMN_py82bMa2adniM,813
|
|
8
|
+
nmk_python/plugin.yml,sha256=hi7osXyIwpHgJAsww5mhOA6emxhzgitDF8cOsvyY29Y,1068
|
|
9
|
+
nmk_python/project.yml,sha256=wBnB6KOglRvIpw1UHuXTYmuE_2BYGBzGWwIEbA5NDv8,985
|
|
10
|
+
nmk_python/ruff.py,sha256=TBmn5nFflcFRvjj36JtJGJ-GYHOK6XfhK9Jp-2dO5_E,1557
|
|
11
|
+
nmk_python/ruff.yml,sha256=FNmYjbv2l5vlqFXinY87LfgzpZ3PSiduB_xUiYw8aMw,3019
|
|
12
|
+
nmk_python/tests.py,sha256=8kRKP3dT2Thi5W5sCQSQOPXkV1D9C7tde3QYySo6G2c,1212
|
|
13
|
+
nmk_python/tests.yml,sha256=Sg6ZezkBVuvOzh-4QbJmZQymCOzXfenc0EpMdMZsEBc,1687
|
|
14
|
+
nmk_python/version.py,sha256=fLpOWdujYwlJB7XhWaOGCTeg3gQaClk2YHoRkkW64dE,3109
|
|
15
|
+
nmk_python/version.yml,sha256=WpZyQ2mChmvA_6eVb_Yp6ZaFIkX6oINxWBhKgb8h4GE,833
|
|
16
|
+
nmk_python/backends/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
17
|
+
nmk_python/backends/build_backend.py,sha256=yW5__VMb_dlHvQQ8svdrDSLHxWbGWHSxpbl_pJu9F8M,1292
|
|
18
|
+
nmk_python/backends/factory.py,sha256=NMYByORffwSSIjeNMLkOnwh6x1xhJQVhoV-0rSooq6Q,953
|
|
19
|
+
nmk_python/backends/pip_build_backend.py,sha256=amI0pf5pqQBDnCXhOc2ca_tiDm6v7XLLtW-Jhqd0w4U,1688
|
|
20
|
+
nmk_python/backends/uv_build_backend.py,sha256=3BTqirTrbAeFdxkSAp3ot2zcJIfApaX1GaMpd46yM1U,1872
|
|
21
|
+
nmk_python/templates/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
22
|
+
nmk_python/templates/build.toml.jinja,sha256=6F1Kdb32JVBWEitxLC7AsUdhx2VTyQEyWhhSb7n3oBs,1770
|
|
23
|
+
nmk_python/templates/pytest.toml.jinja,sha256=zQ3SRWnF23Omxm7zInE54j0l3OyjXSOn5pQ5Pak8Boo,641
|
|
24
|
+
nmk_python/templates/python-settings.json.jinja,sha256=jYXSy96cX9X9GIHoF7XiZDzd4P2GOlMisAVWW626WF4,749
|
|
25
|
+
nmk_python/templates/python-test-debug-launch.json.jinja,sha256=J_xju2EpHNXvgvqBxlf99p7g-ZMh3xE-_2r7o_57gpU,364
|
|
26
|
+
nmk_python/templates/ruff.toml.jinja,sha256=DTHe1ixK1SBY8d2xBCfkGz89HzjAoMO7Ogs12AY1i4Y,346
|
|
27
|
+
nmk_python-1.7.0.dist-info/licenses/LICENSE,sha256=PROo9EW7wP6jmSr_90OluItAsIB411b_CAqEBioMKpI,1074
|
|
28
|
+
nmk_python-1.7.0.dist-info/METADATA,sha256=HSUvh9OSZ-iTijy1avmwcxLXMGevgRkMdtGNl0qEiLk,3148
|
|
29
|
+
nmk_python-1.7.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
30
|
+
nmk_python-1.7.0.dist-info/top_level.txt,sha256=MCb5w_hoOZ0kk3Dajxrd9Pz6lZ3pyuS6TQCRA3vddTo,11
|
|
31
|
+
nmk_python-1.7.0.dist-info/RECORD,,
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
nmk_python/__init__.py,sha256=EouCWXbAeObby1vOCx0Vx_WaGC2fEEFDMCen3JZt4TU,446
|
|
2
|
-
nmk_python/badges.yml,sha256=LzElZecCXKxdF-oPkvIwfnbQlOcAM_zUj6MelClmAug,749
|
|
3
|
-
nmk_python/build.py,sha256=K8BowkROfrGwOPk7wKwOo9fsWJrrk8bDqJqliC876WI,6716
|
|
4
|
-
nmk_python/build.yml,sha256=tbKjPRef7ZydEogsX3tAuQMR1B-vaMX5_q8q8tqzOnM,5046
|
|
5
|
-
nmk_python/doc.yml,sha256=12amAlYylH7JAHaqBIOoEZ_LrXY_bPNKuHrrwUkIj8w,932
|
|
6
|
-
nmk_python/files.py,sha256=gtPf6ldR5F4oGsAdzFnEIbI9MqqvF3z5JQnyONZmLmk,1863
|
|
7
|
-
nmk_python/files.yml,sha256=-vGjogdulwsfdKVEUa5RARYDKxF3m9RmHKFnIhaT3_k,780
|
|
8
|
-
nmk_python/plugin.yml,sha256=hi7osXyIwpHgJAsww5mhOA6emxhzgitDF8cOsvyY29Y,1068
|
|
9
|
-
nmk_python/project.yml,sha256=sRIMvKkasrYlIvOo3DsVyNM_sgID_sHVgZg_bSIqtfw,975
|
|
10
|
-
nmk_python/ruff.py,sha256=TBmn5nFflcFRvjj36JtJGJ-GYHOK6XfhK9Jp-2dO5_E,1557
|
|
11
|
-
nmk_python/ruff.yml,sha256=FNmYjbv2l5vlqFXinY87LfgzpZ3PSiduB_xUiYw8aMw,3019
|
|
12
|
-
nmk_python/tests.py,sha256=8kRKP3dT2Thi5W5sCQSQOPXkV1D9C7tde3QYySo6G2c,1212
|
|
13
|
-
nmk_python/tests.yml,sha256=Sg6ZezkBVuvOzh-4QbJmZQymCOzXfenc0EpMdMZsEBc,1687
|
|
14
|
-
nmk_python/version.py,sha256=fLpOWdujYwlJB7XhWaOGCTeg3gQaClk2YHoRkkW64dE,3109
|
|
15
|
-
nmk_python/version.yml,sha256=amHNaA7WVnD6S1kL0IFD1KLKef9-2aEM3xU2ZkiZanc,905
|
|
16
|
-
nmk_python/templates/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
17
|
-
nmk_python/templates/build.toml.jinja,sha256=RJ-hCDc2SJG3K5rxK8tIIFcW-R7nt7Bu-x0wP9uPGGQ,1114
|
|
18
|
-
nmk_python/templates/pytest.toml.jinja,sha256=zQ3SRWnF23Omxm7zInE54j0l3OyjXSOn5pQ5Pak8Boo,641
|
|
19
|
-
nmk_python/templates/python-settings.json.jinja,sha256=jYXSy96cX9X9GIHoF7XiZDzd4P2GOlMisAVWW626WF4,749
|
|
20
|
-
nmk_python/templates/python-test-debug-launch.json.jinja,sha256=J_xju2EpHNXvgvqBxlf99p7g-ZMh3xE-_2r7o_57gpU,364
|
|
21
|
-
nmk_python/templates/ruff.toml.jinja,sha256=DTHe1ixK1SBY8d2xBCfkGz89HzjAoMO7Ogs12AY1i4Y,346
|
|
22
|
-
nmk_python-1.6.0.dist-info/licenses/LICENSE,sha256=PROo9EW7wP6jmSr_90OluItAsIB411b_CAqEBioMKpI,1074
|
|
23
|
-
nmk_python-1.6.0.dist-info/METADATA,sha256=0tKglaK0AkZMKrLPmsIuBmjKcN5sAeW-7r1zrKJuqHA,3148
|
|
24
|
-
nmk_python-1.6.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
25
|
-
nmk_python-1.6.0.dist-info/top_level.txt,sha256=MCb5w_hoOZ0kk3Dajxrd9Pz6lZ3pyuS6TQCRA3vddTo,11
|
|
26
|
-
nmk_python-1.6.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|