hatch-cpp 0.3.7__tar.gz → 0.4.1__tar.gz

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.
Files changed (67) hide show
  1. {hatch_cpp-0.3.7 → hatch_cpp-0.4.1}/.gitignore +12 -7
  2. {hatch_cpp-0.3.7 → hatch_cpp-0.4.1}/PKG-INFO +2 -3
  3. {hatch_cpp-0.3.7 → hatch_cpp-0.4.1}/hatch_cpp/__init__.py +1 -1
  4. {hatch_cpp-0.3.7 → hatch_cpp-0.4.1}/hatch_cpp/config.py +9 -10
  5. {hatch_cpp-0.3.7 → hatch_cpp-0.4.1}/hatch_cpp/hooks.py +1 -3
  6. {hatch_cpp-0.3.7 → hatch_cpp-0.4.1}/hatch_cpp/plugin.py +1 -1
  7. {hatch_cpp-0.3.7/hatch_cpp/tests/test_project_cmake_vcpkg → hatch_cpp-0.4.1/hatch_cpp/tests/test_project_cmake}/CMakeLists.txt +3 -11
  8. {hatch_cpp-0.3.7/hatch_cpp/tests/test_project_cmake → hatch_cpp-0.4.1/hatch_cpp/tests/test_project_cmake_vcpkg}/CMakeLists.txt +3 -11
  9. {hatch_cpp-0.3.7 → hatch_cpp-0.4.1}/hatch_cpp/tests/test_projects.py +17 -9
  10. {hatch_cpp-0.3.7 → hatch_cpp-0.4.1}/hatch_cpp/tests/test_vcpkg_ref.py +21 -0
  11. {hatch_cpp-0.3.7 → hatch_cpp-0.4.1}/hatch_cpp/toolchains/cmake.py +8 -8
  12. {hatch_cpp-0.3.7 → hatch_cpp-0.4.1}/hatch_cpp/toolchains/common.py +63 -75
  13. {hatch_cpp-0.3.7 → hatch_cpp-0.4.1}/hatch_cpp/toolchains/vcpkg.py +16 -11
  14. {hatch_cpp-0.3.7 → hatch_cpp-0.4.1}/hatch_cpp/utils.py +2 -2
  15. {hatch_cpp-0.3.7 → hatch_cpp-0.4.1}/pyproject.toml +6 -4
  16. {hatch_cpp-0.3.7 → hatch_cpp-0.4.1}/LICENSE +0 -0
  17. {hatch_cpp-0.3.7 → hatch_cpp-0.4.1}/README.md +0 -0
  18. {hatch_cpp-0.3.7 → hatch_cpp-0.4.1}/hatch_cpp/tests/test_hatch_build.py +0 -0
  19. {hatch_cpp-0.3.7 → hatch_cpp-0.4.1}/hatch_cpp/tests/test_platform_specific.py +0 -0
  20. {hatch_cpp-0.3.7 → hatch_cpp-0.4.1}/hatch_cpp/tests/test_project_basic/cpp/project/basic.cpp +0 -0
  21. {hatch_cpp-0.3.7 → hatch_cpp-0.4.1}/hatch_cpp/tests/test_project_basic/cpp/project/basic.hpp +0 -0
  22. {hatch_cpp-0.3.7 → hatch_cpp-0.4.1}/hatch_cpp/tests/test_project_basic/project/__init__.py +0 -0
  23. {hatch_cpp-0.3.7 → hatch_cpp-0.4.1}/hatch_cpp/tests/test_project_basic/pyproject.toml +0 -0
  24. {hatch_cpp-0.3.7 → hatch_cpp-0.4.1}/hatch_cpp/tests/test_project_cmake/Makefile +0 -0
  25. {hatch_cpp-0.3.7 → hatch_cpp-0.4.1}/hatch_cpp/tests/test_project_cmake/cpp/project/basic.cpp +0 -0
  26. {hatch_cpp-0.3.7 → hatch_cpp-0.4.1}/hatch_cpp/tests/test_project_cmake/cpp/project/basic.hpp +0 -0
  27. {hatch_cpp-0.3.7 → hatch_cpp-0.4.1}/hatch_cpp/tests/test_project_cmake/project/__init__.py +0 -0
  28. {hatch_cpp-0.3.7 → hatch_cpp-0.4.1}/hatch_cpp/tests/test_project_cmake/project/include/project/basic.hpp +0 -0
  29. {hatch_cpp-0.3.7 → hatch_cpp-0.4.1}/hatch_cpp/tests/test_project_cmake/pyproject.toml +0 -0
  30. {hatch_cpp-0.3.7 → hatch_cpp-0.4.1}/hatch_cpp/tests/test_project_cmake_vcpkg/Makefile +0 -0
  31. {hatch_cpp-0.3.7 → hatch_cpp-0.4.1}/hatch_cpp/tests/test_project_cmake_vcpkg/cpp/project/basic.cpp +0 -0
  32. {hatch_cpp-0.3.7 → hatch_cpp-0.4.1}/hatch_cpp/tests/test_project_cmake_vcpkg/cpp/project/basic.hpp +0 -0
  33. {hatch_cpp-0.3.7 → hatch_cpp-0.4.1}/hatch_cpp/tests/test_project_cmake_vcpkg/project/__init__.py +0 -0
  34. {hatch_cpp-0.3.7 → hatch_cpp-0.4.1}/hatch_cpp/tests/test_project_cmake_vcpkg/project/include/project/basic.hpp +0 -0
  35. {hatch_cpp-0.3.7 → hatch_cpp-0.4.1}/hatch_cpp/tests/test_project_cmake_vcpkg/pyproject.toml +0 -0
  36. {hatch_cpp-0.3.7 → hatch_cpp-0.4.1}/hatch_cpp/tests/test_project_cmake_vcpkg/vcpkg.json +0 -0
  37. {hatch_cpp-0.3.7 → hatch_cpp-0.4.1}/hatch_cpp/tests/test_project_hatch_build/cpp/project/basic.cpp +0 -0
  38. {hatch_cpp-0.3.7 → hatch_cpp-0.4.1}/hatch_cpp/tests/test_project_hatch_build/cpp/project/basic.hpp +0 -0
  39. {hatch_cpp-0.3.7 → hatch_cpp-0.4.1}/hatch_cpp/tests/test_project_hatch_build/project/__init__.py +0 -0
  40. {hatch_cpp-0.3.7 → hatch_cpp-0.4.1}/hatch_cpp/tests/test_project_hatch_build/pyproject.toml +0 -0
  41. {hatch_cpp-0.3.7 → hatch_cpp-0.4.1}/hatch_cpp/tests/test_project_limited_api/cpp/project/basic.cpp +0 -0
  42. {hatch_cpp-0.3.7 → hatch_cpp-0.4.1}/hatch_cpp/tests/test_project_limited_api/cpp/project/basic.hpp +0 -0
  43. {hatch_cpp-0.3.7 → hatch_cpp-0.4.1}/hatch_cpp/tests/test_project_limited_api/project/__init__.py +0 -0
  44. {hatch_cpp-0.3.7 → hatch_cpp-0.4.1}/hatch_cpp/tests/test_project_limited_api/pyproject.toml +0 -0
  45. {hatch_cpp-0.3.7 → hatch_cpp-0.4.1}/hatch_cpp/tests/test_project_nanobind/cpp/project/basic.cpp +0 -0
  46. {hatch_cpp-0.3.7 → hatch_cpp-0.4.1}/hatch_cpp/tests/test_project_nanobind/cpp/project/basic.hpp +0 -0
  47. {hatch_cpp-0.3.7 → hatch_cpp-0.4.1}/hatch_cpp/tests/test_project_nanobind/project/__init__.py +0 -0
  48. {hatch_cpp-0.3.7 → hatch_cpp-0.4.1}/hatch_cpp/tests/test_project_nanobind/pyproject.toml +0 -0
  49. {hatch_cpp-0.3.7 → hatch_cpp-0.4.1}/hatch_cpp/tests/test_project_override_classes/cpp/project/basic.cpp +0 -0
  50. {hatch_cpp-0.3.7 → hatch_cpp-0.4.1}/hatch_cpp/tests/test_project_override_classes/cpp/project/basic.hpp +0 -0
  51. {hatch_cpp-0.3.7 → hatch_cpp-0.4.1}/hatch_cpp/tests/test_project_override_classes/project/__init__.py +0 -0
  52. {hatch_cpp-0.3.7 → hatch_cpp-0.4.1}/hatch_cpp/tests/test_project_override_classes/pyproject.toml +0 -0
  53. {hatch_cpp-0.3.7 → hatch_cpp-0.4.1}/hatch_cpp/tests/test_project_override_toolchain/cpp/project/basic.cpp +0 -0
  54. {hatch_cpp-0.3.7 → hatch_cpp-0.4.1}/hatch_cpp/tests/test_project_override_toolchain/cpp/project/basic.hpp +0 -0
  55. {hatch_cpp-0.3.7 → hatch_cpp-0.4.1}/hatch_cpp/tests/test_project_override_toolchain/project/__init__.py +0 -0
  56. {hatch_cpp-0.3.7 → hatch_cpp-0.4.1}/hatch_cpp/tests/test_project_override_toolchain/pyproject.toml +0 -0
  57. {hatch_cpp-0.3.7 → hatch_cpp-0.4.1}/hatch_cpp/tests/test_project_pybind/cpp/project/basic.cpp +0 -0
  58. {hatch_cpp-0.3.7 → hatch_cpp-0.4.1}/hatch_cpp/tests/test_project_pybind/cpp/project/basic.hpp +0 -0
  59. {hatch_cpp-0.3.7 → hatch_cpp-0.4.1}/hatch_cpp/tests/test_project_pybind/project/__init__.py +0 -0
  60. {hatch_cpp-0.3.7 → hatch_cpp-0.4.1}/hatch_cpp/tests/test_project_pybind/pyproject.toml +0 -0
  61. {hatch_cpp-0.3.7 → hatch_cpp-0.4.1}/hatch_cpp/tests/test_project_pybind_vcpkg/cpp/project/basic.cpp +0 -0
  62. {hatch_cpp-0.3.7 → hatch_cpp-0.4.1}/hatch_cpp/tests/test_project_pybind_vcpkg/cpp/project/basic.hpp +0 -0
  63. {hatch_cpp-0.3.7 → hatch_cpp-0.4.1}/hatch_cpp/tests/test_project_pybind_vcpkg/project/__init__.py +0 -0
  64. {hatch_cpp-0.3.7 → hatch_cpp-0.4.1}/hatch_cpp/tests/test_project_pybind_vcpkg/pyproject.toml +0 -0
  65. {hatch_cpp-0.3.7 → hatch_cpp-0.4.1}/hatch_cpp/tests/test_project_pybind_vcpkg/vcpkg.json +0 -0
  66. {hatch_cpp-0.3.7 → hatch_cpp-0.4.1}/hatch_cpp/tests/test_structs.py +0 -0
  67. {hatch_cpp-0.3.7 → hatch_cpp-0.4.1}/hatch_cpp/toolchains/__init__.py +0 -0
