loganasherjones / yapconf

Yet Another Python Configuration
http://yapconf.readthedocs.io/en/stable/
MIT License
18 stars 4 forks source link

Fallback spec #72

Closed loganasherjones closed 6 years ago

loganasherjones commented 6 years ago

As brought up in part of #45, it would be nice to allow users to specify a fallback specification. Something like the following is a very common use-case:

from yapconf.spec import YapconfSpec

spec = YapconfSpec({
    'ssl': {
        'type': 'dict',
        'items': {
            'enabled': {
                'type': 'bool',
                'default': False,
                'description': 'Serve content using SSL',
            },
            'private_key': {
                'type': 'str',
                'description': 'Path to a private key',
                'required': False,
            },
            'public_key': {
                'type': 'str',
                'description': 'Path to a public key',
                'required': False,
            },
        },
    },
    'connection1': {
        'type': 'dict',
        'items': {
            'host': {
                'type': 'str',
                'description': 'The host',
            },
            # ssl config for this specific connection
            'ssl': {
                'type': 'dict',
                'fallback_spec': 'ssl'
            },
        },
    },
})

In this case, we would use the spec defined in the ssl key in order to handle the construction of the specification. What this would result in, is an ssl config item under connection1 that looks something like this:

'connection1': {
    'type': 'dict',
    'items': {
        'ssl': {
            'type': 'dict',
            'items': {
                'enabled': {
                    'type': 'bool',
                    'default': False,
                    'description': 'Serve content using SSL',
                    'fallback': 'ssl.enabled',
                },
                'private_key': {
                    'type': 'str',
                    'description': 'Path to a private key',
                    'fallback': 'ssl.private_key',
                },
                'public_key': {
                    'type': 'str',
                    'description': 'Path to a public key',
                    'fallback': 'ssl.public_key',
                },
            },
        }
    }
}
loganasherjones commented 6 years ago

One annoying thing to watch out for here is circular dependencies.

loganasherjones commented 6 years ago

I think there are too many possible issues from inheriting specifications. I believe the problem this particular use-case is trying to solve can be solved alternatively like this:

ssl_spec = {
            'type': 'dict',
            'items': {
                'enabled': {
                    'type': 'bool',
                    'default': False,
                    'description': 'Serve content using SSL',
                    'fallback': 'ssl.enabled',
                },
                'private_key': {
                    'type': 'str',
                    'description': 'Path to a private key',
                    'fallback': 'ssl.private_key',
                },
                'public_key': {
                    'type': 'str',
                    'description': 'Path to a public key',
                    'fallback': 'ssl.public_key',
                },
            },
}

Then you can simply use this spec in different parts:

spec = {
  'defaults': { 
    'type': 'dict', 
    'items': { 
      'ssl': ssl_spec
    } 
  }, 
  'connection1': {
    'type': 'dict', 
    'items': {
      'ssl': ssl_spec
    }
  }
}