examples/usercmodule: Add a sub-package example.

This demonstrates how to add a sub-package in a user c module, as well
as how to define the necessary qstrs and enable the feature in the build.

This is used by the unix coverage build to test this feature.

This work was funded through GitHub Sponsors.

Signed-off-by: Jim Mussared <jim.mussared@gmail.com>
This commit is contained in:
Jim Mussared 2023-05-12 17:03:14 +10:00 committed by Damien George
parent 6a8114eee8
commit 5e04521251
10 changed files with 156 additions and 13 deletions

View File

@ -68,7 +68,7 @@ MP_DEFINE_CONST_OBJ_TYPE(
locals_dict, &example_Timer_locals_dict
);
// Define all properties of the module.
// Define all attributes of the module.
// Table entries are key/value pairs of the attribute name (a string)
// and the MicroPython object reference.
// All identifiers and strings are written as MP_QSTR_xxx and will be

View File

@ -1,9 +1,8 @@
EXAMPLE_MOD_DIR := $(USERMOD_DIR)
CEXAMPLE_MOD_DIR := $(USERMOD_DIR)
# Add all C files to SRC_USERMOD.
SRC_USERMOD += $(EXAMPLE_MOD_DIR)/examplemodule.c
SRC_USERMOD += $(CEXAMPLE_MOD_DIR)/examplemodule.c
# We can add our module folder to include paths if needed
# This is not actually needed in this example.
CFLAGS_USERMOD += -I$(EXAMPLE_MOD_DIR)
CEXAMPLE_MOD_DIR := $(USERMOD_DIR)
CFLAGS_USERMOD += -I$(CEXAMPLE_MOD_DIR)

View File

@ -4,7 +4,7 @@
// See example.cpp for the definition.
STATIC MP_DEFINE_CONST_FUN_OBJ_2(cppfunc_obj, cppfunc);
// Define all properties of the module.
// Define all attributes of the module.
// Table entries are key/value pairs of the attribute name (a string)
// and the MicroPython object reference.
// All identifiers and strings are written as MP_QSTR_xxx and will be

View File

@ -0,0 +1 @@
This is an example of a user C module that includes subpackages.

View File

@ -0,0 +1,19 @@
# Create an INTERFACE library for our C module.
add_library(usermod_subpackage_example INTERFACE)
# Add our source files to the lib
target_sources(usermod_subpackage_example INTERFACE
${CMAKE_CURRENT_LIST_DIR}/examplemodule.c
)
# Add the current directory as an include directory.
target_include_directories(usermod_subpackage_example INTERFACE
${CMAKE_CURRENT_LIST_DIR}
)
target_compile_definitions(usermod_subpackage_example INTERFACE
MICROPY_MODULE_BUILTIN_SUBPACKAGES=1
)
# Link our INTERFACE library to the usermod target.
target_link_libraries(usermod INTERFACE usermod_subpackage_example)

View File

@ -0,0 +1,10 @@
SUBPACKAGE_EXAMPLE_MOD_DIR := $(USERMOD_DIR)
# Add all C files to SRC_USERMOD.
SRC_USERMOD += $(SUBPACKAGE_EXAMPLE_MOD_DIR)/modexamplepackage.c
# We can add our module folder to include paths if needed
# This is not actually needed in this example.
CFLAGS_USERMOD += -I$(SUBPACKAGE_EXAMPLE_MOD_DIR) -DMICROPY_MODULE_BUILTIN_SUBPACKAGES=1
QSTR_DEFS += $(SUBPACKAGE_EXAMPLE_MOD_DIR)/qstrdefsexamplepackage.h

View File

