use libc::c_char;
use std::ffi::{CStr, CString};
use crate::conversion::ToPyObject;
use crate::err::{self, PyErr, PyResult};
use crate::ffi;
use crate::objectprotocol::ObjectProtocol;
use crate::objects::{exc, PyDict, PyObject, PyTuple};
use crate::py_class::PythonObjectFromPyClassMacro;
use crate::python::{PyDrop, Python, PythonObject};
pub struct PyModule(PyObject);
pyobject_newtype!(PyModule, PyModule_Check, PyModule_Type);
impl PyModule {
pub fn new(py: Python, name: &str) -> PyResult<PyModule> {
let name = CString::new(name).unwrap();
unsafe { err::result_cast_from_owned_ptr(py, ffi::PyModule_New(name.as_ptr())) }
}
pub fn import(py: Python, name: &str) -> PyResult<PyModule> {
let name = CString::new(name).unwrap();
unsafe { err::result_cast_from_owned_ptr(py, ffi::PyImport_ImportModule(name.as_ptr())) }
}
pub fn dict(&self, py: Python) -> PyDict {
unsafe {
let r = PyObject::from_borrowed_ptr(py, ffi::PyModule_GetDict(self.0.as_ptr()));
r.unchecked_cast_into::<PyDict>()
}
}
unsafe fn str_from_ptr<'a>(&'a self, py: Python, ptr: *const c_char) -> PyResult<&'a str> {
if ptr.is_null() {
Err(PyErr::fetch(py))
} else {
let slice = CStr::from_ptr(ptr).to_bytes();
match std::str::from_utf8(slice) {
Ok(s) => Ok(s),
Err(e) => Err(PyErr::from_instance(
py,
exc::UnicodeDecodeError::new_utf8(py, slice, e)?,
)),
}
}
}
pub fn name<'a>(&'a self, py: Python) -> PyResult<&'a str> {
unsafe { self.str_from_ptr(py, ffi::PyModule_GetName(self.0.as_ptr())) }
}
#[allow(deprecated)]
pub fn filename(&self, py: Python) -> PyResult<&str> {
unsafe { self.str_from_ptr(py, ffi::PyModule_GetFilename(self.0.as_ptr())) }
}
#[cfg(feature = "python3-sys")]
pub fn filename_object(&self, py: Python) -> PyResult<PyObject> {
let ptr = unsafe { ffi::PyModule_GetFilenameObject(self.0.as_ptr()) };
if ptr.is_null() {
Err(PyErr::fetch(py))
} else {
Ok(unsafe { PyObject::from_borrowed_ptr(py, ptr) })
}
}
pub fn get(&self, py: Python, name: &str) -> PyResult<PyObject> {
self.as_object().getattr(py, name)
}
pub fn call<A>(
&self,
py: Python,
name: &str,
args: A,
kwargs: Option<&PyDict>,
) -> PyResult<PyObject>
where
A: ToPyObject<ObjectType = PyTuple>,
{
self.as_object().getattr(py, name)?.call(py, args, kwargs)
}
pub fn add<V>(&self, py: Python, name: &str, value: V) -> PyResult<()>
where
V: ToPyObject,
{
self.as_object().setattr(py, name, value)
}
pub fn add_class<T>(&self, py: Python<'_>) -> PyResult<()>
where
T: PythonObjectFromPyClassMacro,
{
T::add_to_module(py, self)
}
}