@@ -5,6 +5,8 @@ __pycache__/
5
5
 
6
6
  # C extensions
7
7
  *.a
8
+ *.o
9
+ *.dSYM
8
10
  *.so
9
11
  *.obj
10
12
  *.dll
@@ -13,6 +15,7 @@ __pycache__/
13
15
 
14
16
  # Rust
15
17
  target
18
+ target-capi
16
19
 
17
20
  # Distribution / packaging
18
21
  .Python
@@ -112,11 +115,12 @@ dmypy.json
112
115
  /site
113
116
  index.md
114
117
  docs/_build/
115
- docs/src/_build/
116
118
  docs/api
117
- docs/index.md
118
119
  docs/html
120
+ docs/index.md
119
121
  docs/jupyter_execute
122
+ docs/src/_build/
123
+ docs/superpowers
120
124
  index.md
121
125
 
122
126
  # JS
@@ -136,20 +140,21 @@ hatch_cpp/extension
136
140
  hatch_cpp/nbextension
137
141
  hatch_cpp/labextension
138
142
 
143
+ # Emscripten SDK (locally installed)
144
+ emsdk
145
+
139
146
  # Mac
140
147
  .DS_Store
141
148
 
142
- # Rust
143
- target
144
-
145
149
  # Hydra
146
- outputs/
147
- multirun/
150
+ /outputs/
151
+ /multirun/
148
152
 
149
153
  # AI
150
154
  ROADMAP.md
151
155
  AGENTS.md
152
156
  .github/hooks/sdlc.json
157
+ .superpowers
153
158
 
154
159
  vcpkg
155
160
  vcpkg_installed
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: hatch-cpp
3
- Version: 0.3.7
3
+ Version: 0.4.1
4
4
  Summary: Hatch plugin for C++ builds
5
5
  Project-URL: Repository, https://github.com/python-project-templates/hatch-cpp
6
6
  Project-URL: Homepage, https://github.com/python-project-templates/hatch-cpp
@@ -12,7 +12,6 @@ Classifier: Development Status :: 3 - Alpha
12
12
  Classifier: License :: OSI Approved :: Apache Software License
13
13
  Classifier: Programming Language :: Python
