Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

descriptor __set_name__ feature broken for dataclass descriptor fields #77322

Closed
Ricyteach mannequin opened this issue Mar 26, 2018 · 16 comments
Closed

descriptor __set_name__ feature broken for dataclass descriptor fields #77322

Ricyteach mannequin opened this issue Mar 26, 2018 · 16 comments
Assignees
Labels
3.7 (EOL) end of life 3.8 only security fixes stdlib Python modules in the Lib dir type-bug An unexpected behavior, bug, or error

Comments

@Ricyteach
Copy link
Mannequin

Ricyteach mannequin commented Mar 26, 2018

BPO 33141
Nosy @ericvsmith, @miss-islington, @Ricyteach
PRs
  • bpo-33141: Have dataclasses.Field pass through __set_name__ to any default descriptor. #6260
  • [3.7] bpo-33141: Have dataclasses.Field pass through __set_name__ to any default argument. (GH-6260) #6261
  • Files
  • broken__set_name__.py: raises AttributeError on accessing descriptor_object.name attribute
  • Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.

    Show more details

    GitHub fields:

    assignee = 'https://github.com/ericvsmith'
    closed_at = <Date 2018-03-26.18:14:56.616>
    created_at = <Date 2018-03-26.02:25:48.957>
    labels = ['3.7', '3.8', 'type-bug', 'library']
    title = 'descriptor __set_name__ feature broken for dataclass descriptor fields'
    updated_at = <Date 2018-03-26.18:14:56.615>
    user = 'https://github.com/Ricyteach'

    bugs.python.org fields:

    activity = <Date 2018-03-26.18:14:56.615>
    actor = 'eric.smith'
    assignee = 'eric.smith'
    closed = True
    closed_date = <Date 2018-03-26.18:14:56.616>
    closer = 'eric.smith'
    components = ['Library (Lib)']
    creation = <Date 2018-03-26.02:25:48.957>
    creator = 'Ricyteach'
    dependencies = []
    files = ['47499']
    hgrepos = []
    issue_num = 33141
    keywords = ['patch']
    message_count = 16.0
    messages = ['314438', '314446', '314447', '314452', '314458', '314459', '314460', '314463', '314466', '314467', '314468', '314469', '314470', '314471', '314473', '314474']
    nosy_count = 3.0
    nosy_names = ['eric.smith', 'miss-islington', 'Ricyteach']
    pr_nums = ['6260', '6261']
    priority = 'normal'
    resolution = 'fixed'
    stage = 'resolved'
    status = 'closed'
    superseder = None
    type = 'behavior'
    url = 'https://bugs.python.org/issue33141'
    versions = ['Python 3.7', 'Python 3.8']

    @Ricyteach
    Copy link
    Mannequin Author

    Ricyteach mannequin commented Mar 26, 2018

    Summary: The descriptor __set_name__ functionality (introduced in Python 3.6) does not seem to be working correctly for dataclass.Field objects with a default pointing to a descriptor. I have attached a file demonstrating the trouble.

    Details: If I set a dataclass class object field to a dataclass.field with a descriptor object for the default argument, the descriptor's __set_name__ method is not called during initialization. This is unexpected because descriptors themselves seem to work pretty much flawlessly, otherwise.

    (Bravo on that by the way! Working descriptors isn't mentioned at all in the PEP as a feature but I was very pleased to see them working!!)

    System details:
    Python 3.7b02
    Windows 10
    PyCharm Community Edition

    btw this is my first ever Python bug report; I hope I did a good job.

    @Ricyteach Ricyteach mannequin added 3.7 (EOL) end of life type-bug An unexpected behavior, bug, or error labels Mar 26, 2018
    @ericvsmith
    Copy link
    Member

    That's a tough one. Because C.d is not set to a descriptor at type creation time (it's set to a Field object), the __set_name__ behavior is never invoked. It's when the @DataClass decorator is called that C.d is set to D().

    https://docs.python.org/3/reference/datamodel.html#creating-the-class-object

    I'm not sure it's possible to work around this without duplicating some of the type creation code, and even then I'm not convinced it's doable.

    @ericvsmith
    Copy link
    Member

    I suppose I could, when overwriting the class member, check for inspect.ismethoddescriptor and call __set_name__ myself.

    @ericvsmith ericvsmith added stdlib Python modules in the Lib dir 3.8 only security fixes labels Mar 26, 2018
    @Ricyteach
    Copy link
    Mannequin Author

    Ricyteach mannequin commented Mar 26, 2018

    hmmm... if I check the C.d class attribute it seems to return the
    descriptor instance object (not a field object) before any C instances have
    been created. i guess this is just a part of how the dataclass
    implementation works.

    i didn't realize there's nothing "special" going on with descriptors here-
    the descriptors "just work" by virtue of being set to the class attribute
    at creation time. interesting.

    maybe because of this descriptors should short-circuit the field creation
    process entirely? that would be a shame though. having the option of
    auto-including a descriptor in the class repr turns out to be very useful
    and i'm already playing around with it in a project.

    one idea: what if it there were a keyword argument to mark a field as a
    descriptor, allowing tje descriptor to be set at type creation? this would
    need to disallow init=True, i think. and setting a field default to a
    descriptor class would then raise a type error.

    ---
    Ricky.

    "I've never met a Kentucky man who wasn't either thinking about going home
    or actually going home." - Happy Chandler

    On Mon, Mar 26, 2018 at 6:47 AM, Eric V. Smith <report@bugs.python.org>
    wrote:

    Eric V. Smith <eric@trueblade.com> added the comment:

    I suppose I could, when overwriting the class member, check for
    inspect.ismethoddescriptor and call __set_name__ myself.

    ----------
    components: +Library (Lib)
    versions: +Python 3.8


    Python tracker <report@bugs.python.org>
    <https://bugs.python.org/issue33141\>


    @ericvsmith
    Copy link
    Member

    Nick Coghlan suggested (on python-dev) to have Field implement __set_name__ and call through to the default value, if it exists.

    That approach seems to work fine. I'll generate a PR with tests sometime before today's release.

    @Ricyteach
    Copy link
    Mannequin Author

    Ricyteach mannequin commented Mar 26, 2018

    Sounds like a relatively easy solution then. Hopefully it makes the beta 3 so I can use it immediately- thanks!

    @Ricyteach
    Copy link
    Mannequin Author

    Ricyteach mannequin commented Mar 26, 2018

    I suppose one downside of that solution is __set_name__ will be called for every Field whether or not it is need. Probably can't be helped without major complications.

    @ericvsmith
    Copy link
    Member

    I don't expect there to be too much usage of Field objects, so I'm not so worried about it.

    If you can, try out the code in the PR. Thanks.

    @Ricyteach
    Copy link
    Mannequin Author

    Ricyteach mannequin commented Mar 26, 2018

    Eric, looking at the PR; note that if you do this for the __set_name__ check:

        if inspect.ismethoddescriptor(self.default):

    ...an object like the one below will not get its __set_name__ called, even though PEP-487 says it should:

    class D:
    	def __set_name__(self, o, n):
    		self.name = n
    
    class C:
    	d: int = D()
    
    if __name__ == "__main__":
    	print(f"C.d.name = {C.d.name}") # __set_name__ was called
    	assert inspect.ismethoddescriptor(C.d) # Error

    @ericvsmith
    Copy link
    Member

    Yes, I noticed the same thing. I'll remove the test.

    @Ricyteach
    Copy link
    Mannequin Author

    Ricyteach mannequin commented Mar 26, 2018

    Yeah and I think lines 2709-2712 of TestDescriptors also needs removed.

    @ericvsmith
    Copy link
    Member

    I've updated the PR.

    I left those lines in, and added a different test. After all, it does need to work with real descriptors.

    @Ricyteach
    Copy link
    Mannequin Author

    Ricyteach mannequin commented Mar 26, 2018

    Looks great to me. Thanks!

    @ericvsmith
    Copy link
    Member

    New changeset de7a2f0 by Eric V. Smith in branch 'master':
    bpo-33141: Have dataclasses.Field pass through __set_name__ to any default argument. (GH-6260)
    de7a2f0

    @miss-islington
    Copy link
    Contributor

    New changeset c6147ac by Miss Islington (bot) in branch '3.7':
    bpo-33141: Have dataclasses.Field pass through __set_name__ to any default argument. (GH-6260)
    c6147ac

    @ericvsmith
    Copy link
    Member

    Thanks for the bug report.

    @ezio-melotti ezio-melotti transferred this issue from another repository Apr 10, 2022
    Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
    Labels
    3.7 (EOL) end of life 3.8 only security fixes stdlib Python modules in the Lib dir type-bug An unexpected behavior, bug, or error
    Projects
    None yet
    Development

    No branches or pull requests

    2 participants