Skip to content

Commit

Permalink
info: cache get metadata from pep517
Browse files Browse the repository at this point in the history
  • Loading branch information
abn authored and neersighted committed May 13, 2022
1 parent 4423fd6 commit 141d9eb
Show file tree
Hide file tree
Showing 3 changed files with 77 additions and 76 deletions.
144 changes: 73 additions & 71 deletions src/poetry/inspection/info.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from __future__ import annotations

import functools
import glob
import logging
import os
Expand Down Expand Up @@ -449,76 +450,6 @@ def _get_poetry_package(path: Path) -> ProjectPackage | None:
return Factory().create_poetry(path).package
return None

@classmethod
def _pep517_metadata(cls, 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 = cls.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,
)
return cls.from_metadata(dest_dir)
except EnvCommandError as e:
# something went wrong while attempting pep517 metadata build
# fallback to egg_info if setup.py available
cls._log(f"PEP517 build failed: {e}", level="debug")
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")
return cls.from_metadata(path)
except EnvCommandError as fbe:
raise PackageInfoError(
path, "Fallback egg_info generation failed.", fbe
)
finally:
os.chdir(cwd.as_posix())

if info:
cls._log(f"Falling back to parsed setup.py file for {path}", "debug")
return info

# if we reach here, everything has failed and all hope is lost
raise PackageInfoError(path, "Exhausted all core metadata sources.")

@classmethod
def from_directory(cls, path: Path, disable_build: bool = False) -> PackageInfo:
"""
Expand All @@ -542,7 +473,7 @@ def from_directory(cls, path: Path, disable_build: bool = False) -> PackageInfo:
if disable_build:
info = cls.from_setup_files(path)
else:
info = cls._pep517_metadata(path)
info = get_pep517_metadata(path)
except PackageInfoError:
if not info:
raise
Expand Down Expand Up @@ -609,3 +540,74 @@ def from_path(cls, path: Path) -> PackageInfo:
return cls.from_bdist(path=path)
except PackageInfoError:
return cls.from_sdist(path=path)


@functools.lru_cache(maxsize=None)
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.")
7 changes: 3 additions & 4 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -233,15 +233,14 @@ def download_mock(mocker: MockerFixture) -> None:

@pytest.fixture(autouse=True)
def pep517_metadata_mock(mocker: MockerFixture) -> None:
@classmethod
def _pep517_metadata(cls: PackageInfo, path: Path) -> PackageInfo:
def get_pep517_metadata(path: Path) -> PackageInfo:
with suppress(PackageInfoError):
return PackageInfo.from_setup_files(path)
return PackageInfo(name="demo", version="0.1.2")

mocker.patch(
"poetry.inspection.info.PackageInfo._pep517_metadata",
_pep517_metadata,
"poetry.inspection.info.get_pep517_metadata",
get_pep517_metadata,
)


Expand Down
2 changes: 1 addition & 1 deletion tests/puzzle/test_provider.py
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ def test_search_for_vcs_read_setup_raises_error_if_no_version(
provider: Provider, mocker: MockerFixture
):
mocker.patch(
"poetry.inspection.info.PackageInfo._pep517_metadata",
"poetry.inspection.info.get_pep517_metadata",
return_value=PackageInfo(name="demo", version=None),
)

Expand Down

0 comments on commit 141d9eb

Please sign in to comment.