How to use dataclass 'kw_only' correctly? - python

I want to have deafult values for Base class variables while not having default values for derived class variables.
I have read about 'kw_only' at:
https://medium.com/#aniscampos/python-dataclass-inheritance-finally-686eaf60fbb5
And tried it on my code:
from dataclasses import dataclass, field
#dataclass(kw_only=True)
class Base:
c:int = field(default=8, compare=False)
def printBVars(self):
print("Base:", self.c)
#dataclass(kw_only=True)
class Derive(Base):
cc:int = field()
def printDVars(self):
super().printBVars()
print("Derive:", self.cc)
a = Derive()
a.printDVars()
But Python is givving this error:
File "<string>", line 8, in <module> TypeError: dataclass() got an unexpected keyword argument 'kw_only'
What am I doing wrong?
Im using python 3.9
I have read about some solution suggestions from google, tried some but did not help. such as running:
pip install attrs --upgrade

Related

ImportError: cannot import name 'Annotated' and 'ValueRange'

Hello I am using Python 3.8
And I am implementing a dataclass with a fix list in order to do this I have the following code:
from dataclasses import dataclass
from typing import Annotated, List, ValueRange
from pydantic import validate_arguments
#validate_arguments
#dataclass
class WorldArea:
...
data: Annotated[List[float], ValueRange(1, 3)]
...
The idea is that data will be a list with 1, 2 or 3 elements, as you can see I am using Annotated and ValueRange, but when I execute I get the following error:
File "a.py", line 2, in
from typing import List, ValueRange ImportError: cannot import name 'Annotated' from 'typing'
File "a.py", line 2, in
from typing import List, ValueRange ImportError: cannot import name 'ValueRange' from 'typing'
Annotated has been introduced in Python 3.9 (see last line in the linked section).
ValueRange (and MaxLen) in the linked section appear to be example classes.
They are not part of the typing package.

Autodoc failing with class that has nested pydantic model

As my MRE, I've got the following file:
blah.py
'''Blah module'''
import pydantic
class Foo:
'''Foo class'''
class Bar(pydantic.BaseModel):
'''Bar class'''
x: str = pydantic.Field(description='The x.')
#pydantic.validator('x')
def do_nothing(cls, value: str) -> str:
return value
I'm attempting to use Sphinx to generate documentation for this module. In my conf.py, I have
extensions = [
'sphinx.ext.autodoc',
'sphinxcontrib.autodoc_pydantic',
]
My blah.rst is
Blah
====
.. automodule:: blah.blah
:members:
I've pip installed pydantic and autodoc_pydantic.
However, when I make html, I get
Exception occurred:
File "/home/user/Projects/Workspace/env/lib/python3.10/site-packages/sphinxcontrib/autodoc_pydantic/inspection.py", line 311, in __init__
self.attribute: Dict = self.model.Config
AttributeError: type object 'Foo' has no attribute 'Config'
It appears that autodoc_pydantic thinks that Foo inherits from pydantic.BaseModel when it's really Bar that does. If I remove 'sphinxcontrib.autodoc_pydantic' from extensions, the error goes away.
More interestingly, if I delete the validator, the error goes away as well.
autodoc_pydantic is version 1.6.1.
This issue was fixed in version 1.7.2.

How can mypy accept pydantic's constr() types?

