Skip to content

Commit 1577599

Browse files
committed
Reduce complexity a bit
1 parent 852e4ed commit 1577599

File tree

2 files changed

+21
-73
lines changed

2 files changed

+21
-73
lines changed

ninja/signature/details.py

Lines changed: 21 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -230,47 +230,17 @@ def _model_flatten_map(self, model: TModel, prefix: str) -> Generator:
230230
if get_origin(model) in UNION_TYPES:
231231
# If the model is a union type, process each type in the union
232232
for arg in get_args(model):
233-
if arg is type(None):
234-
continue # Skip NoneType
235233
yield from self._model_flatten_map(arg, prefix)
236234
else:
237235
for attr, field in model.model_fields.items():
238236
field_name = field.alias or attr
239237
name = f"{prefix}{self.FLATTEN_PATH_SEP}{field_name}"
240238

241-
# Check if this is a union type field
242-
if get_origin(field.annotation) in UNION_TYPES:
243-
union_args = get_args(field.annotation)
244-
has_none = type(None) in union_args
245-
non_none_args = [arg for arg in union_args if arg is not type(None)]
246-
247-
# If it's an optional field (Union with None) and has a default value,
248-
# don't flatten it - treat it as a single optional field
249-
if has_none and field.default is not PydanticUndefined:
250-
yield field_name, name
251-
continue
252-
253-
# For non-optional unions or unions without defaults,
254-
# check if any of the union args are pydantic models
255-
pydantic_args = [
256-
arg for arg in non_none_args if is_pydantic_model(arg)
257-
]
258-
if pydantic_args:
259-
# This branch is unreachable because union fields with pydantic models
260-
# are flattened during earlier processing stages
261-
for arg in pydantic_args: # pragma: no cover
262-
yield from self._model_flatten_map(
263-
arg, name
264-
) # pragma: no cover
265-
else:
266-
# No pydantic models in union, treat as simple field
267-
yield field_name, name
268-
# This else branch is unreachable because union fields are always processed above.
269-
# Any field that reaches this point would have been handled by the union logic.
270-
elif is_pydantic_model(field.annotation): # pragma: no cover
271-
yield from self._model_flatten_map(field.annotation, name) # type: ignore # pragma: no cover
272-
else:
273-
yield field_name, name
239+
if get_origin(
240+
field.annotation
241+
) not in UNION_TYPES and is_pydantic_model(field.annotation):
242+
yield from self._model_flatten_map(field.annotation, name) # type: ignore
243+
yield field_name, name
274244

275245
def _get_param_type(self, name: str, arg: inspect.Parameter) -> FuncParam:
276246
# _EMPTY = self.signature.empty
@@ -332,9 +302,9 @@ def _get_param_type(self, name: str, arg: inspect.Parameter) -> FuncParam:
332302

333303
# 2) if param name is a part of the path parameter
334304
elif name in self.path_params_names:
335-
assert (
336-
default == self.signature.empty
337-
), f"'{name}' is a path param, default not allowed"
305+
assert default == self.signature.empty, (
306+
f"'{name}' is a path param, default not allowed"
307+
)
338308
param_source = Path(...)
339309

340310
# 3) if param is a collection, or annotation is part of pydantic model:
@@ -426,11 +396,11 @@ def detect_collection_fields(
426396
found = False
427397
# This for loop is unreachable in practice because union types with missing fields
428398
# should be handled earlier in the validation process
429-
for arg in get_args(annotation_or_field): # pragma: no cover
399+
for arg in get_args(annotation_or_field):
430400
# This continue path is unreachable because NoneType handling is done earlier in union processing
431-
if arg is type(None): # pragma: no cover
432-
continue # Skip NoneType # pragma: no cover
433-
if hasattr(arg, "model_fields"): # pragma: no cover
401+
if arg is type(None):
402+
continue # Skip NoneType
403+
if hasattr(arg, "model_fields"):
434404
found_field = next(
435405
(
436406
a
@@ -445,10 +415,10 @@ def detect_collection_fields(
445415
break
446416
# This error condition is unreachable because union fields are pre-validated
447417
# and all union members should have compatible field structures
448-
if not found: # pragma: no cover
449-
# No suitable field found in any union member, skip this path # pragma: no cover
450-
annotation_or_field = None # pragma: no cover
451-
break # Break out of the attr loop # pragma: no cover
418+
if not found:
419+
# No suitable field found in any union member, skip this path
420+
annotation_or_field = None
421+
break # Break out of the attr loop
452422
else:
453423
annotation_or_field = next(
454424
(
@@ -457,21 +427,21 @@ def detect_collection_fields(
457427
if a.alias == attr
458428
),
459429
annotation_or_field.model_fields.get(attr),
460-
) # pragma: no cover
430+
)
461431

462432
annotation_or_field = getattr(
463433
annotation_or_field, "outer_type_", annotation_or_field
464434
)
465435

466436
# This condition is unreachable because union processing failures are handled above
467437
# and annotation_or_field should never be None at this point in normal operation
468-
if annotation_or_field is None: # pragma: no cover
469-
continue # pragma: no cover
438+
if annotation_or_field is None:
439+
continue
470440

471441
# This condition is unreachable because annotation access is handled in the union processing
472442
# and should not require additional annotation unwrapping at this point
473-
if hasattr(annotation_or_field, "annotation"): # pragma: no cover
474-
annotation_or_field = annotation_or_field.annotation # pragma: no cover
443+
if hasattr(annotation_or_field, "annotation"):
444+
annotation_or_field = annotation_or_field.annotation
475445

476446
if is_collection_type(annotation_or_field):
477447
result.append(path[-1])

tests/test_models.py

Lines changed: 0 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55

66
from ninja import Form, NinjaAPI, Query, Router
77
from ninja.errors import ConfigError
8-
from ninja.signature.details import ViewSignature
98
from ninja.testing import TestClient
109

1110

@@ -572,24 +571,3 @@ def test_invalid_body():
572571
assert response.json() == {
573572
"detail": "Cannot parse request body",
574573
}
575-
576-
577-
def test_force_line_233_coverage():
578-
"""Force line 233 to be executed by directly calling _model_flatten_map with Union[Model, None]."""
579-
580-
# Create a test function with Union[Model, None] parameter
581-
def test_func(request, param: Union[SomeModel, None]):
582-
return param
583-
584-
# Create ViewSignature which will call _model_flatten_map
585-
vs = ViewSignature("/test", test_func)
586-
587-
# Force the _model_flatten_map to process Union[SomeModel, None] directly
588-
# This should trigger line 233: if arg is type(None): continue
589-
try:
590-
result = list(vs._model_flatten_map(Union[SomeModel, None], "test_prefix"))
591-
# The result should contain flattened fields from SomeModel but skip None
592-
assert len(result) > 0 # Should have some fields from SomeModel
593-
except Exception:
594-
# Even if it fails, we want to ensure line 233 gets executed
595-
pass

0 commit comments

Comments
 (0)