λ€μ€ νκ²½ ν μ€νΈλ₯Ό μν Toxλ₯Ό λ§μ€ν°νμΈμ. μ΄ μ’ ν© κ°μ΄λλ tox.ini ꡬμ±, CI/CD ν΅ν©, κ·Έλ¦¬κ³ λ€μν Python λ²μ , μ’ μμ± λ° μ΄μ 체μ μμ Python μ½λκ° μλ²½νκ² μλνλλ‘ λ³΄μ₯νλ κ³ κΈ μ λ΅μ λ€λ£Ήλλ€.
Tox ν μ€νΈ μλν: κΈλ‘λ² νμ μν λ€μ€ νκ²½ ν μ€νΈ μ¬μΈ΅ λΆμ
μ€λλ μ κΈλ‘λ² μννΈμ¨μ΄ νκ²½μμ "μ μ»΄ν¨ν°μμλ μ μλν©λλ€"λΌλ λ§μ κ°λ°μλ€μ νν νΈλ μ λμ΄μ μ€λν λΉμ¦λμ€ μνμ λλ€. μ¬μ©μμ κ³ κ°, νμ μλ€μ μ μΈκ³μ νΌμ Έ μμΌλ©°, λ€μν μ΄μ 체μ , Python λ²μ , κ·Έλ¦¬κ³ μ’ μμ± μ€νμ μ¬μ©νκ³ μμ΅λλ€. λͺ¨λ μ¬λμ΄ μ΄λμλ μ¬λ¬λΆμ μ½λκ° λ¨μν κΈ°λ₯ν λΏλ§ μλλΌ μμ μ μΌλ‘ κ²¬κ³ νκ² μλνλλ‘ μ΄λ»κ² 보μ₯ν μ μμκΉμ?
κ·Έ λ΅μ 체κ³μ μ΄κ³ μλνλ λ€μ€ νκ²½ ν μ€νΈμ μμ΅λλ€. λ°λ‘ μ¬κΈ°μμ λͺ λ Ήμ€ κΈ°λ° μλν λκ΅¬μΈ Toxκ° νλ Python κ°λ°μ λꡬ ν€νΈμ νμμ μΈ λΆλΆμ΄ λ©λλ€. Toxλ ν μ€νΈλ₯Ό νμ€ννμ¬ λ¨μΌ λͺ λ ΉμΌλ‘ λ€μν κ΅¬μ± λ§€νΈλ¦μ€μ κ±Έμ³ ν μ€νΈλ₯Ό μ μνκ³ μ€νν μ μλλ‘ ν©λλ€.
μ΄ μ’ ν© κ°μ΄λλ Toxμ κΈ°λ³ΈλΆν° λ€μ€ νκ²½ ν μ€νΈλ₯Ό μν κ³ κΈ μ λ΅κΉμ§ μλ΄ν©λλ€. μ¬λ¬λΆμ μννΈμ¨μ΄κ° μ μΈκ³ μ¬μ©μμκ² νΈνλκ³ μμ μ μ΄λ©° μ€λΉλμμμ 보μ₯νλ νλ ₯μ μΈ ν μ€νΈ νμ΄νλΌμΈμ ꡬμΆνλ λ°©λ²μ μ΄ν΄λ³΄κ² μ΅λλ€.
λ€μ€ νκ²½ ν μ€νΈλ 무μμ΄λ©° μ μ€μν κΉμ?
λ€μ€ νκ²½ ν μ€νΈλ μ¬λ¬ κ°μ μλ‘ λ€λ₯Έ ꡬμ±μ λν΄ ν μ€νΈ μ€μνΈλ₯Ό μ€ννλ κ΄νμ λλ€. μ΄λ¬ν ꡬμ±, μ¦ "νκ²½"μ μΌλ°μ μΌλ‘ λ€μ μμμ λ°λΌ λ¬λΌμ§λλ€:
- Python μΈν°νλ¦¬ν° λ²μ : μ¬λ¬λΆμ μ½λκ° Python 3.8μμ μλνλ κ²λ§νΌ Python 3.11μμλ μ μλνλμ? κ³§ μΆμλ Python 3.12μμλ μ΄λ¨κΉμ?
- μ’ μμ± λ²μ : μ¬λ¬λΆμ μ ν리μΌμ΄μ μ Django, Pandas λλ Requestsμ κ°μ λΌμ΄λΈλ¬λ¦¬μ μμ‘΄ν μ μμ΅λλ€. μ¬μ©μκ° μ΄ ν¨ν€μ§λ€μ μ½κ° λ μ€λλκ±°λ μλ‘μ΄ λ²μ μ κ°μ§κ³ μλ€λ©΄ μλμ΄ μ€λ¨λ κΉμ?
- μ΄μ 체μ : μ¬λ¬λΆμ μ½λκ° Windows, macOS, Linuxμμ νμΌ κ²½λ‘μ μμ€ν νΈμΆμ μ¬λ°λ₯΄κ² μ²λ¦¬νλμ?
- μν€ν μ²: ARM κΈ°λ° νλ‘μΈμ(Apple Silicon λ±)μ λ±μ₯μΌλ‘ μΈν΄, λ€μν CPU μν€ν μ²(x86_64, arm64)μμμ ν μ€νΈκ° μ μ λ μ€μν΄μ§κ³ μμ΅λλ€.
λ€μ€ νκ²½ μ λ΅μ λΉμ¦λμ€ μ¬λ‘
μ΄λ¬ν μ’ λ₯μ ν μ€νΈλ₯Ό μ€μ νλ λ° μκ°μ ν¬μνλ κ²μ λ¨μν νμ μ μΈ λ Έλ ₯μ΄ μλλλ€. μ΄λ μ§μ μ μΈ λΉμ¦λμ€ μν₯μ λ―ΈμΉ©λλ€:
- μ§μ λΉμ© μ κ°: νΈνμ± λ¬Έμ λ₯Ό μ‘°κΈ°μ νμ ν¨μΌλ‘μ¨, μμμΉ λͺ»ν νκ²½μ κ°μ§ μ¬μ©μλ€λ‘λΆν° μμμ§λ μλ§μ μ§μ μμ²μ λ°©μ§ν μ μμ΅λλ€.
- μ¬μ©μ μ λ’°λ ν₯μ: λ€μν μ€μ μμ μμ μ μΌλ‘ μλνλ μννΈμ¨μ΄λ λ λμ νμ§λ‘ μΈμλ©λλ€. μ΄λ μ€ν μμ€ λΌμ΄λΈλ¬λ¦¬μ μμ© μ ν λͺ¨λμ μ€μν©λλ€.
- μνν μ κ·Έλ μ΄λ κ°λ₯: μλ‘μ΄ Python λ²μ μ΄ μΆμλλ©΄ ν μ€νΈ λ§€νΈλ¦μ€μ κ°λ¨ν μΆκ°ν μ μμ΅λλ€. ν μ€νΈκ° ν΅κ³Όνλ©΄ μ§μ μ€λΉκ° λ κ²μ λλ€. μ€ν¨νλ©΄ μμ ν΄μΌ ν μ¬νμ λν λͺ ννκ³ μ€ν κ°λ₯ν λͺ©λ‘μ μ»κ² λ©λλ€.
- κΈλ‘λ² ν μ§μ: μ΅μ λꡬλ₯Ό μ¬μ©νλ ν κ΅κ°μ κ°λ°μκ° νμ€νλ, μ½κ° μ€λλ μν°νλΌμ΄μ¦ μ€νμ μ¬μ©νλ λ€λ₯Έ μ§μμ νκ³Ό ν¨κ³Όμ μΌλ‘ νμ ν μ μλλ‘ λ³΄μ₯ν©λλ€.
Tox μκ°: μ¬λ¬λΆμ μλν λͺ λ Ή μΌν°
Toxλ μ΄ λ¬Έμ λ₯Ό μ°μνκ² ν΄κ²°νλλ‘ μ€κ³λμμ΅λλ€. Toxμ ν΅μ¬μ 격리λ Python κ°μ νκ²½ μμ±μ μλννκ³ , μ¬λ¬λΆμ νλ‘μ νΈμ ν΄λΉ μ’ μμ±μ μ€μΉν λ€μ, μ μλ λͺ λ Ή(ν μ€νΈ, λ¦°ν°, λ¬Έμ λΉλ λ±)μ μ€ννλ κ²μ λλ€.
μ΄ λͺ¨λ κ²μ λ¨μΌνκ³ κ°λ¨ν κ΅¬μ± νμΌμΈ tox.ini
μ μν΄ μ μ΄λ©λλ€.
μμνκΈ°: μ€μΉ λ° κΈ°λ³Έ ꡬμ±
μ€μΉλ pipλ‘ κ°λ¨ν©λλ€:
pip install tox
λ€μμΌλ‘, νλ‘μ νΈ λ£¨νΈμ tox.ini
νμΌμ μμ±ν©λλ€. μ¬λ¬ Python λ²μ μ λν΄ ν
μ€νΈνκΈ° μν μ΅μ ꡬμ±μΌλ‘ μμν΄ λ³΄κ² μ΅λλ€.
μμ: κΈ°λ³Έμ μΈ tox.ini
[tox] min_version = 3.7 isolated_build = true envlist = py38, py39, py310, py311 [testenv] description = Run the main test suite deps = pytest commands = pytest
μ΄λ₯Ό λΆμν΄ λ΄ μλ€:
[tox]
μΉμ : μ΄λ μ μ Tox μ€μ μ μν κ²μ λλ€.min_version
: μ΄ κ΅¬μ±μ μ€ννλ λ° νμν Toxμ μ΅μ λ²μ μ μ§μ ν©λλ€.isolated_build
: ν μ€νΈλ₯Ό μν΄ μ€μΉλκΈ° μ μ ν¨ν€μ§κ° 격리λ νκ²½μμ λΉλλλλ‘ λ³΄μ₯νλ μ΅μ λͺ¨λ² μ¬λ‘(PEP 517)μ λλ€.envlist
: μ΄κ²μ΄ λ€μ€ νκ²½ ν μ€νΈμ ν΅μ¬μ λλ€. Toxκ° κ΄λ¦¬νλ €λ νκ²½λ€μ μΌνλ‘ κ΅¬λΆλ λͺ©λ‘μ λλ€. μ¬κΈ°μλ 3.8λΆν° 3.11κΉμ§ κ° Python λ²μ λ³λ‘ λ€ κ°μ νκ²½μ μ μνμ΅λλ€.[testenv]
μΉμ : μ΄λenvlist
μ μ μλ λͺ¨λ νκ²½μ μν ν νλ¦Ώμ λλ€.description
: νκ²½μ΄ λ¬΄μμ νλμ§ μ€λͺ νλ μ μ©ν λ©μμ§μ λλ€.deps
: λͺ λ Ήμ μ€ννλ λ° νμν μ’ μμ± λͺ©λ‘μ λλ€. μ¬κΈ°μλpytest
λ§ νμν©λλ€.commands
: κ°μ νκ²½ λ΄μμ μ€νν λͺ λ Ήμ λλ€. μ¬κΈ°μλ λ¨μνpytest
ν μ€νΈ λ¬λλ₯Ό μ€νν©λλ€.
μ΄λ₯Ό μ€ννλ €λ©΄ ν°λ―Έλμμ νλ‘μ νΈμ λ£¨νΈ λλ ν°λ¦¬λ‘ μ΄λνμ¬ λ¨μν λ€μμ μ λ ₯ν©λλ€:
tox
Toxλ μ΄μ `envlist` (py38, py39 λ±)μ κ° νκ²½μ λν΄ λ€μ λ¨κ³λ₯Ό μνν©λλ€:
- μμ€ν μμ ν΄λΉ Python μΈν°ν리ν°λ₯Ό μ°Ύμ΅λλ€ (μ: `python3.8`, `python3.9`).
.tox/
λλ ν 리 λ΄μ μλ‘κ³ κ²©λ¦¬λ κ°μ νκ²½μ μμ±ν©λλ€.- νλ‘μ νΈμ `deps` μλμ λμ΄λ μ’ μμ±μ μ€μΉν©λλ€.
- `commands` μλμ λμ΄λ λͺ λ Ήμ μ€νν©λλ€.
μ΄λ€ νκ²½μμλ λ¨κ³κ° μ€ν¨νλ©΄ Toxλ μ€λ₯λ₯Ό λ³΄κ³ νκ³ 0μ΄ μλ μν μ½λλ‘ μ’ λ£νλ―λ‘ μ§μμ ν΅ν©(CI) μμ€ν μ μλ²½ν©λλ€.
μ¬μΈ΅ λΆμ: κ°λ ₯ν tox.ini
μμ±νκΈ°
κΈ°λ³Έ μ€μ μ κ°λ ₯νμ§λ§, Toxμ μ§μ ν λ§λ²μ 볡μ‘ν ν μ€νΈ λ§€νΈλ¦μ€λ₯Ό μμ±νκΈ° μν μ μ°ν κ΅¬μ± μ΅μ μ μμ΅λλ€.
μμ±μ νκ²½: μ‘°ν© ν μ€νΈμ ν΅μ¬
Django λ²μ 3.2μ 4.2λ₯Ό μ§μν΄μΌ νλ©° Python 3.9μ 3.10μμ μ€νλλ λΌμ΄λΈλ¬λ¦¬κ° μλ€κ³ κ°μ ν΄ λ΄ μλ€. λ€ κ°μ§ μ‘°ν©μ μλμΌλ‘ μ μνλ κ²μ λ°λ³΅μ μΌ κ²μ λλ€:
λ°λ³΅μ μΈ λ°©λ²: envlist = py39-django32, py39-django42, py310-django32, py310-django42
Toxλ μ€κ΄νΈ {}
λ₯Ό μ¬μ©νμ¬ ν¨μ¬ λ κΉλνκ³ μμ±μ μΈ κ΅¬λ¬Έμ μ 곡ν©λλ€:
μμ±μ μΈ λ°©λ²: envlist = {py39,py310}-django{32,42}
μ΄ ν μ€μ λμΌν λ€ κ°μ§ νκ²½μΌλ‘ νμ₯λ©λλ€. μ΄ μ κ·Ό λ°©μμ νμ₯μ±μ΄ λ§€μ° λ°μ΄λ©λλ€. μλ‘μ΄ Python λ²μ μ΄λ Django λ²μ μ μΆκ°νλ κ²μ κ° λͺ©λ‘μ νλͺ© νλλ₯Ό μΆκ°νλ κ²λ§νΌ κ°λ¨ν©λλ€.
μμ-μ‘°κ±΄λΆ μ€μ : κ° νκ²½ μ¬μ©μ μ§μ
μ΄μ λ§€νΈλ¦μ€λ₯Ό μ μνμΌλ, κ° νκ²½μ μ¬λ°λ₯Έ Django λ²μ μ μ€μΉνλλ‘ Toxμ μ΄λ»κ² μ§μν κΉμ? μ΄λ μμ-μ‘°κ±΄λΆ μ€μ μΌλ‘ μνλ©λλ€.
[tox] envlist = {py39,py310}-django{32,42} [testenv] deps = pytest django32: Django>=3.2,<3.3 django42: Django>=4.2,<4.3 commands = pytest
μ¬κΈ°μ `django32: Django>=3.2,<3.3` μ΄ μ€μ Toxμ λ€μκ³Ό κ°μ΄ λ§ν©λλ€: "νκ²½ μ΄λ¦μ `django32` μμκ° ν¬ν¨λ κ²½μ°μλ§ μ΄ μ’ μμ±μ ν¬ν¨νμΈμ." `django42`λ λ§μ°¬κ°μ§μ λλ€. Toxλ νκ²½ μ΄λ¦(μ: `py310-django42`)μ ꡬ문 λΆμνκ³ μ¬λ°λ₯Έ μ€μ μ μ μ©ν λ§νΌ μ€λ§νΈν©λλ€.
μ΄κ²μ λ€μμ κ΄λ¦¬νλ λ° μμ²λκ² κ°λ ₯ν κΈ°λ₯μ λλ€:
- μ΄μ /μλ‘μ΄ Python λ²μ κ³Ό νΈνλμ§ μλ μ’ μμ±.
- ν΅μ¬ λΌμ΄λΈλ¬λ¦¬(Pandas, NumPy, SQLAlchemy λ±)μ λ€λ₯Έ λ²μ μ λν ν μ€νΈ.
- νλ«νΌλ³ μ’ μμ±μ μ‘°κ±΄λΆ μ€μΉ.
κΈ°λ³Έ ν μ€νΈλ₯Ό λμ΄ νλ‘μ νΈ κ΅¬μ‘°ν
κ°λ ₯ν νμ§ νμ΄νλΌμΈμ λ¨μν ν μ€νΈλ₯Ό μ€ννλ κ² μ΄μμ ν¬ν¨ν©λλ€. λ¦°ν°, νμ 체컀λ₯Ό μ€ννκ³ λ¬Έμλ₯Ό λΉλν΄μΌ ν©λλ€. μ΄λ¬ν μμ μ μν΄ λ³λμ Tox νκ²½μ μ μνλ κ²μ΄ λͺ¨λ² μ¬λ‘μ λλ€.
[tox] envlist = py{39,310}, lint, typing, docs [testenv] deps = pytest commands = pytest [testenv:lint] description = λ¦°ν° μ€ν (ruff, black) basepython = python3.10 deps = ruff black commands = ruff check . black --check . [testenv:typing] description = μ μ νμ 체컀 μ€ν (mypy) basepython = python3.10 deps = mypy # also include other dependencies with type hints django djangorestframework commands = mypy my_project/ [testenv:docs] description = λ¬Έμ λΉλ basepython = python3.10 deps = sphinx commands = sphinx-build -b html docs/source docs/build/html
μ¬κΈ°μ μλ‘μ΄ μ μ λ€μκ³Ό κ°μ΅λλ€:
- νΉμ νκ²½ μΉμ : `[testenv:lint]`, `[testenv:typing]`, `[testenv:docs]`λ₯Ό μΆκ°νμ΅λλ€. μ΄ μΉμ λ€μ ν΄λΉ μ΄λ¦μ νκ²½μ λν μ€μ μ ꡬ체μ μΌλ‘ μ μνλ©°, `[testenv]`μ κΈ°λ³Έκ°μ μ¬μ μν©λλ€.
basepython
: `lint` λλ `docs`μ κ°μ λΉ ν μ€νΈ νκ²½μ κ²½μ°, λͺ¨λ Python λ²μ μμ μ€νν νμκ° μλ κ²½μ°κ° λ§μ΅λλ€. `basepython`μ μ¬μ©νλ©΄ νΉμ μΈν°ν리ν°μ κ³ μ νμ¬ λ λΉ λ₯΄κ³ κ²°μ λ‘ μ μΌλ‘ λ§λ€ μ μμ΅λλ€.- κΉλν λΆλ¦¬: μ΄ κ΅¬μ‘°λ μ’ μμ±μ κΉλνκ² μ μ§ν©λλ€. `lint` νκ²½μ λ¦°ν°λ§ μ€μΉνλ©°, μ£Ό ν μ€νΈ νκ²½μλ νμνμ§ μμ΅λλ€.
μ΄μ `tox`λ‘ λͺ¨λ νκ²½μ μ€ννκ±°λ, `tox -e py310,lint`λ‘ νΉμ μΈνΈλ₯Ό μ€ννκ±°λ, `tox -e docs`λ‘ λ¨μΌ νκ²½λ§ μ€νν μ μμ΅λλ€.
κΈλ‘λ² κ·λͺ¨ μλνλ₯Ό μν CI/CDμ Tox ν΅ν©
Toxλ₯Ό λ‘컬μμ μ€ννλ κ²λ μ’μ§λ§, μ§μ ν νμ μ§μμ ν΅ν©/μ§μμ λ°°ν¬(CI/CD) νμ΄νλΌμΈμ ν΅ν©λ λ λ°νλ©λλ€. μ΄λ λͺ¨λ μ½λ λ³κ²½μ΄ μ 체 ν μ€νΈ λ§€νΈλ¦μ€μ λν΄ μλμΌλ‘ κ²μ¦λλλ‘ λ³΄μ₯ν©λλ€.
GitHub Actions, GitLab CI, Jenkinsμ κ°μ μλΉμ€κ° μ΄μ μλ²½ν©λλ€. μ΄λ€μ λ€μν μ΄μ 체μ μμ μμ μ μ€ννμ¬ ν¬κ΄μ μΈ OS νΈνμ± λ§€νΈλ¦μ€λ₯Ό ꡬμΆν μ μλλ‘ ν©λλ€.
μμ: GitHub Actions μν¬νλ‘μ°
Linux, macOS, Windowsμ κ±Έμ³ Tox νκ²½μ λ³λ ¬λ‘ μ€ννλ GitHub Actions μν¬νλ‘μ°λ₯Ό λ§λ€μ΄ λ΄ μλ€.
.github/workflows/ci.yml
μ νμΌμ μμ±ν©λλ€:
name: CI on: [push, pull_request] jobs: test: runs-on: ${{ matrix.os }} strategy: fail-fast: false matrix: os: [ubuntu-latest, macos-latest, windows-latest] python-version: ['3.8', '3.9', '3.10', '3.11'] steps: - name: 리ν¬μ§ν 리 체ν¬μμ uses: actions/checkout@v3 - name: Python ${{ matrix.python-version }} μ€μ uses: actions/setup-python@v4 with: python-version: ${{ matrix.python-version }} - name: Tox μ€μΉ run: pip install tox tox-gh-actions - name: Tox μ€ν run: tox -e py
μ΄ μν¬νλ‘μ°λ₯Ό λΆμν΄ λ΄ μλ€:
strategy.matrix
: μ΄κ²μ CI λ§€νΈλ¦μ€μ ν΅μ¬μ λλ€. GitHub Actionsλ `os`μ `python-version`μ κ° μ‘°ν©μ λν΄ λ³λμ μμ μ μμ±ν©λλ€. μ΄ κ΅¬μ±μ κ²½μ°, 3κ°μ μ΄μ 체μ Γ 4κ°μ Python λ²μ = 12κ°μ λ³λ ¬ μμ μ΄ λ©λλ€.actions/setup-python@v4
: μ΄ νμ€ μ‘μ μ κ° μμ μ νμν νΉμ Python λ²μ μ μ€μ ν©λλ€.tox-gh-actions
: μ΄λ CI νκ²½μ Python λ²μ μ μ¬λ°λ₯Έ Tox νκ²½μ μλμΌλ‘ λ§€ννλ μ μ©ν Tox νλ¬κ·ΈμΈμ λλ€. μλ₯Ό λ€μ΄, Python 3.9μμ μ€νλλ μμ μμ `tox -e py`λ μλμΌλ‘ `tox -e py39`λ₯Ό μ€ννλλ‘ ν΄κ²°λ©λλ€. μ΄λ CI μ€ν¬λ¦½νΈμμ 볡μ‘ν λ‘μ§μ μμ±νλ μκ³ λ₯Ό λμ΄μ€λλ€.
μ΄μ μ½λκ° νΈμλ λλ§λ€ μ 체 ν μ€νΈ λ§€νΈλ¦μ€κ° μΈ κ°μ§ μ£Όμ μ΄μ 체μ μμ μλμΌλ‘ μ€νλ©λλ€. λ³κ²½ μ¬νμ΄ λΉνΈνμ±μ μ λ°νλμ§ μ¦κ°μ μΈ νΌλλ°±μ λ°μ, κΈλ‘λ² μ¬μ©μ κΈ°λ°μ μν΄ μμ κ° μκ² λΉλν μ μμ΅λλ€.
κ³ κΈ μ λ΅ λ° λͺ¨λ² μ¬λ‘
{posargs}
λ₯Ό μ¬μ©νμ¬ λͺ
λ Ήμ μΈμ μ λ¬νκΈ°
λλλ‘ ν
μ€νΈ λ¬λμ μΆκ° μΈμλ₯Ό μ λ¬ν΄μΌ ν λκ° μμ΅λλ€. μλ₯Ό λ€μ΄, νΉμ ν
μ€νΈ νμΌμΈ pytest tests/test_api.py
λ₯Ό μ€ννκ³ μΆμ μ μμ΅λλ€. Toxλ {posargs}
λ체λ₯Ό ν΅ν΄ μ΄λ₯Ό μ§μν©λλ€.
`tox.ini`λ₯Ό μμ ν©λλ€:
[testenv] deps = pytest commands = pytest {posargs}
μ΄μ Toxλ₯Ό λ€μκ³Ό κ°μ΄ μ€νν μ μμ΅λλ€:
tox -e py310 -- -k "test_login" -v
--
λ Toxλ₯Ό μν μΈμμ λͺ
λ Ήμ μν μΈμλ₯Ό ꡬλΆν©λλ€. κ·Έ λ€μ λͺ¨λ κ²μ {posargs}
λ‘ λ체λ©λλ€. Toxλ `py310` νκ²½ λ΄μμ pytest -k "test_login" -v
λ₯Ό μ€νν©λλ€.
νκ²½ λ³μ μ μ΄νκΈ°
μ ν리μΌμ΄μ μ νκ²½ λ³μ(μ: `DJANGO_SETTINGS_MODULE`)μ λ°λΌ λ€λ₯΄κ² λμν μ μμ΅λλ€. `setenv` μ§μλ¬Έμ μ¬μ©νλ©΄ Tox νκ²½ λ΄μμ μ΄λ₯Ό μ μ΄ν μ μμ΅λλ€.
[testenv] setenv = PYTHONPATH = . MYAPP_MODE = testing [testenv:docs] setenv = SPHINX_BUILD = 1
λ λΉ λ₯Έ Tox μ€νμ μν ν
- λ³λ ¬ λͺ¨λ: `tox -p auto`λ₯Ό μ€ννμ¬ Toxκ° μ¬μ© κ°λ₯ν CPU μ½μ΄ μλ§νΌ νκ²½μ λ³λ ¬λ‘ μ€ννκ² νμΈμ. μ΄λ νλμ μΈ λ¨Έμ μμ λ§€μ° ν¨κ³Όμ μ λλ€.
- νκ²½ μ νμ μ¬κ΅¬μ±: κΈ°λ³Έμ μΌλ‘ Toxλ νκ²½μ μ¬μ¬μ©ν©λλ€. `tox.ini` λλ `requirements.txt`μ μ’ μμ±μ΄ λ³κ²½λλ©΄ Toxμ νκ²½μ μ²μλΆν° λ€μ λΉλνλλ‘ μ§μν΄μΌ ν©λλ€. μ¬κ΅¬μ± νλκ·Έλ₯Ό μ¬μ©νμΈμ: `tox -r -e py310`.
- CI μΊμ±: CI/CD νμ΄νλΌμΈμμ
.tox/
λλ ν 리λ₯Ό μΊμνμΈμ. μ΄λ μ’ μμ±μ΄ λ³κ²½λμ§ μλ ν λ§€λ² λ€μ΄λ‘λλκ³ μ€μΉλ νμκ° μμΌλ―λ‘ νμ μ€ν μλλ₯Ό ν¬κ² λμΌ μ μμ΅λλ€.
μ€μ κΈλ‘λ² μ¬μ© μ¬λ‘
μλλ¦¬μ€ 1: μ€ν μμ€ λ°μ΄ν° λΆμ λΌμ΄λΈλ¬λ¦¬
Pandasμ NumPyλ₯Ό κΈ°λ°μΌλ‘ ꡬμΆλ μΈκΈ° μλ λΌμ΄λΈλ¬λ¦¬λ₯Ό μ μ§ κ΄λ¦¬νκ³ μμ΅λλ€. μ¬λ¬λΆμ μ¬μ©μλ μ μΈκ³μ λ°μ΄ν° κ³Όνμμ λΆμκ°μ λλ€.
- κ³Όμ : μ¬λ¬ Python, Pandas, NumPy λ²μ μ μ§μνκ³ , Linux μλ², macOS λ©ν±, Windows λ°μ€ν¬ν±μμ μλνλλ‘ λ³΄μ₯ν΄μΌ ν©λλ€.
- Tox μ루μ
:
envlist = {py39,py310,py311}-{pandas1,pandas2}-{numpy18,numpy19}
μ¬λ¬λΆμ `tox.ini`λ μμ-μ‘°κ±΄λΆ μ€μ μ μ¬μ©νμ¬ κ° νκ²½μ μ¬λ°λ₯Έ λΌμ΄λΈλ¬λ¦¬ λ²μ μ μ€μΉν κ²μ λλ€. GitHub Actions μν¬νλ‘μ°λ μΈ κ°μ§ μ£Όμ μ΄μ 체μ μ κ±Έμ³ μ΄ λ§€νΈλ¦μ€λ₯Ό ν μ€νΈν κ²μ λλ€. μ΄λ μ΄μ Pandas λ²μ μ μ¬μ©νλ λΈλΌμ§ μ¬μ©μκ° μ΅μ μ€νμ μ¬μ©νλ μΌλ³Έ μ¬μ©μμ λμΌνκ² μμ μ μΈ κ²½νμ μ»λλ‘ λ³΄μ₯ν©λλ€.
μλλ¦¬μ€ 2: ν΄λΌμ΄μΈνΈ λΌμ΄λΈλ¬λ¦¬λ₯Ό ν¬ν¨ν μν°νλΌμ΄μ¦ SaaS μ ν리μΌμ΄μ
μ λ½μ λ³Έμ¬λ₯Ό λ μ¬λ¬λΆμ νμ¬λ SaaS μ νμ μ 곡ν©λλ€. μ¬λ¬λΆμ κ³ κ°μ μ μΈκ³μ λκΈ°μ λ€μ΄λ©°, μ΄λ€ μ€ λ€μλ μμ μ±μ μν΄ μ΄μ 체μ λ° Pythonμ μ€λλ μ₯κΈ° μ§μ(LTS) λ²μ μ μ¬μ©ν©λλ€.
- κ³Όμ : κ°λ° νμ μ΅μ λꡬλ₯Ό μ¬μ©νμ§λ§, ν΄λΌμ΄μΈνΈ λΌμ΄λΈλ¬λ¦¬λ μ΄μ μν°νλΌμ΄μ¦ νκ²½κ³Ό νμ νΈνλμ΄μΌ ν©λλ€.
- Tox μ루μ
:
envlist = py38, py39, py310, py311
μ¬λ¬λΆμ `tox.ini`λ Python 3.8μ λν΄ λͺ¨λ ν μ€νΈκ° ν΅κ³Όνλλ‘ λ³΄μ₯νλ©°, μ΄λ λΆλ―Έμ μ£Όμ ν΄λΌμ΄μΈνΈμμ νμ€μΌ μ μμ΅λλ€. CIμμ μ΄λ₯Ό μλμΌλ‘ μ€νν¨μΌλ‘μ¨, κ°λ°μλ€μ΄ μ€μλ‘ μ΅μ Python λ²μ μμλ§ μ¬μ© κ°λ₯ν ꡬ문μ΄λ λΌμ΄λΈλ¬λ¦¬λ₯Ό μ¬μ©νλ κΈ°λ₯μ λμ νλ κ²μ λ°©μ§νμ¬ λΉμ©μ΄ λ§μ΄ λλ λ°°ν¬ μ€ν¨λ₯Ό λ§μ μ μμ΅λλ€.
κ²°λ‘ : κΈλ‘λ² μμ κ°μ κ°μ§κ³ λ°°ν¬νμΈμ
λ€μ€ νκ²½ ν μ€νΈλ λ μ΄μ μ¬μΉκ° μλλλ€. κ³ νμ§μ μ λ¬Έ μννΈμ¨μ΄λ₯Ό κ°λ°νκΈ° μν κ·Όλ³Έμ μΈ κ΄νμ λλ€. Toxλ₯Ό ν΅ν μλνλ₯Ό μμ©ν¨μΌλ‘μ¨, μ΄ λ³΅μ‘ν κ³Όμ λ₯Ό κ°μνλκ³ λ°λ³΅ κ°λ₯ν νλ‘μΈμ€λ‘ μ νν μ μμ΅λλ€.
λ¨μΌ tox.ini
νμΌμ μ§μλλ νκ²½μ μ μνκ³ μ΄λ₯Ό CI/CD νμ΄νλΌμΈκ³Ό ν΅ν©ν¨μΌλ‘μ¨ κ°λ ₯ν νμ§ κ²μ΄νΈλ₯Ό μμ±ν©λλ€. μ΄ κ²μ΄νΈλ μ ν리μΌμ΄μ
μ΄ κ²¬κ³ νκ³ νΈνλλ©° λ€μνκ³ κΈλ‘λ²ν μ¬μ©μμκ² μ€λΉλμμμ 보μ₯ν©λλ€. μ¬λ¬λΆμ λμ°ν "μ μ»΄ν¨ν°μμλ μ μλν©λλ€" λ¬Έμ μ λν κ±±μ μ λ©μΆκ³ , μ μΈκ³ μ΄λμ μλ λͺ¨λ μ¬λμ μ»΄ν¨ν°μμ μλν κ²μ΄λΌλ νμ μ κ°μ§κ³ μ½λλ₯Ό λ°°ν¬ν μ μμ΅λλ€.