Noxãšã¯äœãïŒ ð€
Noxã¯ãPythonãããžã§ã¯ãã«ããããã¹ãããªã³ãã£ã³ã°ããã«ããªã©ã®æ§ã ãªã¿ã¹ã¯ãèªååããããã®ã³ãã³ãã©ã€ã³ããŒã«ã§ããç¹ã«ãè€æ°ã®PythonããŒãžã§ã³ãç°å¢ã§äžè²«ãããã¹ããå®è¡ãããå Žåã«åŒ·åãªå³æ¹ãšãªããŸãã
䌌ããããªããŒã«ãšããŠToxããããŸãããNoxã®æ倧ã®ç¹åŸŽã¯ãèšå®ãã¡ã€ã«ãPythonã¹ã¯ãªããïŒnoxfile.py
ïŒã§èšè¿°ããç¹ã§ããããã«ãããToxã®èšå®ãã¡ã€ã«ïŒtox.ini
ïŒãããæè»ã§åŒ·åãªèšå®ãå¯èœã«ãªããŸããPythonã®æšæºã©ã€ãã©ãªããµãŒãããŒãã£ã©ã€ãã©ãªãèªç±ã«å©çšããŠãè€éãªã¿ã¹ã¯å®çŸ©ãåçãªèšå®ãè¡ãããšãã§ããŸãã
Noxã¯ãGoogle Cloud Platformã®Pythonã¯ã©ã€ã¢ã³ãã©ã€ãã©ãªããpip, pipx, cibuildwheel, Scikit-HEP, Urllib3ãªã©ãå€ãã®èåãªPythonãããžã§ã¯ãã§æ¡çšãããŠããŸãã
ð Noxã®ã€ã³ã¹ããŒã«
Noxã¯éåžžããããžã§ã¯ãåºæã®ä»®æ³ç°å¢ã§ã¯ãªããã°ããŒãã«ãªç°å¢ã«ã€ã³ã¹ããŒã«ããããšãæšå¥šãããŸããããã«ãããã©ã®ãããžã§ã¯ããã£ã¬ã¯ããªããã§ãnox
ã³ãã³ããå®è¡ã§ããããã«ãªããŸãã
pipx
ã䜿ãã®ãæãæšå¥šãããæ¹æ³ã§ããpipx
ã¯Python補ã®CLIããŒã«ãç¬ç«ããç°å¢ã«ã€ã³ã¹ããŒã«ã»ç®¡çããããã®ããŒã«ã§ãã
pipx install nox
ããpipx
ãã€ã³ã¹ããŒã«ãããŠããªãå Žåã¯ããŸãpipx
ãã€ã³ã¹ããŒã«ããŠãã ããã
python3 -m pip install --user pipx
python3 -m pipx ensurepath
ãããã¯ãéåžžã®pip
ã䜿ã£ãŠã°ããŒãã«ãªPythonç°å¢ã«ã€ã³ã¹ããŒã«ããããšãå¯èœã§ãïŒãã ããã·ã¹ãã ã®Pythonç°å¢ãæ±æããå¯èœæ§ããããã泚æãå¿
èŠã§ãïŒã
python3 -m pip install --user nox
ã€ã³ã¹ããŒã«åŸã以äžã®ã³ãã³ãã§Noxãæ£ããã€ã³ã¹ããŒã«ãããã確èªã§ããŸãã
nox --version
ãŸãã¯
pip show nox
ããã«ãããã€ã³ã¹ããŒã«ãããŠããNoxã®ããŒãžã§ã³æ å ±ã衚瀺ãããŸãã
ð§ åºæ¬çãªäœ¿ãæ¹: `noxfile.py` ã®äœæãšå®è¡
Noxã®èšå®ã¯ããããžã§ã¯ãã®ã«ãŒããã£ã¬ã¯ããªã«noxfile.py
ãšããååã®Pythonãã¡ã€ã«ãäœæããŠè¡ããŸãããã®ãã¡ã€ã«å
ã§ããã»ãã·ã§ã³ããšåŒã°ããã¿ã¹ã¯ã®åäœãå®çŸ©ããŸãã
ã»ãã·ã§ã³ã¯ãç¹å®ã®Pythonç°å¢ãšãã®ç°å¢ã§å®è¡ãããäžé£ã®ã³ãã³ããå®çŸ©ãããã®ã§ããããã¯Toxã«ããããç°å¢ïŒenvironmentïŒãã«çžåœããŸãã
ç°¡åãª`noxfile.py`ã®äŸ
以äžã¯ã`flake8`ã«ãããªã³ãã£ã³ã°ãš`pytest`ã«ãããã¹ããå®è¡ããç°¡åãªnoxfile.py
ã®äŸã§ãã
import nox
# @nox.sessionãã³ã¬ãŒã¿ã䜿ã£ãŠã»ãã·ã§ã³ãå®çŸ©
@nox.session
def lint(session):
"""ã³ãŒãã®éç解æãå®è¡ããã»ãã·ã§ã³"""
# ã»ãã·ã§ã³å
ã§äœ¿çšããã©ã€ãã©ãªãã€ã³ã¹ããŒã«
session.install("flake8")
# ã€ã³ã¹ããŒã«ããã³ãã³ããå®è¡
session.run("flake8", ".", "--count", "--select=E9,F63,F7,F82", "--show-source", "--statistics")
@nox.session(python=["3.9", "3.10", "3.11", "3.12"]) # è€æ°ã®PythonããŒãžã§ã³ãæå®
def tests(session):
"""pytestã䜿ã£ãŠãã¹ããå®è¡ããã»ãã·ã§ã³"""
# çŸåšã®ãããžã§ã¯ããšãã¹ãçšäŸåã©ã€ãã©ãªãã€ã³ã¹ããŒã«
# requirements.txt ã pyproject.toml (Poetry, PDMãªã©) ãããã°ããããå©çšå¯èœ
session.install(".[test]") # ãã `.[test]` ã®ãããªextraãããã°
# session.install("pytest", "pytest-cov") # åå¥ã«æå®ãå¯èœ
# pytestãå®è¡ã session.posargs ã䜿ããšãnoxã³ãã³ãçµç±ã§åŒæ°ãæž¡ãã
session.run("pytest", *session.posargs)
ã»ãã·ã§ã³ã®å®è¡
noxfile.py
ãäœæããããã¿ãŒããã«ã§ä»¥äžã®ã³ãã³ããå®è¡ããŸãã
å©çšå¯èœãªã»ãã·ã§ã³ã®äžèŠ§è¡šç€º:
nox -l
# ãŸãã¯
nox --list
ããã«ãããnoxfile.py
ã§å®çŸ©ãããŠããã»ãã·ã§ã³ã®äžèŠ§ã衚瀺ãããŸããäžèšã®äŸã ãšã`lint`ãš`tests-3.9`, `tests-3.10`, `tests-3.11`, `tests-3.12` ã衚瀺ãããã§ãããã
ãã¹ãŠã®ã»ãã·ã§ã³ãå®è¡:
nox
åŒæ°ãªãã§nox
ãå®è¡ãããšãããã©ã«ãã§å®çŸ©ãããŠãããã¹ãŠã®ã»ãã·ã§ã³ãé çªã«å®è¡ãããŸããNoxã¯åã»ãã·ã§ã³ããšã«ç¬ç«ããä»®æ³ç°å¢ïŒããã©ã«ãã§ã¯`.nox`ãã£ã¬ã¯ããªä»¥äžã«äœæïŒãèªåã§äœæããæå®ãããäŸåé¢ä¿ãã€ã³ã¹ããŒã«ããã³ãã³ããå®è¡ããŸãã
ç¹å®ã®ã»ãã·ã§ã³ãå®è¡:
nox -s lint
# ãŸãã¯
nox --session lint
-s
(ãŸã㯠--session
) ãªãã·ã§ã³ã«ç¶ããŠã»ãã·ã§ã³åãæå®ãããšããã®ã»ãã·ã§ã³ã®ã¿ãå®è¡ã§ããŸãã
è€æ°ã®ã»ãã·ã§ã³ãåå¥ã«æå®ããŠå®è¡:
nox -s lint tests-3.10
ç¹å®ã®PythonããŒãžã§ã³ãæå®ããŠå®è¡:
Noxã§ã¯ãPythonããŒãžã§ã³ãã»ãã·ã§ã³éžæã®ããŒãšããŠäœ¿ããŸãã
nox -p 3.11
# ãŸãã¯
nox --python 3.11
ããã«ãããPython 3.11ã䜿çšããããã«æå®ãããŠãããã¹ãŠã®ã»ãã·ã§ã³ïŒãã®äŸã§ã¯`tests-3.11`ïŒãå®è¡ãããŸããããã¯Toxã®-e py311
ãšã¯ç°ãªããPythonããŒãžã§ã³èªäœãã»ã¬ã¯ã¿ãšããŠæ±ããç¹ãNoxã®äŸ¿å©ãªç¹åŸŽã§ãã
Positional Arguments (ã³ãã³ãã©ã€ã³åŒæ°ã®åŒãæž¡ã):
session.posargs
ã䜿ããšãnox
ã³ãã³ãã«æž¡ãããè¿œå ã®åŒæ°ãã»ãã·ã§ã³å
ã®ã³ãã³ãïŒäŸ: `pytest`ïŒã«æž¡ãããšãã§ããŸãã
# pytestã« `-k "ç¹å®ã®ãã¹ãå"` ãš `-v` ãªãã·ã§ã³ãæž¡ã
nox -s tests -- -k "ç¹å®ã®ãã¹ãå" -v
--
ã®åŸã«ç¶ãåŒæ°ã session.posargs
ã«ãªã¹ããšããŠæ ŒçŽãããŸãã
ð ã»ãã·ã§ã³ã®è©³çŽ°èšå®
@nox.session
ãã³ã¬ãŒã¿ããã»ãã·ã§ã³é¢æ°ã«æž¡ãããsession
ãªããžã§ã¯ããéããŠãæ§ã
ãªèšå®ãè¡ãããšãã§ããŸãã
`@nox.session` ãã³ã¬ãŒã¿ã®åŒæ°
åŒæ° | 説æ | äŸ |
---|---|---|
python | ã»ãã·ã§ã³ã§äœ¿çšããPythonã€ã³ã¿ããªã¿ã®ããŒãžã§ã³ãæå®ããŸããæååãŸãã¯ãªã¹ãã§æå®ã§ããŸããFalse ãæå®ãããšä»®æ³ç°å¢ãäœæããŸããïŒã·ã¹ãã Pythonã䜿çšïŒã | python="3.11" python=["3.9", "3.10"] python=False |
venv_backend | ä»®æ³ç°å¢ãäœæããããã¯ãšã³ããæå®ããŸãã"virtualenv" (ããã©ã«ã), "conda" , "mamba" , "uv" ãªã©ãéžæå¯èœã§ããNone ãæå®ãããšä»®æ³ç°å¢ãäœæããŸããã | venv_backend="conda" venv_backend="uv" |
venv_params | ä»®æ³ç°å¢äœææã«ããã¯ãšã³ãã«æž¡ãè¿œå ã®åŒæ°ããªã¹ãã§æå®ããŸãã | venv_params=["--system-site-packages"] |
reuse_venv | True ãæå®ãããšãæ¢åã®ä»®æ³ç°å¢ãåå©çšããŸããããã©ã«ãã¯False ã§ãæ¯åã¯ãªãŒã³ãªç°å¢ãäœæããŸãã | reuse_venv=True |
name | ã»ãã·ã§ã³ã®ããã©ã«ãåïŒé¢æ°åïŒãäžæžãããŸãã | name="docs-build" |
tags | ã»ãã·ã§ã³ã«ã¿ã°ãä»ããŸããã¿ã°ã䜿ã£ãŠã»ãã·ã§ã³ãã°ã«ãŒãåãã-t ãªãã·ã§ã³ã§å®è¡ã§ããŸãã | tags=["test", "core"] |
`session` ãªããžã§ã¯ãã®äž»ãªã¡ãœãããšå±æ§
ã¡ãœãã/å±æ§ | 説æ | äŸ |
---|---|---|
session.install(*args) | æå®ãããããã±ãŒãžãã»ãã·ã§ã³ã®ä»®æ³ç°å¢ã«ã€ã³ã¹ããŒã«ããŸããpip installãšåãåŒæ°ãæå®ã§ããŸãã | session.install("pytest", "requests>=2.0") session.install("-r", "requirements.txt") session.install(".[dev]") |
session.run(*cmd, **kwargs) | æå®ãããã³ãã³ããã»ãã·ã§ã³ã®ä»®æ³ç°å¢å
ã§å®è¡ããŸããã³ãã³ããšãã®åŒæ°ãåå¥ã®æååãšããŠæž¡ããŸããexternal=True ãæå®ãããšãä»®æ³ç°å¢å€ã®ã³ãã³ããå®è¡ã§ããŸãã | session.run("pytest", "-v", "tests/") session.run("bash", "-c", "echo 'Hello'", external=True) |
session.log(message) | ã³ã³ãœãŒã«ã«ã¡ãã»ãŒãžãåºåããŸãã | session.log("ãã¹ããéå§ããŸã...") |
session.error(*message) | ãšã©ãŒã¡ãã»ãŒãžãåºåããã»ãã·ã§ã³ã倱æãããŸãã | session.error("å¿
èŠãªãã¡ã€ã«ãèŠã€ãããŸãã") |
session.skip(*message) | ã¡ãã»ãŒãžãåºåããã»ãã·ã§ã³ãã¹ãããããŸãã | session.skip("ãã®ç°å¢ã§ã¯å®è¡äžèŠã§ã") |
session.posargs | nox ã³ãã³ãã©ã€ã³ã§-- 以éã«æž¡ãããåŒæ°ã®ãªã¹ãã | session.run("pytest", *session.posargs) |
session.python | ã»ãã·ã§ã³ã§äœ¿çšãããŠããPythonã€ã³ã¿ããªã¿ã®ããŒãžã§ã³æååã | if session.python == "3.11": ... |
session.invoked_from | Noxãå®è¡ããããã£ã¬ã¯ããªã®ãã¹ã | print(session.invoked_from) |
session.create_tmp() | äžæãã£ã¬ã¯ããªãäœæãããã®ãã¹ãè¿ããŸããã»ãã·ã§ã³çµäºæã«èªåã§ã¯ãªãŒã³ã¢ãããããŸãã | tmpdir = session.create_tmp() |
session.cd(path) | ã»ãã·ã§ã³å ã§ã®ã«ã¬ã³ããã£ã¬ã¯ããªãå€æŽããŸããã³ã³ããã¹ããããŒãžã£ãšããŠã䜿çšå¯èœã§ãã | with session.cd("docs"): session.run("make", "html") |
ãããã®æ©èœãçµã¿åãããããšã§ãéåžžã«æè»ãªã¿ã¹ã¯èªååãå®çŸã§ããŸãã
âš é«åºŠãªæ©èœ
ãã©ã¡ãŒã¿åã»ãã·ã§ã³ (`@nox.parametrize`)
pytestã®ãã©ã¡ãŒã¿åãšåæ§ã«ãNoxã§ãã»ãã·ã§ã³ããã©ã¡ãŒã¿åã§ããŸããããã«ãããåãåŠçãç°ãªããã©ã¡ãŒã¿ã§ç¹°ãè¿ãå®è¡ããã»ãã·ã§ã³ãç°¡æœã«èšè¿°ã§ããŸãã
import nox
@nox.session
@nox.parametrize(
"django_version",
["3.2", "4.0", "4.1"]
)
def tests(session, django_version):
session.install(f"django=={django_version}", "pytest", ".")
session.run("pytest")
# å®è¡ãããã»ãã·ã§ã³:
# tests(django_version='3.2')
# tests(django_version='4.0')
# tests(django_version='4.1')
è€æ°ã®ãã©ã¡ãŒã¿ãçµã¿åãããããšãå¯èœã§ãã
import nox
@nox.session(python=["3.10", "3.11"])
@nox.parametrize(
"db_backend",
["sqlite", "postgres"]
)
def tests(session, db_backend):
session.install(f".[{db_backend}]", "pytest")
# ç°å¢å€æ°ã䜿ã£ãŠDBããã¯ãšã³ããæå®ããäŸ
env = {"DATABASE_URL": f"{db_backend}://..."}
session.run("pytest", env=env)
# å®è¡ãããã»ãã·ã§ã³äŸ:
# tests-3.10(db_backend='sqlite')
# tests-3.10(db_backend='postgres')
# tests-3.11(db_backend='sqlite')
# tests-3.11(db_backend='postgres')
ã¿ã°ä»ããšã¿ã°ã«ããå®è¡
@nox.session
ãã³ã¬ãŒã¿ã®tags
åŒæ°ã䜿ã£ãŠãã»ãã·ã§ã³ã«ã¿ã°ãä»ããããšãã§ããŸããããã«ãããé¢é£ããã»ãã·ã§ã³ãã°ã«ãŒãåãã-t
(ãŸã㯠--tags
) ãªãã·ã§ã³ã§ãŸãšããŠå®è¡ã§ããŸãã
import nox
@nox.session(tags=["test"])
def unit_tests(session):
session.install(".[test]", "pytest")
session.run("pytest", "tests/unit")
@nox.session(tags=["test", "integration"])
def integration_tests(session):
session.install(".[test]", "pytest", "docker")
# Dockerã³ã³ããèµ·åãªã©ã®ååŠç
session.run("pytest", "tests/integration")
@nox.session(tags=["lint"])
def linting(session):
session.install("flake8", "black", "isort")
session.run("flake8", ".")
session.run("black", "--check", ".")
session.run("isort", "--check-only", ".")
@nox.session(tags=["docs"])
def build_docs(session):
session.install(".[docs]", "sphinx")
session.run("sphinx-build", "docs/", "docs/_build/html")
å®è¡äŸ:
- ãã¹ãŠã®ãã¹ããå®è¡:
nox -t test
- ãªã³ãã£ã³ã°ã®ã¿å®è¡:
nox -t lint
- ãã¹ããšããã¥ã¡ã³ããã«ããå®è¡:
nox -t test docs
åå©çšå¯èœãªé¢æ°ãšèšå®
noxfile.py
ã¯éåžžã®Pythonãã¡ã€ã«ãªã®ã§ããã«ããŒé¢æ°ãå®çŸ©ããããèšå®ãå
±éåãããããããšã容æã§ãã
import nox
# å
±éã®èšå®
nox.options.sessions = ["lint", "tests"] # noxã³ãã³ãã§ããã©ã«ãå®è¡ãããã»ãã·ã§ã³ãæå®
nox.options.stop_on_first_error = True # æåã®ã»ãã·ã§ã³å€±æã§åæ¢
# PythonããŒãžã§ã³ã®ãªã¹ããå
±éå
SUPPORTED_PYTHONS = ["3.9", "3.10", "3.11", "3.12"]
# å
±éã®ã€ã³ã¹ããŒã«åŠçãé¢æ°å
def install_dev_deps(session):
session.install("-r", "requirements-dev.txt")
session.install(".")
@nox.session(python=SUPPORTED_PYTHONS)
def tests(session):
install_dev_deps(session)
session.run("pytest", *session.posargs)
@nox.session
def lint(session):
install_dev_deps(session)
session.run("flake8", ".")
session.run("black", "--check", ".")
@nox.session
def format(session):
"""ã³ãŒããã©ãŒããããå®è¡ãã (ããã©ã«ãã§ã¯å®è¡ãããªã)"""
install_dev_deps(session)
session.run("black", ".")
session.run("isort", ".")
å€éšããŒã«ãšã®çµ±å (Poetry, PDM, uv)
Noxã¯ä»ã®ããã±ãŒãžç®¡çããŒã«ãé«éåããŒã«ãšãé£æºã§ããŸãã
Poetry/PDM: ãããã®ããŒã«ã䜿ã£ãŠããå Žåã§ããNoxã¯ããŸãé£æºã§ããŸããsession.install(".")
㯠pyproject.toml
ãèªèãããããžã§ã¯ããšãã®äŸåé¢ä¿ãã€ã³ã¹ããŒã«ããŸãã
# PoetryãPDMãããžã§ã¯ãã§ã®ãã¹ãã»ãã·ã§ã³äŸ
import nox
@nox.session(python=["3.10", "3.11"])
def tests(session):
# Poetry/PDMã管çããäŸåé¢ä¿ãå«ããŠã€ã³ã¹ããŒã«
session.install(".[test]") # Poetryã® extras ã PDM ã® dev-dependencies ã°ã«ãŒããªã©
session.run("pytest")
@nox.session
def lint(session):
# Poetry/PDMã§deväŸåãšããŠç®¡çãããŠãããªã³ã¿ãŒãã€ã³ã¹ããŒã«
session.install(".[lint]") # äŸ: [tool.poetry.group.lint.dependencies] ã [tool.pdm.dev-dependencies]
session.run("flake8")
session.run("mypy")
uv: é«éãªPythonããã±ãŒãžã€ã³ã¹ããŒã©ãŒã§ãã uv
ãNoxã®ä»®æ³ç°å¢ããã¯ãšã³ããšããŠäœ¿çšã§ããŸããuv
ãã·ã¹ãã ã«ã€ã³ã¹ããŒã«ãããŠããã°ãnoxfile.py
ã®å
é ã«ä»¥äžãè¿œå ããã ãã§å©çšã§ããŸãã
import nox
# uv ãå©çšå¯èœã§ããã°ããã©ã«ãã®ããã¯ãšã³ããšããŠèšå® (Nox 2024.3.2以éãå¿
èŠ)
nox.needs_version = ">=2024.3.2"
nox.options.default_venv_backend = "uv|virtualenv" # uvãããã°uvãããªããã°virtualenvã䜿ã
@nox.session
def tests(session):
# uvã䜿ã£ãŠé«éã«ã€ã³ã¹ããŒã«ããã
session.install("pytest", ".")
session.run("pytest")
ð ïž å®è·µçãªãŠãŒã¹ã±ãŒã¹
Noxã¯æ§ã ãªéçºã¿ã¹ã¯ã®èªååã«æŽ»çšã§ããŸãã
- è€æ°PythonããŒãžã§ã³ã§ã®ãã¹ã: æãäžè¬çãªãŠãŒã¹ã±ãŒã¹ã§ãã
@nox.session(python=["3.9", "3.10", ...])
ã®ããã«æå®ããã ãã§ãåããŒãžã§ã³ã§ç¬ç«ãããã¹ãç°å¢ãæ§ç¯ã»å®è¡ã§ããŸãã - ãªã³ãã£ã³ã°ãšãã©ãŒããã: Flake8, Black, isort, MyPyãªã©ã䜿ã£ãã³ãŒãå質ãã§ãã¯ãšèªåä¿®æ£ã¿ã¹ã¯ãå®çŸ©ã§ããŸãããã©ãŒãããçšã®ã»ãã·ã§ã³ãšãã§ãã¯çšã®ã»ãã·ã§ã³ãåããããšãäžè¬çã§ãã
- ããã¥ã¡ã³ãçæ: SphinxãMkDocsã䜿ã£ãããã¥ã¡ã³ãã®ãã«ããããŒã«ã«ã§ã®ãã¬ãã¥ãŒãµãŒããŒã®èµ·åãªã©ãèªååã§ããŸãã
- ããã±ãŒãžã®ãã«ããšå
Ž:
build
ã©ã€ãã©ãªã䜿ã£ããã€ãŒã«ãsdistã®äœæãtwine
ã䜿ã£ãPyPIãžã®ã¢ããããŒããªã©ãã»ãã·ã§ã³ãšããŠå®çŸ©ã§ããŸãããªãªãŒã¹ããã»ã¹ã®äžè²«æ§ãä¿ã€ã®ã«åœ¹ç«ã¡ãŸãã - ã«ãã¬ããžã¬ããŒãçæ:
pytest-cov
ãcoverage.py
ã䜿ã£ãŠãã¹ãã«ãã¬ããžã枬å®ããã¬ããŒãïŒHTMLãXMLïŒãçæããã»ãã·ã§ã³ãäœæã§ããŸãã - äŸåé¢ä¿ã®æŽæ°ãã§ãã¯:
pip-tools
ãªã©ãå©çšããŠãäŸåé¢ä¿ã®ãã³çããã¡ã€ã«ãæŽæ°ããããææ°ããŒãžã§ã³ã§ã®ãã¹ããå®è¡ãããããã»ãã·ã§ã³ãäœæã§ããŸãã
import nox
import tempfile
import os
# ããã©ã«ãã»ãã·ã§ã³ã®èšå®
nox.options.sessions = ["lint", "mypy", "tests"]
# 䜿çšããPythonããŒãžã§ã³
PYTHON_VERSIONS = ["3.9", "3.10", "3.11", "3.12"]
def install_with_constraints(session, *args, **kwargs):
# Poetryã䜿çšããŠããå ŽåãexportããŠå¶çŽãã¡ã€ã«ãšããŠäœ¿ãäŸ
# requirements.txt ãããå Žåã¯ããã䜿ããªã©ããããžã§ã¯ãã«åãããŠèª¿æŽ
with tempfile.NamedTemporaryFile(delete=False) as requirements:
session.run(
"poetry",
"export",
"--dev",
"--format=requirements.txt",
f"--output={requirements.name}",
external=True, # poetryã¯éåžžä»®æ³ç°å¢å€ã«ãããã
)
session.install(f"--constraint={requirements.name}", *args, **kwargs)
os.unlink(requirements.name)
@nox.session(python=PYTHON_VERSIONS)
def tests(session):
"""Pytestã§ãã¹ããå®è¡ããã«ãã¬ããžã¬ããŒããçæãã"""
args = session.posargs or ["--cov=src", "--cov-report=term-missing", "--cov-report=xml"]
session.run("poetry", "install", "--no-dev", external=True) # ãããžã§ã¯ãæ¬äœãã€ã³ã¹ããŒã«
install_with_constraints(session, "pytest", "pytest-cov")
session.run("pytest", *args)
@nox.session(python=PYTHON_VERSIONS[-1]) # ææ°ã®Pythonã§Lintãå®è¡
def lint(session):
"""Flake8, Black, isortã§ãªã³ãã£ã³ã°ãå®è¡ãã"""
args = session.posargs or ["src", "tests", "noxfile.py"]
install_with_constraints(
session,
"flake8",
"flake8-black",
"flake8-isort",
"flake8-bugbear",
"flake8-bandit",
"flake8-docstrings",
)
session.run("flake8", *args)
@nox.session(python=PYTHON_VERSIONS[-1])
def black(session):
"""Blackã§ã³ãŒããã©ãŒãããããã§ãã¯ãã"""
args = session.posargs or ["--check", "."]
install_with_constraints(session, "black")
session.run("black", *args)
@nox.session(python=PYTHON_VERSIONS[-1])
def isort(session):
"""isortã§importé ããã§ãã¯ãã"""
args = session.posargs or ["--check-only", "."]
install_with_constraints(session, "isort")
session.run("isort", *args)
@nox.session(python=PYTHON_VERSIONS)
def mypy(session):
"""MyPyã§åãã§ãã¯ãå®è¡ãã"""
args = session.posargs or ["src"]
install_with_constraints(session, "mypy")
session.run("mypy", *args)
@nox.session(python=PYTHON_VERSIONS[-1])
def docs(session):
"""Sphinxã§ããã¥ã¡ã³ãããã«ããã"""
session.run("poetry", "install", "--only=docs", external=True)
install_with_constraints(session, "sphinx", "sphinx-rtd-theme")
session.run("sphinx-build", "docs", "docs/_build/html")
@nox.session(python=PYTHON_VERSIONS[-1])
def build(session):
"""ãã€ãŒã«ãšsdistããã«ããã"""
install_with_constraints(session, "build")
session.run("python", "-m", "build")
ð Nox vs Tox: ç°¡åãªæ¯èŒ
NoxãšToxã¯ç®çã¯äŒŒãŠããŸãããã¢ãããŒããç°ãªããŸãã
ç¹åŸŽ | Nox | Tox |
---|---|---|
èšå®ãã¡ã€ã« | noxfile.py (Pythonã¹ã¯ãªãã) | tox.ini ãŸã㯠pyproject.toml ([tool.tox]ã»ã¯ã·ã§ã³) (INI圢åŒããŒã¹ã®DSL) |
æè»æ§ | éåžžã«é«ããPythonã®å šæ©èœãå©çšå¯èœãåçãªèšå®ãè€éãªããžãã¯ã®å®è£ ã容æã | æ¯èŒçäœããINI圢åŒãšç¬èªã®DSLã«å¶çŽããããè€éãªåŠçã¯ã·ã§ã«ã¹ã¯ãªãããªã©ã«é Œãå¿ èŠãããå Žåãããã |
åŠç¿ã³ã¹ã | Pythonã®ç¥èãããã°æ¯èŒç容æãNoxç¹æã®APIãèŠããå¿ èŠã¯ããã | Toxç¬èªã®DSLãšINI圢åŒãåŠã¶å¿ èŠãããã |
çšèª | ã»ãã·ã§ã³ (Session) | ç°å¢ (Environment / Env) |
PythonããŒãžã§ã³éžæ | 第äžçŽã®ã»ã¬ã¯ã¿ãšããŠæ±ãã (nox -p 3.10 ) | ç°å¢åã®ãã¬ãã£ãã¯ã¹ãšããŠæ±ã (tox -e py310 ) |
䞊åå®è¡ | æšæºã§ã¯ãµããŒããããŠããªãïŒå°æ¥çã«è¿œå ãããå¯èœæ§ããïŒ | -p ãªãã·ã§ã³ã§äžŠåå®è¡ãå¯èœ |
ãšã³ã·ã¹ãã /æŽå² | æ¯èŒçæ°ããããå€ãã®äž»èŠãããžã§ã¯ãã§æ¡çšãé²ãã§ããã掻çºã«éçºãããŠããã | é·å¹Žã®å®çžŸããããPythonãã¹ãèªååã®ããã¡ã¯ãã¹ã¿ã³ããŒããè±å¯ãªãã©ã°ã€ã³ãååšããã |
ã©ã¡ããéžã¶ã¹ããã¯ããããžã§ã¯ãã®èŠä»¶ãããŒã ã®å¥œã¿ã«ãããŸãã
- INI圢åŒã®èšå®ã«æ £ããŠãããã·ã³ãã«ãªãã¹ãèªååã§ååãªå Žåã¯Toxãé©ããŠãããããããŸããã
- ããè€éãªã¿ã¹ã¯ã®èªååãåçãªèšå®ãPythonã¹ã¯ãªããã«ããæè»æ§ãæ±ããå Žåã¯Noxã匷åãªéžæè¢ãšãªããŸãã
(åè: 2023幎1æ Hynek Schlawackæ°ã®ããã°èšäº “Why I Like Nox”)
ð ãŸãšã
Noxã¯ãPythonãããžã§ã¯ãã«ãããæ§ã
ãªéçºã¿ã¹ã¯ãèªååããããã®åŒ·åã§æè»ãªããŒã«ã§ããnoxfile.py
ãšããPythonã¹ã¯ãªããã§èšå®ãèšè¿°ããããšã«ãããåçŽãªãã¹ãå®è¡ããè€éãªãã«ããã€ãã©ã€ã³ãŸã§ãå¹
åºãããŒãºã«å¯Ÿå¿ã§ããŸãã
Noxã®äž»ãªã¡ãªãã:
- â èšå®ãã¡ã€ã«ãPythonã¹ã¯ãªããã§ãããé«ãæè»æ§ãšè¡šçŸåãæã€ã
- â è€æ°PythonããŒãžã§ã³ã§ã®ãã¹ãå®è¡ã容æã
- â ä»®æ³ç°å¢ã®ç®¡çãèªååã
- â ãã©ã¡ãŒã¿åãã¿ã°ä»ãã«ãããã»ãã·ã§ã³ç®¡çãããããã
- â PoetryãPDMãuvãªã©ã®ã¢ãã³ãªããŒã«ãšã®é£æºãå¯èœã
- â å€ãã®äž»èŠãããžã§ã¯ãã§æ¡çšãããŠããã掻çºã«éçºãããŠããã
ããããªããPythonãããžã§ã¯ãã§ç¹°ãè¿ãè¡ãã¿ã¹ã¯ã«æéãæããŠãããªããNoxã®å°å ¥ãæ€èšããŠã¿ãŠã¯ãããã§ããããããã£ãšéçºã¯ãŒã¯ãããŒã®æ¹åã«è²¢ç®ããŠãããã¯ãã§ãïŒ âš
ã³ã¡ã³ã