chore(vendor): bump micropython to 1.19.1

Relevant micropython commits:
  01374d941f9d7398e35990b574769b20c6779457 py/mpconfig.h: Define initial templates for "feature levels".
  7b89ad8dbf432ab51eea6d138e179bf51394c786 py/vm: Add a fast path for LOAD_ATTR on instance types.
  68219a295c75457c096ac42dbe8411b84e1e1a51 stm32: Enable LOAD_ATTR fast path, and map lookup caching on >M0.
  e0bf4611c3a8b23b3c52e6a7804aac341ac3a87d py: Only search frozen modules when '.frozen' is found in sys.path.
  f2040bfc7ee033e48acef9f289790f3b4e6b74e5 py: Rework bytecode and .mpy file format to be mostly static data.
  926b554dafffa1e9bd80aa12fea5c621221c9d79 extmod/moduos: Create general uos module to be used by all ports.
  2b409ef8a46015f8f3bd20bc44e644637dbe9bd3 unix/moduos: Convert module to use extmod version.
  47f634300c5572571816817f16836113c98814ae py: Change makemoduledefs process so it uses output of qstr extraction.
  0e7bfc88c6ac6b5d64240f91183a3cfe2ab67ade all: Use mp_obj_malloc everywhere it's applicable.
  2a6ba47110be88ff1e1f5abd1bd76c353447884c py/obj: Add static safety checks to mp_obj_is_type().
pull/2764/head
Martin Milata 1 year ago
parent eea52174ac
commit 3fb3f108cc

@ -132,9 +132,9 @@ WIRETYPE_ENTRY = c.Sequence(
"msg_offset" / c.Int16ul,
)
# QDEF(MP_QSTR_copysign, (const byte*)"\x33\x14\x08" "copysign")
# QDEF(MP_QSTR_copysign, 5171, 8, "copysign")
QDEF_RE = re.compile(
r'^QDEF\(MP_QSTR(\S+), \(const byte\*\)"(\\x..\\x..\\x..)" "(.*)"\)$'
r'^QDEF\(MP_QSTR(\S+), ([0-9]+), ([0-9])+, "(.*)"\)$'
)
@ -549,7 +549,7 @@ class RustBlobRenderer:
if not match:
continue
line = match.group(0)
string = match.group(3)
string = match.group(4)
self.qstr_map[string] = qstr_counter
qstr_counter += 1
logging.debug(f"Found {qstr_counter} Qstr defs")

@ -0,0 +1 @@
Update to MicroPython 1.19.1.

