2012년 11월 20일 화요일

[Python] 인터프리터 테스트는 다르다

특정 모둘을 만들고 이 모듈을 파이썬 인터프리터로 테스트 할 때 간혹 문제가 생기는 케이스가 있다. 특히 PYTHONPATH와 함께 발생 할 수 있는 import 문제가 있다.

약간의 신중하지 못한 (혹은 무식한) 점이 이틀 간의 삽질로 나를 이끌었다. 아직도 명확한 원인은 모른다. 애초에 이런 디자인은 좋지 않다는 것을 되세기며 이번 포스팅을 기록으로 남긴다.

약간 복잡한 디렉토리 구조를 가지고 있는 웹 서비스를 만들고 있었다. 여기서 쓸 모듈을 하나 만들었는데 이 모듈이 잘 돌아가는지 확인하기 위해 파이썬 인터프리터로 해당 모듈을 import 했다. 그런데 자기 자신을 import 하는 다른 모듈에서 import 에러가 발생했다.

디렉토리 및 모듈 구조는 이런 식이었다.
ProjectRoot/
    B/
        __init__.py
        ModuleB.py
    ModuleA.py
    ModuleC.py
각 모듈의 코드는 이런 식이다.

ModuleA.py:
import B.ModuleB

someinstance = ...
...

ModuleB.py:
from ModuleC import somefunc
...

ModuleC.py
from ModuleA import someinstance
...
def somefunc():
    ...

뭔가 복잡해 보인다. 단순히 용도를 설명하자면, ModuleC는 일종의 라이브러리이다. 그래서 어디서든 import를 할 수 있어야 한다. 그런데 ModuleA는 서비스 인스턴스로 역시 여러 군데서 엑세스 할 수 있어야 한다. ModuleB는 ModuleA에 종속적으로 동작하는 서비스 모듈 중 하나이다.

이런 상황에서 Python 인터프리터로 ModuleC를 import하면 ImportError가 발생한다. 문제가 발생하는 곳은 ModuleB에서 ModuleA를 import 하려는 코드이다.

얼핏 보면 cross import 문제가 아닐까 의심되기도 했다. 그래서 문제 해결을 위해 구글신께 구글링을 하며 빌었지만 전혀 힌트를 찾을 수 없었다. 당연하다. Python은 원래 한번 import된 모듈은 다시 import 하더라도 무시하도록 애초에 cross import가 발생하지 않도록 디자인 되어 있기 때문이다.

아직도 이해하기에는 뭔가 좀 부족한 것 같은데, 어쨌거나 파이썬 인터프리터로 ModuleC를 import 하려 할 때만 문제가 생긴다. 실서비스로 테스트 해 보면 아무 문제가 없다. 그렇다면 인터프리터 특유의 문제로 이해해야 할 것 같다.

위에는 서술하지 않은 다른 부분이 있다면 바로 __file__ 식별자를 이용해서 sys.path(환경변수 PYTHONPATH)를 등록하는 부분이 있다. 이런 코드는 파이썬 인터프리터에서 제대로 동작하지 않는다. 왜냐하면 인터프리터를 이용 할 때는 __file__ 이 정의되지 않기 때문이다. 하지만 이건 이 문제의 원인은 아니다.

이 글의 중요한 점은 이런 디자인은 하지 말자는 것이다. 서로가 서로를 의존하게 되는 커플링이 발생하는 코드는 나쁜 코드 중 하나이다. 그런데 어렵다! 어떻게 해야 할까. 정말 어려운 숙제다. :-(

댓글 없음 :