spark-submit提交EMR任务时argparse无法正确解析sys.argv参数
问题原因
报错核心是**sys.argv[0]被异常赋值为-arg1,导致argparse默认读取参数时跳过了第一个业务参数**。
从报错的usage行usage: -arg1 [-h] -arg2 ARG2 -arg1 ARG1可以看出,正常usage开头应该展示的程序名(即sys.argv[0]的取值,通常是运行的脚本名)变成了-arg1,说明执行parse_args()时,sys.argv的完整值就是你打印的['-arg1', 'val1', '-arg2', 'val2'],完全缺失了脚本名作为第一个元素。
argparse在不手动传入待解析参数时,默认会读取sys.argv[1:]作为解析输入,对应到这个异常的sys.argv结构,实际被解析的参数列表是['val1', '-arg2', 'val2'],列表里没有-arg1这个参数标记,自然会触发「必填参数-arg1缺失」的报错。
这个问题的触发和spark-submit的参数处理逻辑有关:在EMR集群上运行时,spark-submit会先消费属于自身的启动参数,再把剩余参数传给用户脚本,如果你没有在入口处对参数做切割修正,很容易出现sys.argv结构不符合Python脚本默认预期的问题。
解决方案
- 显式传入待解析参数,不依赖argparse的默认sys.argv读取逻辑
如果你已经在代码中拿到了正确的业务参数列表,直接把列表传给parse_args()即可,不需要依赖sys.argv的默认结构,修改后的代码示例:
调用时直接传入正确的参数即可:def main(param_list): parser = argparse.ArgumentParser() parser.add_argument('-arg1', '--argument1', type=str, required=True) parser.add_argument('-arg2', '--argument2', type=str, required=True) # 手动传入确认正确的参数列表做解析 args = parser.parse_args(param_list)mod.main(['-arg1', 'val1', '-arg2', 'val2']) - 在脚本入口处提前修正sys.argv结构
在调用业务模块的main函数之前,先从spark-submit传入的原始参数中切割出业务参数,重新构造符合Python规范的sys.argv(第一个元素为脚本名,后续元素为传入脚本的参数),示例代码:import sys # 定位业务参数的起始位置,比如"module_to_call"之后的内容都是业务参数 biz_param_start_idx = sys.argv.index("module_to_call") + 1 biz_params = sys.argv[biz_param_start_idx:] # 重写sys.argv,保留第一个元素为原始脚本名,后续拼接切割出来的业务参数 sys.argv = [sys.argv[0]] + biz_params # 修正完成后再调用mod.main()即可 - 在EMR步骤配置中增加参数分隔符
spark-submit支持用--作为自身参数和用户脚本参数的分隔符,分隔符之后的所有内容都会被直接透传给用户脚本,不会被spark自身的参数逻辑消费篡改,修改后的HadoopJarStep配置示例:"HadoopJarStep": { "Args": [ "spark-submit",..., "run_module.py", "module_to_call", "--", "-arg1", "val1", "-arg2", "val2",... ] }
内容的提问来源于stack exchange,提问作者pralik
相关产品推荐
相关产品推荐

