Skip to content

Commit 4a95f3e

Browse files
committed
Fix pyi and some other things too
1 parent 7327ca6 commit 4a95f3e

File tree

14 files changed

+158
-87
lines changed

14 files changed

+158
-87
lines changed

pyproject.toml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,6 @@ dependencies = [
3131
"typing-extensions",
3232
"validobj",
3333
"pyyaml >= 5.1",
34-
"patch == 1.*",
3534
"pybind11-stubgen ~= 2.5.1",
3635
"delocate; platform_system == 'Darwin'",
3736
"distro; platform_system == 'Linux'",

src/semiwrap/autowrap/cxxparser.py

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -90,16 +90,20 @@
9090

9191

9292
class HasSubpackage(Protocol):
93-
subpackage: typing.Optional[str]
93+
@property
94+
def subpackage(self) -> typing.Optional[str]: ...
9495

9596

9697
class HasDoc(Protocol):
97-
doc: str
98-
doc_append: str
98+
@property
99+
def doc(self) -> typing.Optional[str]: ...
100+
@property
101+
def doc_append(self) -> typing.Optional[str]: ...
99102

100103

101104
class HasNameData(Protocol):
102-
rename: str
105+
@property
106+
def rename(self) -> typing.Optional[str]: ...
103107

104108

105109
# TODO: this isn't the best solution
@@ -1998,7 +2002,7 @@ def parse_header(
19982002
extra_includes_first=user_cfg.extra_includes_first,
19992003
extra_includes=user_cfg.extra_includes,
20002004
inline_code=user_cfg.inline_code,
2001-
rel_fname=str(header_path.relative_to(header_root)),
2005+
rel_fname=header_path.relative_to(header_root, walk_up=True).as_posix(),
20022006
)
20032007

20042008
# Parse the header using a custom visitor

src/semiwrap/autowrap/generator_data.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,12 @@
1212

1313
from cxxheaderparser.types import Function
1414

15+
from validobj.validation import parse_input
16+
1517
import dataclasses
18+
import enum
1619
import pathlib
17-
from typing import Dict, List, Optional, Tuple
20+
from typing import Any, Dict, List, Optional, Tuple
1821

1922

2023
@dataclasses.dataclass

src/semiwrap/cmd_gen_pkgconf.py

Lines changed: 12 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
import inspect
77
import pathlib
88

9-
from .pkgconf_cache import INITPY_VARNAME
9+
from .mkpc import make_pc_file
1010
from .pyproject import PyProject
1111

1212

@@ -26,39 +26,17 @@ def main():
2626
depends = project.get_extension_deps(module)
2727

2828
pc_install_path = project.package_root / pathlib.Path(*package_name.split("."))
29-
30-
pc_content = [
31-
"# automatically generated by semiwrap",
32-
"prefix=${pcfiledir}",
33-
]
34-
35-
if args.libinit_py:
36-
pc_content.append(f"{INITPY_VARNAME}={args.libinit_py}")
37-
38-
cflags = ["-I${prefix}"]
39-
40-
for i, inc in enumerate(module.includes):
41-
includedir = project.root / pathlib.PurePosixPath(inc)
42-
rel = includedir.relative_to(pc_install_path.parent)
43-
pc_content.append(f"inc{i}=${{prefix}}/{rel.as_posix()}")
44-
cflags.append(f"-I${{inc{i}}}")
45-
46-
pc_content += [
47-
"",
48-
f"Name: {package_name}",
49-
f"Description: semiwrap pybind11 module",
50-
"Version:", # TODO put in correct version
51-
"Cflags: " + " ".join(cflags),
52-
]
53-
54-
if depends:
55-
requires = " ".join(depends)
56-
pc_content.append(f"Requires: {requires}")
57-
58-
pc_content.append("")
59-
60-
with open(args.pcfile, "w") as fp:
61-
fp.write("\n".join(pc_content))
29+
make_pc_file(
30+
project_root=project.root,
31+
pcfile=args.pcfile,
32+
pc_install_path=pc_install_path,
33+
name=args.name,
34+
desc="semiwrap pybind11 module",
35+
version="",
36+
includes=module.includes,
37+
depends=depends,
38+
libinit_py=args.libinit_py,
39+
)
6240

6341

6442
if __name__ == "__main__":

src/semiwrap/cmd_header2dat.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -89,8 +89,8 @@ def generate_wrapper(
8989

9090
gendata.report_missing(src_yml, missing_reporter)
9191

92-
if not report_only and missing_reporter:
93-
print("WARNING: some items not in generation yaml for", src_h)
92+
if not report_only and missing_reporter and not data.defaults.ignore:
93+
print("WARNING: some items not in", src_yml, "for", src_h)
9494
for name, contents in missing_reporter.as_yaml():
9595
print(contents)
9696

src/semiwrap/cmd_make_pyi.py

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@ def _write_pyi(package_name, generated_pyi: T.Dict[pathlib.PurePath, pathlib.Pat
4040
# to a temporary directory and then we copy the files from there to
4141
# our desired location
4242
with tempfile.TemporaryDirectory() as tmpdir:
43+
tmpdir_pth = pathlib.Path(tmpdir)
44+
4345
# Call pybind11-stubgen
4446
sys.argv = [
4547
"<dummy>",
@@ -51,11 +53,19 @@ def _write_pyi(package_name, generated_pyi: T.Dict[pathlib.PurePath, pathlib.Pat
5153
package_name,
5254
]
5355

56+
os.system(f"find {tmpdir_pth}")
57+
58+
# Create the parent directories in the temporary directory
59+
for infile in generated_pyi.keys():
60+
(tmpdir_pth / infile).parent.mkdir(parents=True, exist_ok=True)
61+
5462
pybind11_stubgen.main()
5563

64+
print("=" * 80, file=sys.stderr)
65+
os.system(f"find {tmpdir_pth}")
66+
5667
# stubgen doesn't take a direct output filename, so move the file
5768
# to our desired location
58-
tmpdir_pth = pathlib.Path(tmpdir)
5969
for infile, output in generated_pyi.items():
6070
output.unlink(missing_ok=True)
6171
shutil.move(tmpdir_pth / infile, output)
@@ -103,6 +113,12 @@ def main():
103113
)
104114
pkg = ppkg
105115

116+
import pprint
117+
118+
pprint.pprint(package_map, sys.stderr)
119+
pprint.pprint(generated_pyi, sys.stderr)
120+
print("*" * 80, file=sys.stderr)
121+
106122
sys.meta_path.insert(0, _PackageFinder)
107123

108124
_write_pyi(package_name, generated_pyi)

src/semiwrap/cmd_publish_casters.py

Lines changed: 36 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import sys
1010

1111
from .casters import TypeCasterJsonData, TypeCasterJsonHeader, save_typecaster_json_data
12+
from .mkpc import make_pc_file
1213
from .pyproject import PyProject
1314

1415

@@ -22,40 +23,31 @@ def main():
2223
project = PyProject(pathlib.Path(pyproject_toml))
2324
cfg = project.project.export_type_casters[caster_name]
2425

25-
# determine the include directory location relative to the pc directory
26-
# .. needs to be the pc install directory, not the output file
27-
includedir = project.root / pathlib.Path(cfg.includedir)
28-
if not includedir.exists():
29-
print(f"ERROR: {includedir} does not exist", file=sys.stderr)
30-
print(
31-
f"- specified at [tool.semiwrap.export_type_casters.{caster_name}].includedir",
32-
file=sys.stderr,
33-
)
34-
sys.exit(1)
26+
# make sure the include directories actually exist
27+
include_dirs = []
28+
for inc in cfg.includedir:
29+
includedir = project.root / pathlib.Path(inc)
30+
include_dirs.append(includedir)
31+
if not includedir.exists():
32+
print(f"ERROR: {includedir} does not exist", file=sys.stderr)
33+
print(
34+
f"- specified at [tool.semiwrap.export_type_casters.{caster_name}].includedir",
35+
file=sys.stderr,
36+
)
37+
sys.exit(1)
3538

3639
pc_install_path = project.package_root / pathlib.Path(*cfg.pypackage.split("."))
37-
rel_includedir = includedir.relative_to(pc_install_path)
38-
39-
# Write the pc file
40-
pc_content = [
41-
"# automatically generated by semiwrap",
42-
"prefix=${pcfiledir}",
43-
f"includedir=${{prefix}}/{rel_includedir.as_posix()}",
44-
"",
45-
f"Name: {caster_name}",
46-
"Description: pybind11 type casters",
47-
"Version:", # TODO put in correct version
48-
"Cflags: -I${includedir}",
49-
]
50-
51-
if cfg.requires:
52-
requires = " ".join(cfg.requires)
53-
pc_content.append(f"Requires: {requires}")
54-
55-
pc_content.append("")
56-
57-
with open(output_pc, "w") as fp:
58-
fp.write("\n".join(pc_content))
40+
make_pc_file(
41+
project_root=project.root,
42+
pcfile=pathlib.Path(output_pc),
43+
pc_install_path=pc_install_path,
44+
name=caster_name,
45+
desc="pybind11 type casters",
46+
version="",
47+
includes=cfg.includedir,
48+
depends=cfg.requires,
49+
libinit_py=None,
50+
)
5951

6052
#
6153
# Gather the data and write it next to the pc file
@@ -65,13 +57,22 @@ def main():
6557
for hdr in cfg.headers:
6658

6759
# Ensure the published header actually exists
68-
full_hdr = includedir / hdr.header
69-
if not full_hdr.exists():
70-
print(f"ERROR: {full_hdr} does not exist", file=sys.stderr)
60+
searched = []
61+
for inc in include_dirs:
62+
full_hdr = inc / hdr.header
63+
if full_hdr.exists():
64+
break
65+
66+
searched.append(full_hdr)
67+
else:
68+
69+
print(f"ERROR: {hdr.header} does not exist", file=sys.stderr)
7170
print(
7271
f"- specified at [[tool.semiwrap.export_type_casters.{caster_name}.headers]].header",
7372
file=sys.stderr,
7473
)
74+
for s in searched:
75+
print(f"- searched '{s}'")
7576
sys.exit(1)
7677

7778
data.headers.append(

src/semiwrap/config/pyproject_toml.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ class TypeCasterConfig:
3838
3939
[tool.semiwrap.export_type_casters.NAME]
4040
pypackage = "mypkg"
41+
includedirs = ["src/mypkg/type-casters"]
4142
4243
[[tool.semiwrap.export_type_casters.NAME.headers]]
4344
header = "my_type_caster.h"
@@ -50,7 +51,7 @@ class TypeCasterConfig:
5051
pypackage: str
5152

5253
#: Location of type caster header files, relative to the root of the project
53-
includedir: str
54+
includedir: List[str]
5455

5556
#: pkgconf 'requires'
5657
requires: List[str] = dataclasses.field(default_factory=list)

src/semiwrap/makeplan.py

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import pathlib
77
import pprint
88
import sys
9+
import sysconfig
910
import typing as T
1011

1112
from .casters import PKGCONF_CASTER_EXT
@@ -192,7 +193,7 @@ def _process_export_type_caster(self, name: str, caster_cfg: TypeCasterConfig):
192193

193194
dep = self.pkgcache.add_local(
194195
name=name,
195-
includes=[self.project_root / caster_cfg.includedir],
196+
includes=[self.project_root / inc for inc in caster_cfg.includedir],
196197
requires=caster_cfg.requires,
197198
)
198199
caster_dep = LocalDependency(
@@ -218,7 +219,7 @@ def _process_extension_module(
218219

219220
# Detect the location of the package in the source tree
220221
package_init_py = self.pyproject.package_root / package_path / "__init__.py"
221-
self.pyi_args += (parent_package, package_init_py.as_posix())
222+
self.pyi_args += [parent_package, package_init_py.as_posix()]
222223

223224
depends = self.pyproject.get_extension_deps(extension)
224225
depends.append("semiwrap")
@@ -260,7 +261,9 @@ def _process_extension_module(
260261
install_path=package_path,
261262
)
262263

263-
self.pyi_args += [libinit_py, libinit_tgt]
264+
libinit_module = f"{parent_package}.{libinit_py}"[:-3]
265+
self.pyi_args += [libinit_module, libinit_tgt]
266+
264267
yield libinit_tgt
265268

266269
#
@@ -454,6 +457,12 @@ def _process_headers(
454457
for inc in include_directories_uniq:
455458
header2dat_args += ["-I", inc]
456459

460+
# https://github.com/pkgconf/pkgconf/issues/391
461+
header2dat_args += ["-I", sysconfig.get_path("include")]
462+
463+
# TODO
464+
header2dat_args += ["-D", "__cplusplus 201703L"]
465+
457466
header2dat_args.append(yml)
458467
header2dat_args.append(yml_input)
459468
header2dat_args.append(h_input)
@@ -544,7 +553,7 @@ def _locate_header(self, hdr: str, search_path: T.List[pathlib.Path]):
544553
for p in search_path:
545554
h_path = p / phdr
546555
if h_path.exists():
547-
return InputFile(h_path.relative_to(self.project_root)), p
556+
return InputFile(h_path.relative_to(self.project_root, walk_up=True)), p
548557
raise FileNotFoundError(
549558
f"cannot locate {phdr} in {', '.join(map(str, search_path))}"
550559
)

src/semiwrap/mkpc.py

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
import pathlib
2+
import typing as T
3+
4+
from .pkgconf_cache import INITPY_VARNAME
5+
6+
7+
def make_pc_file(
8+
project_root: pathlib.Path,
9+
pcfile: pathlib.Path,
10+
pc_install_path: pathlib.Path,
11+
name: str,
12+
desc: str,
13+
version: str,
14+
includes: T.List[str],
15+
depends: T.List[str],
16+
libinit_py: T.Optional[str],
17+
):
18+
19+
pc_content = [
20+
"# automatically generated by semiwrap",
21+
"prefix=${pcfiledir}",
22+
]
23+
24+
if libinit_py:
25+
pc_content.append(f"{INITPY_VARNAME}={libinit_py}")
26+
27+
cflags = ["-I${prefix}"]
28+
29+
for i, inc in enumerate(includes):
30+
includedir = project_root / pathlib.PurePosixPath(inc)
31+
rel = includedir.relative_to(pc_install_path.parent)
32+
pc_content.append(f"inc{i}=${{prefix}}/{rel.as_posix()}")
33+
cflags.append(f"-I${{inc{i}}}")
34+
35+
pc_content += [
36+
"",
37+
f"Name: {name}",
38+
f"Description: {desc}",
39+
f"Version: {version}",
40+
"Cflags: " + " ".join(cflags),
41+
]
42+
43+
if depends:
44+
requires = " ".join(depends)
45+
pc_content.append(f"Requires: {requires}")
46+
47+
pc_content.append("")
48+
49+
with open(pcfile, "w") as fp:
50+
fp.write("\n".join(pc_content))

0 commit comments

Comments
 (0)