14
14
  Classifier: Programming Language :: Python :: 3
15
- Classifier: Programming Language :: Python :: 3.10
16
15
  Classifier: Programming Language :: Python :: 3.11
17
16
  Classifier: Programming Language :: Python :: 3.12
18
17
  Classifier: Programming Language :: Python :: 3.13
@@ -33,7 +32,7 @@ Requires-Dist: hatch-build>=0.3.2; extra == 'develop'
33
32
  Requires-Dist: hatchling; extra == 'develop'
34
33
  Requires-Dist: mdformat; extra == 'develop'
35
34
  Requires-Dist: mdformat-tables>=1; extra == 'develop'
36
- Requires-Dist: nanobind<2.13.0; extra == 'develop'
35
+ Requires-Dist: nanobind; extra == 'develop'
37
36
  Requires-Dist: pybind11; extra == 'develop'
38
37
  Requires-Dist: pytest; extra == 'develop'
39
38
  Requires-Dist: pytest-cov; extra == 'develop'
@@ -1,4 +1,4 @@
1
- __version__ = "0.3.7"
1
+ __version__ = "0.4.1"
2
2
 
3
3
  from .config import *
4
4
  from .hooks import *
@@ -2,7 +2,6 @@ from __future__ import annotations
2
2
 
3
3
  from os import environ, system as system_call
4
4
  from pathlib import Path
5
- from typing import List, Optional
6
5
 
7
6
  from pkn import getSimpleLogger
8
7
  from pydantic import BaseModel, Field, model_validator
@@ -21,13 +20,13 @@ log = getSimpleLogger("hatch_cpp")
21
20
  class HatchCppBuildConfig(BaseModel):
22
21
  """Build config values for Hatch C++ Builder."""
23
22
 
24
- verbose: Optional[bool] = Field(default=False)
25
- skip: Optional[bool] = Field(default=False)
26
- name: Optional[str] = Field(default=None)
27
- libraries: List[HatchCppLibrary] = Field(default_factory=list)
28
- cmake: Optional[HatchCppCmakeConfiguration] = Field(default=None)
29
- platform: Optional[HatchCppPlatform] = Field(default_factory=HatchCppPlatform.default)
30
- vcpkg: Optional[HatchCppVcpkgConfiguration] = Field(default_factory=HatchCppVcpkgConfiguration)
23
+ verbose: bool | None = Field(default=False)
24
+ skip: bool | None = Field(default=False)
25
+ name: str | None = Field(default=None)
26
+ libraries: list[HatchCppLibrary] = Field(default_factory=list)
27
+ cmake: HatchCppCmakeConfiguration | None = Field(default=None)
28
+ platform: HatchCppPlatform | None = Field(default_factory=HatchCppPlatform.default)
29
+ vcpkg: HatchCppVcpkgConfiguration | None = Field(default_factory=HatchCppVcpkgConfiguration)
31
30
 
32
31
  @model_validator(mode="wrap")
33
32
  @classmethod
@@ -56,9 +55,9 @@ class HatchCppBuildConfig(BaseModel):
56
55
 
57
56
  class HatchCppBuildPlan(HatchCppBuildConfig):
58
57
  build_type: BuildType = "release"
59
- commands: List[str] = Field(default_factory=list)
58
+ commands: list[str] = Field(default_factory=list)
60
59
 
61
- _active_toolchains: List[Toolchain] = []
60
+ _active_toolchains: list[Toolchain] = []
62
61
 
63
62
  def generate(self):
64
63
  self.commands = []
@@ -1,10 +1,8 @@
1
- from typing import Type
2
-
3
1
  from hatchling.plugin import hookimpl
4
2
 
5
3
  from .plugin import HatchCppBuildHook
6
4
 
7
5
 
8
6
  @hookimpl
9
- def hatch_register_build_hook() -> Type[HatchCppBuildHook]:
7
+ def hatch_register_build_hook() -> type[HatchCppBuildHook]:
10
8
  return HatchCppBuildHook
@@ -82,7 +82,7 @@ class HatchCppBuildHook(BuildHookInterface[HatchCppBuildConfig]):
82
82
  os_name = "linux"
83
83
  else:
84
84
  os_name = "win"
85
- if all([lib.py_limited_api for lib in build_plan.libraries]):
85
+ if all(lib.py_limited_api for lib in build_plan.libraries):
86
86
  build_data["tag"] = f"cp{version_major}{version_minor}-abi3-{os_name}_{machine}"
87
87
  else:
88
88
  build_data["tag"] = f"cp{version_major}{version_minor}-cp{version_major}{version_minor}-{os_name}_{machine}"
@@ -70,20 +70,12 @@ else()
70
70
  endif()
71
71
 
72
72
 
73
- find_package(Python ${CSP_PYTHON_VERSION} EXACT REQUIRED COMPONENTS Interpreter Development.Module)
74
- link_directories(${Python_LIBRARY_DIRS})
75
- include_directories(${Python_INCLUDE_DIRS})
76
-
77
- set(CMAKE_SHARED_LIBRARY_PREFIX "")
78
- if(NOT WIN32)
79
- set(CMAKE_SHARED_LIBRARY_SUFFIX .so)
80
- else()
81
- set(CMAKE_SHARED_LIBRARY_SUFFIX .pyd)
82
- endif()
73
+ find_package(Python ${HATCH_CPP_TEST_PROJECT_BASIC_PYTHON_VERSION} EXACT REQUIRED COMPONENTS Interpreter Development.Module)
83
74
 
84
75
  include_directories("${CMAKE_SOURCE_DIR}/cpp")
85
76
 
86
- add_library(extension SHARED cpp/project/basic.cpp)
77
+ python_add_library(extension MODULE WITH_SOABI cpp/project/basic.cpp)
78
+
87
79
  set_target_properties(extension PROPERTIES PUBLIC_HEADER cpp/project/basic.hpp)
