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
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, ))
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()
def handle(self) -> int: from pathlib import Path from poetry.core.pyproject.toml import PyProjectTOML 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( "<error>A pyproject.toml file with a poetry section already" " exists.</error>") return 1 if pyproject.data.get("build-system"): self.line_error( "<error>A pyproject.toml file with a defined build-system already" " exists.</error>") return 1 vcs_config = GitConfig() if self.io.is_interactive(): 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( f"Package name [<comment>{name}</comment>]: ", default=name) name = self.ask(question) version = "0.1.0" question = self.create_question( f"Version [<comment>{version}</comment>]: ", default=version) version = self.ask(question) description = self.option("description") if not description: description = self.ask( self.create_question("Description []: ", default="")) author = self.option("author") if not author and vcs_config.get("user.name"): author = vcs_config["user.name"] author_email = vcs_config.get("user.email") if author_email: author += f" <{author_email}>" question = self.create_question( f"Author [<comment>{author}</comment>, n to skip]: ", 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") if not license: license = self.ask(self.create_question("License []: ", default="")) python = self.option("python") if not python: current_env = SystemEnv(Path(sys.executable)) default_python = "^" + ".".join( str(v) for v in current_env.version_info[:2]) question = self.create_question( f"Compatible Python versions [<comment>{default_python}</comment>]: ", default=default_python, ) python = self.ask(question) if self.io.is_interactive(): self.line("") requirements: 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: - A single name (<b>requests</b>): this will search for matches on PyPI - A name and a constraint (<b>requests@^2.23.0</b>) - A git url (<b>git+https://github.com/python-poetry/poetry.git</b>) - A git url with a revision\ (<b>git+https://github.com/python-poetry/poetry.git#develop</b>) - A file path (<b>../my-package/my-package.whl</b>) - A directory (<b>../my-package/</b>) - A url (<b>https://example.com/packages/my-package-0.1.0.tar.gz</b>) """ help_displayed = False if self.confirm(question, True): if self.io.is_interactive(): self.line(help_message) help_displayed = True requirements.update( self._format_requirements(self._determine_requirements([]))) if self.io.is_interactive(): self.line("") dev_requirements: 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 self.io.is_interactive() and not help_displayed: self.line(help_message) dev_requirements.update( self._format_requirements(self._determine_requirements([]))) if self.io.is_interactive(): 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() for section in content: pyproject.data.append(section, content[section]) if self.io.is_interactive(): self.line("<info>Generated file</info>") self.line("") self.line(pyproject.data.as_string().replace("\r\n", "\n")) self.line("") if not self.confirm("Do you confirm generation?", True): self.line_error("<error>Command aborted</error>") return 1 pyproject.save() return 0