Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit88a3d7b

Browse files
committed
py/runtime.c: Add support for using __all__ in star import.
When the symbol __all__ is defined in a module, mp_import_allshould import all listed symbols into the global environment,rather than relying on the underscore-is-private default.This is the standard in CPython.Each item is loaded in the same way as if it wouldbe an explicit import statement, and will invokethe module's __getattr__ function if needed. Thisprovides a straightforward solution for fixing starimport of modules using a dynamic loader, such asextmod/asyncio (see issue#7266).This improvement has been enabled at BASIC_FEATURES level,to avoid impacting devices with limited ressources, forwhich star import is of little use anyway.Additionally, detailled reporting of errors during __all__import has been implemented to match CPython, but this isonly enabled when ERROR_REPORTING is set toMICROPY_ERROR_REPORTING_DETAILED.Signed-off-by: Yoctopuce dev <dev@yoctopuce.com>
1 parent9ef16b4 commit88a3d7b

File tree

7 files changed

+160
-1
lines changed

7 files changed

+160
-1
lines changed

‎py/mpconfig.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -603,6 +603,11 @@
603603
#defineMICROPY_ENABLE_EXTERNAL_IMPORT (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_CORE_FEATURES)
604604
#endif
605605

606+
// Whether to enable parsing __all__ when importing all public symbols from modules
607+
#ifndefMICROPY_ENABLE_MODULE_ALL
608+
#defineMICROPY_ENABLE_MODULE_ALL (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_BASIC_FEATURES)
609+
#endif
610+
606611
// Whether to use the POSIX reader for importing files
607612
#ifndefMICROPY_READER_POSIX
608613
#defineMICROPY_READER_POSIX (0)

