Pydantic: Make field None in validator based on other field's value
I'm using the pydantic BaseModel with a validator like this:
from datetime import date
from typing import List, Optional
from pydantic import BaseModel, BaseConfig, validator
class Model(BaseModel):
class Config(BaseConfig):
allow_population_by_alias = True
fields = {
"some_date": {
"alias": "some_list"
}
}
some_date: Optional[date]
some_list: List[date]
@validator("some_date", pre=True, always=True)
def validate_date(cls, value):
if len(value) < 2: # here value is some_list
return None
return value[0] # return the first value - let's assume it's a date string
# This reproduces the problem
m = Model(some_list=['2019-01-03'])
I would like to compute the value of some_date based on the value of some_list and make it None if a certain condition met.
My JSON never contains the field some_date, it's always populated based on some_list hence pre=True, always=True. However the default validator for some_date will run after my custom one, which will fail if validate_date returns None.
Is there a way to create such a field which is only computed by another one and still can be Optional?
python
add a comment |
I'm using the pydantic BaseModel with a validator like this:
from datetime import date
from typing import List, Optional
from pydantic import BaseModel, BaseConfig, validator
class Model(BaseModel):
class Config(BaseConfig):
allow_population_by_alias = True
fields = {
"some_date": {
"alias": "some_list"
}
}
some_date: Optional[date]
some_list: List[date]
@validator("some_date", pre=True, always=True)
def validate_date(cls, value):
if len(value) < 2: # here value is some_list
return None
return value[0] # return the first value - let's assume it's a date string
# This reproduces the problem
m = Model(some_list=['2019-01-03'])
I would like to compute the value of some_date based on the value of some_list and make it None if a certain condition met.
My JSON never contains the field some_date, it's always populated based on some_list hence pre=True, always=True. However the default validator for some_date will run after my custom one, which will fail if validate_date returns None.
Is there a way to create such a field which is only computed by another one and still can be Optional?
python
I'm getting an exception when executing your code:NameError: Field name "fields" shadows a BaseModel attribute; use a different field name with "alias='fields'".Something special to take into account? (Testing with python3.6 and pydantic 0.17)
– normanius
Jan 3 at 14:35
@normanius my bad, forgot thatallow...andfieldswere in an inner Config class
– Dániel Nagy
Jan 3 at 14:42
btw I'm trying with python 3.6.1 and pydantic 0.16.1
– Dániel Nagy
Jan 3 at 14:44
add a comment |
I'm using the pydantic BaseModel with a validator like this:
from datetime import date
from typing import List, Optional
from pydantic import BaseModel, BaseConfig, validator
class Model(BaseModel):
class Config(BaseConfig):
allow_population_by_alias = True
fields = {
"some_date": {
"alias": "some_list"
}
}
some_date: Optional[date]
some_list: List[date]
@validator("some_date", pre=True, always=True)
def validate_date(cls, value):
if len(value) < 2: # here value is some_list
return None
return value[0] # return the first value - let's assume it's a date string
# This reproduces the problem
m = Model(some_list=['2019-01-03'])
I would like to compute the value of some_date based on the value of some_list and make it None if a certain condition met.
My JSON never contains the field some_date, it's always populated based on some_list hence pre=True, always=True. However the default validator for some_date will run after my custom one, which will fail if validate_date returns None.
Is there a way to create such a field which is only computed by another one and still can be Optional?
python
I'm using the pydantic BaseModel with a validator like this:
from datetime import date
from typing import List, Optional
from pydantic import BaseModel, BaseConfig, validator
class Model(BaseModel):
class Config(BaseConfig):
allow_population_by_alias = True
fields = {
"some_date": {
"alias": "some_list"
}
}
some_date: Optional[date]
some_list: List[date]
@validator("some_date", pre=True, always=True)
def validate_date(cls, value):
if len(value) < 2: # here value is some_list
return None
return value[0] # return the first value - let's assume it's a date string
# This reproduces the problem
m = Model(some_list=['2019-01-03'])
I would like to compute the value of some_date based on the value of some_list and make it None if a certain condition met.
My JSON never contains the field some_date, it's always populated based on some_list hence pre=True, always=True. However the default validator for some_date will run after my custom one, which will fail if validate_date returns None.
Is there a way to create such a field which is only computed by another one and still can be Optional?
python
python
edited Jan 3 at 22:18
normanius
1,6701332
1,6701332
asked Jan 3 at 13:59
Dániel NagyDániel Nagy
8,83273651
8,83273651
I'm getting an exception when executing your code:NameError: Field name "fields" shadows a BaseModel attribute; use a different field name with "alias='fields'".Something special to take into account? (Testing with python3.6 and pydantic 0.17)
– normanius
Jan 3 at 14:35
@normanius my bad, forgot thatallow...andfieldswere in an inner Config class
– Dániel Nagy
Jan 3 at 14:42
btw I'm trying with python 3.6.1 and pydantic 0.16.1
– Dániel Nagy
Jan 3 at 14:44
add a comment |
I'm getting an exception when executing your code:NameError: Field name "fields" shadows a BaseModel attribute; use a different field name with "alias='fields'".Something special to take into account? (Testing with python3.6 and pydantic 0.17)
– normanius
Jan 3 at 14:35
@normanius my bad, forgot thatallow...andfieldswere in an inner Config class
– Dániel Nagy
Jan 3 at 14:42
btw I'm trying with python 3.6.1 and pydantic 0.16.1
– Dániel Nagy
Jan 3 at 14:44
I'm getting an exception when executing your code:
NameError: Field name "fields" shadows a BaseModel attribute; use a different field name with "alias='fields'". Something special to take into account? (Testing with python3.6 and pydantic 0.17)– normanius
Jan 3 at 14:35
I'm getting an exception when executing your code:
NameError: Field name "fields" shadows a BaseModel attribute; use a different field name with "alias='fields'". Something special to take into account? (Testing with python3.6 and pydantic 0.17)– normanius
Jan 3 at 14:35
@normanius my bad, forgot that
allow... and fields were in an inner Config class– Dániel Nagy
Jan 3 at 14:42
@normanius my bad, forgot that
allow... and fields were in an inner Config class– Dániel Nagy
Jan 3 at 14:42
btw I'm trying with python 3.6.1 and pydantic 0.16.1
– Dániel Nagy
Jan 3 at 14:44
btw I'm trying with python 3.6.1 and pydantic 0.16.1
– Dániel Nagy
Jan 3 at 14:44
add a comment |
1 Answer
1
active
oldest
votes
I'm inclined to say that this is not possible in the way you try.
You correctly pointed out that the default validator for date is called after the custom validate_date from your data model. The relevant source code can be found here: pydantic.fields.py (as of Jan 2019, git-hash: 19320bf). Apparently, the allow_none-mode is not supported for a cascade of validators, see pydantic.Field._apply_validators for details. More concretely, the output of a particular validator is never tested for None, that test is done further upstream in Model.validate.
From skim reading documentation and source of pydantic, I tend to to say that pydantic's validation mechanism currently has very limited support for type-transformations (list -> date, list -> NoneType) within the validation functions. If you have good arguments for your use-case, you may want to request that feature here.
Taking a step back, however, your approach using an alias and the flag allow_population_by_alias (which is not recommended, anyways, as stated in the documentation) seems a bit overloaded. some_date is needed only as a shortcut for some_list[0] if len(some_list) >= 2 else None, but it's never set independently from some_list. If that's really the case, why not opting for the following, much simpler option?
class Model(BaseModel):
some_list: List[date] = ...
@property
def some_date(self):
return None if len(self.some_list) < 2 else self.some_list[0]
I was wondering if my approach was possible at all, but you are right, this problem shouldn’t be solved like this
– Dániel Nagy
Jan 3 at 19:52
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f54023782%2fpydantic-make-field-none-in-validator-based-on-other-fields-value%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
I'm inclined to say that this is not possible in the way you try.
You correctly pointed out that the default validator for date is called after the custom validate_date from your data model. The relevant source code can be found here: pydantic.fields.py (as of Jan 2019, git-hash: 19320bf). Apparently, the allow_none-mode is not supported for a cascade of validators, see pydantic.Field._apply_validators for details. More concretely, the output of a particular validator is never tested for None, that test is done further upstream in Model.validate.
From skim reading documentation and source of pydantic, I tend to to say that pydantic's validation mechanism currently has very limited support for type-transformations (list -> date, list -> NoneType) within the validation functions. If you have good arguments for your use-case, you may want to request that feature here.
Taking a step back, however, your approach using an alias and the flag allow_population_by_alias (which is not recommended, anyways, as stated in the documentation) seems a bit overloaded. some_date is needed only as a shortcut for some_list[0] if len(some_list) >= 2 else None, but it's never set independently from some_list. If that's really the case, why not opting for the following, much simpler option?
class Model(BaseModel):
some_list: List[date] = ...
@property
def some_date(self):
return None if len(self.some_list) < 2 else self.some_list[0]
I was wondering if my approach was possible at all, but you are right, this problem shouldn’t be solved like this
– Dániel Nagy
Jan 3 at 19:52
add a comment |
I'm inclined to say that this is not possible in the way you try.
You correctly pointed out that the default validator for date is called after the custom validate_date from your data model. The relevant source code can be found here: pydantic.fields.py (as of Jan 2019, git-hash: 19320bf). Apparently, the allow_none-mode is not supported for a cascade of validators, see pydantic.Field._apply_validators for details. More concretely, the output of a particular validator is never tested for None, that test is done further upstream in Model.validate.
From skim reading documentation and source of pydantic, I tend to to say that pydantic's validation mechanism currently has very limited support for type-transformations (list -> date, list -> NoneType) within the validation functions. If you have good arguments for your use-case, you may want to request that feature here.
Taking a step back, however, your approach using an alias and the flag allow_population_by_alias (which is not recommended, anyways, as stated in the documentation) seems a bit overloaded. some_date is needed only as a shortcut for some_list[0] if len(some_list) >= 2 else None, but it's never set independently from some_list. If that's really the case, why not opting for the following, much simpler option?
class Model(BaseModel):
some_list: List[date] = ...
@property
def some_date(self):
return None if len(self.some_list) < 2 else self.some_list[0]
I was wondering if my approach was possible at all, but you are right, this problem shouldn’t be solved like this
– Dániel Nagy
Jan 3 at 19:52
add a comment |
I'm inclined to say that this is not possible in the way you try.
You correctly pointed out that the default validator for date is called after the custom validate_date from your data model. The relevant source code can be found here: pydantic.fields.py (as of Jan 2019, git-hash: 19320bf). Apparently, the allow_none-mode is not supported for a cascade of validators, see pydantic.Field._apply_validators for details. More concretely, the output of a particular validator is never tested for None, that test is done further upstream in Model.validate.
From skim reading documentation and source of pydantic, I tend to to say that pydantic's validation mechanism currently has very limited support for type-transformations (list -> date, list -> NoneType) within the validation functions. If you have good arguments for your use-case, you may want to request that feature here.
Taking a step back, however, your approach using an alias and the flag allow_population_by_alias (which is not recommended, anyways, as stated in the documentation) seems a bit overloaded. some_date is needed only as a shortcut for some_list[0] if len(some_list) >= 2 else None, but it's never set independently from some_list. If that's really the case, why not opting for the following, much simpler option?
class Model(BaseModel):
some_list: List[date] = ...
@property
def some_date(self):
return None if len(self.some_list) < 2 else self.some_list[0]
I'm inclined to say that this is not possible in the way you try.
You correctly pointed out that the default validator for date is called after the custom validate_date from your data model. The relevant source code can be found here: pydantic.fields.py (as of Jan 2019, git-hash: 19320bf). Apparently, the allow_none-mode is not supported for a cascade of validators, see pydantic.Field._apply_validators for details. More concretely, the output of a particular validator is never tested for None, that test is done further upstream in Model.validate.
From skim reading documentation and source of pydantic, I tend to to say that pydantic's validation mechanism currently has very limited support for type-transformations (list -> date, list -> NoneType) within the validation functions. If you have good arguments for your use-case, you may want to request that feature here.
Taking a step back, however, your approach using an alias and the flag allow_population_by_alias (which is not recommended, anyways, as stated in the documentation) seems a bit overloaded. some_date is needed only as a shortcut for some_list[0] if len(some_list) >= 2 else None, but it's never set independently from some_list. If that's really the case, why not opting for the following, much simpler option?
class Model(BaseModel):
some_list: List[date] = ...
@property
def some_date(self):
return None if len(self.some_list) < 2 else self.some_list[0]
edited Jan 3 at 20:03
answered Jan 3 at 19:39
normaniusnormanius
1,6701332
1,6701332
I was wondering if my approach was possible at all, but you are right, this problem shouldn’t be solved like this
– Dániel Nagy
Jan 3 at 19:52
add a comment |
I was wondering if my approach was possible at all, but you are right, this problem shouldn’t be solved like this
– Dániel Nagy
Jan 3 at 19:52
I was wondering if my approach was possible at all, but you are right, this problem shouldn’t be solved like this
– Dániel Nagy
Jan 3 at 19:52
I was wondering if my approach was possible at all, but you are right, this problem shouldn’t be solved like this
– Dániel Nagy
Jan 3 at 19:52
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f54023782%2fpydantic-make-field-none-in-validator-based-on-other-fields-value%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
I'm getting an exception when executing your code:
NameError: Field name "fields" shadows a BaseModel attribute; use a different field name with "alias='fields'".Something special to take into account? (Testing with python3.6 and pydantic 0.17)– normanius
Jan 3 at 14:35
@normanius my bad, forgot that
allow...andfieldswere in an inner Config class– Dániel Nagy
Jan 3 at 14:42
btw I'm trying with python 3.6.1 and pydantic 0.16.1
– Dániel Nagy
Jan 3 at 14:44