Example #1
0
    def _install_directory(self, operation: Install | Update) -> int:
        from poetry.factory import Factory

        package = operation.package
        operation_message = self.get_operation_message(operation)

        message = (
            f"  <fg=blue;options=bold>•</> {operation_message}:"
            " <info>Building...</info>"
        )
        self._write(operation, message)

        assert package.source_url is not None
        if package.root_dir:
            req = package.root_dir / package.source_url
        else:
            req = Path(package.source_url).resolve(strict=False)

        pyproject = PyProjectTOML(os.path.join(req, "pyproject.toml"))

        if pyproject.is_poetry_project():
            # Even if there is a build system specified
            # some versions of pip (< 19.0.0) don't understand it
            # so we need to check the version of pip to know
            # if we can rely on the build system
            legacy_pip = (
                self._env.pip_version
                < self._env.pip_version.__class__.from_parts(19, 0, 0)
            )
            package_poetry = Factory().create_poetry(pyproject.file.path.parent)

            builder: Builder
            if package.develop and not package_poetry.package.build_script:
                from poetry.masonry.builders.editable import EditableBuilder

                # This is a Poetry package in editable mode
                # we can use the EditableBuilder without going through pip
                # to install it, unless it has a build script.
                builder = EditableBuilder(package_poetry, self._env, NullIO())
                builder.build()

                return 0
            elif legacy_pip or package_poetry.package.build_script:
                from poetry.core.masonry.builders.sdist import SdistBuilder

                # We need to rely on creating a temporary setup.py
                # file since the version of pip does not support
                # build-systems
                # We also need it for non-PEP-517 packages
                builder = SdistBuilder(package_poetry)

                with builder.setup_py():
                    if package.develop:
                        return self.pip_install(req, upgrade=True, editable=True)
                    return self.pip_install(req, upgrade=True)

        if package.develop:
            return self.pip_install(req, upgrade=True, editable=True)

        return self.pip_install(req, upgrade=True)
Example #2
0
    def install_directory(self, package: "Package") -> Union[str, int]:
        from cleo.io.null_io import NullIO

        from poetry.factory import Factory

        req: Path

        if package.root_dir:
            req = (package.root_dir / package.source_url).as_posix()
        else:
            req = Path(package.source_url).resolve(strict=False)

        pyproject = PyProjectTOML(os.path.join(req, "pyproject.toml"))

        if pyproject.is_poetry_project():
            # Even if there is a build system specified
            # some versions of pip (< 19.0.0) don't understand it
            # so we need to check the version of pip to know
            # if we can rely on the build system
            legacy_pip = self._env.pip_version < self._env.pip_version.__class__(
                19, 0, 0)
            package_poetry = Factory().create_poetry(
                pyproject.file.path.parent)

            if package.develop and not package_poetry.package.build_script:
                from poetry.masonry.builders.editable import EditableBuilder

                # This is a Poetry package in editable mode
                # we can use the EditableBuilder without going through pip
                # to install it, unless it has a build script.
                builder = EditableBuilder(package_poetry, self._env, NullIO())
                builder.build()

                return 0
            elif legacy_pip or package_poetry.package.build_script:
                from poetry.core.masonry.builders.sdist import SdistBuilder

                # We need to rely on creating a temporary setup.py
                # file since the version of pip does not support
                # build-systems
                # We also need it for non-PEP-517 packages
                builder = SdistBuilder(package_poetry)

                with builder.setup_py():
                    if package.develop:
                        return pip_editable_install(directory=req,
                                                    environment=self._env)
                    return pip_install(path=req,
                                       environment=self._env,
                                       deps=False,
                                       upgrade=True)

        if package.develop:
            return pip_editable_install(directory=req, environment=self._env)
        return pip_install(path=req,
                           environment=self._env,
                           deps=False,
                           upgrade=True)
def test_pyproject_toml_poetry_config(
    pyproject_toml: Path, poetry_section: str
) -> None:
    pyproject = PyProjectTOML(pyproject_toml)
    doc: dict[str, Any] = TOMLFile(pyproject_toml.as_posix()).read()
    config = doc["tool"]["poetry"]

    assert pyproject.is_poetry_project()
    assert pyproject.poetry_config == config
