Skip to content

Commit

Permalink
python bindings: make type annotations for CString and CBuffer less m…
Browse files Browse the repository at this point in the history
…agical

In order to avoid having magical types that only exist during
type-checking, define CString and CBytes in the main _pathrs module and
import them into the _libpathrs_cffi type stubs.

Unfortunately, the straight-forward way of doing this (using a TypeAlias
of _libpathrs_cffi.ffi.CData) doesn't work for some reason so we need to
do a little bit of magic when TYPE_CHECKING to make mypy happy. But at
least this is a little bit less magical than the previous version (where
some variables only existed when type-checking).

Signed-off-by: Aleksa Sarai <cyphar@cyphar.com>
  • Loading branch information
cyphar committed Oct 8, 2024
1 parent ad81670 commit 8e27c04
Show file tree
Hide file tree
Showing 2 changed files with 18 additions and 8 deletions.
3 changes: 1 addition & 2 deletions contrib/bindings/python/pathrs/_libpathrs_cffi/lib.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,7 @@ from typing import Optional, overload, type_check_only, Union
# TODO: Remove this once we only support Python >= 3.10.
from typing_extensions import TypeAlias, Literal

CBuffer: TypeAlias = cffi.FFI.CData # char[n]
CString: TypeAlias = cffi.FFI.CData # char *
from .._pathrs import CBuffer, CString

# pathrs_errorinfo_t *
@type_check_only
Expand Down
23 changes: 17 additions & 6 deletions contrib/bindings/python/pathrs/_pathrs.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,22 @@
import typing
from typing import Any, IO, Optional, TextIO, Union
# TODO: Remove this once we only support Python >= 3.11.
from typing_extensions import Self
from typing_extensions import Self, TypeAlias

from ._libpathrs_cffi import ffi, lib as libpathrs_so
if typing.TYPE_CHECKING:
from ._libpathrs_cffi.lib import CBuffer, CString # type stubs
# mypy apparently cannot handle the "ffi: cffi.api.FFI" definition in
# _libpathrs_cffi/__init__.pyi so we need to explicitly reference the type
# from cffi here.
import cffi
ffi: cffi.FFI
CString: TypeAlias = cffi.FFI.CData
CBuffer: TypeAlias = cffi.FFI.CData
else:
from ._libpathrs_cffi import ffi
CString: TypeAlias = ffi.CData
CBuffer: TypeAlias = ffi.CData

from ._libpathrs_cffi import lib as libpathrs_so

__all__ = [
# core api
Expand All @@ -42,15 +53,15 @@
"Error",
]

def _cstr(pystr: str) -> "CString":
def _cstr(pystr: str) -> CString:
return ffi.new("char[]", pystr.encode("utf8"))

def _pystr(cstr: "CString") -> str:
def _pystr(cstr: CString) -> str:
s = ffi.string(cstr)
assert isinstance(s, bytes) # typing
return s.decode("utf8")

def _cbuffer(size: int) -> "CBuffer":
def _cbuffer(size: int) -> CBuffer:
return ffi.new("char[%d]" % (size,))


Expand Down

0 comments on commit 8e27c04

Please sign in to comment.