I have this code:
from pydantic import BaseModel, constr
DeptNumber = constr(min_length=6, max_length=6)
class MyStuff(BaseModel):
dept: DeptNumber
ms = MyStuff(dept = "123456")
deptnr.py:6: error: Variable "deptnr.DeptNumber" is not valid as a type
deptnr.py:6: note: See https://mypy.readthedocs.io/en/latest/common_issues.html#variables-vs-type-aliases
The provided link doesn't seem to really address my problem (I'm not using Type).
This happens with or without this mypy.ini:
[mypy]
plugins = pydantic.mypy
[pydantic-mypy]
init_typed = true
Initially I also had that error in a Pydantic choice as below, but I got around that by using Python's Literal instead.
DIR = choice(["North", "East", "South", "West"])
What do I need to change to make mypy happy with my Pydantic constr?
This incompatibility with mypy has been discussed in this Github issue https://github.com/samuelcolvin/pydantic/issues/156. Sadly, no concrete solution that uses constr and keeps mypy happy was found.
Instead of constr, you can subclass pydantic's ConstrainedStr, which offers the same configurations and options as constr, but without mypy complaining about type aliases.
from pydantic import BaseModel, ConstrainedStr
class DeptNumber(ConstrainedStr):
min_length = 6
max_length = 6
class MyStuff(BaseModel):
dept: DeptNumber
ms = MyStuff(dept='123456')
The Constrained* classes are briefly mentioned in the Strict Types section of the docs. It is defined in pydantic/types.py and as you can see is basically the same as constr:
class ConstrainedStr(str):
strip_whitespace = False
to_lower = False
min_length: OptionalInt = None
max_length: OptionalInt = None
curtail_length: OptionalInt = None
regex: Optional[Pattern[str]] = None
strict = False
...
Validation works the same:
Traceback (most recent call last):
File "test-2.py", line 13, in <module>
ms = MyStuff(dept='123456789')
File "pydantic/main.py", line 406, in pydantic.main.BaseModel.__init__
pydantic.error_wrappers.ValidationError: 1 validation error for MyStuff
dept
ensure this value has at most 6 characters (type=value_error.any_str.max_length; limit_value=6)
You can try to use Field from Pydantic :
from pydantic import BaseModel, Field
class MyStuff(BaseModel):
dept: str = Field(..., min_length=6, max_length=6)
It seems working for me.

mypy typing leeds to unexpected traceback

I'm trying to use a work-around for the problems described in this GitHub issue ("Class with function fields incorrectly thinks the first argument is self").
from dataclasses import dataclass
from typing import TypeVar, Generic, Any, Iterable, List
T = TypeVar("T")
# See https://github.com/python/mypy/issues/5485
#dataclass
class Box(Generic[T]):
inner: T
#property
def unboxed(self) -> T:
return self.inner
I run into a traceback like this, though:
However, upon importing (only(!) ) the code above from another module I run into a traceback like this:
(py) sugarline:~/src/oss/ormsnack write-compile-eval
Traceback (most recent call last):
[.....]
File "/Users/jacob/src/oss/ormsnack/ormsnack/ng_desc.py", line 8, in <module>
from kingston.kind import Box # type: ignore
File "kingston/kind.py", line 12, in <module>
AttributeError: attribute '__dict__' of 'type' objects is not writable
Googling only lands me in old bugs that seem to have gone stale, though (https://bugs.python.org/issue38099, https://github.com/man-group/arctic/issues/17), etc.
Is anyone able to figure out a work-around?

Using dataclasses with Cython

I'm using cython for code obfuscation, so performance is not an issue at the moment. The problem is with using dataclasses.
There is no error during compilation time when cythonize code that contains dataclass definitions. But when running the code, I get a TypeError: <field> is a field but has no type annotation.
Here is the code I'm trying to cythonize:
from dataclasses import dataclass, field
from typing import Dict, Any, List
#dataclass
class dataclass_test:
ddict: Dict[str, Any]
sstr: str
bbool: bool
llist: List[str]
ffloat: float
llist1: List[str] = field(default_factory=list)
Running the code without cythonization works fine. But after cythonization I get the following error message:
File "dataclass_.py", line 4, in init dataclass_
#dataclass File "/home/aryskin/miniconda3/envs/tf113_gpu_conda/lib/python3.7/dataclasses.py", line 991, in dataclass
return wrap(_cls) File "/home/aryskin/miniconda3/envs/tf113_gpu_conda/lib/python3.7/dataclasses.py", line 983, in wrap
return _process_class(cls, init, repr, eq, order, unsafe_hash, frozen) File "/home/aryskin/miniconda3/envs/tf113_gpu_conda/lib/python3.7/dataclasses.py", line 857, in _process_class
raise TypeError(f'{name!r} is a field but has no type annotation') TypeError: 'llist1' is a field but has no type annotation
Is there any way to avoid this problem without or with minimal rewriting of the source code?
Until support for this is merged into Cython, a workaround is to manually add the __annotations__ attribute to your class and repeat your type annotations:
#dataclass
class Fieldset:
label: str
fields: List[Field] = []
__annotations__ = {
'label': str,
'fields': List[Field],
}

Categories