Example #4
0
    def install_directory(self, package):
        from poetry.factory import Factory
        from poetry.io.null_io import NullIO

        if package.root_dir:
            req = (package.root_dir / package.source_url).as_posix()
        else:
            req = os.path.realpath(package.source_url)

        args = ["install", "--no-deps", "-U"]

        pyproject = PyProjectTOML(os.path.join(req, "pyproject.toml"))

        if pyproject.is_poetry_project():
            # Even if there is a build system specified
            # some versions of pip (< 19.0.0) don't understand it
            # so we need to check the version of pip to know
            # if we can rely on the build system
            legacy_pip = self._env.pip_version < self._env.pip_version.__class__(
                19, 0, 0)
            package_poetry = Factory().create_poetry(
                pyproject.file.path.parent)

            if package.develop and not package_poetry.package.build_script:
                from poetry.masonry.builders.editable import EditableBuilder

                # This is a Poetry package in editable mode
                # we can use the EditableBuilder without going through pip
                # to install it, unless it has a build script.
                builder = EditableBuilder(package_poetry, self._env, NullIO())
                builder.build()

                return 0
            elif legacy_pip or package_poetry.package.build_script:
                from poetry.core.masonry.builders.sdist import SdistBuilder

                # We need to rely on creating a temporary setup.py
                # file since the version of pip does not support
                # build-systems
                # We also need it for non-PEP-517 packages
                builder = SdistBuilder(package_poetry)

                with builder.setup_py():
                    if package.develop:
                        args.append("-e")

                    args.append(req)

                    return self.run_pip(*args)

        if package.develop:
            args.append("-e")

        args.append(req)

        return self.run(*args)
Example #5
0
def test_pyproject_toml_reload(pyproject_toml, poetry_section):
    pyproject = PyProjectTOML(pyproject_toml)
    name_original = pyproject.poetry_config["name"]
    name_new = str(uuid.uuid4())

    pyproject.poetry_config["name"] = name_new
    assert pyproject.poetry_config["name"] == name_new

    pyproject.reload()
    assert pyproject.poetry_config["name"] == name_original
Example #6
0
def test_pyproject_toml_no_poetry_config(pyproject_toml):
    pyproject = PyProjectTOML(pyproject_toml)

    assert not pyproject.is_poetry_project()

    with pytest.raises(PyProjectException) as excval:
        _ = pyproject.poetry_config

    assert "[tool.poetry] section not found in {}".format(
        pyproject_toml.as_posix()) in str(excval.value)
def test_pyproject_toml_no_poetry_config(pyproject_toml: Path) -> None:
    pyproject = PyProjectTOML(pyproject_toml)

    assert not pyproject.is_poetry_project()

    with pytest.raises(PyProjectException) as excval:
        _ = pyproject.poetry_config

    assert f"[tool.poetry] section not found in {pyproject_toml.as_posix()}" in str(
        excval.value
    )
Example #8
0
    def create_poetry(self,
                      cwd: Path | None = None,
                      with_groups: bool = True) -> Poetry:
        from poetry.core.poetry import Poetry
        from poetry.core.pyproject.toml import PyProjectTOML

        poetry_file = self.locate(cwd)
        local_config = PyProjectTOML(path=poetry_file).poetry_config

        # Checking validity
        check_result = self.validate(local_config)
        if check_result["errors"]:
            message = ""
            for error in check_result["errors"]:
                message += f"  - {error}\n"

            raise RuntimeError("The Poetry configuration is invalid:\n" +
                               message)

        # Load package
        name = cast(str, local_config["name"])
        version = cast(str, local_config["version"])
        package = self.get_package(name, version)
        package = self.configure_package(package,
                                         local_config,
                                         poetry_file.parent,
                                         with_groups=with_groups)

        return Poetry(poetry_file, local_config, package)
Example #9
0
def test_pyproject_toml_non_existent(pyproject_toml):
    pyproject_toml.unlink()
    pyproject = PyProjectTOML(pyproject_toml)
    build_system = pyproject.build_system

    assert pyproject.data == TOMLDocument()
    assert build_system.requires == ["poetry-core"]
    assert build_system.build_backend == "poetry.core.masonry.api"
def assert_version(repo: Repo, expected_revision: str) -> None:
    version = PyProjectTOML(path=Path(repo.path).joinpath(
        "pyproject.toml")).poetry_config["version"]

    revision = Git.get_revision(repo=repo)

    assert revision == expected_revision
    assert revision in REVISION_TO_VERSION_MAP
    assert version == REVISION_TO_VERSION_MAP[revision]
