Esempio n. 1
0
def publish_package(
    build_system: BuildSystem = typer.Option(get_default_package_build_system),
    python_version: Optional[str] = None,
    build: bool = typer.Option(False, "--build", "-b"),
    repository_url: Optional[str] = None,
    username: str = typer.Option(
        ..., "--username", "-u", envvar="SENV_PUBLISHER_USERNAME"
    ),
    password: str = typer.Option(
        ..., "--password", "-p", envvar="SENV_PUBLISHER_PASSWORD"
    ),
    yes: bool = build_yes_option(),
):
    with auto_confirm_yes(yes):
        if build:
            build_package(build_system=build_system, python_version=python_version)
        if build_system == BuildSystem.POETRY:
            with cd(PyProject.get().config_path.parent):
                repository_url = (
                    repository_url
                    or PyProject.get().senv.package.poetry_publish_repository
                )
                if repository_url is not None:
                    subprocess.check_call(
                        [
                            PyProject.get().poetry_path,
                            "config",
                            f"repositories.senv_{PyProject.get().package_name}",
                            repository_url,
                        ]
                    )
                args = [PyProject.get().poetry_path, "publish"]
                if username and password:
                    args += ["--username", username, "--password", password]
                subprocess.check_call(args)
        elif build_system == BuildSystem.CONDA:
            with cd(PyProject.get().config_path.parent):
                repository_url = (
                    repository_url or PyProject.get().senv.package.conda_publish_url
                )
                if repository_url is None:
                    # todo add logic to publish to conda-forge
                    raise NotImplementedError(
                        "repository_url is required to publish a conda environment. "
                    )
                publish_conda(username, password, repository_url)
        else:
            raise NotImplementedError()
def test_lock_throws_if_not_all_platform_exists(temp_appdirs_pyproject,
                                                cli_runner,
                                                fake_combined_lock):
    with cd(temp_appdirs_pyproject.parent):
        fake_linux_lock_path = Path("my_lock_file_linux-64.lock")
        fake_linux_lock_path.write_text(fake_combined_lock.json(indent=2))
        result = cli_runner.invoke(
            app,
            [
                "package",
                "-f",
                str(temp_appdirs_pyproject),
                "lock",
                "--platforms",
                "osx-64",
                "--platforms",
                "win-64",
                "--platforms",
                "linux-64",
                "--based-on-tested-lock-file",
                str(fake_linux_lock_path.resolve()),
            ],
        )
        assert result.exit_code != 0
        assert isinstance(result.exception, SenvNotAllPlatformsInBaseLockFile)
        assert set(result.exception.missing_platforms) == {"osx-64", "win-64"}
def test_lock_based_on_tested_includes_pinned_dependencies(
        temp_appdirs_pyproject, cli_runner, appdirs_env_lock_path):
    with cd(temp_appdirs_pyproject.parent):
        click_line = next(
            l for l in appdirs_env_lock_path.read_text().splitlines()
            if "click" in l)

        result = cli_runner.invoke(
            app,
            [
                "package",
                "-f",
                str(temp_appdirs_pyproject),
                "lock",
                "--platforms",
                "linux-64",
                "--based-on-tested-lock-file",
                str(appdirs_env_lock_path.resolve()),
            ],
            catch_exceptions=False,
        )
        assert result.exit_code == 0
        assert PyProject.get().senv.package.conda_lock_path.exists()
        assert click_line in PyProject.get(
        ).senv.package.conda_lock_path.read_text()
Esempio n. 4
0
def sync(build_system: BuildSystem = typer.Option(get_default_env_build_system)
         ):
    c = PyProject.get()
    if build_system == BuildSystem.POETRY:
        with cd(c.config_path.parent):
            subprocess.check_call(
                [c.poetry_path, "install", "--remove-untracked"])
    elif build_system == BuildSystem.CONDA:
        if not c.env.conda_lock_path.exists():
            log.info("No lock file found, locking environment now")
            lock(build_system=build_system, platforms=get_conda_platforms())
        with c.env.platform_conda_lock as lock_file:
            result = subprocess.run([
                str(c.conda_path),
                "create",
                "--file",
                str(lock_file.resolve()),
                "--yes",
                "--name",
                c.env.name,
            ])
        if result.returncode != 0:
            raise typer.Abort("Failed syncing environment")
    else:
        raise NotImplementedError()
def test_build_simple_pyproject_with_conda_even_with_poetry_build_system_in_pyproject(
        temp_simple_pyproject, cli_runner):
    with cd(temp_simple_pyproject.parent):
        result = cli_runner.invoke(
            app,
            [
                "package",
                "-f",
                str(temp_simple_pyproject),
                "build",
            ],
            input="y",
            catch_exceptions=False,
        )
    assert result.exit_code == 0, result.exception
