def pip_install( path: Union[Path, str], environment: Env, editable: bool = False, deps: bool = False, upgrade: bool = False, ) -> Union[int, str]: path = Path(path) if isinstance(path, str) else path args = ["install", "--prefix", str(environment.path)] if upgrade: args.append("--upgrade") if not deps: args.append("--no-deps") if editable: if not path.is_dir(): raise PoetryException( "Cannot install non directory dependencies in editable mode") args.append("-e") args.append(str(path)) if path.is_file() and path.suffix == ".whl": return environment.run_pip(*args) with ephemeral_environment(executable=environment.python, pip=True, setuptools=True) as env: return env.run( "pip", *args, )
def test_builder_setup_generation_runs_with_pip_editable(tmp_dir: str): # create an isolated copy of the project fixture = Path( __file__).parent.parent.parent / "fixtures" / "extended_project" extended_project = Path(tmp_dir) / "extended_project" shutil.copytree(fixture, extended_project) assert extended_project.exists() poetry = Factory().create_poetry(extended_project) # we need a venv with setuptools since we are verifying setup.py builds with ephemeral_environment(flags={"no-setuptools": False}) as venv: builder = EditableBuilder(poetry, venv, NullIO()) builder.build() # is the package installed? repository = InstalledRepository.load(venv) assert repository.package("extended-project", "1.2.3") # check for the module built by build.py try: output = venv.run_python_script( "from extended_project import built; print(built.__file__)" ).strip() except EnvCommandError: pytest.fail("Unable to import built module") else: built_py = Path(output).resolve() expected = extended_project / "extended_project" / "built.py" # ensure the package was installed as editable assert built_py == expected.resolve()
def pip_install( path: Union["Path", Link], environment: "Env", editable: bool = False, deps: bool = False, upgrade: bool = False, ) -> Union[int, str]: path = url_to_path(path.url) if isinstance(path, Link) else path is_wheel = path.suffix == ".whl" # We disable version check here as we are already pinning to version available in # either the virtual environment or the virtualenv package embedded wheel. Version # checks are a wasteful network call that adds a lot of wait time when installing a # lot of packages. args = [ "install", "--disable-pip-version-check", "--prefix", str(environment.path) ] if not is_wheel: args.insert(1, "--use-pep517") if upgrade: args.append("--upgrade") if not deps: args.append("--no-deps") if editable: if not path.is_dir(): raise PoetryException( "Cannot install non directory dependencies in editable mode") args.append("-e") args.append(str(path)) try: return environment.run_pip(*args) except EnvCommandError as e: if sys.version_info < (3, 7) and not is_wheel: # Under certain Python3.6 installs vendored pip wheel does not contain # zip-safe pep517 lib. In this cases we create an isolated ephemeral virtual # environment. with ephemeral_environment(executable=environment.python, with_pip=True, with_setuptools=True) as env: return environment.run( *env.get_pip_command(), *args, env={ **os.environ, "PYTHONPATH": str(env.purelib) }, ) raise PoetryException(f"Failed to install {path.as_posix()}") from e
def pip_install( path: Union[Path, str], environment: Env, editable: bool = False, deps: bool = False, upgrade: bool = False, ) -> Union[int, str]: path = Path(path) if isinstance(path, str) else path is_wheel = path.suffix == ".whl" args = ["install", "--prefix", str(environment.path)] if not is_wheel: args.insert(1, "--use-pep517") if upgrade: args.append("--upgrade") if not deps: args.append("--no-deps") if editable: if not path.is_dir(): raise PoetryException( "Cannot install non directory dependencies in editable mode") args.append("-e") args.append(str(path)) try: return environment.run_pip(*args) except EnvCommandError as e: if sys.version_info < (3, 7) and not is_wheel: # Under certain Python3.6 installs vendored pip wheel does not contain zip-safe # pep517 lib. In this cases we create an isolated ephemeral virtual environment. with ephemeral_environment(executable=environment.python, pip=True, setuptools=True) as env: return environment.run( env._bin("pip"), *args, env={ **os.environ, "PYTHONPATH": str(env.purelib) }, ) raise PoetryException(f"Failed to install {path.as_posix()}") from e
def get_pep517_metadata(path: Path) -> PackageInfo: """ Helper method to use PEP-517 library to build and read package metadata. :param path: Path to package source to build and read metadata for. """ info = None try: info = PackageInfo.from_setup_files(path) if all([info.version, info.name, info.requires_dist]): return info except PackageInfoError: pass with ephemeral_environment(flags={ "no-pip": False, "no-setuptools": False, "no-wheel": False }) as venv: # TODO: cache PEP 517 build environment corresponding to each project venv dest_dir = venv.path.parent / "dist" dest_dir.mkdir() pep517_meta_build_script = PEP517_META_BUILD.format( source=path.as_posix(), dest=dest_dir.as_posix()) try: venv.run_pip( "install", "--disable-pip-version-check", "--ignore-installed", *PEP517_META_BUILD_DEPS, ) venv.run( "python", "-", input_=pep517_meta_build_script, ) info = PackageInfo.from_metadata(dest_dir) except EnvCommandError as e: # something went wrong while attempting pep517 metadata build # fallback to egg_info if setup.py available logger.debug("PEP517 build failed: %s", e) setup_py = path / "setup.py" if not setup_py.exists(): raise PackageInfoError( path, e, "No fallback setup.py file was found to generate egg_info.", ) cwd = Path.cwd() os.chdir(path.as_posix()) try: venv.run("python", "setup.py", "egg_info") info = PackageInfo.from_metadata(path) except EnvCommandError as fbe: raise PackageInfoError(path, "Fallback egg_info generation failed.", fbe) finally: os.chdir(cwd.as_posix()) if info: logger.debug("Falling back to parsed setup.py file for %s", path) return info # if we reach here, everything has failed and all hope is lost raise PackageInfoError(path, "Exhausted all core metadata sources.")