Beispiel #1
0
    def build(self, target_dir=None):  # type: (Path) -> Path
        self._io.writeln(' - Building <info>sdist</info>')
        if target_dir is None:
            target_dir = self._path / 'dist'

        if not target_dir.exists():
            target_dir.mkdir(parents=True)

        target = target_dir / '{}-{}.tar.gz'.format(
            self._package.pretty_name, self._package.version
        )
        gz = GzipFile(target.as_posix(), mode='wb')
        tar = tarfile.TarFile(target.as_posix(), mode='w', fileobj=gz,
                              format=tarfile.PAX_FORMAT)

        try:
            tar_dir = '{}-{}'.format(
                self._package.pretty_name, self._package.version
            )

            files_to_add = self.find_files_to_add(exclude_build=False)

            for relpath in files_to_add:
                path = self._path / relpath
                tar_info = tar.gettarinfo(
                    str(path),
                    arcname=pjoin(tar_dir, str(relpath))
                )
                tar_info = self.clean_tarinfo(tar_info)

                if tar_info.isreg():
                    with path.open('rb') as f:
                        tar.addfile(tar_info, f)
                else:
                    tar.addfile(tar_info)  # Symlinks & ?

            setup = self.build_setup()
            tar_info = tarfile.TarInfo(pjoin(tar_dir, 'setup.py'))
            tar_info.size = len(setup)
            tar.addfile(tar_info, BytesIO(setup))

            pkg_info = encode(PKG_INFO.format(
                name=self._meta.name,
                version=self._meta.version,
                summary=self._meta.summary,
                home_page=self._meta.home_page,
                author=to_str(self._meta.author),
                author_email=to_str(self._meta.author_email),
            ))

            tar_info = tarfile.TarInfo(pjoin(tar_dir, 'PKG-INFO'))
            tar_info.size = len(pkg_info)
            tar.addfile(tar_info, BytesIO(pkg_info))
        finally:
            tar.close()
            gz.close()

        self._io.writeln(' - Built <fg=cyan>{}</>'.format(target.name))

        return target
Beispiel #2
0
    def build_pkg_info(self):
        pkg_info = PKG_INFO.format(
            name=self._meta.name,
            version=self._meta.version,
            summary=self._meta.summary,
            home_page=self._meta.home_page,
            author=to_str(self._meta.author),
            author_email=to_str(self._meta.author_email),
        )

        if self._meta.keywords:
            pkg_info += "Keywords: {}\n".format(self._meta.keywords)

        if self._meta.requires_python:
            pkg_info += "Requires-Python: {}\n".format(self._meta.requires_python)

        for classifier in self._meta.classifiers:
            pkg_info += "Classifier: {}\n".format(classifier)

        for extra in sorted(self._meta.provides_extra):
            pkg_info += "Provides-Extra: {}\n".format(extra)

        for dep in sorted(self._meta.requires_dist):
            pkg_info += "Requires-Dist: {}\n".format(dep)

        return encode(pkg_info)
Beispiel #3
0
    def convert_dependencies(
        cls,
        package,  # type: Package
        dependencies,  # type: List[Dependency]
    ):
        main = []
        extras = defaultdict(list)
        req_regex = re.compile(r"^(.+) \((.+)\)$")

        for dependency in dependencies:
            if dependency.is_optional():
                for extra_name, reqs in package.extras.items():
                    for req in reqs:
                        if req.name == dependency.name:
                            requirement = to_str(
                                dependency.to_pep_508(with_extras=False)
                            )
                            if ";" in requirement:
                                requirement, conditions = requirement.split(";")

                                requirement = requirement.strip()
                                if req_regex.match(requirement):
                                    requirement = req_regex.sub(
                                        "\\1\\2", requirement.strip()
                                    )

                                extras[extra_name + ":" + conditions.strip()].append(
                                    requirement
                                )

                                continue

                            requirement = requirement.strip()
                            if req_regex.match(requirement):
                                requirement = req_regex.sub(
                                    "\\1\\2", requirement.strip()
                                )
                            extras[extra_name].append(requirement)
                continue

            requirement = to_str(dependency.to_pep_508())
            if ";" in requirement:
                requirement, conditions = requirement.split(";")

                requirement = requirement.strip()
                if req_regex.match(requirement):
                    requirement = req_regex.sub("\\1\\2", requirement.strip())

                extras[":" + conditions.strip()].append(requirement)

                continue

            requirement = requirement.strip()
            if req_regex.match(requirement):
                requirement = req_regex.sub("\\1\\2", requirement.strip())

            main.append(requirement)

        return main, dict(extras)