Example #11
0
def test_pyproject_toml_no_build_system_defaults():
    pyproject_toml = (Path(__file__).parent.parent / "fixtures" /
                      "project_with_build_system_requires" / "pyproject.toml")

    build_system = PyProjectTOML(pyproject_toml).build_system
    assert build_system.requires == ["poetry-core", "Cython~=0.29.6"]

    assert len(build_system.dependencies) == 2
    assert build_system.dependencies[0].to_pep_508() == "poetry-core"
    assert build_system.dependencies[1].to_pep_508(
    ) == "Cython (>=0.29.6,<0.30.0)"
Example #12
0
    def __init__(
        self,
        file: "Path",
        local_config: dict,
        package: "ProjectPackage",
    ) -> None:
        from poetry.core.pyproject.toml import PyProjectTOML  # noqa

        self._pyproject = PyProjectTOML(file)
        self._package = package
        self._local_config = local_config
Example #13
0
    def __init__(
        self,
        file: Path,
        local_config: dict[str, Any],
        package: ProjectPackage,
    ) -> None:
        from poetry.core.pyproject.toml import PyProjectTOML

        self._pyproject = PyProjectTOML(file)
        self._package = package
        self._local_config = local_config
Example #14
0
    def __init__(
        self,
        name: str,
        path: Path,
        groups: Optional[List[str]] = None,
        optional: bool = False,
        base: Optional[Path] = None,
        develop: bool = False,
        extras: Optional[Union[List[str], FrozenSet[str]]] = None,
    ) -> None:
        from poetry.core.pyproject.toml import PyProjectTOML

        self._path = path
        self._base = base or Path.cwd()
        self._full_path = path

        if not self._path.is_absolute():
            try:
                self._full_path = self._base.joinpath(self._path).resolve()
            except FileNotFoundError:
                raise ValueError("Directory {} does not exist".format(self._path))

        self._develop = develop
        self._supports_poetry = False

        if not self._full_path.exists():
            raise ValueError("Directory {} does not exist".format(self._path))

        if self._full_path.is_file():
            raise ValueError("{} is a file, expected a directory".format(self._path))

        # Checking content to determine actions
        setup = self._full_path / "setup.py"
        self._supports_poetry = PyProjectTOML(
            self._full_path / "pyproject.toml"
        ).is_poetry_project()

        if not setup.exists() and not self._supports_poetry:
            raise ValueError(
                "Directory {} does not seem to be a Python package".format(
                    self._full_path
                )
            )

        super(DirectoryDependency, self).__init__(
            name,
            "*",
            groups=groups,
            optional=optional,
            allows_prereleases=True,
            source_type="directory",
            source_url=self._full_path.as_posix(),
            extras=extras,
        )
Example #15
0
    def generate_system_pyproject(self) -> None:
        preserved = {}

        if self.system_pyproject.exists():
            content = PyProjectTOML(self.system_pyproject).poetry_config

            for key in {"group", "source"}:
                if key in content:
                    preserved[key] = content[key]

        package = ProjectPackage(name="poetry-instance", version=__version__)
        package.add_dependency(
            Dependency(name="poetry", constraint=f"{__version__}"))

        package.python_versions = ".".join(
            str(v) for v in self.env.version_info[:3])

        content = Factory.create_pyproject_from_package(package=package)

        for key in preserved:
            content[key] = preserved[key]

        self.system_pyproject.write_text(content.as_string(), encoding="utf-8")
Example #16
0
    def handle(self):
        # Load poetry config and display errors, if any
        poetry_file = Factory.locate(Path.cwd())
        config = PyProjectTOML(poetry_file).poetry_config
        check_result = Factory.validate(config, strict=True)
        if not check_result["errors"] and not check_result["warnings"]:
            self.info("All set!")

            return 0

        for error in check_result["errors"]:
            self.line("<error>Error: {}</error>".format(error))

        for error in check_result["warnings"]:
            self.line("<warning>Warning: {}</warning>".format(error))

        return 1
