summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYoctopuce dev <dev@yoctopuce.com>2025-03-20 12:03:59 +0100
committerDamien George <damien@micropython.org>2025-04-21 17:37:39 +1000
commit0d2c18c299936a34cdeb43e2ef9cbdaecb35c610 (patch)
tree3ad96985de946fc79a95de3b7dfb481cb7bec79b
parent8faa6bafdc76a6ee307551ef4d88fd2d54db04b2 (diff)
py/objstr: Fix handling of OP_MODULO with namedtuple.
This fix handles attrtuple as well, eg. os.uname(). A test case has been added in basics/attrtuple2.py. Fixes issue #16969. Signed-off-by: Yoctopuce dev <dev@yoctopuce.com>
-rw-r--r--py/objstr.c4
-rw-r--r--py/objtuple.c3
-rw-r--r--py/objtuple.h3
-rw-r--r--tests/basics/attrtuple2.py25
-rw-r--r--tests/basics/namedtuple1.py3
5 files changed, 33 insertions, 5 deletions
diff --git a/py/objstr.c b/py/objstr.c
index 307e956a1..a160ab415 100644
--- a/py/objstr.c
+++ b/py/objstr.c
@@ -33,6 +33,7 @@
#include "py/objlist.h"
#include "py/runtime.h"
#include "py/cstack.h"
+#include "py/objtuple.h"
#if MICROPY_PY_BUILTINS_STR_OP_MODULO
static mp_obj_t str_modulo_format(mp_obj_t pattern, size_t n_args, const mp_obj_t *args, mp_obj_t dict);
@@ -357,8 +358,7 @@ mp_obj_t mp_obj_str_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs_i
mp_obj_t *args = &rhs_in;
size_t n_args = 1;
mp_obj_t dict = MP_OBJ_NULL;
- if (mp_obj_is_type(rhs_in, &mp_type_tuple)) {
- // TODO: Support tuple subclasses?
+ if (mp_obj_is_tuple_compatible(rhs_in)) {
mp_obj_tuple_get(rhs_in, &n_args, &args);
} else if (mp_obj_is_type(rhs_in, &mp_type_dict)) {
dict = rhs_in;
diff --git a/py/objtuple.c b/py/objtuple.c
index 2cbcc0e50..a8bd11c7e 100644
--- a/py/objtuple.c
+++ b/py/objtuple.c
@@ -31,9 +31,6 @@
#include "py/objtuple.h"
#include "py/runtime.h"
-// type check is done on getiter method to allow tuple, namedtuple, attrtuple
-#define mp_obj_is_tuple_compatible(o) (MP_OBJ_TYPE_GET_SLOT_OR_NULL(mp_obj_get_type(o), iter) == mp_obj_tuple_getiter)
-
/******************************************************************************/
/* tuple */
diff --git a/py/objtuple.h b/py/objtuple.h
index cc42aa6df..034814b82 100644
--- a/py/objtuple.h
+++ b/py/objtuple.h
@@ -61,4 +61,7 @@ void mp_obj_attrtuple_print_helper(const mp_print_t *print, const qstr *fields,
mp_obj_t mp_obj_new_attrtuple(const qstr *fields, size_t n, const mp_obj_t *items);
+// type check is done on getiter method to allow tuple, namedtuple, attrtuple
+#define mp_obj_is_tuple_compatible(o) (MP_OBJ_TYPE_GET_SLOT_OR_NULL(mp_obj_get_type(o), iter) == mp_obj_tuple_getiter)
+
#endif // MICROPY_INCLUDED_PY_OBJTUPLE_H
diff --git a/tests/basics/attrtuple2.py b/tests/basics/attrtuple2.py
new file mode 100644
index 000000000..081d24b6a
--- /dev/null
+++ b/tests/basics/attrtuple2.py
@@ -0,0 +1,25 @@
+# test os.uname() attrtuple, if available
+try:
+ import os
+except ImportError:
+ print("SKIP")
+ raise SystemExit
+
+try:
+ u = os.uname()
+except AttributeError:
+ print("SKIP")
+ raise SystemExit
+
+# test printing of attrtuple
+print(str(u).find("machine=") > 0)
+
+# test read attr
+print(isinstance(u.machine, str))
+
+# test str modulo operator for attrtuple
+impl_str = ("%s " * len(u)) % u
+test_str = ""
+for val in u:
+ test_str += val + " "
+print(impl_str == test_str)
diff --git a/tests/basics/namedtuple1.py b/tests/basics/namedtuple1.py
index 362c60583..b9689b584 100644
--- a/tests/basics/namedtuple1.py
+++ b/tests/basics/namedtuple1.py
@@ -21,6 +21,9 @@ for t in T(1, 2), T(bar=1, foo=2):
print(isinstance(t, tuple))
+ # a NamedTuple can be used as a tuple
+ print("(%d, %d)" % t)
+
# Check tuple can compare equal to namedtuple with same elements
print(t == (t[0], t[1]), (t[0], t[1]) == t)