본문으로 바로가기
728x90
반응형

목차

     

    개요

    Pycharm은 Scracthpad라는 기능을 제공한다. Project 소스 위치 밖의 별개의 영역에서 Python 파일을 만들어 이를 실행할 수 있게 해주는 기능이다. 간단히 말하면 간단한 Script를 작성하는데 사용되는 편리한 기능이다.

    사실 이 기능은 처음 봤을 때 IDE 새로 실행시켜서 따로 코드 작성해서 돌리면 되지 뭐 하러 이런 기능까지 만들어둔 거지 싶었다. 지금에 와서야 이 Scracthpad에 익숙해져서 그런지 너무 잘 쓰고 있다. (IDE를 새로 실행시키는 것이 여간 귀찮다)

    각설하고 Scracthpad를 사용하다 이상한 점을 발견했고 이를 편법으로 해결한 경험을 겪어서 남겨두고자 한다.


    ScracthPad은 어디에 위치하는가

    Pycharm의 Project Navigate 하단 영역을 보게 되면 “Scratched and Consoles”라는 항목이 보인다. 이곳이 ScracthPad를 사용할 수 있는 접점이다.

    ScracthPad 기능을 통해서 새롭게 생성되는 파일은 별도의 영역에 위치하게 된다. 이 영역은 OS별로 그리고 설치하는 환경에 따라 다르지만 내 경우엔 다음과 같은 경로에 위치해 있다.

    /Users/jako/Library/Application Support/JetBrains/PyCharmCE2023.1/scratches

    Pycharm 버전을 업데이트하게 되면 이전에 사용한 Scratch File들은 업데이트한 버전에서 안 보이게 되는데 위 경로를 참조하여 다시 가져올 수 있으니 알아두는 것이 좋다.


    ScracthPad의 Relative import

    ScracthPad도 결국 Directory로 관리되니 다음과 같이 계층 구조를 만들 수 있다.

    (venv) ~/Library/Application Support/JetBrains/PyCharmCE2023.1/scratches
    ╰─$ tree -L 2
    .
    ├── scratch.py
    ├── scripts
    │   ├── config.py
    │   └── script01.py
    ├── test.py
    ├── test02.py
    └── test03.py

    얼핏 보면 ScracthPad 안의 Python 파일도 library를 import 하듯 import 할 수 있을 듯싶다. scripts 디렉터리 안의 config.py에는 다음과 같은 간단한 class가 정의되어 있다.

    # config.py
    class Config:
        foo = "1"
        bar = "2"

    이를 script01.py에서 import 해서 사용해 보자.

    from .config import Config
    
    class Script01(Config):
        def run(self):
            print(self.foo)
    
    if __name__ == '__main__':
        script01 = Script01()
        script01.run()

    위 결과는 다음과 같다.

    Traceback (most recent call last):
      File "/Users/jako/Library/Application Support/JetBrains/PyCharmCE2023.1/scratches/scripts/script01.py", line 1, in <module>
        from .config import Config
    ImportError: attempted relative import with no known parent package

    ImportError가 발생한다. 이유는 SracthPad의 위치를 pycharm에서 package로 인식하지 못하기 때문이다. 그렇다면 단순하게 생각해서 같은 위치에 있으니 절대경로로 참조가 가능할 것이기 때문에 이를 이용하여 import 하면 동작하게 될 것인지를 테스트해 보자.

    from config import Config
    
    class Script01(Config):
    
        def run(self):
            print(self.foo)
    
    if __name__ == '__main__':
        script01 = Script01()
        script01.run()

    결과는 다음과 같다.

    1

    그렇다. 잘 동작된다.


    보기 불편하니 Disable Inspection 처리하자

    ScrachPad의 file을 import 하는 과정에서 상대경로로 접근하는 게 아니라 절대경로로 접근하니 import 되는 것을 확인했다. 그런데 pycharm 상에서는 다음과 같이 표기된다.

    빨간 줄이 떠서 눈에 거슬린다. 여기서 이제 잔머리를 굴려서 해결할 수 있었다. pycharm에는 disable inspections라는 기능이 있는 특정 라인 ‘#noqa’를 달면 해당 경고를 무시할 수 있다.




    눈 가리고 아웅 하기

    이 글을 읽는 동안 눈치채신 분들도 있겠지만 상대경로와 절대경로는 다음과 같은 문제들이 있다.

      상대경로 (from .config import Config) 절대경로(from config import Config)
    장점 typing이 가능함 구현된 코드를 사용 가능함
    단점 (Error) 구현된 코드를 사용하지 못함 typing 불가능함

    상대경로는 구현된 코드를 사용하지 못하는 대신에 typing이 가능하다. 절대경로는 구현된 코드는 사용가능하지만 사용하는 코드 쪽에서는 무슨 기능이 구현됐는지 모른다. 정리하고 보니 괴랄해 보이지만 이는 편법으로 해결이 가능했다.

    두 가지 import를 동시에 사용하는 방식이며 상대경로를 typing 모듈의 TYPE_CHECKING을 곁들이는 것이다. 바로 다음과 같다.

    from config import Config  # noqa
    
    if TYPE_CHECKING:
        from .config import Config  
    
    
    class Script01(Config):
    
        def run(self):
            print(self.foo)
    
    
    if __name__ == '__main__':
        script01 = Script01()
        script01.run()

    typing의 TYPE_CHECKING은 순환참조 방지의 해결책으로도 사용할 수 있다.

    맺음말

    단순한 script는 거의 scratchpad에 작성할 정도로 scratchpad를 많이 사용해 왔다.

    주로 django에 구현된 내부 기능을 밖에서 사용해야 할 때와 django에 구현된 내부 로직을 탐구하기 위한 용도로 많이 사용해 왔는데 ScratchPad에 복잡한 코드를 작성할 일이라던가 코드를 분리해서 관리해야 하는 경우가 드물었는지 ScractchPad 영역에다가 무언가 시도해 볼 생각은 딱히 해보진 않은 듯하다.

    최근에는 ScractchPad를 쓸일이 더 잦아지고 ScratchPad에 복잡한 Script를 작성할 일이 생긴 기회를 통해 이것저것 알아보게 됐는데 이번 포스팅에 기재한 내용은 본문에서 언급되었듯이 편법인 느낌이 강하지만 나만의 노하우가 생겼다는 것을 중요시하며 이번 글을 마친다.





    728x90
    반응형