nebius/SWE-rebench-V2-PRs huggingface dataset:
Repository: vitalik/django-ninja
Pull request #832 (2023-08-24 16:35:43)

Include Enum to NinjaJSONEncoder
This would allow proper usage of enums in path parameters
Currently if you want to have an enum in the path, you would do this.
```
enum_value: SomeEnumClass = Path(...),
```
Which works fine until the request path includes an enum value that does not exist.
ie.
```
class SomeEnumClass(enum.Enum):
    first: "first"
    second: "second"

requests.get("some_path/third/other")
```

This would return a 500 instead of an expected 422 due to crashing in the JSONEncoder.
Returning and error
```
TypeError: Object of type SomeEnumClass is not JSON serializable"
```


Patch:
diff --git a/ninja/responses.py b/ninja/responses.py
index 440e98c..babd366 100644
--- a/ninja/responses.py
+++ b/ninja/responses.py
@@ -1,3 +1,4 @@
+from enum import Enum
 from ipaddress import IPv4Address, IPv6Address
 from typing import Any, FrozenSet
 
@@ -22,6 +23,8 @@ class NinjaJSONEncoder(DjangoJSONEncoder):
             return o.model_dump()
         if isinstance(o, (IPv4Address, IPv6Address)):
             return str(o)
+        if isinstance(o, Enum):
+            return str(o)
         return super().default(o)
 
 


Test patch:
diff --git a/tests/test_response.py b/tests/test_response.py
index 0ef0986..688186e 100644
--- a/tests/test_response.py
+++ b/tests/test_response.py
@@ -1,4 +1,5 @@
 import json
+from enum import Enum
 from ipaddress import IPv4Address, IPv6Address
 from typing import List, Union
 
@@ -30,6 +31,11 @@ class User:
         self.password = password
 
 
+class MyEnum(Enum):
+    first = "first"
+    second = "second"
+
+
 def to_camel(string: str) -> str:
     return "".join(word.capitalize() for word in string.split("_"))
 
@@ -157,3 +163,10 @@ def test_ipv6address_encoding():
     response = Response(data)
     response_data = json.loads(response.content)
     assert response_data["ipv6"] == str(data["ipv6"])
+
+
+def test_enum_encoding():
+    data = {"enum": MyEnum.first}
+    response = Response(data)
+    response_data = json.loads(response.content)
+    assert response_data["enum"] == str(data["enum"])
Repository: vitalik/django-ninja
Pull request #986 (2023-12-07 21:39:31)

Fields not generated when  Meta.fields_optional = '__all__'


Patch:
diff --git a/ninja/orm/factory.py b/ninja/orm/factory.py
index 18b839f..3416df6 100644
--- a/ninja/orm/factory.py
+++ b/ninja/orm/factory.py
@@ -55,7 +55,7 @@ class SchemaFactory:
         if key in self.schemas:
             return self.schemas[key]
 
-        model_fields_list = self._selected_model_fields(model, fields, exclude)
+        model_fields_list = list(self._selected_model_fields(model, fields, exclude))
         if optional_fields:
             if optional_fields == "__all__":
                 optional_fields = [f.name for f in model_fields_list]


Test patch:
diff --git a/tests/test_orm_metaclass.py b/tests/test_orm_metaclass.py
index a74b9e1..ca44604 100644
--- a/tests/test_orm_metaclass.py
+++ b/tests/test_orm_metaclass.py
@@ -101,6 +101,7 @@ def test_optional():
     class OptModel(models.Model):
         title = models.CharField()
         other = models.CharField(null=True)
+        extra = models.IntegerField()
 
         class Meta:
             app_label = "tests"
@@ -117,9 +118,21 @@ def test_optional():
             fields = "__all__"
             fields_optional = "__all__"
 
-    assert OptSchema.json_schema().get("required") is None
+    assert OptSchema.json_schema().get("required") == ["extra"]
+    assert OptSchema.json_schema()["properties"] == {
+        "id": {"anyOf": [{"type": "integer"}, {"type": "null"}], "title": "ID"},
+        "title": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Title"},
+        "other": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Other"},
+        "extra": {"title": "Extra", "type": "integer"},
+    }
 
     assert OptSchema2.json_schema().get("required") is None
+    assert OptSchema2.json_schema()["properties"] == {
+        "id": {"anyOf": [{"type": "integer"}, {"type": "null"}], "title": "ID"},
+        "title": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Title"},
+        "other": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Other"},
+        "extra": {"anyOf": [{"type": "integer"}, {"type": "null"}], "title": "Extra"},
+    }
 
 
 def test_fields_all():
Repository: vitalik/django-ninja
Pull request #1024 (2023-12-21 08:54:33)

