diff --git a/docs/cookbook.rst b/docs/cookbook.rst index 26f45d59..b1abc96e 100644 --- a/docs/cookbook.rst +++ b/docs/cookbook.rst @@ -78,6 +78,166 @@ Enter the ``dev`` nox session: With this, a user can simply run ``nox -s dev`` and have their entire environment set up automatically! +Instant Dev Environment using callable venv_backend +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +As an alternative to the above, you can instead invoke a custom callable for ``venv_backend`` to create a development nox session. + +.. code-block:: python + + from nox.sessions import SessionRunner + from nox.virtualenv import VirtualEnv + + + def create_venv_override_location( + location: str, + interpreter: str | None, + reuse_existing: bool, + venv_params: Any, + runner: SessionRunner, + ) -> VirtualEnv: + """ + Override location of virtualenv + + To set the location, pass `venv_params = {"location": path/to/.venv, "venv_params": ...}` + where `venv_params[venv_params]` will be passed to `VirtualEnv` creation. + """ + + if not isinstance(venv_params, dict) or "location" not in venv_params: + raise ValueError("must supply `venv_backend = {'location': path, ...}") + + # Override the virtual environment location + location = venv_params["location"] + assert isinstance(location, str) + + venv = VirtualEnv( + location=location, + interpreter=interpreter, + reuse_existing=reuse_existing, + venv_params=venv_params.get("venv_params"), + ) + + venv.create() + return venv + + + @nox.session( + python="3.11", + venv_backend=create_venv_override_location, + venv_params={"location": ".venv"}, + ) + def dev(session: nox.Session) -> None: + """Easy way to create a development environment + + This will place the development environment in the `.venv` directory + """ + session.install("-e", ".[dev]") + + + + +Create environment with ``conda env create`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +It's common to create conda environments directly from an ``environment.yaml`` +file with ``conda env create``. There are also cases where using ``micromamba`` is advantageous. +To do this with nox, you can use a callable ``venv_backend``. For example: + +.. code-block:: python + + import os + from nox.sessions import SessionRunner + from nox.virtualenv import CondaEnv + from nox.logger import logger + + + def factory_conda_env(backend: str): + """Create a callable backend with specified conda backend.""" + # Override CondaEnv backend + CondaEnv.allowed_globals = ("conda", "mamba", "micromamba") # type: ignore[assignment] + + if backend not in CondaEnv.allowed_globals: + msg = f"{backend=} must be in {CondaEnv.allowed_globals}" + raise ValueError(msg) + + + def create_conda_env( + location: str, + interpreter: str | None, + reuse_existing: bool, + venv_params: Any, + runner: SessionRunner, + ) -> CondaEnv: + """ + Custom venv_backend to create conda environment from `environment.yaml` file + + This particular callable infers the file from the interpreter. For example, + if `interpreter = "3.8"`, then the environment file will be `environment/py3.8-conda-test.yaml` + """ + if not interpreter: + raise ValueError("must supply interpreter for this backend") + + venv = CondaEnv( + location=location, + interpreter=interpreter, + reuse_existing=reuse_existing, + venv_params=venv_params, + conda_cmd=backend, + ) + + env_file = f"environment/py{interpreter}-conda-test.yaml" + + assert os.path.exists(env_file) + # Custom creating (based on CondaEnv.create) + if not venv._clean_location(): + logger.debug(f"Re-using existing conda env at {venv.location_name}.") + venv._reused = True + + else: + cmd = ( + [venv.conda_cmd] + + (["--yes"] if venv.conda_cmd == "micromamba" else ["env"]) + + ["create", "--prefix", venv.location, "-f", env_file] + ) + # cmd = ["conda", "env", "create", "--prefix", venv.location, "-f", env_file] + + logger.info( + f"Creating conda env in {venv.location_name} with env file {env_file}" + ) + logger.info(f"{cmd}") + nox.command.run(cmd, silent=False, log=nox.options.verbose or False) + + return venv + + return create_conda_env + + + + @nox.session(python=["3.8"], venv_backend=factory_conda_env("conda")) + def conda_tests(session: nox.Session) -> None: + """Run test suite in conda environment.""" + # Note that all extra dependencies are assumed to + # be installed during environment creation + session.install("-e", ".", "--no-deps") + session.run("pytest", *session.posargs) + + + @nox.session(python=["3.8"], venv_backend=factory_conda_env("micromamba")) + def micromamba_tests(session: nox.Session) -> None: + """Run test suite in micromamba environment.""" + # Note that all extra dependencies are assumed to + # be installed during environment creation + session.install("-e", ".", "--no-deps") + session.run("pytest", *session.posargs) + +Note that this scheme can be extended to use, for example, `conda-lock +`_ to install locked environments. + + + + + + The Auto-Release ^^^^^^^^^^^^^^^^ diff --git a/docs/tutorial.rst b/docs/tutorial.rst index ac76a543..613d60a7 100644 --- a/docs/tutorial.rst +++ b/docs/tutorial.rst @@ -410,6 +410,13 @@ incompatible versions of packages already installed with conda. use/require `mamba `_ instead of conda. +Customized virtual environment creation +--------------------------------------- + +If the builtin methods for creating virtual environments don't fit you exact +needs, you can instead pass a callable for ``venv_backend``. See :doc:`cookbook` for examples. + + Parametrization --------------- diff --git a/environment/create_env_files.py b/environment/create_env_files.py new file mode 100644 index 00000000..0e98383e --- /dev/null +++ b/environment/create_env_files.py @@ -0,0 +1,72 @@ +import logging +import os +import sys +from pathlib import Path + +PYTHON_VERSIONS = ["3.7", "3.8", "3.9", "3.10", "3.11"] +LOCK_VERSIONS = ["3.11"] + + +logger = logging.getLogger(__name__) + + +HERE = Path(__file__).resolve().parent + + +def create_yaml(*deps: str) -> str: + x = ["dependencies:"] + x.extend([f" - {dep}" for dep in deps]) + return "\n".join(x) + "\n" + + +def create_yaml_files(): + os.chdir(HERE) + logging.info(f"cwd: {Path.cwd()}") + + # load requirements: + requirements = [ + x.replace(" ", "") + for x in Path("../requirements-conda-test.txt").read_text().strip().split("\n") + ] + + # create environment files + for py in PYTHON_VERSIONS: + yaml = Path(f"py{py}-conda-test.yaml") + + # make sure these have python and pip + s = create_yaml(f"python={py}", *requirements, "pip") + with yaml.open("w") as f: + f.write(s) + + +def create_lock_files(): + import subprocess + + os.chdir(HERE) + for py in LOCK_VERSIONS: + subprocess.run( + [ + "conda-lock", + "lock", + "-c", + "conda-forge", + f"--file=py{py}-conda-test.yaml", + f"--lockfile=py{py}-conda-test-conda-lock.yml", + ], + stdout=sys.stdout, + stderr=sys.stderr, + ) + + +if __name__ == "__main__": + args = sys.argv[1:] + + if not args: + print("pass yaml (to create yaml files) or lock (to create lock files)") + + else: + for arg in args: + if arg == "yaml": + create_yaml_files() + elif arg == "lock": + create_lock_files() diff --git a/environment/py3.10-conda-test.yaml b/environment/py3.10-conda-test.yaml new file mode 100644 index 00000000..9cbe6801 --- /dev/null +++ b/environment/py3.10-conda-test.yaml @@ -0,0 +1,9 @@ +dependencies: + - python=3.10 + - argcomplete>=1.9.4,<3.0 + - colorlog>=2.6.1,<7.0.0 + - jinja2 + - pytest + - tox<4.0.0 + - virtualenv>=14.0.0 + - pip diff --git a/environment/py3.11-conda-test-conda-lock.yml b/environment/py3.11-conda-test-conda-lock.yml new file mode 100644 index 00000000..55a286e6 --- /dev/null +++ b/environment/py3.11-conda-test-conda-lock.yml @@ -0,0 +1,2051 @@ +# This lock file was generated by conda-lock (https://github.com/conda/conda-lock). DO NOT EDIT! +# +# A "lock file" contains a concrete list of package versions (with checksums) to be installed. Unlike +# e.g. `conda env create`, the resulting environment will not change as new package versions become +# available, unless you explicitly update the lock file. +# +# Install this environment as "YOURENV" with: +# conda-lock install -n YOURENV --file py3.11-conda-test-conda-lock.yml +# To update a single package to the latest version compatible with the version constraints in the source: +# conda-lock lock --lockfile py3.11-conda-test-conda-lock.yml --update PACKAGE +# To re-solve the entire environment, e.g. after changing a version constraint in the source file: +# conda-lock -f py3.11-conda-test.yaml --lockfile py3.11-conda-test-conda-lock.yml +version: 1 +metadata: + content_hash: + linux-64: 79890a44306dff3719e90798f83b0fb4ade55598a22cf1d17dc206ad3a6f65bb + osx-arm64: 80643c811b7b03289567d0b1d1eb8be8ac7a77a008b426dae821c161509ba7d9 + osx-64: d047c07dddcc406b95edc42fc7f7d2486ce798e4077eb6420c4bf5369d41565f + win-64: be01e07325a2db2a49bcb673ccd588d6002e87c16234cfacbdfbb2f64a48075a + channels: + - url: conda-forge + used_env_vars: [] + platforms: + - linux-64 + - osx-64 + - osx-arm64 + - win-64 + sources: + - py3.11-conda-test.yaml +package: +- name: _libgcc_mutex + version: '0.1' + manager: conda + platform: linux-64 + dependencies: {} + url: https://conda.anaconda.org/conda-forge/linux-64/_libgcc_mutex-0.1-conda_forge.tar.bz2 + hash: + md5: d7c89558ba9fa0495403155b64376d81 + sha256: fe51de6107f9edc7aa4f786a70f4a883943bc9d39b3bb7307c04c41410990726 + category: main + optional: false +- name: _openmp_mutex + version: '4.5' + manager: conda + platform: linux-64 + dependencies: + _libgcc_mutex: '0.1' + libgomp: '>=7.5.0' + url: https://conda.anaconda.org/conda-forge/linux-64/_openmp_mutex-4.5-2_gnu.tar.bz2 + hash: + md5: 73aaf86a425cc6e73fcf236a5a46396d + sha256: fbe2c5e56a653bebb982eda4876a9178aedfc2b545f25d0ce9c4c0b508253d22 + category: main + optional: false +- name: argcomplete + version: 2.1.2 + manager: conda + platform: linux-64 + dependencies: + python: '>=3.6' + url: https://conda.anaconda.org/conda-forge/noarch/argcomplete-2.1.2-pyhd8ed1ab_0.conda + hash: + md5: 00201195b380c3278cfde109a8fd0562 + sha256: 90765879acce68b0b8bc896c0c633aa7aac5c50896a2db6205a9b9c17901a951 + category: main + optional: false +- name: argcomplete + version: 2.1.2 + manager: conda + platform: osx-64 + dependencies: + python: '>=3.6' + url: https://conda.anaconda.org/conda-forge/noarch/argcomplete-2.1.2-pyhd8ed1ab_0.conda + hash: + md5: 00201195b380c3278cfde109a8fd0562 + sha256: 90765879acce68b0b8bc896c0c633aa7aac5c50896a2db6205a9b9c17901a951 + category: main + optional: false +- name: argcomplete + version: 2.1.2 + manager: conda + platform: osx-arm64 + dependencies: + python: '>=3.6' + url: https://conda.anaconda.org/conda-forge/noarch/argcomplete-2.1.2-pyhd8ed1ab_0.conda + hash: + md5: 00201195b380c3278cfde109a8fd0562 + sha256: 90765879acce68b0b8bc896c0c633aa7aac5c50896a2db6205a9b9c17901a951 + category: main + optional: false +- name: argcomplete + version: 2.1.2 + manager: conda + platform: win-64 + dependencies: + python: '>=3.6' + url: https://conda.anaconda.org/conda-forge/noarch/argcomplete-2.1.2-pyhd8ed1ab_0.conda + hash: + md5: 00201195b380c3278cfde109a8fd0562 + sha256: 90765879acce68b0b8bc896c0c633aa7aac5c50896a2db6205a9b9c17901a951 + category: main + optional: false +- name: bzip2 + version: 1.0.8 + manager: conda + platform: linux-64 + dependencies: + libgcc-ng: '>=12' + url: https://conda.anaconda.org/conda-forge/linux-64/bzip2-1.0.8-hd590300_5.conda + hash: + md5: 69b8b6202a07720f448be700e300ccf4 + sha256: 242c0c324507ee172c0e0dd2045814e746bb303d1eb78870d182ceb0abc726a8 + category: main + optional: false +- name: bzip2 + version: 1.0.8 + manager: conda + platform: osx-64 + dependencies: {} + url: https://conda.anaconda.org/conda-forge/osx-64/bzip2-1.0.8-h10d778d_5.conda + hash: + md5: 6097a6ca9ada32699b5fc4312dd6ef18 + sha256: 61fb2b488928a54d9472113e1280b468a309561caa54f33825a3593da390b242 + category: main + optional: false +- name: bzip2 + version: 1.0.8 + manager: conda + platform: osx-arm64 + dependencies: {} + url: https://conda.anaconda.org/conda-forge/osx-arm64/bzip2-1.0.8-h93a5062_5.conda + hash: + md5: 1bbc659ca658bfd49a481b5ef7a0f40f + sha256: bfa84296a638bea78a8bb29abc493ee95f2a0218775642474a840411b950fe5f + category: main + optional: false +- name: bzip2 + version: 1.0.8 + manager: conda + platform: win-64 + dependencies: + ucrt: '>=10.0.20348.0' + vc: '>=14.2,<15' + vc14_runtime: '>=14.29.30139' + url: https://conda.anaconda.org/conda-forge/win-64/bzip2-1.0.8-hcfcfb64_5.conda + hash: + md5: 26eb8ca6ea332b675e11704cce84a3be + sha256: ae5f47a5c86fd6db822931255dcf017eb12f60c77f07dc782ccb477f7808aab2 + category: main + optional: false +- name: ca-certificates + version: 2023.11.17 + manager: conda + platform: linux-64 + dependencies: {} + url: https://conda.anaconda.org/conda-forge/linux-64/ca-certificates-2023.11.17-hbcca054_0.conda + hash: + md5: 01ffc8d36f9eba0ce0b3c1955fa780ee + sha256: fb4b9f4b7d885002db0b93e22f44b5b03791ef3d4efdc9d0662185a0faafd6b6 + category: main + optional: false +- name: ca-certificates + version: 2023.11.17 + manager: conda + platform: osx-64 + dependencies: {} + url: https://conda.anaconda.org/conda-forge/osx-64/ca-certificates-2023.11.17-h8857fd0_0.conda + hash: + md5: c687e9d14c49e3d3946d50a413cdbf16 + sha256: 7e05d80a97beb7cb7492fae38584a68d51f338a5eddf73a14b5bd266597db90e + category: main + optional: false +- name: ca-certificates + version: 2023.11.17 + manager: conda + platform: osx-arm64 + dependencies: {} + url: https://conda.anaconda.org/conda-forge/osx-arm64/ca-certificates-2023.11.17-hf0a4a13_0.conda + hash: + md5: c01da7c77cfcba2107174e25c1d47384 + sha256: 75f4762a55f7e9453a603c967d549bfa0a7a9669d502d103cb6fbf8c86d993c6 + category: main + optional: false +- name: ca-certificates + version: 2023.11.17 + manager: conda + platform: win-64 + dependencies: {} + url: https://conda.anaconda.org/conda-forge/win-64/ca-certificates-2023.11.17-h56e8100_0.conda + hash: + md5: 1163114b483f26761f993c709e65271f + sha256: c6177e2a4967db7a4e929c6ecd2fafde36e489dbeda23ceda640f4915cb0e877 + category: main + optional: false +- name: colorama + version: 0.4.6 + manager: conda + platform: linux-64 + dependencies: + python: '>=3.7' + url: https://conda.anaconda.org/conda-forge/noarch/colorama-0.4.6-pyhd8ed1ab_0.tar.bz2 + hash: + md5: 3faab06a954c2a04039983f2c4a50d99 + sha256: 2c1b2e9755ce3102bca8d69e8f26e4f087ece73f50418186aee7c74bef8e1698 + category: main + optional: false +- name: colorama + version: 0.4.6 + manager: conda + platform: osx-64 + dependencies: + python: '>=3.7' + url: https://conda.anaconda.org/conda-forge/noarch/colorama-0.4.6-pyhd8ed1ab_0.tar.bz2 + hash: + md5: 3faab06a954c2a04039983f2c4a50d99 + sha256: 2c1b2e9755ce3102bca8d69e8f26e4f087ece73f50418186aee7c74bef8e1698 + category: main + optional: false +- name: colorama + version: 0.4.6 + manager: conda + platform: osx-arm64 + dependencies: + python: '>=3.7' + url: https://conda.anaconda.org/conda-forge/noarch/colorama-0.4.6-pyhd8ed1ab_0.tar.bz2 + hash: + md5: 3faab06a954c2a04039983f2c4a50d99 + sha256: 2c1b2e9755ce3102bca8d69e8f26e4f087ece73f50418186aee7c74bef8e1698 + category: main + optional: false +- name: colorama + version: 0.4.6 + manager: conda + platform: win-64 + dependencies: + python: '>=3.7' + url: https://conda.anaconda.org/conda-forge/noarch/colorama-0.4.6-pyhd8ed1ab_0.tar.bz2 + hash: + md5: 3faab06a954c2a04039983f2c4a50d99 + sha256: 2c1b2e9755ce3102bca8d69e8f26e4f087ece73f50418186aee7c74bef8e1698 + category: main + optional: false +- name: colorlog + version: 6.8.0 + manager: conda + platform: linux-64 + dependencies: + python: '>=3.11,<3.12.0a0' + python_abi: 3.11.* + url: https://conda.anaconda.org/conda-forge/linux-64/colorlog-6.8.0-py311h38be061_0.conda + hash: + md5: 6e81812b1f90ce3f07252c3b42504769 + sha256: 2ef51f578629e11f1b989dfc5f622dc94fd0def8aa540e4a0ca5b3b32acc7865 + category: main + optional: false +- name: colorlog + version: 6.8.0 + manager: conda + platform: osx-64 + dependencies: + python: '>=3.11,<3.12.0a0' + python_abi: 3.11.* + url: https://conda.anaconda.org/conda-forge/osx-64/colorlog-6.8.0-py311h6eed73b_0.conda + hash: + md5: 1435dc18a6e9a78f49d3563814bf6c33 + sha256: 4577a523e480596ac2afe36a7660795933d553b47f0169aa2b679a861031c18e + category: main + optional: false +- name: colorlog + version: 6.8.0 + manager: conda + platform: osx-arm64 + dependencies: + python: '>=3.11,<3.12.0a0' + python_abi: 3.11.* + url: https://conda.anaconda.org/conda-forge/osx-arm64/colorlog-6.8.0-py311h267d04e_0.conda + hash: + md5: 84299fe7602d8b812435e92fef3da5e4 + sha256: 02c36b2291373859afdddfb9e1ffaed1c765103c853568eb149e51fd7224a337 + category: main + optional: false +- name: colorlog + version: 6.8.0 + manager: conda + platform: win-64 + dependencies: + colorama: '' + python: '>=3.11,<3.12.0a0' + python_abi: 3.11.* + url: https://conda.anaconda.org/conda-forge/win-64/colorlog-6.8.0-py311h1ea47a8_0.conda + hash: + md5: d19a34f4cfc8fc1581b26bfbf5e6c618 + sha256: e3f74f31fd2a3d7d3c994651a2b006ae5e870a76fd54ef198789afb5947c190f + category: main + optional: false +- name: distlib + version: 0.3.7 + manager: conda + platform: linux-64 + dependencies: + python: 2.7|>=3.6 + url: https://conda.anaconda.org/conda-forge/noarch/distlib-0.3.7-pyhd8ed1ab_0.conda + hash: + md5: 12d8aae6994f342618443a8f05c652a0 + sha256: 13c887cb4a29e1e853a118cfc0e42b72a7e1d1c50c66c0974885d37f0db30619 + category: main + optional: false +- name: distlib + version: 0.3.7 + manager: conda + platform: osx-64 + dependencies: + python: 2.7|>=3.6 + url: https://conda.anaconda.org/conda-forge/noarch/distlib-0.3.7-pyhd8ed1ab_0.conda + hash: + md5: 12d8aae6994f342618443a8f05c652a0 + sha256: 13c887cb4a29e1e853a118cfc0e42b72a7e1d1c50c66c0974885d37f0db30619 + category: main + optional: false +- name: distlib + version: 0.3.7 + manager: conda + platform: osx-arm64 + dependencies: + python: 2.7|>=3.6 + url: https://conda.anaconda.org/conda-forge/noarch/distlib-0.3.7-pyhd8ed1ab_0.conda + hash: + md5: 12d8aae6994f342618443a8f05c652a0 + sha256: 13c887cb4a29e1e853a118cfc0e42b72a7e1d1c50c66c0974885d37f0db30619 + category: main + optional: false +- name: distlib + version: 0.3.7 + manager: conda + platform: win-64 + dependencies: + python: 2.7|>=3.6 + url: https://conda.anaconda.org/conda-forge/noarch/distlib-0.3.7-pyhd8ed1ab_0.conda + hash: + md5: 12d8aae6994f342618443a8f05c652a0 + sha256: 13c887cb4a29e1e853a118cfc0e42b72a7e1d1c50c66c0974885d37f0db30619 + category: main + optional: false +- name: exceptiongroup + version: 1.2.0 + manager: conda + platform: linux-64 + dependencies: + python: '>=3.7' + url: https://conda.anaconda.org/conda-forge/noarch/exceptiongroup-1.2.0-pyhd8ed1ab_0.conda + hash: + md5: f6c211fee3c98229652b60a9a42ef363 + sha256: cf83dcaf9006015c8ccab3fc6770f478464a66a8769e1763ca5d7dff09d11d08 + category: main + optional: false +- name: exceptiongroup + version: 1.2.0 + manager: conda + platform: osx-64 + dependencies: + python: '>=3.7' + url: https://conda.anaconda.org/conda-forge/noarch/exceptiongroup-1.2.0-pyhd8ed1ab_0.conda + hash: + md5: f6c211fee3c98229652b60a9a42ef363 + sha256: cf83dcaf9006015c8ccab3fc6770f478464a66a8769e1763ca5d7dff09d11d08 + category: main + optional: false +- name: exceptiongroup + version: 1.2.0 + manager: conda + platform: osx-arm64 + dependencies: + python: '>=3.7' + url: https://conda.anaconda.org/conda-forge/noarch/exceptiongroup-1.2.0-pyhd8ed1ab_0.conda + hash: + md5: f6c211fee3c98229652b60a9a42ef363 + sha256: cf83dcaf9006015c8ccab3fc6770f478464a66a8769e1763ca5d7dff09d11d08 + category: main + optional: false +- name: exceptiongroup + version: 1.2.0 + manager: conda + platform: win-64 + dependencies: + python: '>=3.7' + url: https://conda.anaconda.org/conda-forge/noarch/exceptiongroup-1.2.0-pyhd8ed1ab_0.conda + hash: + md5: f6c211fee3c98229652b60a9a42ef363 + sha256: cf83dcaf9006015c8ccab3fc6770f478464a66a8769e1763ca5d7dff09d11d08 + category: main + optional: false +- name: filelock + version: 3.13.1 + manager: conda + platform: linux-64 + dependencies: + python: '>=3.7' + url: https://conda.anaconda.org/conda-forge/noarch/filelock-3.13.1-pyhd8ed1ab_0.conda + hash: + md5: 0c1729b74a8152fde6a38ba0a2ab9f45 + sha256: 4d742d91412d1f163e5399d2b50c5d479694ebcd309127abb549ca3977f89d2b + category: main + optional: false +- name: filelock + version: 3.13.1 + manager: conda + platform: osx-64 + dependencies: + python: '>=3.7' + url: https://conda.anaconda.org/conda-forge/noarch/filelock-3.13.1-pyhd8ed1ab_0.conda + hash: + md5: 0c1729b74a8152fde6a38ba0a2ab9f45 + sha256: 4d742d91412d1f163e5399d2b50c5d479694ebcd309127abb549ca3977f89d2b + category: main + optional: false +- name: filelock + version: 3.13.1 + manager: conda + platform: osx-arm64 + dependencies: + python: '>=3.7' + url: https://conda.anaconda.org/conda-forge/noarch/filelock-3.13.1-pyhd8ed1ab_0.conda + hash: + md5: 0c1729b74a8152fde6a38ba0a2ab9f45 + sha256: 4d742d91412d1f163e5399d2b50c5d479694ebcd309127abb549ca3977f89d2b + category: main + optional: false +- name: filelock + version: 3.13.1 + manager: conda + platform: win-64 + dependencies: + python: '>=3.7' + url: https://conda.anaconda.org/conda-forge/noarch/filelock-3.13.1-pyhd8ed1ab_0.conda + hash: + md5: 0c1729b74a8152fde6a38ba0a2ab9f45 + sha256: 4d742d91412d1f163e5399d2b50c5d479694ebcd309127abb549ca3977f89d2b + category: main + optional: false +- name: importlib-metadata + version: 7.0.0 + manager: conda + platform: linux-64 + dependencies: + python: '>=3.8' + zipp: '>=0.5' + url: https://conda.anaconda.org/conda-forge/noarch/importlib-metadata-7.0.0-pyha770c72_0.conda + hash: + md5: a941237cd06538837b25cd245fcd25d8 + sha256: 9731e82a00d36b182dc515e31723e711ac82890bb1ca86c6a17a4b471135564f + category: main + optional: false +- name: importlib-metadata + version: 7.0.0 + manager: conda + platform: osx-64 + dependencies: + python: '>=3.8' + zipp: '>=0.5' + url: https://conda.anaconda.org/conda-forge/noarch/importlib-metadata-7.0.0-pyha770c72_0.conda + hash: + md5: a941237cd06538837b25cd245fcd25d8 + sha256: 9731e82a00d36b182dc515e31723e711ac82890bb1ca86c6a17a4b471135564f + category: main + optional: false +- name: importlib-metadata + version: 7.0.0 + manager: conda + platform: osx-arm64 + dependencies: + python: '>=3.8' + zipp: '>=0.5' + url: https://conda.anaconda.org/conda-forge/noarch/importlib-metadata-7.0.0-pyha770c72_0.conda + hash: + md5: a941237cd06538837b25cd245fcd25d8 + sha256: 9731e82a00d36b182dc515e31723e711ac82890bb1ca86c6a17a4b471135564f + category: main + optional: false +- name: importlib-metadata + version: 7.0.0 + manager: conda + platform: win-64 + dependencies: + python: '>=3.8' + zipp: '>=0.5' + url: https://conda.anaconda.org/conda-forge/noarch/importlib-metadata-7.0.0-pyha770c72_0.conda + hash: + md5: a941237cd06538837b25cd245fcd25d8 + sha256: 9731e82a00d36b182dc515e31723e711ac82890bb1ca86c6a17a4b471135564f + category: main + optional: false +- name: iniconfig + version: 2.0.0 + manager: conda + platform: linux-64 + dependencies: + python: '>=3.7' + url: https://conda.anaconda.org/conda-forge/noarch/iniconfig-2.0.0-pyhd8ed1ab_0.conda + hash: + md5: f800d2da156d08e289b14e87e43c1ae5 + sha256: 38740c939b668b36a50ef455b077e8015b8c9cf89860d421b3fff86048f49666 + category: main + optional: false +- name: iniconfig + version: 2.0.0 + manager: conda + platform: osx-64 + dependencies: + python: '>=3.7' + url: https://conda.anaconda.org/conda-forge/noarch/iniconfig-2.0.0-pyhd8ed1ab_0.conda + hash: + md5: f800d2da156d08e289b14e87e43c1ae5 + sha256: 38740c939b668b36a50ef455b077e8015b8c9cf89860d421b3fff86048f49666 + category: main + optional: false +- name: iniconfig + version: 2.0.0 + manager: conda + platform: osx-arm64 + dependencies: + python: '>=3.7' + url: https://conda.anaconda.org/conda-forge/noarch/iniconfig-2.0.0-pyhd8ed1ab_0.conda + hash: + md5: f800d2da156d08e289b14e87e43c1ae5 + sha256: 38740c939b668b36a50ef455b077e8015b8c9cf89860d421b3fff86048f49666 + category: main + optional: false +- name: iniconfig + version: 2.0.0 + manager: conda + platform: win-64 + dependencies: + python: '>=3.7' + url: https://conda.anaconda.org/conda-forge/noarch/iniconfig-2.0.0-pyhd8ed1ab_0.conda + hash: + md5: f800d2da156d08e289b14e87e43c1ae5 + sha256: 38740c939b668b36a50ef455b077e8015b8c9cf89860d421b3fff86048f49666 + category: main + optional: false +- name: jinja2 + version: 3.1.2 + manager: conda + platform: linux-64 + dependencies: + markupsafe: '>=2.0' + python: '>=3.7' + url: https://conda.anaconda.org/conda-forge/noarch/jinja2-3.1.2-pyhd8ed1ab_1.tar.bz2 + hash: + md5: c8490ed5c70966d232fdd389d0dbed37 + sha256: b045faba7130ab263db6a8fdc96b1a3de5fcf85c4a607c5f11a49e76851500b5 + category: main + optional: false +- name: jinja2 + version: 3.1.2 + manager: conda + platform: osx-64 + dependencies: + python: '>=3.7' + markupsafe: '>=2.0' + url: https://conda.anaconda.org/conda-forge/noarch/jinja2-3.1.2-pyhd8ed1ab_1.tar.bz2 + hash: + md5: c8490ed5c70966d232fdd389d0dbed37 + sha256: b045faba7130ab263db6a8fdc96b1a3de5fcf85c4a607c5f11a49e76851500b5 + category: main + optional: false +- name: jinja2 + version: 3.1.2 + manager: conda + platform: osx-arm64 + dependencies: + python: '>=3.7' + markupsafe: '>=2.0' + url: https://conda.anaconda.org/conda-forge/noarch/jinja2-3.1.2-pyhd8ed1ab_1.tar.bz2 + hash: + md5: c8490ed5c70966d232fdd389d0dbed37 + sha256: b045faba7130ab263db6a8fdc96b1a3de5fcf85c4a607c5f11a49e76851500b5 + category: main + optional: false +- name: jinja2 + version: 3.1.2 + manager: conda + platform: win-64 + dependencies: + python: '>=3.7' + markupsafe: '>=2.0' + url: https://conda.anaconda.org/conda-forge/noarch/jinja2-3.1.2-pyhd8ed1ab_1.tar.bz2 + hash: + md5: c8490ed5c70966d232fdd389d0dbed37 + sha256: b045faba7130ab263db6a8fdc96b1a3de5fcf85c4a607c5f11a49e76851500b5 + category: main + optional: false +- name: ld_impl_linux-64 + version: '2.40' + manager: conda + platform: linux-64 + dependencies: {} + url: https://conda.anaconda.org/conda-forge/linux-64/ld_impl_linux-64-2.40-h41732ed_0.conda + hash: + md5: 7aca3059a1729aa76c597603f10b0dd3 + sha256: f6cc89d887555912d6c61b295d398cff9ec982a3417d38025c45d5dd9b9e79cd + category: main + optional: false +- name: libexpat + version: 2.5.0 + manager: conda + platform: linux-64 + dependencies: + libgcc-ng: '>=12' + url: https://conda.anaconda.org/conda-forge/linux-64/libexpat-2.5.0-hcb278e6_1.conda + hash: + md5: 6305a3dd2752c76335295da4e581f2fd + sha256: 74c98a563777ae2ad71f1f74d458a8ab043cee4a513467c159ccf159d0e461f3 + category: main + optional: false +- name: libexpat + version: 2.5.0 + manager: conda + platform: osx-64 + dependencies: {} + url: https://conda.anaconda.org/conda-forge/osx-64/libexpat-2.5.0-hf0c8a7f_1.conda + hash: + md5: 6c81cb022780ee33435cca0127dd43c9 + sha256: 80024bd9f44d096c4cc07fb2bac76b5f1f7553390112dab3ad6acb16a05f0b96 + category: main + optional: false +- name: libexpat + version: 2.5.0 + manager: conda + platform: osx-arm64 + dependencies: {} + url: https://conda.anaconda.org/conda-forge/osx-arm64/libexpat-2.5.0-hb7217d7_1.conda + hash: + md5: 5a097ad3d17e42c148c9566280481317 + sha256: 7d143a9c991579ad4207f84c632650a571c66329090daa32b3c87cf7311c3381 + category: main + optional: false +- name: libexpat + version: 2.5.0 + manager: conda + platform: win-64 + dependencies: {} + url: https://conda.anaconda.org/conda-forge/win-64/libexpat-2.5.0-h63175ca_1.conda + hash: + md5: 636cc3cbbd2e28bcfd2f73b2044aac2c + sha256: 794b2a9be72f176a2767c299574d330ffb76b2ed75d7fd20bee3bbadce5886cf + category: main + optional: false +- name: libffi + version: 3.4.2 + manager: conda + platform: linux-64 + dependencies: + libgcc-ng: '>=9.4.0' + url: https://conda.anaconda.org/conda-forge/linux-64/libffi-3.4.2-h7f98852_5.tar.bz2 + hash: + md5: d645c6d2ac96843a2bfaccd2d62b3ac3 + sha256: ab6e9856c21709b7b517e940ae7028ae0737546122f83c2aa5d692860c3b149e + category: main + optional: false +- name: libffi + version: 3.4.2 + manager: conda + platform: osx-64 + dependencies: {} + url: https://conda.anaconda.org/conda-forge/osx-64/libffi-3.4.2-h0d85af4_5.tar.bz2 + hash: + md5: ccb34fb14960ad8b125962d3d79b31a9 + sha256: 7a2d27a936ceee6942ea4d397f9c7d136f12549d86f7617e8b6bad51e01a941f + category: main + optional: false +- name: libffi + version: 3.4.2 + manager: conda + platform: osx-arm64 + dependencies: {} + url: https://conda.anaconda.org/conda-forge/osx-arm64/libffi-3.4.2-h3422bc3_5.tar.bz2 + hash: + md5: 086914b672be056eb70fd4285b6783b6 + sha256: 41b3d13efb775e340e4dba549ab5c029611ea6918703096b2eaa9c015c0750ca + category: main + optional: false +- name: libffi + version: 3.4.2 + manager: conda + platform: win-64 + dependencies: + vc: '>=14.1,<15.0a0' + vs2015_runtime: '>=14.16.27012' + url: https://conda.anaconda.org/conda-forge/win-64/libffi-3.4.2-h8ffe710_5.tar.bz2 + hash: + md5: 2c96d1b6915b408893f9472569dee135 + sha256: 1951ab740f80660e9bc07d2ed3aefb874d78c107264fd810f24a1a6211d4b1a5 + category: main + optional: false +- name: libgcc-ng + version: 13.2.0 + manager: conda + platform: linux-64 + dependencies: + _libgcc_mutex: '0.1' + _openmp_mutex: '>=4.5' + url: https://conda.anaconda.org/conda-forge/linux-64/libgcc-ng-13.2.0-h807b86a_3.conda + hash: + md5: 23fdf1fef05baeb7eadc2aed5fb0011f + sha256: 5e88f658e07a30ab41b154b42c59f079b168acfa9551a75bdc972099453f4105 + category: main + optional: false +- name: libgomp + version: 13.2.0 + manager: conda + platform: linux-64 + dependencies: + _libgcc_mutex: '0.1' + url: https://conda.anaconda.org/conda-forge/linux-64/libgomp-13.2.0-h807b86a_3.conda + hash: + md5: 7124cbb46b13d395bdde68f2d215c989 + sha256: 6ebedee39b6bbbc969715d0d7fa4b381cce67e1139862604ffa393f821c08e81 + category: main + optional: false +- name: libnsl + version: 2.0.1 + manager: conda + platform: linux-64 + dependencies: + libgcc-ng: '>=12' + url: https://conda.anaconda.org/conda-forge/linux-64/libnsl-2.0.1-hd590300_0.conda + hash: + md5: 30fd6e37fe21f86f4bd26d6ee73eeec7 + sha256: 26d77a3bb4dceeedc2a41bd688564fe71bf2d149fdcf117049970bc02ff1add6 + category: main + optional: false +- name: libsqlite + version: 3.44.2 + manager: conda + platform: linux-64 + dependencies: + libgcc-ng: '>=12' + libzlib: '>=1.2.13,<1.3.0a0' + url: https://conda.anaconda.org/conda-forge/linux-64/libsqlite-3.44.2-h2797004_0.conda + hash: + md5: 3b6a9f225c3dbe0d24f4fedd4625c5bf + sha256: ee2c4d724a3ed60d5b458864d66122fb84c6ce1df62f735f90d8db17b66cd88a + category: main + optional: false +- name: libsqlite + version: 3.44.2 + manager: conda + platform: osx-64 + dependencies: + libzlib: '>=1.2.13,<1.3.0a0' + url: https://conda.anaconda.org/conda-forge/osx-64/libsqlite-3.44.2-h92b6c6a_0.conda + hash: + md5: d4419f90019e6a2b152cd4d32f73a82f + sha256: 8a317d2aa6352feba951ca09d5bf34f565f9dd10bb14ff842b8650baa321d781 + category: main + optional: false +- name: libsqlite + version: 3.44.2 + manager: conda + platform: osx-arm64 + dependencies: + libzlib: '>=1.2.13,<1.3.0a0' + url: https://conda.anaconda.org/conda-forge/osx-arm64/libsqlite-3.44.2-h091b4b1_0.conda + hash: + md5: d7e1af696cfadec251a0abdd7b79ed77 + sha256: f0dc2fe69eddb4bab72ff6bb0da51d689294f466ee1b01e80ced1e7878a21aa5 + category: main + optional: false +- name: libsqlite + version: 3.44.2 + manager: conda + platform: win-64 + dependencies: + ucrt: '>=10.0.20348.0' + vc: '>=14.2,<15' + vc14_runtime: '>=14.29.30139' + url: https://conda.anaconda.org/conda-forge/win-64/libsqlite-3.44.2-hcfcfb64_0.conda + hash: + md5: 4a5f5ab56cbf3ccd08d71a1168061213 + sha256: 25bfcf79ec863c2c0f0b3599981e2eac57efc5302faf2bb84f68c3f0faa55d1c + category: main + optional: false +- name: libuuid + version: 2.38.1 + manager: conda + platform: linux-64 + dependencies: + libgcc-ng: '>=12' + url: https://conda.anaconda.org/conda-forge/linux-64/libuuid-2.38.1-h0b41bf4_0.conda + hash: + md5: 40b61aab5c7ba9ff276c41cfffe6b80b + sha256: 787eb542f055a2b3de553614b25f09eefb0a0931b0c87dbcce6efdfd92f04f18 + category: main + optional: false +- name: libzlib + version: 1.2.13 + manager: conda + platform: linux-64 + dependencies: + libgcc-ng: '>=12' + url: https://conda.anaconda.org/conda-forge/linux-64/libzlib-1.2.13-hd590300_5.conda + hash: + md5: f36c115f1ee199da648e0597ec2047ad + sha256: 370c7c5893b737596fd6ca0d9190c9715d89d888b8c88537ae1ef168c25e82e4 + category: main + optional: false +- name: libzlib + version: 1.2.13 + manager: conda + platform: osx-64 + dependencies: {} + url: https://conda.anaconda.org/conda-forge/osx-64/libzlib-1.2.13-h8a1eda9_5.conda + hash: + md5: 4a3ad23f6e16f99c04e166767193d700 + sha256: fc58ad7f47ffea10df1f2165369978fba0a1cc32594aad778f5eec725f334867 + category: main + optional: false +- name: libzlib + version: 1.2.13 + manager: conda + platform: osx-arm64 + dependencies: {} + url: https://conda.anaconda.org/conda-forge/osx-arm64/libzlib-1.2.13-h53f4e23_5.conda + hash: + md5: 1a47f5236db2e06a320ffa0392f81bd8 + sha256: ab1c8aefa2d54322a63aaeeefe9cf877411851738616c4068e0dccc66b9c758a + category: main + optional: false +- name: libzlib + version: 1.2.13 + manager: conda + platform: win-64 + dependencies: + ucrt: '>=10.0.20348.0' + vc: '>=14.2,<15' + vc14_runtime: '>=14.29.30139' + url: https://conda.anaconda.org/conda-forge/win-64/libzlib-1.2.13-hcfcfb64_5.conda + hash: + md5: 5fdb9c6a113b6b6cb5e517fd972d5f41 + sha256: c161822ee8130b71e08b6d282b9919c1de2c5274b29921a867bca0f7d30cad26 + category: main + optional: false +- name: markupsafe + version: 2.1.3 + manager: conda + platform: linux-64 + dependencies: + libgcc-ng: '>=12' + python: '>=3.11,<3.12.0a0' + python_abi: 3.11.* + url: https://conda.anaconda.org/conda-forge/linux-64/markupsafe-2.1.3-py311h459d7ec_1.conda + hash: + md5: 71120b5155a0c500826cf81536721a15 + sha256: e1a9930f35e39bf65bc293e24160b83ebf9f800f02749f65358e1c04882ee6b0 + category: main + optional: false +- name: markupsafe + version: 2.1.3 + manager: conda + platform: osx-64 + dependencies: + python: '>=3.11,<3.12.0a0' + python_abi: 3.11.* + url: https://conda.anaconda.org/conda-forge/osx-64/markupsafe-2.1.3-py311h2725bcf_1.conda + hash: + md5: 52ee86f482b552e547e2b1d6c01adf55 + sha256: 5a8f8caa89eeba6ea6e9e96d3e7c109b675bc3c6ed4b109b8931757da2411d48 + category: main + optional: false +- name: markupsafe + version: 2.1.3 + manager: conda + platform: osx-arm64 + dependencies: + python: '>=3.11,<3.12.0a0' + python_abi: 3.11.* + url: https://conda.anaconda.org/conda-forge/osx-arm64/markupsafe-2.1.3-py311heffc1b2_1.conda + hash: + md5: 5a7b68cb9eea46bea31aaf2d11d0dd2f + sha256: 307c1e3b2e4a2a992a6c94975910adff88cc523e2c9a41e81b2d506d8c9e7359 + category: main + optional: false +- name: markupsafe + version: 2.1.3 + manager: conda + platform: win-64 + dependencies: + python: '>=3.11,<3.12.0a0' + python_abi: 3.11.* + ucrt: '>=10.0.20348.0' + vc: '>=14.2,<15' + vc14_runtime: '>=14.29.30139' + url: https://conda.anaconda.org/conda-forge/win-64/markupsafe-2.1.3-py311ha68e1ae_1.conda + hash: + md5: bc93b9d445824cfce3933b5dcc1087b4 + sha256: 435c4c2df8d98cd49d8332d22b6f4847fc4b594500f0cdf0f9437274c668642b + category: main + optional: false +- name: ncurses + version: '6.4' + manager: conda + platform: linux-64 + dependencies: + libgcc-ng: '>=12' + url: https://conda.anaconda.org/conda-forge/linux-64/ncurses-6.4-h59595ed_2.conda + hash: + md5: 7dbaa197d7ba6032caf7ae7f32c1efa0 + sha256: 91cc03f14caf96243cead96c76fe91ab5925a695d892e83285461fb927dece5e + category: main + optional: false +- name: ncurses + version: '6.4' + manager: conda + platform: osx-64 + dependencies: {} + url: https://conda.anaconda.org/conda-forge/osx-64/ncurses-6.4-hf0c8a7f_0.conda + hash: + md5: c3dbae2411164d9b02c69090a9a91857 + sha256: 7841b1fce1ffb0bfb038f9687b92f04d64acab1f7cb96431972386ea98c7b2fd + category: main + optional: false +- name: ncurses + version: '6.4' + manager: conda + platform: osx-arm64 + dependencies: {} + url: https://conda.anaconda.org/conda-forge/osx-arm64/ncurses-6.4-h7ea286d_0.conda + hash: + md5: 318337fb9d0c53ba635efb7888242373 + sha256: 017e230a1f912e15005d4c4f3d387119190b53240f9ae0ba8a319dd958901780 + category: main + optional: false +- name: openssl + version: 3.2.0 + manager: conda + platform: linux-64 + dependencies: + ca-certificates: '' + libgcc-ng: '>=12' + url: https://conda.anaconda.org/conda-forge/linux-64/openssl-3.2.0-hd590300_1.conda + hash: + md5: 603827b39ea2b835268adb8c821b8570 + sha256: 80efc6f429bd8e622d999652e5cba2ca56fcdb9c16a439d2ce9b4313116e4a87 + category: main + optional: false +- name: openssl + version: 3.2.0 + manager: conda + platform: osx-64 + dependencies: + ca-certificates: '' + url: https://conda.anaconda.org/conda-forge/osx-64/openssl-3.2.0-hd75f5a5_1.conda + hash: + md5: 06cb561619487c88891839b9beb5244c + sha256: 99161bf349f5dc80322f2a2c188588d11efa662566e4e19f2ac0a36d9fa3de25 + category: main + optional: false +- name: openssl + version: 3.2.0 + manager: conda + platform: osx-arm64 + dependencies: + ca-certificates: '' + url: https://conda.anaconda.org/conda-forge/osx-arm64/openssl-3.2.0-h0d3ecfb_1.conda + hash: + md5: 47d16d26100f19ca495882882b7bc93b + sha256: a53e1c6c058b621fd1d13cca6f9cccd534d2b3f4b4ac789fe26f7902031d6c41 + category: main + optional: false +- name: openssl + version: 3.2.0 + manager: conda + platform: win-64 + dependencies: + ca-certificates: '' + ucrt: '>=10.0.20348.0' + vc: '>=14.2,<15' + vc14_runtime: '>=14.29.30139' + url: https://conda.anaconda.org/conda-forge/win-64/openssl-3.2.0-hcfcfb64_1.conda + hash: + md5: d10167022f99bad12ee07dea022d5830 + sha256: 373b9671173ef3413d2a95f3781176b818db904ba82298f8447b9658d71e2cc9 + category: main + optional: false +- name: packaging + version: '23.2' + manager: conda + platform: linux-64 + dependencies: + python: '>=3.7' + url: https://conda.anaconda.org/conda-forge/noarch/packaging-23.2-pyhd8ed1ab_0.conda + hash: + md5: 79002079284aa895f883c6b7f3f88fd6 + sha256: 69b3ace6cca2dab9047b2c24926077d81d236bef45329d264b394001e3c3e52f + category: main + optional: false +- name: packaging + version: '23.2' + manager: conda + platform: osx-64 + dependencies: + python: '>=3.7' + url: https://conda.anaconda.org/conda-forge/noarch/packaging-23.2-pyhd8ed1ab_0.conda + hash: + md5: 79002079284aa895f883c6b7f3f88fd6 + sha256: 69b3ace6cca2dab9047b2c24926077d81d236bef45329d264b394001e3c3e52f + category: main + optional: false +- name: packaging + version: '23.2' + manager: conda + platform: osx-arm64 + dependencies: + python: '>=3.7' + url: https://conda.anaconda.org/conda-forge/noarch/packaging-23.2-pyhd8ed1ab_0.conda + hash: + md5: 79002079284aa895f883c6b7f3f88fd6 + sha256: 69b3ace6cca2dab9047b2c24926077d81d236bef45329d264b394001e3c3e52f + category: main + optional: false +- name: packaging + version: '23.2' + manager: conda + platform: win-64 + dependencies: + python: '>=3.7' + url: https://conda.anaconda.org/conda-forge/noarch/packaging-23.2-pyhd8ed1ab_0.conda + hash: + md5: 79002079284aa895f883c6b7f3f88fd6 + sha256: 69b3ace6cca2dab9047b2c24926077d81d236bef45329d264b394001e3c3e52f + category: main + optional: false +- name: pip + version: 23.3.1 + manager: conda + platform: linux-64 + dependencies: + python: '>=3.7' + setuptools: '' + wheel: '' + url: https://conda.anaconda.org/conda-forge/noarch/pip-23.3.1-pyhd8ed1ab_0.conda + hash: + md5: 2400c0b86889f43aa52067161e1fb108 + sha256: 435829a03e1c6009f013f29bb83de8b876c388820bf8cf69a7baeec25f6a3563 + category: main + optional: false +- name: pip + version: 23.3.1 + manager: conda + platform: osx-64 + dependencies: + setuptools: '' + wheel: '' + python: '>=3.7' + url: https://conda.anaconda.org/conda-forge/noarch/pip-23.3.1-pyhd8ed1ab_0.conda + hash: + md5: 2400c0b86889f43aa52067161e1fb108 + sha256: 435829a03e1c6009f013f29bb83de8b876c388820bf8cf69a7baeec25f6a3563 + category: main + optional: false +- name: pip + version: 23.3.1 + manager: conda + platform: osx-arm64 + dependencies: + setuptools: '' + wheel: '' + python: '>=3.7' + url: https://conda.anaconda.org/conda-forge/noarch/pip-23.3.1-pyhd8ed1ab_0.conda + hash: + md5: 2400c0b86889f43aa52067161e1fb108 + sha256: 435829a03e1c6009f013f29bb83de8b876c388820bf8cf69a7baeec25f6a3563 + category: main + optional: false +- name: pip + version: 23.3.1 + manager: conda + platform: win-64 + dependencies: + setuptools: '' + wheel: '' + python: '>=3.7' + url: https://conda.anaconda.org/conda-forge/noarch/pip-23.3.1-pyhd8ed1ab_0.conda + hash: + md5: 2400c0b86889f43aa52067161e1fb108 + sha256: 435829a03e1c6009f013f29bb83de8b876c388820bf8cf69a7baeec25f6a3563 + category: main + optional: false +- name: platformdirs + version: 4.1.0 + manager: conda + platform: linux-64 + dependencies: + python: '>=3.8' + url: https://conda.anaconda.org/conda-forge/noarch/platformdirs-4.1.0-pyhd8ed1ab_0.conda + hash: + md5: 45a5065664da0d1dfa8f8cd2eaf05ab9 + sha256: 9e4ff17ce802159ed31344eb913eaa877688226765b77947b102b42255a53853 + category: main + optional: false +- name: platformdirs + version: 4.1.0 + manager: conda + platform: osx-64 + dependencies: + python: '>=3.8' + url: https://conda.anaconda.org/conda-forge/noarch/platformdirs-4.1.0-pyhd8ed1ab_0.conda + hash: + md5: 45a5065664da0d1dfa8f8cd2eaf05ab9 + sha256: 9e4ff17ce802159ed31344eb913eaa877688226765b77947b102b42255a53853 + category: main + optional: false +- name: platformdirs + version: 4.1.0 + manager: conda + platform: osx-arm64 + dependencies: + python: '>=3.8' + url: https://conda.anaconda.org/conda-forge/noarch/platformdirs-4.1.0-pyhd8ed1ab_0.conda + hash: + md5: 45a5065664da0d1dfa8f8cd2eaf05ab9 + sha256: 9e4ff17ce802159ed31344eb913eaa877688226765b77947b102b42255a53853 + category: main + optional: false +- name: platformdirs + version: 4.1.0 + manager: conda + platform: win-64 + dependencies: + python: '>=3.8' + url: https://conda.anaconda.org/conda-forge/noarch/platformdirs-4.1.0-pyhd8ed1ab_0.conda + hash: + md5: 45a5065664da0d1dfa8f8cd2eaf05ab9 + sha256: 9e4ff17ce802159ed31344eb913eaa877688226765b77947b102b42255a53853 + category: main + optional: false +- name: pluggy + version: 1.3.0 + manager: conda + platform: linux-64 + dependencies: + python: '>=3.8' + url: https://conda.anaconda.org/conda-forge/noarch/pluggy-1.3.0-pyhd8ed1ab_0.conda + hash: + md5: 2390bd10bed1f3fdc7a537fb5a447d8d + sha256: 7bf2ad9d747e71f1e93d0863c2c8061dd0f2fe1e582f28d292abfb40264a2eb5 + category: main + optional: false +- name: pluggy + version: 1.3.0 + manager: conda + platform: osx-64 + dependencies: + python: '>=3.8' + url: https://conda.anaconda.org/conda-forge/noarch/pluggy-1.3.0-pyhd8ed1ab_0.conda + hash: + md5: 2390bd10bed1f3fdc7a537fb5a447d8d + sha256: 7bf2ad9d747e71f1e93d0863c2c8061dd0f2fe1e582f28d292abfb40264a2eb5 + category: main + optional: false +- name: pluggy + version: 1.3.0 + manager: conda + platform: osx-arm64 + dependencies: + python: '>=3.8' + url: https://conda.anaconda.org/conda-forge/noarch/pluggy-1.3.0-pyhd8ed1ab_0.conda + hash: + md5: 2390bd10bed1f3fdc7a537fb5a447d8d + sha256: 7bf2ad9d747e71f1e93d0863c2c8061dd0f2fe1e582f28d292abfb40264a2eb5 + category: main + optional: false +- name: pluggy + version: 1.3.0 + manager: conda + platform: win-64 + dependencies: + python: '>=3.8' + url: https://conda.anaconda.org/conda-forge/noarch/pluggy-1.3.0-pyhd8ed1ab_0.conda + hash: + md5: 2390bd10bed1f3fdc7a537fb5a447d8d + sha256: 7bf2ad9d747e71f1e93d0863c2c8061dd0f2fe1e582f28d292abfb40264a2eb5 + category: main + optional: false +- name: py + version: 1.11.0 + manager: conda + platform: linux-64 + dependencies: + python: '>=2.7' + url: https://conda.anaconda.org/conda-forge/noarch/py-1.11.0-pyh6c4a22f_0.tar.bz2 + hash: + md5: b4613d7e7a493916d867842a6a148054 + sha256: 268be33a290e3d51467ab29cbb5a80cf79f69dade2f2dead25d7f80d76c3543a + category: main + optional: false +- name: py + version: 1.11.0 + manager: conda + platform: osx-64 + dependencies: + python: '>=2.7' + url: https://conda.anaconda.org/conda-forge/noarch/py-1.11.0-pyh6c4a22f_0.tar.bz2 + hash: + md5: b4613d7e7a493916d867842a6a148054 + sha256: 268be33a290e3d51467ab29cbb5a80cf79f69dade2f2dead25d7f80d76c3543a + category: main + optional: false +- name: py + version: 1.11.0 + manager: conda + platform: osx-arm64 + dependencies: + python: '>=2.7' + url: https://conda.anaconda.org/conda-forge/noarch/py-1.11.0-pyh6c4a22f_0.tar.bz2 + hash: + md5: b4613d7e7a493916d867842a6a148054 + sha256: 268be33a290e3d51467ab29cbb5a80cf79f69dade2f2dead25d7f80d76c3543a + category: main + optional: false +- name: py + version: 1.11.0 + manager: conda + platform: win-64 + dependencies: + python: '>=2.7' + url: https://conda.anaconda.org/conda-forge/noarch/py-1.11.0-pyh6c4a22f_0.tar.bz2 + hash: + md5: b4613d7e7a493916d867842a6a148054 + sha256: 268be33a290e3d51467ab29cbb5a80cf79f69dade2f2dead25d7f80d76c3543a + category: main + optional: false +- name: pytest + version: 7.4.3 + manager: conda + platform: linux-64 + dependencies: + colorama: '' + exceptiongroup: '>=1.0.0rc8' + iniconfig: '' + packaging: '' + pluggy: '>=0.12,<2.0' + python: '>=3.7' + tomli: '>=1.0.0' + url: https://conda.anaconda.org/conda-forge/noarch/pytest-7.4.3-pyhd8ed1ab_0.conda + hash: + md5: 5bdca0aca30b0ee62bb84854e027eae0 + sha256: 14e948e620ec87d9e62a8d9c21d40084b4805a939cfee322be7d457379dc96a0 + category: main + optional: false +- name: pytest + version: 7.4.3 + manager: conda + platform: osx-64 + dependencies: + packaging: '' + colorama: '' + iniconfig: '' + python: '>=3.7' + exceptiongroup: '>=1.0.0rc8' + tomli: '>=1.0.0' + pluggy: '>=0.12,<2.0' + url: https://conda.anaconda.org/conda-forge/noarch/pytest-7.4.3-pyhd8ed1ab_0.conda + hash: + md5: 5bdca0aca30b0ee62bb84854e027eae0 + sha256: 14e948e620ec87d9e62a8d9c21d40084b4805a939cfee322be7d457379dc96a0 + category: main + optional: false +- name: pytest + version: 7.4.3 + manager: conda + platform: osx-arm64 + dependencies: + packaging: '' + colorama: '' + iniconfig: '' + python: '>=3.7' + exceptiongroup: '>=1.0.0rc8' + tomli: '>=1.0.0' + pluggy: '>=0.12,<2.0' + url: https://conda.anaconda.org/conda-forge/noarch/pytest-7.4.3-pyhd8ed1ab_0.conda + hash: + md5: 5bdca0aca30b0ee62bb84854e027eae0 + sha256: 14e948e620ec87d9e62a8d9c21d40084b4805a939cfee322be7d457379dc96a0 + category: main + optional: false +- name: pytest + version: 7.4.3 + manager: conda + platform: win-64 + dependencies: + packaging: '' + colorama: '' + iniconfig: '' + python: '>=3.7' + exceptiongroup: '>=1.0.0rc8' + tomli: '>=1.0.0' + pluggy: '>=0.12,<2.0' + url: https://conda.anaconda.org/conda-forge/noarch/pytest-7.4.3-pyhd8ed1ab_0.conda + hash: + md5: 5bdca0aca30b0ee62bb84854e027eae0 + sha256: 14e948e620ec87d9e62a8d9c21d40084b4805a939cfee322be7d457379dc96a0 + category: main + optional: false +- name: python + version: 3.11.6 + manager: conda + platform: linux-64 + dependencies: + bzip2: '>=1.0.8,<2.0a0' + ld_impl_linux-64: '>=2.36.1' + libexpat: '>=2.5.0,<3.0a0' + libffi: '>=3.4,<4.0a0' + libgcc-ng: '>=12' + libnsl: '>=2.0.0,<2.1.0a0' + libsqlite: '>=3.43.0,<4.0a0' + libuuid: '>=2.38.1,<3.0a0' + libzlib: '>=1.2.13,<1.3.0a0' + ncurses: '>=6.4,<7.0a0' + openssl: '>=3.1.3,<4.0a0' + readline: '>=8.2,<9.0a0' + tk: '>=8.6.13,<8.7.0a0' + tzdata: '' + xz: '>=5.2.6,<6.0a0' + url: https://conda.anaconda.org/conda-forge/linux-64/python-3.11.6-hab00c5b_0_cpython.conda + hash: + md5: b0dfbe2fcbfdb097d321bfd50ecddab1 + sha256: 84f13bd70cff5dcdaee19263b2d4291d5793856a718efc1b63a9cfa9eb6e2ca1 + category: main + optional: false +- name: python + version: 3.11.6 + manager: conda + platform: osx-64 + dependencies: + bzip2: '>=1.0.8,<2.0a0' + libexpat: '>=2.5.0,<3.0a0' + libffi: '>=3.4,<4.0a0' + libsqlite: '>=3.43.0,<4.0a0' + libzlib: '>=1.2.13,<1.3.0a0' + ncurses: '>=6.4,<7.0a0' + openssl: '>=3.1.3,<4.0a0' + readline: '>=8.2,<9.0a0' + tk: '>=8.6.13,<8.7.0a0' + tzdata: '' + xz: '>=5.2.6,<6.0a0' + url: https://conda.anaconda.org/conda-forge/osx-64/python-3.11.6-h30d4d87_0_cpython.conda + hash: + md5: 4d66c5fc01e9be526afe5d828d4de24d + sha256: e3ed331204fbeb03a9a2c2fa834e74997ad4f732ba2124b36f327d38b0cded93 + category: main + optional: false +- name: python + version: 3.11.6 + manager: conda + platform: osx-arm64 + dependencies: + bzip2: '>=1.0.8,<2.0a0' + libexpat: '>=2.5.0,<3.0a0' + libffi: '>=3.4,<4.0a0' + libsqlite: '>=3.43.0,<4.0a0' + libzlib: '>=1.2.13,<1.3.0a0' + ncurses: '>=6.4,<7.0a0' + openssl: '>=3.1.3,<4.0a0' + readline: '>=8.2,<9.0a0' + tk: '>=8.6.13,<8.7.0a0' + tzdata: '' + xz: '>=5.2.6,<6.0a0' + url: https://conda.anaconda.org/conda-forge/osx-arm64/python-3.11.6-h47c9636_0_cpython.conda + hash: + md5: 2271df1db9534f5cac7c2d0820c3359d + sha256: 77054fa9a8fc30f71a18f599ee2897905a3c515202b614fa0f793add7a04a155 + category: main + optional: false +- name: python + version: 3.11.6 + manager: conda + platform: win-64 + dependencies: + bzip2: '>=1.0.8,<2.0a0' + libexpat: '>=2.5.0,<3.0a0' + libffi: '>=3.4,<4.0a0' + libsqlite: '>=3.43.0,<4.0a0' + libzlib: '>=1.2.13,<1.3.0a0' + openssl: '>=3.1.3,<4.0a0' + tk: '>=8.6.13,<8.7.0a0' + tzdata: '' + ucrt: '>=10.0.20348.0' + vc: '>=14.2,<15' + vc14_runtime: '>=14.29.30139' + xz: '>=5.2.6,<6.0a0' + url: https://conda.anaconda.org/conda-forge/win-64/python-3.11.6-h2628c8c_0_cpython.conda + hash: + md5: 80b761856b20383615a3fe8b1b13eef8 + sha256: 7fb38fda8296b2651ef727bb57603f0952c07fc533b172044395744a2641a00a + category: main + optional: false +- name: python_abi + version: '3.11' + manager: conda + platform: linux-64 + dependencies: {} + url: https://conda.anaconda.org/conda-forge/linux-64/python_abi-3.11-4_cp311.conda + hash: + md5: d786502c97404c94d7d58d258a445a65 + sha256: 0be3ac1bf852d64f553220c7e6457e9c047dfb7412da9d22fbaa67e60858b3cf + category: main + optional: false +- name: python_abi + version: '3.11' + manager: conda + platform: osx-64 + dependencies: {} + url: https://conda.anaconda.org/conda-forge/osx-64/python_abi-3.11-4_cp311.conda + hash: + md5: fef7a52f0eca6bae9e8e2e255bc86394 + sha256: f56dfe2a57b3b27bad3f9527f943548e8b2526e949d9d6fc0a383020d9359afe + category: main + optional: false +- name: python_abi + version: '3.11' + manager: conda + platform: osx-arm64 + dependencies: {} + url: https://conda.anaconda.org/conda-forge/osx-arm64/python_abi-3.11-4_cp311.conda + hash: + md5: 8d3751bc73d3bbb66f216fa2331d5649 + sha256: 4837089c477b9b84fa38a17f453e6634e68237267211b27a8a2f5ccd847f4e55 + category: main + optional: false +- name: python_abi + version: '3.11' + manager: conda + platform: win-64 + dependencies: {} + url: https://conda.anaconda.org/conda-forge/win-64/python_abi-3.11-4_cp311.conda + hash: + md5: 70513332c71b56eace4ee6441e66c012 + sha256: 67c2aade3e2160642eec0742384e766b20c766055e3d99335681e3e05d88ed7b + category: main + optional: false +- name: readline + version: '8.2' + manager: conda + platform: linux-64 + dependencies: + libgcc-ng: '>=12' + ncurses: '>=6.3,<7.0a0' + url: https://conda.anaconda.org/conda-forge/linux-64/readline-8.2-h8228510_1.conda + hash: + md5: 47d31b792659ce70f470b5c82fdfb7a4 + sha256: 5435cf39d039387fbdc977b0a762357ea909a7694d9528ab40f005e9208744d7 + category: main + optional: false +- name: readline + version: '8.2' + manager: conda + platform: osx-64 + dependencies: + ncurses: '>=6.3,<7.0a0' + url: https://conda.anaconda.org/conda-forge/osx-64/readline-8.2-h9e318b2_1.conda + hash: + md5: f17f77f2acf4d344734bda76829ce14e + sha256: 41e7d30a097d9b060037f0c6a2b1d4c4ae7e942c06c943d23f9d481548478568 + category: main + optional: false +- name: readline + version: '8.2' + manager: conda + platform: osx-arm64 + dependencies: + ncurses: '>=6.3,<7.0a0' + url: https://conda.anaconda.org/conda-forge/osx-arm64/readline-8.2-h92ec313_1.conda + hash: + md5: 8cbb776a2f641b943d413b3e19df71f4 + sha256: a1dfa679ac3f6007362386576a704ad2d0d7a02e98f5d0b115f207a2da63e884 + category: main + optional: false +- name: setuptools + version: 68.2.2 + manager: conda + platform: linux-64 + dependencies: + python: '>=3.7' + url: https://conda.anaconda.org/conda-forge/noarch/setuptools-68.2.2-pyhd8ed1ab_0.conda + hash: + md5: fc2166155db840c634a1291a5c35a709 + sha256: 851901b1f8f2049edb36a675f0c3f9a98e1495ef4eb214761b048c6f696a06f7 + category: main + optional: false +- name: setuptools + version: 68.2.2 + manager: conda + platform: osx-64 + dependencies: + python: '>=3.7' + url: https://conda.anaconda.org/conda-forge/noarch/setuptools-68.2.2-pyhd8ed1ab_0.conda + hash: + md5: fc2166155db840c634a1291a5c35a709 + sha256: 851901b1f8f2049edb36a675f0c3f9a98e1495ef4eb214761b048c6f696a06f7 + category: main + optional: false +- name: setuptools + version: 68.2.2 + manager: conda + platform: osx-arm64 + dependencies: + python: '>=3.7' + url: https://conda.anaconda.org/conda-forge/noarch/setuptools-68.2.2-pyhd8ed1ab_0.conda + hash: + md5: fc2166155db840c634a1291a5c35a709 + sha256: 851901b1f8f2049edb36a675f0c3f9a98e1495ef4eb214761b048c6f696a06f7 + category: main + optional: false +- name: setuptools + version: 68.2.2 + manager: conda + platform: win-64 + dependencies: + python: '>=3.7' + url: https://conda.anaconda.org/conda-forge/noarch/setuptools-68.2.2-pyhd8ed1ab_0.conda + hash: + md5: fc2166155db840c634a1291a5c35a709 + sha256: 851901b1f8f2049edb36a675f0c3f9a98e1495ef4eb214761b048c6f696a06f7 + category: main + optional: false +- name: six + version: 1.16.0 + manager: conda + platform: linux-64 + dependencies: + python: '' + url: https://conda.anaconda.org/conda-forge/noarch/six-1.16.0-pyh6c4a22f_0.tar.bz2 + hash: + md5: e5f25f8dbc060e9a8d912e432202afc2 + sha256: a85c38227b446f42c5b90d9b642f2c0567880c15d72492d8da074a59c8f91dd6 + category: main + optional: false +- name: six + version: 1.16.0 + manager: conda + platform: osx-64 + dependencies: + python: '' + url: https://conda.anaconda.org/conda-forge/noarch/six-1.16.0-pyh6c4a22f_0.tar.bz2 + hash: + md5: e5f25f8dbc060e9a8d912e432202afc2 + sha256: a85c38227b446f42c5b90d9b642f2c0567880c15d72492d8da074a59c8f91dd6 + category: main + optional: false +- name: six + version: 1.16.0 + manager: conda + platform: osx-arm64 + dependencies: + python: '' + url: https://conda.anaconda.org/conda-forge/noarch/six-1.16.0-pyh6c4a22f_0.tar.bz2 + hash: + md5: e5f25f8dbc060e9a8d912e432202afc2 + sha256: a85c38227b446f42c5b90d9b642f2c0567880c15d72492d8da074a59c8f91dd6 + category: main + optional: false +- name: six + version: 1.16.0 + manager: conda + platform: win-64 + dependencies: + python: '' + url: https://conda.anaconda.org/conda-forge/noarch/six-1.16.0-pyh6c4a22f_0.tar.bz2 + hash: + md5: e5f25f8dbc060e9a8d912e432202afc2 + sha256: a85c38227b446f42c5b90d9b642f2c0567880c15d72492d8da074a59c8f91dd6 + category: main + optional: false +- name: tk + version: 8.6.13 + manager: conda + platform: linux-64 + dependencies: + libgcc-ng: '>=12' + libzlib: '>=1.2.13,<1.3.0a0' + url: https://conda.anaconda.org/conda-forge/linux-64/tk-8.6.13-noxft_h4845f30_101.conda + hash: + md5: d453b98d9c83e71da0741bb0ff4d76bc + sha256: e0569c9caa68bf476bead1bed3d79650bb080b532c64a4af7d8ca286c08dea4e + category: main + optional: false +- name: tk + version: 8.6.13 + manager: conda + platform: osx-64 + dependencies: + libzlib: '>=1.2.13,<1.3.0a0' + url: https://conda.anaconda.org/conda-forge/osx-64/tk-8.6.13-h1abcd95_1.conda + hash: + md5: bf830ba5afc507c6232d4ef0fb1a882d + sha256: 30412b2e9de4ff82d8c2a7e5d06a15f4f4fef1809a72138b6ccb53a33b26faf5 + category: main + optional: false +- name: tk + version: 8.6.13 + manager: conda + platform: osx-arm64 + dependencies: + libzlib: '>=1.2.13,<1.3.0a0' + url: https://conda.anaconda.org/conda-forge/osx-arm64/tk-8.6.13-h5083fa2_1.conda + hash: + md5: b50a57ba89c32b62428b71a875291c9b + sha256: 72457ad031b4c048e5891f3f6cb27a53cb479db68a52d965f796910e71a403a8 + category: main + optional: false +- name: tk + version: 8.6.13 + manager: conda + platform: win-64 + dependencies: + ucrt: '>=10.0.20348.0' + vc: '>=14.2,<15' + vc14_runtime: '>=14.29.30139' + url: https://conda.anaconda.org/conda-forge/win-64/tk-8.6.13-h5226925_1.conda + hash: + md5: fc048363eb8f03cd1737600a5d08aafe + sha256: 2c4e914f521ccb2718946645108c9bd3fc3216ba69aea20c2c3cedbd8db32bb1 + category: main + optional: false +- name: tomli + version: 2.0.1 + manager: conda + platform: linux-64 + dependencies: + python: '>=3.7' + url: https://conda.anaconda.org/conda-forge/noarch/tomli-2.0.1-pyhd8ed1ab_0.tar.bz2 + hash: + md5: 5844808ffab9ebdb694585b50ba02a96 + sha256: 4cd48aba7cd026d17e86886af48d0d2ebc67ed36f87f6534f4b67138f5a5a58f + category: main + optional: false +- name: tomli + version: 2.0.1 + manager: conda + platform: osx-64 + dependencies: + python: '>=3.7' + url: https://conda.anaconda.org/conda-forge/noarch/tomli-2.0.1-pyhd8ed1ab_0.tar.bz2 + hash: + md5: 5844808ffab9ebdb694585b50ba02a96 + sha256: 4cd48aba7cd026d17e86886af48d0d2ebc67ed36f87f6534f4b67138f5a5a58f + category: main + optional: false +- name: tomli + version: 2.0.1 + manager: conda + platform: osx-arm64 + dependencies: + python: '>=3.7' + url: https://conda.anaconda.org/conda-forge/noarch/tomli-2.0.1-pyhd8ed1ab_0.tar.bz2 + hash: + md5: 5844808ffab9ebdb694585b50ba02a96 + sha256: 4cd48aba7cd026d17e86886af48d0d2ebc67ed36f87f6534f4b67138f5a5a58f + category: main + optional: false +- name: tomli + version: 2.0.1 + manager: conda + platform: win-64 + dependencies: + python: '>=3.7' + url: https://conda.anaconda.org/conda-forge/noarch/tomli-2.0.1-pyhd8ed1ab_0.tar.bz2 + hash: + md5: 5844808ffab9ebdb694585b50ba02a96 + sha256: 4cd48aba7cd026d17e86886af48d0d2ebc67ed36f87f6534f4b67138f5a5a58f + category: main + optional: false +- name: tox + version: 3.27.1 + manager: conda + platform: linux-64 + dependencies: + colorama: '>=0.4.1' + filelock: '>=3.0.0' + importlib-metadata: '>=0.12' + packaging: '>=14' + pluggy: '>=0.12.0' + py: '>=1.4.17' + python: '>=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*' + six: '>=1.14.0' + tomli: '>=2.0.1' + virtualenv: '!=20.0.0,!=20.0.1,!=20.0.2,!=20.0.3,!=20.0.4,!=20.0.5,!=20.0.6,!=20.0.7,>=16.0.0' + url: https://conda.anaconda.org/conda-forge/noarch/tox-3.27.1-pyhd8ed1ab_0.tar.bz2 + hash: + md5: 62b743e1030b17163c70654601afb60d + sha256: 408a6969022cb11928c9fa3c7070833d79baac7068f0c2b7ac74da8edd3e0179 + category: main + optional: false +- name: tox + version: 3.27.1 + manager: conda + platform: osx-64 + dependencies: + six: '>=1.14.0' + tomli: '>=2.0.1' + python: '>=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*' + colorama: '>=0.4.1' + py: '>=1.4.17' + packaging: '>=14' + importlib-metadata: '>=0.12' + filelock: '>=3.0.0' + pluggy: '>=0.12.0' + virtualenv: '!=20.0.0,!=20.0.1,!=20.0.2,!=20.0.3,!=20.0.4,!=20.0.5,!=20.0.6,!=20.0.7,>=16.0.0' + url: https://conda.anaconda.org/conda-forge/noarch/tox-3.27.1-pyhd8ed1ab_0.tar.bz2 + hash: + md5: 62b743e1030b17163c70654601afb60d + sha256: 408a6969022cb11928c9fa3c7070833d79baac7068f0c2b7ac74da8edd3e0179 + category: main + optional: false +- name: tox + version: 3.27.1 + manager: conda + platform: osx-arm64 + dependencies: + six: '>=1.14.0' + tomli: '>=2.0.1' + python: '>=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*' + colorama: '>=0.4.1' + py: '>=1.4.17' + packaging: '>=14' + importlib-metadata: '>=0.12' + filelock: '>=3.0.0' + pluggy: '>=0.12.0' + virtualenv: '!=20.0.0,!=20.0.1,!=20.0.2,!=20.0.3,!=20.0.4,!=20.0.5,!=20.0.6,!=20.0.7,>=16.0.0' + url: https://conda.anaconda.org/conda-forge/noarch/tox-3.27.1-pyhd8ed1ab_0.tar.bz2 + hash: + md5: 62b743e1030b17163c70654601afb60d + sha256: 408a6969022cb11928c9fa3c7070833d79baac7068f0c2b7ac74da8edd3e0179 + category: main + optional: false +- name: tox + version: 3.27.1 + manager: conda + platform: win-64 + dependencies: + six: '>=1.14.0' + tomli: '>=2.0.1' + python: '>=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*' + colorama: '>=0.4.1' + py: '>=1.4.17' + packaging: '>=14' + importlib-metadata: '>=0.12' + filelock: '>=3.0.0' + pluggy: '>=0.12.0' + virtualenv: '!=20.0.0,!=20.0.1,!=20.0.2,!=20.0.3,!=20.0.4,!=20.0.5,!=20.0.6,!=20.0.7,>=16.0.0' + url: https://conda.anaconda.org/conda-forge/noarch/tox-3.27.1-pyhd8ed1ab_0.tar.bz2 + hash: + md5: 62b743e1030b17163c70654601afb60d + sha256: 408a6969022cb11928c9fa3c7070833d79baac7068f0c2b7ac74da8edd3e0179 + category: main + optional: false +- name: tzdata + version: 2023c + manager: conda + platform: linux-64 + dependencies: {} + url: https://conda.anaconda.org/conda-forge/noarch/tzdata-2023c-h71feb2d_0.conda + hash: + md5: 939e3e74d8be4dac89ce83b20de2492a + sha256: 0449138224adfa125b220154408419ec37c06b0b49f63c5954724325903ecf55 + category: main + optional: false +- name: tzdata + version: 2023c + manager: conda + platform: osx-64 + dependencies: {} + url: https://conda.anaconda.org/conda-forge/noarch/tzdata-2023c-h71feb2d_0.conda + hash: + md5: 939e3e74d8be4dac89ce83b20de2492a + sha256: 0449138224adfa125b220154408419ec37c06b0b49f63c5954724325903ecf55 + category: main + optional: false +- name: tzdata + version: 2023c + manager: conda + platform: osx-arm64 + dependencies: {} + url: https://conda.anaconda.org/conda-forge/noarch/tzdata-2023c-h71feb2d_0.conda + hash: + md5: 939e3e74d8be4dac89ce83b20de2492a + sha256: 0449138224adfa125b220154408419ec37c06b0b49f63c5954724325903ecf55 + category: main + optional: false +- name: tzdata + version: 2023c + manager: conda + platform: win-64 + dependencies: {} + url: https://conda.anaconda.org/conda-forge/noarch/tzdata-2023c-h71feb2d_0.conda + hash: + md5: 939e3e74d8be4dac89ce83b20de2492a + sha256: 0449138224adfa125b220154408419ec37c06b0b49f63c5954724325903ecf55 + category: main + optional: false +- name: ucrt + version: 10.0.22621.0 + manager: conda + platform: win-64 + dependencies: {} + url: https://conda.anaconda.org/conda-forge/win-64/ucrt-10.0.22621.0-h57928b3_0.tar.bz2 + hash: + md5: 72608f6cd3e5898229c3ea16deb1ac43 + sha256: f29cdaf8712008f6b419b8b1a403923b00ab2504bfe0fb2ba8eb60e72d4f14c6 + category: main + optional: false +- name: vc + version: '14.3' + manager: conda + platform: win-64 + dependencies: + vc14_runtime: '>=14.36.32532' + url: https://conda.anaconda.org/conda-forge/win-64/vc-14.3-h64f974e_17.conda + hash: + md5: 67ff6791f235bb606659bf2a5c169191 + sha256: 86ae94bf680980776aa761c2b0909a0ddbe1f817e7eeb8b16a1730f10f8891b6 + category: main + optional: false +- name: vc14_runtime + version: 14.36.32532 + manager: conda + platform: win-64 + dependencies: + ucrt: '>=10.0.20348.0' + url: https://conda.anaconda.org/conda-forge/win-64/vc14_runtime-14.36.32532-hdcecf7f_17.conda + hash: + md5: d0de20f2f3fc806a81b44fcdd941aaf7 + sha256: b317d49af32d5c031828e62c08d56f01d9a64cd3f40d4cccb052bc38c7a9e62e + category: main + optional: false +- name: virtualenv + version: 20.25.0 + manager: conda + platform: linux-64 + dependencies: + distlib: <1,>=0.3.7 + filelock: <4,>=3.12.2 + platformdirs: <5,>=3.9.1 + python: '>=3.8' + url: https://conda.anaconda.org/conda-forge/noarch/virtualenv-20.25.0-pyhd8ed1ab_0.conda + hash: + md5: c119653cba436d8183c27bf6d190e587 + sha256: 50827c3721a9dbf973b568709d4381add2a6552fa562f26a385c5edc16a534af + category: main + optional: false +- name: virtualenv + version: 20.25.0 + manager: conda + platform: osx-64 + dependencies: + python: '>=3.8' + distlib: <1,>=0.3.7 + filelock: <4,>=3.12.2 + platformdirs: <5,>=3.9.1 + url: https://conda.anaconda.org/conda-forge/noarch/virtualenv-20.25.0-pyhd8ed1ab_0.conda + hash: + md5: c119653cba436d8183c27bf6d190e587 + sha256: 50827c3721a9dbf973b568709d4381add2a6552fa562f26a385c5edc16a534af + category: main + optional: false +- name: virtualenv + version: 20.25.0 + manager: conda + platform: osx-arm64 + dependencies: + python: '>=3.8' + distlib: <1,>=0.3.7 + filelock: <4,>=3.12.2 + platformdirs: <5,>=3.9.1 + url: https://conda.anaconda.org/conda-forge/noarch/virtualenv-20.25.0-pyhd8ed1ab_0.conda + hash: + md5: c119653cba436d8183c27bf6d190e587 + sha256: 50827c3721a9dbf973b568709d4381add2a6552fa562f26a385c5edc16a534af + category: main + optional: false +- name: virtualenv + version: 20.25.0 + manager: conda + platform: win-64 + dependencies: + python: '>=3.8' + distlib: <1,>=0.3.7 + filelock: <4,>=3.12.2 + platformdirs: <5,>=3.9.1 + url: https://conda.anaconda.org/conda-forge/noarch/virtualenv-20.25.0-pyhd8ed1ab_0.conda + hash: + md5: c119653cba436d8183c27bf6d190e587 + sha256: 50827c3721a9dbf973b568709d4381add2a6552fa562f26a385c5edc16a534af + category: main + optional: false +- name: vs2015_runtime + version: 14.36.32532 + manager: conda + platform: win-64 + dependencies: + vc14_runtime: '>=14.36.32532' + url: https://conda.anaconda.org/conda-forge/win-64/vs2015_runtime-14.36.32532-h05e6639_17.conda + hash: + md5: 4618046c39f7c81861e53ded842e738a + sha256: 5ecbd731dc7f13762d67be0eadc47eb7f14713005e430d9b5fc680e965ac0f81 + category: main + optional: false +- name: wheel + version: 0.42.0 + manager: conda + platform: linux-64 + dependencies: + python: '>=3.7' + url: https://conda.anaconda.org/conda-forge/noarch/wheel-0.42.0-pyhd8ed1ab_0.conda + hash: + md5: 1cdea58981c5cbc17b51973bcaddcea7 + sha256: 80be0ccc815ce22f80c141013302839b0ed938a2edb50b846cf48d8a8c1cfa01 + category: main + optional: false +- name: wheel + version: 0.42.0 + manager: conda + platform: osx-64 + dependencies: + python: '>=3.7' + url: https://conda.anaconda.org/conda-forge/noarch/wheel-0.42.0-pyhd8ed1ab_0.conda + hash: + md5: 1cdea58981c5cbc17b51973bcaddcea7 + sha256: 80be0ccc815ce22f80c141013302839b0ed938a2edb50b846cf48d8a8c1cfa01 + category: main + optional: false +- name: wheel + version: 0.42.0 + manager: conda + platform: osx-arm64 + dependencies: + python: '>=3.7' + url: https://conda.anaconda.org/conda-forge/noarch/wheel-0.42.0-pyhd8ed1ab_0.conda + hash: + md5: 1cdea58981c5cbc17b51973bcaddcea7 + sha256: 80be0ccc815ce22f80c141013302839b0ed938a2edb50b846cf48d8a8c1cfa01 + category: main + optional: false +- name: wheel + version: 0.42.0 + manager: conda + platform: win-64 + dependencies: + python: '>=3.7' + url: https://conda.anaconda.org/conda-forge/noarch/wheel-0.42.0-pyhd8ed1ab_0.conda + hash: + md5: 1cdea58981c5cbc17b51973bcaddcea7 + sha256: 80be0ccc815ce22f80c141013302839b0ed938a2edb50b846cf48d8a8c1cfa01 + category: main + optional: false +- name: xz + version: 5.2.6 + manager: conda + platform: linux-64 + dependencies: + libgcc-ng: '>=12' + url: https://conda.anaconda.org/conda-forge/linux-64/xz-5.2.6-h166bdaf_0.tar.bz2 + hash: + md5: 2161070d867d1b1204ea749c8eec4ef0 + sha256: 03a6d28ded42af8a347345f82f3eebdd6807a08526d47899a42d62d319609162 + category: main + optional: false +- name: xz + version: 5.2.6 + manager: conda + platform: osx-64 + dependencies: {} + url: https://conda.anaconda.org/conda-forge/osx-64/xz-5.2.6-h775f41a_0.tar.bz2 + hash: + md5: a72f9d4ea13d55d745ff1ed594747f10 + sha256: eb09823f34cc2dd663c0ec4ab13f246f45dcd52e5b8c47b9864361de5204a1c8 + category: main + optional: false +- name: xz + version: 5.2.6 + manager: conda + platform: osx-arm64 + dependencies: {} + url: https://conda.anaconda.org/conda-forge/osx-arm64/xz-5.2.6-h57fd34a_0.tar.bz2 + hash: + md5: 39c6b54e94014701dd157f4f576ed211 + sha256: 59d78af0c3e071021cfe82dc40134c19dab8cdf804324b62940f5c8cd71803ec + category: main + optional: false +- name: xz + version: 5.2.6 + manager: conda + platform: win-64 + dependencies: + vc: '>=14.1,<15' + vs2015_runtime: '>=14.16.27033' + url: https://conda.anaconda.org/conda-forge/win-64/xz-5.2.6-h8d14728_0.tar.bz2 + hash: + md5: 515d77642eaa3639413c6b1bc3f94219 + sha256: 54d9778f75a02723784dc63aff4126ff6e6749ba21d11a6d03c1f4775f269fe0 + category: main + optional: false +- name: zipp + version: 3.17.0 + manager: conda + platform: linux-64 + dependencies: + python: '>=3.8' + url: https://conda.anaconda.org/conda-forge/noarch/zipp-3.17.0-pyhd8ed1ab_0.conda + hash: + md5: 2e4d6bc0b14e10f895fc6791a7d9b26a + sha256: bced1423fdbf77bca0a735187d05d9b9812d2163f60ab426fc10f11f92ecbe26 + category: main + optional: false +- name: zipp + version: 3.17.0 + manager: conda + platform: osx-64 + dependencies: + python: '>=3.8' + url: https://conda.anaconda.org/conda-forge/noarch/zipp-3.17.0-pyhd8ed1ab_0.conda + hash: + md5: 2e4d6bc0b14e10f895fc6791a7d9b26a + sha256: bced1423fdbf77bca0a735187d05d9b9812d2163f60ab426fc10f11f92ecbe26 + category: main + optional: false +- name: zipp + version: 3.17.0 + manager: conda + platform: osx-arm64 + dependencies: + python: '>=3.8' + url: https://conda.anaconda.org/conda-forge/noarch/zipp-3.17.0-pyhd8ed1ab_0.conda + hash: + md5: 2e4d6bc0b14e10f895fc6791a7d9b26a + sha256: bced1423fdbf77bca0a735187d05d9b9812d2163f60ab426fc10f11f92ecbe26 + category: main + optional: false +- name: zipp + version: 3.17.0 + manager: conda + platform: win-64 + dependencies: + python: '>=3.8' + url: https://conda.anaconda.org/conda-forge/noarch/zipp-3.17.0-pyhd8ed1ab_0.conda + hash: + md5: 2e4d6bc0b14e10f895fc6791a7d9b26a + sha256: bced1423fdbf77bca0a735187d05d9b9812d2163f60ab426fc10f11f92ecbe26 + category: main + optional: false diff --git a/environment/py3.11-conda-test.yaml b/environment/py3.11-conda-test.yaml new file mode 100644 index 00000000..8d9f9b37 --- /dev/null +++ b/environment/py3.11-conda-test.yaml @@ -0,0 +1,9 @@ +dependencies: + - python=3.11 + - argcomplete>=1.9.4,<3.0 + - colorlog>=2.6.1,<7.0.0 + - jinja2 + - pytest + - tox<4.0.0 + - virtualenv>=14.0.0 + - pip diff --git a/environment/py3.7-conda-test.yaml b/environment/py3.7-conda-test.yaml new file mode 100644 index 00000000..abf3ad25 --- /dev/null +++ b/environment/py3.7-conda-test.yaml @@ -0,0 +1,9 @@ +dependencies: + - python=3.7 + - argcomplete>=1.9.4,<3.0 + - colorlog>=2.6.1,<7.0.0 + - jinja2 + - pytest + - tox<4.0.0 + - virtualenv>=14.0.0 + - pip diff --git a/environment/py3.8-conda-test.yaml b/environment/py3.8-conda-test.yaml new file mode 100644 index 00000000..8feb73bc --- /dev/null +++ b/environment/py3.8-conda-test.yaml @@ -0,0 +1,9 @@ +dependencies: + - python=3.8 + - argcomplete>=1.9.4,<3.0 + - colorlog>=2.6.1,<7.0.0 + - jinja2 + - pytest + - tox<4.0.0 + - virtualenv>=14.0.0 + - pip diff --git a/environment/py3.9-conda-test.yaml b/environment/py3.9-conda-test.yaml new file mode 100644 index 00000000..50e3c4fd --- /dev/null +++ b/environment/py3.9-conda-test.yaml @@ -0,0 +1,9 @@ +dependencies: + - python=3.9 + - argcomplete>=1.9.4,<3.0 + - colorlog>=2.6.1,<7.0.0 + - jinja2 + - pytest + - tox<4.0.0 + - virtualenv>=14.0.0 + - pip diff --git a/nox/sessions.py b/nox/sessions.py index bab59d5b..f7a8fe1f 100644 --- a/nox/sessions.py +++ b/nox/sessions.py @@ -734,6 +734,30 @@ def envdir(self) -> str: return _normalize_path(self.global_config.envdir, self.friendly_name) def _create_venv(self) -> None: + reuse_existing = ( + self.func.reuse_venv or self.global_config.reuse_existing_virtualenvs + ) + + if callable(self.func.venv_backend): + # if passed a callable backend, always use just that + if self.global_config.force_venv_backend: + logger.info("Cannot override callable venv_backend") + logger.info("Using callable venv_backend") + + self.venv = self.func.venv_backend( + location=self.envdir, + interpreter=self.func.python, + reuse_existing=reuse_existing, + venv_params=self.func.venv_params, + runner=self, + ) + if not isinstance(self.venv, ProcessEnv): + raise ValueError( + "Callable venv_backend must return an instance of a ProcessEnv " + "such as VirtualEnv or CondaEnv." + ) + return + backend = ( self.global_config.force_venv_backend or self.func.venv_backend @@ -744,10 +768,6 @@ def _create_venv(self) -> None: self.venv = PassthroughEnv() return - reuse_existing = ( - self.func.reuse_venv or self.global_config.reuse_existing_virtualenvs - ) - if backend is None or backend == "virtualenv": self.venv = VirtualEnv( self.envdir, @@ -771,6 +791,7 @@ def _create_venv(self) -> None: venv=True, venv_params=self.func.venv_params, ) + else: raise ValueError( "Expected venv_backend one of ('virtualenv', 'conda', 'mamba'," diff --git a/noxfile.py b/noxfile.py index 3ebed4b6..16c26cd9 100644 --- a/noxfile.py +++ b/noxfile.py @@ -20,8 +20,13 @@ import platform import shutil import sys +from typing import Any import nox +import nox.command +from nox.logger import logger +from nox.sessions import SessionRunner +from nox.virtualenv import CondaEnv ON_WINDOWS_CI = "CI" in os.environ and platform.system() == "Windows" @@ -49,15 +54,7 @@ def tests(session: nox.Session) -> None: session.notify("cover") -@nox.session(python=["3.7", "3.8", "3.9", "3.10"], venv_backend="conda") -def conda_tests(session: nox.Session) -> None: - """Run test suite with pytest.""" - session.create_tmp() # Fixes permission errors on Windows - session.conda_install( - "--file", "requirements-conda-test.txt", "--channel", "conda-forge" - ) - session.install("-e", ".", "--no-deps") - session.run("pytest", *session.posargs) +# NOTE: moved tests to custom backend section below @nox.session @@ -166,3 +163,153 @@ def github_actions_default_tests(session: nox.Session) -> None: def github_actions_all_tests(session: nox.Session) -> None: """Check all versions installed by the nox GHA Action""" _check_python_version(session) + + +################################################################################ +# testing custom backend +################################################################################ +def factory_conda_env(backend: str): + """Create a callable backend with specified conda backend.""" + # Override CondaEnv backend + CondaEnv.allowed_globals = ("conda", "mamba", "micromamba", "conda-lock") # type: ignore[assignment] + + if backend not in CondaEnv.allowed_globals: + msg = f"{backend=} must be in {CondaEnv.allowed_globals}" + raise ValueError(msg) + + def create_conda_env( + location: str, + interpreter: str | None, + reuse_existing: bool, + venv_params: Any, + runner: SessionRunner, + ) -> CondaEnv: + """ + Custom venv_backend to create conda environment from `environment.yaml` file + + This particular callable infers the file from the interpreter. For example, + if `interpreter = "3.8"`, then the environment file will be `environment/py3.8-conda-test.yaml` + """ + if not interpreter: + raise ValueError("must supply interpreter for this backend") + + venv = CondaEnv( + location=location, + interpreter=interpreter, + reuse_existing=reuse_existing, + venv_params=venv_params, + conda_cmd=backend, + ) + + env_file = f"environment/py{interpreter}-conda-test.yaml" + + assert os.path.exists(env_file) + # Custom creating (based on CondaEnv.create) + if not venv._clean_location(): + logger.debug(f"Re-using existing conda env at {venv.location_name}.") + venv._reused = True + + else: + cmd = ( + [venv.conda_cmd] + + (["--yes"] if venv.conda_cmd == "micromamba" else ["env"]) + + ["create", "--prefix", venv.location, "-f", env_file] + ) + # cmd = ["conda", "env", "create", "--prefix", venv.location, "-f", env_file] + + logger.info( + f"Creating conda env in {venv.location_name} with env file {env_file}" + ) + logger.info(f"{cmd}") + nox.command.run(cmd, silent=False, log=nox.options.verbose or False) + + return venv + + return create_conda_env + + +@nox.session( + python=["3.7", "3.8", "3.9", "3.10"], venv_backend=factory_conda_env("conda") +) +def conda_tests(session: nox.Session) -> None: + """Run test suite with pytest.""" + session.create_tmp() # Fixes permission errors on Windows + session.install("-e", ".", "--no-deps") + session.run("pytest", *session.posargs) + + +@nox.session( + python=["3.7", "3.8", "3.9", "3.10"], venv_backend=factory_conda_env("micromamba") +) +def micromamba_tests(session: nox.Session) -> None: + """Run test suite with pytest.""" + session.create_tmp() # Fixes permission errors on Windows + session.install("-e", ".", "--no-deps") + session.run("pytest", *session.posargs) + + +# conda lock backend +def create_conda_lock_env( + location: str, + interpreter: str | None, + reuse_existing: bool, + venv_params: Any, + runner: SessionRunner, +) -> CondaEnv: + if not interpreter: + raise ValueError("must supply interpreter for this backend") + + lock_file = f"./environment/py{interpreter}-conda-test-conda-lock.yml" + assert os.path.exists(lock_file) + + venv = CondaEnv( + location=location, + interpreter=interpreter, + reuse_existing=reuse_existing, + venv_params=venv_params, + ) + + # Custom creating (based on CondaEnv.create) + if not venv._clean_location(): + logger.debug(f"Re-using existing conda env at {venv.location_name}.") + venv._reused = True + + else: + cmd = ["conda-lock", "install", "--prefix", venv.location, lock_file] + + logger.info( + f"Creating conda env in {venv.location_name} with conda-lock {lock_file}" + ) + nox.command.run(cmd, silent=False, log=nox.options.verbose or False) + + return venv + + +@nox.session( + python=["3.11"], + venv_backend=create_conda_lock_env, +) +def conda_lock_tests(session: nox.Session) -> None: + session.create_tmp() + session.install("-e", ".", "--no-deps") + + session.run("pytest", *session.posargs) + + +@nox.session +def bootstrap_conda_lock_tests(session: nox.Session) -> None: + """Avoids need for conda-lock in requirements + + Instead of needing conda-lock in base environment: + + $ pipx install conda-lock + $ nox -s conda-lock-backed .... + + You can just run: + + $ nox -s bootstrap-conda-lock + """ + session.install("conda-lock") + session.install("-e", ".") + + session.run("nox", "-s", "conda_lock_tests", *session.posargs) diff --git a/tests/test_sessions.py b/tests/test_sessions.py index 00a912c6..3c4659c6 100644 --- a/tests/test_sessions.py +++ b/tests/test_sessions.py @@ -61,6 +61,24 @@ def test__normalize_path_give_up(): assert "any-path" in norm_path +def simple_custom_backend( + location, + interpreter, + reuse_existing, + venv_params, + runner, +): + venv = nox.virtualenv.VirtualEnv( + location=location, + interpreter=interpreter, + reuse_existing=reuse_existing, + venv_params=venv_params.get("venv_params"), + ) + + venv.create() + return venv + + class TestSession: def make_session_and_runner(self): func = mock.Mock(spec=["python"], python="3.7") @@ -905,6 +923,12 @@ def test__create_venv(self, create): ), ("nox.virtualenv.VirtualEnv.create", "venv", nox.virtualenv.VirtualEnv), ("nox.virtualenv.CondaEnv.create", "conda", nox.virtualenv.CondaEnv), + # callable + ( + "nox.virtualenv.VirtualEnv.create", + simple_custom_backend, + nox.virtualenv.VirtualEnv, + ), ], ) def test__create_venv_options(self, create_method, venv_backend, expected_backend): @@ -928,6 +952,68 @@ def test__create_venv_unexpected_venv_backend(self): with pytest.raises(ValueError, match="venv_backend"): runner._create_venv() + def test__create_venv_bad_callable(self): + def bad_backend( + location, + interpreter, + reuse_existing, + venv_params, + runner, + ): + return "hello" + + runner = self.make_runner() + runner.func.venv_backend = bad_backend + + with pytest.raises(ValueError, match="Callable venv_backend"): + runner._create_venv() + + @mock.patch("nox.virtualenv.VirtualEnv.create", autospec=True) + def test__create_venv_callable_venv_backend(self, create): + def custom_backend( + location, + interpreter, + reuse_existing, + venv_params, + runner, + ): + """ + Override location of virtualenv + + To set the location, pass `venv_params = {"location": path/to/.venv, "venv_params": ...}` + where `venv_params[venv_params]` will be passed to `VirtualEnv` creation. + """ + + if not isinstance(venv_params, dict) or "location" not in venv_params: + raise ValueError("must supply `venv_backend = {'location': path, ...}") + + location = venv_params["location"] + assert isinstance(location, str) + + venv = nox.virtualenv.VirtualEnv( + location=location, + interpreter=interpreter, + reuse_existing=reuse_existing, + venv_params=venv_params.get("venv_params"), + ) + + venv.create() + return venv + + runner = self.make_runner() + runner.func.venv_backend = custom_backend + runner.func.venv_params = {"location": ".venv"} + + # even with global config, you'll still use callable + runner.global_config.force_venv_backend = "virtualenv" + runner._create_venv() + + create.assert_called_once_with(runner.venv) + assert isinstance(runner.venv, nox.virtualenv.VirtualEnv) + assert runner.venv.location.endswith(".venv") + assert runner.venv.interpreter is None + assert runner.venv.reuse_existing is False + def make_runner_with_mock_venv(self): runner = self.make_runner() runner._create_venv = mock.Mock()