Skip to content

Commit 22a19a3

Browse files
authored
Merge pull request #150 from imandra-ai/hy/fix-python-binding-typing
Fix Python binding typing errors
2 parents bb3b9c6 + 1306090 commit 22a19a3

10 files changed

Lines changed: 326 additions & 258 deletions

File tree

.github/workflows/main.yml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,3 +43,10 @@ jobs:
4343
- name: cargo build
4444
run: cargo build
4545
working-directory: src/rust/lib
46+
pyright:
47+
name: pyright
48+
runs-on: [ubuntu-latest]
49+
steps:
50+
- uses: actions/checkout@main
51+
- uses: astral-sh/setup-uv@v5
52+
- run: cd src/py && uv run pyright -p pyproject.toml lib

src/lib/genbindings/gen_python.ml

Lines changed: 23 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -13,18 +13,19 @@ type tydef = TR.Ty_def.t
1313
let prelude =
1414
{|
1515
# automatically generated using genbindings.ml, do not edit
16+
# pyright: reportPrivateUsage=false, reportUnusedVariable=false
1617

1718
from __future__ import annotations # delaying typing: https://peps.python.org/pep-0563/
1819
from dataclasses import dataclass
1920
from zipfile import ZipFile
2021
import json
21-
from typing import Any, assert_never, Callable, Never
22+
from typing import Any, assert_never, Callable, Never # pyright: ignore[reportUnusedImport]
2223
from . import twine
2324

2425
__all__ = ['twine']
2526

2627
type Error = Error_Error_core
27-
def twine_result[T,E](d: twine.Decoder, off: int, d0: Callable[...,T], d1: Callable[...,E]) -> T | E:
28+
def twine_result[T,E](d: twine.Decoder, off: int, d0: twine.DecoderFn[T], d1: twine.DecoderFn[E]) -> T | E:
2829
match d.get_cstor(off=off):
2930
case twine.Constructor(idx=0, args=args):
3031
args = tuple(args)
@@ -38,7 +39,7 @@ def twine_result[T,E](d: twine.Decoder, off: int, d0: Callable[...,T], d1: Calla
3839
type WithTag6[T] = T
3940
type WithTag7[T] = T
4041

41-
def decode_with_tag[T](tag: int, d: twine.Decoder, off: int, d0: Callable[...,T]) -> WithTag7[T]:
42+
def decode_with_tag[T](tag: int, d: twine.Decoder, off: int, d0: twine.DecoderFn[T]) -> WithTag7[T]:
4243
dec_tag = d.get_tag(off=off)
4344
if dec_tag.tag != tag:
4445
raise twine.Error(f'Expected tag {tag}, got tag {dec_tag.tag} at off=0x{off:x}')
@@ -49,6 +50,13 @@ def decode_q(d: twine.Decoder, off:int) -> tuple[int,int]:
4950
num = d.get_int(off=num)
5051
denum = d.get_int(off=denum)
5152
return num, denum
53+
54+
def Void_of_twine(d: twine.Decoder, off: int) -> Never:
55+
raise twine.Error(f'Cannot decode Void at off=0x{off:x}')
56+
57+
type Eval__Value_Custom_value = Any
58+
def Eval__Value_Custom_value_of_twine(d: twine.Decoder, off: int) -> Eval__Value_Custom_value:
59+
raise twine.Error(f'Cannot decode Eval__Value_Custom_value at off=0x{off:x}')
5260
|}
5361

5462
let footer =
@@ -212,7 +220,7 @@ let rec gen_type_expr (ty : tyexpr) : string =
212220
gen_type_expr ty
213221
| Cstor (s, args) ->
214222
(match s, args with
215-
| ("int" | "Util_twine.Z.t" | "Z.t" | "_Z.t"), [] -> "int"
223+
| ("int" | "int64" | "Util_twine.Z.t" | "Z.t" | "_Z.t"), [] -> "int"
216224
| "string", [] -> "str"
217225
| "bool", [] -> "bool"
218226
| "array", [ x ] | "list", [ x ] -> spf "list[%s]" (gen_type_expr x)
@@ -252,7 +260,7 @@ let rec of_twine_of_type_expr (ty : tyexpr) ~off : string =
252260
| Attrs (ty, _) -> of_twine_of_type_expr ty ~off
253261
| Cstor (s, args) ->
254262
(match s, args with
255-
| ("int" | "Util_twine.Z.t" | "Z.t" | "_Z.t"), [] ->
263+
| ("int" | "int64" | "Util_twine.Z.t" | "Z.t" | "_Z.t"), [] ->
256264
spf "d.get_int(off=%s)" off
257265
| "string", [] -> spf "d.get_str(off=%s)" off
258266
| "bool", [] -> spf "d.get_bool(off=%s)" off
@@ -312,13 +320,13 @@ let special_defs =
312320
( "Imandrax_api.Uid_set.t",
313321
{|type Uid_set = set[Uid]
314322

315-
def Uid_set_of_twine(d, off:int) -> Uid_set:
323+
def Uid_set_of_twine(d: twine.Decoder, off:int) -> Uid_set:
316324
return set(Uid_of_twine(d,off=x) for x in d.get_array(off=off))|}
317325
);
318326
( "Imandrax_api.Chash.t",
319327
{|type Chash = bytes
320328

321-
def Chash_of_twine(d, off:int) -> Chash:
329+
def Chash_of_twine(d: twine.Decoder, off:int) -> Chash:
322330
return d.get_bytes(off=off)|}
323331
);
324332
]
@@ -344,7 +352,7 @@ let gen_clique ~oc (tys : Ty_set.t) : unit =
344352
spf "%s,"
345353
(String.concat ","
346354
@@ List.mapi
347-
(fun i v -> spf "d%d: Callable[...,_V%s]" i v)
355+
(fun i v -> spf "d%d: twine.DecoderFn[_V%s]" i v)
348356
def.params)
349357
and params_decls =
350358
List.mapi (fun i v -> spf "decode_%s = d%d" v i) def.params
@@ -367,10 +375,10 @@ let gen_clique ~oc (tys : Ty_set.t) : unit =
367375
match def.decl with
368376
| Alias ty ->
369377
bpf buf "type %s%s = %s\n\n" pyname pyparams (gen_type_expr ty);
370-
bpf buf "%sdef %s(d: twine.Decoder, %soff: int) -> %s:\n"
378+
bpf buf "%sdef %s%s(d: twine.Decoder, %soff: int) -> %s%s:\n"
371379
cached_decorator
372380
(of_twine_of_ty_name def.name)
373-
pytwine_params pyname;
381+
pyparams pytwine_params pyname pyparams;
374382
List.iter (fun s -> bpf buf " %s\n" s) params_decls;
375383
bpf buf " return %s\n" (of_twine_of_type_expr ty ~off:"off")
376384
| Record r ->
@@ -382,8 +390,8 @@ let gen_clique ~oc (tys : Ty_set.t) : unit =
382390
r.fields;
383391
bpf buf "\n";
384392

385-
bpf buf "%sdef %s_of_twine%s(d: twine.Decoder, %soff: int) -> %s:\n"
386-
cached_decorator pyname pyparams pytwine_params pyname;
393+
bpf buf "%sdef %s_of_twine%s(d: twine.Decoder, %soff: int) -> %s%s:\n"
394+
cached_decorator pyname pyparams pytwine_params pyname pyparams;
387395
if def.unboxed then (
388396
let field_name, field_ty =
389397
match r.fields with
@@ -483,8 +491,8 @@ let gen_clique ~oc (tys : Ty_set.t) : unit =
483491
cstors;
484492
bpf buf "\n\n";
485493

486-
bpf buf "%sdef %s_of_twine%s(d: twine.Decoder, %soff: int) -> %s:\n"
487-
cached_decorator pyname pyparams pytwine_params pyname;
494+
bpf buf "%sdef %s_of_twine%s(d: twine.Decoder, %soff: int) -> %s%s:\n"
495+
cached_decorator pyname pyparams pytwine_params pyname pyparams;
488496
bpf buf " match d.get_cstor(off=off):\n";
489497
List.iteri
490498
(fun i (c : TR.Ty_def.cstor) ->
@@ -528,7 +536,7 @@ let gen_artifacts (artifacts : Artifact.t list) : string =
528536
@@ String.concat "|"
529537
@@ List.map (fun (a : Artifact.t) -> gen_type_expr a.ty) artifacts;
530538

531-
bpf buf "artifact_decoders = {\\\n";
539+
bpf buf "artifact_decoders: dict[str, twine.DecoderFn[Artifact]] = {\\\n";
532540
List.iter
533541
(fun (a : Artifact.t) ->
534542
bpf buf " '%s': (lambda d, off: %s),\n" a.tag

src/py/Makefile

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,11 @@ pre-release-test: build # Run pre-release tests with built wheel
2424
uv run --isolated --no-project --with "$$WHEEL" python ../../tests/api/py/test_cloud_dev.py && \
2525
uv run --isolated --no-project --with "$$WHEEL" python ../../tests/api/py/test_extract_region_str.py
2626

27+
test-setup-py-install:
28+
@echo "Testing setup.py install (with pyproject.toml removed) in Docker (Python 3.12)..."
29+
docker run --rm -v "$(CURDIR):/src:ro" python:3.12-slim \
30+
sh -c 'cp -r /src /tmp/pkg && cd /tmp/pkg && rm pyproject.toml && pip install --no-cache-dir . && python -c "from imandrax_api.lib import twine; print(\"setup.py install: OK\")"'
31+
2732
PYTHON_REPO_URL = https://europe-west1-python.pkg.dev/imandra-dev/imandrax-api/
2833

2934
install-artifact-deps:
@@ -53,4 +58,4 @@ install-go-protobuf-plugin:
5358
@echo "installing twirp plugin for protoc into `echo $(GOBIN)`"
5459
cd protoc-gen-twirpy && GOBIN="`echo $(GOBIN)`" go install ./
5560

56-
.PHONY: remove-wheels build genversion api_types_version.py
61+
.PHONY: remove-wheels build genversion api_types_version.py test-setup-py-install

src/py/__init__.py

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@ def __del__(self):
125125
# Silently ignore errors during cleanup to avoid spurious error messages
126126
pass
127127

128-
def status(self) -> utils_pb2.StatusRes:
128+
def status(self) -> utils_pb2.StringMsg:
129129
return self._client.status(
130130
ctx=self.mk_context(),
131131
request=utils_pb2.Empty(),
@@ -212,9 +212,7 @@ def qcheck_src(
212212
timeout = timeout or self._timeout
213213
return self._client.qcheck_src(
214214
ctx=self.mk_context(),
215-
request=simple_api_pb2.QCheckSrcReq(
216-
src=src, session=self._sesh, seed=seed
217-
),
215+
request=simple_api_pb2.QCheckSrcReq(src=src, session=self._sesh, seed=seed),
218216
timeout=timeout,
219217
)
220218

@@ -360,7 +358,7 @@ async def __aexit__(self, exc_type: Any, exc_val: Any, exc_tb: Any) -> None:
360358
except TwirpServerException as e:
361359
raise Exception("Error while ending session") from e
362360

363-
async def status(self) -> utils_pb2.StatusRes:
361+
async def status(self) -> utils_pb2.StringMsg:
364362
return await self._client.status(
365363
ctx=self.mk_context(),
366364
request=utils_pb2.Empty(),
@@ -447,7 +445,7 @@ async def qcheck_src(
447445
timeout = timeout or self._timeout
448446
return await self._client.qcheck_src(
449447
ctx=self.mk_context(),
450-
request=simple_api_pb2.QcheckSrcReq(
448+
request=simple_api_pb2.QCheckSrcReq(
451449
src=src, session=self._sesh, seed=seed
452450
),
453451
timeout=timeout,
@@ -463,7 +461,7 @@ async def qcheck_name(
463461
timeout = timeout or self._timeout
464462
return await self._client.qcheck_name(
465463
ctx=self.mk_context(),
466-
request=simple_api_pb2.QcheckNameReq(
464+
request=simple_api_pb2.QCheckNameReq(
467465
name=name, session=self._sesh, seed=seed
468466
),
469467
timeout=timeout,

0 commit comments

Comments
 (0)