RustPython은 Rust로 Python3을 구현하는 프로젝트입니다. Rust의 타입 안전성과 풍부한 언어기능에 힘입어 빠른 속도로 개발되고 있지요. 이 글에서는 프로그래밍 언어 개발에 관심이 있어 RustPython에 기여해 보려는 분들이 참고할 수 있는 방법 하나를 소개합니다.
RustPython에는 여전히 빠진 기능이 많지만, 2019년 말 드디어 기초적인 CPython unittest 실행이 가능해 졌습니다. 중요한 이정표 하나에 도달한 셈이죠. 덕분에 CPython 호환성 이슈를 찾아 고치기가 아주 쉬워 졌습니다. 이미 잘 짜여진 테스트를 쓰는 것은 큰 이득이 있기 때문에, 아마도 앞으로 한동안은 새로운 기여자들에게 쉽게 찾을 수 있는 일거리를 잔뜩 공급해 줄 게 틀림 없습니다. 그러므로 구체적인 방법을 소개합니다.
이미 알려진 호환성 버그 수정하기
호환성 이슈를 찾아서 해결해 봅시다.
- 프로젝트의
Lib/test
디렉터리를 봅시다.test_
로 시작하는 파일이 잔뜩 있습니다. 예를 들면test_unicode.py
가 그 가운데 하나입니다. - 테스트 파일 가운데 하나를 열어 봅시다. 슬쩍 보기엔 아무 문제 없어 보일 수도 있어요. 하지만 파일에서
TODO: RUSTPYTHON
를 검색해 보세요.skip
이나expectedFailure
로 표시되거나 주석 처리된 코드가 잔뜩 나옵니다. (여러 파일에서 검색 기능이 있는 도구를 활용하면 좋습니다) - 관심있는 버그 한두개를 고릅시다. skip이든 expectedFailure든 주석이든 테스트 실패를 막고 있는 부분을 제거해 주세요.
- 이제 테스트가 성공할 때까지 열심히 고칩니다.
파일 하나만 테스트하는 방법을 알면 빠르게 시도하고 다시 고치는 데 유용하니 알아둡시다. 이를테면 test_unittest.py
를 실행하려면 다음과 같이 합니다.
$ cargo run --release Lib/test/test_unicode.py
새 테스트 파일 추가하기
아직은 CPython unittest가 RustPython에서 완벽하게 동작하지 않기 때문에, 파일을 하나씩 하나씩 옮겨 넣고 있습니다.
- CPython 소스코드를 내려받으세요.
- CPython의 버전을 확인하세요. 지금은 3.8.3을 권장합니다. (지금은 RustPython 테스트를 3.8 기준으로 하고 있고, 3.8.3은 3.8 가운데 최신 버전이니까요)
- CPython
Lib/test
에서 파일 하나를 복사해 와서 RustPython의 같은 디렉터리에 넣습니다. - 파일을 편집하지 않고 커밋합니다. 복사해온 CPython 버전을 커밋 메시지에 남겨 주세요.
- 크래시도 나지 않고 테스트 실패도 하지 않을 때까지 테스트 파일을 고칩니다.
- 동작하도록 고친 테스트파일의 변경 사항을 커밋합니다. 이까지가 핵심적인 기여 방법입니다.
RustPython은 아직 완벽하지 않기 때문에, "크래시도 나지 않고 테스트 실패도 하지 않을 때까지" 라는 말은 모든 테스트가 100% 동작하게 만든다는 얘기가 아닙니다. 보통은 이런식으로 합니다.
- 최소한 테스트가 실행이 되긴 해야 합니다. 테스트 가운데 최소한 하나는 실행할 때까지 테스트 코드나 버그를 고칩니다. 덜 구현된 stdlib이 있거나 unittest에서 참조하고 있는 다른 파일이 빠져 있는 경우가 보통입니다. 가끔은 RustPython 버그가 문제를 만들기도 하고요.
- 테스트 가운데
SyntaxError
때문에 실패하는 테스트가 있다면 이 부분은 주석 처리가 되어야 합니다. - 테스트 가운데 크래시를 일으키는 게 있다면, 실행할 수 없으므로
skip
으로 표시되어야 합니다. - 테스트 가운데 실행은 되지만 실패하는 게 있다면, 호환성 문제이므로
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와 (거의) 같은 글입니다.