From f380a91e7caecc08b92b754f37d73be8c2d43ad0 Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Sat, 26 Jun 2021 20:00:31 -0500 Subject: [PATCH 1/5] objtuple: Move mp_obj_is_tuple_compatible to obj.h. Signed-off-by: Jeff Epler --- py/obj.h | 2 ++ py/objtuple.c | 2 -- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/py/obj.h b/py/obj.h index 75caf459d4..da2ef08451 100644 --- a/py/obj.h +++ b/py/obj.h @@ -764,6 +764,8 @@ extern const struct _mp_obj_exception_t mp_const_GeneratorExit_obj; #define mp_obj_is_str_or_bytes(o) (mp_obj_is_qstr(o) || (mp_obj_is_obj(o) && ((mp_obj_base_t *)MP_OBJ_TO_PTR(o))->type->binary_op == mp_obj_str_binary_op)) #define mp_obj_is_dict_or_ordereddict(o) (mp_obj_is_obj(o) && ((mp_obj_base_t *)MP_OBJ_TO_PTR(o))->type->make_new == mp_obj_dict_make_new) #define mp_obj_is_fun(o) (mp_obj_is_obj(o) && (((mp_obj_base_t *)MP_OBJ_TO_PTR(o))->type->name == MP_QSTR_function)) +// type check is done on getiter method to allow tuple, namedtuple, attrtuple +#define mp_obj_is_tuple_compatible(o) (mp_obj_get_type(o)->getiter == mp_obj_tuple_getiter) mp_obj_t mp_obj_new_type(qstr name, mp_obj_t bases_tuple, mp_obj_t locals_dict); static inline mp_obj_t mp_obj_new_bool(mp_int_t x) { diff --git a/py/objtuple.c b/py/objtuple.c index bb4f79997c..414cf65c3b 100644 --- a/py/objtuple.c +++ b/py/objtuple.c @@ -34,8 +34,6 @@ #include "supervisor/shared/translate.h" -// type check is done on getiter method to allow tuple, namedtuple, attrtuple -#define mp_obj_is_tuple_compatible(o) (mp_obj_get_type(o)->getiter == mp_obj_tuple_getiter) /******************************************************************************/ /* tuple */ From 33482e0831ca553970080fdb6ac8c85d55352956 Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Sat, 26 Jun 2021 20:00:56 -0500 Subject: [PATCH 2/5] mp_obj_get_array: Work with namedtuple, attrtuple. Signed-off-by: Jeff Epler --- py/obj.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/py/obj.c b/py/obj.c index 9a81d65eca..d2483ed993 100644 --- a/py/obj.c +++ b/py/obj.c @@ -444,7 +444,7 @@ void mp_obj_get_complex(mp_obj_t arg, mp_float_t *real, mp_float_t *imag) { // note: returned value in *items may point to the interior of a GC block void mp_obj_get_array(mp_obj_t o, size_t *len, mp_obj_t **items) { - if (mp_obj_is_type(o, &mp_type_tuple)) { + if (mp_obj_is_tuple_compatible(o)) { mp_obj_tuple_get(o, len, items); } else if (mp_obj_is_type(o, &mp_type_list)) { mp_obj_list_get(o, len, items); From cac71a33fc62f05063417b61f6f2b0eea6e14437 Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Sat, 26 Jun 2021 20:01:19 -0500 Subject: [PATCH 3/5] time: Allow constructing a struct_time from another struct_time Closes: #4917 --- shared-bindings/time/__init__.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/shared-bindings/time/__init__.c b/shared-bindings/time/__init__.c index 87a40f6fc1..5e40d2774a 100644 --- a/shared-bindings/time/__init__.c +++ b/shared-bindings/time/__init__.c @@ -83,12 +83,10 @@ mp_obj_t struct_time_make_new(const mp_obj_type_t *type, size_t n_args, const mp if (n_args != 1 || (kw_args != NULL && kw_args->used > 0)) { return namedtuple_make_new(type, n_args, args, kw_args); } - if (mp_obj_get_type(args[0])->getiter != mp_obj_tuple_getiter || ((mp_obj_tuple_t *)MP_OBJ_TO_PTR(args[0]))->len != 9) { - mp_raise_TypeError(translate("time.struct_time() takes a 9-sequence")); - } - - mp_obj_tuple_t *tuple = MP_OBJ_TO_PTR(args[0]); - return namedtuple_make_new(type, 9, tuple->items, NULL); + size_t len; + mp_obj_t *items; + mp_obj_get_array(args[0], &len, &items); + return namedtuple_make_new(type, len, items, NULL); } //| class struct_time: From 3dcd603e39a63248b84a823207c3200b7b23e623 Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Mon, 28 Jun 2021 19:27:14 -0500 Subject: [PATCH 4/5] time: Fix and better document time.struct_time constructor INCOMPATIBLE CHANGE: struct_time(1,2,3,4,5,6,7,8,9) is now _rejected_ just as on standad Python. This incorrect constructor was added by me in #2327; I assumed without even checking that the `struct_time` constructor was also compatible with the `namedtuple` constructor, but it is not and has always been rejected by standard Python (checked 2.7 and 3.9) This commit restores the specific error message that we used for this purpose, which was removed in the previous commit either out of laziness or out of trying to reduce unneeded error strings. In this case, the alternate string is too misleading (it refers to arguments, not to sequence elements) so let's put the better message back. --- shared-bindings/time/__init__.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/shared-bindings/time/__init__.c b/shared-bindings/time/__init__.c index 5e40d2774a..a2eeee6cef 100644 --- a/shared-bindings/time/__init__.c +++ b/shared-bindings/time/__init__.c @@ -80,20 +80,21 @@ MP_DEFINE_CONST_FUN_OBJ_1(time_sleep_obj, time_sleep); #if MICROPY_PY_COLLECTIONS mp_obj_t struct_time_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *args, mp_map_t *kw_args) { - if (n_args != 1 || (kw_args != NULL && kw_args->used > 0)) { - return namedtuple_make_new(type, n_args, args, kw_args); - } + mp_arg_check_num(n_args, kw_args, 1, 1, false); size_t len; mp_obj_t *items; mp_obj_get_array(args[0], &len, &items); + if (len != 9) { + mp_raise_TypeError(translate("time.struct_time() takes a 9-sequence")); + } return namedtuple_make_new(type, len, items, NULL); } //| class struct_time: -//| def __init__(self, time_tuple: Tuple[int, int, int, int, int, int, int, int, int]) -> None: -//| """Structure used to capture a date and time. Note that it takes a tuple! +//| def __init__(self, time_tuple: Sequence) -> None: +//| """Structure used to capture a date and time. Can be constructed from a `struct_time`, `tuple`, `list`, or `namedtuple` with 9 elements. //| -//| :param tuple time_tuple: Tuple of time info: ``(tm_year, tm_mon, tm_mday, tm_hour, tm_min, tm_sec, tm_wday, tm_yday, tm_isdst)`` +//| :param Sequence time_tuple: Sequence of time info: ``(tm_year, tm_mon, tm_mday, tm_hour, tm_min, tm_sec, tm_wday, tm_yday, tm_isdst)`` //| //| * ``tm_year``: the year, 2017 for example //| * ``tm_mon``: the month, range [1, 12] From fd681ca70a6c0e5d855f9476e095da62db07a19c Mon Sep 17 00:00:00 2001 From: microDev <70126934+microDev1@users.noreply.github.com> Date: Tue, 29 Jun 2021 08:11:16 +0530 Subject: [PATCH 5/5] minor fix for struct_time docs --- shared-bindings/time/__init__.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shared-bindings/time/__init__.c b/shared-bindings/time/__init__.c index a2eeee6cef..03f4fac0dc 100644 --- a/shared-bindings/time/__init__.c +++ b/shared-bindings/time/__init__.c @@ -91,7 +91,7 @@ mp_obj_t struct_time_make_new(const mp_obj_type_t *type, size_t n_args, const mp } //| class struct_time: -//| def __init__(self, time_tuple: Sequence) -> None: +//| def __init__(self, time_tuple: Sequence[int]) -> None: //| """Structure used to capture a date and time. Can be constructed from a `struct_time`, `tuple`, `list`, or `namedtuple` with 9 elements. //| //| :param Sequence time_tuple: Sequence of time info: ``(tm_year, tm_mon, tm_mday, tm_hour, tm_min, tm_sec, tm_wday, tm_yday, tm_isdst)``