Skip to content

Commit 5e04521

Browse files
jimmodpgeorge
authored andcommitted
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>
1 parent 6a8114e commit 5e04521

10 files changed

Lines changed: 156 additions & 13 deletions

File tree

examples/usercmodule/cexample/examplemodule.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ MP_DEFINE_CONST_OBJ_TYPE(
6868
locals_dict, &example_Timer_locals_dict
6969
);
7070

71-
// Define all properties of the module.
71+
// Define all attributes of the module.
7272
// Table entries are key/value pairs of the attribute name (a string)
7373
// and the MicroPython object reference.
7474
// All identifiers and strings are written as MP_QSTR_xxx and will be
Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
1-
EXAMPLE_MOD_DIR := $(USERMOD_DIR)
1+
CEXAMPLE_MOD_DIR := $(USERMOD_DIR)
22

33
# Add all C files to SRC_USERMOD.
4-
SRC_USERMOD += $(EXAMPLE_MOD_DIR)/examplemodule.c
4+
SRC_USERMOD += $(CEXAMPLE_MOD_DIR)/examplemodule.c
55

66
# We can add our module folder to include paths if needed
77
# This is not actually needed in this example.
8-
CFLAGS_USERMOD += -I$(EXAMPLE_MOD_DIR)
9-
CEXAMPLE_MOD_DIR := $(USERMOD_DIR)
8+
CFLAGS_USERMOD += -I$(CEXAMPLE_MOD_DIR)

examples/usercmodule/cppexample/examplemodule.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
// See example.cpp for the definition.
55
STATIC MP_DEFINE_CONST_FUN_OBJ_2(cppfunc_obj, cppfunc);
66

7-
// Define all properties of the module.
7+
// Define all attributes of the module.
88
// Table entries are key/value pairs of the attribute name (a string)
99
// and the MicroPython object reference.
1010
// All identifiers and strings are written as MP_QSTR_xxx and will be
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
This is an example of a user C module that includes subpackages.
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# Create an INTERFACE library for our C module.
2+
add_library(usermod_subpackage_example INTERFACE)
3+
4+
# Add our source files to the lib
5+
target_sources(usermod_subpackage_example INTERFACE
6+
${CMAKE_CURRENT_LIST_DIR}/examplemodule.c
7+
)
8+
9+
# Add the current directory as an include directory.
10+
target_include_directories(usermod_subpackage_example INTERFACE
11+
${CMAKE_CURRENT_LIST_DIR}
12+
)
13+
14+
target_compile_definitions(usermod_subpackage_example INTERFACE
15+
MICROPY_MODULE_BUILTIN_SUBPACKAGES=1
16+
)
17+
18+
# Link our INTERFACE library to the usermod target.
19+
target_link_libraries(usermod INTERFACE usermod_subpackage_example)
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
SUBPACKAGE_EXAMPLE_MOD_DIR := $(USERMOD_DIR)
2+
3+
# Add all C files to SRC_USERMOD.
4+
SRC_USERMOD += $(SUBPACKAGE_EXAMPLE_MOD_DIR)/modexamplepackage.c
5+
6+
# We can add our module folder to include paths if needed
7+
# This is not actually needed in this example.
8+
CFLAGS_USERMOD += -I$(SUBPACKAGE_EXAMPLE_MOD_DIR) -DMICROPY_MODULE_BUILTIN_SUBPACKAGES=1
9+
10+
QSTR_DEFS += $(SUBPACKAGE_EXAMPLE_MOD_DIR)/qstrdefsexamplepackage.h
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
// Include MicroPython API.
2+
#include "py/runtime.h"
3+
4+
// Define example_package.foo.bar.f()
5+
STATIC mp_obj_t example_package_foo_bar_f(void) {
6+
mp_printf(&mp_plat_print, "example_package.foo.bar.f\n");
7+
return mp_const_none;
8+
}
9+
STATIC MP_DEFINE_CONST_FUN_OBJ_0(example_package_foo_bar_f_obj, example_package_foo_bar_f);
10+
11+
// Define all attributes of the second-level sub-package (example_package.foo.bar).
12+
STATIC const mp_rom_map_elem_t example_package_foo_bar_globals_table[] = {
13+
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_example_package_dot_foo_dot_bar) },
14+
{ MP_ROM_QSTR(MP_QSTR_f), MP_ROM_PTR(&example_package_foo_bar_f_obj) },
15+
};
16+
STATIC MP_DEFINE_CONST_DICT(example_package_foo_bar_globals, example_package_foo_bar_globals_table);
17+
18+
// Define example_package.foo.bar module object.
19+
const mp_obj_module_t example_package_foo_bar_user_cmodule = {
20+
.base = { &mp_type_module },
21+
.globals = (mp_obj_dict_t *)&example_package_foo_bar_globals,
22+
};
23+
24+
// Define example_package.foo.f()
25+
STATIC mp_obj_t example_package_foo_f(void) {
26+
mp_printf(&mp_plat_print, "example_package.foo.f\n");
27+
return mp_const_none;
28+
}
29+
STATIC MP_DEFINE_CONST_FUN_OBJ_0(example_package_foo_f_obj, example_package_foo_f);
30+
31+
// Define all attributes of the first-level sub-package (example_package.foo).
32+
STATIC const mp_rom_map_elem_t example_package_foo_globals_table[] = {
33+
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_example_package_dot_foo) },
34+
{ MP_ROM_QSTR(MP_QSTR_bar), MP_ROM_PTR(&example_package_foo_bar_user_cmodule) },
35+
{ MP_ROM_QSTR(MP_QSTR_f), MP_ROM_PTR(&example_package_foo_f_obj) },
36+
};
37+
STATIC MP_DEFINE_CONST_DICT(example_package_foo_globals, example_package_foo_globals_table);
38+
39+
// Define example_package.foo module object.
40+
const mp_obj_module_t example_package_foo_user_cmodule = {
41+
.base = { &mp_type_module },
42+
.globals = (mp_obj_dict_t *)&example_package_foo_globals,
43+
};
44+
45+
// Define example_package.f()
46+
STATIC mp_obj_t example_package_f(void) {
47+
mp_printf(&mp_plat_print, "example_package.f\n");
48+
return mp_const_none;
49+
}
50+
STATIC MP_DEFINE_CONST_FUN_OBJ_0(example_package_f_obj, example_package_f);
51+
52+
STATIC mp_obj_t example_package___init__(void) {
53+
if (!MP_STATE_VM(example_package_initialised)) {
54+
// __init__ for builtins is called each time the module is imported,
55+
// so ensure that initialisation only happens once.
56+
MP_STATE_VM(example_package_initialised) = true;
57+
mp_printf(&mp_plat_print, "example_package.__init__\n");
58+
}
59+
return mp_const_none;
60+
}
61+
STATIC MP_DEFINE_CONST_FUN_OBJ_0(example_package___init___obj, example_package___init__);
62+
63+
// The "initialised" state is stored on mp_state so that it is cleared on soft
64+
// reset.
65+
MP_REGISTER_ROOT_POINTER(int example_package_initialised);
66+
67+
// Define all attributes of the top-level package (example_package).
68+
STATIC const mp_rom_map_elem_t example_package_globals_table[] = {
69+
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_example_package) },
70+
{ MP_ROM_QSTR(MP_QSTR___init__), MP_ROM_PTR(&example_package___init___obj) },
71+
{ MP_ROM_QSTR(MP_QSTR_foo), MP_ROM_PTR(&example_package_foo_user_cmodule) },
72+
{ MP_ROM_QSTR(MP_QSTR_f), MP_ROM_PTR(&example_package_f_obj) },
73+
};
74+
STATIC MP_DEFINE_CONST_DICT(example_package_globals, example_package_globals_table);
75+
76+
// Define module object.
77+
const mp_obj_module_t example_package_user_cmodule = {
78+
.base = { &mp_type_module },
79+
.globals = (mp_obj_dict_t *)&example_package_globals,
80+
};
81+
82+
// Register the module to make it available in Python.
83+
// Note: subpackages should not be registered with MP_REGISTER_MODULE.
84+
MP_REGISTER_MODULE(MP_QSTR_example_package, example_package_user_cmodule);
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Q(example_package.foo)
2+
Q(example_package.foo.bar)

