파이썬 argparse에서 unrecognized arguments가 나오면 parser 정의부터 고치기보다 실제로 parser에 전달된 인자 목록을 먼저 확인해야 합니다. 특히 parse_args(sys.argv)처럼 스크립트명까지 넘겼거나, Jupyter 커널이 추가한 -f 인자를 읽은 경우라면 실행 환경과 코드의 경계를 분리하는 것이 핵심입니다. 그 다음에 정말 등록되지 않은 옵션인지, positional 인자의 배치가 문제인지 확인하면 수정 방향이 선명해집니다.
먼저 확인할 핵심: parser가 받은 목록
argparse의 일반적인 사용은 parser.parse_args()입니다. 인자 목록을 생략하면 parse_args()는 기본적으로 sys.argv를 사용합니다. sys.argv의 첫 원소는 실행한 스크립트명이고, 그 뒤에 사용자가 전달한 명령줄 인자가 이어집니다.
따라서 다음처럼 sys.argv 전체를 다시 넘기는 코드는 주의해야 합니다.
import argparse
import sys
parser = argparse.ArgumentParser()
parser.add_argument("input_file")
args = parser.parse_args(sys.argv) # 스크립트명이 positional 값으로 들어올 수 있음
일반적인 스크립트에서는 다음처럼 호출하는 편이 맞습니다.
args = parser.parse_args()
테스트 코드나 함수로 분리한 코드에서 직접 목록을 주고 싶다면 스크립트명 자리를 제외한 목록을 넘깁니다.
def parse_options(argv=None):
parser = argparse.ArgumentParser()
parser.add_argument("input_file")
return parser.parse_args(argv)
args = parse_options(["report.csv"])
이 단계에서 print(sys.argv) 또는 함수에 전달된 argv를 잠시 확인해 보십시오. 오류 메시지에 보이는 값이 코드에서 등록한 옵션인지, 실행기가 덧붙인 값인지 구분하는 것이 첫 판단입니다.
Jupyter에서 보이는 -f는 parser 옵션이 아닐 수 있습니다
IPython 커널 명세에는 커널 시작 시 connection file 경로를 -f 뒤에 전달하는 예시가 있습니다. 따라서 노트북 커널 환경에서 실행 코드가 sys.argv를 직접 파싱하면 -f와 그 경로가 사용자 입력이 아니라 실행 환경의 인자로 보일 수 있습니다. 이때 -f를 애플리케이션 옵션으로 등록하는 식으로 해결하면 실행 환경의 인자와 프로그램 인자의 경계가 더 흐려집니다.
노트북에서 테스트할 함수는 인자 목록을 명시적으로 받도록 분리하는 것이 안전합니다.
import argparse
def parse_options(argv=None):
parser = argparse.ArgumentParser()
parser.add_argument("--name", required=True)
return parser.parse_args(argv)
args = parse_options(["--name", "daily-job"])
실행 환경이 주입한 값은 이 테스트 목록에 들어오지 않습니다. 실제 명령줄에서 실행할 때만 기본값인 parse_args()를 사용하고, 라이브러리처럼 호출되는 함수나 노트북 셀에서는 명시적 목록을 넘기면 됩니다.
Google Colab을 포함해 노트북 계열 환경에서 같은 증상이 보인다면 먼저 sys.argv의 실제 내용을 확인하십시오. 다만 확인한 공식 자료만으로 모든 Colab 실행 경로가 같은 인자 구성을 사용한다고 단정할 수는 없으므로, 환경 이름만 보고 -f를 일반적인 사용자 옵션으로 취급하지 않는 것이 좋습니다.
실제 미등록 인자인지 확인하는 순서
-f가 실행 환경의 인자가 아니라면 다음 순서로 좁혀 갑니다.
add_argument()에 옵션 이름과 positional 인자가 실제로 등록되어 있는지 확인합니다.- 실행 명령의 철자와 하이픈 형태가 등록된 이름과 같은지 확인합니다.
parse_args()에 전달한 목록을 출력해 오타나 예상하지 않은 값을 찾습니다.- 예약 실행기나 상위 프로세스가 인자를 추가하는지 실행 명령과 로그를 확인합니다.
운영 자동화에서 미지 인자를 무조건 버리는 것은 조심해야 합니다. 인자 이름의 오타나 배포 설정의 불일치를 조용히 통과시키면 작업은 실행된 것처럼 보이지만 다른 설정으로 동작할 수 있습니다. 미지 인자를 허용해야 하는 구조라면 parse_known_args()로 나머지 목록을 받은 뒤 기록하고, 정말 허용할 값인지 판단한 다음 진행하는 편이 안전합니다.
args, unknown = parser.parse_known_args(argv)
if unknown:
raise ValueError(f"허용하지 않은 인자입니다: {unknown}")
반대로 플러그인이나 상위 실행기가 일부 인자를 책임지는 구조라서 나머지를 전달해야 한다면 unknown을 명시적으로 다음 계층에 넘기십시오. parse_known_args()를 단순한 오류 숨김 도구로 사용하지 않는 것이 운영상 중요한 기준입니다.
positional 인자 배치와 — 구분자
옵션과 positional 인자를 섞어 쓸 때는 parser 정의와 호출 순서를 함께 확인해야 합니다. 기본 parse_args()가 현재 명령 형태를 원하는 방식으로 해석하지 못한다면 parse_intermixed_args()를 검토할 수 있습니다. 다만 이 방식은 subparser나 일부 mutually exclusive group과 함께 사용할 수 없는 경우가 있으므로 parser 구조를 먼저 확인해야 합니다.
값이 옵션처럼 보이지만 positional 데이터로 전달되어야 한다면 -- 구분자를 사용할 수 있습니다. -- 뒤의 값은 positional 인자로 처리됩니다.
parser.add_argument("files", nargs="+")
args = parser.parse_args(["--", "-f", "input.txt"])
이 구분자는 실행 환경이 자동으로 넣어 주는 -f를 해결하는 만능 방법은 아닙니다. 애초에 어떤 목록을 parser에 넘기는지 통제할 수 있을 때, 사용자가 입력한 값과 옵션 해석의 경계를 분명히 하는 용도로 보십시오.
parse_args(), parse_known_args(), parse_intermixed_args() 선택 기준
- 정상적인 CLI 프로그램이고 모든 인자를 이 프로그램이 소유한다면
parse_args()를 기본으로 둡니다. 미등록 옵션이나 잘못된 positional 인자 수를 오류로 알려 주기 때문입니다. - 상위 실행기나 플러그인에 넘길 인자가 일부 존재한다면
parse_known_args()로 알려진 인자와 나머지를 분리합니다. 나머지를 기록하거나 다음 계층으로 전달하는 정책을 코드에 남깁니다. - 옵션과 positional 인자의 혼합 배치가 필요하고 parser 구조가 호환된다면
parse_intermixed_args()를 검토합니다. - 노트북·테스트 함수에서는
parse_args(argv)처럼 명시적 목록을 전달해 실행 환경의sys.argv와 테스트 입력을 분리합니다.
불리언 옵션 때문에 비슷한 오류를 따라가게 되는 경우도 있습니다. store_true와 store_false는 --flag False를 일반적인 문자열 불리언 입력처럼 해석하는 방식과 다르므로, 이 문제는 별도로 확인해야 합니다. 관련 선택 기준은 파이썬 argparse에서 –flag False가 True가 되는 이유와 불리언 옵션 선택법에서 이어서 볼 수 있습니다.
운영 자동화에 적용하는 최종 점검
자동화 스크립트를 예약 실행 환경에 옮길 때는 다음 세 가지를 기록으로 남기면 원인 추적이 쉬워집니다.
- parser를 호출한 함수가 기본
sys.argv를 읽는지, 명시적 목록을 받는지 - 실행기가 추가할 수 있는 인자와 프로그램이 소유한 인자의 구분
- 미지 인자를 거부할지, 기록 후 다음 계층에 전달할지에 대한 정책
결국 unrecognized arguments의 수정은 오류 문구에 나온 인자를 무작정 등록하는 일이 아닙니다. sys.argv[0] 전달 실수인지, 노트북 커널의 -f인지, 실제 미등록 옵션인지, positional 배치 문제인지 순서대로 분리한 뒤 parser의 소유 범위에 맞는 방식을 선택해야 합니다. 터미널과 노트북, 예약 실행에서 같은 함수를 재사용한다면 입력 목록을 인자로 받는 구조부터 만들어 두는 것이 가장 재현성 있는 출발점입니다.