def do_init( project: Project, name: str = "", version: str = "", license: str = "MIT", author: str = "", email: str = "", ) -> None: """Bootstrap the project and create a pyproject.toml""" data = { "tool": { "pdm": { "name": name, "version": version, "description": "", "author": f"{author} <{email}>", "license": license, "homepage": "", "dependencies": tomlkit.table(), "dev-dependencies": tomlkit.table(), } }, "build-system": { "requires": ["pdm"], "build-backend": "pdm.builders.api" }, } if not project.pyproject: project._pyproject = data else: project._pyproject.setdefault("tool", {})["pdm"] = data["tool"]["pdm"] project._pyproject["build-system"] = data["build-system"] project.write_pyproject()
def do_import(project: Project, filename: str, format: Optional[str] = None) -> None: """Import project metadata from given file. :param project: the project instance :param filename: the file name :param format: the file format, or guess if not given. """ if not format: for key in FORMATS: if FORMATS[key].check_fingerprint(project, filename): break else: raise PdmUsageError("Can't derive the file format automatically, " "please specify it via '-f/--format' option.") else: key = format tool_settings = FORMATS[key].convert(project, filename) format_toml(tool_settings) if not project.pyproject_file.exists(): project.pyproject = {"tool": {"pdm": {}}} project.tool_settings.update(tool_settings) project.pyproject["build-system"] = { "requires": ["pdm"], "build-backend": ["pdm.builders.api"], } project.write_pyproject()
def do_init( project: Project, name: str = "", version: str = "", license: str = "MIT", author: str = "", email: str = "", python_requires: str = "", ) -> None: """Bootstrap the project and create a pyproject.toml""" data = { "project": { "name": name, "version": version, "description": "", "authors": array_of_inline_tables([{"name": author, "email": email}]), "license": make_inline_table({"text": license}), "urls": {"homepage": ""}, "dependencies": make_array([], True), "dev-dependencies": make_array([], True), "requires-python": python_requires, "dynamic": ["classifiers"], }, "build-system": {"requires": ["pdm-pep517"], "build-backend": "pdm.pep517.api"}, } if python_requires and python_requires != "*": get_specifier(python_requires) if not project.pyproject: project._pyproject = data else: project._pyproject["project"] = data["project"] project._pyproject["build-system"] = data["build-system"] project.write_pyproject()
def do_remove( project: Project, dev: bool = False, group: str | None = None, sync: bool = True, packages: Collection[str] = (), no_editable: bool = False, no_self: bool = False, dry_run: bool = False, ) -> None: """Remove packages from working set and pyproject.toml""" check_project_file(project) if not packages: raise PdmUsageError("Must specify at least one package to remove.") if not group: group = "dev" if dev else "default" if group not in list(project.iter_groups()): raise ProjectError(f"No-exist group {group}") deps = project.get_pyproject_dependencies(group, dev) project.core.ui.echo( f"Removing packages from {group} {'dev-' if dev else ''}dependencies: " + ", ".join(str(termui.green(name, bold=True)) for name in packages) ) for name in packages: req = parse_requirement(name) matched_indexes = sorted( (i for i, r in enumerate(deps) if req.matches(r, False)), reverse=True ) if not matched_indexes: raise ProjectError( "{} does not exist in {} dependencies.".format( termui.green(name, bold=True), group ) ) for i in matched_indexes: del deps[i] if not dry_run: project.write_pyproject() do_lock(project, "reuse", dry_run=dry_run) if sync: do_sync( project, groups=(group,), default=False, clean=True, no_editable=no_editable, no_self=no_self, dry_run=dry_run, )
def migrate_pyproject(project: Project): """Migrate the legacy pyproject format to PEP 621""" if project.pyproject and "project" in project.pyproject: pyproject = project.pyproject settings = {} updated_fields = [] for field in ("includes", "excludes", "build", "package-dir"): if field in pyproject["project"]: updated_fields.append(field) settings[field] = pyproject["project"][field] del pyproject["project"][field] if "dev-dependencies" in pyproject["project"]: if pyproject["project"]["dev-dependencies"]: settings["dev-dependencies"] = { "dev": pyproject["project"]["dev-dependencies"] } del pyproject["project"]["dev-dependencies"] updated_fields.append("dev-dependencies") if updated_fields: if "tool" not in pyproject or "pdm" not in pyproject["tool"]: setdefault(pyproject, "tool", {})["pdm"] = tomlkit.table() pyproject["tool"]["pdm"].update(settings) project.pyproject = pyproject project.write_pyproject() project.core.ui.echo( f"{termui.yellow('[AUTO-MIGRATION]')} These fields are moved from " f"[project] to [tool.pdm] table: {updated_fields}", err=True, ) return if not project.pyproject_file.exists() or not FORMATS["legacy"].check_fingerprint( project, project.pyproject_file ): return project.core.ui.echo( f"{termui.yellow('[AUTO-MIGRATION]')} Legacy pdm 0.x metadata detected, " "migrating to PEP 621...", err=True, ) do_import(project, project.pyproject_file, "legacy") project.core.ui.echo( termui.green("pyproject.toml") + termui.yellow( " has been migrated to PEP 621 successfully. " "Now you can safely delete the legacy metadata under [tool.pdm] table." ), err=True, )
def do_import( project: Project, filename: str, format: str | None = None, options: Namespace | None = None, ) -> None: """Import project metadata from given file. :param project: the project instance :param filename: the file name :param format: the file format, or guess if not given. :param options: other options parsed to the CLI. """ if not format: for key in FORMATS: if FORMATS[key].check_fingerprint(project, filename): break else: raise PdmUsageError( "Can't derive the file format automatically, " "please specify it via '-f/--format' option." ) else: key = format if options is None: options = Namespace(dev=False, group=None) project_data, settings = FORMATS[key].convert(project, filename, options) pyproject = project.pyproject or tomlkit.document() if "tool" not in pyproject or "pdm" not in pyproject["tool"]: # type: ignore pyproject.setdefault("tool", {})["pdm"] = tomlkit.table() if "project" not in pyproject: pyproject.add("project", tomlkit.table()) # type: ignore pyproject["project"].add( # type: ignore tomlkit.comment("PEP 621 project metadata") ) pyproject["project"].add( # type: ignore tomlkit.comment("See https://www.python.org/dev/peps/pep-0621/") ) merge_dictionary(pyproject["project"], project_data) # type: ignore merge_dictionary(pyproject["tool"]["pdm"], settings) # type: ignore pyproject["build-system"] = { "requires": ["pdm-pep517"], "build-backend": "pdm.pep517.api", } project.pyproject = cast(dict, pyproject) project.write_pyproject()
def do_remove( project: Project, dev: bool = False, section: Optional[str] = None, sync: bool = True, packages: Sequence[str] = (), ): """Remove packages from working set and pyproject.toml :param project: The project instance :param dev: Remove package from dev-dependencies :param section: Remove package from given section :param sync: Whether perform syncing action :param packages: Package names to be removed :return: None """ check_project_file(project) if not packages: raise click.BadParameter( "Must specify at least one package to remove.") section = "dev" if dev else section or "default" toml_section = f"{section}-dependencies" if section != "default" else "dependencies" if toml_section not in project.tool_settings: raise ProjectError( f"No such section {context.io.yellow(toml_section)} in pyproject.toml." ) deps = project.tool_settings[toml_section] context.io.echo(f"Removing packages from {section} dependencies: " + ", ".join( str(context.io.green(name, bold=True)) for name in packages)) for name in packages: matched_name = next( filter( lambda k: safe_name(k).lower() == safe_name(name).lower(), deps.keys(), ), None, ) if not matched_name: raise ProjectError("{} does not exist in {} dependencies.".format( context.io.green(name, bold=True), section)) del deps[matched_name] project.write_pyproject() do_lock(project, "reuse") if sync: do_sync(project, sections=(section, ), default=False, clean=True)
def do_remove( project: Project, dev: bool = False, section: Optional[str] = None, sync: bool = True, packages: Sequence[str] = (), ): """Remove packages from working set and pyproject.toml :param project: The project instance :param dev: Remove package from dev-dependencies :param section: Remove package from given section :param sync: Whether perform syncing action :param packages: Package names to be removed :return: None """ check_project_file(project) if not packages: raise PdmUsageError("Must specify at least one package to remove.") if not section: section = "dev" if dev else "default" if section not in list(project.iter_sections()): raise ProjectError(f"No-exist section {section}") deps = project.get_pyproject_dependencies(section, dev) project.core.ui.echo( f"Removing packages from {section} {'dev-' if dev else ''}dependencies: " + ", ".join(str(termui.green(name, bold=True)) for name in packages) ) for name in packages: req = parse_requirement(name) matched_indexes = sorted( (i for i, r in enumerate(deps) if req.matches(r, False)), reverse=True ) if not matched_indexes: raise ProjectError( "{} does not exist in {} dependencies.".format( termui.green(name, bold=True), section ) ) for i in matched_indexes: del deps[i] project.write_pyproject() do_lock(project, "reuse") if sync: do_sync(project, sections=(section,), default=False, clean=True)
def do_init( project: Project, name: str = "", version: str = "", description: str = "", license: str = "MIT", author: str = "", email: str = "", python_requires: str = "", ) -> None: """Bootstrap the project and create a pyproject.toml""" data = { "project": { "name": name, "version": version, "description": description, "authors": array_of_inline_tables([{"name": author, "email": email}]), "license": make_inline_table({"text": license}), "dependencies": make_array([], True), }, "build-system": { "requires": ["pdm-pep517>=0.12.0"], "build-backend": "pdm.pep517.api", }, } if python_requires and python_requires != "*": data["project"]["requires-python"] = python_requires # type: ignore if name and version: readme = next(project.root.glob("README*"), None) if readme is None: readme = project.root.joinpath("README.md") readme.write_text(f"# {name}\n\n{description}\n") data["project"]["readme"] = readme.name # type: ignore get_specifier(python_requires) if not project.pyproject: project._pyproject = data else: project._pyproject["project"] = data["project"] # type: ignore project._pyproject["build-system"] = data["build-system"] # type: ignore project.write_pyproject() signals.post_init.send(project)
def do_import(project: Project, filename: str, format: Optional[str] = None) -> None: """Import project metadata from given file. :param project: the project instance :param filename: the file name :param format: the file format, or guess if not given. """ if not format: for key in FORMATS: if FORMATS[key].check_fingerprint(project, filename): break else: raise PdmUsageError("Can't derive the file format automatically, " "please specify it via '-f/--format' option.") else: key = format project_data, settings = FORMATS[key].convert(project, filename) pyproject = project.pyproject or tomlkit.document() if "tool" not in pyproject or "pdm" not in pyproject["tool"]: setdefault(pyproject, "tool", {})["pdm"] = tomlkit.table() pyproject["tool"]["pdm"].update(settings) if "project" not in pyproject: pyproject.add("project", tomlkit.table()) pyproject["project"].add(tomlkit.comment("PEP 621 project metadata")) pyproject["project"].add( tomlkit.comment("See https://www.python.org/dev/peps/pep-0621/")) pyproject["project"].update(project_data) pyproject["build-system"] = { "requires": ["pdm-pep517"], "build-backend": "pdm.pep517.api", } project.pyproject = pyproject project.write_pyproject()