diff --git a/.github/workflows/unix.yml b/.github/workflows/unix.yml index 72da62595b..fbadc9cf78 100644 --- a/.github/workflows/unix.yml +++ b/.github/workflows/unix.yml @@ -112,7 +112,7 @@ jobs: shell: bash -l {0} run: | pybind11-stubgen libmambapy.bindings - pre-commit run --files stubs/libmambapy/binginds-stubs/__init__.pyi + pre-commit run --files stubs/libmambapy/bindings-stubs/__init__.pyi python compare_stubs.py libmambapy/libmambapy/__init__.pyi stubs/libmambapy/bindings-stubs/__init__.pyi - name: Show build cache statistics run: sccache --show-stats @@ -140,10 +140,22 @@ jobs: mkdir -p $CONDA_PREFIX/conda-bld/linux-64 wget -P $CONDA_PREFIX/conda-bld/linux-64 https://anaconda.org/conda-forge/xtensor/0.21.8/download/linux-64/xtensor-0.21.8-hc9558a2_0.tar.bz2 wget -P $CONDA_PREFIX/conda-bld/linux-64 https://anaconda.org/conda-forge/xtl/0.6.21/download/linux-64/xtl-0.6.21-h0efe328_0.tar.bz2 + elif [ "$RUNNER_OS" == "macOS" ]; then + if [ "$(uname -m)" == "x86_64" ]; then + mkdir -p $CONDA_PREFIX/conda-bld/osx-64 + wget -P $CONDA_PREFIX/conda-bld/osx-64 https://anaconda.org/conda-forge/xtensor/0.21.8/download/osx-64/xtensor-0.21.8-h879752b_0.tar.bz2 + wget -P $CONDA_PREFIX/conda-bld/osx-64 https://anaconda.org/conda-forge/xtl/0.6.21/download/osx-64/xtl-0.6.21-h6516342_0.tar.bz2 + elif [ "$(uname -m)" == "arm64" ]; then + mkdir -p $CONDA_PREFIX/conda-bld/osx-arm64 + wget -P $CONDA_PREFIX/conda-bld/osx-arm64 https://anaconda.org/conda-forge/xtensor/0.21.10/download/osx-arm64/xtensor-0.21.10-h260d524_0.tar.bz2 + wget -P $CONDA_PREFIX/conda-bld/osx-arm64 https://anaconda.org/conda-forge/xtl/0.6.23/download/osx-arm64/xtl-0.6.23-h260d524_1.tar.bz2 + else + echo "Unsupported architecture: $(uname -m)" + exit 1 + fi else - mkdir -p $CONDA_PREFIX/conda-bld/osx-64 - wget -P $CONDA_PREFIX/conda-bld/osx-64 https://anaconda.org/conda-forge/xtensor/0.21.8/download/osx-64/xtensor-0.21.8-h879752b_0.tar.bz2 - wget -P $CONDA_PREFIX/conda-bld/osx-64 https://anaconda.org/conda-forge/xtl/0.6.21/download/osx-64/xtl-0.6.21-h6516342_0.tar.bz2 + echo "Unsupported OS: $RUNNER_OS" + exit 1 fi conda index $CONDA_PREFIX/conda-bld mamba create -n l_o_cal_test local::xtensor -c conda-forge -y diff --git a/libmamba/environment-dev.yml b/libmamba/environment-dev.yml index 615f10e839..ea2b2d5d99 100644 --- a/libmamba/environment-dev.yml +++ b/libmamba/environment-dev.yml @@ -16,5 +16,5 @@ dependencies: - yaml-cpp >=0.8.0 - cli11 >=2.2 - spdlog - - fmt + - fmt < 11 # TODO remove constraint when backporting the fix for fmt last release (from mamba main branch) - sel(win): winreg diff --git a/libmambapy/libmambapy/__init__.pyi b/libmambapy/libmambapy/__init__.pyi index e4b2678194..7bd867cad7 100644 --- a/libmambapy/libmambapy/__init__.pyi +++ b/libmambapy/libmambapy/__init__.pyi @@ -132,10 +132,8 @@ class Channel: def __init__(self, arg0: str) -> None: ... def __repr__(self) -> str: ... def platform_url(self, platform: str, with_credentials: bool = True) -> str: ... - def platform_urls( - self, with_credentials: bool = True - ) -> typing.List[typing.Tuple[str, str]]: ... - def urls(self, with_credentials: bool = True) -> typing.List[str]: ... + def platform_urls(self, with_credentials: bool = True) -> list[tuple[str, str]]: ... + def urls(self, with_credentials: bool = True) -> list[str]: ... @property def auth(self) -> typing.Optional[str]: """ @@ -162,9 +160,9 @@ class Channel: :type: typing.Optional[str] """ @property - def platforms(self) -> typing.List[str]: + def platforms(self) -> list[str]: """ - :type: typing.List[str] + :type: list[str] """ @property def scheme(self) -> str: @@ -198,6 +196,7 @@ class ChannelPriority: def __ne__(self, other: object) -> bool: ... def __repr__(self) -> str: ... def __setstate__(self, state: int) -> None: ... + def __str__(self) -> str: ... @property def name(self) -> str: """ @@ -219,11 +218,11 @@ class CompressedProblemsGraph: def __bool__(self) -> bool: ... def __contains__(self, arg0: int) -> bool: ... def __init__(self) -> None: ... - def __iter__(self) -> typing.Iterator: ... + def __iter__(self) -> typing.Iterator[tuple[int, set[int]]]: ... def __len__(self) -> int: ... def add(self, arg0: int, arg1: int) -> bool: ... def clear(self) -> None: ... - def conflicts(self, arg0: int) -> typing.Set[int]: ... + def conflicts(self, arg0: int) -> set[int]: ... def has_conflict(self, arg0: int) -> bool: ... def in_conflict(self, arg0: int, arg1: int) -> bool: ... pass @@ -231,7 +230,7 @@ class CompressedProblemsGraph: class ConstraintListNode: def __bool__(self) -> bool: ... def __init__(self) -> None: ... - def __iter__(self) -> typing.Iterator: ... + def __iter__(self) -> typing.Iterator[ProblemsGraph.ConstraintNode]: ... def __len__(self) -> int: ... def add(self, arg0: ProblemsGraph.ConstraintNode) -> None: ... def build_strings_trunc( @@ -240,7 +239,7 @@ class CompressedProblemsGraph: etc: str = "...", threshold: int = 5, remove_duplicates: bool = True, - ) -> typing.Tuple[str, int]: ... + ) -> tuple[str, int]: ... def clear(self) -> None: ... def name(self) -> str: ... def versions_and_build_strings_trunc( @@ -249,20 +248,20 @@ class CompressedProblemsGraph: etc: str = "...", threshold: int = 5, remove_duplicates: bool = True, - ) -> typing.Tuple[str, int]: ... + ) -> tuple[str, int]: ... def versions_trunc( self, sep: str = "|", etc: str = "...", threshold: int = 5, remove_duplicates: bool = True, - ) -> typing.Tuple[str, int]: ... + ) -> tuple[str, int]: ... pass class DependencyList: def __bool__(self) -> bool: ... def __init__(self) -> None: ... - def __iter__(self) -> typing.Iterator: ... + def __iter__(self) -> typing.Iterator[MatchSpec]: ... def __len__(self) -> int: ... def add(self, arg0: MatchSpec) -> None: ... def build_strings_trunc( @@ -271,7 +270,7 @@ class CompressedProblemsGraph: etc: str = "...", threshold: int = 5, remove_duplicates: bool = True, - ) -> typing.Tuple[str, int]: ... + ) -> tuple[str, int]: ... def clear(self) -> None: ... def name(self) -> str: ... def versions_and_build_strings_trunc( @@ -280,20 +279,20 @@ class CompressedProblemsGraph: etc: str = "...", threshold: int = 5, remove_duplicates: bool = True, - ) -> typing.Tuple[str, int]: ... + ) -> tuple[str, int]: ... def versions_trunc( self, sep: str = "|", etc: str = "...", threshold: int = 5, remove_duplicates: bool = True, - ) -> typing.Tuple[str, int]: ... + ) -> tuple[str, int]: ... pass class PackageListNode: def __bool__(self) -> bool: ... def __init__(self) -> None: ... - def __iter__(self) -> typing.Iterator: ... + def __iter__(self) -> typing.Iterator[ProblemsGraph.PackageNode]: ... def __len__(self) -> int: ... def add(self, arg0: ProblemsGraph.PackageNode) -> None: ... def build_strings_trunc( @@ -302,7 +301,7 @@ class CompressedProblemsGraph: etc: str = "...", threshold: int = 5, remove_duplicates: bool = True, - ) -> typing.Tuple[str, int]: ... + ) -> tuple[str, int]: ... def clear(self) -> None: ... def name(self) -> str: ... def versions_and_build_strings_trunc( @@ -311,14 +310,14 @@ class CompressedProblemsGraph: etc: str = "...", threshold: int = 5, remove_duplicates: bool = True, - ) -> typing.Tuple[str, int]: ... + ) -> tuple[str, int]: ... def versions_trunc( self, sep: str = "|", etc: str = "...", threshold: int = 5, remove_duplicates: bool = True, - ) -> typing.Tuple[str, int]: ... + ) -> tuple[str, int]: ... pass class RootNode: @@ -328,7 +327,9 @@ class CompressedProblemsGraph: class UnresolvedDependencyListNode: def __bool__(self) -> bool: ... def __init__(self) -> None: ... - def __iter__(self) -> typing.Iterator: ... + def __iter__( + self, + ) -> typing.Iterator[ProblemsGraph.UnresolvedDependencyNode]: ... def __len__(self) -> int: ... def add(self, arg0: ProblemsGraph.UnresolvedDependencyNode) -> None: ... def build_strings_trunc( @@ -337,7 +338,7 @@ class CompressedProblemsGraph: etc: str = "...", threshold: int = 5, remove_duplicates: bool = True, - ) -> typing.Tuple[str, int]: ... + ) -> tuple[str, int]: ... def clear(self) -> None: ... def name(self) -> str: ... def versions_and_build_strings_trunc( @@ -346,14 +347,14 @@ class CompressedProblemsGraph: etc: str = "...", threshold: int = 5, remove_duplicates: bool = True, - ) -> typing.Tuple[str, int]: ... + ) -> tuple[str, int]: ... def versions_trunc( self, sep: str = "|", etc: str = "...", threshold: int = 5, remove_duplicates: bool = True, - ) -> typing.Tuple[str, int]: ... + ) -> tuple[str, int]: ... pass def conflicts(self) -> ProblemsGraph.ConflictMap: ... @staticmethod @@ -366,8 +367,8 @@ class CompressedProblemsGraph: def from_problems_graph(arg0: ProblemsGraph) -> CompressedProblemsGraph: ... def graph( self, - ) -> typing.Tuple[ - typing.Dict[ + ) -> tuple[ + dict[ int, typing.Union[ ProblemsGraph.RootNode, @@ -376,7 +377,7 @@ class CompressedProblemsGraph: CompressedProblemsGraph.ConstraintListNode, ], ], - typing.Dict[typing.Tuple[int, int], CompressedProblemsGraph.DependencyList], + dict[tuple[int, int], CompressedProblemsGraph.DependencyList], ]: ... def root_node(self) -> int: ... def tree_message(self) -> str: ... @@ -458,12 +459,12 @@ class Context: def max_retries(self, arg0: int) -> None: pass @property - def proxy_servers(self) -> typing.Dict[str, str]: + def proxy_servers(self) -> dict[str, str]: """ - :type: typing.Dict[str, str] + :type: dict[str, str] """ @proxy_servers.setter - def proxy_servers(self, arg0: typing.Dict[str, str]) -> None: + def proxy_servers(self, arg0: dict[str, str]) -> None: pass @property def retry_backoff(self) -> int: @@ -556,20 +557,20 @@ class Context: def channel_priority(self, arg0: ChannelPriority) -> None: pass @property - def channels(self) -> typing.List[str]: + def channels(self) -> list[str]: """ - :type: typing.List[str] + :type: list[str] """ @channels.setter - def channels(self, arg0: typing.List[str]) -> None: + def channels(self, arg0: list[str]) -> None: pass @property - def conda_build_local_paths(self) -> typing.List[str]: + def conda_build_local_paths(self) -> list[str]: """ - :type: typing.List[str] + :type: list[str] """ @conda_build_local_paths.setter - def conda_build_local_paths(self, arg1: typing.List[str]) -> None: + def conda_build_local_paths(self, arg1: list[str]) -> None: pass @property def conda_prefix(self) -> Path: @@ -588,28 +589,28 @@ class Context: def connect_timeout_secs(self, arg1: float) -> None: pass @property - def custom_channels(self) -> typing.Dict[str, str]: + def custom_channels(self) -> dict[str, str]: """ - :type: typing.Dict[str, str] + :type: dict[str, str] """ @custom_channels.setter - def custom_channels(self, arg0: typing.Dict[str, str]) -> None: + def custom_channels(self, arg0: dict[str, str]) -> None: pass @property - def custom_multichannels(self) -> typing.Dict[str, typing.List[str]]: + def custom_multichannels(self) -> dict[str, list[str]]: """ - :type: typing.Dict[str, typing.List[str]] + :type: dict[str, list[str]] """ @custom_multichannels.setter - def custom_multichannels(self, arg0: typing.Dict[str, typing.List[str]]) -> None: + def custom_multichannels(self, arg0: dict[str, list[str]]) -> None: pass @property - def default_channels(self) -> typing.List[str]: + def default_channels(self) -> list[str]: """ - :type: typing.List[str] + :type: list[str] """ @default_channels.setter - def default_channels(self, arg0: typing.List[str]) -> None: + def default_channels(self, arg0: list[str]) -> None: pass @property def download_only(self) -> bool: @@ -636,12 +637,12 @@ class Context: def dry_run(self, arg0: bool) -> None: pass @property - def envs_dirs(self) -> typing.List[Path]: + def envs_dirs(self) -> list[Path]: """ - :type: typing.List[Path] + :type: list[Path] """ @envs_dirs.setter - def envs_dirs(self, arg0: typing.List[Path]) -> None: + def envs_dirs(self, arg0: list[Path]) -> None: pass @property def experimental_sat_error_message(self) -> bool: @@ -700,12 +701,12 @@ class Context: def output_params(self, arg0: Context.OutputParams) -> None: pass @property - def pkgs_dirs(self) -> typing.List[Path]: + def pkgs_dirs(self) -> list[Path]: """ - :type: typing.List[Path] + :type: list[Path] """ @pkgs_dirs.setter - def pkgs_dirs(self, arg0: typing.List[Path]) -> None: + def pkgs_dirs(self, arg0: list[Path]) -> None: pass @property def platform(self) -> str: @@ -724,12 +725,12 @@ class Context: def prefix_params(self, arg0: Context.PrefixParams) -> None: pass @property - def proxy_servers(self) -> typing.Dict[str, str]: + def proxy_servers(self) -> dict[str, str]: """ - :type: typing.Dict[str, str] + :type: dict[str, str] """ @proxy_servers.setter - def proxy_servers(self, arg1: typing.Dict[str, str]) -> None: + def proxy_servers(self, arg1: dict[str, str]) -> None: pass @property def quiet(self) -> bool: @@ -865,7 +866,7 @@ class ExtraPkgInfo: class History: def __init__(self, arg0: Path) -> None: ... - def get_requested_specs_map(self) -> typing.Dict[str, MatchSpec]: ... + def get_requested_specs_map(self) -> dict[str, MatchSpec]: ... pass class Key: @@ -903,7 +904,7 @@ class Key: pass class RoleBase: - def all_keys(self) -> typing.Dict[str, RoleFullKeys]: ... + def all_keys(self) -> dict[str, RoleFullKeys]: ... @property def expired(self) -> bool: """ @@ -968,6 +969,7 @@ class LogLevel: def __ne__(self, other: object) -> bool: ... def __repr__(self) -> str: ... def __setstate__(self, state: int) -> None: ... + def __str__(self) -> str: ... @property def name(self) -> str: """ @@ -1000,7 +1002,7 @@ class MatchSpec: pass class MultiPackageCache: - def __init__(self, arg0: typing.List[Path]) -> None: ... + def __init__(self, arg0: list[Path]) -> None: ... def get_tarball_path(self, arg0: PackageInfo, arg1: bool) -> Path: ... @property def first_writable_path(self) -> Path: @@ -1041,28 +1043,28 @@ class PackageInfo: def channel(self, arg0: str) -> None: pass @property - def constrains(self) -> typing.List[str]: + def constrains(self) -> list[str]: """ - :type: typing.List[str] + :type: list[str] """ @constrains.setter - def constrains(self, arg0: typing.List[str]) -> None: + def constrains(self, arg0: list[str]) -> None: pass @property - def defaulted_keys(self) -> typing.Set[str]: + def defaulted_keys(self) -> set[str]: """ - :type: typing.Set[str] + :type: set[str] """ @defaulted_keys.setter - def defaulted_keys(self, arg0: typing.Set[str]) -> None: + def defaulted_keys(self, arg0: set[str]) -> None: pass @property - def depends(self) -> typing.List[str]: + def depends(self) -> list[str]: """ - :type: typing.List[str] + :type: list[str] """ @depends.setter - def depends(self, arg0: typing.List[str]) -> None: + def depends(self, arg0: list[str]) -> None: pass @property def fn(self) -> str: @@ -1192,17 +1194,17 @@ class Pool: def matchspec2id(self, ms: MatchSpec) -> int: ... @typing.overload def matchspec2id(self, ms: str) -> int: ... - def select_solvables(self, id: int, sorted: bool = False) -> typing.List[int]: ... + def select_solvables(self, id: int, sorted: bool = False) -> list[int]: ... def set_debuglevel(self) -> None: ... pass class PrefixData: def __init__(self, arg0: Path) -> None: ... - def add_packages(self, arg0: typing.List[PackageInfo]) -> None: ... + def add_packages(self, arg0: list[PackageInfo]) -> None: ... @property - def package_records(self) -> typing.Dict[str, PackageInfo]: + def package_records(self) -> dict[str, PackageInfo]: """ - :type: typing.Dict[str, PackageInfo] + :type: dict[str, PackageInfo] """ pass @@ -1226,8 +1228,8 @@ class ProblemsGraph: def from_solver(arg0: Solver, arg1: Pool) -> ProblemsGraph: ... def graph( self, - ) -> typing.Tuple[ - typing.Dict[ + ) -> tuple[ + dict[ int, typing.Union[ ProblemsGraph.RootNode, @@ -1236,7 +1238,7 @@ class ProblemsGraph: ProblemsGraph.ConstraintNode, ], ], - typing.Dict[typing.Tuple[int, int], MatchSpec], + dict[tuple[int, int], MatchSpec], ]: ... def root_node(self) -> int: ... pass @@ -1272,6 +1274,7 @@ class QueryFormat: def __ne__(self, other: object) -> bool: ... def __repr__(self) -> str: ... def __setstate__(self, state: int) -> None: ... + def __str__(self) -> str: ... @property def name(self) -> str: """ @@ -1295,10 +1298,10 @@ class Repo: def __init__(self, arg0: Pool, arg1: str, arg2: str, arg3: str) -> None: ... @typing.overload def __init__(self, arg0: Pool, arg1: PrefixData) -> None: ... - def add_extra_pkg_info(self, arg0: typing.Dict[str, ExtraPkgInfo]) -> None: ... + def add_extra_pkg_info(self, arg0: dict[str, ExtraPkgInfo]) -> None: ... def clear(self, arg0: bool) -> bool: ... def name(self) -> str: ... - def priority(self) -> typing.Tuple[int, int]: ... + def priority(self) -> tuple[int, int]: ... def set_installed(self) -> None: ... def set_priority(self, arg0: int, arg1: int) -> None: ... def size(self) -> int: ... @@ -1316,14 +1319,14 @@ class RoleFullKeys: @typing.overload def __init__(self) -> None: ... @typing.overload - def __init__(self, keys: typing.Dict[str, Key], threshold: int) -> None: ... + def __init__(self, keys: dict[str, Key], threshold: int) -> None: ... @property - def keys(self) -> typing.Dict[str, Key]: + def keys(self) -> dict[str, Key]: """ - :type: typing.Dict[str, Key] + :type: dict[str, Key] """ @keys.setter - def keys(self, arg0: typing.Dict[str, Key]) -> None: + def keys(self, arg0: dict[str, Key]) -> None: pass @property def threshold(self) -> int: @@ -1345,23 +1348,19 @@ class RootRole: pass class Solver: - def __init__( - self, arg0: Pool, arg1: typing.List[typing.Tuple[int, int]] - ) -> None: ... + def __init__(self, arg0: Pool, arg1: list[tuple[int, int]]) -> None: ... def add_constraint(self, arg0: str) -> None: ... def add_global_job(self, arg0: int) -> None: ... - def add_jobs(self, arg0: typing.List[str], arg1: int) -> None: ... + def add_jobs(self, arg0: list[str], arg1: int) -> None: ... def add_pin(self, arg0: str) -> None: ... - def all_problems_structured(self) -> typing.List[SolverProblem]: ... + def all_problems_structured(self) -> list[SolverProblem]: ... def all_problems_to_str(self) -> str: ... def explain_problems(self) -> str: ... def is_solved(self) -> bool: ... def must_solve(self) -> None: ... def problems_to_str(self) -> str: ... - def set_flags(self, arg0: typing.List[typing.Tuple[int, int]]) -> None: ... - def set_postsolve_flags( - self, arg0: typing.List[typing.Tuple[int, int]] - ) -> None: ... + def set_flags(self, arg0: list[tuple[int, int]]) -> None: ... + def set_postsolve_flags(self, arg0: list[tuple[int, int]]) -> None: ... def solve(self) -> bool: ... def try_solve(self) -> bool: ... pass @@ -1506,6 +1505,7 @@ class SolverRuleinfo: def __ne__(self, other: object) -> bool: ... def __repr__(self) -> str: ... def __setstate__(self, state: int) -> None: ... + def __str__(self) -> str: ... @property def name(self) -> str: """ @@ -1583,16 +1583,14 @@ class Transaction: def __init__(self, arg0: Pool, arg1: Solver, arg2: MultiPackageCache) -> None: ... def execute(self, arg0: PrefixData) -> bool: ... def fetch_extract_packages(self) -> bool: ... - def find_python_version(self) -> typing.Tuple[str, str]: ... + def find_python_version(self) -> tuple[str, str]: ... def log_json(self) -> None: ... def print(self) -> None: ... def prompt(self) -> bool: ... def to_conda( self, - ) -> typing.Tuple[ - typing.Tuple[typing.List[str], typing.List[str]], - typing.List[typing.Tuple[str, str, str]], - typing.List[typing.Tuple[str, str]], + ) -> tuple[ + tuple[list[str], list[str]], list[tuple[str, str, str]], list[tuple[str, str]] ]: ... pass @@ -1614,13 +1612,13 @@ def clean(arg0: int) -> None: def create_cache_dir(arg0: Path) -> str: pass -def generate_ed25519_keypair() -> typing.Tuple[str, str]: +def generate_ed25519_keypair() -> tuple[str, str]: pass -def get_channels(arg0: typing.List[str]) -> typing.List[Channel]: +def get_channels(arg0: list[str]) -> list[Channel]: pass -def get_virtual_packages() -> typing.List[PackageInfo]: +def get_virtual_packages() -> list[PackageInfo]: pass def init_console() -> None: diff --git a/mamba/environment-dev.yml b/mamba/environment-dev.yml index 220a8f0859..d9bc86af49 100644 --- a/mamba/environment-dev.yml +++ b/mamba/environment-dev.yml @@ -28,6 +28,6 @@ dependencies: - conda >=24.1.0 - conda-content-trust - cryptography<40.0 # Or breaks conda-content-trust - - pip: - - securesystemslib + - pre-commit + - securesystemslib - sel(win): winreg diff --git a/mamba/tests/test_all.py b/mamba/tests/test_all.py index d7c6af0008..495295a375 100644 --- a/mamba/tests/test_all.py +++ b/mamba/tests/test_all.py @@ -102,7 +102,9 @@ def test_env_update(shell_type, tmpdir): def test_track_features(shell_type): with Environment(shell_type) as env: # should install CPython since PyPy has track features - version = "3.7.9" + # macos runners switched to arm64, where available python versions are at least "3.8" + # "3.8.12" seems to be a stable one + version = "3.8.12" env.mamba( f'install -q -y "python={version}" --strict-channel-priority -c conda-forge' ) diff --git a/mamba/tests/utils.py b/mamba/tests/utils.py index 3942beb232..d94bc1e5b1 100644 --- a/mamba/tests/utils.py +++ b/mamba/tests/utils.py @@ -170,18 +170,23 @@ def add_glibc_virtual_package(): def copy_channels_osx(): here = os.path.dirname(os.path.abspath(__file__)) - for channel in ["a", "b"]: - if not os.path.exists(os.path.join(here, f"channel_{channel}/osx-64")): - shutil.copytree( - os.path.join(here, f"channel_{channel}/linux-64"), - os.path.join(here, f"channel_{channel}/osx-64"), - ) - with open( - os.path.join(here, f"channel_{channel}/osx-64/repodata.json") - ) as f: - repodata = f.read() - with open( - os.path.join(here, f"channel_{channel}/osx-64/repodata.json"), "w" - ) as f: - repodata = repodata.replace("linux", "osx") - f.write(repodata) + # In CI, macos-latest can be arm64 or not + for arch in ["osx-64", "osx-arm64"]: + for channel in ["a", "b"]: + if not os.path.exists(os.path.join(here, f"channel_{channel}/{arch}")): + shutil.copytree( + os.path.join(here, f"channel_{channel}/linux-64"), + os.path.join(here, f"channel_{channel}/{arch}"), + ) + with open( + os.path.join(here, f"channel_{channel}/{arch}/repodata.json") + ) as f: + repodata = f.read() + with open( + os.path.join(here, f"channel_{channel}/{arch}/repodata.json"), "w" + ) as f: + if arch == "osx-64": + repodata = repodata.replace("linux", "osx") + else: + repodata = repodata.replace("linux-", "osx-arm") + f.write(repodata) diff --git a/micromamba/tests/test_create.py b/micromamba/tests/test_create.py index 28e4c231d7..6fbf066161 100644 --- a/micromamba/tests/test_create.py +++ b/micromamba/tests/test_create.py @@ -60,7 +60,7 @@ def test_specs(tmp_home, tmp_root_prefix, tmp_path, source, file_type, create_cm specs = [] if source in ("cli_only", "both"): - specs = ["xframe", "xtl"] + specs = ["xtensor-python", "xtl"] cmd += specs if source in ("spec_file_only", "both"): @@ -660,7 +660,7 @@ def test_channel_nodefaults(tmp_home, tmp_root_prefix, tmp_path): " - yaml", " - nodefaults", "dependencies:", - " - xframe", + " - xtensor-python", ] with open(spec_file, "w") as f: f.write("\n".join(contents)) @@ -682,7 +682,7 @@ def test_channel_nodefaults(tmp_home, tmp_root_prefix, tmp_path): @pytest.mark.parametrize("shared_pkgs_dirs", [True], indirect=True) def test_pin_applicable(tmp_home, tmp_root_prefix, tmp_path): pin_name = "xtensor" - pin_max_version = "0.20" + pin_max_version = "0.24" # We add the channel to test a fragile behavior of ``MPool`` spec_name = "conda-forge::xtensor" rc_file = tmp_path / "rc.yaml" @@ -700,7 +700,7 @@ def test_pin_applicable(tmp_home, tmp_root_prefix, tmp_path): install_pkg = p # Should do proper version comparison - assert install_pkg["version"] == "0.20.0" + assert install_pkg["version"] == "0.24.0" @pytest.mark.parametrize("shared_pkgs_dirs", [True], indirect=True) @@ -754,7 +754,6 @@ def test_set_platform(tmp_home, tmp_root_prefix): @pytest.mark.parametrize( "version,build,cache_tag", [ - ["2.7", "*", ""], ["3.10", "*_cpython", "cpython-310"], # FIXME: https://github.com/mamba-org/mamba/issues/1432 # [ "3.7", "*_pypy","pypy37"], diff --git a/micromamba/tests/test_env-lock.yaml b/micromamba/tests/test_env-lock.yaml index a37987df80..3f983d5882 100644 --- a/micromamba/tests/test_env-lock.yaml +++ b/micromamba/tests/test_env-lock.yaml @@ -24,6 +24,7 @@ metadata: - linux-64 - osx-64 - win-64 + - osx-arm64 sources: - environment.yml package: @@ -124,6 +125,29 @@ package: platform: osx-64 url: https://conda.anaconda.org/conda-forge/osx-64/zlib-1.2.11-h9173be1_1013.tar.bz2 version: 1.2.11 +- category: main + dependencies: {} + hash: + md5: fe3c74ef0fe456a4011468f860b0c3dc + sha256: 008465adb9815441f03437393d4274e0154edc55e278bdf1acdf87224d1107e6 + manager: conda + name: libzlib + optional: false + platform: osx-arm64 + url: https://conda.anaconda.org/conda-forge/osx-arm64/libzlib-1.2.11-hee7b306_1013.tar.bz2 + version: 1.2.11 +- category: main + dependencies: + libzlib: 1.2.11 hee7b306_1013 + hash: + md5: 0b65c3db409dd06257dd879605eddb45 + sha256: 04cbcc43aaf9b1ba31eddb0a93adb1a025156542fd4ba2b7b66b4ba4f4126d50 + manager: conda + name: zlib + optional: false + platform: osx-arm64 + url: https://conda.anaconda.org/conda-forge/osx-arm64/zlib-1.2.11-hee7b306_1013.tar.bz2 + version: 1.2.11 - category: main dependencies: {} hash: diff --git a/micromamba/tests/test_install.py b/micromamba/tests/test_install.py index e707540f75..9a9eef02a6 100644 --- a/micromamba/tests/test_install.py +++ b/micromamba/tests/test_install.py @@ -73,7 +73,7 @@ def test_specs(self, source, file_type, existing_cache): specs = [] if source in ("cli_only", "both"): - specs = ["xframe", "xtl"] + specs = ["xtensor-python", "xtl"] cmd = list(specs) if source in ("spec_file_only", "both"): @@ -440,8 +440,8 @@ def test_channel_alias(self, alias, existing_cache): dry_run_tests is DryRun.ULTRA_DRY, reason="Running only ultra-dry tests" ) def test_no_python_pinning(self, existing_cache): - install("python=3.9", no_dry_run=True) - res = install("setuptools=28.4.0", "--no-py-pin", "--json") + install("python=3.9.19", no_dry_run=True) + res = install("setuptools=63.4.3", "--no-py-pin", "--json") keys = {"success", "prefix", "actions", "dry_run"} assert keys.issubset(set(res.keys())) @@ -449,24 +449,26 @@ def test_no_python_pinning(self, existing_cache): action_keys = {"LINK", "UNLINK", "PREFIX"} assert action_keys.issubset(set(res["actions"].keys())) - expected_link_packages = ( - {"python"} if os.name == "nt" else {"python", "python_abi"} - ) + expected_link_packages = {"python"} link_packages = {pkg["name"] for pkg in res["actions"]["LINK"]} assert expected_link_packages.issubset(link_packages) unlink_packages = {pkg["name"] for pkg in res["actions"]["UNLINK"]} assert {"python"}.issubset(unlink_packages) py_pkg = [pkg for pkg in res["actions"]["LINK"] if pkg["name"] == "python"][0] - assert not py_pkg["version"].startswith("3.9") + assert py_pkg["version"] != ("3.9.19") py_pkg = [pkg for pkg in res["actions"]["UNLINK"] if pkg["name"] == "python"][0] - assert py_pkg["version"].startswith("3.9") + assert py_pkg["version"] == ("3.9.19") @pytest.mark.skipif( dry_run_tests is DryRun.ULTRA_DRY, reason="Running only ultra-dry tests" ) - @pytest.mark.skipif(sys.platform == "win32", reason="Python2 no available") + @pytest.mark.skipif( + sys.platform == "win32" + or (sys.platform == "darwin" and platform.machine() == "arm64"), + reason="Python2 not available", + ) def test_python_pinning(self, existing_cache): """Black fails to install as it is not available for pinned Python 2.""" res = install("python=2", "--json", no_dry_run=True) @@ -482,20 +484,20 @@ def test_python_pinning(self, existing_cache): dry_run_tests is DryRun.ULTRA_DRY, reason="Running only ultra-dry tests" ) def test_freeze_installed(self, existing_cache): - install("xtensor=0.20", no_dry_run=True) - res = install("xframe", "--freeze-installed", "--json") + install("xtensor=0.24", no_dry_run=True) + res = install("xtensor-blas", "--freeze-installed", "--json") - # without freeze installed, xframe 0.3.0 should be installed and xtensor updated to 0.21 + # without freeze installed, xtensor-blas 0.21.0 should be installed and xtensor updated to 0.25 keys = {"success", "prefix", "actions", "dry_run"} assert keys.issubset(set(res.keys())) action_keys = {"LINK", "PREFIX"} assert action_keys.issubset(set(res["actions"].keys())) - expected_packages = {"xframe"} + expected_packages = {"xtensor-blas"} link_packages = {pkg["name"] for pkg in res["actions"]["LINK"]} - assert expected_packages == link_packages - assert res["actions"]["LINK"][0]["version"] == "0.2.0" + assert expected_packages.issubset(link_packages) + assert res["actions"]["LINK"][-1]["version"] == "0.20.0" def test_channel_specific(self, existing_cache): res = install( diff --git a/micromamba/tests/test_list.py b/micromamba/tests/test_list.py index 09eb2c931e..ed482bb697 100644 --- a/micromamba/tests/test_list.py +++ b/micromamba/tests/test_list.py @@ -17,7 +17,7 @@ class TestList: @classmethod def setup_class(cls): - create("xtensor=0.18", "-n", TestList.env_name, "--json", no_dry_run=True) + create("xtensor=0.24.5", "-n", TestList.env_name, "--json", no_dry_run=True) os.environ["CONDA_PREFIX"] = TestList.prefix @classmethod diff --git a/micromamba/tests/test_remove.py b/micromamba/tests/test_remove.py index 7c4054419e..67ad4f846f 100644 --- a/micromamba/tests/test_remove.py +++ b/micromamba/tests/test_remove.py @@ -70,15 +70,17 @@ def test_remove(self, env_selector, env_created): ) def test_remove_orphaned(self, env_created): env_pkgs = [p["name"] for p in umamba_list("-p", TestRemove.prefix, "--json")] - install("xframe", "-n", TestRemove.env_name, no_dry_run=True) + install("xtensor-python", "-n", TestRemove.env_name, no_dry_run=True) - res = remove("xframe", "-p", TestRemove.prefix, "--json") + res = remove("xtensor-python", "-p", TestRemove.prefix, "--json") keys = {"dry_run", "success", "prefix", "actions"} assert keys.issubset(set(res.keys())) assert res["success"] - assert len(res["actions"]["UNLINK"]) == 1 - assert res["actions"]["UNLINK"][0]["name"] == "xframe" + + assert len(res["actions"]["UNLINK"]) > 1 + assert res["actions"]["UNLINK"][0]["name"] == "xtensor-python" + assert res["actions"]["PREFIX"] == TestRemove.prefix res = remove("xtensor", "-p", TestRemove.prefix, "--json") @@ -97,7 +99,7 @@ def test_remove_force(self, env_created): # check that we can remove a package without solving the environment (putting # it in a bad state, actually) env_pkgs = [p["name"] for p in umamba_list("-p", TestRemove.prefix, "--json")] - install("xframe", "-n", TestRemove.env_name, no_dry_run=True) + install("xtensor-python", "-n", TestRemove.env_name, no_dry_run=True) res = remove("xtl", "-p", TestRemove.prefix, "--json", "--force") @@ -110,7 +112,7 @@ def test_remove_force(self, env_created): def test_remove_noprune(self, env_created): env_pkgs = [p["name"] for p in umamba_list("-p", TestRemove.prefix, "--json")] - install("xframe", "-n", TestRemove.env_name, no_dry_run=True) + install("xtensor-python", "-n", TestRemove.env_name, no_dry_run=True) res = remove("xtensor", "-p", TestRemove.prefix, "--json", "--no-prune") @@ -120,7 +122,7 @@ def test_remove_noprune(self, env_created): assert len(res["actions"]["UNLINK"]) == 2 removed_names = [x["name"] for x in res["actions"]["UNLINK"]] assert "xtensor" in removed_names - assert "xframe" in removed_names + assert "xtensor-python" in removed_names assert res["actions"]["PREFIX"] == TestRemove.prefix def test_remove_in_use(self, env_created): @@ -238,7 +240,7 @@ def common_tests(cls, res, root_prefix=root_prefix, target_prefix=prefix): assert res["target_prefix_checks"] == checks def test_specs(self, env_created): - specs = ["xframe", "xtl"] + specs = ["xtensor-python", "xtl"] cmd = list(specs) res = remove(*cmd, "--print-config-only") diff --git a/micromamba/tests/test_update.py b/micromamba/tests/test_update.py index 8b7003bcf8..387c3b3eca 100644 --- a/micromamba/tests/test_update.py +++ b/micromamba/tests/test_update.py @@ -117,12 +117,12 @@ def site_packages_path(p, pyver): assert requests_link["build_string"] == prev_requests["build_string"] def test_further_constrained_update(self, env_created): - update_res = update("xtensor==0.21.1=*_0", "--json") + update_res = update("xtensor==0.24.5=*_0", "--json") xtensor_link = [ l for l in update_res["actions"]["LINK"] if l["name"] == "xtensor" ][0] - assert xtensor_link["version"] == "0.21.1" + assert xtensor_link["version"] == "0.24.5" assert xtensor_link["build_number"] == 0 def test_classic_spec(self, env_created): @@ -266,7 +266,7 @@ def test_specs(self, source, file_type, env_created): specs = [] if source in ("cli_only", "both"): - specs = ["xframe", "xtl"] + specs = ["xtensor-python", "xtl"] cmd = list(specs) if source in ("spec_file_only", "both"):