Source code for mafw.scaffold.prompting

#  Copyright 2026 European Union
#  Author: Bulgheroni Antonio (antonio.bulgheroni@ec.europa.eu)
#  SPDX-License-Identifier: EUPL-1.2
"""Interactive prompts and success reporting for project scaffolding.

:author: Bulgheroni Antonio
"""

import pathlib

from rich import print as rprint
from rich.prompt import Prompt

from mafw.scaffold import ProjectSpec, ScaffoldError
from mafw.scaffold.names import to_import_name, validate, validate_email


[docs] def _prompt_project_name(project_name: str | None) -> str: """Prompt for a valid project name, re-prompting up to three times. :param project_name: The name supplied on the command line, if any. :type project_name: str | None :return: A validated project name. :rtype: str :raises mafw.scaffold.errors.ScaffoldError: If a valid name is not provided within the attempts. """ attempts = 0 candidate = project_name while True: if candidate is not None and candidate.strip(): try: validate(candidate.strip(), to_import_name(candidate.strip())) return candidate.strip() except ScaffoldError as exc: rprint(f'[yellow]{exc}[/yellow]') attempts += 1 if attempts > 3: raise ScaffoldError('No valid project name was provided after several attempts.') candidate = Prompt.ask('Project name')
[docs] def _prompt_optional(label: str, value: str | None, default: str) -> str: """Prompt for an optional value, showing and accepting a default. :param label: The human-readable label for the prompt. :type label: str :param value: The value supplied on the command line, if any. :type value: str | None :param default: The default used when the user accepts the prompt. :type default: str :return: The resolved value. :rtype: str """ if value is not None and value.strip(): return value.strip() return str(Prompt.ask(label, default=default))
[docs] def _prompt_author_email(value: str | None, default: str) -> str: """Prompt for a well-formed author e-mail, re-prompting up to three times. A malformed e-mail would make the generated project's build backend fail, so the address is validated here and the user is asked again on invalid input. :param value: The e-mail supplied on the command line, if any. :type value: str | None :param default: The default e-mail used when the user accepts the prompt. :type default: str :return: A validated e-mail address. :rtype: str :raises mafw.scaffold.errors.ScaffoldError: If no valid e-mail is provided in time. """ attempts = 0 candidate = value while True: if candidate is not None and candidate.strip(): try: validate_email(candidate.strip()) return candidate.strip() except ScaffoldError as exc: rprint(f'[yellow]{exc}[/yellow]') attempts += 1 if attempts > 3: raise ScaffoldError('No valid author e-mail was provided after several attempts.') candidate = str(Prompt.ask('Author e-mail', default=default))
[docs] def _report_success(spec: ProjectSpec, project_dir: pathlib.Path, install: str | None) -> None: """Print the post-generation summary and next-step commands. :param spec: The validated project specification. :type spec: mafw.scaffold.spec.ProjectSpec :param project_dir: The absolute path to the generated project. :type project_dir: pathlib.Path :param install: The install manager requested, if any. :type install: str | None """ steering = f'conf/{spec.import_name}_steering.toml' rprint(f'[green]Project created:[/green] [blue underline]{project_dir}[/blue underline]') rprint(f' Distribution name: [cyan]{spec.distribution_name}[/cyan]') rprint(f' Import package: [cyan]{spec.import_name}[/cyan]') rprint('') rprint('Next steps:') rprint(f' cd {project_dir}') if install is None: rprint(' hatch env create') rprint(' hatch run mafw list') rprint(f' hatch run mafw run {steering}') rprint(' hatch test')