Example #17
0
    def handle(self) -> int:
        from poetry.core.pyproject.toml import PyProjectTOML

        from poetry.factory import Factory

        # Load poetry config and display errors, if any
        poetry_file = Factory.locate(Path.cwd())
        config = PyProjectTOML(poetry_file).poetry_config
        check_result = Factory.validate(config, strict=True)
        if not check_result["errors"] and not check_result["warnings"]:
            self.info("All set!")

            return 0

        for error in check_result["errors"]:
            self.line_error(f"<error>Error: {error}</error>")

        for error in check_result["warnings"]:
            self.line_error(f"<warning>Warning: {error}</warning>")

        return 1
Example #18
0
def test_pyproject_toml_save(pyproject_toml, poetry_section,
                             build_system_section):
    pyproject = PyProjectTOML(pyproject_toml)

    name = str(uuid.uuid4())
    build_backend = str(uuid.uuid4())
    build_requires = str(uuid.uuid4())

    pyproject.poetry_config["name"] = name
    pyproject.build_system.build_backend = build_backend
    pyproject.build_system.requires.append(build_requires)

    pyproject.save()

    pyproject = PyProjectTOML(pyproject_toml)

    assert pyproject.poetry_config["name"] == name
    assert pyproject.build_system.build_backend == build_backend
    assert build_requires in pyproject.build_system.requires
Example #19
0
    def handle(self) -> int:
        from pathlib import Path

        from poetry.core.vcs.git import GitConfig
        from poetry.layouts import layout
        from poetry.utils.env import SystemEnv

        pyproject = PyProjectTOML(Path.cwd() / "pyproject.toml")

        if pyproject.file.exists():
            if pyproject.is_poetry_project():
                self.line(
                    "<error>A pyproject.toml file with a poetry section already exists.</error>"
                )
                return 1

            if pyproject.data.get("build-system"):
                self.line(
                    "<error>A pyproject.toml file with a defined build-system already exists.</error>"
                )
                return 1

        vcs_config = GitConfig()

        self.line("")
        self.line(
            "This command will guide you through creating your <info>pyproject.toml</> config."
        )
        self.line("")

        name = self.option("name")
        if not name:
            name = Path.cwd().name.lower()

            question = self.create_question(
                "Package name [<comment>{}</comment>]: ".format(name), default=name
            )
            name = self.ask(question)

        version = "0.1.0"
        question = self.create_question(
            "Version [<comment>{}</comment>]: ".format(version), default=version
        )
        version = self.ask(question)

        description = self.option("description") or ""
        question = self.create_question(
            "Description [<comment>{}</comment>]: ".format(description),
            default=description,
        )
        description = self.ask(question)

        author = self.option("author")
        if not author and vcs_config and vcs_config.get("user.name"):
            author = vcs_config["user.name"]
            author_email = vcs_config.get("user.email")
            if author_email:
                author += " <{}>".format(author_email)

        question = self.create_question(
            "Author [<comment>{}</comment>, n to skip]: ".format(author), default=author
        )
        question.set_validator(lambda v: self._validate_author(v, author))
        author = self.ask(question)

        if not author:
            authors = []
        else:
            authors = [author]

        license = self.option("license") or ""

        question = self.create_question(
            "License [<comment>{}</comment>]: ".format(license), default=license
        )
        question.set_validator(self._validate_license)
        license = self.ask(question)

        python = self.option("python")
        if not python:
            current_env = SystemEnv(Path(sys.executable))
            default_python = "^{}".format(
                ".".join(str(v) for v in current_env.version_info[:2])
            )
            question = self.create_question(
                "Compatible Python versions [<comment>{}</comment>]: ".format(
                    default_python
                ),
                default=default_python,
            )
            python = self.ask(question)

        self.line("")

        requirements = {}
        if self.option("dependency"):
            requirements = self._format_requirements(
                self._determine_requirements(self.option("dependency"))
            )

        question = "Would you like to define your main dependencies interactively?"
        help_message = (
            "You can specify a package in the following forms:\n"
            "  - A single name (<b>requests</b>)\n"
            "  - A name and a constraint (<b>requests@^2.23.0</b>)\n"
            "  - A git url (<b>git+https://github.com/python-poetry/poetry.git</b>)\n"
            "  - A git url with a revision (<b>git+https://github.com/python-poetry/poetry.git#develop</b>)\n"
            "  - A file path (<b>../my-package/my-package.whl</b>)\n"
            "  - A directory (<b>../my-package/</b>)\n"
            "  - A url (<b>https://example.com/packages/my-package-0.1.0.tar.gz</b>)\n"
        )
        help_displayed = False
        if self.confirm(question, True):
            self.line(help_message)
            help_displayed = True
            requirements.update(
                self._format_requirements(self._determine_requirements([]))
            )
            self.line("")

        dev_requirements = {}
        if self.option("dev-dependency"):
            dev_requirements = self._format_requirements(
                self._determine_requirements(self.option("dev-dependency"))
            )

        question = (
            "Would you like to define your development dependencies interactively?"
        )
        if self.confirm(question, True):
            if not help_displayed:
                self.line(help_message)

            dev_requirements.update(
                self._format_requirements(self._determine_requirements([]))
            )
            self.line("")

        layout_ = layout("standard")(
            name,
            version,
            description=description,
            author=authors[0] if authors else None,
            license=license,
            python=python,
            dependencies=requirements,
            dev_dependencies=dev_requirements,
        )

        content = layout_.generate_poetry_content(original=pyproject)
        if self.io.is_interactive():
            self.line("<info>Generated file</info>")
            self.line("")
            self.line(content)
            self.line("")

        if not self.confirm("Do you confirm generation?", True):
            self.line("<error>Command aborted</error>")

            return 1

        with (Path.cwd() / "pyproject.toml").open("w", encoding="utf-8") as f:
            f.write(content)
