kp2pml30's personal blog HOME ROFS ABOUT LNK


How to do a re-export in python properly?

I stumbled upon this problem while compiling numpy for wasm32-wasip1. Dynamic linking isn't supported out of the box there, so all modules must be statically linked into CPython. However, numpy uses relative imports, while native modules can't have dots in name

V0 (naive)

from _native_module import *
Well, this obviously won't work because of... Cyclic imports!
However, pep-0562 comes for rescue. It allows to override __getattr__ on module level, though usage is not that straight forward

V1

import _native_module as _imp
def __getattr__(name):
	return getattr(_imp, name)
Or:
def __getattr__(name):
	return getattr(_imp, name)
import _native_module as _imp
Neither of them works, because of the cyclic import (again)

V2 (correct)

def __getattr__(name):
	import _native_module as _imp
	return getattr(_imp, name)
This one finally worked. Why so?
  • Python executes bytecode sequentially, so __getattr__ has to be defined before importing a circular module
  • import _common as _imp appears to assign to _imp after initializing the module, so it's more like the following
    mod = new_mod()
    init_mod(mod, 'common')
    _imp = mod
    And not with the last two lines swapped
Moreover, assignment should work just fine. However, I think from ... import * won't. because __all__ is missing