py: Add generic mp_not_implemented() func to use instead of assert().

Benefits: won't crash baremetal targets, will provide Python source location
when not implemented feature used (it will no longer provide C source
location, but just grep for error message).
diff --git a/py/emitglue.c b/py/emitglue.c
index a89ef67..732e4b5 100644
--- a/py/emitglue.c
+++ b/py/emitglue.c
@@ -120,7 +120,9 @@
     assert(def_args == MP_OBJ_NULL || MP_OBJ_IS_TYPE(def_args, &mp_type_tuple));
 
     // TODO implement default kw args
-    assert(def_kw_args == MP_OBJ_NULL);
+    if (def_kw_args != MP_OBJ_NULL) {
+        mp_not_implemented("Default values for kw-only args");
+    }
 
     // make the function, depending on the raw code kind
     mp_obj_t fun;
diff --git a/py/runtime.c b/py/runtime.c
index cdbf99d..179b48d 100644
--- a/py/runtime.c
+++ b/py/runtime.c
@@ -1150,6 +1150,10 @@
     nlr_raise((mp_obj_t)&mp_const_MemoryError_obj);
 }
 
+NORETURN void mp_not_implemented(const char *msg) {
+    nlr_raise(mp_obj_new_exception_msg(&mp_type_NotImplementedError, msg));
+}
+
 // these must correspond to the respective enum
 void *const mp_fun_table[MP_F_NUMBER_OF] = {
     mp_load_const_int,
diff --git a/py/runtime.h b/py/runtime.h
index dbd4131..fb61c01 100644
--- a/py/runtime.h
+++ b/py/runtime.h
@@ -112,6 +112,9 @@
 mp_obj_t mp_import_from(mp_obj_t module, qstr name);
 void mp_import_all(mp_obj_t module);
 
+// Raise NotImplementedError with given message
+NORETURN void mp_not_implemented(const char *msg);
+
 extern struct _mp_obj_list_t mp_sys_path_obj;
 extern struct _mp_obj_list_t mp_sys_argv_obj;
 #define mp_sys_path ((mp_obj_t)&mp_sys_path_obj)