toml-combine 1.0.1__py3-none-any.whl → 1.0.2__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
toml_combine/cli.py CHANGED
@@ -70,7 +70,7 @@ def cli(argv) -> int:
70
70
  try:
71
71
  config = combiner.build_config(dict_config)
72
72
  except exceptions.TomlCombineError as exc:
73
- print(exc, file=sys.stderr)
73
+ print(f"Error: {exc}", file=sys.stderr)
74
74
  return 1
75
75
 
76
76
  # Parse all arguments
@@ -86,7 +86,7 @@ def cli(argv) -> int:
86
86
  try:
87
87
  result = lib.combine(config=dict_config, **mapping)
88
88
  except exceptions.TomlCombineError as exc:
89
- print(exc, file=sys.stderr)
89
+ print(f"Error: {exc}", file=sys.stderr)
90
90
  return 1
91
91
 
92
92
  if args.format == "toml":
toml_combine/combiner.py CHANGED
@@ -21,6 +21,7 @@ class Override:
21
21
  class Config:
22
22
  dimensions: Mapping[str, list[str]]
23
23
  default: Mapping[str, Any]
24
+ # List of overrides, in order of increasing specificity
24
25
  overrides: Sequence[Override]
25
26
 
26
27
 
@@ -30,6 +31,7 @@ def clean_dimensions_dict(
30
31
  """
31
32
  Recreate a dictionary of dimension values with the same order as the
32
33
  dimensions list.
34
+ Also check that the values are valid.
33
35
  """
34
36
  result = {}
35
37
  if invalid_dimensions := set(to_sort) - set(clean):
@@ -63,7 +65,7 @@ T = TypeVar("T", dict, list, str, int, float, bool)
63
65
 
64
66
  def merge_configs(a: T, b: T, /) -> T:
65
67
  """
66
- Recursively merge two configuration dictionaries, with b taking precedence.
68
+ Recursively merge two configuration dictionaries a and b, with b taking precedence.
67
69
  """
68
70
  if isinstance(a, dict) != isinstance(b, dict):
69
71
  raise ValueError(f"Cannot merge {type(a)} with {type(b)}")
@@ -116,6 +118,9 @@ def are_conditions_compatible(
116
118
 
117
119
 
118
120
  def build_config(config: dict[str, Any]) -> Config:
121
+ """
122
+ Build a finalized Config object from the given configuration dictionary.
123
+ """
119
124
  config = copy.deepcopy(config)
120
125
  # Parse dimensions
121
126
  dimensions = config.pop("dimensions")
@@ -165,6 +170,13 @@ def generate_for_mapping(
165
170
  config: Config,
166
171
  mapping: Mapping[str, str],
167
172
  ) -> Mapping[str, Any]:
173
+ """
174
+ Generate a configuration based on the provided mapping of dimension values.
175
+ The mapping should contain only the dimensions defined in the config.
176
+ If a dimension is not defined in the mapping, the default value for that
177
+ dimension will be used.
178
+ """
179
+
168
180
  result = copy.deepcopy(config.default)
169
181
  keys_to_conditions: dict[tuple[str, ...], list[Mapping[str, list[str]]]] = {}
170
182
  # Apply each matching override
@@ -20,7 +20,7 @@ class TomlEncodeError(TomlCombineError):
20
20
 
21
21
 
22
22
  class IncompatibleOverrides(TomlCombineError):
23
- """In override {id}: Overrides defining the same configuration keys must be included in one another or mutually exclusive.\nKey defined multiple times: {key}\nOther override: {other_override}"""
23
+ """Incompatible overrides `{id}` and `{other_override}`: When they're both applicable, overrides defining a common overridden key ({key}) must be a subset of one another"""
24
24
 
25
25
 
26
26
  class DimensionNotFound(TomlCombineError):
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: toml-combine
3
- Version: 1.0.1
3
+ Version: 1.0.2
4
4
  Summary: A tool for combining complex configurations in TOML format.
5
5
  Author-email: Joachim Jablon <ewjoachim@gmail.com>
6
6
  License-Expression: MIT
@@ -68,29 +68,58 @@ The common configuration to start from, before we start overlaying overrides on
68
68
 
69
69
  ### Overrides
70
70
 
71
- Overrides define a set of condition where they apply (`when.<dimension> =
72
- "<value>"`) and the values that are overridgden when they're applicable.
73
-
74
- - In case 2 overrides are applicable and define a value for the same key, if one is more
75
- specific than the other (e.g. env=prod,region=us is more specific than env=prod) then
76
- its values will have precedence.
77
- - If 2 applicable overrides both define a dimension that the other one doesn't, they're
78
- incompatible, and running the tool with a configuration that would select both of them
79
- will yield an error.
80
-
81
- Examples:
82
- - Override 1: `env=staging` & Override 2: `region=eu` are incompatible (1 defines
83
- `env` not in 2, 2 defines `region` not in 1).
84
- - Override 1: `env=staging` & Override 2: `env=staging, region=eu` are compatible
85
- (all dimensions defined in 1 are also in 2)
86
- - Override 1: `env=staging` & Override 2: `env=prod` are compatible
87
- (they define the same dimensions)
88
- - Override 1: `env=staging, service=frontend` & Override 2: `region=eu, service=frontend`
89
- are incompatible (1 defines `env` not in 2, 2 defines `region` not in 1)
71
+ Each override defines a set of condition where it applies (`when.<dimension> =
72
+ "<dimension_value>"`) and a set of overridden key/values.
73
+
74
+ ```toml
75
+ [[override]]
76
+ # Conditions
77
+ when.environment = "staging"
78
+ when.region = "us"
79
+
80
+ # Overridden keys / values
81
+ service_account = "my-us-staging-service-account"
82
+ ```
83
+
84
+ If two overrides are both applicable in the same run of `toml-combine`, they will be
85
+ checked for _compatibility_ with one another, and an error if they're not compatible.
86
+
87
+ Compatibility rules:
88
+
89
+ - If the two overrides don't share any overridden key, then they're always compatible.
90
+ - If the conditions of an override are a subset of the condition of the other one,
91
+ they're compatible. Also, in that case, the overridden values of the more specific one
92
+ **will have precedence**.
93
+ - If they both define a dimension that the other one doesn't, they're incompatible.
94
+
95
+ Example of incompatible overrides: neither is a subset of the other one and they both
96
+ define a value for `foo`:
97
+
98
+ ```toml
99
+ [dimensions]
100
+ environment = ["staging"]
101
+ region = ["eu"]
102
+
103
+ [[override]]
104
+ when.environment = "staging"
105
+ foo = "bar"
106
+
107
+ [[override]]
108
+ when.region = "eu"
109
+ foo = "baz"
110
+ ```
111
+
112
+ ```console
113
+ $ toml-combine config.toml --environment=staging --region=eu
114
+ Error: Incompatible overrides `{'region': ['eu']}` and `{'environment': ['staging']}`:
115
+ When they're both applicable, overrides defining a common overridden key (foo) must be
116
+ a subset of one another
117
+ ```
90
118
 
91
119
  > [!Note]
92
120
  > Instead of defining a single value for the override dimensions, you can define a list.
93
121
  > This is a shortcut to duplicating the override with each individual value:
122
+ >
94
123
  > ```
95
124
  > [[override]]
96
125
  > when.environment = ["staging", "prod"]
@@ -0,0 +1,12 @@
1
+ toml_combine/__init__.py,sha256=TDkOwwEM-nS6hOh79u9Qae6g2Q6VfANpPpnKGfSgu80,84
2
+ toml_combine/__main__.py,sha256=hmF8N8xX6UEApzbKTVZ-4E1HU5-rjgUkdXNLO-mF6vo,100
3
+ toml_combine/cli.py,sha256=1eeh6sdKLsn5klRSc7E1rcBhN5Cf1O1Za5-Ule9FRVU,2867
4
+ toml_combine/combiner.py,sha256=fjsZ4WAKl7uO8BE8lYirJgo_1uj1t2o24rJA_FT1NFM,6147
5
+ toml_combine/exceptions.py,sha256=KrZpSdaI_ssYKw9LMsc3PAqNXEP-q6sT9scpgpXOo8o,1094
6
+ toml_combine/lib.py,sha256=jh6OG57JefpGa-WE-mLSIK6KjyJ0-1yGBynr_kiVTww,1634
7
+ toml_combine/toml.py,sha256=iBV8xj0qWcvGp2AZaML8FCT3i2X9DL7iA6jd-wcP5Bc,814
8
+ toml_combine-1.0.2.dist-info/METADATA,sha256=HUlO98eoZxeR0ZkvbmkB5VjZfcEmRkr1ZoP4p9RqvMU,9122
9
+ toml_combine-1.0.2.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
10
+ toml_combine-1.0.2.dist-info/entry_points.txt,sha256=dXUQNom54uZt_7ylEG81iNYMamYpaFo9-ItcZJU6Uzc,58
11
+ toml_combine-1.0.2.dist-info/licenses/LICENSE,sha256=tA7wpipzIPGl7xL5xzMMg0RhhXz9CKOa-ZnlYzgiTKg,1059
12
+ toml_combine-1.0.2.dist-info/RECORD,,
@@ -1,12 +0,0 @@
1
- toml_combine/__init__.py,sha256=TDkOwwEM-nS6hOh79u9Qae6g2Q6VfANpPpnKGfSgu80,84
2
- toml_combine/__main__.py,sha256=hmF8N8xX6UEApzbKTVZ-4E1HU5-rjgUkdXNLO-mF6vo,100
3
- toml_combine/cli.py,sha256=hG03eDKz7xU-ydJIa1kDuu6WlFzNS3GTMJ6zals9M9c,2843
4
- toml_combine/combiner.py,sha256=HG7KV3EGwmcHOMruhp7sMkH-uXqWKpsO7_BvhNQ2KQY,5668
5
- toml_combine/exceptions.py,sha256=cRAZhxg3OHgzp5hJzyxNGG_jvGUm8gG8XzndQXBhvo8,1116
6
- toml_combine/lib.py,sha256=jh6OG57JefpGa-WE-mLSIK6KjyJ0-1yGBynr_kiVTww,1634
7
- toml_combine/toml.py,sha256=iBV8xj0qWcvGp2AZaML8FCT3i2X9DL7iA6jd-wcP5Bc,814
8
- toml_combine-1.0.1.dist-info/METADATA,sha256=K0j97FCiS7tpENiP_HVoxE1b6_nLDqk_E1OklTtFhpk,8812
9
- toml_combine-1.0.1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
10
- toml_combine-1.0.1.dist-info/entry_points.txt,sha256=dXUQNom54uZt_7ylEG81iNYMamYpaFo9-ItcZJU6Uzc,58
11
- toml_combine-1.0.1.dist-info/licenses/LICENSE,sha256=tA7wpipzIPGl7xL5xzMMg0RhhXz9CKOa-ZnlYzgiTKg,1059
12
- toml_combine-1.0.1.dist-info/RECORD,,