File: C:/Users/fred/anaconda3/Lib/site-packages/conda_build/create_test.py
# Copyright (C) 2014 Anaconda, Inc
# SPDX-License-Identifier: BSD-3-Clause
"""
Module to handle generating test files.
"""
from __future__ import annotations
import json
import os
from os.path import basename, exists, isfile, join
from pathlib import Path
from typing import TYPE_CHECKING
from .utils import copy_into, ensure_list, on_win, rm_rf
if TYPE_CHECKING:
from .metadata import MetaData
def create_files(m: MetaData, test_dir: Path) -> bool:
"""
Copy all test files from recipe over into testing directory.
:param metadata: The meta.yaml object.
:param test_dir: The testing directory.
:return: Whether any test scripts copied were copied over.
"""
patterns = ensure_list(m.get_value("test/files", []))
for pattern in patterns:
for file in Path(m.path).rglob(pattern):
copy_into(
file,
test_dir / file.relative_to(m.path),
m.config.timeout,
locking=False,
clobber=True,
)
return bool(patterns)
def _get_output_script_name(
m: MetaData,
win_status: bool,
) -> tuple[os.PathLike, os.PathLike]:
# the way this works is that each output needs to explicitly define a test script to run.
# They do not automatically pick up run_test.*, but can be pointed at that explicitly.
ext = ".bat" if win_status else ".sh"
dst_name = "run_test" + ext
src_name = dst_name
if m.is_output:
src_name = "no-file"
for out in m.get_section("outputs"):
if m.name() == out.get("name"):
out_test_script = out.get("test", {}).get("script", "no-file")
if os.path.splitext(out_test_script)[1].lower() == ext:
src_name = out_test_script
break
return src_name, dst_name
def create_shell_files(m: MetaData, test_dir: os.PathLike) -> list[str]:
win_status = [False, True] if m.noarch else [on_win]
shell_files = []
for status in win_status:
src_name, dst_name = _get_output_script_name(m, status)
dest_file = join(test_dir, dst_name)
if exists(join(m.path, src_name)):
# disable locking to avoid locking a temporary directory (the extracted test folder)
copy_into(
join(m.path, src_name),
dest_file,
m.config.timeout,
locking=False,
)
commands = ensure_list(m.get_value("test/commands", []))
if commands:
with open(join(dest_file), "a") as f:
f.write("\n\n")
if not status:
f.write("set -ex\n\n")
f.write("\n\n")
for cmd in commands:
f.write(cmd)
f.write("\n")
if status:
f.write("IF %ERRORLEVEL% NEQ 0 exit /B 1\n")
if status:
f.write("exit /B 0\n")
else:
f.write("exit 0\n")
if isfile(dest_file):
shell_files.append(dest_file)
return shell_files
def _create_test_files(
m: MetaData,
test_dir: os.PathLike,
ext: str,
comment_char: str = "# ",
) -> tuple[os.PathLike, bool]:
name = "run_test" + ext
if m.is_output:
name = ""
# the way this works is that each output needs to explicitly define a test script to run
# They do not automatically pick up run_test.*, but can be pointed at that explicitly.
for out in m.get_section("outputs"):
if m.name() == out.get("name"):
out_test_script = out.get("test", {}).get("script", "no-file")
if out_test_script.endswith(ext):
name = out_test_script
break
out_file = join(test_dir, "run_test" + ext)
if name:
test_file = join(m.path, name)
if isfile(test_file):
with open(out_file, "w") as fo:
fo.write(
f"{comment_char} tests for {m.dist()} (this is a generated file);\n"
)
fo.write(f"print('===== testing package: {m.dist()} =====');\n")
try:
with open(test_file) as fi:
fo.write(f"print('running {name}');\n")
fo.write(f"{comment_char} --- {name} (begin) ---\n")
fo.write(fi.read())
fo.write(f"{comment_char} --- {name} (end) ---\n")
except AttributeError:
fo.write(
"# tests were not packaged with this module, and cannot be run\n"
)
fo.write(f"\nprint('===== {m.dist()} OK =====');\n")
return (
out_file,
bool(name) and isfile(out_file) and basename(test_file) != "no-file",
)
def create_py_files(m: MetaData, test_dir: os.PathLike) -> bool:
tf, tf_exists = _create_test_files(m, test_dir, ".py")
# Ways in which we can mark imports as none python imports
# 1. preface package name with r-, lua- or perl-
# 2. use list of dicts for test/imports, and have lang set in those dicts
pkg_name = m.name()
likely_r_pkg = pkg_name.startswith("r-")
likely_lua_pkg = pkg_name.startswith("lua-")
likely_perl_pkg = pkg_name.startswith("perl-")
likely_non_python_pkg = likely_r_pkg or likely_lua_pkg or likely_perl_pkg
if likely_non_python_pkg:
imports = []
for import_item in ensure_list(m.get_value("test/imports", [])):
# add any imports specifically marked as python
if (
hasattr(import_item, "keys")
and "lang" in import_item
and import_item["lang"] == "python"
):
imports.extend(import_item["imports"])
else:
imports = ensure_list(m.get_value("test/imports", []))
imports = [
item
for item in imports
if (
not hasattr(item, "keys") or "lang" in item and item["lang"] == "python"
)
]
if imports:
with open(tf, "a") as fo:
for name in imports:
fo.write(f'print("import: {name!r}")\n')
fo.write(f"import {name}\n")
fo.write("\n")
return tf if (tf_exists or imports) else False
def create_r_files(m: MetaData, test_dir: os.PathLike) -> bool:
tf, tf_exists = _create_test_files(m, test_dir, ".r")
imports = None
# two ways we can enable R import tests:
# 1. preface package name with r- and just list imports in test/imports
# 2. use list of dicts for test/imports, and have lang: 'r' set in one of those dicts
if m.name().startswith("r-"):
imports = ensure_list(m.get_value("test/imports", []))
else:
for import_item in ensure_list(m.get_value("test/imports", [])):
if (
hasattr(import_item, "keys")
and "lang" in import_item
and import_item["lang"] == "r"
):
imports = import_item["imports"]
break
if imports:
with open(tf, "a") as fo:
for name in imports:
fo.write(f'print("library({name!r})")\n')
fo.write(f"library({name})\n")
fo.write("\n")
return tf if (tf_exists or imports) else False
def create_pl_files(m: MetaData, test_dir: os.PathLike) -> bool:
tf, tf_exists = _create_test_files(m, test_dir, ".pl")
imports = None
if m.name().startswith("perl-"):
imports = ensure_list(m.get_value("test/imports", []))
else:
for import_item in ensure_list(m.get_value("test/imports", [])):
if (
hasattr(import_item, "keys")
and "lang" in import_item
and import_item["lang"] == "perl"
):
imports = import_item["imports"]
break
if tf_exists or imports:
with open(tf, "a") as fo:
print(
r'my $expected_version = "{}";'.format(m.version().rstrip("0")), file=fo
)
if imports:
for name in imports:
print(rf'print("import: {name}\n");', file=fo)
print(f"use {name};\n", file=fo)
# Don't try to print version for complex imports
if " " not in name:
print(
f"if (defined {name}->VERSION) {{\n"
f"\tmy $given_version = {name}->VERSION;\n"
f"\t$given_version =~ s/0+$//;\n"
f"\tdie('Expected version ' . $expected_version . ' but"
f" found ' . $given_version) unless ($expected_version "
f"eq $given_version);\n"
f"\tprint('\tusing version ' . {name}->VERSION . '\n');\n"
f"\n}}",
file=fo,
)
return tf if (tf_exists or imports) else False
def create_lua_files(m: MetaData, test_dir: os.PathLike) -> bool:
tf, tf_exists = _create_test_files(m, test_dir, ".lua")
imports = None
if m.name().startswith("lua-"):
imports = ensure_list(m.get_value("test/imports", []))
else:
for import_item in ensure_list(m.get_value("test/imports", [])):
if (
hasattr(import_item, "keys")
and "lang" in import_item
and import_item["lang"] == "lua"
):
imports = import_item["imports"]
break
if imports:
with open(tf, "a+") as fo:
for name in imports:
print(rf'print("require \"{name}\"\n");', file=fo)
print(f'require "{name}"\n', file=fo)
return tf if (tf_exists or imports) else False
def create_all_test_files(
m: MetaData,
test_dir: os.PathLike | None = None,
) -> tuple[bool, bool, bool, bool, bool, list[str]]:
if test_dir:
# this happens when we're finishing the build
rm_rf(test_dir)
os.makedirs(test_dir, exist_ok=True)
test_requires = ensure_list(m.get_value("test/requires", []))
if test_requires:
Path(test_dir, "test_time_dependencies.json").write_text(
json.dumps(test_requires)
)
else:
# this happens when we're running a package's tests
test_dir = m.config.test_dir
os.makedirs(test_dir, exist_ok=True)
return (
create_files(m, Path(test_dir)),
create_pl_files(m, test_dir),
create_py_files(m, test_dir),
create_r_files(m, test_dir),
create_lua_files(m, test_dir),
create_shell_files(m, test_dir),
)