@ -0,0 +1,84 @@
// Include MicroPython API.
#include "py/runtime.h"
// Define example_package.foo.bar.f()
STATIC mp_obj_t example_package_foo_bar_f(void) {
mp_printf(&mp_plat_print, "example_package.foo.bar.f\n");
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_0(example_package_foo_bar_f_obj, example_package_foo_bar_f);
// Define all attributes of the second-level sub-package (example_package.foo.bar).
STATIC const mp_rom_map_elem_t example_package_foo_bar_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_example_package_dot_foo_dot_bar) },
{ MP_ROM_QSTR(MP_QSTR_f), MP_ROM_PTR(&example_package_foo_bar_f_obj) },
};
STATIC MP_DEFINE_CONST_DICT(example_package_foo_bar_globals, example_package_foo_bar_globals_table);
// Define example_package.foo.bar module object.
const mp_obj_module_t example_package_foo_bar_user_cmodule = {
.base = { &mp_type_module },
.globals = (mp_obj_dict_t *)&example_package_foo_bar_globals,
};
// Define example_package.foo.f()
STATIC mp_obj_t example_package_foo_f(void) {
mp_printf(&mp_plat_print, "example_package.foo.f\n");
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_0(example_package_foo_f_obj, example_package_foo_f);
// Define all attributes of the first-level sub-package (example_package.foo).
STATIC const mp_rom_map_elem_t example_package_foo_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_example_package_dot_foo) },
{ MP_ROM_QSTR(MP_QSTR_bar), MP_ROM_PTR(&example_package_foo_bar_user_cmodule) },
{ MP_ROM_QSTR(MP_QSTR_f), MP_ROM_PTR(&example_package_foo_f_obj) },
};
STATIC MP_DEFINE_CONST_DICT(example_package_foo_globals, example_package_foo_globals_table);
// Define example_package.foo module object.
const mp_obj_module_t example_package_foo_user_cmodule = {
.base = { &mp_type_module },
.globals = (mp_obj_dict_t *)&example_package_foo_globals,
};
// Define example_package.f()
STATIC mp_obj_t example_package_f(void) {
mp_printf(&mp_plat_print, "example_package.f\n");
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_0(example_package_f_obj, example_package_f);
STATIC mp_obj_t example_package___init__(void) {
if (!MP_STATE_VM(example_package_initialised)) {
// __init__ for builtins is called each time the module is imported,
// so ensure that initialisation only happens once.
MP_STATE_VM(example_package_initialised) = true;
mp_printf(&mp_plat_print, "example_package.__init__\n");
}
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_0(example_package___init___obj, example_package___init__);
// The "initialised" state is stored on mp_state so that it is cleared on soft
// reset.
MP_REGISTER_ROOT_POINTER(int example_package_initialised);
// Define all attributes of the top-level package (example_package).
STATIC const mp_rom_map_elem_t example_package_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_example_package) },
{ MP_ROM_QSTR(MP_QSTR___init__), MP_ROM_PTR(&example_package___init___obj) },
{ MP_ROM_QSTR(MP_QSTR_foo), MP_ROM_PTR(&example_package_foo_user_cmodule) },
{ MP_ROM_QSTR(MP_QSTR_f), MP_ROM_PTR(&example_package_f_obj) },
};
STATIC MP_DEFINE_CONST_DICT(example_package_globals, example_package_globals_table);
// Define module object.
const mp_obj_module_t example_package_user_cmodule = {
.base = { &mp_type_module },
.globals = (mp_obj_dict_t *)&example_package_globals,
};
// Register the module to make it available in Python.
// Note: subpackages should not be registered with MP_REGISTER_MODULE.
MP_REGISTER_MODULE(MP_QSTR_example_package, example_package_user_cmodule);

View File

@ -0,0 +1,2 @@
Q(example_package.foo)
Q(example_package.foo.bar)

View File

@ -96,3 +96,20 @@ print(returns_NULL())
import frozentest
print(frozentest.__file__)
# test for builtin sub-packages
from example_package.foo import bar
print(bar)
bar.f()
import example_package
print(example_package, example_package.foo, example_package.foo.bar)
example_package.f()
example_package.foo.f()
example_package.foo.bar.f()
print(bar == example_package.foo.bar)
from example_package.foo import f as foo_f
foo_f()
print(foo_f == example_package.foo.f)

View File

@ -52,13 +52,14 @@ mport
builtins micropython _thread _uasyncio
btree cexample cmath cppexample
ffi framebuf gc math
termios uarray ubinascii ucollections
ucryptolib uctypes uerrno uhashlib
uheapq uio ujson umachine
uos urandom ure uselect
usocket ussl ustruct usys
utime utimeq uwebsocket uzlib
example_package ffi framebuf
gc math termios uarray
ubinascii ucollections ucryptolib uctypes
uerrno uhashlib uheapq uio
ujson umachine uos urandom
ure uselect usocket ussl
ustruct usys utime utimeq
uwebsocket uzlib
ime
utime utimeq
@ -211,3 +212,13 @@ b'bytes 1234\x01'
2
3
frozentest.py
example_package.__init__
<module 'example_package.foo.bar'>
example_package.foo.bar.f
<module 'example_package'> <module 'example_package.foo'> <module 'example_package.foo.bar'>
example_package.f
example_package.foo.f
example_package.foo.bar.f
True
example_package.foo.f
True