CPython unittest를 이용해 RustPython에 기여하는 방법

, by youknowone

RustPythonRustPython3을 구현하는 프로젝트입니다. Rust의 타입 안전성과 풍부한 언어기능에 힘입어 빠른 속도로 개발되고 있지요. 이 글에서는 프로그래밍 언어 개발에 관심이 있어 RustPython에 기여해 보려는 분들이 참고할 수 있는 방법 하나를 소개합니다.

RustPython에는 여전히 빠진 기능이 많지만, 2019년 말 드디어 기초적인 CPython unittest 실행이 가능해 졌습니다. 중요한 이정표 하나에 도달한 셈이죠. 덕분에 CPython 호환성 이슈를 찾아 고치기가 아주 쉬워 졌습니다. 이미 잘 짜여진 테스트를 쓰는 것은 큰 이득이 있기 때문에, 아마도 앞으로 한동안은 새로운 기여자들에게 쉽게 찾을 수 있는 일거리를 잔뜩 공급해 줄 게 틀림 없습니다. 그러므로 구체적인 방법을 소개합니다.

이미 알려진 호환성 버그 수정하기

호환성 이슈를 찾아서 해결해 봅시다.

  1. 프로젝트의 Lib/test 디렉터리를 봅시다. test_ 로 시작하는 파일이 잔뜩 있습니다. 예를 들면 test_unicode.py 가 그 가운데 하나입니다.
  2. 테스트 파일 가운데 하나를 열어 봅시다. 슬쩍 보기엔 아무 문제 없어 보일 수도 있어요. 하지만 파일에서 TODO: RUSTPYTHON 를 검색해 보세요. skip 이나 expectedFailure 로 표시되거나 주석 처리된 코드가 잔뜩 나옵니다. (여러 파일에서 검색 기능이 있는 도구를 활용하면 좋습니다)
  3. 관심있는 버그 한두개를 고릅시다. skip이든 expectedFailure든 주석이든 테스트 실패를 막고 있는 부분을 제거해 주세요.
  4. 이제 테스트가 성공할 때까지 열심히 고칩니다.

파일 하나만 테스트하는 방법을 알면 빠르게 시도하고 다시 고치는 데 유용하니 알아둡시다. 이를테면 test_unittest.py 를 실행하려면 다음과 같이 합니다.

$ cargo run --release Lib/test/test_unicode.py

새 테스트 파일 추가하기

아직은 CPython unittest가 RustPython에서 완벽하게 동작하지 않기 때문에, 파일을 하나씩 하나씩 옮겨 넣고 있습니다.

  1. CPython 소스코드를 내려받으세요.
  2. CPython의 버전을 확인하세요. 지금은 3.8.3을 권장합니다. (지금은 RustPython 테스트를 3.8 기준으로 하고 있고, 3.8.3은 3.8 가운데 최신 버전이니까요)
  3. CPython Lib/test 에서 파일 하나를 복사해 와서 RustPython의 같은 디렉터리에 넣습니다.
  4. 파일을 편집하지 않고 커밋합니다. 복사해온 CPython 버전을 커밋 메시지에 남겨 주세요.
  5. 크래시도 나지 않고 테스트 실패도 하지 않을 때까지 테스트 파일을 고칩니다.
  6. 동작하도록 고친 테스트파일의 변경 사항을 커밋합니다. 이까지가 핵심적인 기여 방법입니다.

RustPython은 아직 완벽하지 않기 때문에, "크래시도 나지 않고 테스트 실패도 하지 않을 때까지" 라는 말은 모든 테스트가 100% 동작하게 만든다는 얘기가 아닙니다. 보통은 이런식으로 합니다.

  1. 최소한 테스트가 실행이 되긴 해야 합니다. 테스트 가운데 최소한 하나는 실행할 때까지 테스트 코드나 버그를 고칩니다. 덜 구현된 stdlib이 있거나 unittest에서 참조하고 있는 다른 파일이 빠져 있는 경우가 보통입니다. 가끔은 RustPython 버그가 문제를 만들기도 하고요.
  2. 테스트 가운데 SyntaxError 때문에 실패하는 테스트가 있다면 이 부분은 주석 처리가 되어야 합니다.
  3. 테스트 가운데 크래시를 일으키는 게 있다면, 실행할 수 없으므로 skip으로 표시되어야 합니다.
  4. 테스트 가운데 실행은 되지만 실패하는 게 있다면, 호환성 문제이므로 expectedFailure로 표시합니다.

위에 제안한 방법 중 아래에 있는 방법일수록 더 좋은 방법입니다. 아래에 있는 방법일수록 더 엄격하기 때문에 RustPython 코드가 더 나아지거나 더 나빠지는 경우를 더 쉽게 알아낼 수 있거든요. RustPython의 문제 때문에 일부 테스트를 꺼 둘 때는 나중에 찾기 쉽도록 표시를 남겨둡니다. 아래 예시를 참고하거나 Lib/test 디렉터리 안에서 TODO: RUSTPYTHON 를 검색해 실제로 어떻게 사용되는지 확인해 주세요.

주석 처리

# TODO: RUSTPYTHON
#
# def ...  # commented out tests

skip

@unittest.skip("TODO: RUSTPYTHON")
def ...  # skipped tests

expectedFailure

# TODO: RUSTPYTHON
@unittest.expectedFailure
def ...  # failed tests

개발자 문서

개발에 관한 일반적인 문서는 RustPython development guide (영어)를 참고해 주세요.

이 글은 RustPython 블로그에 게시된 글 How to contribute to RustPython by CPython unittest와 (거의) 같은 글입니다.