tests/unix/extra_coverage.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,3 +96,20 @@
9696
import frozentest
9797

9898
print(frozentest.__file__)
99+
100+
# test for builtin sub-packages
101+
from example_package.foo import bar
102+
103+
print(bar)
104+
bar.f()
105+
import example_package
106+
107+
print(example_package, example_package.foo, example_package.foo.bar)
108+
example_package.f()
109+
example_package.foo.f()
110+
example_package.foo.bar.f()
111+
print(bar == example_package.foo.bar)
112+
from example_package.foo import f as foo_f
113+
114+
foo_f()
115+
print(foo_f == example_package.foo.f)

tests/unix/extra_coverage.py.exp

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -52,13 +52,14 @@ mport
5252

5353
builtins micropython _thread _uasyncio
5454
btree cexample cmath cppexample
55-
ffi framebuf gc math
56-
termios uarray ubinascii ucollections
57-
ucryptolib uctypes uerrno uhashlib
58-
uheapq uio ujson umachine
59-
uos urandom ure uselect
60-
usocket ussl ustruct usys
61-
utime utimeq uwebsocket uzlib
55+
example_package ffi framebuf
56+
gc math termios uarray
57+
ubinascii ucollections ucryptolib uctypes
58+
uerrno uhashlib uheapq uio
59+
ujson umachine uos urandom
60+
ure uselect usocket ussl
61+
ustruct usys utime utimeq
62+
uwebsocket uzlib
6263
ime
6364

6465
utime utimeq
@@ -211,3 +212,13 @@ b'bytes 1234\x01'
211212
2
212213
3
213214
frozentest.py
215+
example_package.__init__
216+
<module 'example_package.foo.bar'>
217+
example_package.foo.bar.f
218+
<module 'example_package'> <module 'example_package.foo'> <module 'example_package.foo.bar'>
219+
example_package.f
220+
example_package.foo.f
221+
example_package.foo.bar.f
222+
True
223+
example_package.foo.f
224+
True

0 commit comments

Comments
 (0)