[issue42742] Add abc.Mapping to dataclass

2020-12-29 Thread Anton Abrosimov


Anton Abrosimov  added the comment:

Link to python-ideas thread:
https://mail.python.org/archives/list/python-id...@python.org/thread/XNXCUJVNOOVPAPL6LF627EOCBUUUX2DG/

--

___
Python tracker 

___
___
Python-bugs-list mailing list
Unsubscribe: 
https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com



[issue42742] Add abc.Mapping to dataclass

2020-12-25 Thread Anton Abrosimov


Anton Abrosimov  added the comment:

Thanks for the good offer, I will definitely use it.

--

___
Python tracker 

___
___
Python-bugs-list mailing list
Unsubscribe: 
https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com



[issue42742] Add abc.Mapping to dataclass

2020-12-25 Thread Eric V. Smith


Eric V. Smith  added the comment:

I'm just warning you that I probably won't accept it. I haven't heard of any 
demand for this feature.

You might want to bring it up on python-ideas if you want to generate support 
for the proposal.

--

___
Python tracker 

___
___
Python-bugs-list mailing list
Unsubscribe: 
https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com



[issue42742] Add abc.Mapping to dataclass

2020-12-25 Thread Anton Abrosimov


Anton Abrosimov  added the comment:

This Mixin only works with dataclass objects. And uses the private 
functionality of the dataclasses. So dataclasses.py is the right place for 
this. I think I can do enough tests.

And I think that this is too little for a standalone project.

--

___
Python tracker 

___
___
Python-bugs-list mailing list
Unsubscribe: 
https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com



[issue42742] Add abc.Mapping to dataclass

2020-12-25 Thread Eric V. Smith


Eric V. Smith  added the comment:

I don't think this belongs in dataclasses itself, at least not until it's been 
vetted widely. You might want to put it on PyPI first as a standalone project.

--

___
Python tracker 

___
___
Python-bugs-list mailing list
Unsubscribe: 
https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com



[issue42742] Add abc.Mapping to dataclass

2020-12-25 Thread Anton Abrosimov


Anton Abrosimov  added the comment:

I think the second option looks better.
More pythonic.
No need to create new classes
No typing hacks.
Mixin can be easily expanded.

Yes, I will do refactoring, typing, documentation and tests in PR.

--

___
Python tracker 

___
___
Python-bugs-list mailing list
Unsubscribe: 
https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com



[issue42742] Add abc.Mapping to dataclass

2020-12-25 Thread Anton Abrosimov


Anton Abrosimov  added the comment:

An alternative way:

from collections.abc import Mapping
from dataclasses import dataclass, fields, _FIELDS, _FIELD

class DataclassMappingMixin(Mapping):
def __iter__(self):
return (f.name for f in fields(self))

def __getitem__(self, key):
field = getattr(self, _FIELDS)[key]
if field._field_type is not _FIELD:
raise KeyError(f"'{key}' is not a dataclass field.")
return getattr(self, field.name)

def __len__(self):
return len(fields(self))


@dataclass
class MyDataclass(DataclassMappingMixin):
a: int = 1
b: int = 2


my_dataclass = MyDataclass(a='3')
print(my_dataclass.__class__.__mro__)
print(my_dataclass.__class__.__name__)
print(my_dataclass['a'])
print(my_dataclass['b'])
print(dict(my_dataclass))
print(dict(**my_dataclass))
print(fields(my_dataclass))


Result:
(,
 ,
 ,
 ,
 ,
 ,
 ,
 )
MyDataclass
3
2
{'a': '3', 'b': 2}
{'a': '3', 'b': 2}
(Field(name='a',type=, ...),
 Field(name='b',type=, ...))

--

___
Python tracker 

___
___
Python-bugs-list mailing list
Unsubscribe: 
https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com



[issue42742] Add abc.Mapping to dataclass

2020-12-25 Thread Eric V. Smith


Eric V. Smith  added the comment:

Something like that. You'd have to write some tests and try it out.

--

___
Python tracker 

___
___
Python-bugs-list mailing list
Unsubscribe: 
https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com



[issue42742] Add abc.Mapping to dataclass

2020-12-25 Thread Anton Abrosimov


Anton Abrosimov  added the comment:

Thanks for the answer, I agree.
The implementation should be like this?


from collections.abc import Mapping
from dataclasses import dataclass, fields, _FIELDS, _FIELD

class _DataclassMappingMixin(Mapping):
def __iter__(self):
return (f.name for f in fields(self))

