Skip to content

settings.py

User settings models and helper functions.

Settings

Bases: BaseModel

User settings model.

Source code in copier/settings.py
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
class Settings(BaseModel):
    """User settings model."""

    defaults: dict[str, Any] = Field(
        default_factory=dict, description="Default values for questions"
    )
    trust: set[str] = Field(
        default_factory=set, description="List of trusted repositories or prefixes"
    )

    @staticmethod
    def _default_settings_path() -> Path:
        return user_config_path("copier", appauthor=False) / "settings.yml"

    @classmethod
    def from_file(cls, settings_path: Path | None = None) -> Settings:
        """Load settings from a file."""
        env_path = os.getenv(ENV_VAR)
        if settings_path is None:
            if env_path:
                settings_path = Path(env_path)
            else:
                settings_path = cls._default_settings_path()

                # NOTE: Remove after a sufficiently long deprecation period.
                if OS == "windows":
                    old_settings_path = user_config_path("copier") / "settings.yml"
                    if old_settings_path.is_file():
                        warnings.warn(
                            f"Settings path {old_settings_path} is deprecated. "
                            f"Please migrate to {settings_path}.",
                            DeprecationWarning,
                            stacklevel=2,
                        )
                        settings_path = old_settings_path
        if settings_path.is_file():
            data = yaml.safe_load(settings_path.read_bytes())
            return cls.model_validate(data)
        elif env_path:
            warnings.warn(
                f"Settings file not found at {env_path}", MissingSettingsWarning
            )
        return cls()

    def is_trusted(self, repository: str) -> bool:
        """Check if a repository is trusted."""
        return any(
            repository.startswith(self.normalize(trusted))
            if trusted.endswith("/")
            else repository == self.normalize(trusted)
            for trusted in self.trust
        )

    def normalize(self, url: str) -> str:
        """Normalize an URL using user settings."""
        if url.startswith("~"):  # Only expand on str to avoid messing with URLs
            url = expanduser(url)  # noqa: PTH111
        return url

from_file(settings_path=None) classmethod

Load settings from a file.

Source code in copier/settings.py
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
@classmethod
def from_file(cls, settings_path: Path | None = None) -> Settings:
    """Load settings from a file."""
    env_path = os.getenv(ENV_VAR)
    if settings_path is None:
        if env_path:
            settings_path = Path(env_path)
        else:
            settings_path = cls._default_settings_path()

            # NOTE: Remove after a sufficiently long deprecation period.
            if OS == "windows":
                old_settings_path = user_config_path("copier") / "settings.yml"
                if old_settings_path.is_file():
                    warnings.warn(
                        f"Settings path {old_settings_path} is deprecated. "
                        f"Please migrate to {settings_path}.",
                        DeprecationWarning,
                        stacklevel=2,
                    )
                    settings_path = old_settings_path
    if settings_path.is_file():
        data = yaml.safe_load(settings_path.read_bytes())
        return cls.model_validate(data)
    elif env_path:
        warnings.warn(
            f"Settings file not found at {env_path}", MissingSettingsWarning
        )
    return cls()

is_trusted(repository)

Check if a repository is trusted.

Source code in copier/settings.py
65
66
67
68
69
70
71
72
def is_trusted(self, repository: str) -> bool:
    """Check if a repository is trusted."""
    return any(
        repository.startswith(self.normalize(trusted))
        if trusted.endswith("/")
        else repository == self.normalize(trusted)
        for trusted in self.trust
    )

normalize(url)

Normalize an URL using user settings.

Source code in copier/settings.py
74
75
76
77
78
def normalize(self, url: str) -> str:
    """Normalize an URL using user settings."""
    if url.startswith("~"):  # Only expand on str to avoid messing with URLs
        url = expanduser(url)  # noqa: PTH111
    return url