Skip to content

Commit

Permalink
examples/usercmodule: Add a sub-package example.
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
jimmo authored and dpgeorge committed Jun 1, 2023
1 parent 6a8114e commit 5e04521
Show file tree
Hide file tree
Showing 10 changed files with 156 additions and 13 deletions.
2 changes: 1 addition & 1 deletion examples/usercmodule/cexample/examplemodule.c
Expand Up @@ -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
Expand Down
7 changes: 3 additions & 4 deletions examples/usercmodule/cexample/micropython.mk
@@ -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)
2 changes: 1 addition & 1 deletion examples/usercmodule/cppexample/examplemodule.c
Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions examples/usercmodule/subpackage/README.md
@@ -0,0 +1 @@
This is an example of a user C module that includes subpackages.
19 changes: 19 additions & 0 deletions examples/usercmodule/subpackage/micropython.cmake
@@ -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)
10 changes: 10 additions & 0 deletions examples/usercmodule/subpackage/micropython.mk
@@ -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
84 changes: 84 additions & 0 deletions examples/usercmodule/subpackage/modexamplepackage.c
@@ -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);
2 changes: 2 additions & 0 deletions examples/usercmodule/subpackage/qstrdefsexamplepackage.h
@@ -0,0 +1,2 @@
Q(example_package.foo)
Q(example_package.foo.bar)
17 changes: 17 additions & 0 deletions tests/unix/extra_coverage.py
Expand Up @@ -96,3 +96,20 @@
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)
25 changes: 18 additions & 7 deletions tests/unix/extra_coverage.py.exp
Expand Up @@ -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
Expand Down Expand Up @@ -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

0 comments on commit 5e04521

Please sign in to comment.