@ -225,7 +225,6 @@ SOURCE_MICROPYTHON = [
'vendor/micropython/shared/timeutils/timeutils.c',
'vendor/micropython/ports/stm32/gccollect.c',
'vendor/micropython/ports/stm32/pendsv.c',
'vendor/micropython/ports/stm32/softtimer.c',
'vendor/micropython/py/argcheck.c',
'vendor/micropython/py/asmarm.c',
'vendor/micropython/py/asmbase.c',
@ -535,7 +534,23 @@ qstr_generated = env.GenerateQstrDefs(
env.Ignore(qstr_collected, qstr_generated)
#
# Micropython version and modules
# Micropython module declarations
#
moduledefs_collected = env.CollectModules(
target='genhdr/moduledefs.collected.h', source=SOURCE_QSTR)
hdr_moduledefs = env.Command(
target='genhdr/moduledefs.h',
source=moduledefs_collected,
action='$MAKEMODULEDEFS $SOURCE > $TARGET', )
env.Ignore(moduledefs_collected, moduledefs_collected)
env.Ignore(moduledefs_collected, qstr_generated)
env.Ignore(moduledefs_collected, hdr_moduledefs)
#
# Micropython version
#
hdr_version = env.Command(
@ -543,11 +558,6 @@ hdr_version = env.Command(
source='',
action='$MAKEVERSIONHDR $TARGET', )
hdr_moduledefs = env.Command(
target='genhdr/moduledefs.h',
source=SOURCE_QSTR,
action='$MAKEMODULEDEFS --vpath="." $SOURCES > $TARGET', )
env.Ignore(hdr_moduledefs, hdr_moduledefs)
env.Ignore(hdr_moduledefs, qstr_collected)
env.Ignore(hdr_moduledefs, qstr_preprocessed)

@ -214,11 +214,11 @@ SOURCE_MICROPYTHON = [
'vendor/micropython/extmod/modubinascii.c',
'vendor/micropython/extmod/moductypes.c',
'vendor/micropython/extmod/moduheapq.c',
'vendor/micropython/extmod/moduos.c',
'vendor/micropython/extmod/modutimeq.c',
'vendor/micropython/extmod/utime_mphal.c',
'vendor/micropython/shared/readline/readline.c',
'vendor/micropython/shared/timeutils/timeutils.c',
'vendor/micropython/ports/unix/modos.c',
'vendor/micropython/py/argcheck.c',
'vendor/micropython/py/asmarm.c',
'vendor/micropython/py/asmbase.c',
@ -504,7 +504,24 @@ qstr_generated = env.GenerateQstrDefs(
env.Ignore(qstr_collected, qstr_generated)
#
# Micropython version and modules
# Micropython module declarations
#
moduledefs_collected = env.CollectModules(
target='genhdr/moduledefs.collected.h', source=SOURCE_QSTR)
hdr_moduledefs = env.Command(
target='genhdr/moduledefs.h',
source=moduledefs_collected,
action='$MAKEMODULEDEFS $SOURCE > $TARGET', )
env.Ignore(moduledefs_collected, moduledefs_collected)
env.Ignore(moduledefs_collected, qstr_generated)
env.Ignore(moduledefs_collected, hdr_moduledefs)
#
# Micropython version
#
hdr_version = env.Command(
@ -512,11 +529,6 @@ hdr_version = env.Command(
source='',
action='$MAKEVERSIONHDR $TARGET', )
hdr_moduledefs = env.Command(
target='genhdr/moduledefs.h',
source=SOURCE_QSTR,
action='$MAKEMODULEDEFS --vpath="." $SOURCES > $TARGET', )
env.Ignore(hdr_moduledefs, hdr_moduledefs)
env.Ignore(hdr_moduledefs, qstr_collected)
env.Ignore(hdr_moduledefs, qstr_preprocessed)

@ -446,7 +446,6 @@ const mp_obj_module_t mp_module_trezorconfig = {
.globals = (mp_obj_dict_t *)&mp_module_trezorconfig_globals,
};
MP_REGISTER_MODULE(MP_QSTR_trezorconfig, mp_module_trezorconfig,
MICROPY_PY_TREZORCONFIG);
MP_REGISTER_MODULE(MP_QSTR_trezorconfig, mp_module_trezorconfig);
#endif // MICROPY_PY_TREZORCONFIG

@ -129,8 +129,7 @@ const mp_obj_module_t mp_module_trezorcrypto = {
.globals = (mp_obj_dict_t *)&mp_module_trezorcrypto_globals,
};
MP_REGISTER_MODULE(MP_QSTR_trezorcrypto, mp_module_trezorcrypto,
MICROPY_PY_TREZORCRYPTO);
MP_REGISTER_MODULE(MP_QSTR_trezorcrypto, mp_module_trezorcrypto);
#ifdef USE_SECP256K1_ZKP
void secp256k1_default_illegal_callback_fn(const char *str, void *data) {

@ -386,8 +386,8 @@ STATIC mp_obj_t mod_trezorio_fatfs_open(mp_obj_t path, mp_obj_t flags) {
if (res != FR_OK) {
FATFS_RAISE(FatFSError, res);
}
mp_obj_FatFSFile_t *f = m_new_obj(mp_obj_FatFSFile_t);
f->base.type = &mod_trezorio_FatFSFile_type;
mp_obj_FatFSFile_t *f =
mp_obj_malloc(mp_obj_FatFSFile_t, &mod_trezorio_FatFSFile_type);
f->fp = fp;
return f;
}
@ -407,8 +407,8 @@ STATIC mp_obj_t mod_trezorio_fatfs_listdir(mp_obj_t path) {
if (res != FR_OK) {
FATFS_RAISE(FatFSError, res);
}
mp_obj_FatFSDir_t *d = m_new_obj(mp_obj_FatFSDir_t);
d->base.type = &mod_trezorio_FatFSDir_type;
mp_obj_FatFSDir_t *d =
mp_obj_malloc(mp_obj_FatFSDir_t, &mod_trezorio_FatFSDir_type);
d->dp = dp;
return d;
}

@ -37,8 +37,7 @@ STATIC mp_obj_t mod_trezorio_FlashOTP_make_new(const mp_obj_type_t *type,
size_t n_args, size_t n_kw,
const mp_obj_t *args) {
mp_arg_check_num(n_args, n_kw, 0, 0, false);
mp_obj_FlashOTP_t *o = m_new_obj(mp_obj_FlashOTP_t);
o->base.type = type;
mp_obj_FlashOTP_t *o = mp_obj_malloc(mp_obj_FlashOTP_t, type);
return MP_OBJ_FROM_PTR(o);
}

@ -94,8 +94,7 @@ STATIC mp_obj_t mod_trezorio_HID_make_new(const mp_obj_type_t *type,
CHECK_PARAM_RANGE(polling_interval, 1, 255)
CHECK_PARAM_RANGE(max_packet_len, 64, 64)
mp_obj_HID_t *o = m_new_obj(mp_obj_HID_t);
o->base.type = type;
mp_obj_HID_t *o = mp_obj_malloc(mp_obj_HID_t, type);
o->info.rx_buffer = m_new(uint8_t, max_packet_len);
o->info.report_desc = report_desc.buf;

@ -35,8 +35,7 @@ STATIC mp_obj_t mod_trezorio_SBU_make_new(const mp_obj_type_t *type,
size_t n_args, size_t n_kw,
const mp_obj_t *args) {
mp_arg_check_num(n_args, n_kw, 0, 0, false);
mp_obj_SBU_t *o = m_new_obj(mp_obj_SBU_t);
o->base.type = type;
mp_obj_SBU_t *o = mp_obj_malloc(mp_obj_SBU_t, type);
sbu_init();
return MP_OBJ_FROM_PTR(o);
}

@ -85,8 +85,7 @@ STATIC mp_obj_t mod_trezorio_VCP_make_new(const mp_obj_type_t *type,
const size_t vcp_buffer_len = 1024;
const size_t vcp_packet_len = 64;
mp_obj_VCP_t *o = m_new_obj(mp_obj_VCP_t);
o->base.type = type;
mp_obj_VCP_t *o = mp_obj_malloc(mp_obj_VCP_t, type);
o->info.tx_packet = m_new(uint8_t, vcp_packet_len);
o->info.tx_buffer = m_new(uint8_t, vcp_buffer_len);

@ -84,8 +84,7 @@ STATIC mp_obj_t mod_trezorio_WebUSB_make_new(const mp_obj_type_t *type,
CHECK_PARAM_RANGE(polling_interval, 1, 255)
CHECK_PARAM_RANGE(max_packet_len, 64, 64)
mp_obj_WebUSB_t *o = m_new_obj(mp_obj_WebUSB_t);
o->base.type = type;
mp_obj_WebUSB_t *o = mp_obj_malloc(mp_obj_WebUSB_t, type);
o->info.rx_buffer = m_new(uint8_t, max_packet_len);
o->info.iface_num = (uint8_t)(iface_num);

@ -127,6 +127,6 @@ const mp_obj_module_t mp_module_trezorio = {
.globals = (mp_obj_dict_t*)&mp_module_trezorio_globals,
};
MP_REGISTER_MODULE(MP_QSTR_trezorio, mp_module_trezorio, MICROPY_PY_TREZORIO);
MP_REGISTER_MODULE(MP_QSTR_trezorio, mp_module_trezorio);
#endif // MICROPY_PY_TREZORIO

@ -43,8 +43,7 @@ STATIC mp_obj_t mod_trezorui_Display_make_new(const mp_obj_type_t *type,
size_t n_args, size_t n_kw,
const mp_obj_t *args) {
mp_arg_check_num(n_args, n_kw, 0, 0, false);
mp_obj_Display_t *o = m_new_obj(mp_obj_Display_t);
o->base.type = type;
mp_obj_Display_t *o = mp_obj_malloc(mp_obj_Display_t, type);
return MP_OBJ_FROM_PTR(o);
}

@ -41,6 +41,6 @@ const mp_obj_module_t mp_module_trezorui = {
.globals = (mp_obj_dict_t*)&mp_module_trezorui_globals,
};
MP_REGISTER_MODULE(MP_QSTR_trezorui, mp_module_trezorui, MICROPY_PY_TREZORUI);
MP_REGISTER_MODULE(MP_QSTR_trezorui, mp_module_trezorui);
#endif // MICROPY_PY_TREZORUI

@ -253,17 +253,21 @@ void dump_dict_inner(FILE *out, const mp_obj_dict_t *dict) {
void dump_function(FILE *out, const mp_obj_fun_bc_t *func) {
print_type(out, "function", NULL, func, false);
fprintf(out, ",\n\"globals\": \"%p\"", func->globals);
fprintf(out, ",\n\"code_alloc\": %ld", find_allocated_size(func->bytecode));
fprintf(out, ",\n\"code_ptr\": \"%p\"", func->bytecode);
fprintf(out, ",\n\"const_table_alloc\": %ld",
find_allocated_size(func->const_table));
fprintf(out, ",\n\"const_table_ptr\": \"%p\"", func->const_table);
mark(func->bytecode);
mark(func->const_table);
fprintf(out, ",\n\"context_ptr\": \"%p\"", func->context);
fprintf(out, ",\n\"qstr_table_ptr\": \"%p\"",
func->context->constants.qstr_table);
fprintf(out, ",\n\"qstr_table_alloc\": \"%ld\"",
find_allocated_size(func->context->constants.qstr_table));
// obj_table uses the same allocation as qstr_table
fprintf(out, "},\n");
dump_value(out, func->globals);
// mp_module_context_t has mp_obj_module_t value at the beginning,
// dump_value will handle it as a module. The two pointers in
// mp_module_constants_t are handled above.
dump_value(out, &func->context);
}
typedef struct _mp_obj_bound_meth_t {
@ -672,10 +676,11 @@ void dump_value(FILE *out, mp_const_obj_t value) {
dump_value_opt(out, value, false);
}
void dump_qstr_pool(FILE *out, qstr_pool_t *pool) {
void dump_qstr_pool(FILE *out, const qstr_pool_t *pool) {
print_type(out, "qstrpool", NULL, pool, false);
fprintf(out, ", \"qstrs\": [\n");
for (const byte **q = pool->qstrs, **q_top = pool->qstrs + pool->len;
for (const char *const *q = pool->qstrs, *const *q_top =
pool->qstrs + pool->len;
q < q_top; q++) {
if (q < (q_top - 1))
fprintf(out, "\"%s\",\n", Q_GET_DATA(*q));
@ -683,7 +688,8 @@ void dump_qstr_pool(FILE *out, qstr_pool_t *pool) {
fprintf(out, "\"%s\"]\n", Q_GET_DATA(*q));
}
fprintf(out, "},\n");
for (const byte **q = pool->qstrs, **q_top = pool->qstrs + pool->len;
for (const char *const *q = pool->qstrs, *const *q_top =
pool->qstrs + pool->len;
q < q_top; q++) {
print_type(out, "qstrdata", NULL, *q, false);
fprintf(out, ", \"pool\": \"%p\"},\n", pool);
@ -691,9 +697,10 @@ void dump_qstr_pool(FILE *out, qstr_pool_t *pool) {
}
void dump_qstrdata(FILE *out) {
qstr_pool_t *pool = MP_STATE_VM(last_pool);
const qstr_pool_t *pool = MP_STATE_VM(last_pool);
while (pool != NULL) {
for (const byte **q = pool->qstrs, **q_top = pool->qstrs + pool->len;
for (const char *const *q = pool->qstrs, *const *q_top =
pool->qstrs + pool->len;
q < q_top; q++) {
if ((void *)*q > (void *)mp_state_ctx.mem.gc_pool_start) {
print_type(out, "qstrdata", NULL, q, false);
@ -757,7 +764,7 @@ STATIC mp_obj_t mod_trezorutils_meminfo(mp_obj_t filename) {
dump_value(out, MP_STATE_VM(trezorconfig_ui_wait_callback));
fprintf(out, "\"qstr_pools\",\n");
qstr_pool_t *pool = MP_STATE_VM(last_pool);
const qstr_pool_t *pool = MP_STATE_VM(last_pool);
while (VERIFY_PTR((void *)pool)) {
dump_qstr_pool(out, pool);
pool = pool->prev;

@ -287,7 +287,6 @@ const mp_obj_module_t mp_module_trezorutils = {
.globals = (mp_obj_dict_t *)&mp_module_trezorutils_globals,
};
MP_REGISTER_MODULE(MP_QSTR_trezorutils, mp_module_trezorutils,
MICROPY_PY_TREZORUTILS);
MP_REGISTER_MODULE(MP_QSTR_trezorutils, mp_module_trezorutils);
#endif // MICROPY_PY_TREZORUTILS

@ -69,4 +69,4 @@ const mp_obj_module_t mp_module_utime = {
.globals = (mp_obj_dict_t*)&time_module_globals,
};
MP_REGISTER_MODULE(MP_QSTR_utime, mp_module_utime, MICROPY_PY_UTIME);
MP_REGISTER_MODULE(MP_QSTR_utime, mp_module_utime);

@ -80,7 +80,6 @@ const mp_obj_module_t mp_module_trezorproto = {
.globals = (mp_obj_dict_t *)&mp_module_trezorproto_globals,
};
MP_REGISTER_MODULE(MP_QSTR_trezorproto, mp_module_trezorproto,
MICROPY_PY_TREZORPROTO);
MP_REGISTER_MODULE(MP_QSTR_trezorproto, mp_module_trezorproto);
#endif // MICROPY_PY_TREZORPROTO

@ -23,7 +23,6 @@
#include "librust.h"
MP_REGISTER_MODULE(MP_QSTR_trezorui2, mp_module_trezorui2,
MICROPY_PY_TREZORUI2);
MP_REGISTER_MODULE(MP_QSTR_trezorui2, mp_module_trezorui2);
#endif // MICROPY_PY_TREZORUI2

@ -54,7 +54,7 @@ bool trezor_obj_get_ll_checked(mp_obj_t obj, long long *value) {
*value = MP_OBJ_SMALL_INT_VALUE(obj);
return true;
} else if (mp_obj_is_type(obj, &mp_type_int)) {
} else if (mp_obj_is_int(obj)) {
// Value is not fitting into small int range, but is an integer.
mp_obj_int_t *self = MP_OBJ_TO_PTR(obj);
// Try to get the long long value out of the MPZ struct.

@ -23,6 +23,7 @@
#include <stdio.h>
#include <string.h>
#include "py/builtin.h"
#include "py/compile.h"
#include "py/gc.h"
#include "py/mperrno.h"
@ -173,9 +174,7 @@ int main(void) {
mp_init();
mp_obj_list_init(mp_sys_argv, 0);
mp_obj_list_init(mp_sys_path, 0);
mp_obj_list_append(
mp_sys_path,
MP_OBJ_NEW_QSTR(MP_QSTR_)); // current dir (or base dir of the script)
mp_obj_list_append(mp_sys_path, MP_OBJ_NEW_QSTR(MP_QSTR__dot_frozen));
// Execute the main script
printf("CORE: Executing main script\n");

@ -55,9 +55,12 @@
// optimisations
#define MICROPY_OPT_COMPUTED_GOTO (1)
#define MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE (0)
#define MICROPY_OPT_MPZ_BITWISE (1)
#define MICROPY_OPT_MATH_FACTORIAL (0)
#define MICROPY_OPT_LOAD_ATTR_FAST_PATH (1)
#define MICROPY_OPT_MAP_LOOKUP_CACHE (1)
#define MICROPY_CONFIG_ROM_LEVEL (MICROPY_CONFIG_ROM_LEVEL_CORE_FEATURES)
// Python internal features
#define MICROPY_READER_VFS (0)
@ -129,6 +132,7 @@
#define MICROPY_PY_UCTYPES (1)
#define MICROPY_PY_UZLIB (0)
#define MICROPY_PY_UJSON (0)
#define MICROPY_PY_UOS (0)
#define MICROPY_PY_URE (0)
#define MICROPY_PY_URE_SUB (0)
#define MICROPY_PY_UHEAPQ (0)

@ -41,3 +41,7 @@ void mp_hal_stdout_tx_strn(const char *str, size_t len) {
}
void mp_hal_set_vcp_iface(int iface_num) { vcp_iface_num = iface_num; }
// Dummy implementation required by ports/stm32/gccollect.c.
// The normal version requires MICROPY_ENABLE_SCHEDULER which we don't use.
void soft_timer_gc_mark_all(void) {}

@ -1,5 +1,5 @@
enum Qstr {
#define QDEF(id, str) id,
#define QDEF(id, hash, len, str) id,
#include "genhdr/qstrdefs.generated.h"
#undef QDEF
};

@ -501,7 +501,7 @@ MP_NOINLINE int main_(int argc, char **argv) {
#ifdef MICROPY_PY_SYS_PATH_DEFAULT
path = MICROPY_PY_SYS_PATH_DEFAULT;
#else
path = "~/.micropython/lib:/usr/lib/micropython";
path = ".frozen:~/.micropython/lib:/usr/lib/micropython";
#endif
}
size_t path_num = 1; // [0] is for current dir (or base dir of the script)
@ -724,3 +724,5 @@ void nlr_jump_fail(void *val) {
printf("FATAL: uncaught NLR %p\n", val);
exit(1);
}
MP_REGISTER_MODULE(MP_QSTR_uos, mp_module_uos);

@ -60,9 +60,12 @@
// optimisations
#define MICROPY_OPT_COMPUTED_GOTO (1)
#define MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE (0)
#define MICROPY_OPT_MPZ_BITWISE (1)
#define MICROPY_OPT_MATH_FACTORIAL (0)
#define MICROPY_OPT_LOAD_ATTR_FAST_PATH (1)
#define MICROPY_OPT_MAP_LOOKUP_CACHE (1)
#define MICROPY_CONFIG_ROM_LEVEL (MICROPY_CONFIG_ROM_LEVEL_CORE_FEATURES)
// Python internal features
#define MICROPY_READER_VFS (0)
@ -137,6 +140,13 @@
#define MICROPY_PY_UCTYPES (1)
#define MICROPY_PY_UZLIB (0)
#define MICROPY_PY_UJSON (0)
#define MICROPY_PY_UOS (1)
#define MICROPY_PY_UOS_INCLUDEFILE "ports/unix/moduos.c"
#define MICROPY_PY_UOS_ERRNO (1)
#define MICROPY_PY_UOS_GETENV_PUTENV_UNSETENV (1)
#define MICROPY_PY_UOS_SEP (1)
#define MICROPY_PY_UOS_SYSTEM (1)
#define MICROPY_PY_UOS_URANDOM (1)
#define MICROPY_PY_URE (0)
#define MICROPY_PY_URE_SUB (0)
#define MICROPY_PY_UHEAPQ (0)
@ -208,13 +218,6 @@ extern const struct _mp_print_t mp_stderr_print;
// ============= this ends common config section ===================
// extra built in modules to add to the list of known ones
extern const struct _mp_obj_module_t mp_module_os;
#define MICROPY_PORT_BUILTIN_MODULES \
{ MP_ROM_QSTR(MP_QSTR_uos), MP_ROM_PTR(&mp_module_os) },
// For size_t and ssize_t
#include <unistd.h>

@ -4,7 +4,8 @@ import SCons.Builder
def generate(env):
env.SetDefault(
QSTRCOL='site_scons/site_tools/micropython/qstrdefs.py', )
QSTRCOL='site_scons/site_tools/micropython/qstrdefs.py',
MODULECOL='site_scons/site_tools/micropython/moduledefs.py', )
env['BUILDERS']['CollectQstr'] = SCons.Builder.Builder(
action='$CC -E $CCFLAGS_QSTR $CFLAGS $CCFLAGS $_CCCOMCOM $SOURCES'
@ -19,6 +20,10 @@ def generate(env):
env['BUILDERS']['GenerateQstrDefs'] = SCons.Builder.Builder(
action='$MAKEQSTRDATA $SOURCE > $TARGET', )
env['BUILDERS']['CollectModules'] = SCons.Builder.Builder(
action='$CC -E $CCFLAGS_QSTR $CFLAGS $CCFLAGS $_CCCOMCOM $SOURCES'
' | $PYTHON $MODULECOL > $TARGET')
def generate_frozen_module(source, target, env, for_signature):
target = str(target[0])
source = str(source[0])

@ -0,0 +1,13 @@
import re
import sys
def process(source, target):
re_module = re.compile(r"MP_REGISTER_MODULE\(.*?,\s*.*?\);")
for line in source:
for match in re_module.findall(line):
target.write(f"{match}\n")
if __name__ == "__main__":
process(sys.stdin, sys.stdout)

@ -1 +1 @@
Subproject commit fce614cbe213e3f6c9e1a2a9634d2c1edae7c57b
Subproject commit 2e06e072519194ba76d3f11298c76a2733dd95ec
Loading…
Cancel
Save