Fix   dict   when validate assignment true
Issue reported [here](https://github.com/vitalik/django-ninja/issues/1006).

This PR fixes an issue with v1.1.0 where setting validate_assignment = True on a Schema throws an Attribute error for __dict__ on DjangoGetter. Example, from added test with change removed to force the error:
```
FAILED tests/test_schema.py::test_django_getter_validates_assignment - AttributeError: 'DjangoGetter' object has no attribute '__dict__'
```
It appears this functionality was broken when GetterDict was removed as a parent from DjangoGetter, and adding __dict__ in __slots__ seems to be the easiest fix.

I'm very open to feedback, and if this is intended or what a better fix might be, this PR is just me taking a stab at fixing something needed by my company.

Note: It appears running the linting fixed a couple other linting issues unrelated to this change.


Patch:
diff --git a/ninja/schema.py b/ninja/schema.py
index f2f1634..f0e7858 100644
--- a/ninja/schema.py
+++ b/ninja/schema.py
@@ -42,7 +42,7 @@ S = TypeVar("S", bound="Schema")
 
 
 class DjangoGetter:
-    __slots__ = ("_obj", "_schema_cls", "_context")
+    __slots__ = ("_obj", "_schema_cls", "_context", "__dict__")
 
     def __init__(self, obj: Any, schema_cls: Type[S], context: Any = None):
         self._obj = obj


Test patch:
diff --git a/tests/test_schema.py b/tests/test_schema.py
index a298297..8f92d52 100644
--- a/tests/test_schema.py
+++ b/tests/test_schema.py
@@ -4,6 +4,7 @@ from unittest.mock import Mock
 import pytest
 from django.db.models import Manager, QuerySet
 from django.db.models.fields.files import ImageFieldFile
+from pydantic_core import ValidationError
 
 from ninja import Schema
 from ninja.schema import DjangoGetter, Field
@@ -194,3 +195,23 @@ def test_django_getter():
 
     dg = DjangoGetter({"i": 1}, Somechema)
     assert repr(dg) == "<DjangoGetter: {'i': 1}>"
+
+
+def test_django_getter_validates_assignment():
+    class ValidateAssignmentSchema(Schema):
+        str_var: str
+
+        model_config = {"validate_assignment": True}
+
+    schema_inst = ValidateAssignmentSchema(str_var="test_value")
+
+    # Validate we can re-assign the value, this is a test for
+    # a bug where validate_assignment would cause an AttributeError
+    # for __dict__ on the target schema.
+    schema_inst.str_var = "reassigned_value"
+    try:
+        schema_inst.str_var = 5
+        raise AssertionError()
+    except ValidationError:
+        # We expect this error, all is okay
+        pass
Repository: vitalik/django-ninja
Pull request #1256 (2024-08-05 15:26:05)

Support import string in router.add_router
Added support for importing nested router with string path. This unifies behaviour with `api.add_router`:


```
# api.add_router
api = NinjaAPI()
api.add_router("main", "myproject.app1.router")

# router.add_router
router = Router()
router.add_router("nested", "myproject.app1.nested.router")
```


Patch:
diff --git a/ninja/router.py b/ninja/router.py
index c1d1372..13e26d4 100644
--- a/ninja/router.py
+++ b/ninja/router.py
@@ -12,6 +12,7 @@ from typing import (
 
 from django.urls import URLPattern
 from django.urls import path as django_path
+from django.utils.module_loading import import_string
 
 from ninja.constants import NOT_SET, NOT_SET_TYPE
 from ninja.errors import ConfigError
@@ -371,12 +372,16 @@ class Router:
     def add_router(
         self,
         prefix: str,
-        router: "Router",
+        router: Union["Router", str],
         *,
         auth: Any = NOT_SET,
         throttle: Union[BaseThrottle, List[BaseThrottle], NOT_SET_TYPE] = NOT_SET,
         tags: Optional[List[str]] = None,
     ) -> None:
+        if isinstance(router, str):
+            router = import_string(router)
+            assert isinstance(router, Router)
+
         if self.api:
             # we are already attached to an api
             self.api.add_router(


Test patch:
diff --git a/tests/test_router_add_router.py b/tests/test_router_add_router.py
new file mode 100644
index 0000000..e777892
--- /dev/null
+++ b/tests/test_router_add_router.py
@@ -0,0 +1,21 @@
+from ninja import NinjaAPI, Router
+from ninja.testing import TestClient
+
+router = Router()
+
+
+@router.get("/")
+def op(request):
+    return True
+
+
+def test_add_router_with_string_path():
+    main_router = Router()
+    main_router.add_router("sub", "tests.test_router_add_router.router")
+
+    api = NinjaAPI()
+    api.add_router("main", main_router)
+
+    client = TestClient(api)
+
+    assert client.get("/main/sub/").status_code == 200