Beispiel #1
0
    def build(self):
        # We start by building the tarball
        # We will use it to build the wheel
        sdist_builder = SdistBuilder(self._poetry)
        build_for_all_formats = False
        for p in self._package.packages:
            formats = p.get("format", [])
            if not isinstance(formats, list):
                formats = [formats]

            if formats and sdist_builder.format not in formats:
                build_for_all_formats = True
                break

        sdist_file = sdist_builder.build()

        dist_dir = self._path / "dist"

        if build_for_all_formats:
            sdist_builder = SdistBuilder(self._poetry, ignore_packages_formats=True)
            with temporary_directory() as tmp_dir:
                sdist_file = sdist_builder.build(Path(tmp_dir))

                with self.unpacked_tarball(sdist_file) as tmpdir:
                    WheelBuilder.make_in(
                        Factory().create_poetry(tmpdir), dist_dir, original=self._poetry
                    )
        else:
            with self.unpacked_tarball(sdist_file) as tmpdir:
                WheelBuilder.make_in(
                    Factory().create_poetry(tmpdir), dist_dir, original=self._poetry
                )
Beispiel #2
0
    def _pep517_metadata(cls, path):  # type (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 info.requires_dist is not None:
                return info
        except PackageInfoError:
            pass

        with temporary_directory() as tmp_dir:
            # TODO: cache PEP 517 build environment corresponding to each project venv
            venv_dir = Path(tmp_dir) / ".venv"
            EnvManager.build_venv(venv_dir.as_posix())
            venv = VirtualEnv(venv_dir, venv_dir)

            dest_dir = Path(tmp_dir) / "dist"
            dest_dir.mkdir()

            try:
                venv.run("python", "-m", "pip", "install",
                         "--disable-pip-version-check", "--ignore-installed",
                         *PEP517_META_BUILD_DEPS)
                venv.run(
                    "python",
                    "-",
                    input_=PEP517_META_BUILD.format(source=path.as_posix(),
                                                    dest=dest_dir.as_posix()),
                )
                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("PEP517 build failed: {}".format(e), level="debug")
                setup_py = path / "setup.py"
                if not setup_py.exists():
                    raise PackageInfoError(path)

                cwd = Path.cwd()
                os.chdir(path.as_posix())
                try:
                    venv.run("python", "setup.py", "egg_info")
                    return cls.from_metadata(path)
                except EnvCommandError:
                    raise PackageInfoError(path)
                finally:
                    os.chdir(cwd.as_posix())

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

        # if we reach here, everything has failed and all hope is lost
        raise PackageInfoError(path)
Beispiel #3
0
    def _from_sdist_file(cls, path):  # type: (Path) -> PackageInfo
        """
        Helper method to parse package information from an sdist file. We attempt to first inspect the
        file using `pkginfo.SDist`. If this does not provide us with package requirements, we extract the
        source and handle it as a directory.

        :param path: The sdist file to parse information from.
        """
        info = None

        try:
            info = cls._from_distribution(pkginfo.SDist(str(path)))
        except ValueError:
            # Unable to determine dependencies
            # We pass and go deeper
            pass
        else:
            if info.requires_dist is not None:
                # we successfully retrieved dependencies from sdist metadata
                return info

        # Still not dependencies found
        # So, we unpack and introspect
        suffix = path.suffix

        if suffix == ".zip":
            context = zipfile.ZipFile
        else:
            if suffix == ".bz2":
                suffixes = path.suffixes
                if len(suffixes) > 1 and suffixes[-2] == ".tar":
                    suffix = ".tar.bz2"
            else:
                suffix = ".tar.gz"

            context = tarfile.open

        with temporary_directory() as tmp:
            tmp = Path(tmp)
            with context(path.as_posix()) as archive:
                archive.extractall(tmp.as_posix())

            # a little bit of guess work to determine the directory we care about
            elements = list(tmp.glob("*"))

            if len(elements) == 1 and elements[0].is_dir():
                sdist_dir = elements[0]
            else:
                sdist_dir = tmp / path.name.rstrip(suffix)
                if not sdist_dir.is_dir():
                    sdist_dir = tmp

            # now this is an unpacked directory we know how to deal with
            new_info = cls.from_directory(path=sdist_dir)

        if not info:
            return new_info

        return info.update(new_info)
Beispiel #4
0
def test_build_sdist():
    with temporary_directory() as tmp_dir, cwd(os.path.join(fixtures, "complete")):
        filename = api.build_sdist(tmp_dir)

        with tarfile.open(str(os.path.join(tmp_dir, filename))) as tar:
            namelist = tar.getnames()

            assert "my-package-1.2.3/LICENSE" in namelist
Beispiel #5
0
def test_build_wheel_extended():
    with temporary_directory() as tmp_dir, cwd(
            os.path.join(fixtures, "extended")):
        filename = api.build_wheel(tmp_dir)
        whl = Path(tmp_dir) / filename
        assert whl.exists()
        validate_wheel_contents(name="extended",
                                version="0.1",
                                path=whl.as_posix())