‎py/runtime.c

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1247,6 +1247,19 @@ void mp_load_method(mp_obj_t base, qstr attr, mp_obj_t *dest) {
12471247
mp_raise_msg_varg(&mp_type_AttributeError,
12481248
MP_ERROR_TEXT("type object '%q' has no attribute '%q'"),
12491249
((mp_obj_type_t*)MP_OBJ_TO_PTR(base))->name,attr);
1250+
#ifMICROPY_ERROR_REPORTING >=MICROPY_ERROR_REPORTING_DETAILED
1251+
}elseif (mp_obj_is_type(base,&mp_type_module)) {
1252+
// report errors in __all__ as done by CPython
1253+
mp_obj_tdest_name[2];
1254+
qstrmodule_name=MP_QSTR_;
1255+
mp_load_method_maybe(base,MP_QSTR___name__,dest_name);
1256+
if (mp_obj_is_qstr(dest_name[0])) {
1257+
module_name=mp_obj_str_get_qstr(dest_name[0]);
1258+
}
1259+
mp_raise_msg_varg(&mp_type_AttributeError,
1260+
MP_ERROR_TEXT("module '%q' has no attribute '%q'"),
1261+
module_name,attr);
1262+
#endif
12501263
}else {
12511264
mp_raise_msg_varg(&mp_type_AttributeError,
12521265
MP_ERROR_TEXT("'%s' object has no attribute '%q'"),
@@ -1593,8 +1606,28 @@ mp_obj_t mp_import_from(mp_obj_t module, qstr name) {
15931606
voidmp_import_all(mp_obj_tmodule) {
15941607
DEBUG_printf("import all %p\n",module);
15951608

1596-
// TODO: Support __all__
15971609
mp_map_t*map=&mp_obj_module_get_globals(module)->map;
1610+
1611+
#ifMICROPY_ENABLE_MODULE_ALL
1612+
mp_map_elem_t*elem=mp_map_lookup(map,MP_OBJ_NEW_QSTR(MP_QSTR___all__),MP_MAP_LOOKUP);
1613+
if (elem!=NULL&&mp_obj_is_type(elem->value,&mp_type_list)) {
1614+
// When __all__ is defined, we must explicitly load all specified
1615+
// symbols, possibly invoking the module __getattr__ function
1616+
size_tlen;
1617+
mp_obj_t*items;
1618+
mp_obj_list_get(elem->value,&len,&items);
1619+
for (size_ti=0;i<len;i++) {
1620+
qstrqname=mp_obj_str_get_qstr(items[i]);
1621+
mp_obj_tdest[2];
1622+
mp_load_method(module,qname,dest);
1623+
mp_store_name(qname,dest[0]);
1624+
}
1625+
return;
1626+
}
1627+
#endif
1628+
1629+
// By default, the set of public names includes all names found in the module's
1630+
// namespace which do not begin with an underscore character ('_')
15981631
for (size_ti=0;i<map->alloc;i++) {
15991632
if (mp_map_slot_is_filled(map,i)) {
16001633
// Entry in module global scope may be generated programmatically

‎tests/import/import_star.py

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
# test `from package import *` conventions, including __all__ support
2+
#
3+
# This test requires MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_BASIC_FEATURES
4+
5+
try:
6+
next(iter([]),42)
7+
exceptTypeError:
8+
# 2-argument version of next() not supported
9+
# we are probably not at MICROPY_CONFIG_ROM_LEVEL_BASIC_FEATURES
10+
print('SKIP')
11+
raiseSystemExit
12+
13+
# 1. test default visibility
14+
frompkgstar_defimport*
15+
16+
print('visibleFun'inglobals())
17+
print('VisibleClass'inglobals())
18+
print('_hiddenFun'inglobals())
19+
print('_HiddenClass'inglobals())
20+
print(visibleFun())
21+
22+
# 2. test explicit visibility as defined by __all__
23+
frompkgstar_allimport*
24+
25+
print('publicFun'inglobals())
26+
print('PublicClass'inglobals())
27+
print('unlistedFun'inglobals())
28+
print('UnlistedClass'inglobals())
29+
print('_privateFun'inglobals())
30+
print('_PrivateClass'inglobals())
31+
print(publicFun())
32+
# test dynamic import as used in asyncio
33+
print('dynamicFun'inglobals())
34+
print(dynamicFun())
35+
36+
# 3. test reporting of bad entries in __all__
37+
try:
38+
frompkgstar_badimport*
39+
40+
print("missed detection of incorrect __all__ definition")
41+
exceptAttributeErroraser:
42+
print("AttributeError triggered for bad __all__ definition")

‎tests/import/pkgstar_all/__init__.py

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
__all__= ['publicFun','PublicClass','dynamicFun']
2+
3+
4+
# Definitions below should always be imported by a star import
5+
defpublicFun():
6+
return1
7+
8+
9+
classPublicClass:
10+
def__init__(self):
11+
self._val=1
12+
13+
14+
# If __all__ support is enabled, definitions below
15+
# should not be imported by a star import
16+
defunlistedFun():
17+
return0
18+
19+
20+
classUnlistedClass:
21+
def__init__(self):
22+
self._val=0
23+
24+
25+
# Definitions below should be not be imported by a star import
26+
# (they start with an underscore, and are not listed in __all__)
27+
def_privateFun():
28+
return-1
29+
30+
31+
class_PrivateClass:
32+
def__init__(self):
33+
self._val=-1
34+
35+
36+
# Test lazy loaded function, as used by extmod/asyncio:
37+
# Works with a star import only if __all__ support is enabled
38+
_attrs= {
39+
"dynamicFun":"funcs",
40+
}
41+
42+
43+
def__getattr__(attr):
44+
mod=_attrs.get(attr,None)
45+
ifmodisNone:
46+
raiseAttributeError(attr)
47+
value=getattr(__import__(mod,globals(),locals(),True,1),attr)
48+
globals()[attr]=value
49+
returnvalue

‎tests/import/pkgstar_all/funcs.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
defdynamicFun():
2+
return777

‎tests/import/pkgstar_bad/__init__.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
__all__= ['existingFun','missingFun']
2+
3+
4+
defexistingFun():
5+
returnNone
6+
7+
8+
# missingFun is not defined, should raise an error on import

‎tests/import/pkgstar_def/__init__.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
# When __all__ is undefined, star import should only
2+
# show objects that do not start with an underscore
3+
4+
5+
defvisibleFun():
6+
return42
7+
8+
9+
classVisibleClass:
10+
def__init__(self):
11+
self._val=42
12+
13+
14+
def_hiddenFun():
15+
return-1
16+
17+
18+
class_HiddenClass:
19+
def__init__(self):
20+
self._val=-1

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp