From 2f5d113fad4ca2b22b084ccaf835c595cd6a7a4e Mon Sep 17 00:00:00 2001
From: Paul Sokolovsky <pfalcon@users.sourceforge.net>
Date: Fri, 21 Dec 2018 14:20:55 +0300
Subject: [PATCH] py/warning: Support categories for warnings.

Python defines warnings as belonging to categories, where category is a
warning type (descending from exception type). This is useful, as e.g.
allows to disable warnings selectively and provide user-defined warning
types.  So, implement this in MicroPython, except that categories are
represented just with strings.  However, enough hooks are left to implement
categories differently per-port (e.g. as types), without need to patch each
and every usage.
---
 extmod/modlwip.c                   |  2 +-
 ports/unix/mpconfigport_coverage.h |  1 +
 ports/zephyr/modusocket.c          |  2 +-
 py/mpconfig.h                      | 16 ++++++++++++++++
 py/obj.c                           |  2 +-
 py/runtime.h                       |  4 +++-
 py/vm.c                            |  2 +-
 py/warning.c                       | 11 ++++++++---
 8 files changed, 32 insertions(+), 8 deletions(-)

diff --git a/extmod/modlwip.c b/extmod/modlwip.c
index 84a1bd3c1..d76fd1b1e 100644
--- a/extmod/modlwip.c
+++ b/extmod/modlwip.c
@@ -1454,7 +1454,7 @@ STATIC mp_obj_t lwip_getaddrinfo(size_t n_args, const mp_obj_t *args) {
             && (type == 0 || type == MOD_NETWORK_SOCK_STREAM)
             && proto == 0
             && flags == 0)) {
-            mp_warning("unsupported getaddrinfo constraints");
+            mp_warning(MP_WARN_CAT(RuntimeWarning), "unsupported getaddrinfo constraints");
         }
     }
 
diff --git a/ports/unix/mpconfigport_coverage.h b/ports/unix/mpconfigport_coverage.h
index 2519482b0..87bf8454c 100644
--- a/ports/unix/mpconfigport_coverage.h
+++ b/ports/unix/mpconfigport_coverage.h
@@ -36,6 +36,7 @@
 #define MICROPY_FLOAT_HIGH_QUALITY_HASH (1)
 #define MICROPY_ENABLE_SCHEDULER       (1)
 #define MICROPY_READER_VFS             (1)
+#define MICROPY_WARNINGS_CATEGORY      (1)
 #define MICROPY_MODULE_GETATTR         (1)
 #define MICROPY_PY_DELATTR_SETATTR     (1)
 #define MICROPY_PY_REVERSE_SPECIAL_METHODS (1)
diff --git a/ports/zephyr/modusocket.c b/ports/zephyr/modusocket.c
index 84d6fa729..083083788 100644
--- a/ports/zephyr/modusocket.c
+++ b/ports/zephyr/modusocket.c
@@ -288,7 +288,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_recv_obj, socket_recv);
 
 STATIC mp_obj_t socket_setsockopt(size_t n_args, const mp_obj_t *args) {
     (void)n_args; // always 4
-    mp_warning("setsockopt() not implemented");
+    mp_warning(MP_WARN_CAT(RuntimeWarning), "setsockopt() not implemented");
     return mp_const_none;
 }
 STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(socket_setsockopt_obj, 4, 4, socket_setsockopt);
diff --git a/py/mpconfig.h b/py/mpconfig.h
index 48427c3e5..4fd08db23 100644
--- a/py/mpconfig.h
+++ b/py/mpconfig.h
@@ -598,6 +598,11 @@ typedef long long mp_longint_impl_t;
 #define MICROPY_WARNINGS (0)
 #endif
 
+// Whether to support warning categories
+#ifndef MICROPY_WARNINGS_CATEGORY
+#define MICROPY_WARNINGS_CATEGORY (0)
+#endif
+
 // This macro is used when printing runtime warnings and errors
 #ifndef MICROPY_ERROR_PRINTER
 #define MICROPY_ERROR_PRINTER (&mp_plat_print)
@@ -1508,4 +1513,15 @@ typedef double mp_float_t;
 #endif
 #endif
 
+// Warning categories are by default implemented as strings, though
+// hook is left for a port to define them as something else.
+#if MICROPY_WARNINGS_CATEGORY
+# ifndef MP_WARN_CAT
+# define MP_WARN_CAT(x) #x
+# endif
+#else
+# undef MP_WARN_CAT
+# define MP_WARN_CAT(x) (NULL)
+#endif
+
 #endif // MICROPY_INCLUDED_PY_MPCONFIG_H
diff --git a/py/obj.c b/py/obj.c
index 47b7d15ae..7007d5070 100644
--- a/py/obj.c
+++ b/py/obj.c
@@ -202,7 +202,7 @@ bool mp_obj_equal(mp_obj_t o1, mp_obj_t o2) {
     str_cmp_err:
         #if MICROPY_PY_STR_BYTES_CMP_WARN
         if (MP_OBJ_IS_TYPE(o1, &mp_type_bytes) || MP_OBJ_IS_TYPE(o2, &mp_type_bytes)) {
-            mp_warning("Comparison between bytes and str");
+            mp_warning(MP_WARN_CAT(BytesWarning), "Comparison between bytes and str");
         }
         #endif
         return false;
diff --git a/py/runtime.h b/py/runtime.h
index dd4c9a984..9811c1b5a 100644
--- a/py/runtime.h
+++ b/py/runtime.h
@@ -179,7 +179,9 @@ void mp_native_raise(mp_obj_t o);
 #define mp_sys_argv (MP_OBJ_FROM_PTR(&MP_STATE_VM(mp_sys_argv_obj)))
 
 #if MICROPY_WARNINGS
-void mp_warning(const char *msg, ...);
+#ifndef mp_warning
+void mp_warning(const char *category, const char *msg, ...);
+#endif
 #else
 #define mp_warning(...)
 #endif
diff --git a/py/vm.c b/py/vm.c
index f9f9a3d6a..fce59349f 100644
--- a/py/vm.c
+++ b/py/vm.c
@@ -1116,7 +1116,7 @@ unwind_return:
                     mp_uint_t unum = *ip;
                     mp_obj_t obj;
                     if (unum == 2) {
-                        mp_warning("exception chaining not supported");
+                        mp_warning(NULL, "exception chaining not supported");
                         // ignore (pop) "from" argument
                         sp--;
                     }
diff --git a/py/warning.c b/py/warning.c
index 12d0f9c99..ebaf2d078 100644
--- a/py/warning.c
+++ b/py/warning.c
@@ -32,10 +32,15 @@
 
 #if MICROPY_WARNINGS
 
-void mp_warning(const char *msg, ...) {
+void mp_warning(const char *category, const char *msg, ...) {
+    if (category == NULL) {
+        category = "Warning";
+    }
+    mp_print_str(MICROPY_ERROR_PRINTER, category);
+    mp_print_str(MICROPY_ERROR_PRINTER, ": ");
+
     va_list args;
     va_start(args, msg);
-    mp_print_str(MICROPY_ERROR_PRINTER, "Warning: ");
     mp_vprintf(MICROPY_ERROR_PRINTER, msg, args);
     mp_print_str(MICROPY_ERROR_PRINTER, "\n");
     va_end(args);
@@ -43,7 +48,7 @@ void mp_warning(const char *msg, ...) {
 
 void mp_emitter_warning(pass_kind_t pass, const char *msg) {
     if (pass == MP_PASS_CODE_SIZE) {
-        mp_warning(msg, NULL);
+        mp_warning(NULL, msg);
     }
 }
 
-- 
GitLab