Beispiel #6
0
def test_build_wheel_with_include():
    with temporary_directory() as tmp_dir, cwd(os.path.join(fixtures, "with-include")):
        filename = api.build_wheel(tmp_dir)
        validate_wheel_contents(
            name="with_include",
            version="1.2.3",
            path=str(os.path.join(tmp_dir, filename)),
            files=["entry_points.txt"],
        )
Beispiel #7
0
def test_build_sdist():
    with temporary_directory() as tmp_dir, cwd(os.path.join(fixtures, "complete")):
        filename = api.build_sdist(tmp_dir)
        validate_sdist_contents(
            name="my-package",
            version="1.2.3",
            path=str(os.path.join(tmp_dir, filename)),
            files=["LICENSE"],
        )
Beispiel #8
0
def test_utils_helpers_temporary_directory_readonly_file():
    with temporary_directory() as temp_dir:
        readonly_filename = os.path.join(temp_dir, "file.txt")
        with open(readonly_filename, "w+") as readonly_file:
            readonly_file.write("Poetry rocks!")
        os.chmod(str(readonly_filename), S_IREAD)

    assert not os.path.exists(temp_dir)
    assert not os.path.exists(readonly_filename)
Beispiel #9
0
def test_build_sdist_with_include() -> None:
    with temporary_directory() as tmp_dir, cwd(
            os.path.join(fixtures, "with-include")):
        filename = api.build_sdist(tmp_dir)
        validate_sdist_contents(
            name="with-include",
            version="1.2.3",
            path=str(os.path.join(tmp_dir, filename)),
            files=["LICENSE"],
        )
Beispiel #10
0
def test_build_wheel() -> None:
    with temporary_directory() as tmp_dir, cwd(
            os.path.join(fixtures, "complete")):
        filename = api.build_wheel(tmp_dir)
        validate_wheel_contents(
            name="my_package",
            version="1.2.3",
            path=str(os.path.join(tmp_dir, filename)),
            files=["entry_points.txt"],
        )
Beispiel #11
0
def test_build_wheel():
    with temporary_directory() as tmp_dir, cwd(os.path.join(fixtures, "complete")):
        filename = api.build_wheel(tmp_dir)

        with zipfile.ZipFile(str(os.path.join(tmp_dir, filename))) as zip:
            namelist = zip.namelist()

            assert "my_package-1.2.3.dist-info/entry_points.txt" in namelist
            assert "my_package-1.2.3.dist-info/WHEEL" in namelist
            assert "my_package-1.2.3.dist-info/METADATA" in namelist
Beispiel #12
0
    def _links_to_data(self, links: list[Link],
                       data: PackageInfo) -> dict[str, Any]:
        if not links:
            raise PackageNotFound(
                f'No valid distribution links found for package: "{data.name}" version:'
                f' "{data.version}"')
        urls = defaultdict(list)
        files: list[dict[str, Any]] = []
        for link in links:
            if link.is_wheel:
                urls["bdist_wheel"].append(link.url)
            elif link.filename.endswith(
                (".tar.gz", ".zip", ".bz2", ".xz", ".Z", ".tar")):
                urls["sdist"].append(link.url)

            file_hash = f"{link.hash_name}:{link.hash}" if link.hash else None

            if not link.hash or (link.hash_name is not None and link.hash_name
                                 not in ("sha256", "sha384", "sha512")
                                 and hasattr(hashlib, link.hash_name)):
                with temporary_directory() as temp_dir:
                    filepath = Path(temp_dir) / link.filename
                    self._download(link.url, str(filepath))

                    known_hash = (getattr(hashlib, link.hash_name)()
                                  if link.hash_name else None)
                    required_hash = hashlib.sha256()

                    chunksize = 4096
                    with filepath.open("rb") as f:
                        while True:
                            chunk = f.read(chunksize)
                            if not chunk:
                                break
                            if known_hash:
                                known_hash.update(chunk)
                            required_hash.update(chunk)

                    if not known_hash or known_hash.hexdigest() == link.hash:
                        file_hash = f"{required_hash.name}:{required_hash.hexdigest()}"

            files.append({"file": link.filename, "hash": file_hash})

        data.files = files

        info = self._get_info_from_urls(urls)

        data.summary = info.summary
        data.requires_dist = info.requires_dist
        data.requires_python = info.requires_python

        return data.asdict()
Beispiel #13
0
    def _get_info_from_wheel(self, url: str) -> PackageInfo:
        from poetry.inspection.info import PackageInfo

        wheel_name = urllib.parse.urlparse(url).path.rsplit("/")[-1]
        self._log(f"Downloading wheel: {wheel_name}", level="debug")

        filename = os.path.basename(wheel_name)

        with temporary_directory() as temp_dir:
            filepath = Path(temp_dir) / filename
            self._download(url, str(filepath))

            return PackageInfo.from_wheel(filepath)
