{"meta":{"title":"Python 빌드 및 테스트","intro":"CI(연속 통합) 워크플로를 만들어 Python 프로젝트를 빌드하고 테스트하는 방법을 알아봅니다.","product":"GitHub Actions","breadcrumbs":[{"href":"/ko/enterprise-server@3.19/actions","title":"GitHub Actions"},{"href":"/ko/enterprise-server@3.19/actions/tutorials","title":"자습서"},{"href":"/ko/enterprise-server@3.19/actions/tutorials/build-and-test-code","title":"코드 빌드 및 테스트"},{"href":"/ko/enterprise-server@3.19/actions/tutorials/build-and-test-code/python","title":"Python"}],"documentType":"article"},"body":"# Python 빌드 및 테스트\n\nCI(연속 통합) 워크플로를 만들어 Python 프로젝트를 빌드하고 테스트하는 방법을 알아봅니다.\n\n> \\[!NOTE]\n> GitHub Enterprise Server 호스트 실행기는 현재 GitHub에서 지원되지 않습니다.\n\n## 소개\n\n이 가이드에서는 Python 패키지를 빌드, 테스트 및 게시하는 방법을 보여줍니다.\n\nGitHub에서 호스팅하는 러너에는 Python 및 PyPy가 사전 설치된 소프트웨어를 포함하는 도구 캐시가 마련되어 있습니다. 사용자는 아무것도 설치할 필요가 없습니다. 최신 소프트웨어와 미리 설치된 Python 및 PyPy 버전의 전체 목록은 [GitHub 호스팅 실행기](/ko/enterprise-server@3.19/actions/using-github-hosted-runners/about-github-hosted-runners#supported-software)를 참조하세요.\n\n## 필수 조건\n\nYAML 및 GitHub Actions의 구문에 대해 잘 알고 있어야 합니다. 자세한 내용은 [워크플로 작성](/ko/enterprise-server@3.19/actions/learn-github-actions)을(를) 참조하세요.\n\nPython 및 pip에 대한 기본적인 이해가 있는 것이 좋습니다. 자세한 내용은 다음을 참조하세요.\n\n* [Python 시작하기](https://www.python.org/about/gettingstarted/)\n* [pip 패키지 관리자](https://pypi.org/project/pip/)\n\n### GitHub Enterprise Server에서 자체 호스팅 실행기 사용\n\n실행기를 자체 호스팅하는 GitHub Enterprise Server에서 `actions/setup-LANGUAGE` 같은 설정 작업을 사용할 경우 인터넷에 액세스할 수 없는 실행기에서 도구 캐시를 설정해야 할 수 있습니다. 자세한 내용은 [인터넷에 액세스할 수 없는 자체 호스팅 실행기에서 도구 캐시 설정](/ko/enterprise-server@3.19/admin/github-actions/managing-access-to-actions-from-githubcom/setting-up-the-tool-cache-on-self-hosted-runners-without-internet-access)을(를) 참조하세요.\n\n## Python 워크플로 템플릿 사용\n\n빠르게 시작하려면 워크플로 템플릿을 리포지토리의 `.github/workflows` 디렉터리에 추가합니다.\n\nGitHub는 리포지토리에 `.py` 파일이 하나 이상 존재하는 경우 활용 가능한 Python 워크플로우 템플릿을 제공합니다. 이 가이드의 후속 섹션에서는 이 워크플로 템플릿을 사용자 지정하는 방법에 대한 예시를 제공합니다.\n\n1. GitHub에서 리포지토리의 기본 페이지로 이동합니다.\n\n2. 리포지토리 이름에서 **<svg version=\"1.1\" width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" class=\"octicon octicon-play\" aria-label=\"play\" role=\"img\"><path d=\"M8 0a8 8 0 1 1 0 16A8 8 0 0 1 8 0ZM1.5 8a6.5 6.5 0 1 0 13 0 6.5 6.5 0 0 0-13 0Zm4.879-2.773 4.264 2.559a.25.25 0 0 1 0 .428l-4.264 2.559A.25.25 0 0 1 6 10.559V5.442a.25.25 0 0 1 .379-.215Z\"></path></svg> 작업**을 클릭합니다.\n\n   ![\"github/docs\" 리포지토리의 탭 스크린샷. \"작업\" 탭은 주황색 윤곽선으로 강조 표시됩니다.](/assets/images/help/repository/actions-tab-global-nav-update.png)\n\n3. 리포지토리에 워크플로가 이미 있는 경우 **새 워크플로**를 클릭합니다.\n\n4. \"워크플로 선택\" 페이지에는 권장되는 워크플로 템플릿의 선택 항목이 표시됩니다. \"Python 애플리케이션\"을 검색합니다.\n\n5. \"Python 애플리케이션\" 워크플로에서 **Configure** 클릭합니다.\n\n   \"Python 애플리케이션\" 워크플로 템플릿을 찾을 수 없는 경우 다음 워크플로 코드를 리포지토리의 `python-app.yml` 디렉터리에 있는 `.github/workflows`이라는 새 파일에 복사합니다.\n\n   ```yaml copy\n   name: Python application\n\n   on:\n     push:\n       branches: [ \"main\" ]\n     pull_request:\n       branches: [ \"main\" ]\n\n   permissions:\n     contents: read\n\n   jobs:\n     build:\n       runs-on: ubuntu-latest\n\n       steps:\n       - uses: actions/checkout@v6\n       - name: Set up Python 3.13\n         uses: actions/setup-python@v5\n         with:\n           python-version: \"3.13\"\n       - name: Install dependencies\n         run: |\n           python -m pip install --upgrade pip\n           pip install ruff pytest\n           if [ -f requirements.txt ]; then pip install -r requirements.txt; fi\n       - name: Lint and format Python code with ruff\n         run: |\n          # Lint with the default set of ruff rules with GitHub Annotations\n          ruff check --format=github --target-version=py39\n          # Verify the code is properly formatted\n          ruff format --diff --target-version=py39\n       - name: Test with pytest\n         run: |\n           pytest\n   ```\n\n6. 필요에 따라 워크플로를 편집합니다. 예를 들어 Python 버전을 변경합니다.\n\n7. ```\n          **변경 내용 커밋**을 클릭합니다.\n   ```\n\n## Python 버전 지정\n\nGitHub 호스트 실행기에서 사전 설치된 버전의 Python 또는 PyPy를 사용하려면 `setup-python` 작업을 사용하세요. 이 작업은 각 실행기의 도구 캐시에서 Python 또는 PyPy의 특정 버전을 찾아 필수 이진 파일을 `PATH`에 추가합니다. 이는 나머지 작업 동안 유지됩니다. 특정 버전의 Python 도구 캐시에 미리 설치되지 않은 경우 `setup-python` 작업은 [`python-versions`](https://github.com/actions/python-versions) 리포지토리에서 적절한 버전을 다운로드하고 설정합니다.\n\n```\n          `setup-python` 액션을 사용하는 것이 GitHub Actions와 함께 Python을 사용하는 권장 방법입니다. 이는 다양한 실행기와 다양한 버전의 Python에서 일관된 동작을 보장하기 때문입니다. 자체 호스팅 실행기를 사용하는 경우, Python을 설치하고 `PATH` 경로에 추가해야 합니다. 자세한 내용은 [`setup-python`작업](https://github.com/marketplace/actions/setup-python)을 참조하세요.\n```\n\n아래 테이블에서는 각 GitHub호스트 실행기에서 도구 캐시의 위치를 설명합니다.\n\n<div class=\"ghd-tool rowheaders\">\n\n|                  | Ubuntu                          | Mac                                      | Windows                               |\n| ---------------- | ------------------------------- | ---------------------------------------- | ------------------------------------- |\n| **도구 캐시 디렉터리**   | `/opt/hostedtoolcache/*`        | `/Users/runner/hostedtoolcache/*`        | `C:\\hostedtoolcache\\windows\\*`        |\n| **Python 도구 캐시** | `/opt/hostedtoolcache/Python/*` | `/Users/runner/hostedtoolcache/Python/*` | `C:\\hostedtoolcache\\windows\\Python\\*` |\n| **PyPy 도구 캐시**   | `/opt/hostedtoolcache/PyPy/*`   | `/Users/runner/hostedtoolcache/PyPy/*`   | `C:\\hostedtoolcache\\windows\\PyPy\\*`   |\n\n</div>\n\n자체 호스팅 실행기를 사용하는 경우 `setup-python` 작업을 사용하여 종속성을 관리하도록 실행기를 구성할 수 있습니다. 자세한 내용은 [](https://github.com/actions/setup-python#using-setup-python-with-a-self-hosted-runner) 추가 정보에서 `setup-python`을 참조하세요.\n\nGitHub는 의미 체계 버전 관리 구문을 지원합니다. 자세한 내용은 [의미 체계 버전 관리 사용](https://docs.npmjs.com/about-semantic-versioning#using-semantic-versioning-to-specify-update-types-your-package-can-accept) 및 [의미 체계 버전 관리 사양](https://semver.org/)을 참조하세요.\n\n### 여러 Python 버전 사용\n\n다음 예제에서는 작업에 대한 행렬을 사용하여 여러 Python 버전을 설정합니다. 자세한 내용은 [워크플로에서 작업 변형 실행](/ko/enterprise-server@3.19/actions/using-jobs/using-a-matrix-for-your-jobs)을(를) 참조하세요.\n\n```yaml copy\nname: Python package\n\non: [push]\n\njobs:\n  build:\n\n    runs-on: ubuntu-latest\n    strategy:\n      matrix:\n        python-version: [\"pypy3.10\", \"3.9\", \"3.10\", \"3.11\", \"3.12\", \"3.13\"]\n\n    steps:\n      - uses: actions/checkout@v6\n      - name: Set up Python ${{ matrix.python-version }}\n        uses: actions/setup-python@v5\n        with:\n          python-version: ${{ matrix.python-version }}\n      # You can test your matrix by printing the current Python version\n      - name: Display Python version\n        run: python -c \"import sys; print(sys.version)\"\n```\n\n### 특정 Python 버전 사용\n\n특정 버전의 Python 구성할 수 있습니다. 예: 3.12. 또는 시맨틱 버전 구문을 사용하여 최신 마이너 릴리스를 가져올 수 있습니다. 이 예제에서는 Python 3의 최신 부 릴리스를 사용합니다.\n\n```yaml copy\nname: Python package\n\non: [push]\n\njobs:\n  build:\n\n    runs-on: ubuntu-latest\n\n    steps:\n      - uses: actions/checkout@v6\n      - name: Set up Python\n        # This is the version of the action for setting up Python, not the Python version.\n        uses: actions/setup-python@v5\n        with:\n          # Semantic version range syntax or exact version of a Python version\n          python-version: '3.x'\n          # Optional - x64 or x86 architecture, defaults to x64\n          architecture: 'x64'\n      # You can test your matrix by printing the current Python version\n      - name: Display Python version\n        run: python -c \"import sys; print(sys.version)\"\n```\n\n### 버전을 제외하기\n\n사용할 수 없는 Python 버전을 지정하면 다음과 같은 오류와 함께 `setup-python` 실패합니다. `##[error]Version 3.7 with arch x64 not found`. 오류 메시지에는 사용 가능한 버전이 포함됩니다.\n\n실행하지 않으려는 Python 구성이 있는 경우 워크플로에서 `exclude` 키워드를 사용할 수도 있습니다. 자세한 내용은 [GitHub Actions에 대한 워크플로 구문](/ko/enterprise-server@3.19/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstrategy)을(를) 참조하세요.\n\n```yaml copy\nname: Python package\n\non: [push]\n\njobs:\n  build:\n\n    runs-on: ${{ matrix.os }}\n    strategy:\n      matrix:\n        os: [ubuntu-latest, macos-latest, windows-latest]\n        python-version: [\"3.9\", \"3.11\", \"3.13\", \"pypy3.10\"]\n        exclude:\n          - os: macos-latest\n            python-version: \"3.11\"\n          - os: windows-latest\n            python-version: \"3.11\"\n```\n\n### 기본 Python 버전 사용\n\n```\n          `setup-python` 사용하여 종속성을 명시적으로 설정하는 데 도움이 되므로 워크플로에 사용되는 Python 버전을 구성하는 것이 좋습니다. \n          `setup-python` 사용하지 않는 경우 `PATH` 호출할 때 모든 셸에서 `python` 설정된 Python 기본 버전이 사용됩니다. Python의 기본 버전은 GitHub 호스트 실행기마다 다르며 이로 인해 예기치 않은 변경이 발생하거나 예상보다 이전 버전을 사용할 수 있습니다.\n```\n\n| GitHub 호스트 실행기 | 설명                                                                                                                                                                            |\n| -------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| Ubuntu         | Ubuntu 실행기에는 여러 버전의 시스템 Python이 `/usr/bin/python` 및 `/usr/bin/python3` 디렉터리에 설치되어 있습니다. Ubuntu와 함께 패키지된 Python 버전은 GitHub가 도구 캐시에 설치하는 버전에 추가됩니다.                             |\n| Windows        | 도구 캐시에 있는 Python 버전을 제외하면 Windows 동일한 버전의 시스템 Python 함께 제공하지 않습니다. 다른 실행기와 일관된 동작을 유지하고 `setup-python` 작업 없이 즉시 사용 가능한 Python을 허용하기 위해 GitHub는 도구 캐시의 몇 가지 버전을 `PATH`에 추가합니다. |\n| macOS          | macOS 실행기에는 도구 캐시에 포함된 버전 외에도 둘 이상의 시스템 Python 버전이 설치되어 있습니다. 시스템 Python 버전은 `/usr/local/Cellar/python/*` 디렉터리에 있습니다.                                                         |\n\n## 종속성 설치\n\nGitHub 호스트 실행기에는 pip 패키지 관리자가 설치되어 있습니다. 코드를 빌드하고 테스트하기 전에 pip을 사용하여 PyPI 패키지 레지스트리에서 종속성을 설치할 수 있습니다. 예를 들어 아래 YAML은 `pip` 패키지 설치 프로그램과 `setuptools` 및 `wheel` 패키지를 설치하거나 업그레이드합니다.\n\n종속성을 캐시하여 워크플로 속도를 높일 수도 있습니다. 자세한 내용은 [종속성 캐싱 참조](/ko/enterprise-server@3.19/actions/using-workflows/caching-dependencies-to-speed-up-workflows)을(를) 참조하세요.\n\n```yaml copy\nsteps:\n- uses: actions/checkout@v6\n- name: Set up Python\n  uses: actions/setup-python@v5\n  with:\n    python-version: '3.x'\n- name: Install dependencies\n  run: python -m pip install --upgrade pip setuptools wheel\n```\n\n### 요구 사항 파일\n\n```\n          `pip`을 업데이트한 후 일반적인 다음 단계는 `requirements.txt`에서 종속성을 설치하는 것입니다. 자세한 내용은 [pip](https://pip.pypa.io/en/stable/cli/pip_install/#example-requirements-file)를 참조하세요.\n```\n\n```yaml copy\nsteps:\n- uses: actions/checkout@v6\n- name: Set up Python\n  uses: actions/setup-python@v5\n  with:\n    python-version: '3.x'\n- name: Install dependencies\n  run: |\n    python -m pip install --upgrade pip\n    pip install -r requirements.txt\n```\n\n### 종속성 캐싱\n\n```\n          [\n          `setup-python`작업](https://github.com/actions/setup-python)을 사용하여 종속성을 캐시하고 복원할 수 있습니다.\n```\n\n다음 예시에서는 pip에 대한 종속성을 캐시합니다.\n\n```yaml copy\nsteps:\n- uses: actions/checkout@v6\n- uses: actions/setup-python@v5\n  with:\n    python-version: '3.12'\n    cache: 'pip'\n- run: pip install -r requirements.txt\n- run: pip test\n```\n\n기본적으로 `setup-python` 작업은 전체 리포지토리에서 종속성 파일(pip의 경우 `requirements.txt`, pipenv의 경우 `Pipfile.lock` 또는 poetry의 경우 `poetry.lock`)을 검색합니다. 자세한 내용은 [패키지 의존성 캐싱](https://github.com/actions/setup-python#caching-packages-dependencies) 항목을 `setup-python` README에서 참조하세요.\n\n사용자 지정 요구사항이 있거나 캐싱에 대한 세부적인 제어가 필요한 경우 [`cache` 작업](https://github.com/marketplace/actions/cache)을 사용할 수 있습니다. pip는 실행기의 운영 체제에 따라 다른 위치에 종속성을 캐시합니다. 캐시해야 하는 경로는 사용하는 운영 체제에 따라 위의 Ubuntu 예시와 다를 수 있습니다. 자세한 내용은 [](https://github.com/actions/cache/blob/main/examples.md#python---pip) 작업 리포지토리의 `cache`를 참조하세요.\n\n## 코드 테스트\n\n코드를 빌드하고 테스트하기 위해 로컬에서 사용하는 것과 동일한 명령을 사용할 수 있습니다.\n\n### pytest 및 pytest-cov를 사용하여 테스트\n\n```\n          `pytest` 및 `pytest-cov`를 설치하거나 업그레이드합니다. 그런 다음 테스트가 실행되어 JUnit 형식으로 출력되고 코드 검사 결과는 Cobertura로 출력됩니다. 자세한 내용은 [JUnit](https://junit.org/junit5/) 및 [Cobertura](https://cobertura.github.io/cobertura/)를 참조하세요.\n```\n\n```yaml copy\nsteps:\n- uses: actions/checkout@v6\n- name: Set up Python\n  uses: actions/setup-python@v5\n  with:\n    python-version: '3.x'\n- name: Install dependencies\n  run: |\n    python -m pip install --upgrade pip\n    pip install -r requirements.txt\n- name: Test with pytest\n  run: |\n    pip install pytest pytest-cov\n    pytest tests.py --doctest-modules --junitxml=junit/test-results.xml --cov=com --cov-report=xml --cov-report=html\n```\n\n### Ruff를 사용하여 코드 린팅 및/또는 서식 지정\n\n다음 예시에서는 `ruff`을(를) 설치하거나 업그레이드하고 이를 사용하여 모든 파일을 린트합니다. 자세한 내용은 [Ruff](https://docs.astral.sh/ruff)를 참조하세요.\n\n```yaml copy\nsteps:\n- uses: actions/checkout@v6\n- name: Set up Python\n  uses: actions/setup-python@v5\n  with:\n    python-version: '3.x'\n- name: Install the code linting and formatting tool Ruff\n  run: pipx install ruff\n- name: Lint code with Ruff\n  run: ruff check --output-format=github --target-version=py39\n- name: Check code formatting with Ruff\n  run: ruff format --diff --target-version=py39\n  continue-on-error: true\n```\n\n서식 지정 단계가 `continue-on-error: true` 설정되었습니다. 이렇게 하면 서식 지정 단계가 성공하지 못한 경우 워크플로가 실패하지 않습니다. 모든 서식 지정 오류를 해결했으면 워크플로가 새 문제를 catch할 수 있도록 해당 옵션을 제거할 수 있습니다.\n\n### tox를 사용하여 테스트 실행\n\nGitHub Actions를 사용하면 tox로 테스트를 실행하고 여러 작업에 작업을 분산할 수 있습니다. 특정 버전을 지정하는 대신, `-e py` 옵션을 사용하여 `PATH` 내에서 Python 버전을 선택하기 위해 tox를 실행해야 합니다. 자세한 내용은 [tox](https://tox.readthedocs.io/en/latest/)를 참조하세요.\n\n```yaml copy\nname: Python package\n\non: [push]\n\njobs:\n  build:\n\n    runs-on: ubuntu-latest\n    strategy:\n      matrix:\n        python: [\"3.9\", \"3.11\", \"3.13\"]\n\n    steps:\n      - uses: actions/checkout@v6\n      - name: Setup Python\n        uses: actions/setup-python@v5\n        with:\n          python-version: ${{ matrix.python }}\n      - name: Install tox and any other packages\n        run: pip install tox\n      - name: Run tox\n        # Run tox using the version of Python in `PATH`\n        run: tox -e py\n```\n\n## 워크플로 데이터를 아티팩트로 패키지\n\n워크플로가 완료된 후 볼 아티팩트를 업로드할 수 있습니다. 예를 들어 로그 파일, 코어 덤프, 테스트 결과 또는 스크린샷을 저장해야 할 수 있습니다. 자세한 내용은 [워크플로 아티팩트와 데이터 저장 및 공유](/ko/enterprise-server@3.19/actions/using-workflows/storing-workflow-data-as-artifacts)을(를) 참조하세요.\n\n다음 예시는 `upload-artifact` 작업을 사용하여 `pytest` 실행의 테스트 결과를 보관하는 방법을 보여 줍니다. 자세한 내용은 [`upload-artifact`작업](https://github.com/actions/upload-artifact)을 참조하세요.\n\n```yaml copy\nname: Python package\n\non: [push]\n\njobs:\n  build:\n\n    runs-on: ubuntu-latest\n    strategy:\n      matrix:\n        python-version: [\"3.9\", \"3.10\", \"3.11\", \"3.12\", \"3.13\"]\n\n    steps:\n      - uses: actions/checkout@v6\n      - name: Setup Python # Set Python version\n        uses: actions/setup-python@v5\n        with:\n          python-version: ${{ matrix.python-version }}\n      # Install pip and pytest\n      - name: Install dependencies\n        run: |\n          python -m pip install --upgrade pip\n          pip install pytest\n      - name: Test with pytest\n        run: pytest tests.py --doctest-modules --junitxml=junit/test-results-${{ matrix.python-version }}.xml\n      - name: Upload pytest test results\n        uses: actions/upload-artifact@v3\n        with:\n          name: pytest-results-${{ matrix.python-version }}\n          path: junit/test-results-${{ matrix.python-version }}.xml\n        # Use always() to always run this step to publish test results when there are test failures\n        if: ${{ always() }}\n```\n\n## PyPI에 게시\n\nCI 테스트가 통과되면 Python 패키지를 PyPI에 게시하도록 워크플로를 구성할 수 있습니다. 이 섹션에서는 릴리스를 게시할 때마다 GitHub Actions를 사용하여 PyPI에 패키지를 업로드하는 방법을 보여 줍니다. 자세한 내용은 [리포지토리에서 릴리스 관리](/ko/enterprise-server@3.19/repositories/releasing-projects-on-github/managing-releases-in-a-repository)을(를) 참조하세요.\n\n아래 예시 워크플로에서는 [신뢰할 수 있는 게시](https://docs.pypi.org/trusted-publishers/)를 사용하여 PyPI를 인증하므로 수동으로 구성된 API 토큰이 필요하지 않습니다.\n\n```yaml copy\n# 이 워크플로는 GitHub에서 인증되지 않은 작업을 사용합니다.\n# 작업은 타사에서 제공하며\n# 별도의 서비스 약관, 개인정보처리방침, 지원 설명서에서 규정됩니다.\n# 참조하세요.\n\n# 커밋 SHA에 작업을 고정하는 것이 좋습니다.\n# 최신 버전을 얻으려면 SHA를 업데이트해야 합니다.\n# 태그 또는 분기를 참조할 수도 있지만 경고 없이 작업이 변경될 수 있습니다.\n\nname: Upload Python Package\n\non:\n  release:\n    types: [published]\n\npermissions:\n  contents: read\n\njobs:\n  release-build:\n    runs-on: ubuntu-latest\n\n    steps:\n      - uses: actions/checkout@v6\n\n      - uses: actions/setup-python@v5\n        with:\n          python-version: \"3.x\"\n\n      - name: Build release distributions\n        run: |\n          # NOTE: put your own distribution build steps here.\n          python -m pip install build\n          python -m build\n\n      - name: Upload distributions\n        uses: actions/upload-artifact@v3\n        with:\n          name: release-dists\n          path: dist/\n\n  pypi-publish:\n    runs-on: ubuntu-latest\n\n    needs:\n      - release-build\n\n    permissions:\n      # IMPORTANT: this permission is mandatory for trusted publishing\n      id-token: write\n\n    # Dedicated environments with protections for publishing are strongly recommended.\n    environment:\n      name: pypi\n      # OPTIONAL: uncomment and update to include your PyPI project URL in the deployment status:\n      # url: https://pypi.org/p/YOURPROJECT\n\n    steps:\n      - name: Retrieve release distributions\n        uses: actions/download-artifact@v3\n        with:\n          name: release-dists\n          path: dist/\n\n      - name: Publish release distributions to PyPI\n        uses: pypa/gh-action-pypi-publish@6f7e8d9c0b1a2c3d4e5f6a7b8c9d0e1f2a3b4c5d\n```"}