Beispiel #4
0
    def convert_dependencies(
        cls, package, dependencies  # type: Package  # type: List[Dependency]
    ):
        main = []
        extras = defaultdict(list)
        req_regex = re.compile("^(.+) \((.+)\)$")

        for dependency in dependencies:
            if dependency.is_optional():
                for extra_name, reqs in package.extras.items():
                    for req in reqs:
                        if req.name == dependency.name:
                            requirement = to_str(
                                dependency.to_pep_508(with_extras=False)
                            )
                            if ";" in requirement:
                                requirement, conditions = requirement.split(";")

                                requirement = requirement.strip()
                                if req_regex.match(requirement):
                                    requirement = req_regex.sub(
                                        "\\1\\2", requirement.strip()
                                    )

                                extras[extra_name + ":" + conditions.strip()].append(
                                    requirement
                                )

                                continue

                            requirement = requirement.strip()
                            if req_regex.match(requirement):
                                requirement = req_regex.sub(
                                    "\\1\\2", requirement.strip()
                                )
                            extras[extra_name].append(requirement)
                continue

            requirement = to_str(dependency.to_pep_508())
            if ";" in requirement:
                requirement, conditions = requirement.split(";")

                requirement = requirement.strip()
                if req_regex.match(requirement):
                    requirement = req_regex.sub("\\1\\2", requirement.strip())

                extras[":" + conditions.strip()].append(requirement)

                continue

            requirement = requirement.strip()
            if req_regex.match(requirement):
                requirement = req_regex.sub("\\1\\2", requirement.strip())

            main.append(requirement)

        return main, dict(extras)
Beispiel #5
0
    def build_setup(self):  # type: () -> bytes
        before, extra, after = [], [], []

        # If we have a build script, use it
        if self._package.build:
            after += [
                "from {} import *".format(self._package.build.split(".")[0]),
                "build(setup_kwargs)",
            ]

        if self._module.is_in_src():
            before.append("package_dir = \\\n{}\n".format(pformat({"": "src"})))
            extra.append("'package_dir': package_dir,")

        if self._module.is_package():
            packages, package_data = self.find_packages(self._module.path.as_posix())
            before.append("packages = \\\n{}\n".format(pformat(sorted(packages))))
            before.append("package_data = \\\n{}\n".format(pformat(package_data)))
            extra.append("'packages': packages,")
            extra.append("'package_data': package_data,")
        else:
            extra.append("'py_modules': {!r},".format(to_str(self._module.name)))

        dependencies, extras = self.convert_dependencies(
            self._package, self._package.requires
        )
        if dependencies:
            before.append(
                "install_requires = \\\n{}\n".format(pformat(sorted(dependencies)))
            )
            extra.append("'install_requires': install_requires,")

        if extras:
            before.append("extras_require = \\\n{}\n".format(pformat(extras)))
            extra.append("'extras_require': extras_require,")

        entry_points = self.convert_entry_points()
        if entry_points:
            before.append("entry_points = \\\n{}\n".format(pformat(entry_points)))
            extra.append("'entry_points': entry_points,")

        if self._package.python_versions != "*":
            python_requires = self._meta.requires_python

            extra.append("'python_requires': {!r},".format(python_requires))

        return encode(
            SETUP.format(
                before="\n".join(before),
                name=to_str(self._meta.name),
                version=to_str(self._meta.version),
                description=to_str(self._meta.summary),
                long_description=to_str(self._meta.description),
                author=to_str(self._meta.author),
                author_email=to_str(self._meta.author_email),
                url=to_str(self._meta.home_page),
                extra="\n    ".join(extra),
                after="\n".join(after),
            )
        )
Beispiel #6
0
    def search(self, query, mode=0):
        results = []

        search = {"name": query}

        if mode == self.SEARCH_FULLTEXT:
            search["summary"] = query

        client = ServerProxy("https://pypi.python.org/pypi")
        hits = client.search(search, "or")

        for hit in hits:
            try:
                result = Package(hit["name"], hit["version"], hit["version"])
                result.description = to_str(hit["summary"])
                results.append(result)
            except ParseVersionError:
                self._log(
                    'Unable to parse version "{}" for the {} package, skipping'.format(
                        hit["version"], hit["name"]
                    ),
                    level="debug",
                )

        return results