88
80
  install(TARGETS extension
89
81
  PUBLIC_HEADER DESTINATION project/include/project
@@ -70,20 +70,12 @@ else()
70
70
  endif()
71
71
 
72
72
 
73
- find_package(Python ${CSP_PYTHON_VERSION} EXACT REQUIRED COMPONENTS Interpreter Development.Module)
74
- link_directories(${Python_LIBRARY_DIRS})
75
- include_directories(${Python_INCLUDE_DIRS})
76
-
77
- set(CMAKE_SHARED_LIBRARY_PREFIX "")
78
- if(NOT WIN32)
79
- set(CMAKE_SHARED_LIBRARY_SUFFIX .so)
80
- else()
81
- set(CMAKE_SHARED_LIBRARY_SUFFIX .pyd)
82
- endif()
73
+ find_package(Python ${HATCH_CPP_TEST_PROJECT_BASIC_PYTHON_VERSION} EXACT REQUIRED COMPONENTS Interpreter Development.Module)
83
74
 
84
75
  include_directories("${CMAKE_SOURCE_DIR}/cpp")
85
76
 
86
- add_library(extension SHARED cpp/project/basic.cpp)
77
+ python_add_library(extension MODULE WITH_SOABI cpp/project/basic.cpp)
78
+
87
79
  set_target_properties(extension PROPERTIES PUBLIC_HEADER cpp/project/basic.hpp)
88
80
  install(TARGETS extension
89
81
  PUBLIC_HEADER DESTINATION project/include/project
@@ -1,8 +1,9 @@
1
- from os import listdir
1
+ import contextlib
2
+ from os import listdir, remove
2
3
  from pathlib import Path
3
- from shutil import rmtree
4
4
  from subprocess import check_call
5
5
  from sys import modules, path, platform
6
+ from sysconfig import get_config_var
6
7
 
7
8
  import pytest
8
9
 
@@ -13,7 +14,6 @@ class TestProject:
13
14
  [
14
15
  "test_project_basic",
15
16
  "test_project_override_classes",
16
- "test_project_override_classes",
17
17
  "test_project_override_toolchain",
18
18
  "test_project_pybind",
19
19
  "test_project_pybind_vcpkg",
@@ -24,9 +24,17 @@ class TestProject:
24
24
  ],
25
25
  )
26
26
  def test_basic(self, project):
27
+
28
+ suffix_ext = get_config_var("EXT_SUFFIX")
29
+
27
30
  # cleanup
28
- rmtree(f"hatch_cpp/tests/{project}/project/extension.so", ignore_errors=True)
29
- rmtree(f"hatch_cpp/tests/{project}/project/extension.pyd", ignore_errors=True)
31
+ with contextlib.suppress(FileNotFoundError):
32
+ remove(f"hatch_cpp/tests/{project}/project/extension.so")
33
+ with contextlib.suppress(FileNotFoundError):
34
+ remove(f"hatch_cpp/tests/{project}/project/extension.pyd")
35
+ with contextlib.suppress(FileNotFoundError):
36
+ remove(f"hatch_cpp/tests/{project}/project/extension{suffix_ext}")
37
+
30
38
  modules.pop("project", None)
31
39
  modules.pop("project.extension", None)
32
40
 
@@ -40,14 +48,14 @@ class TestProject:
40
48
  )
41
49
 
42
50
  # assert built
43
-
51
+ project_dir_content = listdir(f"hatch_cpp/tests/{project}/project")
44
52
  if project == "test_project_limited_api" and platform != "win32":
45
- assert "extension.abi3.so" in listdir(f"hatch_cpp/tests/{project}/project")
53
+ assert "extension.abi3.so" in project_dir_content
46
54
  else:
47
55
  if platform == "win32":
48
- assert "extension.pyd" in listdir(f"hatch_cpp/tests/{project}/project")
56
+ assert "extension.pyd" in project_dir_content or f"extension{suffix_ext}" in project_dir_content
49
57
  else:
50
- assert "extension.so" in listdir(f"hatch_cpp/tests/{project}/project")
58
+ assert "extension.so" in project_dir_content or f"extension{suffix_ext}" in project_dir_content
51
59
 
52
60
  # import
53
61
  here = Path(__file__).parent / project
@@ -153,6 +153,27 @@ class TestVcpkgGenerate:
153
153
  assert not any("checkout" in cmd for cmd in commands)
154
154
  assert any("git clone" in cmd for cmd in commands)
155
155
 
156
+ def test_generate_uses_posix_command_paths(self, tmp_path, monkeypatch):
157
+ monkeypatch.chdir(tmp_path)
158
+ self._make_vcpkg_env(tmp_path)
159
+
160
+ cfg = HatchCppVcpkgConfiguration(vcpkg_triplet="x64-linux")
161
+ commands = cfg.generate(None)
162
+
163
+ assert "./vcpkg/bootstrap-vcpkg.sh" in commands
164
+ assert "./vcpkg/vcpkg install --triplet x64-linux" in commands
165
+
166
+ def test_generate_uses_windows_command_paths(self, tmp_path, monkeypatch):
167
+ monkeypatch.chdir(tmp_path)
168
+ monkeypatch.setattr("hatch_cpp.toolchains.vcpkg.sys_platform", "win32")
169
+ self._make_vcpkg_env(tmp_path)
170
+
171
+ cfg = HatchCppVcpkgConfiguration(vcpkg_triplet="x64-windows-static-md")
172
+ commands = cfg.generate(None)
173
+
174
+ assert r"vcpkg\bootstrap-vcpkg.bat" in commands
175
+ assert r"vcpkg\vcpkg.exe install --triplet x64-windows-static-md" in commands
176
+
156
177
  def test_generate_skips_clone_when_vcpkg_root_exists(self, tmp_path, monkeypatch):
157
178
  monkeypatch.chdir(tmp_path)
158
179
  self._make_vcpkg_env(tmp_path)
@@ -3,7 +3,7 @@ from __future__ import annotations
3
3
  from os import environ
4
4
  from pathlib import Path
5
5
  from sys import version_info
6
- from typing import Any, Dict, Optional, Union
6
+ from typing import Any
7
7
 
8
8
  from pydantic import BaseModel, Field
9
9
 