def __getitem__(self, key):
fields = getattr(self, _FIELDS)
f = fields[key]
if f._field_type is not _FIELD:
raise KeyError(f"'{key}' is not a dataclass field.")
return getattr(self, f.name)

def __len__(self):
return len(fields(self))


def dataclass_mapping(cls=None, **kwargs):
def apply_dataclass(cls):
dataclass_wrap = dataclass(**kwargs)
return dataclass_wrap(cls)

def check_mapping_attrs(cls):
mapping_attrs = (i for i in dir(_DataclassMappingMixin) if i[0] != '_')
for key in mapping_attrs:
if hasattr(cls, key):
raise AttributeError(f"'{key}' is the Mapping reserved 
attribute.")

def apply_mapping(cls):
return type(cls.__name__ + 'Mapping',
(cls, _DataclassMappingMixin),
{})

def wrap(cls):
check_mapping_attrs(cls)
cls_dataclass = apply_dataclass(cls)
return apply_mapping(cls_dataclass)

# See if we're being called as @dataclass or @dataclass().
if cls is None:
# We're called with parens.
return wrap

# We're called as @dataclass without parens.
return wrap(cls)


@dataclass_mapping
class MyDataclass:
a: int = 1
b: int = 2


my_dataclass = MyDataclass(b='3')
print(my_dataclass.__class__.__name__)
print(my_dataclass['a'])
print(my_dataclass['b'])
print(dict(my_dataclass))
print(dict(**my_dataclass))

--

___
Python tracker 

___
___
Python-bugs-list mailing list
Unsubscribe: 
https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com



[issue42742] Add abc.Mapping to dataclass

2020-12-25 Thread Eric V. Smith


Eric V. Smith  added the comment:

You'd need to return a different class in order to add the 
collections.abc.Mapping base class. Currently, dataclasses by design always 
return the same class that's passed in.

I'd suggest adding this as a stand-alone decorator.

--
assignee:  -> eric.smith
nosy: +eric.smith

___
Python tracker 

___
___
Python-bugs-list mailing list
Unsubscribe: 
https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com



[issue42742] Add abc.Mapping to dataclass

2020-12-25 Thread Anton Abrosimov


New submission from Anton Abrosimov :

I want to add `abc.Mapping` extension to `dataclasses.dataclass`.

Motivation:

1. `asdict` makes a deep copy of the `dataclass` object. If I only want to 
iterate over the `field` attributes, I don't want to do a deep copy.
2. `dict(my_dataclass)` can be used as a `dict` representation of 
`my_dataclass` class without deep copying.
3. `myfunc(**my_dataclass)` looks better and is faster then 
`myfunc(**asdict(my_dataclass))`.
4. `len(my_dataclass) == len(asdict(my_dataclass))` is expected behavior.
5. `my_dataclass.my_field is my_dataclass['my_field']` is expected behavior.


Looks like a prototype:

from collections.abc import Mapping
from dataclasses import dataclass, fields, _FIELDS, _FIELD


@dataclass  # `(mapping=True)` creates such a class:
class MyDataclass(Mapping):
a: int = 1
b: int = 2

# In `dataclasses._process_class`:
# if `mapping` is `True`.
# Make sure 'get', 'items', 'keys', 'values' is not in `MyDataclass` fields.

def __iter__(self):
return (f.name for f in fields(self))

def __getitem__(self, key):
fields = getattr(self, _FIELDS)
f = fields[key]
if f._field_type is not _FIELD:
raise KeyError(f"'{key}' is not a field of the dataclass.")
return getattr(self, f.name)

def __len__(self):
return len(fields(self))


my_dataclass = MyDataclass(b=3)
print(my_dataclass['a'])
print(my_dataclass['b'])
print(dict(my_dataclass))
print(dict(**my_dataclass))

Stdout:
1
3
{'a': 1, 'b': 3}
{'a': 1, 'b': 3}


Realisation:

Updating the `dataclasses.py`: `dataclass`, `_process_class`, 
`_DataclassParams`.
Set `mapping` argument to default `False`.


Can this enhancement be accepted?

--
components: Library (Lib)
messages: 383752
nosy: abrosimov.a.a
priority: normal
severity: normal
status: open
title: Add abc.Mapping to dataclass
type: enhancement
versions: Python 3.10

___
Python tracker 

___
___
Python-bugs-list mailing list
Unsubscribe: 
https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com