Skip to content

Commit 87093c1

Browse files
committed
Make libzim a package.
It is possible to import libzim in python : ``` import libzim libzim.reader.Archive("foo.zim") ``` Libzim is imported and submodule is created and correctly set. But it is not possible to directly import `libzim.reader`. Although the modules are created, the python import mechanism don't recognize libzim as a package and fail to locate the submodule. So we have to tweak a bit the system : - Add a __path__ to libzim to "mark" it as a package. - Provide our own module loader to not make python trying to load 'libzim.writer` from `___LIBZIM___/writer.py`. Now it is possible to directly import a submodule : ``` from libzim.reader import Archive Archive("foo.zim") ```
1 parent 0fcc120 commit 87093c1

File tree

1 file changed

+31
-0
lines changed

1 file changed

+31
-0
lines changed

libzim/wrapper.pyx

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@
1717
# You should have received a copy of the GNU General Public License
1818
# along with this program. If not, see <http://www.gnu.org/licenses/>.
1919

20+
# Make our libzim module a package by setting a __path__
21+
# There is no real path here, but it will be passed to our module finder.
22+
__path__ = "___LIBZIM___"
2023

2124
cimport zim
2225

@@ -39,6 +42,7 @@ import pathlib
3942
import traceback
4043
from types import ModuleType
4144
import sys
45+
import importlib
4246

4347
pybool = type(True)
4448

@@ -950,5 +954,32 @@ search_public_objects = [
950954
]
951955
search = create_module(search_module_name, search_module_doc, search_public_objects)
952956

957+
958+
class ModuleLoader(importlib.abc.Loader):
959+
# Create our module. Easy, just return the created module
960+
@staticmethod
961+
def create_module(spec):
962+
return {
963+
'libzim.writer': writer,
964+
'libzim.reader': reader,
965+
'libzim.search': search
966+
}.get(spec.name, None)
967+
968+
@staticmethod
969+
def exec_module(module):
970+
# Nothing to execute for our already existing module.
971+
# But we need to define exec_module to tell python not use the legacy import system.
972+
pass
973+
974+
class ModuleFinder(importlib.abc.MetaPathFinder):
975+
def find_spec(self, fullname, path, target=None):
976+
if path != __path__:
977+
# This is not our problem, let import mechanism continue
978+
return None
979+
return importlib.machinery.ModuleSpec(fullname, ModuleLoader)
980+
981+
# register finder for our submodules
982+
sys.meta_path.insert(0, ModuleFinder())
983+
953984
__all__ = ["writer", "reader", "search"]
954985

0 commit comments

Comments
 (0)