Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 26 additions & 1 deletion relenv/create.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
format_shebang,
relative_interpreter,
)
from .pyversions import Version, python_versions


@contextlib.contextmanager
Expand Down Expand Up @@ -251,8 +252,32 @@ def main(args: argparse.Namespace) -> None:
print(
"Warning: Cross compilation support is experimental and is not fully tested or working!"
)

# Resolve version (support minor version like "3.12" or full version like "3.12.7")
requested = Version(args.python)

if requested.micro:
# Full version specified (e.g., "3.12.7")
pyversions = python_versions()
if requested not in pyversions:
print(f"Unknown version {requested}")
strversions = "\n".join([str(_) for _ in pyversions])
print(f"Known versions are:\n{strversions}")
sys.exit(1)
create_version = requested
else:
# Minor version specified (e.g., "3.12"), resolve to latest
pyversions = python_versions(args.python)
if not pyversions:
print(f"Unknown minor version {requested}")
all_versions = python_versions()
strversions = "\n".join([str(_) for _ in all_versions])
print(f"Known versions are:\n{strversions}")
sys.exit(1)
create_version = sorted(list(pyversions.keys()))[-1]

try:
create(name, arch=args.arch, version=args.python)
create(name, arch=args.arch, version=str(create_version))
except CreateException as exc:
print(exc)
sys.exit(1)
143 changes: 143 additions & 0 deletions tests/test_create.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,3 +52,146 @@ def test_create_arches_directory_exists(tmp_path: pathlib.Path) -> None:
with patch("relenv.create.arches", mocked_arches):
with pytest.raises(CreateException):
create("foo", dest=tmp_path)


def test_create_with_minor_version(tmp_path: pathlib.Path) -> None:
"""Test that minor version (e.g., '3.12') resolves to latest micro version."""
import argparse
import sys

from relenv.create import main
from relenv.pyversions import Version

# Mock python_versions to return some test versions
all_versions = {
Version("3.11.5"): "aaa111",
Version("3.12.5"): "abc123",
Version("3.12.6"): "def456",
Version("3.12.7"): "ghi789",
Version("3.13.1"): "zzz999",
}

def mock_python_versions(minor: str | None = None) -> dict[Version, str]:
"""Mock that filters versions by minor version like the real function."""
if minor is None:
return all_versions
# Filter versions matching the minor version
mv = Version(minor)
return {
v: h
for v, h in all_versions.items()
if v.major == mv.major and v.minor == mv.minor
}

# Create a fake archive
to_be_archived = tmp_path / "to_be_archived"
to_be_archived.mkdir()
test_file = to_be_archived / "testfile"
test_file.touch()
tar_file = tmp_path / "fake_archive"
with tarfile.open(str(tar_file), "w:xz") as tar:
tar.add(str(to_be_archived), to_be_archived.name)

# Use appropriate architecture for the platform
test_arch = "amd64" if sys.platform == "win32" else "x86_64"
args = argparse.Namespace(name="test_env", arch=test_arch, python="3.12")

with chdir(str(tmp_path)):
with patch("relenv.create.python_versions", side_effect=mock_python_versions):
with patch("relenv.create.archived_build", return_value=tar_file):
with patch("relenv.create.build_arch", return_value=test_arch):
main(args)

to_dir = tmp_path / "test_env"
assert to_dir.exists()


def test_create_with_full_version(tmp_path: pathlib.Path) -> None:
"""Test that full version (e.g., '3.12.7') still works."""
import argparse
import sys

from relenv.create import main
from relenv.pyversions import Version

# Mock python_versions to return some test versions
all_versions = {
Version("3.11.5"): "aaa111",
Version("3.12.5"): "abc123",
Version("3.12.6"): "def456",
Version("3.12.7"): "ghi789",
Version("3.13.1"): "zzz999",
}

def mock_python_versions(minor: str | None = None) -> dict[Version, str]:
"""Mock that filters versions by minor version like the real function."""
if minor is None:
return all_versions
# Filter versions matching the minor version
mv = Version(minor)
return {
v: h
for v, h in all_versions.items()
if v.major == mv.major and v.minor == mv.minor
}

# Create a fake archive
to_be_archived = tmp_path / "to_be_archived"
to_be_archived.mkdir()
test_file = to_be_archived / "testfile"
test_file.touch()
tar_file = tmp_path / "fake_archive"
with tarfile.open(str(tar_file), "w:xz") as tar:
tar.add(str(to_be_archived), to_be_archived.name)

# Use appropriate architecture for the platform
test_arch = "amd64" if sys.platform == "win32" else "x86_64"
args = argparse.Namespace(name="test_env", arch=test_arch, python="3.12.7")

with chdir(str(tmp_path)):
with patch("relenv.create.python_versions", side_effect=mock_python_versions):
with patch("relenv.create.archived_build", return_value=tar_file):
with patch("relenv.create.build_arch", return_value=test_arch):
main(args)

to_dir = tmp_path / "test_env"
assert to_dir.exists()


def test_create_with_unknown_minor_version(tmp_path: pathlib.Path) -> None:
"""Test that unknown minor version produces an error."""
import argparse
import sys

from relenv.create import main
from relenv.pyversions import Version

# Mock python_versions to return empty dict for unknown version
all_versions = {
Version("3.11.5"): "aaa111",
Version("3.12.5"): "abc123",
Version("3.12.6"): "def456",
Version("3.12.7"): "ghi789",
Version("3.13.1"): "zzz999",
}

# Use appropriate architecture for the platform
test_arch = "amd64" if sys.platform == "win32" else "x86_64"
args = argparse.Namespace(name="test_env", arch=test_arch, python="3.99")

def mock_python_versions(minor: str | None = None) -> dict[Version, str]:
"""Mock that filters versions by minor version like the real function."""
if minor is None:
return all_versions
# Filter versions matching the minor version
mv = Version(minor)
return {
v: h
for v, h in all_versions.items()
if v.major == mv.major and v.minor == mv.minor
}

with patch("relenv.create.python_versions", side_effect=mock_python_versions):
with patch("relenv.create.build_arch", return_value=test_arch):
with pytest.raises(SystemExit):
main(args)
Loading