Add __try_from_py__ API

pull/335/head
A. R. Shajii 2023-02-23 13:15:08 -05:00
parent f3f3e7ee91
commit 732dfcbab3
1 changed files with 184 additions and 0 deletions

View File

@ -109,6 +109,7 @@ PyErr_SetString = Function[[cobj, cobj], NoneType](cobj())
Py_None = cobj()
Py_True = cobj()
Py_False = cobj()
Py_Ellipsis = cobj()
Py_NotImplemented = cobj()
Py_LT = 0
Py_LE = 1
@ -117,6 +118,18 @@ Py_NE = 3
Py_GT = 4
Py_GE = 5
# types
PyLong_Type = cobj()
PyFloat_Type = cobj()
PyBool_Type = cobj()
PyUnicode_Type = cobj()
PyComplex_Type = cobj()
PyList_Type = cobj()
PyDict_Type = cobj()
PySet_Type = cobj()
PyTuple_Type = cobj()
PySlice_Type = cobj()
# exceptions
PyExc_BaseException = cobj()
PyExc_Exception = cobj()
@ -269,7 +282,18 @@ def init_handles_dlopen(py_handle: cobj):
global Py_None
global Py_True
global Py_False
global Py_Ellipsis
global Py_NotImplemented
global PyLong_Type
global PyFloat_Type
global PyBool_Type
global PyUnicode_Type
global PyComplex_Type
global PyList_Type
global PyDict_Type
global PySet_Type
global PyTuple_Type
global PySlice_Type
global PyExc_BaseException
global PyExc_Exception
global PyExc_NameError
@ -384,7 +408,18 @@ def init_handles_dlopen(py_handle: cobj):
Py_None = dlsym(py_handle, "_Py_NoneStruct")
Py_True = dlsym(py_handle, "_Py_TrueStruct")
Py_False = dlsym(py_handle, "_Py_FalseStruct")
Py_Ellipsis = dlsym(py_handle, "_Py_EllipsisObject")
Py_NotImplemented = dlsym(py_handle, "_Py_NotImplementedStruct")
PyLong_Type = dlsym(py_handle, "PyLong_Type")
PyFloat_Type = dlsym(py_handle, "PyFloat_Type")
PyBool_Type = dlsym(py_handle, "PyBool_Type")
PyUnicode_Type = dlsym(py_handle, "PyUnicode_Type")
PyComplex_Type = dlsym(py_handle, "PyComplex_Type")
PyList_Type = dlsym(py_handle, "PyList_Type")
PyDict_Type = dlsym(py_handle, "PyDict_Type")
PySet_Type = dlsym(py_handle, "PySet_Type")
PyTuple_Type = dlsym(py_handle, "PyTuple_Type")
PySlice_Type = dlsym(py_handle, "PySlice_Type")
PyExc_BaseException = Ptr[cobj](dlsym(py_handle, "PyExc_BaseException"))[0]
PyExc_Exception = Ptr[cobj](dlsym(py_handle, "PyExc_Exception"))[0]
PyExc_NameError = Ptr[cobj](dlsym(py_handle, "PyExc_NameError"))[0]
@ -500,7 +535,18 @@ def init_handles_static():
from C import _Py_NoneStruct: cobj
from C import _Py_TrueStruct: cobj
from C import _Py_FalseStruct: cobj
from C import _Py_EllipsisObject: cobj
from C import _Py_NotImplementedStruct: cobj
from C import PyLong_Type: cobj as _PyLong_Type
from C import PyFloat_Type: cobj as _PyFloat_Type
from C import PyBool_Type: cobj as _PyBool_Type
from C import PyUnicode_Type: cobj as _PyUnicode_Type
from C import PyComplex_Type: cobj as _PyComplex_Type
from C import PyList_Type: cobj as _PyList_Type
from C import PyDict_Type: cobj as _PyDict_Type
from C import PySet_Type: cobj as _PySet_Type
from C import PyTuple_Type: cobj as _PyTuple_Type
from C import PySlice_Type: cobj as _PySlice_Type
from C import PyExc_BaseException: cobj as _PyExc_BaseException
from C import PyExc_Exception: cobj as _PyExc_Exception
from C import PyExc_NameError: cobj as _PyExc_NameError
@ -615,7 +661,18 @@ def init_handles_static():
global Py_None
global Py_True
global Py_False
global Py_Ellipsis
global Py_NotImplemented
global PyLong_Type
global PyFloat_Type
global PyBool_Type
global PyUnicode_Type
global PyComplex_Type
global PyList_Type
global PyDict_Type
global PySet_Type
global PyTuple_Type
global PySlice_Type
global PyExc_BaseException
global PyExc_Exception
global PyExc_NameError
@ -730,7 +787,18 @@ def init_handles_static():
Py_None = __ptr__(_Py_NoneStruct).as_byte()
Py_True = __ptr__(_Py_TrueStruct).as_byte()
Py_False = __ptr__(_Py_FalseStruct).as_byte()
Py_Ellipsis = __ptr__(_Py_EllipsisObject).as_byte()
Py_NotImplemented = __ptr__(_Py_NotImplementedStruct).as_byte()
PyLong_Type = __ptr__(_PyLong_Type).as_byte()
PyFloat_Type = __ptr__(_PyFloat_Type).as_byte()
PyBool_Type = __ptr__(_PyBool_Type).as_byte()
PyUnicode_Type = __ptr__(_PyUnicode_Type).as_byte()
PyComplex_Type = __ptr__(_PyComplex_Type).as_byte()
PyList_Type = __ptr__(_PyList_Type).as_byte()
PyDict_Type = __ptr__(_PyDict_Type).as_byte()
PySet_Type = __ptr__(_PySet_Type).as_byte()
PyTuple_Type = __ptr__(_PyTuple_Type).as_byte()
PySlice_Type = __ptr__(_PySlice_Type).as_byte()
PyExc_BaseException = _PyExc_BaseException
PyExc_Exception = _PyExc_Exception
PyExc_NameError = _PyExc_NameError
@ -1148,6 +1216,14 @@ def _get_identifier(typ: str) -> pyobj:
def _isinstance(what: pyobj, typ: pyobj) -> bool:
return bool(pyobj.exc_wrap(PyObject_IsInstance(what.p, typ.p)))
@tuple
class _PyObject_Struct:
refcnt: int
pytype: cobj
def _is_type(o: cobj, t: cobj):
return Ptr[_PyObject_Struct](o)[0].pytype == t
# Type conversions
@ -1160,6 +1236,9 @@ class NoneType:
def __from_py__(i: cobj) -> None:
return
def __try_from_py__(i: cobj) -> Optional[NoneType]:
return
@extend
class int:
def __to_py__(self) -> cobj:
@ -1168,6 +1247,11 @@ class int:
def __from_py__(i: cobj) -> int:
return pyobj.exc_wrap(PyLong_AsLong(i))
def __try_from_py__(i: cobj) -> Optional[int]:
if _is_type(i, PyLong_Type):
return PyLong_AsLong(i)
return None
@extend
class float:
def __to_py__(self) -> cobj:
@ -1176,6 +1260,11 @@ class float:
def __from_py__(d: cobj) -> float:
return pyobj.exc_wrap(PyFloat_AsDouble(d))
def __try_from_py__(d: cobj) -> Optional[float]:
if _is_type(d, PyFloat_Type):
return PyFloat_AsDouble(d)
return None
@extend
class bool:
def __to_py__(self) -> cobj:
@ -1184,6 +1273,11 @@ class bool:
def __from_py__(b: cobj) -> bool:
return pyobj.exc_wrap(PyObject_IsTrue(b)) != 0
def __try_from_py__(b: cobj) -> Optional[bool]:
if _is_type(b, PyBool_Type):
return PyObject_IsTrue(b) != 0
return None
@extend
class byte:
def __to_py__(self) -> cobj:
@ -1192,6 +1286,12 @@ class byte:
def __from_py__(c: cobj) -> byte:
return str.__from_py__(c).ptr[0]
def __try_from_py__(c: cobj) -> Optional[byte]:
x = str.__try_from_py__(c)
if x is None or len(x) != 1:
return None
return x.ptr[0]
@extend
class str:
def __to_py__(self) -> cobj:
@ -1200,6 +1300,11 @@ class str:
def __from_py__(s: cobj) -> str:
return pyobj.exc_wrap(pyobj.to_str(s, "strict"))
def __try_from_py__(s: cobj) -> Optional[str]:
if _is_type(s, PyUnicode_Type):
return pyobj.to_str(s, "strict")
return None
@extend
class complex:
def __to_py__(self) -> cobj:
@ -1210,6 +1315,13 @@ class complex:
imag = pyobj.exc_wrap(PyComplex_ImagAsDouble(c))
return complex(real, imag)
def __try_from_py__(c: cobj) -> Optional[complex]:
if _is_type(c, PyComplex_Type):
real = PyComplex_RealAsDouble(c)
imag = PyComplex_ImagAsDouble(c)
return complex(real, imag)
return None
@extend
class List:
def __to_py__(self) -> cobj:
@ -1231,6 +1343,19 @@ class List:
t.append(T.__from_py__(elem))
return t
def __try_from_py__(v: cobj) -> Optional[List[T]]:
if _is_type(v, PyList_Type):
n = PyObject_Length(v)
t = List[T](n)
for i in range(n):
elem = PyList_GetItem(v, i)
x = T.__try_from_py__(elem)
if x is None:
return None
t.append(x)
return t
return None
@extend
class Dict:
def __to_py__(self) -> cobj:
@ -1253,6 +1378,21 @@ class Dict:
b[k] = v
return b
def __try_from_py__(d: cobj) -> Optional[Dict[K, V]]:
if _is_type(d, PyDict_Type):
b = dict[K, V]()
pos = 0
k_ptr = cobj()
v_ptr = cobj()
while PyDict_Next(d, __ptr__(pos), __ptr__(k_ptr), __ptr__(v_ptr)):
k = K.__try_from_py__(k_ptr)
v = V.__try_from_py__(v_ptr)
if k is None or v is None:
return None
b[k] = v
return b
return None
@extend
class Set:
def __to_py__(self) -> cobj:
@ -1276,6 +1416,23 @@ class Set:
pyobj.decref(s_iter)
return b
def __try_from_py__(s: cobj) -> Optional[Set[K]]:
if _is_type(s, PySet_Type):
b = set[K]()
s_iter = PyObject_GetIter(s)
while True:
k_ptr = PyIter_Next(s_iter)
if not k_ptr:
break
k = K.__try_from_py__(k_ptr)
if k is None:
return None
pyobj.decref(k_ptr)
b.add(k)
pyobj.decref(s_iter)
return b
return None
@extend
class DynamicTuple:
def __to_py__(self) -> cobj:
@ -1294,6 +1451,18 @@ class DynamicTuple:
p[i] = T.__from_py__(PyTuple_GetItem(t, i))
return DynamicTuple(p, n)
def __try_from_py__(t: cobj) -> Optional[DynamicTuple[T]]:
if _is_type(t, PyTuple_Type):
n = PyTuple_Size(t)
p = Ptr[T](n)
for i in range(n):
x = T.__try_from_py__(PyTuple_GetItem(t, i))
if x is None:
return None
p[i] = x
return DynamicTuple(p, n)
return None
@extend
class Slice:
def __to_py__(self) -> cobj:
@ -1312,6 +1481,15 @@ class Slice:
pyobj.exc_wrap(PySlice_Unpack(s, __ptr__(start), __ptr__(stop), __ptr__(step)))
return Slice(Optional(start), Optional(stop), Optional(step))
def __try_from_py__(s: cobj) -> Optional[Slice]:
if _is_type(s, PySlice_Type):
start = 0
stop = 0
step = 0
PySlice_Unpack(s, __ptr__(start), __ptr__(stop), __ptr__(step))
return Slice(Optional(start), Optional(stop), Optional(step))
return None
@extend
class Optional:
def __to_py__(self) -> cobj:
@ -1326,6 +1504,12 @@ class Optional:
else:
return Optional[T](T.__from_py__(o))
def __try_from_py__(o: cobj) -> Optional[Optional[T]]:
if o == Py_None:
return Optional[Optional[T]]()
else:
return Optional[Optional[T]](T.__try_from_py__(o))
__pyenv__: Optional[pyobj] = None
def _____(): __pyenv__ # make it global!