def test_pyproject_toml_simple(
    pyproject_toml: Path, build_system_section: str, poetry_section: str
) -> None:
    data = TOMLFile(pyproject_toml.as_posix()).read()
    assert PyProjectTOML(pyproject_toml).data == data
Example #21
0
 def _get_poetry_package(path: Path) -> Optional[ProjectPackage]:
     # Note: we ignore any setup.py file at this step
     # TODO: add support for handling non-poetry PEP-517 builds
     if PyProjectTOML(path.joinpath("pyproject.toml")).is_poetry_project():
         return Factory().create_poetry(path).package
Example #22
0
    def _install_directory(self, operation: Union[Install, Update]) -> int:
        from poetry.factory import Factory

        package = operation.package
        operation_message = self.get_operation_message(operation)

        message = (
            "  <fg=blue;options=bold>•</> {message}: <info>Building...</info>".
            format(message=operation_message, ))
        self._write(operation, message)

        if package.root_dir:
            req = os.path.join(str(package.root_dir), package.source_url)
        else:
            req = os.path.realpath(package.source_url)

        args = ["install", "--no-deps", "-U"]

        pyproject = PyProjectTOML(os.path.join(req, "pyproject.toml"))

        if pyproject.is_poetry_project():
            # Even if there is a build system specified
            # some versions of pip (< 19.0.0) don't understand it
            # so we need to check the version of pip to know
            # if we can rely on the build system
            legacy_pip = self._env.pip_version < self._env.pip_version.__class__(
                19, 0, 0)
            package_poetry = Factory().create_poetry(
                pyproject.file.path.parent)

            if package.develop and not package_poetry.package.build_script:
                from poetry.masonry.builders.editable import EditableBuilder

                # This is a Poetry package in editable mode
                # we can use the EditableBuilder without going through pip
                # to install it, unless it has a build script.
                builder = EditableBuilder(package_poetry, self._env, NullIO())
                builder.build()

                return 0
            elif legacy_pip or package_poetry.package.build_script:
                from poetry.core.masonry.builders.sdist import SdistBuilder

                # We need to rely on creating a temporary setup.py
                # file since the version of pip does not support
                # build-systems
                # We also need it for non-PEP-517 packages
                builder = SdistBuilder(package_poetry)

                with builder.setup_py():
                    if package.develop:
                        args.append("-e")

                    args.append(req)

                    return self.run_pip(*args)

        if package.develop:
            args.append("-e")

        args.append(req)

        return self.run_pip(*args)
Example #23
0
 def _write_poetry(self, path: Path) -> None:
     pyproject = PyProjectTOML(path / "pyproject.toml")
     content = self.generate_poetry_content()
     for section in content:
         pyproject.data.append(section, content[section])
     pyproject.save()
Example #24
0
    def handle(self) -> int:
        from pathlib import Path

        import tomlkit

        from cleo.io.inputs.string_input import StringInput
        from cleo.io.io import IO
        from poetry.core.pyproject.toml import PyProjectTOML
        from poetry.core.semver.helpers import parse_constraint

        from poetry.factory import Factory
        from poetry.packages.project_package import ProjectPackage
        from poetry.repositories.installed_repository import InstalledRepository
        from poetry.utils.env import EnvManager

        plugins = self.argument("plugins")

        # Plugins should be installed in the system env to be globally available
        system_env = EnvManager.get_system_env(naive=True)

        env_dir = Path(os.getenv("POETRY_HOME") or system_env.path)

        # We check for the plugins existence first.
        if env_dir.joinpath("pyproject.toml").exists():
            pyproject = tomlkit.loads(
                env_dir.joinpath("pyproject.toml").read_text(encoding="utf-8"))
            poetry_content = pyproject["tool"]["poetry"]
            existing_packages = self.get_existing_packages_from_input(
                plugins, poetry_content, "dependencies")

            if existing_packages:
                self.notify_about_existing_packages(existing_packages)

            plugins = [
                plugin for plugin in plugins if plugin not in existing_packages
            ]

        if not plugins:
            return 0

        plugins = self._determine_requirements(plugins)

        # We retrieve the packages installed in the system environment.
        # We assume that this environment will be a self contained virtual environment
        # built by the official installer or by pipx.
        # If not, it might lead to side effects since other installed packages
        # might not be required by Poetry but still taken into account when resolving dependencies.
        installed_repository = InstalledRepository.load(system_env,
                                                        with_dependencies=True)

        root_package = None
        for package in installed_repository.packages:
            if package.name == "poetry":
                root_package = ProjectPackage(package.name, package.version)
                for dependency in package.requires:
                    root_package.add_dependency(dependency)

                break

        root_package.python_versions = ".".join(
            str(v) for v in system_env.version_info[:3])
        # We create a `pyproject.toml` file based on all the information
        # we have about the current environment.
        if not env_dir.joinpath("pyproject.toml").exists():
            Factory.create_pyproject_from_package(root_package, env_dir)

        # We add the plugins to the dependencies section of the previously
        # created `pyproject.toml` file
        pyproject = PyProjectTOML(env_dir.joinpath("pyproject.toml"))
        poetry_content = pyproject.poetry_config
        poetry_dependency_section = poetry_content["dependencies"]
        plugin_names = []
        for plugin in plugins:
            if "version" in plugin:
                # Validate version constraint
                parse_constraint(plugin["version"])

            constraint = tomlkit.inline_table()
            for name, value in plugin.items():
                if name == "name":
                    continue

                constraint[name] = value

            if len(constraint) == 1 and "version" in constraint:
                constraint = constraint["version"]

            poetry_dependency_section[plugin["name"]] = constraint
            plugin_names.append(plugin["name"])

        pyproject.save()

        # From this point forward, all the logic will be deferred to
        # the update command, by using the previously created `pyproject.toml`
        # file.
        application = cast(Application, self.application)
        update_command: UpdateCommand = cast(UpdateCommand,
                                             application.find("update"))
        # We won't go through the event dispatching done by the application
        # so we need to configure the command manually
        update_command.set_poetry(Factory().create_poetry(env_dir))
        update_command.set_env(system_env)
        application._configure_installer(update_command, self._io)

        argv = ["update"] + plugin_names
        if self.option("dry-run"):
            argv.append("--dry-run")

        return update_command.run(
            IO(
                StringInput(" ".join(argv)),
                self._io.output,
                self._io.error_output,
            ))
Example #25
0
def test_pyproject_toml_simple(pyproject_toml, build_system_section,
                               poetry_section):
    data = TOMLFile(pyproject_toml.as_posix()).read()
    assert PyProjectTOML(pyproject_toml).data == data
Example #26
0
def test_pyproject_toml_poetry_config(pyproject_toml, poetry_section):
    pyproject = PyProjectTOML(pyproject_toml)
    config = TOMLFile(pyproject_toml.as_posix()).read()["tool"]["poetry"]

    assert pyproject.is_poetry_project()
    assert pyproject.poetry_config == config
Example #27
0
def test_pyproject_toml_build_requires_as_dependencies(pyproject_toml):
    build_system = PyProjectTOML(pyproject_toml).build_system
    assert build_system.requires == ["setuptools", "wheel"]
    assert build_system.build_backend == "setuptools.build_meta:__legacy__"