toml-combine 0.1.7__py3-none-any.whl → 0.1.9__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/combiner.py +26 -10
- {toml_combine-0.1.7.dist-info → toml_combine-0.1.9.dist-info}/METADATA +116 -30
- {toml_combine-0.1.7.dist-info → toml_combine-0.1.9.dist-info}/RECORD +5 -5
- {toml_combine-0.1.7.dist-info → toml_combine-0.1.9.dist-info}/WHEEL +0 -0
- {toml_combine-0.1.7.dist-info → toml_combine-0.1.9.dist-info}/entry_points.txt +0 -0
    
        toml_combine/combiner.py
    CHANGED
    
    | @@ -5,7 +5,7 @@ import dataclasses | |
| 5 5 | 
             
            import itertools
         | 
| 6 6 | 
             
            from collections.abc import Mapping, Sequence
         | 
| 7 7 | 
             
            from functools import partial
         | 
| 8 | 
            -
            from typing import Any
         | 
| 8 | 
            +
            from typing import Any, TypeVar, Union
         | 
| 9 9 |  | 
| 10 10 | 
             
            from . import exceptions
         | 
| 11 11 |  | 
| @@ -24,7 +24,7 @@ class Output: | |
| 24 24 |  | 
| 25 25 | 
             
            @dataclasses.dataclass()
         | 
| 26 26 | 
             
            class Override:
         | 
