-
Notifications
You must be signed in to change notification settings - Fork 215
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add default values handling. Fixes #12. #19
base: master
Are you sure you want to change the base?
Conversation
Hm, seems like |
In this implementation, So if we remove Hence if you want to remove one, I suggest removing Tell me what do you think about it and if you want me to update the PR to remove it. Edit: an other argument for keeping |
I never needed this feature, so I'm not totally sure which API is better yet. |
@reedboat: as you opened the issue, could you share your thought about the API I described on this PR? Thanks! |
+1 |
I prefer the |
We seems to move for a consensus against While I was at it, I also rebased on master, and made a little change to take into account #41. Should be easier to merge that way :-) Edit:
|
Hey @Rogdham, I finally had some time to look over your code. I added some comments to here Aside from my comments, I wonder if the design would be a bit cleaner with a chad. |
Sorry for taking so long. Recently I actually needed to have some default functionality with schema. Here are my thoughts: The default value should be used only if no value is provided, not if value is not validated. The later would make errors pass silently. "Value not provided" could mean different thing, e.g.: a dictionary key is missing altogether, or a value is If we take only "key is missing" as a reason to apply a default, then a nice API for that would be: Schema({Optional('key', default='DEFAULT'): str) If we take only "value is Schema({'key': Schema(str, default='DEFAULT')}) But I don't want to add Maybe we should have a Schema({'key': WithDefault(str, 'DEFAULT')}) Another option is to have a Default('DEFAULT').valudate(None) => 'DEFAULT'
Default('DEFAULT').validate(1234) => SchemaError This would allow it to be used as: schema = Schema({'key': Or(str, Default('DEFAULT')})
schema.validate({'key': None}) => {'key': 'DEFAULT'}
schema.validate({'key': 1234}) => {'key': 1234} I think I prefer the last variant the most. It can also be extended for cases when non- Or(str, Default('DEFAULT', when='')).validate('') => 'DEFAULT' On the negative side, this would not work for keys that are not present. Schema({Optional('key', Default('DEFAULT')): str}) What is your opinion? And sorry for being a shitty maintainer and leaving this pull request hanging for more than a year. |
I like |
@chadrik: Let me try to sum up for clarity what you're suggesting (the main points):
Here are my answers:
@halst: I guess we should consider the API with more intensity before coding anything. There has been some discussion though, which may be worth re-reading. I'm not sure if this is the best place to discuss the API, as this is a PR on a particular API ; maybe it is better to discuss the API in #12 ? However, there is one thing I find bizarre with some of the API you mentioned. Schema({Optional('key', default='DEFAULT'): str) I believe this is a pitfall worth considering. As you have understood, I am against it, and my preference goes to the definition of a default value in the value part of the dict. To give a more in-depth example, consider what is in the API of this PR: default for keys as well: >>> Schema({Optional(int, default=42): Use(str, default='The answer')}).validate({})
{42: 'The answer'} An other point: you mentioned that using the default could be triggered when there is no value for a specific key, or when that value is Last but not least, you mentioned that you would prefer not relying on inheritance for defaults handling (see point 2 on top of that message). Could you elaborate on that a little bit, so that we could understand why it is not a good idea? |
This is a more or less religious thingy I have: I believe in duck-typing and that types don't matter—the interface matters. We should avoid making users of schema subclass anything. I find it hard to justify this opinion, but I have one example: Imagine a user of schema testing something. If they are required to subclass something, they are forced to make a subclass even for a throw-away scenario. However, if they are not forced to subclass, they can just pass a stub for testing. |
Schema({Optional(int, default=42): Use(str, default='The answer')}) In case of passing |
@andor44 I'm not sure I follow you. I don't see much difference between |
As you described it, I'd imagined |
This PR adds a way to handle default values for optional keys, as requested by #12.
You can pass the
default
keyword argument quite everywhere to specify a default, and that default is used if the corresponding key is optional:You can also use the
Default
class, which wraps whatever you gave as the first argument, and tries to find the appropriate default value (here0
for anint
):Of course, your need to give a proper default value, or else it complains, raising a
ValueError
(I think it is important that this is not aSchemaError
, because that one means that the programmer made a mistake, nothing to do with the user data to validate):And in case your optional key is a
type
, you can specify its default value as well:Tell me what you think!