#[cfg(windows)]
use {
super::memory_dll::{free_library_memory, get_proc_address_memory, load_library_memory},
cpython::exc::SystemError,
std::ffi::{c_void, CString},
};
use {
super::pyinterp::PYOXIDIZER_IMPORTER_NAME,
super::python_resources::{OptimizeLevel, PythonResourcesState},
cpython::exc::{FileNotFoundError, ImportError, RuntimeError, ValueError},
cpython::{
py_class, py_fn, NoArgs, ObjectProtocol, PyClone, PyDict, PyErr, PyList, PyModule,
PyObject, PyResult, PyString, PyTuple, Python, PythonObject,
},
python3_sys as pyffi,
python_packed_resources::data::ResourceFlavor,
std::path::PathBuf,
std::sync::Arc,
};
#[cfg(windows)]
#[allow(non_camel_case_types)]
type py_init_fn = extern "C" fn() -> *mut pyffi::PyObject;
#[cfg(windows)]
fn extension_module_shared_library_create_module(
resources_state: &PythonResourcesState<u8>,
py: Python,
sys_modules: PyObject,
spec: &PyObject,
name_py: PyObject,
name: &str,
library_data: &[u8],
) -> PyResult<PyObject> {
let origin = PyString::new(py, "memory");
let existing_module = unsafe {
pyffi::_PyImport_FindExtensionObjectEx(
name_py.as_ptr(),
origin.as_object().as_ptr(),
sys_modules.as_ptr(),
)
};
if !existing_module.is_null() {
return Ok(unsafe { PyObject::from_owned_ptr(py, existing_module) });
}
if !unsafe { pyffi::PyErr_Occurred() }.is_null() {
return Err(PyErr::fetch(py));
}
let module = unsafe { load_library_memory(resources_state, library_data) };
if module.is_null() {
return Err(PyErr::new::<ImportError, _>(
py,
("unable to load extension module library from memory", name),
));
}
load_dynamic_library(py, sys_modules, spec, name_py, name, module).or_else(|e| {
unsafe {
free_library_memory(module);
}
Err(e)
})
}
#[cfg(unix)]
fn extension_module_shared_library_create_module(
_resources_state: &PythonResourcesState<u8>,
_py: Python,
_sys_modules: PyObject,
_spec: &PyObject,
_name_py: PyObject,
_name: &str,
_library_data: &[u8],
) -> PyResult<PyObject> {
panic!("should only be called on Windows");
}
#[cfg(windows)]
fn load_dynamic_library(
py: Python,
sys_modules: PyObject,
spec: &PyObject,
name_py: PyObject,
name: &str,
library_module: *const c_void,
) -> PyResult<PyObject> {
let last_name_part = if name.contains('.') {
name.split('.').last().unwrap()
} else {
name
};
let name_cstring = CString::new(name).unwrap();
let init_fn_name = CString::new(format!("PyInit_{}", last_name_part)).unwrap();
let address = unsafe { get_proc_address_memory(library_module, &init_fn_name) };
if address.is_null() {
return Err(PyErr::new::<ImportError, _>(
py,
(
format!(
"dynamic module does not define module export function ({})",
init_fn_name.to_str().unwrap()
),
name,
),
));
}
let init_fn: py_init_fn = unsafe { std::mem::transmute(address) };
let py_module = unsafe {
let old_context = pyffi::_Py_PackageContext;
pyffi::_Py_PackageContext = name_cstring.as_ptr();
let py_module = init_fn();
pyffi::_Py_PackageContext = old_context;
py_module
};
if py_module.is_null() {
if unsafe { pyffi::PyErr_Occurred().is_null() } {
return Err(PyErr::new::<SystemError, _>(
py,
format!(
"initialization of {} failed without raising an exception",
name
),
));
}
}
let py_module = unsafe { PyObject::from_owned_ptr(py, py_module) };
if !unsafe { pyffi::PyErr_Occurred().is_null() } {
unsafe {
pyffi::PyErr_Clear();
}
return Err(PyErr::new::<SystemError, _>(
py,
format!("initialization of {} raised unreported exception", name),
));
}
if unsafe { pyffi::Py_TYPE(py_module.as_ptr()) }.is_null() {
return Err(PyErr::new::<SystemError, _>(
py,
format!("init function of {} returned uninitialized object", name),
));
}
if unsafe { pyffi::PyObject_TypeCheck(py_module.as_ptr(), &mut pyffi::PyModuleDef_Type) } != 0 {
let py_module = unsafe {
pyffi::PyModule_FromDefAndSpec(
py_module.as_ptr() as *mut pyffi::PyModuleDef,
spec.as_ptr(),
)
};
return if py_module.is_null() {
Err(PyErr::fetch(py))
} else {
Ok(unsafe { PyObject::from_owned_ptr(py, py_module) })
};
}
let mut module_def = unsafe { pyffi::PyModule_GetDef(py_module.as_ptr()) };
if module_def.is_null() {
return Err(PyErr::new::<SystemError, _>(
py,
format!(
"initialization of {} did not return an extension module",
name
),
));
}
unsafe {
(*module_def).m_base.m_init = Some(init_fn);
}
let fixup_result = unsafe {
pyffi::_PyImport_FixupExtensionObject(
py_module.as_ptr(),
name_py.as_ptr(),
name_py.as_ptr(),
sys_modules.as_ptr(),
)
};
if fixup_result < 0 {
Err(PyErr::fetch(py))
} else {
Ok(py_module)
}
}
pub(crate) struct ImporterState {
imp_module: PyModule,
sys_module: PyModule,
marshal_loads: PyObject,
builtin_importer: PyObject,
frozen_importer: PyObject,
call_with_frames_removed: PyObject,
module_spec_type: PyObject,
decode_source: PyObject,
exec_fn: PyObject,
optimize_level: OptimizeLevel,
pub resources_state: PythonResourcesState<'static, u8>,
}
impl ImporterState {
fn new(
py: Python,
bootstrap_module: &PyModule,
marshal_module: &PyModule,
decode_source: PyObject,
resources_data: &'static [u8],
current_exe: PathBuf,
origin: PathBuf,
) -> Result<Self, PyErr> {
let imp_module = bootstrap_module.get(py, "_imp")?;
let imp_module = imp_module.cast_into::<PyModule>(py)?;
let sys_module = bootstrap_module.get(py, "sys")?;
let sys_module = sys_module.cast_into::<PyModule>(py)?;
let meta_path_object = sys_module.get(py, "meta_path")?;
let meta_path = meta_path_object.cast_as::<PyList>(py)?;
if meta_path.len(py) != 2 {
return Err(PyErr::new::<ValueError, _>(
py,
"sys.meta_path does not contain 2 values",
));
}
let builtin_importer = meta_path.get_item(py, 0);
let frozen_importer = meta_path.get_item(py, 1);
let mut resources_state = PythonResourcesState {
current_exe,
origin,
..PythonResourcesState::default()
};
if let Err(e) = resources_state.load(resources_data) {
return Err(PyErr::new::<ValueError, _>(py, e));
}
let marshal_loads = marshal_module.get(py, "loads")?;
let call_with_frames_removed = bootstrap_module.get(py, "_call_with_frames_removed")?;
let module_spec_type = bootstrap_module.get(py, "ModuleSpec")?;
let builtins_module =
match unsafe { PyObject::from_borrowed_ptr_opt(py, pyffi::PyEval_GetBuiltins()) } {
Some(o) => o.cast_into::<PyDict>(py),
None => {
return Err(PyErr::new::<ValueError, _>(
py,
"unable to obtain __builtins__",
));
}
}?;
let exec_fn = match builtins_module.get_item(py, "exec") {
Some(v) => v,
None => {
return Err(PyErr::new::<ValueError, _>(
py,
"could not obtain __builtins__.exec",
));
}
};
let sys_flags = sys_module.get(py, "flags")?;
let optimize_value = sys_flags.getattr(py, "optimize")?;
let optimize_value = optimize_value.extract::<i64>(py)?;
let optimize_level = match optimize_value {
0 => Ok(OptimizeLevel::Zero),
1 => Ok(OptimizeLevel::One),
2 => Ok(OptimizeLevel::Two),
_ => Err(PyErr::new::<ValueError, _>(
py,
"unexpected value for sys.flags.optimize",
)),
}?;
Ok(ImporterState {
imp_module,
sys_module,
marshal_loads,
builtin_importer,
frozen_importer,
call_with_frames_removed,
module_spec_type,
decode_source,
exec_fn,
optimize_level,
resources_state,
})
}
}
#[allow(unused_doc_comments)]
py_class!(class PyOxidizerFinder |py| {
data state: Arc<Box<ImporterState>>;
def find_spec(&self, fullname: &PyString, path: &PyObject, target: Option<PyObject> = None) -> PyResult<PyObject> {
self.find_spec_impl(py, fullname, path, target)
}
def find_module(&self, fullname: &PyObject, path: &PyObject) -> PyResult<PyObject> {
self.find_module_impl(py, fullname, path)
}
def invalidate_caches(&self) -> PyResult<PyObject> {
self.invalidate_caches_impl(py)
}
def create_module(&self, spec: &PyObject) -> PyResult<PyObject> {
self.create_module_impl(py, spec)
}
def exec_module(&self, module: &PyObject) -> PyResult<PyObject> {
self.exec_module_impl(py, module)
}
def get_data(&self, path: &PyString) -> PyResult<PyObject> {
self.get_data_impl(py, path)
}
def get_code(&self, fullname: &PyString) -> PyResult<PyObject> {
self.get_code_impl(py, fullname)
}
def get_source(&self, fullname: &PyString) -> PyResult<PyObject> {
self.get_source_impl(py, fullname)
}
def get_filename(&self, fullname: &PyString) -> PyResult<PyObject> {
self.get_filename_impl(py, fullname)
}
def get_resource_reader(&self, fullname: &PyString) -> PyResult<PyObject> {
self.get_resource_reader_impl(py, fullname)
}
def find_distributions(&self, context: Option<PyObject> = None) -> PyResult<PyObject> {
self.find_distributions_impl(py, context)
}
});
impl PyOxidizerFinder {
fn find_spec_impl(
&self,
py: Python,
fullname: &PyString,
path: &PyObject,
target: Option<PyObject>,
) -> PyResult<PyObject> {
let state = self.state(py);
let key = fullname.to_string(py)?;
let module = match state
.resources_state
.resolve_importable_module(&key, state.optimize_level)
{
Some(module) => module,
None => return Ok(py.None()),
};
match module.flavor {
ResourceFlavor::Extension | ResourceFlavor::Module => module.resolve_module_spec(
py,
&state.module_spec_type,
self.as_object(),
state.optimize_level,
),
ResourceFlavor::BuiltinExtensionModule => {
state
.builtin_importer
.call_method(py, "find_spec", (fullname,), None)
}
ResourceFlavor::FrozenModule => {
state
.frozen_importer
.call_method(py, "find_spec", (fullname, path, target), None)
}
_ => Ok(py.None()),
}
}
fn invalidate_caches_impl(&self, py: Python) -> PyResult<PyObject> {
Ok(py.None())
}
fn find_module_impl(
&self,
py: Python,
fullname: &PyObject,
path: &PyObject,
) -> PyResult<PyObject> {
let finder = self.as_object();
let find_spec = finder.getattr(py, "find_spec")?;
let spec = find_spec.call(py, (fullname, path), None)?;
if spec == py.None() {
Ok(py.None())
} else {
spec.getattr(py, "loader")
}
}
}
impl PyOxidizerFinder {
fn create_module_impl(&self, py: Python, spec: &PyObject) -> PyResult<PyObject> {
let state = self.state(py);
let name = spec.getattr(py, "name")?;
let key = name.extract::<String>(py)?;
let entry = match state.resources_state.resources.get(&*key) {
Some(entry) => entry,
None => return Ok(py.None()),
};
match entry.flavor {
ResourceFlavor::Extension => {
if let Some(library_data) = &entry.in_memory_extension_module_shared_library {
let sys_modules = state.sys_module.as_object().getattr(py, "modules")?;
extension_module_shared_library_create_module(
&state.resources_state,
py,
sys_modules,
spec,
name,
&key,
library_data,
)
} else {
let create_dynamic =
state.imp_module.as_object().getattr(py, "create_dynamic")?;
state
.call_with_frames_removed
.call(py, (&create_dynamic, spec), None)
}
}
_ => Ok(py.None()),
}
}
fn exec_module_impl(&self, py: Python, module: &PyObject) -> PyResult<PyObject> {
let state = self.state(py);
let name = module.getattr(py, "__name__")?;
let key = name.extract::<String>(py)?;
let mut entry = match state
.resources_state
.resolve_importable_module(&key, state.optimize_level)
{
Some(entry) => entry,
None => {
return Ok(py.None());
}
};
if let Some(bytecode) = entry.resolve_bytecode(py, state.optimize_level)? {
let code = state.marshal_loads.call(py, (bytecode,), None)?;
let dict = module.getattr(py, "__dict__")?;
state
.call_with_frames_removed
.call(py, (&state.exec_fn, code, dict), None)
} else if entry.flavor == &ResourceFlavor::BuiltinExtensionModule {
state
.builtin_importer
.call_method(py, "exec_module", (module,), None)
} else if entry.flavor == &ResourceFlavor::FrozenModule {
state
.frozen_importer
.call_method(py, "exec_module", (module,), None)
} else if entry.flavor == &ResourceFlavor::Extension {
let exec_dynamic = state.imp_module.as_object().getattr(py, "exec_dynamic")?;
state
.call_with_frames_removed
.call(py, (&exec_dynamic, module), None)
} else {
Ok(py.None())
}
}
}
impl PyOxidizerFinder {
fn get_data_impl(&self, py: Python, path: &PyString) -> PyResult<PyObject> {
self.state(py)
.resources_state
.resolve_resource_data_from_path(py, path)
}
}
impl PyOxidizerFinder {
fn get_code_impl(&self, py: Python, fullname: &PyString) -> PyResult<PyObject> {
let state = self.state(py);
let key = fullname.to_string(py)?;
let mut module = match state
.resources_state
.resolve_importable_module(&key, state.optimize_level)
{
Some(module) => module,
None => return Ok(py.None()),
};
if let Some(bytecode) = module.resolve_bytecode(py, state.optimize_level)? {
state.marshal_loads.call(py, (bytecode,), None)
} else if module.flavor == &ResourceFlavor::FrozenModule {
state
.imp_module
.call(py, "get_frozen_object", (fullname,), None)
} else {
Ok(py.None())
}
}
fn get_source_impl(&self, py: Python, fullname: &PyString) -> PyResult<PyObject> {
let state = self.state(py);
let key = fullname.to_string(py)?;
let module = match state
.resources_state
.resolve_importable_module(&key, state.optimize_level)
{
Some(module) => module,
None => return Ok(py.None()),
};
if let Some(source) = module.resolve_source(py)? {
state.decode_source.call(py, (source,), None)
} else {
Ok(py.None())
}
}
}
impl PyOxidizerFinder {
fn get_filename_impl(&self, py: Python, fullname: &PyString) -> PyResult<PyObject> {
let state = self.state(py);
let key = fullname.to_string(py)?;
let make_error = |msg: &str| -> PyErr { PyErr::new::<ImportError, _>(py, (msg, &key)) };
let module = state
.resources_state
.resolve_importable_module(&key, state.optimize_level)
.ok_or_else(|| make_error("unknown module"))?;
module
.resolve_origin(py)
.or_else(|_| Err(make_error("unable to resolve origin")))?
.ok_or_else(|| make_error("no origin"))
}
}
impl PyOxidizerFinder {
fn get_resource_reader_impl(&self, py: Python, fullname: &PyString) -> PyResult<PyObject> {
let state = self.state(py);
let key = fullname.to_string(py)?;
let entry = match state
.resources_state
.resolve_importable_module(&key, state.optimize_level)
{
Some(entry) => entry,
None => return Ok(py.None()),
};
if entry.is_package {
let reader =
PyOxidizerResourceReader::create_instance(py, state.clone(), key.to_string())?
.into_object();
Ok(reader)
} else {
Ok(py.None())
}
}
}
impl PyOxidizerFinder {
fn find_distributions_impl(&self, py: Python, context: Option<PyObject>) -> PyResult<PyObject> {
let state = self.state(py);
let (path, name) = if let Some(context) = context {
let path = context.getattr(py, "path")?;
let name = context.getattr(py, "name")?;
(Some(path), Some(name))
} else {
(None, None)
};
super::package_metadata::find_distributions(py, state.clone(), path, name)
}
}
#[allow(unused_doc_comments)]
py_class!(class PyOxidizerResourceReader |py| {
data state: Arc<Box<ImporterState>>;
data package: String;
def open_resource(&self, resource: &PyString) -> PyResult<PyObject> {
self.open_resource_impl(py, resource)
}
def resource_path(&self, resource: &PyString) -> PyResult<PyObject> {
self.resource_path_impl(py, resource)
}
def is_resource(&self, name: &PyString) -> PyResult<PyObject> {
self.is_resource_impl(py, name)
}
def contents(&self) -> PyResult<PyObject> {
self.contents_impl(py)
}
});
impl PyOxidizerResourceReader {
fn open_resource_impl(&self, py: Python, resource: &PyString) -> PyResult<PyObject> {
let state = self.state(py);
let package = self.package(py);
if let Some(file) = state.resources_state.get_package_resource_file(
py,
&package,
&resource.to_string(py)?,
)? {
Ok(file)
} else {
Err(PyErr::new::<FileNotFoundError, _>(py, "resource not found"))
}
}
fn resource_path_impl(&self, py: Python, _resource: &PyString) -> PyResult<PyObject> {
Err(PyErr::new::<FileNotFoundError, _>(
py,
"in-memory resources do not have filesystem paths",
))
}
fn is_resource_impl(&self, py: Python, name: &PyString) -> PyResult<PyObject> {
let state = self.state(py);
let package = self.package(py);
if state
.resources_state
.is_package_resource(&package, &name.to_string(py)?)
{
Ok(py.True().as_object().clone_ref(py))
} else {
Err(PyErr::new::<FileNotFoundError, _>(py, "resource not found"))
}
}
fn contents_impl(&self, py: Python) -> PyResult<PyObject> {
let state = self.state(py);
let package = self.package(py);
state.resources_state.package_resource_names(py, &package)
}
}
#[allow(unused_doc_comments)]
py_class!(class PyOxidizerTraversable |py| {
data state: Arc<Box<ImporterState>>;
data path: String;
def iterdir(&self) -> PyResult<PyObject> {
self.iterdir_impl(py)
}
def read_bytes(&self) -> PyResult<PyObject> {
self.read_bytes_impl(py)
}
def read_text(&self) -> PyResult<PyObject> {
self.read_text_impl(py)
}
def is_dir(&self) -> PyResult<PyObject> {
self.is_dir_impl(py)
}
def is_file(&self) -> PyResult<PyObject> {
self.is_file_impl(py)
}
def joinpath(&self, child: &PyObject) -> PyResult<PyObject> {
self.joinpath_impl(py, child)
}
def __truediv__(&self, child: &PyObject) -> PyResult<PyObject> {
self.joinpath_impl(py, child)
}
def open(&self, *args, **kwargs) -> PyResult<PyObject> {
self.open_impl(py, args, kwargs)
}
});
impl PyOxidizerTraversable {
fn iterdir_impl(&self, _py: Python) -> PyResult<PyObject> {
unimplemented!();
}
fn read_bytes_impl(&self, _py: Python) -> PyResult<PyObject> {
unimplemented!();
}
fn read_text_impl(&self, _py: Python) -> PyResult<PyObject> {
unimplemented!();
}
fn is_dir_impl(&self, py: Python) -> PyResult<PyObject> {
let state = self.state(py);
let path = self.path(py);
if let Some(entry) = state
.resources_state
.resolve_importable_module(&path, state.optimize_level)
{
if entry.is_package {
return Ok(py.True().into_object());
}
}
Ok(py.False().into_object())
}
fn is_file_impl(&self, _py: Python) -> PyResult<PyObject> {
unimplemented!();
}
fn joinpath_impl(&self, _py: Python, _child: &PyObject) -> PyResult<PyObject> {
unimplemented!();
}
fn open_impl(
&self,
_py: Python,
_args: &PyTuple,
_kwargs: Option<&PyDict>,
) -> PyResult<PyObject> {
unimplemented!();
}
}
const DOC: &[u8] = b"Binary representation of Python modules\0";
#[derive(Debug)]
pub struct InitModuleState {
pub current_exe: PathBuf,
pub origin: PathBuf,
pub register_filesystem_importer: bool,
pub sys_paths: Vec<String>,
pub packed_resources: &'static [u8],
}
pub static mut NEXT_MODULE_STATE: *const InitModuleState = std::ptr::null();
#[derive(Debug)]
struct ModuleState {
current_exe: PathBuf,
origin: PathBuf,
register_filesystem_importer: bool,
sys_paths: Vec<String>,
packed_resources: &'static [u8],
setup_called: bool,
}
fn get_module_state<'a>(py: Python, m: &'a PyModule) -> Result<&'a mut ModuleState, PyErr> {
let ptr = m.as_object().as_ptr();
let state = unsafe { pyffi::PyModule_GetState(ptr) as *mut ModuleState };
if state.is_null() {
let err = PyErr::new::<ValueError, _>(py, "unable to retrieve module state");
return Err(err);
}
Ok(unsafe { &mut *state })
}
fn module_init(py: Python, m: &PyModule) -> PyResult<()> {
let mut state = get_module_state(py, m)?;
unsafe {
state.current_exe = (*NEXT_MODULE_STATE).current_exe.clone();
state.origin = (*NEXT_MODULE_STATE).origin.clone();
state.register_filesystem_importer = (*NEXT_MODULE_STATE).register_filesystem_importer;
state.sys_paths = (*NEXT_MODULE_STATE).sys_paths.clone();
state.packed_resources = (*NEXT_MODULE_STATE).packed_resources;
}
state.setup_called = false;
m.add(
py,
"_setup",
py_fn!(
py,
module_setup(
m: PyModule,
bootstrap_module: PyModule,
marshal_module: PyModule,
decode_source: PyObject
)
),
)?;
Ok(())
}
fn module_setup(
py: Python,
m: PyModule,
bootstrap_module: PyModule,
marshal_module: PyModule,
decode_source: PyObject,
) -> PyResult<PyObject> {
let state = get_module_state(py, &m)?;
if state.setup_called {
return Err(PyErr::new::<RuntimeError, _>(
py,
"PyOxidizer _setup() already called",
));
}
state.setup_called = true;
let sys_module = bootstrap_module.get(py, "sys")?;
let sys_module = sys_module.cast_into::<PyModule>(py)?;
let sys_module_ref = sys_module.clone_ref(py);
let unified_importer = PyOxidizerFinder::create_instance(
py,
Arc::new(Box::new(ImporterState::new(
py,
&bootstrap_module,
&marshal_module,
decode_source,
&state.packed_resources,
state.current_exe.clone(),
state.origin.clone(),
)?)),
)?;
let meta_path_object = sys_module.get(py, "meta_path")?;
meta_path_object.call_method(py, "clear", NoArgs, None)?;
meta_path_object.call_method(py, "append", (unified_importer,), None)?;
if state.register_filesystem_importer {
let frozen_importlib_external = py.import("_frozen_importlib_external")?;
let loaders =
frozen_importlib_external.call(py, "_get_supported_file_loaders", NoArgs, None)?;
let loaders_list = loaders.cast_as::<PyList>(py)?;
let loaders_vec: Vec<PyObject> = loaders_list.iter(py).collect();
let loaders_tuple = PyTuple::new(py, loaders_vec.as_slice());
let file_finder = frozen_importlib_external.get(py, "FileFinder")?;
let path_hook = file_finder.call_method(py, "path_hook", loaders_tuple, None)?;
let path_hooks = sys_module_ref.get(py, "path_hooks")?;
path_hooks.call_method(py, "append", (path_hook,), None)?;
let path_finder = frozen_importlib_external.get(py, "PathFinder")?;
let meta_path = sys_module_ref.get(py, "meta_path")?;
meta_path.call_method(py, "append", (path_finder,), None)?;
}
let sys_path = sys_module_ref.get(py, "path")?;
sys_path.call_method(py, "clear", NoArgs, None)?;
for path in &state.sys_paths {
let py_path = PyString::new(py, path.as_str());
sys_path.call_method(py, "append", (py_path,), None)?;
}
Ok(py.None())
}
static mut MODULE_DEF: pyffi::PyModuleDef = pyffi::PyModuleDef {
m_base: pyffi::PyModuleDef_HEAD_INIT,
m_name: std::ptr::null(),
m_doc: std::ptr::null(),
m_size: std::mem::size_of::<ModuleState>() as isize,
m_methods: 0 as *mut _,
m_slots: 0 as *mut _,
m_traverse: None,
m_clear: None,
m_free: None,
};
#[allow(non_snake_case)]
pub extern "C" fn PyInit__pyoxidizer_importer() -> *mut pyffi::PyObject {
let py = unsafe { cpython::Python::assume_gil_acquired() };
unsafe {
if MODULE_DEF.m_name.is_null() {
MODULE_DEF.m_name = PYOXIDIZER_IMPORTER_NAME.as_ptr() as *const _;
MODULE_DEF.m_doc = DOC.as_ptr() as *const _;
}
}
let module = unsafe { pyffi::PyModule_Create(&mut MODULE_DEF) };
if module.is_null() {
return module;
}
let module = match unsafe { PyObject::from_owned_ptr(py, module).cast_into::<PyModule>(py) } {
Ok(m) => m,
Err(e) => {
PyErr::from(e).restore(py);
return std::ptr::null_mut();
}
};
match module_init(py, &module) {
Ok(()) => module.into_object().steal_ptr(),
Err(e) => {
e.restore(py);
std::ptr::null_mut()
}
}
}