def docs(session: Session) -> None: """Build docs with sphinx.""" extras = "docs" cmd = "sphinx-build" args = ["-b", "html", "-aE", "docs/source", "docs/build/html"] if "autobuild" in session.posargs or "ab" in session.posargs: extras += " sphinx-autobuild" cmd = "sphinx-autobuild" args += ["--open-browser"] if "skip_install" not in session.posargs: session.poetry_install( extras, no_root=(TOX_CALLS or SKIP_INSTALL), no_dev=(TOX_CALLS or IN_CI), pip_require_venv=poetry_require_venv(session), ) else: session.log("Skipping install step.") #: Remove processed posargs for arg in ("skip_install", "autobuild", "ab"): with contextlib.suppress(ValueError): session.posargs.remove(arg) color = ["--color"] if FORCE_COLOR else [] session.run(cmd, *color, *args, *session.posargs) index_file = NOXFILE_DIR / "docs/build/html/index.html" print(f"DOCUMENTATION AVAILABLE UNDER: {index_file.as_uri()}")
def safety(session: Session) -> None: """Check all dependencies for known vulnerabilities.""" if "skip_install" not in session.posargs: extras = "poetry safety" session.poetry_install( extras, no_root=True, no_dev=(TOX_CALLS or IN_CI), pip_require_venv=poetry_require_venv(session), ) else: session.log("Skipping install step.") venv_path = get_venv_path() req_file_path = (get_venv_tmp_dir(venv_path, create_if_missing=True) / "requirements.txt") #: Use `poetry show` to fill `requirements.txt` command = [str(get_venv_bin_dir(venv_path) / "poetry"), "show"] # TODO:#i# simplify when py36 is not longer supported. if sys.version_info[0:2] > (3, 6): cmd = subprocess.run(command, check=True, capture_output=True) # noqa: S603 else: cmd = subprocess.run(command, check=True, stdout=subprocess.PIPE) # noqa: S603 with open(req_file_path, "w") as req_file: req_file.write( re.sub(r"([\w-]+)[ (!)]+([\d.a-z-]+).*", r"\1==\2", cmd.stdout.decode())) session.run("safety", "check", "-r", str(req_file_path), "--full-report")
def package(session: Session) -> None: """Check sdist and wheel.""" if "skip_install" not in session.posargs: extras = "poetry twine" session.poetry_install( extras, no_root=True, no_dev=(TOX_CALLS or IN_CI), pip_require_venv=poetry_require_venv(session), ) else: session.log("Skipping install step.") color = ["--ansi"] if FORCE_COLOR else [] session.run("poetry", "build", *color, "-vvv") session.run("twine", "check", "--strict", "dist/*")
def _coverage(session: Session, job: str) -> None: if "skip_install" not in session.posargs: extras = "coverage" if job in ("report", "all"): extras += " diff-cover" session.poetry_install( extras, no_root=True, no_dev=(TOX_CALLS or IN_CI), pip_require_venv=poetry_require_venv(session), ) else: session.log("Skipping install step.") #: Remove processed posargs with contextlib.suppress(ValueError): session.posargs.remove("skip_install") session.env["COVERAGE_FILE"] = str(COV_CACHE_DIR / ".coverage") cov_xml_file = f"{COV_CACHE_DIR / 'coverage.xml'}" cov_html_dir = f"{COV_CACHE_DIR / 'htmlcov'}" if job in ("merge", "all"): session.run("coverage", "combine") session.run("coverage", "xml", "-o", cov_xml_file) session.run("coverage", "html", "-d", cov_html_dir) if job in ("report", "all"): raise_error = False min_cov = session.env.get("MIN_COVERAGE") or 100 try: session.run("coverage", "report", "-m", f"--fail-under={min_cov}") except CommandFailed: raise_error = True session.run( "diff-cover", f"--compare-branch={session.env.get('DIFF_AGAINST') or 'origin/main'}", "--ignore-staged", "--ignore-unstaged", f"--fail-under={session.env.get('MIN_DIFF_COVERAGE') or 100}", f"--diff-range-notation={session.env.get('DIFF_RANGE_NOTATION') or '..'}", cov_xml_file, ) if raise_error: raise CommandFailed
def test_code(session: Session) -> None: """Run tests with given python version.""" if "skip_install" not in session.posargs: extras = "testing" session.poetry_install( extras, no_root=(TOX_CALLS or SKIP_INSTALL), no_dev=(TOX_CALLS or IN_CI), pip_require_venv=poetry_require_venv(session), ) else: session.log("Skipping install step.") #: Remove processed posargs with contextlib.suppress(ValueError): session.posargs.remove("skip_install") interpreter = sys.implementation.__getattribute__("name") version = ".".join([str(v) for v in sys.version_info[0:2]]) name = f"{OS}.{interpreter}{version}" session.env["COVERAGE_FILE"] = str(COV_CACHE_DIR / f".coverage.{name}") cov_source_dir = Path("no-spec-found") with contextlib.suppress(AttributeError, TypeError): cov_source_dir = Path( find_spec( PACKAGE_NAME).origin # type: ignore[union-attr, arg-type] ).parent color = ["--color=yes"] if FORCE_COLOR else [] posargs = session.posargs if session.posargs else ["tests"] session.run( "pytest", *color, f"--basetemp={get_venv_tmp_dir(get_venv_path(), create_if_missing=True)}", f"--junitxml={NOXFILE_DIR / '.junit_cache' / f'junit.{name}.xml'}", f"--cov={cov_source_dir}", f"--cov-fail-under={session.env.get('MIN_COVERAGE') or 100}", f"--numprocesses={session.env.get('PYTEST_XDIST_N') or 'auto'}", *posargs, )
def check_for_tox_call(session: Session, **kwargs: Dict[str, Any]) -> None: """Call session function or tox. :param session: nox session object :param kwargs: keyword arguments from e.g. parametrize """ tox_env = session_func.__name__ if tox_target: tox_env = tox_target.format( **kwargs) if parametrized else tox_target in_venv = False with contextlib.suppress(FileNotFoundError): in_venv = get_venv_path() is not None if not in_venv or "tox" in session.posargs: posargs = [arg for arg in session.posargs if arg != "tox"] session.log("Using `tox` as venv backend.") _tox_caller(session, tox_env, posargs) else: session_func(session=session, **kwargs)
def test_docs(session: Session, builder: str) -> None: """Build and check docs with (see env name) sphinx builder.""" if "skip_install" not in session.posargs: extras = "docs" session.poetry_install( extras, no_root=(TOX_CALLS or SKIP_INSTALL), no_dev=(TOX_CALLS or IN_CI), pip_require_venv=poetry_require_venv(session), ) else: session.log("Skipping install step.") #: Remove processed posargs with contextlib.suppress(ValueError): session.posargs.remove("skip_install") source_dir = "docs/source" target_dir = f"docs/build/test/{builder}" std_args = ["-aE", "-v", "-nW", "--keep-going", source_dir, target_dir] color = ["--color"] if FORCE_COLOR else [] session.run("sphinx-build", "-b", builder, *color, *std_args, *session.posargs)
def pre_commit(session: Session) -> None: # noqa: R0912 """Format and check the code.""" if "skip_install" not in session.posargs: extras = "pre-commit testing docs poetry dev_nox" session.poetry_install( extras, no_root=(TOX_CALLS or SKIP_INSTALL), no_dev=(TOX_CALLS or IN_CI), pip_require_venv=poetry_require_venv(session), ) else: session.log("Skipping install step.") #: Set 'show-diff' and 'skip identity hook' show_diff = [] env = {"SKIP": "identity"} if (session.interactive and "diff" in session.posargs) or ( not session.interactive and "nodiff" not in session.posargs): show_diff = ["--show-diff-on-failure"] env = {} #: Add SKIP from posargs to env skip = "" for arg in session.posargs: if arg.startswith("SKIP="): skip = arg break if skip: env = {"SKIP": f"{skip[5:]},{env.get('SKIP', '')}"} #: Get hooks from posargs hooks_arg = "" for arg in session.posargs: if arg.startswith("HOOKS="): hooks_arg = arg break #: Remove processed posargs for arg in ("skip_install", "diff", "nodiff", skip, hooks_arg): with contextlib.suppress(ValueError): session.posargs.remove(arg) hooks = hooks_arg[6:].split(",") if hooks_arg else [""] color = ["--color=always"] if FORCE_COLOR else [] error_hooks = [] for hook in hooks: add_args = show_diff + session.posargs + ([hook] if hook else []) try: session.run("pre-commit", "run", *color, "--all-files", *add_args, env=env) except CommandFailed: error_hooks.append(hook) print( "HINT: to add checks as pre-commit hook run: ", f'"{get_venv_bin_dir(get_venv_path()) / "pre-commit"} ' "install -t pre-commit -t commit-msg.", ) if error_hooks: if hooks != [""]: nox_logger.error( f"The following pre-commit hooks failed: {error_hooks}." # noqa: G004 ) raise CommandFailed