@@ -23,17 +23,17 @@ DefaultMSVCGenerator = {
23
23
 
24
24
 
25
25
  class HatchCppCmakeConfiguration(BaseModel):
26
- root: Optional[Path] = None
26
+ root: Path | None = None
27
27
  build: Path = Field(default_factory=lambda: Path("build"))
28
- install: Optional[Path] = Field(default=None)
28
+ install: Path | None = Field(default=None)
29
29
 
30
- cmake_arg_prefix: Optional[str] = Field(default=None)
31
- cmake_args: Dict[str, str] = Field(default_factory=dict)
32
- cmake_env_args: Dict[Platform, Dict[str, str]] = Field(default_factory=dict)
30
+ cmake_arg_prefix: str | None = Field(default=None)
31
+ cmake_args: dict[str, str] = Field(default_factory=dict)
32
+ cmake_env_args: dict[Platform, dict[str, str]] = Field(default_factory=dict)
33
33
 
34
- include_flags: Optional[Dict[str, Union[str, int, float, bool]]] = Field(default=None)
34
+ include_flags: dict[str, str | int | float | bool] | None = Field(default=None)
35
35
 
36
- def generate(self, config) -> Dict[str, Any]:
36
+ def generate(self, config) -> dict[str, Any]:
37
37
  commands = []
38
38
 
39
39
  # Derive prefix
@@ -6,20 +6,20 @@ from re import match
6
6
  from shutil import which
7
7
  from sys import base_exec_prefix, exec_prefix, executable, platform as sys_platform
8
8
  from sysconfig import get_config_var, get_path
9
- from typing import Any, List, Literal, Optional
9
+ from typing import Any, Literal
10
10
 
11
11
  from pydantic import AliasChoices, BaseModel, Field, field_validator, model_validator
12
12
 
13
13
  __all__ = (
14
+ "Binding",
14
15
  "BuildType",
15
16
  "CompilerToolchain",
16
- "Toolchain",
17
+ "HatchCppLibrary",
18
+ "HatchCppPlatform",
17
19
  "Language",
18
- "Binding",
19
20
  "Platform",
20
21
  "PlatformDefaults",
21
- "HatchCppLibrary",
22
- "HatchCppPlatform",
22
+ "Toolchain",
23
23
  "_normalize_rpath",
24
24
  )
25
25
 
@@ -41,66 +41,68 @@ class HatchCppLibrary(BaseModel, validate_assignment=True):
41
41
  """A C++ library."""
42
42
 
43
43
  name: str
44
- sources: List[str]
44
+ sources: list[str]
45
45
  language: Language = "c++"
46
46
 
47
47
  binding: Binding = "cpython"
48
- std: Optional[str] = None
48
+ std: str | None = None
49
49
 
50
- include_dirs: List[str] = Field(default_factory=list, alias=AliasChoices("include_dirs", "include-dirs"))
51
- include_dirs_linux: List[str] = Field(default_factory=list, alias=AliasChoices("include_dirs_linux", "include-dirs-linux"))
52
- include_dirs_darwin: List[str] = Field(default_factory=list, alias=AliasChoices("include_dirs_darwin", "include-dirs-darwin"))
53
- include_dirs_win32: List[str] = Field(default_factory=list, alias=AliasChoices("include_dirs_win32", "include-dirs-win32"))
50
+ include_dirs: list[str] = Field(default_factory=list, alias=AliasChoices("include_dirs", "include-dirs"))
51
+ include_dirs_linux: list[str] = Field(default_factory=list, alias=AliasChoices("include_dirs_linux", "include-dirs-linux"))
52
+ include_dirs_darwin: list[str] = Field(default_factory=list, alias=AliasChoices("include_dirs_darwin", "include-dirs-darwin"))
53
+ include_dirs_win32: list[str] = Field(default_factory=list, alias=AliasChoices("include_dirs_win32", "include-dirs-win32"))
54
54
 
55
- library_dirs: List[str] = Field(default_factory=list, alias=AliasChoices("library_dirs", "library-dirs"))
56
- library_dirs_linux: List[str] = Field(default_factory=list, alias=AliasChoices("library_dirs_linux", "library-dirs-linux"))
57
- library_dirs_darwin: List[str] = Field(default_factory=list, alias=AliasChoices("library_dirs_darwin", "library-dirs-darwin"))
58
- library_dirs_win32: List[str] = Field(default_factory=list, alias=AliasChoices("library_dirs_win32", "library-dirs-win32"))
55
+ library_dirs: list[str] = Field(default_factory=list, alias=AliasChoices("library_dirs", "library-dirs"))
56
+ library_dirs_linux: list[str] = Field(default_factory=list, alias=AliasChoices("library_dirs_linux", "library-dirs-linux"))
57
+ library_dirs_darwin: list[str] = Field(default_factory=list, alias=AliasChoices("library_dirs_darwin", "library-dirs-darwin"))
58
+ library_dirs_win32: list[str] = Field(default_factory=list, alias=AliasChoices("library_dirs_win32", "library-dirs-win32"))
59
59
 
60
- libraries: List[str] = Field(default_factory=list)
61
- libraries_linux: List[str] = Field(default_factory=list, alias=AliasChoices("libraries_linux", "libraries-linux"))
62
- libraries_darwin: List[str] = Field(default_factory=list, alias=AliasChoices("libraries_darwin", "libraries-darwin"))
63
- libraries_win32: List[str] = Field(default_factory=list, alias=AliasChoices("libraries_win32", "libraries-win32"))
60
+ libraries: list[str] = Field(default_factory=list)
61
+ libraries_linux: list[str] = Field(default_factory=list, alias=AliasChoices("libraries_linux", "libraries-linux"))
62
+ libraries_darwin: list[str] = Field(default_factory=list, alias=AliasChoices("libraries_darwin", "libraries-darwin"))
63
+ libraries_win32: list[str] = Field(default_factory=list, alias=AliasChoices("libraries_win32", "libraries-win32"))
64
64
 
65
- extra_compile_args: List[str] = Field(default_factory=list, alias=AliasChoices("extra_compile_args", "extra-compile-args"))
66
- extra_compile_args_linux: List[str] = Field(default_factory=list, alias=AliasChoices("extra_compile_args_linux", "extra-compile-args-linux"))
67
- extra_compile_args_darwin: List[str] = Field(default_factory=list, alias=AliasChoices("extra_compile_args_darwin", "extra-compile-args-darwin"))
68
- extra_compile_args_win32: List[str] = Field(default_factory=list, alias=AliasChoices("extra_compile_args_win32", "extra-compile-args-win32"))
65
+ extra_compile_args: list[str] = Field(default_factory=list, alias=AliasChoices("extra_compile_args", "extra-compile-args"))
66
+ extra_compile_args_linux: list[str] = Field(default_factory=list, alias=AliasChoices("extra_compile_args_linux", "extra-compile-args-linux"))
67
+ extra_compile_args_darwin: list[str] = Field(default_factory=list, alias=AliasChoices("extra_compile_args_darwin", "extra-compile-args-darwin"))
68
+ extra_compile_args_win32: list[str] = Field(default_factory=list, alias=AliasChoices("extra_compile_args_win32", "extra-compile-args-win32"))
69
69
 
70
- extra_link_args: List[str] = Field(default_factory=list, alias=AliasChoices("extra_link_args", "extra-link-args"))
71
- extra_link_args_linux: List[str] = Field(default_factory=list, alias=AliasChoices("extra_link_args_linux", "extra-link-args-linux"))
72
- extra_link_args_darwin: List[str] = Field(default_factory=list, alias=AliasChoices("extra_link_args_darwin", "extra-link-args-darwin"))
73
- extra_link_args_win32: List[str] = Field(default_factory=list, alias=AliasChoices("extra_link_args_win32", "extra-link-args-win32"))
70
+ extra_link_args: list[str] = Field(default_factory=list, alias=AliasChoices("extra_link_args", "extra-link-args"))
71
+ extra_link_args_linux: list[str] = Field(default_factory=list, alias=AliasChoices("extra_link_args_linux", "extra-link-args-linux"))
72
+ extra_link_args_darwin: list[str] = Field(default_factory=list, alias=AliasChoices("extra_link_args_darwin", "extra-link-args-darwin"))
73
+ extra_link_args_win32: list[str] = Field(default_factory=list, alias=AliasChoices("extra_link_args_win32", "extra-link-args-win32"))
74
74
 
75
- extra_objects: List[str] = Field(default_factory=list, alias=AliasChoices("extra_objects", "extra-objects"))
76
- extra_objects_linux: List[str] = Field(default_factory=list, alias=AliasChoices("extra_objects_linux", "extra-objects-linux"))
77
- extra_objects_darwin: List[str] = Field(default_factory=list, alias=AliasChoices("extra_objects_darwin", "extra-objects-darwin"))
78
- extra_objects_win32: List[str] = Field(default_factory=list, alias=AliasChoices("extra_objects_win32", "extra-objects-win32"))
75
+ extra_objects: list[str] = Field(default_factory=list, alias=AliasChoices("extra_objects", "extra-objects"))
76
+ extra_objects_linux: list[str] = Field(default_factory=list, alias=AliasChoices("extra_objects_linux", "extra-objects-linux"))
77
+ extra_objects_darwin: list[str] = Field(default_factory=list, alias=AliasChoices("extra_objects_darwin", "extra-objects-darwin"))
78
+ extra_objects_win32: list[str] = Field(default_factory=list, alias=AliasChoices("extra_objects_win32", "extra-objects-win32"))
79
79
 
80
- define_macros: List[str] = Field(default_factory=list, alias=AliasChoices("define_macros", "define-macros"))
81
- define_macros_linux: List[str] = Field(default_factory=list, alias=AliasChoices("define_macros_linux", "define-macros-linux"))
82
- define_macros_darwin: List[str] = Field(default_factory=list, alias=AliasChoices("define_macros_darwin", "define-macros-darwin"))
83
- define_macros_win32: List[str] = Field(default_factory=list, alias=AliasChoices("define_macros_win32", "define-macros-win32"))
80
+ define_macros: list[str] = Field(default_factory=list, alias=AliasChoices("define_macros", "define-macros"))
81
+ define_macros_linux: list[str] = Field(default_factory=list, alias=AliasChoices("define_macros_linux", "define-macros-linux"))
82
+ define_macros_darwin: list[str] = Field(default_factory=list, alias=AliasChoices("define_macros_darwin", "define-macros-darwin"))
83
+ define_macros_win32: list[str] = Field(default_factory=list, alias=AliasChoices("define_macros_win32", "define-macros-win32"))
84
84
 
85
- undef_macros: List[str] = Field(default_factory=list, alias=AliasChoices("undef_macros", "undef-macros"))
86
- undef_macros_linux: List[str] = Field(default_factory=list, alias=AliasChoices("undef_macros_linux", "undef-macros-linux"))
87
- undef_macros_darwin: List[str] = Field(default_factory=list, alias=AliasChoices("undef_macros_darwin", "undef-macros-darwin"))
88
- undef_macros_win32: List[str] = Field(default_factory=list, alias=AliasChoices("undef_macros_win32", "undef-macros-win32"))
85
+ undef_macros: list[str] = Field(default_factory=list, alias=AliasChoices("undef_macros", "undef-macros"))
86
+ undef_macros_linux: list[str] = Field(default_factory=list, alias=AliasChoices("undef_macros_linux", "undef-macros-linux"))
87
+ undef_macros_darwin: list[str] = Field(default_factory=list, alias=AliasChoices("undef_macros_darwin", "undef-macros-darwin"))
88
+ undef_macros_win32: list[str] = Field(default_factory=list, alias=AliasChoices("undef_macros_win32", "undef-macros-win32"))
89
89
 
90
- export_symbols: List[str] = Field(default_factory=list, alias=AliasChoices("export_symbols", "export-symbols"))
91
- depends: List[str] = Field(default_factory=list)
90
+ export_symbols: list[str] = Field(default_factory=list, alias=AliasChoices("export_symbols", "export-symbols"))
91
+ depends: list[str] = Field(default_factory=list)
92
92
 
93
- py_limited_api: Optional[str] = Field(default="", alias=AliasChoices("py_limited_api", "py-limited-api"))
93
+ py_limited_api: str | None = Field(default="", alias=AliasChoices("py_limited_api", "py-limited-api"))
94
94
 
95
95
  @field_validator("py_limited_api", mode="before")
96
96
  @classmethod
97
97
  def check_py_limited_api(cls, value: Any) -> Any:
98
- if value:
99
- if not match(r"cp3\d", value):
100
- raise ValueError("py-limited-api must be in the form of cp3X")
98
+ if value and not match(r"cp3\d", value):
99
+ raise ValueError("py-limited-api must be in the form of cp3X")
101
100
  return value
102
101
 
103
102
  def get_qualified_name(self, platform):
103
+ if self.binding == "cpython" and not self.py_limited_api:
104
+ suffix = get_config_var("EXT_SUFFIX")
105
+ return f"{self.name}{suffix}"
104
106
  if platform == "win32":
105
107
  suffix = "dll" if self.binding == "generic" else "pyd"
106
108
  elif platform == "darwin":
@@ -119,7 +121,7 @@ class HatchCppLibrary(BaseModel, validate_assignment=True):
119
121
  raise ValueError("Generic binding can not support Py_LIMITED_API")
120
122
  return self
121
123
 
122
- def get_effective_link_args(self, platform: Platform) -> List[str]:
124
+ def get_effective_link_args(self, platform: Platform) -> list[str]:
123
125
  """Get link args merged with platform-specific link args."""
124
126
  args = list(self.extra_link_args)
125
127
  if platform == "linux":
@@ -130,7 +132,7 @@ class HatchCppLibrary(BaseModel, validate_assignment=True):
130
132
  args.extend(self.extra_link_args_win32)
131
133
  return args
132
134
 
133
- def get_effective_include_dirs(self, platform: Platform) -> List[str]:
135
+ def get_effective_include_dirs(self, platform: Platform) -> list[str]:
134
136
  """Get include dirs merged with platform-specific include dirs."""
135
137
  dirs = list(self.include_dirs)
136
138
  if platform == "linux":
@@ -141,7 +143,7 @@ class HatchCppLibrary(BaseModel, validate_assignment=True):
141
143
  dirs.extend(self.include_dirs_win32)
142
144
  return dirs
143
145
 
144
- def get_effective_library_dirs(self, platform: Platform) -> List[str]:
146
+ def get_effective_library_dirs(self, platform: Platform) -> list[str]:
145
147
  """Get library dirs merged with platform-specific library dirs."""
146
148
  dirs = list(self.library_dirs)
147
149
  if platform == "linux":
@@ -152,7 +154,7 @@ class HatchCppLibrary(BaseModel, validate_assignment=True):
152
154
  dirs.extend(self.library_dirs_win32)
153
155
  return dirs
154
156
 
155
- def get_effective_libraries(self, platform: Platform) -> List[str]:
157
+ def get_effective_libraries(self, platform: Platform) -> list[str]:
156
158
  """Get libraries merged with platform-specific libraries."""
157
159
  libs = list(self.libraries)
158
160
  if platform == "linux":
@@ -163,7 +165,7 @@ class HatchCppLibrary(BaseModel, validate_assignment=True):
163
165
  libs.extend(self.libraries_win32)
164
166
  return libs
165
167
 
166
- def get_effective_compile_args(self, platform: Platform) -> List[str]:
168
+ def get_effective_compile_args(self, platform: Platform) -> list[str]:
167
169
  """Get compile args merged with platform-specific compile args."""
168
170
  args = list(self.extra_compile_args)
169
171
  if platform == "linux":
@@ -174,7 +176,7 @@ class HatchCppLibrary(BaseModel, validate_assignment=True):
174
176
  args.extend(self.extra_compile_args_win32)
175
177
  return args
176
178
 
177
- def get_effective_extra_objects(self, platform: Platform) -> List[str]:
179
+ def get_effective_extra_objects(self, platform: Platform) -> list[str]:
178
180
  """Get extra objects merged with platform-specific extra objects."""
179
181
  objs = list(self.extra_objects)
180
182
  if platform == "linux":
@@ -185,7 +187,7 @@ class HatchCppLibrary(BaseModel, validate_assignment=True):
185
187
  objs.extend(self.extra_objects_win32)
186
188
  return objs
187
189
 
188
- def get_effective_define_macros(self, platform: Platform) -> List[str]:
190
+ def get_effective_define_macros(self, platform: Platform) -> list[str]:
189
191
  """Get define macros merged with platform-specific define macros."""
190
192
  macros = list(self.define_macros)
191
193
  if platform == "linux":
@@ -196,7 +198,7 @@ class HatchCppLibrary(BaseModel, validate_assignment=True):
196
198
  macros.extend(self.define_macros_win32)
197
199
  return macros
198
200
 
199
- def get_effective_undef_macros(self, platform: Platform) -> List[str]:
201
+ def get_effective_undef_macros(self, platform: Platform) -> list[str]:
200
202
  """Get undef macros merged with platform-specific undef macros."""
201
203
  macros = list(self.undef_macros)
202
204
  if platform == "linux":
@@ -271,12 +273,11 @@ class HatchCppPlatform(BaseModel):
271
273
  @classmethod
272
274
  def validate_model(cls, data, handler):
273
275
  model = handler(data)
274
- if which("ccache") and not model.disable_ccache:
275
- if model.toolchain in ["gcc", "clang"]:
276
- if not model.cc.startswith("ccache "):
277
- model.cc = f"ccache {model.cc}"
278
- if not model.cxx.startswith("ccache "):
279
- model.cxx = f"ccache {model.cxx}"
276
+ if which("ccache") and not model.disable_ccache and model.toolchain in ["gcc", "clang"]:
277
+ if not model.cc.startswith("ccache "):
278
+ model.cc = f"ccache {model.cc}"
279
+ if not model.cxx.startswith("ccache "):
280
+ model.cxx = f"ccache {model.cxx}"
280
281
  return model
281
282
 
282
283
  @staticmethod
@@ -313,7 +314,7 @@ class HatchCppPlatform(BaseModel):
313
314
  if not library.std:
314
315
  library.std = "c++17"
315
316
  library.sources.append(str(Path(nanobind.include_dir()).parent / "src" / "nb_combined.cpp"))
316
- effective_include_dirs.append(str((Path(nanobind.include_dir()).parent / "ext" / "robin_map" / "include")))
317
+ effective_include_dirs.append(str(Path(nanobind.include_dir()).parent / "ext" / "robin_map" / "include"))
317
318
 
318
319
  if library.py_limited_api:
319
320
  if library.binding == "pybind11":
@@ -364,20 +365,7 @@ class HatchCppPlatform(BaseModel):
364
365
  # Normalize rpath values ($ORIGIN <-> @loader_path) and escape for shell
365
366
  effective_link_args = [_normalize_rpath(arg, self.platform) for arg in effective_link_args]
366
367
 
367
- if self.toolchain == "gcc":
368
- flags += " -shared"
369
- flags += " " + " ".join(effective_link_args)
370
- flags += " " + " ".join(effective_extra_objects)
371
- flags += " " + " ".join(f"-l{lib}" for lib in effective_libraries)
372
- flags += " " + " ".join(f"-L{lib}" for lib in effective_library_dirs)
373
- flags += f" -o {library.get_qualified_name(self.platform)}"
374
- if self.platform == "darwin":
375
- flags += " -undefined dynamic_lookup"
376
- if "mold" in self.ld:
377
- flags += f" -fuse-ld={self.ld}"
378
- elif "lld" in self.ld:
379
- flags += " -fuse-ld=lld"
380
- elif self.toolchain == "clang":
368
+ if self.toolchain == "gcc" or self.toolchain == "clang":
381
369
  flags += " -shared"
382
370
  flags += " " + " ".join(effective_link_args)
383
371
  flags += " " + " ".join(effective_extra_objects)
@@ -408,7 +396,7 @@ class HatchCppPlatform(BaseModel):
408
396
  ]
