Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 29 additions & 23 deletions cppython/configuration.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,11 @@
This module handles loading configuration from multiple sources:
1. Global configuration (~/.cppython/config.toml) - User-wide settings for all projects
2. Project configuration (pyproject.toml or cppython.toml) - Project-specific settings
3. Local overrides (.cppython.toml) - Overrides for global configuration
3. Local overrides (.cppython.toml) - User-specific overrides, repository ignored

Local overrides (.cppython.toml) can override any field from both CPPythonLocalConfiguration
and CPPythonGlobalConfiguration. Validation occurs on the merged result, not on the override
file itself, allowing flexible user-specific customization.
"""

from pathlib import Path
Expand Down Expand Up @@ -77,7 +81,12 @@ def load_global_config(self) -> dict[str, Any] | None:
def load_local_overrides(self) -> dict[str, Any] | None:
"""Load local overrides from .cppython.toml if it exists

These overrides only affect the global configuration, not project configuration.
These overrides have the highest priority and override both global
and project configuration. This file should be gitignored as it
contains machine-specific or user-specific settings.

The override file can contain any fields from CPPythonLocalConfiguration
or CPPythonGlobalConfiguration. Validation occurs on the merged result.

Returns:
Dictionary containing local override data, or None if file doesn't exist
Expand Down Expand Up @@ -113,23 +122,15 @@ def load_cppython_table(self) -> dict[str, Any] | None:
"""Load and merge the CPPython configuration table from all sources

Priority (highest to lowest):
1. Project configuration (pyproject.toml or cppython.toml)
2. Local overrides (.cppython.toml) merged with global config
3. Global configuration (~/.cppython/config.toml)
1. Local overrides (.cppython.toml) - Machine/user-specific settings
2. Project configuration (pyproject.toml or cppython.toml) - Project-specific settings
3. Global configuration (~/.cppython/config.toml) - User-wide defaults

Returns:
Merged CPPython configuration dictionary, or None if no config found
"""
# Start with global configuration
global_config = self.load_global_config()

# Apply local overrides to global config
local_overrides = self.load_local_overrides()
if local_overrides is not None and global_config is not None:
global_config = self.merge_configurations(global_config, local_overrides)
elif local_overrides is not None and global_config is None:
# Local overrides exist but no global config - use overrides as base
global_config = local_overrides
# Start with global configuration (lowest priority)
result_config = self.load_global_config()

# Load project configuration (pyproject.toml or cppython.toml)
pyproject_data = self.load_pyproject_data()
Expand All @@ -145,16 +146,21 @@ def load_cppython_table(self) -> dict[str, Any] | None:
)
project_config = cppython_toml_config

# Merge: global config (with local overrides) + project config
# Project config has highest priority
if project_config is not None and global_config is not None:
return self.merge_configurations(global_config, project_config)
# Merge project config over global config
if project_config is not None and result_config is not None:
result_config = self.merge_configurations(result_config, project_config)
elif project_config is not None:
return project_config
elif global_config is not None:
return global_config
result_config = project_config

# Apply local overrides with highest priority
local_overrides = self.load_local_overrides()
if local_overrides is not None:
if result_config is not None:
result_config = self.merge_configurations(result_config, local_overrides)
else:
result_config = local_overrides

return None
return result_config

def get_project_data(self) -> dict[str, Any]:
"""Get the complete pyproject data with merged CPPython configuration
Expand Down
6 changes: 5 additions & 1 deletion cppython/core/schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -269,7 +269,11 @@ class CPPythonGlobalConfiguration(CPPythonModel, extra='forbid'):


class CPPythonLocalConfiguration(CPPythonModel, extra='forbid'):
"""Data required by the tool"""
"""Project-level CPPython configuration

This configuration is stored in pyproject.toml or cppython.toml.
User-specific overrides can be placed in .cppython.toml (which should be gitignored).
"""

configuration_path: Annotated[
Path | None,
Expand Down
2 changes: 1 addition & 1 deletion cppython/plugins/cmake/schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ class CMakeData(CPPythonModel):


class CMakeConfiguration(CPPythonModel):
"""Configuration"""
"""Configuration for the CMake generator plugin"""

preset_file: Annotated[
Path,
Expand Down
4 changes: 2 additions & 2 deletions cppython/plugins/conan/schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -298,7 +298,7 @@ class ConanData(CPPythonModel):


class ConanConfiguration(CPPythonModel):
"""Raw conan data"""
"""Conan provider configuration"""

remotes: Annotated[
list[str],
Expand All @@ -312,7 +312,7 @@ class ConanConfiguration(CPPythonModel):
str,
Field(
description='Directory containing Conan profiles. Profiles will be looked up relative to this directory. '
'If profiles do not exist in this directory, Conan will fall back to default profiles.'
'If profiles do not exist in this directory, Conan will fall back to default profiles. '
"If a relative path is provided, it will be resolved relative to the tool's working directory."
),
] = 'profiles'
4 changes: 2 additions & 2 deletions cppython/plugins/vcpkg/schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,13 +49,13 @@ class VcpkgData(CPPythonModel):


class VcpkgConfiguration(CPPythonModel):
"""vcpkg provider data"""
"""vcpkg provider configuration"""

install_directory: Annotated[
Path,
Field(
alias='install-directory',
description='The referenced dependencies defined by the local vcpkg.json manifest file',
description='The directory where vcpkg artifacts will be installed.',
),
] = Path('build')

Expand Down
Loading
Loading