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)
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)
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())
def test_file_dependency_pep_508_local_file_relative_path(mocker): path = Path("..") / "fixtures" / "distributions" / "demo-0.2.0.tar.gz" with pytest.raises(ValueError): requirement = "{} @ file://{}".format("demo", path.as_posix()) _test_file_dependency_pep_508(mocker, "demo", path, requirement) requirement = "{} @ {}".format("demo", path) _test_file_dependency_pep_508(mocker, "demo", path, requirement)
def test_to_dependency_for_directory(): path = Path(__file__).parent.parent.joinpath("fixtures/simple_project") package = Package( "foo", "1.2.3", source_type="directory", source_url=path.as_posix(), features=["baz", "bar"], ) dep = package.to_dependency() assert "foo" == dep.name assert package.version == dep.constraint assert frozenset({"bar", "baz"}) == dep.features assert dep.is_directory() assert path == dep.path assert "directory" == dep.source_type assert path.as_posix() == dep.source_url
def test_to_dependency_for_file(): path = Path(__file__).parent.parent.joinpath( "fixtures/distributions/demo-0.1.0.tar.gz") package = Package( "foo", "1.2.3", source_type="file", source_url=path.as_posix(), features=["baz", "bar"], ) dep = package.to_dependency() assert "foo" == dep.name assert package.version == dep.constraint assert frozenset({"bar", "baz"}) == dep.features assert dep.is_file() assert path == dep.path assert "file" == dep.source_type assert path.as_posix() == dep.source_url
def test_directory_dependency_pep_508_local_relative(): path = Path( "..") / "fixtures" / "project_with_multi_constraints_dependency" with pytest.raises(ValueError): requirement = "{} @ file://{}".format("demo", path.as_posix()) _test_directory_dependency_pep_508("demo", path, requirement) requirement = "{} @ {}".format("demo", path) _test_directory_dependency_pep_508("demo", path, requirement)
def is_excluded(self, filepath): # type: (Union[str, Path]) -> bool exclude_path = Path(filepath) while True: if exclude_path.as_posix() in self.find_excluded_files(): return True if len(exclude_path.parts) > 1: exclude_path = exclude_path.parent else: break return False
def test_complete_no_vcs(): # Copy the complete fixtures dir to a temporary directory module_path = fixtures_dir / "complete" temporary_dir = Path(tempfile.mkdtemp()) / "complete" shutil.copytree(module_path.as_posix(), temporary_dir.as_posix()) builder = Builder(Factory().create_poetry(temporary_dir)) builder.build(fmt="all") whl = temporary_dir / "dist" / "my_package-1.2.3-py3-none-any.whl" assert whl.exists() zip = zipfile.ZipFile(str(whl)) # Check the zipped file to be sure that included and excluded files are # correctly taken account of without vcs expected_name_list = [ "my_package/__init__.py", "my_package/data1/test.json", "my_package/sub_pkg1/__init__.py", "my_package/sub_pkg2/__init__.py", "my_package/sub_pkg2/data2/data.json", "my_package/sub_pkg3/foo.py", "my_package-1.2.3.dist-info/entry_points.txt", "my_package-1.2.3.dist-info/LICENSE", "my_package-1.2.3.dist-info/WHEEL", "my_package-1.2.3.dist-info/METADATA", "my_package-1.2.3.dist-info/RECORD", ] assert sorted(zip.namelist()) == sorted(expected_name_list) try: entry_points = zip.read("my_package-1.2.3.dist-info/entry_points.txt") assert (decode(entry_points.decode()) == """\ [console_scripts] extra-script=my_package.extra:main[time] my-2nd-script=my_package:main2 my-script=my_package:main """) wheel_data = decode(zip.read("my_package-1.2.3.dist-info/WHEEL")) assert (wheel_data == """\ Wheel-Version: 1.0 Generator: poetry {} Root-Is-Purelib: true Tag: py3-none-any """.format(__version__)) wheel_data = decode(zip.read("my_package-1.2.3.dist-info/METADATA")) assert (wheel_data == """\ 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.10 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 ========== """) finally: zip.close()
def __init__(self, path): # type: (Union[str, Path]) -> None if isinstance(path, str): path = Path(path) super(TOMLFile, self).__init__(path.as_posix()) self.__path = path