Beispiel #7
0
    def search(self, query: str) -> List[Package]:
        results = []

        search = {"q": query}

        response = requests.session().get(self._base_url + "search",
                                          params=search)
        content = parse(response.content, namespaceHTMLElements=False)
        for result in content.findall(".//*[@class='package-snippet']"):
            name = result.find("h3/*[@class='package-snippet__name']").text
            version = result.find(
                "h3/*[@class='package-snippet__version']").text

            if not name or not version:
                continue

            description = result.find(
                "p[@class='package-snippet__description']").text
            if not description:
                description = ""

            try:
                result = Package(name, version, description)
                result.description = to_str(description.strip())
                results.append(result)
            except ParseVersionError:
                self._log(
                    'Unable to parse version "{}" for the {} package, skipping'
                    .format(version, name),
                    level="debug",
                )

        return results
Beispiel #8
0
def test_with_src_module_file():
    poetry = Poetry.create(project('source_file'))

    builder = SdistBuilder(poetry, NullVenv(), NullIO())

    # Check setup.py
    setup = builder.build_setup()
    setup_ast = ast.parse(setup)

    setup_ast.body = [n for n in setup_ast.body if isinstance(n, ast.Assign)]
    ns = {}
    exec(compile(setup_ast, filename="setup.py", mode="exec"), ns)
    assert ns['package_dir'] == {'': 'src'}
    assert re.search('\'py_modules\': \'module_src\'',
                     to_str(setup)) is not None

    builder.build()

    sdist = fixtures_dir / 'source_file' / 'dist' / 'module-src-0.1.tar.gz'

    assert sdist.exists()

    tar = tarfile.open(str(sdist), 'r')

    assert 'module-src-0.1/src/module_src.py' in tar.getnames()
Beispiel #9
0
    def get_metadata_content(self):  # type: () -> bytes
        content = METADATA_BASE.format(
            name=self._meta.name,
            version=self._meta.version,
            summary=to_str(self._meta.summary),
        )

        # Optional fields
        if self._meta.home_page:
            content += "Home-page: {}\n".format(self._meta.home_page)

        if self._meta.license:
            content += "License: {}\n".format(self._meta.license)

        if self._meta.keywords:
            content += "Keywords: {}\n".format(self._meta.keywords)

        if self._meta.author:
            content += "Author: {}\n".format(to_str(self._meta.author))

        if self._meta.author_email:
            content += "Author-email: {}\n".format(to_str(self._meta.author_email))

        if self._meta.requires_python:
            content += "Requires-Python: {}\n".format(self._meta.requires_python)

        for classifier in self._meta.classifiers:
            content += "Classifier: {}\n".format(classifier)

        for extra in sorted(self._meta.provides_extra):
            content += "Provides-Extra: {}\n".format(extra)

        for dep in sorted(self._meta.requires_dist):
            content += "Requires-Dist: {}\n".format(dep)

        for url in sorted(self._meta.project_urls, key=lambda u: u[0]):
            content += "Project-URL: {}\n".format(to_str(url))

        if self._meta.description_content_type:
            content += "Description-Content-Type: {}\n".format(
                self._meta.description_content_type
            )

        if self._meta.description is not None:
            content += "\n" + to_str(self._meta.description) + "\n"

        return content
Beispiel #10
0
def test_proper_python_requires_if_three_digits_precision_version_specified():
    poetry = Poetry.create(project("single_python"))

    builder = SdistBuilder(poetry, NullEnv(), NullIO())
    pkg_info = builder.build_pkg_info()
    p = Parser()
    parsed = p.parsestr(to_str(pkg_info))

    assert parsed["Requires-Python"] == "==2.7.15"
Beispiel #11
0
def test_make_pkg_info_any_python():
    poetry = Poetry.create(project("module1"))

    builder = SdistBuilder(poetry, NullEnv(), NullIO())
    pkg_info = builder.build_pkg_info()
    p = Parser()
    parsed = p.parsestr(to_str(pkg_info))

    assert "Requires-Python" not in parsed
Beispiel #12
0
def test_proper_python_requires_if_two_digits_precision_version_specified():
    poetry = Factory().create_poetry(project("simple_version"))

    builder = SdistBuilder(poetry, NullEnv(), NullIO())
    pkg_info = builder.build_pkg_info()
    p = Parser()
    parsed = p.parsestr(to_str(pkg_info))

    assert parsed["Requires-Python"] == ">=3.6,<3.7"
Beispiel #13
0
def test_proper_python_requires_if_single_version_specified():
    poetry = Poetry.create(project("simple_version"))

    builder = SdistBuilder(poetry, NullVenv(), NullIO())
    pkg_info = builder.build_pkg_info()
    p = Parser()
    parsed = p.parsestr(to_str(pkg_info))

    assert parsed["Requires-Python"] == ">=3.6,<3.7"