Beispiel #14
0
def test_build_wheel_extended():
    with temporary_directory() as tmp_dir, cwd(
            os.path.join(fixtures, "extended")):
        filename = api.build_wheel(tmp_dir)

        whl = Path(tmp_dir) / filename
        assert whl.exists()

        with zipfile.ZipFile(str(os.path.join(tmp_dir, filename))) as zip:
            namelist = zip.namelist()

            assert "extended-0.1.dist-info/RECORD" in namelist
            assert "extended-0.1.dist-info/WHEEL" in namelist
            assert "extended-0.1.dist-info/METADATA" in namelist
Beispiel #15
0
def test_build_editable_wheel():
    pkg_dir = Path(fixtures) / "complete"

    with temporary_directory() as tmp_dir, cwd(pkg_dir):
        filename = api.build_editable(tmp_dir)
        wheel_pth = Path(tmp_dir) / filename

        validate_wheel_contents(
            name="my_package",
            version="1.2.3",
            path=str(wheel_pth),
        )

        with zipfile.ZipFile(wheel_pth) as z:
            namelist = z.namelist()

            assert "my_package.pth" in namelist
            assert pkg_dir.as_posix() == z.read(
                "my_package.pth").decode().strip()
Beispiel #16
0
def test_prepare_metadata_for_build_wheel_with_bad_path_dep_succeeds():
    with pytest.raises(
            ValueError) as err, temporary_directory() as tmp_dir, cwd(
                os.path.join(fixtures, "with_bad_path_dep")):
        api.prepare_metadata_for_build_wheel(tmp_dir)
    assert "does not exist" in str(err.value)
Beispiel #17
0
def test_prepare_metadata_for_build_wheel():
    entry_points = """\
[console_scripts]
extra-script=my_package.extra:main[time]
my-2nd-script=my_package:main2
my-script=my_package:main

"""
    wheel_data = """\
Wheel-Version: 1.0
Generator: poetry {}
Root-Is-Purelib: true
Tag: py3-none-any
""".format(__version__)
    metadata = """\
Metadata-Version: 2.1
Name: my-package
Version: 1.2.3
Summary: Some description.
Home-page: https://python-poetry.org/
License: MIT
Keywords: packaging,dependency,poetry
Author: Sébastien Eustace
Author-email: [email protected]
Maintainer: People Everywhere
Maintainer-email: [email protected]
Requires-Python: >=3.6,<4.0
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.6
Classifier: Programming Language :: Python :: 3.7
Classifier: Programming Language :: Python :: 3.8
Classifier: Programming Language :: Python :: 3.9
Classifier: Topic :: Software Development :: Build Tools
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Provides-Extra: time
Requires-Dist: cachy[msgpack] (>=0.2.0,<0.3.0)
Requires-Dist: cleo (>=0.6,<0.7)
Requires-Dist: pendulum (>=1.4,<2.0); (python_version ~= "2.7" and sys_platform == "win32" or python_version in "3.4 3.5") and (extra == "time")
Project-URL: Documentation, https://python-poetry.org/docs
Project-URL: Issue Tracker, https://github.com/python-poetry/poetry/issues
Project-URL: Repository, https://github.com/python-poetry/poetry
Description-Content-Type: text/x-rst

My Package
==========

"""
    with temporary_directory() as tmp_dir, cwd(
            os.path.join(fixtures, "complete")):
        dirname = api.prepare_metadata_for_build_wheel(tmp_dir)

        assert "my_package-1.2.3.dist-info" == dirname

        dist_info = Path(tmp_dir, dirname)

        assert (dist_info / "entry_points.txt").exists()
        assert (dist_info / "WHEEL").exists()
        assert (dist_info / "METADATA").exists()

        with (dist_info / "entry_points.txt").open(encoding="utf-8") as f:
            assert entry_points == decode(f.read())

        with (dist_info / "WHEEL").open(encoding="utf-8") as f:
            assert wheel_data == decode(f.read())

        with (dist_info / "METADATA").open(encoding="utf-8") as f:
            assert metadata == decode(f.read())
Beispiel #18
0
def test_prepare_metadata_for_build_wheel_with_bad_path_dev_dep_succeeds(
) -> None:
    with temporary_directory() as tmp_dir, cwd(
            os.path.join(fixtures, "with_bad_path_dev_dep")):
        api.prepare_metadata_for_build_wheel(tmp_dir)
Beispiel #19
0
def test_build_wheel_with_bad_path_dep_fails():
    with pytest.raises(
            ValueError) as err, temporary_directory() as tmp_dir, cwd(
                os.path.join(fixtures, "with_bad_path_dep")):
        api.build_wheel(tmp_dir)
    assert "does not exist" in str(err.value)
Beispiel #20
0
def test_build_wheel_with_bad_path_dev_dep_succeeds():
    with temporary_directory() as tmp_dir, cwd(
            os.path.join(fixtures, "with_bad_path_dev_dep")):
        api.build_wheel(tmp_dir)