| 27 | 
            -
                when: Mapping[str,  | 
| 27 | 
            +
                when: Mapping[str, list[str]]
         | 
| 28 28 | 
             
                config: Mapping[str, Any]
         | 
| 29 29 |  | 
| 30 30 | 
             
                def __str__(self) -> str:
         | 
| @@ -48,9 +48,12 @@ def wrap_in_list(value: str | list[str]) -> list[str]: | |
| 48 48 | 
             
                return value
         | 
| 49 49 |  | 
| 50 50 |  | 
| 51 | 
            +
            T = TypeVar("T", bound=Union[str, list[str]])
         | 
| 52 | 
            +
             | 
| 53 | 
            +
             | 
| 51 54 | 
             
            def clean_dimensions_dict(
         | 
| 52 | 
            -
                to_sort: Mapping[str,  | 
| 53 | 
            -
            ) -> dict[str,  | 
| 55 | 
            +
                to_sort: Mapping[str, T], clean: dict[str, list[str]], type: str
         | 
| 56 | 
            +
            ) -> dict[str, T]:
         | 
| 54 57 | 
             
                """
         | 
| 55 58 | 
             
                Recreate a dictionary of dimension values with the same order as the
         | 
| 56 59 | 
             
                dimensions list.
         | 
| @@ -148,7 +151,9 @@ def build_config(config: dict[str, Any]) -> Config: | |
| 148 151 | 
             
                    except KeyError:
         | 
| 149 152 | 
             
                        raise exceptions.MissingOverrideCondition(id=override)
         | 
| 150 153 |  | 
| 151 | 
            -
                     | 
| 154 | 
            +
                    when = {k: wrap_in_list(v) for k, v in when.items()}
         | 
| 155 | 
            +
             | 
| 156 | 
            +
                    conditions = tuple((k, tuple(v)) for k, v in when.items())
         | 
| 152 157 | 
             
                    if conditions in seen_conditions:
         | 
| 153 158 | 
             
                        raise exceptions.DuplicateError(type="override", id=when)
         | 
| 154 159 |  | 
| @@ -176,7 +181,6 @@ def build_config(config: dict[str, Any]) -> Config: | |
| 176 181 | 
             
                        output[key] = wrap_in_list(output[key])
         | 
| 177 182 |  | 
| 178 183 | 
             
                    for cartesian_product in itertools.product(*output.values()):
         | 
| 179 | 
            -
                        # Create a dictionary with the same keys as when
         | 
| 180 184 | 
             
                        single_output = dict(zip(output.keys(), cartesian_product))
         | 
| 181 185 |  | 
| 182 186 | 
             
                        conditions = tuple(single_output.items())
         | 
| @@ -200,6 +204,20 @@ def build_config(config: dict[str, Any]) -> Config: | |
| 200 204 | 
             
                )
         | 
| 201 205 |  | 
| 202 206 |  | 
| 207 | 
            +
            def output_matches_override(output: Output, override: Override) -> bool:
         | 
| 208 | 
            +
                """
         | 
| 209 | 
            +
                Check if the values in the override match the output dimensions.
         | 
| 210 | 
            +
                """
         | 
| 211 | 
            +
                for dim, values in override.when.items():
         | 
| 212 | 
            +
                    if dim not in output.dimensions:
         | 
| 213 | 
            +
                        return False
         | 
| 214 | 
            +
             | 
| 215 | 
            +
                    if output.dimensions[dim] not in values:
         | 
| 216 | 
            +
                        return False
         | 
| 217 | 
            +
             | 
| 218 | 
            +
                return True
         | 
| 219 | 
            +
             | 
| 220 | 
            +
             | 
| 203 221 | 
             
            def generate_output(
         | 
| 204 222 | 
             
                default: Mapping[str, Any], overrides: Sequence[Override], output: Output
         | 
| 205 223 | 
             
            ) -> dict[str, Any]:
         | 
| @@ -207,10 +225,8 @@ def generate_output( | |
| 207 225 | 
             
                # Apply each matching override
         | 
| 208 226 | 
             
                for override in overrides:
         | 
| 209 227 | 
             
                    # Check if all dimension values in the override match
         | 
| 210 | 
            -
             | 
| 211 | 
            -
             | 
| 212 | 
            -
                        for dim in override.when.keys()
         | 
| 213 | 
            -
                    ):
         | 
| 228 | 
            +
             | 
| 229 | 
            +
                    if output_matches_override(output=output, override=override):
         | 
| 214 230 | 
             
                        result = merge_configs(result, override.config)
         | 
| 215 231 |  | 
| 216 232 | 
             
                return {"dimensions": output.dimensions, **result}
         | 
| @@ -1,6 +1,6 @@ | |
| 1 1 | 
             
            Metadata-Version: 2.4
         | 
| 2 2 | 
             
            Name: toml-combine
         | 
| 3 | 
            -
            Version: 0.1. | 
| 3 | 
            +
            Version: 0.1.9
         | 
| 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
         | 
| @@ -146,6 +146,41 @@ This example is simple because `name` is a natural choice for the key. In some c | |
| 146 146 | 
             
            the choice is less natural, but you can always decide to name the elements of your
         | 
| 147 147 | 
             
            list and use that name as a key. Also, yes, you'll loose ordering.
         | 
| 148 148 |  | 
| 149 | 
            +
            ### CLI
         | 
| 150 | 
            +
             | 
| 151 | 
            +
            ```console
         | 
| 152 | 
            +
            $ toml-combine {path/to/config.toml}
         | 
| 153 | 
            +
            ```
         | 
| 154 | 
            +
             | 
| 155 | 
            +
            Generates all the outputs described by the given TOML config.
         | 
| 156 | 
            +
             | 
| 157 | 
            +
            Note that you can restrict generation to some dimension values by passing
         | 
| 158 | 
            +
            `--{dimension}={value}`
         | 
| 159 | 
            +
             | 
| 160 | 
            +
            ## Lib
         | 
| 161 | 
            +
             | 
| 162 | 
            +
            ```python
         | 
| 163 | 
            +
            import toml_combine
         | 
| 164 | 
            +
             | 
| 165 | 
            +
             | 
| 166 | 
            +
            result = toml_combine.combine(
         | 
| 167 | 
            +
                    config_file=config_file,
         | 
| 168 | 
            +
                    environment=["production", "staging"],
         | 
| 169 | 
            +
                    type="job",
         | 
| 170 | 
            +
                    job=["manage", "special-command"],
         | 
| 171 | 
            +
                )
         | 
| 172 | 
            +
             | 
| 173 | 
            +
            print(result)
         | 
| 174 | 
            +
            {
         | 
| 175 | 
            +
              "production-job-manage": {...},
         | 
| 176 | 
            +
              "production-job-special-command": {...},
         | 
| 177 | 
            +
              "staging-job-manage": {...},
         | 
| 178 | 
            +
              "staging-job-special-command": {...},
         | 
| 179 | 
            +
            }
         | 
| 180 | 
            +
            ```
         | 
| 181 | 
            +
             | 
| 182 | 
            +
            You can pass either `config` (TOML string or dict) or `config_file` (`pathlib.Path` or string path) to `combine()`. Additional `kwargs` restrict the output.
         | 
| 183 | 
            +
             | 
| 149 184 | 
             
            ### A bigger example
         | 
| 150 185 |  | 
| 151 186 | 
             
            ```toml
         | 
| @@ -181,39 +216,90 @@ container.port = 8080 | |
| 181 216 | 
             
            name = "service-dev"
         | 
| 182 217 | 
             
            when.environment = "dev"
         | 
| 183 218 | 
             
            container.env.DEBUG = true
         | 
| 184 | 
            -
            ```
         | 
| 185 | 
            -
             | 
| 186 | 
            -
            ### CLI
         | 
| 187 219 |  | 
| 188 | 
            -
             | 
| 189 | 
            -
             | 
| 220 | 
            +
            [[override]]
         | 
| 221 | 
            +
            when.environment = ["staging", "dev"]
         | 
| 222 | 
            +
            when.service = "backend"
         | 
| 223 | 
            +
            container.env.ENABLE_EXPENSIVE_MONITORING = false
         | 
| 190 224 | 
             
            ```
         | 
| 191 225 |  | 
| 192 | 
            -
             | 
| 193 | 
            -
             | 
| 194 | 
            -
            Note that you can restrict generation to some dimension values by passing
         | 
| 195 | 
            -
            `--{dimension}={value}`
         | 
| 226 | 
            +
            This produces the following configs:
         | 
| 196 227 |  | 
| 197 | 
            -
             | 
| 198 | 
            -
             | 
| 199 | 
            -
            ```python
         | 
| 200 | 
            -
            import toml_combine
         | 
| 201 | 
            -
             | 
| 202 | 
            -
             | 
| 203 | 
            -
            result = toml_combine.combine(
         | 
| 204 | 
            -
                    config_file=config_file,
         | 
| 205 | 
            -
                    environment=["production", "staging"],
         | 
| 206 | 
            -
                    type="job",
         | 
| 207 | 
            -
                    job=["manage", "special-command"],
         | 
| 208 | 
            -
                )
         | 
| 209 | 
            -
             | 
| 210 | 
            -
            print(result)
         | 
| 228 | 
            +
            ```json
         | 
| 211 229 | 
             
            {
         | 
| 212 | 
            -
              "production- | 
| 213 | 
            -
             | 
| 214 | 
            -
             | 
| 215 | 
            -
             | 
| 230 | 
            +
              "production-frontend-eu": {
         | 
| 231 | 
            +
                "dimensions": {
         | 
| 232 | 
            +
                  "environment": "production",
         | 
| 233 | 
            +
                  "service": "frontend",
         | 
| 234 | 
            +
                  "region": "eu"
         | 
| 235 | 
            +
                },
         | 
| 236 | 
            +
                "registry": "gcr.io/my-project/",
         | 
| 237 | 
            +
                "service_account": "my-service-account",
         | 
| 238 | 
            +
                "name": "service-frontend",
         | 
| 239 | 
            +
                "container": {
         | 
| 240 | 
            +
                  "image_name": "my-image-frontend"
         | 
| 241 | 
            +
                }
         | 
| 242 | 
            +
              },
         | 
| 243 | 
            +
              "production-backend-eu": {
         | 
| 244 | 
            +
                "dimensions": {
         | 
| 245 | 
            +
                  "environment": "production",
         | 
| 246 | 
            +
                  "service": "backend",
         | 
| 247 | 
            +
                  "region": "eu"
         | 
| 248 | 
            +
                },
         | 
| 249 | 
            +
                "registry": "gcr.io/my-project/",
         | 
| 250 | 
            +
                "service_account": "my-service-account",
         | 
| 251 | 
            +
                "name": "service-backend",
         | 
| 252 | 
            +
                "container": {
         | 
| 253 | 
            +
                  "image_name": "my-image-backend",
         | 
| 254 | 
            +
                  "port": 8080
         | 
| 255 | 
            +
                }
         | 
| 256 | 
            +
              },
         | 
| 257 | 
            +
              "staging-frontend-eu": {
         | 
| 258 | 
            +
                "dimensions": {
         | 
| 259 | 
            +
                  "environment": "staging",
         | 
| 260 | 
            +
                  "service": "frontend",
         | 
| 261 | 
            +
                  "region": "eu"
         | 
| 262 | 
            +
                },
         | 
| 263 | 
            +
                "registry": "gcr.io/my-project/",
         | 
| 264 | 
            +
                "service_account": "my-service-account",
         | 
| 265 | 
            +
                "name": "service-frontend",
         | 
| 266 | 
            +
                "container": {
         | 
| 267 | 
            +
                  "image_name": "my-image-frontend"
         | 
| 268 | 
            +
                }
         | 
| 269 | 
            +
              },
         | 
| 270 | 
            +
              "staging-backend-eu": {
         | 
| 271 | 
            +
                "dimensions": {
         | 
| 272 | 
            +
                  "environment": "staging",
         | 
| 273 | 
            +
                  "service": "backend",
         | 
| 274 | 
            +
                  "region": "eu"
         | 
| 275 | 
            +
                },
         | 
| 276 | 
            +
                "registry": "gcr.io/my-project/",
         | 
| 277 | 
            +
                "service_account": "my-service-account",
         | 
| 278 | 
            +
                "name": "service-backend",
         | 
| 279 | 
            +
                "container": {
         | 
| 280 | 
            +
                  "image_name": "my-image-backend",
         | 
| 281 | 
            +
                  "port": 8080,
         | 
| 282 | 
            +
                  "env": {
         | 
| 283 | 
            +
                    "ENABLE_EXPENSIVE_MONITORING": false
         | 
| 284 | 
            +
                  }
         | 
| 285 | 
            +
                }
         | 
| 286 | 
            +
              },
         | 
| 287 | 
            +
              "dev-backend": {
         | 
| 288 | 
            +
                "dimensions": {
         | 
| 289 | 
            +
                  "environment": "dev",
         | 
| 290 | 
            +
                  "service": "backend"
         | 
| 291 | 
            +
                },
         | 
| 292 | 
            +
                "registry": "gcr.io/my-project/",
         | 
| 293 | 
            +
                "service_account": "my-service-account",
         | 
| 294 | 
            +
                "name": "service-backend",
         | 
| 295 | 
            +
                "container": {
         | 
| 296 | 
            +
                  "env": {
         | 
| 297 | 
            +
                    "DEBUG": true,
         | 
| 298 | 
            +
                    "ENABLE_EXPENSIVE_MONITORING": false
         | 
| 299 | 
            +
                  },
         | 
| 300 | 
            +
                  "image_name": "my-image-backend",
         | 
| 301 | 
            +
                  "port": 8080
         | 
| 302 | 
            +
                }
         | 
| 303 | 
            +
              }
         | 
| 216 304 | 
             
            }
         | 
| 217 305 | 
             
            ```
         | 
| 218 | 
            -
             | 
| 219 | 
            -
            You can pass either `config` (TOML string or dict) or `config_file` (`pathlib.Path` or string path) to `combine()`. Additional `kwargs` restrict the output.
         | 
| @@ -1,10 +1,10 @@ | |
| 1 1 | 
             
            toml_combine/__init__.py,sha256=l7i0GkM9k7cc__wj1yqK5XjpB3IJ0jqFU63tqKMuYlY,1625
         | 
| 2 2 | 
             
            toml_combine/__main__.py,sha256=hmF8N8xX6UEApzbKTVZ-4E1HU5-rjgUkdXNLO-mF6vo,100
         | 
| 3 3 | 
             
            toml_combine/cli.py,sha256=MZrAEP4wt6f9Qn0TEXIjeLoQMlvQulFpkMciwU8GRO4,2328
         | 
| 4 | 
            -
            toml_combine/combiner.py,sha256= | 
| 4 | 
            +
            toml_combine/combiner.py,sha256=_sSOCVBlv8ljAdMd6BEthS6rxiCnt-VV9rMEPSK_Cvk,7643
         | 
| 5 5 | 
             
            toml_combine/exceptions.py,sha256=SepRFDxeWQEbD88jhF5g7laZSSULthho83BpW8u9RWs,897
         | 
| 6 6 | 
             
            toml_combine/toml.py,sha256=_vCINvfJeS3gWid35Pmm3Yz4xyJ8LpKJRHL0axSU8nk,384
         | 
| 7 | 
            -
            toml_combine-0.1. | 
| 8 | 
            -
            toml_combine-0.1. | 
| 9 | 
            -
            toml_combine-0.1. | 
| 10 | 
            -
            toml_combine-0.1. | 
| 7 | 
            +
            toml_combine-0.1.9.dist-info/METADATA,sha256=ti8e_ng-_KdRPCAJybModogRhP4guqH8UilQTeXQHAk,8375
         | 
| 8 | 
            +
            toml_combine-0.1.9.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
         | 
| 9 | 
            +
            toml_combine-0.1.9.dist-info/entry_points.txt,sha256=dXUQNom54uZt_7ylEG81iNYMamYpaFo9-ItcZJU6Uzc,58
         | 
| 10 | 
            +
            toml_combine-0.1.9.dist-info/RECORD,,
         | 
| 
            File without changes
         | 
| 
            File without changes
         |