Beispiel #14
0
def test_make_pkg_info_multi_constraints_dependency():
    poetry = Poetry.create(
        Path(__file__).parent.parent.parent / "fixtures" /
        "project_with_multi_constraints_dependency")

    builder = SdistBuilder(poetry, NullEnv(), NullIO())
    pkg_info = builder.build_pkg_info()
    p = Parser()
    parsed = p.parsestr(to_str(pkg_info))

    requires = parsed.get_all("Requires-Dist")
    assert requires == [
        'pendulum (>=1.5,<2.0); python_version < "3.4"',
        'pendulum (>=2.0,<3.0); python_version >= "3.4" and python_version < "4.0"',
    ]
Beispiel #15
0
    def search(self, query, mode=0):
        results = []

        search = {"name": query}

        if mode == self.SEARCH_FULLTEXT:
            search["summary"] = query

        client = ServerProxy("https://pypi.python.org/pypi")
        hits = client.search(search, "or")

        for hit in hits:
            result = Package(hit["name"], hit["version"], hit["version"])
            result.description = to_str(hit["summary"])
            results.append(result)

        return results
Beispiel #16
0
    def search(self, query, mode=0):
        results = []

        search = {'name': query}

        if mode == self.SEARCH_FULLTEXT:
            search['summary'] = query

        client = ServerProxy('https://pypi.python.org/pypi')
        hits = client.search(search, 'or')

        for hit in hits:
            result = Package(hit['name'], hit['version'], hit['version'])
            result.description = to_str(hit['summary'])
            results.append(result)

        return results
Beispiel #17
0
    def search(self, query, mode=0):
        results = []

        search = {"name": query}

        if mode == self.SEARCH_FULLTEXT:
            search["summary"] = query

        client = ServerProxy("https://pypi.python.org/pypi")
        hits = client.search(search, "or")

        for hit in hits:
            result = Package(hit["name"], hit["version"], hit["version"])
            result.description = to_str(hit["summary"])
            results.append(result)

        return results
Beispiel #18
0
def test_metadata_file_with_vcs_dependencies():
    project_path = fixtures_dir / "with_vcs_dependency"
    WheelBuilder.make(Poetry.create(str(project_path)), NullEnv(), NullIO())

    whl = project_path / "dist" / "with_vcs_dependency-1.2.3-py3-none-any.whl"

    assert whl.exists()

    p = Parser()

    with zipfile.ZipFile(str(whl)) as z:
        metadata = p.parsestr(
            to_str(z.read("with_vcs_dependency-1.2.3.dist-info/METADATA"))
        )

    requires_dist = metadata["Requires-Dist"]

    assert "cleo @ git+https://github.com/sdispater/cleo.git@master" == requires_dist
Beispiel #19
0
    def search(self, query: str) -> list[Package]:
        results = []

        search = {"q": query}

        response = requests.session().get(self._base_url + "search", params=search)
        content = parse(response.content, namespaceHTMLElements=False)
        for result in content.findall(".//*[@class='package-snippet']"):
            name_element = result.find("h3/*[@class='package-snippet__name']")
            version_element = result.find("h3/*[@class='package-snippet__version']")

            if (
                name_element is None
                or version_element is None
                or not name_element.text
                or not version_element.text
            ):
                continue

            name = name_element.text
            version = version_element.text

            description_element = result.find(
                "p[@class='package-snippet__description']"
            )
            description = (
                description_element.text
                if description_element is not None and description_element.text
                else ""
            )

            try:
                package = Package(name, version)
                package.description = to_str(description.strip())
                results.append(package)
            except InvalidVersion:
                self._log(
                    f'Unable to parse version "{version}" for the {name} package,'
                    " skipping",
                    level="debug",
                )

        return results
