Skip to content

Commit 8d5f8c2

Browse files
committed
Fix test + move to helper function with docs
1 parent f4e5b93 commit 8d5f8c2

File tree

1 file changed

+38
-27
lines changed

1 file changed

+38
-27
lines changed

mypyc/irbuild/util.py

Lines changed: 38 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -128,44 +128,55 @@ def get_mypyc_attrs(stmt: ClassDef | Decorator) -> dict[str, Any]:
128128

129129
def is_extension_class(path: str, cdef: ClassDef, errors: Errors) -> bool:
130130
# Check for @mypyc_attr(native_class=True/False) decorator.
131+
explicit_native_class = get_explicit_native_class(path, cdef, errors)
132+
131133
# Classes with native_class=False are explicitly marked as non extension.
132-
# Classes with native_class=True should be extension classes, but they might
133-
# not be able to be due to other reasons. Print an error in that case.
134-
forced_native_class = False
135-
for d in cdef.decorators:
136-
mypyc_attr_call = get_mypyc_attr_call(d)
137-
if mypyc_attr_call:
138-
for i, name in enumerate(mypyc_attr_call.arg_names):
139-
if name != "native_class":
140-
continue
141-
142-
if not isinstance(mypyc_attr_call.args[i], NameExpr):
143-
errors.error(
144-
"native_class must be used with True or False only", path, cdef.line
145-
)
146-
break
147-
148-
if mypyc_attr_call.args[i].name == "False":
149-
return False
150-
elif mypyc_attr_call.args[i].name == "True":
151-
forced_native_class = True
152-
break
153-
else:
154-
errors.error(
155-
"native_class must be used with True or False only", path, cdef.line
156-
)
157-
break
134+
if explicit_native_class is False:
135+
return False
158136

159137
implicit_extension_class = is_implicit_extension_class(cdef)
160138

161-
if forced_native_class and not implicit_extension_class:
139+
# Classes with native_class=True should be extension classes, but they might
140+
# not be able to be due to other reasons. Print an error in that case.
141+
if explicit_native_class is True and not implicit_extension_class:
162142
errors.error(
163143
"Class is marked as native_class=True but it can't be a native class", path, cdef.line
164144
)
165145

166146
return implicit_extension_class
167147

168148

149+
def get_explicit_native_class(path: str, cdef: ClassDef, errors: Errors) -> bool | None:
150+
"""Return value of @mypyc_attr(native_class=True/False) decorator.
151+
152+
Look for a @mypyc_attr decorator with native_class=True/False and return
153+
the value assigned or None if it doesn't exist. Other values are an error.
154+
"""
155+
156+
for d in cdef.decorators:
157+
mypyc_attr_call = get_mypyc_attr_call(d)
158+
if not mypyc_attr_call:
159+
continue
160+
161+
for i, name in enumerate(mypyc_attr_call.arg_names):
162+
if name != "native_class":
163+
continue
164+
165+
arg = mypyc_attr_call.args[i]
166+
if not isinstance(arg, NameExpr):
167+
errors.error("native_class must be used with True or False only", path, cdef.line)
168+
return None
169+
170+
if arg.name == "False":
171+
return False
172+
elif arg.name == "True":
173+
return True
174+
else:
175+
errors.error("native_class must be used with True or False only", path, cdef.line)
176+
return None
177+
return None
178+
179+
169180
def is_implicit_extension_class(cdef: ClassDef) -> bool:
170181
for d in cdef.decorators:
171182
# Classes that have any decorator other than supported decorators, are not extension classes

0 commit comments

Comments
 (0)