Pydantic: Make field None in validator based on other field's value












1















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?










share|improve this question

























  • 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











  • btw I'm trying with python 3.6.1 and pydantic 0.16.1

    – Dániel Nagy
    Jan 3 at 14:44
















1















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?










share|improve this question

























  • 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











  • btw I'm trying with python 3.6.1 and pydantic 0.16.1

    – Dániel Nagy
    Jan 3 at 14:44














1












1








1








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?










share|improve this question
















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






share|improve this question















share|improve this question













share|improve this question




share|improve this question








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 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



















  • 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











  • 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












1 Answer
1






active

oldest

votes


















1














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]





share|improve this answer


























  • 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












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
});


}
});














draft saved

draft discarded


















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









1














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]





share|improve this answer


























  • 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
















1














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]





share|improve this answer


























  • 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














1












1








1







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]





share|improve this answer















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]






share|improve this answer














share|improve this answer



share|improve this answer








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



















  • 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




















draft saved

draft discarded




















































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.




draft saved


draft discarded














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





















































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







Popular posts from this blog

Mossoró

Error while reading .h5 file using the rhdf5 package in R

Pushsharp Apns notification error: 'InvalidToken'