Beispiel #20
0
def test_make_pkg_info():
    poetry = Poetry.create(project("complete"))

    builder = SdistBuilder(poetry, NullEnv(), NullIO())
    pkg_info = builder.build_pkg_info()
    p = Parser()
    parsed = p.parsestr(to_str(pkg_info))

    assert parsed["Metadata-Version"] == "2.1"
    assert parsed["Name"] == "my-package"
    assert parsed["Version"] == "1.2.3"
    assert parsed["Summary"] == "Some description."
    assert parsed["Author"] == "Sébastien Eustace"
    assert parsed["Author-email"] == "*****@*****.**"
    assert parsed["Keywords"] == "packaging,dependency,poetry"
    assert parsed["Requires-Python"] == ">=3.6,<4.0"

    classifiers = parsed.get_all("Classifier")
    assert classifiers == [
        "License :: OSI Approved :: MIT License",
        "Programming Language :: Python :: 3",
        "Programming Language :: Python :: 3.6",
        "Programming Language :: Python :: 3.7",
        "Topic :: Software Development :: Build Tools",
        "Topic :: Software Development :: Libraries :: Python Modules",
    ]

    extras = parsed.get_all("Provides-Extra")
    assert extras == ["time"]

    requires = parsed.get_all("Requires-Dist")
    assert requires == [
        "cachy[msgpack] (>=0.2.0,<0.3.0)",
        "cleo (>=0.6,<0.7)",
        'pendulum (>=1.4,<2.0); extra == "time"',
    ]

    urls = parsed.get_all("Project-URL")
    assert urls == [
        "Documentation, https://poetry.eustace.io/docs",
        "Repository, https://github.com/sdispater/poetry",
    ]
Beispiel #21
0
def test_with_src_module_file():
    poetry = Poetry.create(project("source_file"))

    builder = SdistBuilder(poetry, NullVenv(), NullIO())

    # Check setup.py
    setup = builder.build_setup()
    setup_ast = ast.parse(setup)

    setup_ast.body = [n for n in setup_ast.body if isinstance(n, ast.Assign)]
    ns = {}
    exec(compile(setup_ast, filename="setup.py", mode="exec"), ns)
    assert ns["package_dir"] == {"": "src"}
    assert re.search("'py_modules': 'module_src'", to_str(setup)) is not None

    builder.build()

    sdist = fixtures_dir / "source_file" / "dist" / "module-src-0.1.tar.gz"

    assert sdist.exists()

    tar = tarfile.open(str(sdist), "r")

    assert "module-src-0.1/src/module_src.py" in tar.getnames()
Beispiel #22
0
    def build_setup(self):  # type: () -> bytes
        before, extra, after = [], [], []
        package_dir = {}

        # If we have a build script, use it
        if self._package.build:
            after += [
                "from {} import *".format(self._package.build.split(".")[0]),
                "build(setup_kwargs)",
            ]

        modules = []
        packages = []
        package_data = {}
        for include in self._module.includes:
            if isinstance(include, PackageInclude):
                if include.is_package():
                    pkg_dir, _packages, _package_data = self.find_packages(include)

                    if pkg_dir is not None:
                        package_dir[""] = os.path.relpath(pkg_dir, str(self._path))

                    packages += _packages
                    package_data.update(_package_data)
                else:
                    if include.source is not None:
                        package_dir[""] = str(include.base.relative_to(self._path))

                    modules.append(include.elements[0].relative_to(include.base).stem)
            else:
                pass

        if package_dir:
            before.append("package_dir = \\\n{}\n".format(pformat(package_dir)))
            extra.append("'package_dir': package_dir,")

        if packages:
            before.append("packages = \\\n{}\n".format(pformat(sorted(packages))))
            extra.append("'packages': packages,")

        if package_data:
            before.append("package_data = \\\n{}\n".format(pformat(package_data)))
            extra.append("'package_data': package_data,")

        if modules:
            before.append("modules = \\\n{}".format(pformat(modules)))
            extra.append("'py_modules': modules,".format())

        dependencies, extras = self.convert_dependencies(
            self._package, self._package.requires
        )
        if dependencies:
            before.append(
                "install_requires = \\\n{}\n".format(pformat(sorted(dependencies)))
            )
            extra.append("'install_requires': install_requires,")

        if extras:
            before.append("extras_require = \\\n{}\n".format(pformat(extras)))
            extra.append("'extras_require': extras_require,")

        entry_points = self.convert_entry_points()
        if entry_points:
            before.append("entry_points = \\\n{}\n".format(pformat(entry_points)))
            extra.append("'entry_points': entry_points,")

        if self._package.python_versions != "*":
            python_requires = self._meta.requires_python

            extra.append("'python_requires': {!r},".format(python_requires))

        return encode(
            SETUP.format(
                before="\n".join(before),
                name=to_str(self._meta.name),
                version=to_str(self._meta.version),
                description=to_str(self._meta.summary),
                long_description=to_str(self._meta.description),
                author=to_str(self._meta.author),
                author_email=to_str(self._meta.author_email),
                url=to_str(self._meta.home_page),
                extra="\n    ".join(extra),
                after="\n".join(after),
            )
        )