python data class default value for str to None - python

I have a dataclass like this:
from dataclasses import dataclass
#dataclass
class DataClassCard:
rank: str = None
suit: str
I am getting an error saying:
TypeError: non-default argument 'suit' follows default argument
Is there anyway to set this default value?
Finally calling:
queen_of_hearts = DataClassCard(suit = 'a')
queen_of_hearts.rank

Fields with a default value must come after any fields without a default. Just put suit above

Related

Python typing: define type of the classvar based on another var

Is it possible to define type of the python class field based on another field?
Something like this:
from dataclasses import dataclass
from typing import ClassVar
#dataclass
class A:
a: str
#dataclass
class B(A):
b: str
#dataclass
class UseA:
field_cls: ClassVar[type] = A
field: A # <-- here should be something other, not just "A"
class UseB(UseA):
field_cls = B
def print_b(self) -> None:
print(self.field.b) # Here mypy says that "A has no attribute b"
If I'll run mypy --strict on this code I'll get the error: "A" has no attribute "b".
I need to define the type of "field" dynamically by another field "field_cls" so type checkers like mypy and my IDE (vscode) have to understand the right type of the UseB.field

pydantic's `Field`'s default value ignores constraint checks

from pydantic import BaseModel
class User(BaseModel):
age: int = Field('foo', ge=0)
User() # doesn't raise an error
# User(age='foo')
Why doesn't this raise an error since a string foo is passed even though an int is expected?
User(age='foo') however raises the ValidationError as expected.
This connected to the config that you can add to all of your models.
By default the default of Fields are excluding from validation, simply assuming that the programmer puts a proper default value.
However, if you want to enforce validation you cann enforce it by adding a Config to your model:
class User(BaseModel):
age: int = Field('foo', ge=0)
class Config(BaseConfig):
validate_all = True
if __name__ == "__main__":
User() # Now raise an error
Also have a look at the other options for configs in the the docs: https://pydantic-docs.helpmanual.io/usage/model_config/

Either of the two Pydantic attributes should be optional

I want validate a payload schema & I am using Pydantic to do that. The class created by inheriting Pydantic's BaseModel is named as PayloadValidator and it has two attributes, addCustomPages which is list of dictionaries & deleteCustomPages which is a list of strings.
class NestedCustomPages(BaseModel):
"""This is the schema for each custom page."""
html: str
label: str
type: int
class PayloadValidator(BaseModelWithContext):
"""This class defines the payload load schema and also validates it."""
addCustomPages: Optional[List[NestedCustomPages]]
deleteCustomPages: Optional[List[str]]
I want to declare either of the attributes of class PayloadValidator as optional. I have tried looking for the solution for this but couldn't find anything.
There was a question on this a while ago on the pydantic Github page: https://github.com/samuelcolvin/pydantic/issues/506. The conclusion there includes a toy example with a model that requires either a or b to be filled by using a validator:
from typing import Optional
from pydantic import validator
from pydantic.main import BaseModel
class MyModel(BaseModel):
a: Optional[str] = None
b: Optional[str] = None
#validator('b', always=True)
def check_a_or_b(cls, b, values):
if not values.get('a') and not b:
raise ValueError('Either a or b is required')
return b
mm = MyModel()

How to decode json with reserved name as key using json_dataclass?

I am trying to decode a json I received from an api using dataclass_json from the dataclasses_json module, however one of the json fields is called class which is a python reserved keyword. How can I define them?
{'some_var': False,
'class': '/12345.jpg'}
I tried this
#dataclass_json
#dataclass
class Media:
some_var: str
class: str ### error because class is a reserved keyword
parsedObject = Media.from_json(jsonString)
but get an error due to 'class' being a reserved keyword.
Specify the original field name as a field_name and name your class property differently:
from dataclasses import dataclass, field
from dataclasses_json import config, dataclass_json
#dataclass_json
#dataclass
class Media:
some_var: str
the_class: str = field(metadata=config(field_name="class"))
Check out the docs, scroll down to "Encode or decode using a different name".

How to cast a variable to a dataclass type?

I want to use the function fields from the dataclasses module but my IDE keeps warning me that it should be only used on dataclasses (classes or instances). I know it is possible to ignore the warning, but I would like to cast my variable into a dataclass type, as it is more readable and IDE-compatible.
A brief example:
from dataclasses import fields
all_fields = fields(some_instance) # Here I get a warning
Context:
I want to write a "mixin" class to add type-enforcing on my dataclasses. Example:
from typing import Any
from dataclasses import fields, Field
class TypedDCMixin:
def __post_init__(self):
self._check_fields_types()
def _check_fields_types(self):
for field in fields(self): # HERE I get the warning from my IDE
field_value = getattr(self, field.name)
self._check_field_type(field, field_value)
def _check_field_type(self, field: Field, field_value: Any):
# whatever
pass
The same warning would arise from any other context where dataclasses.fields is used with an argument which is not known to be a dataclass.
I usually avoid type warnings like that by using the function typing.cast, but there is no DataclassType for me to do cast(DataclassType, self) at the warned line.
Hence my question: How to cast a variable to a dataclass type?
Using cast with the dataclass decorator works.
Modifying the original example to add the casting:
from typing import Any, cast
from dataclasses import fields, Field, dataclass
class TypedDCMixin:
def __post_init__(self):
self._check_fields_types()
def _check_fields_types(self):
for field in fields(cast(dataclass, self)): # Here the casting is used
field_value = getattr(self, field.name)
self._check_field_type(field, field_value)
def _check_field_type(self, field: Field, field_value: Any):
# whatever
pass

Categories