Esempio n. 6
0
def test_conda_build_dir_can_not_be_in_project(tmp_path):
    tmp_toml = tmp_path / "tmp_toml"
    config_dict = {
        "tool": {
            "senv": {
                "name": "senv3",
                "package": {
                    "conda-build-path": "./dist",
                },
            },
        }
    }
    tmp_toml.write_text(toml.dumps(config_dict))

    with cd(tmp_path), pytest.raises(SenvBadConfiguration):
        PyProject.read_toml(tmp_toml)
Esempio n. 7
0
def update(
    build_system: BuildSystem = typer.Option(get_default_env_build_system),
    platforms: List[str] = typer.Option(
        get_conda_platforms,
        case_sensitive=False,
        help="conda platforms, for example osx-64 or linux-64",
    ),
):
    if build_system == BuildSystem.POETRY:
        with cd(PyProject.get().config_path.parent):
            subprocess.check_call([PyProject.get().poetry_path, "update"])
    elif build_system == BuildSystem.CONDA:
        lock(build_system=build_system, platforms=platforms)
        sync(build_system=build_system)

    else:
        raise NotImplementedError()
def appdirs_env_lock_path(temp_appdirs_pyproject) -> Path:
    with cd(temp_appdirs_pyproject.parent):
        # env lock first to get the env locks that we will use to tests our code
        result = CliRunner().invoke(
            app,
            [
                "env",
                "-f",
                str(temp_appdirs_pyproject),
                "lock",
                "--platforms",
                "linux-64",
            ],
            catch_exceptions=False,
        )
        assert result.exit_code == 0
        yield PyProject.get().senv.env.conda_lock_path
Esempio n. 9
0
def run(
        ctx: typer.Context,
        build_system: BuildSystem = typer.Option(get_default_env_build_system),
):
    if build_system == BuildSystem.POETRY:
        with cd(PyProject.get().config_path.parent):
            subprocess.check_call(["poetry", "run"] + ctx.args)
    elif build_system == BuildSystem.CONDA:
        subprocess.check_call([
            "conda",
            "run",
            "-n",
            PyProject.get().env.name,
            "--no-capture-output",
            "--live-stream",
        ] + ctx.args)
    else:
        raise NotImplementedError()
Esempio n. 10
0
def test_lock_appdirs_simple_includes_metadata(temp_appdirs_pyproject,
                                               cli_runner):
    with cd(temp_appdirs_pyproject.parent):
        cli_runner.invoke(
            app,
            [
                "package",
                "-f",
                str(temp_appdirs_pyproject),
                "lock",
                "--platforms",
                "osx-64",
            ],
            catch_exceptions=False,
        )
        conda_lock = CombinedCondaLock.parse_file(
            PyProject.get().senv.package.conda_lock_path)
        assert conda_lock.metadata.package_name == "appdirs"
        assert conda_lock.metadata.entry_points == []
Esempio n. 11
0
def publish_locked_package(
    build_system: BuildSystem = typer.Option(get_default_package_build_system),
    repository_url: Optional[str] = None,
    username: str = typer.Option(
        ..., "--username", "-u", envvar="SENV_PUBLISHER_USERNAME"
    ),
    password: str = typer.Option(
        ..., "--password", "-p", envvar="SENV_PUBLISHER_PASSWORD"
    ),
    lock_file: Path = typer.Option(
        lambda: PyProject.get().senv.package.conda_lock_path,
        "--lock-file",
        "-l",
        exists=True,
    ),
    yes: bool = build_yes_option(),
):
    c: PyProject = PyProject.get()
    with auto_confirm_yes(yes):
        if build_system == BuildSystem.POETRY:
            raise NotImplementedError("publish locked ")
        elif build_system == BuildSystem.CONDA:
            with cd_tmp_dir() as tmp_dir:
                meta_path = tmp_dir / "conda.recipe" / "meta.yaml"
                temp_lock_path = meta_path.parent / "package_locked_file.lock.json"
                meta_path.parent.mkdir(parents=True)
                shutil.copyfile(
                    str(lock_file.absolute()), str(temp_lock_path.absolute())
                )

                locked_package_to_recipe_yaml(temp_lock_path, meta_path)
                build_conda_package_from_recipe(meta_path.absolute())

                with cd(meta_path.parent):
                    repository_url = repository_url or c.senv.package.conda_publish_url
                    publish_conda(
                        username,
                        password,
                        repository_url,
                        package_name=c.package_name_locked,
                    )
        else:
            raise NotImplementedError()
