hatch-cpp 0.0.0__tar.gz → 0.1.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.
@@ -0,0 +1,169 @@
1
+ # Byte-compiled / optimized / DLL files
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+
6
+ # C extensions
7
+ *.a
8
+ *.so
9
+ *.obj
10
+ *.dll
11
+ *.exp
12
+ *.lib
13
+
14
+ # Distribution / packaging
15
+ .Python
16
+ env/
17
+ build/
18
+ develop-eggs/
19
+ dist/
20
+ downloads/
21
+ eggs/
22
+ .eggs/
23
+ lib/
24
+ lib64/
25
+ parts/
26
+ sdist/
27
+ var/
28
+ *.egg-info/
29
+ .installed.cfg
30
+ *.egg
31
+
32
+ # PyInstaller
33
+ # Usually these files are written by a python script from a template
34
+ # before PyInstaller builds the exe, so as to inject date/other infos into it.
35
+ *.manifest
36
+ *.spec
37
+
38
+ # Installer logs
39
+ pip-log.txt
40
+ pip-delete-this-directory.txt
41
+
42
+ # Unit test / coverage reports
43
+ htmlcov/
44
+ .tox/
45
+ .coverage
46
+ .coverage.*
47
+ .cache
48
+ python_junit.xml
49
+ junit.xml
50
+ nosetests.xml
51
+ coverage.xml
52
+ *,cover
53
+ .hypothesis/
54
+ .pytest_cache
55
+ .ruff_cache
56
+ js/playwright-report
57
+
58
+ # Translations
59
+ *.mo
60
+ *.pot
61
+
62
+ # Django stuff:
63
+ *.log
64
+ local_settings.py
65
+
66
+ # Flask instance folder
67
+ instance/
68
+
69
+ # Scrapy stuff:
70
+ .scrapy
71
+
72
+ # Sphinx documentation
73
+ docs/_build/
74
+ docs/source
75
+
76
+ # PyBuilder
77
+ target/
78
+
79
+ # IPython Notebook
80
+ .ipynb_checkpoints
81
+ *.ipynb
82
+ .autoversion
83
+
84
+ # pyenv
85
+ .python-version
86
+
87
+ # celery beat schedule file
88
+ celerybeat-schedule
89
+
90
+ # dotenv
91
+ .env
92
+
93
+ # virtualenv
94
+ venv/
95
+ ENV/
96
+
97
+ # Spyder project settings
98
+ .spyderproject
99
+
100
+ # Rope project settings
101
+ .ropeproject
102
+
103
+ # =========================
104
+ # Operating System Files
105
+ # =========================
106
+
107
+ # OSX
108
+ # =========================
109
+
110
+ .DS_Store
111
+ .AppleDouble
112
+ .LSOverride
113
+
114
+ # Thumbnails
115
+ ._*
116
+
117
+ # Files that might appear in the root of a volume
118
+ .DocumentRevisions-V100
119
+ .fseventsd
120
+ .Spotlight-V100
121
+ .TemporaryItems
122
+ .Trashes
123
+ .VolumeIcon.icns
124
+
125
+ # Directories potentially created on remote AFP share
126
+ .AppleDB
127
+ .AppleDesktop
128
+ Network Trash Folder
129
+ Temporary Items
130
+ .apdisk
131
+
132
+ # Windows
133
+ # =========================
134
+
135
+ # Windows image file caches
136
+ Thumbs.db
137
+ ehthumbs.db
138
+
139
+ # Folder config file
140
+ Desktop.ini
141
+
142
+ # Recycle Bin used on file shares
143
+ $RECYCLE.BIN/
144
+
145
+ # Windows Installer files
146
+ *.cab
147
+ *.msi
148
+ *.msm
149
+ *.msp
150
+
151
+ # Windows shortcuts
152
+ *.lnk
153
+
154
+
155
+ # NPM
156
+ # ----
157
+ **/node_modules/
158
+
159
+ # Coverage data
160
+ # -------------
161
+ **/coverage/
162
+
163
+ # Notebook and lab extensions
164
+
165
+ nbprint/extension/*
166
+ nbprint/templates/nbprint/static/*
167
+ nbprint/voila/static/*
168
+ tmp.html
169
+ examples/output/
@@ -186,7 +186,7 @@
186
186
  same "printed page" as the copyright notice for easier
187
187
  identification within third-party archives.
188
188
 
189
- Copyright 2024, the hatch-cpp authors
189
+ Copyright [yyyy] [name of copyright owner]
190
190
 
191
191
  Licensed under the Apache License, Version 2.0 (the "License");
192
192
  you may not use this file except in compliance with the License.
@@ -0,0 +1,46 @@
1
+ Metadata-Version: 2.4
2
+ Name: hatch-cpp
3
+ Version: 0.1.1
4
+ Summary: Hatch plugin for C++ builds
5
+ Project-URL: Repository, https://github.com/python-project-templates/hatch-cpp
6
+ Project-URL: Homepage, https://github.com/python-project-templates/hatch-cpp
7
+ Author-email: the hatch-cpp authors <t.paine154@gmail.com>
8
+ License: Apache-2.0
9
+ License-File: LICENSE
10
+ Keywords: build,c++,cmake,cpp,hatch,python
11
+ Classifier: Development Status :: 3 - Alpha
12
+ Classifier: License :: OSI Approved :: Apache Software License
13
+ Classifier: Programming Language :: Python
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Programming Language :: Python :: 3.9
16
+ Classifier: Programming Language :: Python :: 3.10
17
+ Classifier: Programming Language :: Python :: 3.11
18
+ Classifier: Programming Language :: Python :: 3.12
19
+ Classifier: Programming Language :: Python :: Implementation :: CPython
20
+ Classifier: Programming Language :: Python :: Implementation :: PyPy
21
+ Requires-Python: >=3.9
22
+ Requires-Dist: hatchling>=1.20
23
+ Provides-Extra: develop
24
+ Requires-Dist: build; extra == 'develop'
25
+ Requires-Dist: bump-my-version; extra == 'develop'
26
+ Requires-Dist: check-manifest; extra == 'develop'
27
+ Requires-Dist: pytest; extra == 'develop'
28
+ Requires-Dist: pytest-cov; extra == 'develop'
29
+ Requires-Dist: ruff<0.9,>=0.3; extra == 'develop'
30
+ Requires-Dist: twine; extra == 'develop'
31
+ Requires-Dist: wheel; extra == 'develop'
32
+ Description-Content-Type: text/markdown
33
+
34
+ # hatch-cpp
35
+
36
+ Hatch plugin for C++ builds
37
+
38
+ [![Build Status](https://github.com/python-project-templates/hatch-cpp/actions/workflows/build.yml/badge.svg?branch=main&event=push)](https://github.com/python-project-templates/hatch-cpp/actions/workflows/build.yml)
39
+ [![codecov](https://codecov.io/gh/python-project-templates/hatch-cpp/branch/main/graph/badge.svg)](https://codecov.io/gh/python-project-templates/hatch-cpp)
40
+ [![License](https://img.shields.io/github/license/python-project-templates/hatch-cpp)](https://github.com/python-project-templates/hatch-cpp)
41
+ [![PyPI](https://img.shields.io/pypi/v/hatch-cpp.svg)](https://pypi.python.org/pypi/hatch-cpp)
42
+
43
+ ## Overview
44
+
45
+ > [!NOTE]
46
+ > This library was generated using [copier](https://copier.readthedocs.io/en/stable/) from the [Base Python Project Template repository](https://github.com/python-project-templates/base).
@@ -0,0 +1,13 @@
1
+ # hatch-cpp
2
+
3
+ Hatch plugin for C++ builds
4
+
5
+ [![Build Status](https://github.com/python-project-templates/hatch-cpp/actions/workflows/build.yml/badge.svg?branch=main&event=push)](https://github.com/python-project-templates/hatch-cpp/actions/workflows/build.yml)
6
+ [![codecov](https://codecov.io/gh/python-project-templates/hatch-cpp/branch/main/graph/badge.svg)](https://codecov.io/gh/python-project-templates/hatch-cpp)
7
+ [![License](https://img.shields.io/github/license/python-project-templates/hatch-cpp)](https://github.com/python-project-templates/hatch-cpp)
8
+ [![PyPI](https://img.shields.io/pypi/v/hatch-cpp.svg)](https://pypi.python.org/pypi/hatch-cpp)
9
+
10
+ ## Overview
11
+
12
+ > [!NOTE]
13
+ > This library was generated using [copier](https://copier.readthedocs.io/en/stable/) from the [Base Python Project Template repository](https://github.com/python-project-templates/base).
@@ -0,0 +1 @@
1
+ __version__ = "0.1.1"
@@ -0,0 +1,4 @@
1
+ from .cli import main
2
+
3
+ if __name__ == "__main__":
4
+ main()
@@ -0,0 +1,10 @@
1
+ from typing import Type
2
+
3
+ from hatchling.plugin import hookimpl
4
+
5
+ from .plugin import HatchCppBuildHook
6
+
7
+
8
+ @hookimpl
9
+ def hatch_register_build_hook() -> Type[HatchCppBuildHook]:
10
+ return HatchCppBuildHook
@@ -0,0 +1,89 @@
1
+ from __future__ import annotations
2
+
3
+ import logging
4
+ import os
5
+ import typing as t
6
+ from dataclasses import fields
7
+
8
+ from hatchling.builders.hooks.plugin.interface import BuildHookInterface
9
+
10
+ from .structs import HatchCppBuildConfig, HatchCppBuildPlan, HatchCppLibrary, HatchCppPlatform
11
+
12
+ __all__ = ("HatchCppBuildHook",)
13
+
14
+
15
+ class HatchCppBuildHook(BuildHookInterface[HatchCppBuildConfig]):
16
+ """The hatch-cpp build hook."""
17
+
18
+ PLUGIN_NAME = "hatch-cpp"
19
+ _logger = logging.getLogger(__name__)
20
+
21
+ def initialize(self, version: str, _: dict[str, t.Any]) -> None:
22
+ """Initialize the plugin."""
23
+ self._logger.info("Running hatch-cpp")
24
+
25
+ if self.target_name != "wheel":
26
+ self._logger.info("ignoring target name %s", self.target_name)
27
+ return
28
+
29
+ if os.getenv("SKIP_HATCH_CPP"):
30
+ self._logger.info("Skipping the build hook since SKIP_HATCH_CPP was set")
31
+ return
32
+
33
+ kwargs = {k.replace("-", "_"): v if not isinstance(v, bool) else str(v) for k, v in self.config.items()}
34
+ available_fields = [f.name for f in fields(HatchCppBuildConfig)]
35
+ for key in list(kwargs):
36
+ if key not in available_fields:
37
+ del kwargs[key]
38
+ config = HatchCppBuildConfig(**kwargs)
39
+
40
+ library_kwargs = [
41
+ {k.replace("-", "_"): v if not isinstance(v, bool) else str(v) for k, v in library_kwargs.items()} for library_kwargs in config.libraries
42
+ ]
43
+ libraries = [HatchCppLibrary(**library_kwargs) for library_kwargs in library_kwargs]
44
+ platform = HatchCppPlatform.default()
45
+ if config.toolchain == "raw":
46
+ build_plan = HatchCppBuildPlan(libraries=libraries, platform=platform)
47
+ build_plan.generate()
48
+ if config.verbose:
49
+ for command in build_plan.commands:
50
+ self._logger.info(command)
51
+ build_plan.execute()
52
+ build_plan.cleanup()
53
+
54
+ # build_kwargs = config.build_kwargs
55
+ # if version == "editable":
56
+ # build_kwargs = config.editable_build_kwargs or build_kwargs
57
+
58
+ # should_skip_build = False
59
+ # if not config.build_function:
60
+ # log.warning("No build function found")
61
+ # should_skip_build = True
62
+
63
+ # elif config.skip_if_exists and version == "standard":
64
+ # should_skip_build = should_skip(config.skip_if_exists)
65
+ # if should_skip_build:
66
+ # log.info("Skip-if-exists file(s) found")
67
+
68
+ # # Get build function and call it with normalized parameter names.
69
+ # if not should_skip_build and config.build_function:
70
+ # build_func = get_build_func(config.build_function)
71
+ # build_kwargs = normalize_kwargs(build_kwargs)
72
+ # log.info("Building with %s", config.build_function)
73
+ # log.info("With kwargs: %s", build_kwargs)
74
+ # try:
75
+ # build_func(self.target_name, version, **build_kwargs)
76
+ # except Exception as e:
77
+ # if version == "editable" and config.optional_editable_build.lower() == "true":
78
+ # warnings.warn(f"Encountered build error:\n{e}", stacklevel=2)
79
+ # else:
80
+ # raise e
81
+ # else:
82
+ # log.info("Skipping build")
83
+
84
+ # # Ensure targets in distributable dists.
85
+ # if version == "standard":
86
+ # ensure_targets(config.ensured_targets)
87
+
88
+ self._logger.info("Finished running hatch-cpp")
89
+ return
@@ -0,0 +1,159 @@
1
+ from __future__ import annotations
2
+
3
+ from dataclasses import dataclass, field
4
+ from os import environ, system
5
+ from pathlib import Path
6
+ from sys import executable, platform as sys_platform
7
+ from sysconfig import get_path
8
+ from typing import Literal
9
+
10
+ from hatchling.builders.config import BuilderConfig
11
+
12
+ __all__ = (
13
+ "HatchCppBuildConfig",
14
+ "HatchCppLibrary",
15
+ "HatchCppPlatform",
16
+ "HatchCppBuildPlan",
17
+ )
18
+
19
+ Platform = Literal["linux", "darwin", "win32"]
20
+ CompilerToolchain = Literal["gcc", "clang", "msvc"]
21
+ PlatformDefaults = {
22
+ "linux": {"CC": "gcc", "CXX": "g++"},
23
+ "darwin": {"CC": "clang", "CXX": "clang++"},
24
+ "win32": {"CC": "cl", "CXX": "cl"},
25
+ }
26
+
27
+
28
+ @dataclass
29
+ class HatchCppBuildConfig(BuilderConfig):
30
+ """Build config values for Hatch C++ Builder."""
31
+
32
+ toolchain: str | None = field(default="raw")
33
+ libraries: list[dict[str, str]] = field(default_factory=list)
34
+ verbose: bool | None = field(default=False)
35
+ # build_function: str | None = None
36
+ # build_kwargs: t.Mapping[str, str] = field(default_factory=dict)
37
+ # editable_build_kwargs: t.Mapping[str, str] = field(default_factory=dict)
38
+ # ensured_targets: list[str] = field(default_factory=list)
39
+ # skip_if_exists: list[str] = field(default_factory=list)
40
+
41
+
42
+ @dataclass
43
+ class HatchCppLibrary(object):
44
+ """A C++ library."""
45
+
46
+ name: str
47
+ sources: list[str]
48
+
49
+ include_dirs: list[str] = field(default_factory=list)
50
+ library_dirs: list[str] = field(default_factory=list)
51
+ libraries: list[str] = field(default_factory=list)
52
+ extra_compile_args: list[str] = field(default_factory=list)
53
+ extra_link_args: list[str] = field(default_factory=list)
54
+ extra_objects: list[str] = field(default_factory=list)
55
+ define_macros: list[str] = field(default_factory=list)
56
+ undef_macros: list[str] = field(default_factory=list)
57
+
58
+ export_symbols: list[str] = field(default_factory=list)
59
+ depends: list[str] = field(default_factory=list)
60
+
61
+
62
+ @dataclass
63
+ class HatchCppPlatform(object):
64
+ cc: str
65
+ cxx: str
66
+ platform: Platform
67
+ toolchain: CompilerToolchain
68
+
69
+ @staticmethod
70
+ def default() -> HatchCppPlatform:
71
+ platform = environ.get("HATCH_CPP_PLATFORM", sys_platform)
72
+ CC = environ.get("CC", PlatformDefaults[platform]["CC"])
73
+ CXX = environ.get("CXX", PlatformDefaults[platform]["CXX"])
74
+ if "gcc" in CC and "g++" in CXX:
75
+ toolchain = "gcc"
76
+ elif "clang" in CC and "clang++" in CXX:
77
+ toolchain = "clang"
78
+ elif "cl" in CC and "cl" in CXX:
79
+ toolchain = "msvc"
80
+ else:
81
+ raise Exception(f"Unrecognized toolchain: {CC}, {CXX}")
82
+ return HatchCppPlatform(cc=CC, cxx=CXX, platform=platform, toolchain=toolchain)
83
+
84
+ def get_compile_flags(self, library: HatchCppLibrary) -> str:
85
+ flags = ""
86
+ if self.toolchain == "gcc":
87
+ flags = f"-I{get_path('include')}"
88
+ flags += " " + " ".join(f"-I{d}" for d in library.include_dirs)
89
+ flags += " -fPIC -shared"
90
+ flags += " " + " ".join(library.extra_compile_args)
91
+ flags += " " + " ".join(library.extra_link_args)
92
+ flags += " " + " ".join(library.extra_objects)
93
+ flags += " " + " ".join(f"-l{lib}" for lib in library.libraries)
94
+ flags += " " + " ".join(f"-L{lib}" for lib in library.library_dirs)
95
+ flags += " " + " ".join(f"-D{macro}" for macro in library.define_macros)
96
+ flags += " " + " ".join(f"-U{macro}" for macro in library.undef_macros)
97
+ flags += f" -o {library.name}.so"
98
+ elif self.toolchain == "clang":
99
+ flags = f"-I{get_path('include')} "
100
+ flags += " ".join(f"-I{d}" for d in library.include_dirs)
101
+ flags += " -undefined dynamic_lookup -fPIC -shared"
102
+ flags += " " + " ".join(library.extra_compile_args)
103
+ flags += " " + " ".join(library.extra_link_args)
104
+ flags += " " + " ".join(library.extra_objects)
105
+ flags += " " + " ".join(f"-l{lib}" for lib in library.libraries)
106
+ flags += " " + " ".join(f"-L{lib}" for lib in library.library_dirs)
107
+ flags += " " + " ".join(f"-D{macro}" for macro in library.define_macros)
108
+ flags += " " + " ".join(f"-U{macro}" for macro in library.undef_macros)
109
+ flags += f" -o {library.name}.so"
110
+ elif self.toolchain == "msvc":
111
+ flags = f"/I{get_path('include')} "
112
+ flags += " ".join(f"/I{d}" for d in library.include_dirs)
113
+ flags += " " + " ".join(library.extra_compile_args)
114
+ flags += " " + " ".join(library.extra_link_args)
115
+ flags += " " + " ".join(library.extra_objects)
116
+ flags += " " + " ".join(f"/D{macro}" for macro in library.define_macros)
117
+ flags += " " + " ".join(f"/U{macro}" for macro in library.undef_macros)
118
+ flags += " /EHsc /DWIN32 /LD"
119
+ flags += f" /Fo:{library.name}.obj"
120
+ flags += f" /Fe:{library.name}.pyd"
121
+ flags += " /link /DLL"
122
+ if (Path(executable).parent / "libs").exists():
123
+ flags += f" /LIBPATH:{str(Path(executable).parent / 'libs')}"
124
+ flags += " " + " ".join(f"{lib}.lib" for lib in library.libraries)
125
+ flags += " " + " ".join(f"/LIBPATH:{lib}" for lib in library.library_dirs)
126
+ # clean
127
+ while flags.count(" "):
128
+ flags = flags.replace(" ", " ")
129
+ return flags
130
+
131
+ def get_link_flags(self, library: HatchCppLibrary) -> str:
132
+ flags = ""
133
+ return flags
134
+
135
+
136
+ @dataclass
137
+ class HatchCppBuildPlan(object):
138
+ libraries: list[HatchCppLibrary] = field(default_factory=list)
139
+ platform: HatchCppPlatform = field(default_factory=HatchCppPlatform.default)
140
+ commands: list[str] = field(default_factory=list)
141
+
142
+ def generate(self):
143
+ self.commands = []
144
+ for library in self.libraries:
145
+ flags = self.platform.get_compile_flags(library)
146
+ self.commands.append(f"{self.platform.cc} {' '.join(library.sources)} {flags}")
147
+ return self.commands
148
+
149
+ def execute(self):
150
+ for command in self.commands:
151
+ system(command)
152
+ return self.commands
153
+
154
+ def cleanup(self):
155
+ if self.platform.platform == "win32":
156
+ for library in self.libraries:
157
+ temp_obj = Path(f"{library.name}.obj")
158
+ if temp_obj.exists():
159
+ temp_obj.unlink()
@@ -0,0 +1,2 @@
1
+ def test_import():
2
+ pass
@@ -0,0 +1,5 @@
1
+ #include "basic-project/basic.hpp"
2
+
3
+ PyObject* hello(PyObject*, PyObject*) {
4
+ return PyUnicode_FromString("A string");
5
+ }
@@ -0,0 +1,17 @@
1
+ #pragma once
2
+ #include "Python.h"
3
+
4
+ PyObject* hello(PyObject*, PyObject*);
5
+
6
+ static PyMethodDef extension_methods[] = {
7
+ {"hello", (PyCFunction)hello, METH_NOARGS},
8
+ {nullptr, nullptr, 0, nullptr}
9
+ };
10
+
11
+ static PyModuleDef extension_module = {
12
+ PyModuleDef_HEAD_INIT, "extension", "extension", -1, extension_methods};
13
+
14
+ PyMODINIT_FUNC PyInit_extension(void) {
15
+ Py_Initialize();
16
+ return PyModule_Create(&extension_module);
17
+ }
@@ -0,0 +1,63 @@
1
+ [build-system]
2
+ requires = ["hatchling>=1.20"]
3
+ build-backend = "hatchling.build"
4
+
5
+ [project]
6
+ name = "hatch-cpp-test-project-basic"
7
+ description = "Basic test project for hatch-cpp"
8
+ version = "0.1.0"
9
+ requires-python = ">=3.9"
10
+ dependencies = [
11
+ "hatchling>=1.20",
12
+ "hatch-cpp",
13
+ ]
14
+
15
+ [tool.hatch.build]
16
+ artifacts = [
17
+ "basic_project/*.dll",
18
+ "basic_project/*.dylib",
19
+ "basic_project/*.so",
20
+ ]
21
+
22
+ [tool.hatch.build.sources]
23
+ src = "/"
24
+
25
+ [tool.hatch.build.targets.sdist]
26
+ packages = ["basic_project"]
27
+
28
+ [tool.hatch.build.targets.wheel]
29
+ packages = ["basic_project"]
30
+
31
+ [tool.hatch.build.hooks.hatch-cpp]
32
+ verbose = true
33
+ libraries = [
34
+ {name = "basic_project/extension", sources = ["cpp/basic-project/basic.cpp"], include-dirs = ["cpp"]}
35
+ ]
36
+
37
+ # build-function = "hatch_cpp.cpp_builder"
38
+
39
+ # [tool.hatch.build.hooks.defaults]
40
+ # build-type = "release"
41
+
42
+ # [tool.hatch.build.hooks.env-vars]
43
+ # TODO: these will all be available via
44
+ # CLI after https://github.com/pypa/hatch/pull/1743
45
+ # e.g. --hatch-cpp-build-type=debug
46
+ # build-type = "BUILD_TYPE"
47
+ # ccache = "USE_CCACHE"
48
+ # manylinux = "MANYLINUX"
49
+ # vcpkg = "USE_VCPKG"
50
+
51
+ # [tool.hatch.build.hooks.cmake]
52
+
53
+ # [tool.hatch.build.hooks.vcpkg]
54
+ # triplets = {linux="x64-linux", macos="x64-osx", windows="x64-windows-static-md"}
55
+ # clone = true
56
+ # update = true
57
+
58
+ # [tool.hatch.build.hooks.hatch-cpp.build-kwargs]
59
+ # path = "cpp"
60
+
61
+ [tool.pytest.ini_options]
62
+ asyncio_mode = "strict"
63
+ testpaths = "basic_project/tests"
@@ -0,0 +1,28 @@
1
+ from os import listdir
2
+ from pathlib import Path
3
+ from shutil import rmtree
4
+ from subprocess import check_output
5
+ from sys import path, platform
6
+
7
+
8
+ class TestProject:
9
+ def test_basic(self):
10
+ rmtree("hatch_cpp/tests/test_project_basic/basic_project/extension.so", ignore_errors=True)
11
+ rmtree("hatch_cpp/tests/test_project_basic/basic_project/extension.pyd", ignore_errors=True)
12
+ check_output(
13
+ [
14
+ "hatchling",
15
+ "build",
16
+ "--hooks-only",
17
+ ],
18
+ cwd="hatch_cpp/tests/test_project_basic",
19
+ )
20
+ if platform == "win32":
21
+ assert "extension.pyd" in listdir("hatch_cpp/tests/test_project_basic/basic_project")
22
+ else:
23
+ assert "extension.so" in listdir("hatch_cpp/tests/test_project_basic/basic_project")
24
+ here = Path(__file__).parent / "test_project_basic"
25
+ path.insert(0, str(here))
26
+ import basic_project.extension
27
+
28
+ assert basic_project.extension.hello() == "A string"
File without changes
File without changes