시스템 개발 및 관리/프로젝트 구조 설정

파이썬 프로젝트 구조, 왜 이렇게 해야 할까요? (feat. src 레이아웃, pyproject.toml)

Data Jun 2025. 5. 5. 15:45

파이썬 개발을 하다 보면 여러 개의 파일과 폴더로 이루어진 프로젝트를 다루게 됩니다. 이때 프로젝트를 어떻게 구성하느냐에 따라 코드의 가독성, 유지보수성, 그리고 배포 용이성이 크게 달라질 수 있습니다. 오늘은 효과적인 파이썬 프로젝트 구조에 대해 이야기해보려 합니다.

 

혼돈의 카오스, 왜 구조가 중요할까요?

처음에는 몇 개의 스크립트로 시작한 프로젝트가 점점 커지면서 어디에 뭐가 있는지 찾기 어려워지는 경험, 다들 있으실 겁니다. 마치 서랍 속이 뒤죽박죽인 것처럼 말이죠. 잘 정의된 프로젝트 구조는 이러한 혼란을 방지하고, 다음과 같은 이점을 제공합니다.

  • 가독성 향상: 파일과 폴더가 논리적으로 정리되어 있어 코드를 쉽게 찾고 이해할 수 있습니다.
  • 유지보수 용이성: 기능별로 코드가 분리되어 있어 변경이나 버그 수정 시 영향을 최소화할 수 있습니다.
  • 협업 효율 증대: 여러 개발자가 함께 작업할 때 파일 위치를 명확히 알 수 있어 충돌을 줄이고 협업 효율을 높입니다.
  • 배포 용이성: 패키징 도구가 필요한 파일을 정확하게 찾아 배포 파일을 생성할 수 있도록 돕습니다.

일반적인 파이썬 프로젝트 구조:

 

많은 파이썬 프로젝트에서 채택하는 기본적인 구조는 다음과 같습니다.

my_project/
├── my_package/      # 실제 패키지 코드
│   ├── __init__.py
│   ├── module1.py
│   ├── submodule/
│   │   └── __init__.py
│   │   └── module2.py
├── tests/         # 테스트 코드
│   ├── __init__.py
│   └── test_module1.py
├── README.md
├── LICENSE
├── requirements.txt  # 의존성 목록 (구 방식)
└── setup.py        # 패키징 설정 (구 방식)

 

하지만 최근에는 더욱 발전된 구조와 설정 파일들이 등장하고 있습니다.

 

떠오르는 강자, src 레이아웃:

규모가 있는 라이브러리나 프레임워크에서 자주 사용되는 구조로, 소스 코드를 src 폴더 아래에 두는 방식입니다.

my_project/
├── src/
│   └── my_package/  # 실제 패키지 코드
│       ├── __init__.py
│       ├── module1.py
│       └── submodule/
│           ├── __init__.py
│           └── module2.py
├── tests/         # 테스트 코드
│   ├── __init__.py
│   └── test_module1.py
├── README.md
├── LICENSE
└── pyproject.toml    # 프로젝트 설정 (최신 방식)

src 레이아웃의 장점:

  • 루트 디렉토리 정리: 설정 파일, 문서 등과 소스 코드를 명확히 분리하여 루트 디렉토리를 깔끔하게 유지합니다.
  • 패키징 용이성: 패키징 도구가 src 폴더 아래의 코드만 패키징하도록 설정하기 용이합니다.
  • 상대 임포트의 일관성: src를 패키지 루트로 간주하여 상대 임포트가 직관적입니다.

현대적인 설정, pyproject.toml:

과거에는 패키징 설정을 위해 setup.py 파일을 주로 사용했지만, 최근에는 PEP 517과 PEP 518에 정의된 표준 설정 파일인 pyproject.toml이 각광받고 있습니다.

[build-system]
requires = ["setuptools>=61.0.0"]
build-backend = "setuptools.build_meta"

[project]
name = "my-package"
version = "0.1.0"
authors = [
  { name="Your Name", email="your.email@example.com" },
]
description = "A short description of your project"
readme = "README.md"
requires-python = ">=3.8"
dependencies = [
  "requests>=2.28",
  "pandas>=1.5",
]
classifiers = [
    "Programming Language :: Python :: 3 :: Only",
    "License :: OSI Approved :: MIT License",
    "Operating System :: OS Independent",
]

[tool.setuptools.packages.find]
where = ["src"]  # src 폴더 아래에서 패키지 찾기

pyproject.toml의 장점:

  • 표준화: 파이썬 패키징 도구 간의 호환성을 높이고 일관된 빌드 프로세스를 보장합니다.
  • 빌드 시스템 분리: 빌드 백엔드를 명시적으로 지정하여 유연성을 높입니다.
  • 빌드 의존성 관리: 빌드에 필요한 도구를 명시하여 환경 격리를 용이하게 합니다.
  • 선언적인 설정: 패키지 정보를 명확하고 이해하기 쉬운 방식으로 정의합니다.

독립적인 패키지 관리:

규모가 큰 라이브러리나 프레임워크를 개발할 때는 여러 개의 독립적인 "프로젝트" 또는 "패키지"로 구성될 수 있습니다. 이 경우 각 패키지 내에 자체적인 pyproject.toml 파일을 두어 의존성을 관리하는 것이 좋습니다.

my_library/
├── package_a/
│   ├── src/
│   │   └── ...
│   └── pyproject.toml  # package_a의 의존성
├── package_b/
│   ├── src/
│   │   └── ...
│   └── pyproject.toml  # package_b의 의존성
└── ...

이렇게 하면 각 패키지의 의존성을 독립적으로 관리하여 충돌을 방지하고 유지보수성을 높일 수 있습니다.

 

결론:

 

잘 구성된 파이썬 프로젝트 구조는 개발 효율성과 코드 품질을 향상시키는 데 필수적입니다. src 레이아웃을 사용하여 소스 코드를 분리하고, pyproject.toml 파일을 통해 현대적인 방식으로 프로젝트를 설정하고 의존성을 관리하는 것은 좋은 습관입니다. 프로젝트의 규모와 복잡성에 따라 적절한 구조를 선택하고 일관성을 유지하는 것이 중요합니다. 지금 여러분의 프로젝트는 어떻게 구성되어 있나요?