Skip to content

Commit e3c84d5

Browse files
committed
feat: Forbid bulkId field
1 parent d5f199b commit e3c84d5

3 files changed

Lines changed: 36 additions & 0 deletions

File tree

scim2_models/base.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
from inspect import isclass
33
from typing import Any
44
from typing import Optional
5+
from typing import ClassVar
56
from typing import get_args
67
from typing import get_origin
78

@@ -112,6 +113,14 @@ class BaseModel(PydanticBaseModel):
112113
extra="forbid",
113114
)
114115

116+
_allow_bulk_id: ClassVar[bool] = False
117+
"""Allow bulkId field for the model"""
118+
119+
@classmethod
120+
def __pydantic_init_subclass__(cls, **kwargs) -> None:
121+
# Validate field names
122+
cls._check_bulk_id()
123+
115124
@classmethod
116125
def get_field_annotation(cls, field_name: str, annotation_type: type) -> Any:
117126
"""Return the annotation of type 'annotation_type' of the field 'field_name'.
@@ -538,6 +547,19 @@ def _set_complex_attribute_urns(self) -> None:
538547
else:
539548
attr_value._attribute_urn = schema
540549

550+
@classmethod
551+
def _check_bulk_id(cls) -> None:
552+
"""Enforce bulkId as reserved field per RFC 7643 §3.1.
553+
554+
Check if a bulkdId field is defined and
555+
raise error if `_allow_bulk_id` is set to `False`
556+
"""
557+
if cls._allow_bulk_id:
558+
return
559+
for info in cls.model_fields.values():
560+
if info.serialization_alias == "bulkId":
561+
raise TypeError(f"{cls.__name__}: bulkId is reserved for BulkOperation")
562+
541563
@field_serializer("*", mode="wrap")
542564
def scim_serializer(
543565
self,

scim2_models/messages/bulk.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212

1313

1414
class BulkOperation(ComplexAttribute):
15+
_allow_bulk_id = True
16+
1517
class Method(str, Enum):
1618
post = "POST"
1719
put = "PUT"

tests/test_model_attributes.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
import uuid
2+
import pytest
23
from typing import Annotated
4+
from pydantic import Field
35

46
from scim2_models import URN
57
from scim2_models.annotations import Returned
@@ -377,3 +379,13 @@ def test_short_attr_path_with_plain_name():
377379

378380
assert _short_attr_path("userName") == "userName"
379381
assert _short_attr_path("name.familyName") == "name.familyName"
382+
383+
384+
def test_forbid_bulk_id():
385+
"""Forbid bulkId from class definition"""
386+
with pytest.raises(TypeError) as exc_info:
387+
class CustomModel(Resource):
388+
__schema__ = URN("urn:example:schemas:CustomModel")
389+
bulk_id: str | None = None
390+
391+
assert str(exc_info.value) == "CustomModel: bulkId is reserved for BulkOperation"

0 commit comments

Comments
 (0)