409
397
  for libs_path in python_libs_paths:
410
398
  if libs_path.exists():
411
- flags += f" /LIBPATH:{str(libs_path)}"
399
+ flags += f" /LIBPATH:{libs_path!s}"
412
400
  break
413
401
  flags += " " + " ".join(f"{lib}.lib" for lib in effective_libraries)
414
402
  flags += " " + " ".join(f"/LIBPATH:{lib}" for lib in effective_library_dirs)
@@ -5,7 +5,7 @@ import subprocess
5
5
  from pathlib import Path
6
6
  from platform import machine as platform_machine
7
7
  from sys import platform as sys_platform
8
- from typing import Literal, Optional
8
+ from typing import Literal
9
9
 
10
10
  from pydantic import BaseModel, Field
11
11
 
@@ -40,7 +40,7 @@ VcpkgPlatformDefaults = {
40
40
  }
41
41
 
42
42
 
43
- def _read_vcpkg_ref_from_gitmodules(vcpkg_root: Path) -> Optional[str]:
43
+ def _read_vcpkg_ref_from_gitmodules(vcpkg_root: Path) -> str | None:
44
44
  """Read the branch/ref for vcpkg from .gitmodules if it exists.
45
45
 
46
46
  Looks for a submodule whose path matches ``vcpkg_root`` and returns
@@ -61,11 +61,11 @@ def _read_vcpkg_ref_from_gitmodules(vcpkg_root: Path) -> Optional[str]:
61
61
 
62
62
 
63
63
  class HatchCppVcpkgConfiguration(BaseModel):
64
- vcpkg: Optional[str] = Field(default="vcpkg.json")
65
- vcpkg_root: Optional[Path] = Field(default=Path("vcpkg"))
66
- vcpkg_repo: Optional[str] = Field(default="https://github.com/microsoft/vcpkg.git")
67
- vcpkg_triplet: Optional[VcpkgTriplet] = Field(default=None)
68
- vcpkg_ref: Optional[str] = Field(
64
+ vcpkg: str | None = Field(default="vcpkg.json")
65
+ vcpkg_root: Path | None = Field(default=Path("vcpkg"))
66
+ vcpkg_repo: str | None = Field(default="https://github.com/microsoft/vcpkg.git")
67
+ vcpkg_triplet: VcpkgTriplet | None = Field(default=None)
68
+ vcpkg_ref: str | None = Field(
69
69
  default=None,
70
70
  description="Branch, tag, or commit SHA to checkout after cloning vcpkg. "
71
71
  "If not set, falls back to the branch specified in .gitmodules for the vcpkg submodule.",
@@ -73,7 +73,7 @@ class HatchCppVcpkgConfiguration(BaseModel):
73
73
 
74
74
  # TODO: overlay
75
75
 
76
- def _resolve_vcpkg_ref(self) -> Optional[str]:
76
+ def _resolve_vcpkg_ref(self) -> str | None:
77
77
  """Return the ref to checkout: explicit config takes priority, then .gitmodules."""
78
78
  if self.vcpkg_ref is not None:
79
79
  return self.vcpkg_ref
@@ -87,6 +87,11 @@ class HatchCppVcpkgConfiguration(BaseModel):
87
87
  return self.vcpkg_root / "vcpkg.exe"
88
88
  return self.vcpkg_root / "vcpkg"
89
89
 
90
+ def _command_path(self, path: Path) -> str:
91
+ if sys_platform == "win32":
92
+ return str(path).replace("/", "\\")
93
+ return f"./{path}"
94
+
90
95
  def _delete_dir_command(self, path: Path) -> str:
91
96
  if sys_platform == "win32":
92
97
  return f'rmdir /s /q "{path}"'
@@ -109,7 +114,7 @@ class HatchCppVcpkgConfiguration(BaseModel):
109
114
  if ref is not None:
110
115
  commands.append(f"git -C {self.vcpkg_root} checkout {ref}")
111
116
 
112
- commands.append(f"./{self._bootstrap_script_path()}")
117
+ commands.append(self._command_path(self._bootstrap_script_path()))
113
118
  return commands
114
119
 
115
120
  def generate(self, config):
@@ -134,11 +139,11 @@ class HatchCppVcpkgConfiguration(BaseModel):
134
139
  else:
135
140
  vcpkg_executable = self._vcpkg_executable_path()
136
141
  if not vcpkg_executable.exists():
137
- commands.append(f"./{bootstrap_script}")
142
+ commands.append(self._command_path(bootstrap_script))
138
143
  elif not self._is_vcpkg_working():
139
144
  commands.append(self._delete_dir_command(vcpkg_root))
140
145
  commands.extend(self._clone_checkout_bootstrap_commands())
141
146
 
142
- commands.append(f"./{self.vcpkg_root / 'vcpkg'} install --triplet {self.vcpkg_triplet}")
147
+ commands.append(f"{self._command_path(self._vcpkg_executable_path())} install --triplet {self.vcpkg_triplet}")
143
148
 
144
149
  return commands
@@ -1,12 +1,12 @@
1
1
  from __future__ import annotations
2
2
 
3
- from functools import lru_cache
3
+ from functools import cache
4
4
 
5
5
  from pydantic import ImportString, TypeAdapter
6
6
 
7
7
  _import_string_adapter = TypeAdapter(ImportString)
8
8
 
9
9
 
10
- @lru_cache(maxsize=None)
10
+ @cache
11
11
  def import_string(input_string: str):
12
12
  return _import_string_adapter.validate_python(input_string)
@@ -12,7 +12,7 @@ authors = [
12
12
  description = "Hatch plugin for C++ builds"
13
13
  readme = "README.md"
14
14
  license = { text = "Apache-2.0" }
15
- version = "0.3.7"
15
+ version = "0.4.1"
16
16
  requires-python = ">=3.10"
17
17
  keywords = [
18
18
  "hatch",
@@ -30,7 +30,6 @@ classifiers = [
30
30
  "Programming Language :: Python :: Implementation :: CPython",
31
31
  "Programming Language :: Python :: Implementation :: PyPy",
32
32
  "Programming Language :: Python :: 3",
33
- "Programming Language :: Python :: 3.10",
34
33
  "Programming Language :: Python :: 3.11",
35
34
  "Programming Language :: Python :: 3.12",
36
35
  "Programming Language :: Python :: 3.13",
@@ -62,7 +61,7 @@ develop = [
62
61
  "uv",
63
62
  "wheel",
64
63
  # test
65
- "nanobind<2.13.0", # https://github.com/wjakob/nanobind/commit/abd27e3b5565bc95f5091321f0f863fce8b5b95b
64
+ "nanobind",
66
65
  "pybind11",
67
66
  "pytest",
68
67
  "pytest-cov",
@@ -80,7 +79,7 @@ Repository = "https://github.com/python-project-templates/hatch-cpp"
80
79
  Homepage = "https://github.com/python-project-templates/hatch-cpp"
81
80
 
82
81
  [tool.bumpversion]
83
- current_version = "0.3.7"
82
+ current_version = "0.4.1"
84
83
  commit = true
85
84
  tag = true
86
85
  commit_args = "-s"
@@ -100,6 +99,8 @@ branch = false
100
99
  omit = [
101
100
  "hatch_cpp/tests/integration/",
102
101
  ]
102
+ patch = ["subprocess"]
103
+
103
104
 
104
105
  [tool.coverage.report]
105
106
  exclude_also = [
@@ -132,6 +133,7 @@ addopts = [
132
133
  "--junitxml=junit.xml",
133
134
  ]
134
135
  testpaths = "hatch_cpp/tests"
136
+ norecursedirs = "vcpkg"
135
137
 
136
138
  [tool.ruff]
137
139
  line-length = 150
File without changes
File without changes