Esempio n. 12
0
def test_lock_appdirs_simple_does_not_include_fake_dependencies(
        temp_appdirs_pyproject, cli_runner):
    with cd(temp_appdirs_pyproject.parent):
        result = cli_runner.invoke(
            app,
            [
                "package",
                "-f",
                str(temp_appdirs_pyproject),
                "lock",
                "--platforms",
                "linux-64",
            ],
            catch_exceptions=False,
        )
        assert result.exit_code == 0
        assert PyProject.get().senv.package.conda_lock_path.exists()
        assert "click" not in PyProject.get(
        ).senv.package.conda_lock_path.read_text()
Esempio n. 13
0
def build_package(
    build_system: BuildSystem = typer.Option(get_default_package_build_system),
    python_version: Optional[str] = None,
):
    # todo add progress bar
    if build_system == BuildSystem.POETRY:
        with cd(PyProject.get().config_path.parent):
            subprocess.check_call([PyProject.get().poetry_path, "build"])
    elif build_system == BuildSystem.CONDA:
        with tmp_env():
            meta_path = (
                PyProject.get().config_path.parent / "conda.recipe" / "meta.yaml"
            )
            pyproject_to_recipe_yaml(
                python_version=python_version,
                output=meta_path,
            )
            build_conda_package_from_recipe(meta_path, python_version)
    else:
        raise NotImplementedError()
Esempio n. 14
0
def lock(
    build_system: BuildSystem = typer.Option(get_default_env_build_system),
    platforms: List[str] = typer.Option(
        get_conda_platforms,
        case_sensitive=False,
        help="conda platforms, for example osx-64 or linux-64",
    ),
):
    c = PyProject.get()
    if build_system == BuildSystem.POETRY:
        with cd(c.config_path.parent):
            subprocess.check_call([c.poetry_path, "lock"])
    elif build_system == BuildSystem.CONDA:
        c.env.conda_lock_path.parent.mkdir(exist_ok=True, parents=True)
        combined_lock = generate_combined_conda_lock_file(
            platforms,
            pyproject_to_conda_env_dict(),
        )
        c.env.conda_lock_path.write_text(combined_lock.json(indent=2))
    else:
        raise NotImplementedError()
Esempio n. 15
0
def test_env_locks_builds_the_lock_files_in_default_env_lock_files(
    temp_pyproject, cli_runner
):
    with cd(temp_pyproject.parent):
        result = cli_runner.invoke(
            app,
            [
                "env",
                "-f",
                str(temp_pyproject),
                "lock",
                "--platforms",
                "linux-64",
            ],
            catch_exceptions=False,
        )
        assert result.exit_code == 0
        lock_file = PyProject.get().senv.env.__fields__["conda_lock_path"].default
        assert lock_file.exists()

        combined_lock = CombinedCondaLock.parse_file(lock_file)
        assert set(combined_lock.platform_tar_links.keys()) == {"linux-64"}
Esempio n. 16
0
def shell(build_system: BuildSystem = typer.Option(
    get_default_env_build_system)):
    c = PyProject.get()
    # conda activate does not work using the conda executable path (I am not sure why)
    # force adding the conda executable to the path and then call it
    environ[
        "PATH"] = f"{c.conda_path.parent}{os.path.pathsep}{environ.get('PATH')}"
    if build_system == BuildSystem.POETRY:
        cwd = os.getcwd()
        with cd(c.config_path.parent):
            with spawn_shell(command="poetry shell", cwd=cwd):
                pass

    elif build_system == BuildSystem.CONDA:
        with spawn_shell(
                command=
                f"{shlex.quote(str(c.conda_path.name))} activate {c.env.name}",
        ):
            pass
    else:
        raise NotImplementedError()
    environ["PATH"] = os.path.pathsep.join(
        environ.get("PATH").split(os.path.pathsep)[1:])
Esempio n. 17
0
def test_publish_requires_username_and_password(temp_small_conda_pyproject,
                                                cli_runner):
    args = [
        "package",
        "-f",
        str(temp_small_conda_pyproject),
        "publish",
    ]
    with cd(temp_small_conda_pyproject.parent):
        result = cli_runner.invoke(
            app,
            args,
        )
        assert result.exit_code == 2, result.output
        result = cli_runner.invoke(
            app,
            args + ["-u", "username"],
        )
        assert result.exit_code == 2, result.output
        result = cli_runner.invoke(
            app,
            args + ["-p", "password"],
        )
        assert result.exit_code == 2, result.output