Skip to content
New issue

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

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

Already on GitHub? # to your account

bug: parameter kinds for dataclasses should match the non-dataclass equivalents #234

Closed
has2k1 opened this issue Feb 8, 2024 · 0 comments
Assignees

Comments

@has2k1
Copy link
Contributor

has2k1 commented Feb 8, 2024

Currently, parameters derived from dataclass fields have no kind information.

This is mainly for python 3.10+ which have keyword_only specification for dataclass fields. Here are failing test cases.

from griffe.tests import temporary_visited_module

code = """
from dataclasses import dataclass, field, KW_ONLY

# Pair of dataclass and equivalent non-dataclass
# The parameter kinds for each pair should be the same
    
@dataclass
class PointA:
    x: float
    y: float = field(kw_only=True)

class PointA_:
    def __init__(self, x: float, *, y: float): ...

@dataclass
class PointB:
    x: float = field(kw_only=True)
    y: float

class PointB_:
    def __init__(self, y: float, *, x: float): ...

@dataclass
class PointC:
    x: float
    _: KW_ONLY
    y: float

class PointC_:
    def __init__(self, x: float, *, y: float): ...

@dataclass
class PointD:
    _: KW_ONLY
    x: float
    y: float

class PointD_:
    def __init__(self, *, x: float, y: float): ...

@dataclass(kw_only=True)
class PointE:
    x: float
    y: float

class PointE_:
    def __init__(self, *, x: float, y: float): ...
"""

def parameter_kinds(obj):
    return [(p.kind and p.kind.value) or None for p in obj.parameters]

with temporary_visited_module(code) as module:
    def both_parameter_kinds(s):
        return [parameter_kinds(obj) for obj in (module[s], module[f"{s}_"])]

    kindsA, kindsA_ = both_parameter_kinds("PointA")
    kindsB, kindsB_ = both_parameter_kinds("PointB")
    kindsC, kindsC_ = both_parameter_kinds("PointC")
    kindsD, kindsD_ = both_parameter_kinds("PointD")
    kindsE, kindsE_ = both_parameter_kinds("PointE")

    assert kindsA == kindsA_
    assert kindsB == kindsB_
    assert kindsC == kindsC_
    assert kindsD == kindsD_
    assert kindsE == kindsE_
pawamoy added a commit that referenced this issue Mar 5, 2024
Instead of generating parameters on the fly by (wrongly) checking attributes of the class,
we always load a Griffe extension that re-creates `__init__` methods and their parameters.

Issue-33: #233
Issue-34: #234
Issue-38: #238
Issue-39: #239
PR-240: #240
@pawamoy pawamoy closed this as completed Mar 5, 2024
# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants