Skip to content

Commit

Permalink
fix: add the Required.true flag to schemas
Browse files Browse the repository at this point in the history
  • Loading branch information
azmeuk committed Dec 2, 2024
1 parent d131d07 commit f228849
Show file tree
Hide file tree
Showing 18 changed files with 68 additions and 27 deletions.
4 changes: 3 additions & 1 deletion scim2_models/rfc7643/enterprise_user.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,9 @@ class Manager(ComplexAttribute):


class EnterpriseUser(Extension):
schemas: list[str] = ["urn:ietf:params:scim:schemas:extension:enterprise:2.0:User"]
schemas: Annotated[list[str], Required.true] = [
"urn:ietf:params:scim:schemas:extension:enterprise:2.0:User"
]

employee_number: Optional[str] = None
"""Numeric or alphanumeric identifier assigned to a person, typically based
Expand Down
5 changes: 4 additions & 1 deletion scim2_models/rfc7643/group.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
from ..base import MultiValuedComplexAttribute
from ..base import Mutability
from ..base import Reference
from ..base import Required
from .resource import Resource


Expand All @@ -31,7 +32,9 @@ class GroupMember(MultiValuedComplexAttribute):


class Group(Resource):
schemas: list[str] = ["urn:ietf:params:scim:schemas:core:2.0:Group"]
schemas: Annotated[list[str], Required.true] = [
"urn:ietf:params:scim:schemas:core:2.0:Group"
]

display_name: Optional[str] = None
"""A human-readable name for the Group."""
Expand Down
4 changes: 2 additions & 2 deletions scim2_models/rfc7643/resource.py
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ def __new__(cls, name, bases, attrs, **kwargs):


class Resource(BaseModel, Generic[AnyExtension], metaclass=ResourceMetaclass):
schemas: list[str]
schemas: Annotated[list[str], Required.true]
"""The "schemas" attribute is a REQUIRED attribute and is an array of
Strings containing URIs that are used to indicate the namespaces of the
SCIM schemas that define the attributes present in the current JSON
Expand Down Expand Up @@ -229,7 +229,7 @@ def get_by_payload(resource_types: list[type], payload: dict, **kwargs):
return Resource.get_by_schema(resource_types, schema, **kwargs)

@field_serializer("schemas")
def set_extension_schemas(self, schemas: list[str]):
def set_extension_schemas(self, schemas: Annotated[list[str], Required.true]):
"""Add model extension ids to the 'schemas' attribute."""
extension_schemas = self.get_extension_models().keys()
schemas = self.schemas + [
Expand Down
4 changes: 3 additions & 1 deletion scim2_models/rfc7643/resource_type.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,9 @@ class SchemaExtension(ComplexAttribute):


class ResourceType(Resource):
schemas: list[str] = ["urn:ietf:params:scim:schemas:core:2.0:ResourceType"]
schemas: Annotated[list[str], Required.true] = [
"urn:ietf:params:scim:schemas:core:2.0:ResourceType"
]

name: Annotated[Optional[str], Mutability.read_only, Required.true] = None
"""The resource type name.
Expand Down
6 changes: 4 additions & 2 deletions scim2_models/rfc7643/schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ def make_python_model(
if attr.name
}
pydantic_attributes["schemas"] = (
Optional[list[str]],
Annotated[list[str], Required.true],
Field(default=[obj.id]),
)

Expand Down Expand Up @@ -240,7 +240,9 @@ def to_python(self) -> Optional[tuple[Any, Field]]:


class Schema(Resource):
schemas: list[str] = ["urn:ietf:params:scim:schemas:core:2.0:Schema"]
schemas: Annotated[list[str], Required.true] = [
"urn:ietf:params:scim:schemas:core:2.0:Schema"
]

id: Annotated[Optional[str], Mutability.read_only, Required.true] = None
"""The unique URI of the schema."""
Expand Down
4 changes: 3 additions & 1 deletion scim2_models/rfc7643/service_provider_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,9 @@ class Type(str, Enum):


class ServiceProviderConfig(Resource):
schemas: list[str] = ["urn:ietf:params:scim:schemas:core:2.0:ServiceProviderConfig"]
schemas: Annotated[list[str], Required.true] = [
"urn:ietf:params:scim:schemas:core:2.0:ServiceProviderConfig"
]

id: Annotated[
Optional[str], Mutability.read_only, Returned.default, Uniqueness.global_
Expand Down
4 changes: 3 additions & 1 deletion scim2_models/rfc7643/user.py
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,9 @@ class X509Certificate(MultiValuedComplexAttribute):


class User(Resource):
schemas: list[str] = ["urn:ietf:params:scim:schemas:core:2.0:User"]
schemas: Annotated[list[str], Required.true] = [
"urn:ietf:params:scim:schemas:core:2.0:User"
]

user_name: Annotated[Optional[str], Uniqueness.server, Required.true] = None
"""Unique identifier for the User, typically used by the user to directly
Expand Down
9 changes: 7 additions & 2 deletions scim2_models/rfc7644/bulk.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
from pydantic import PlainSerializer

from ..base import ComplexAttribute
from ..base import Required
from ..utils import int_to_str
from .message import Message

Expand Down Expand Up @@ -53,7 +54,9 @@ class BulkRequest(Message):
The models for Bulk operations are defined, but their behavior is not implemented nor tested yet.
"""

schemas: list[str] = ["urn:ietf:params:scim:api:messages:2.0:BulkRequest"]
schemas: Annotated[list[str], Required.true] = [
"urn:ietf:params:scim:api:messages:2.0:BulkRequest"
]

fail_on_errors: Optional[int] = None
"""An integer specifying the number of errors that the service provider
Expand All @@ -74,7 +77,9 @@ class BulkResponse(Message):
The models for Bulk operations are defined, but their behavior is not implemented nor tested yet.
"""

schemas: list[str] = ["urn:ietf:params:scim:api:messages:2.0:BulkResponse"]
schemas: Annotated[list[str], Required.true] = [
"urn:ietf:params:scim:api:messages:2.0:BulkResponse"
]

operations: Optional[list[BulkOperation]] = Field(
None, serialization_alias="Operations"
Expand Down
5 changes: 4 additions & 1 deletion scim2_models/rfc7644/error.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,17 @@

from pydantic import PlainSerializer

from ..base import Required
from ..utils import int_to_str
from .message import Message


class Error(Message):
"""Representation of SCIM API errors."""

schemas: list[str] = ["urn:ietf:params:scim:api:messages:2.0:Error"]
schemas: Annotated[list[str], Required.true] = [
"urn:ietf:params:scim:api:messages:2.0:Error"
]

status: Annotated[Optional[int], PlainSerializer(int_to_str)] = None
"""The HTTP status code (see Section 6 of [RFC7231]) expressed as a JSON
Expand Down
5 changes: 4 additions & 1 deletion scim2_models/rfc7644/list_response.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
from ..base import BaseModel
from ..base import BaseModelType
from ..base import Context
from ..base import Required
from ..rfc7643.resource import AnyResource
from .message import Message

Expand Down Expand Up @@ -78,7 +79,9 @@ def __new__(cls, name, bases, attrs, **kwargs):


class ListResponse(Message, Generic[AnyResource], metaclass=ListResponseMetaclass):
schemas: list[str] = ["urn:ietf:params:scim:api:messages:2.0:ListResponse"]
schemas: Annotated[list[str], Required.true] = [
"urn:ietf:params:scim:api:messages:2.0:ListResponse"
]

total_results: Optional[int] = None
"""The total number of results returned by the list or query operation."""
Expand Down
5 changes: 4 additions & 1 deletion scim2_models/rfc7644/message.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
from typing import Annotated

from ..base import BaseModel
from ..base import Required


class Message(BaseModel):
"""SCIM protocol messages as defined by :rfc:`RFC7644 §3.1 <7644#section-3.1>`."""

schemas: list[str]
schemas: Annotated[list[str], Required.true]
6 changes: 5 additions & 1 deletion scim2_models/rfc7644/patch_op.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
from enum import Enum
from typing import Annotated
from typing import Any
from typing import Optional

from pydantic import Field
from pydantic import field_validator

from ..base import ComplexAttribute
from ..base import Required
from .message import Message


Expand Down Expand Up @@ -57,7 +59,9 @@ class PatchOp(Message):
The models for Patch operations are defined, but their behavior is not implemented nor tested yet.
"""

schemas: list[str] = ["urn:ietf:params:scim:api:messages:2.0:PatchOp"]
schemas: Annotated[list[str], Required.true] = [
"urn:ietf:params:scim:api:messages:2.0:PatchOp"
]

operations: Optional[list[PatchOperation]] = Field(
None, serialization_alias="Operations"
Expand Down
6 changes: 5 additions & 1 deletion scim2_models/rfc7644/search_request.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
from enum import Enum
from typing import Annotated
from typing import Optional

from pydantic import field_validator
from pydantic import model_validator

from ..base import Required
from .message import Message


Expand All @@ -13,7 +15,9 @@ class SearchRequest(Message):
https://datatracker.ietf.org/doc/html/rfc7644#section-3.4.3
"""

schemas: list[str] = ["urn:ietf:params:scim:api:messages:2.0:SearchRequest"]
schemas: Annotated[list[str], Required.true] = [
"urn:ietf:params:scim:api:messages:2.0:SearchRequest"
]

attributes: Optional[list[str]] = None
"""A multi-valued list of strings indicating the names of resource
Expand Down
4 changes: 3 additions & 1 deletion tests/test_list_response.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from typing import Annotated
from typing import Union

import pytest
Expand All @@ -7,6 +8,7 @@
from scim2_models import EnterpriseUser
from scim2_models import Group
from scim2_models import ListResponse
from scim2_models import Required
from scim2_models import Resource
from scim2_models import ResourceType
from scim2_models import ServiceProviderConfig
Expand Down Expand Up @@ -107,7 +109,7 @@ def test_mixed_types(load_sample):


class Foobar(Resource):
schemas: list[str] = ["foobarschema"]
schemas: Annotated[list[str], Required.true] = ["foobarschema"]


def test_mixed_types_type_missing(load_sample):
Expand Down
9 changes: 5 additions & 4 deletions tests/test_model_attributes.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
from scim2_models.base import BaseModel
from scim2_models.base import ComplexAttribute
from scim2_models.base import Context
from scim2_models.base import Required
from scim2_models.base import Returned
from scim2_models.base import validate_attribute_urn
from scim2_models.rfc7643.enterprise_user import EnterpriseUser
Expand All @@ -20,7 +21,7 @@ class Sub(ComplexAttribute):


class Sup(Resource):
schemas: list[str] = ["urn:example:2.0:Sup"]
schemas: Annotated[list[str], Required.true] = ["urn:example:2.0:Sup"]
dummy: str
sub: Sub
subs: list[Sub]
Expand All @@ -44,23 +45,23 @@ class Baz(ComplexAttribute):


class Foo(Resource):
schemas: list[str] = ["urn:example:2.0:Foo"]
schemas: Annotated[list[str], Required.true] = ["urn:example:2.0:Foo"]
sub: Annotated[ReturnedModel, Returned.default]
bar: str
snake_case: str
baz: Optional[Baz] = None


class Bar(Resource):
schemas: list[str] = ["urn:example:2.0:Bar"]
schemas: Annotated[list[str], Required.true] = ["urn:example:2.0:Bar"]
sub: Annotated[ReturnedModel, Returned.default]
bar: str
snake_case: str
baz: Optional[Baz] = None


class Extension(Resource):
schemas: list[str] = ["urn:example:2.0:Extension"]
schemas: Annotated[list[str], Required.true] = ["urn:example:2.0:Extension"]
baz: str


Expand Down
5 changes: 3 additions & 2 deletions tests/test_model_serialization.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from scim2_models.base import ComplexAttribute
from scim2_models.base import Context
from scim2_models.base import Mutability
from scim2_models.base import Required
from scim2_models.base import Returned
from scim2_models.rfc7643.resource import Resource

Expand All @@ -18,7 +19,7 @@ class SubRetModel(ComplexAttribute):


class SupRetResource(Resource):
schemas: list[str] = ["org:example:SupRetResource"]
schemas: Annotated[list[str], Required.true] = ["org:example:SupRetResource"]

always_returned: Annotated[Optional[str], Returned.always] = None
never_returned: Annotated[Optional[str], Returned.never] = None
Expand All @@ -29,7 +30,7 @@ class SupRetResource(Resource):


class MutResource(Resource):
schemas: list[str] = ["org:example:MutResource"]
schemas: Annotated[list[str], Required.true] = ["org:example:MutResource"]

read_only: Annotated[Optional[str], Mutability.read_only] = None
read_write: Annotated[Optional[str], Mutability.read_write] = None
Expand Down
6 changes: 3 additions & 3 deletions tests/test_model_validation.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@


class RetResource(Resource):
schemas: list[str] = ["org:example:RetResource"]
schemas: Annotated[list[str], Required.true] = ["org:example:RetResource"]

always_returned: Annotated[Optional[str], Returned.always] = None
never_returned: Annotated[Optional[str], Returned.never] = None
Expand All @@ -21,7 +21,7 @@ class RetResource(Resource):


class MutResource(Resource):
schemas: list[str] = ["org:example:MutResource"]
schemas: Annotated[list[str], Required.true] = ["org:example:MutResource"]

read_only: Annotated[Optional[str], Mutability.read_only] = None
read_write: Annotated[Optional[str], Mutability.read_write] = None
Expand All @@ -30,7 +30,7 @@ class MutResource(Resource):


class ReqResource(Resource):
schemas: list[str] = ["org:example:ReqResource"]
schemas: Annotated[list[str], Required.true] = ["org:example:ReqResource"]

required: Annotated[Optional[str], Required.true] = None
optional: Annotated[Optional[str], Required.false] = None
Expand Down
4 changes: 3 additions & 1 deletion tests/test_resource_extension.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import datetime
from typing import Annotated
from typing import Optional
from typing import Union

Expand All @@ -9,6 +10,7 @@
from scim2_models import Extension
from scim2_models import Manager
from scim2_models import Meta
from scim2_models import Required
from scim2_models import User


Expand Down Expand Up @@ -201,7 +203,7 @@ def test_invalid_setitem():


class SuperHero(Extension):
schemas: list[str] = ["example:extensions:SuperHero"]
schemas: Annotated[list[str], Required.true] = ["example:extensions:SuperHero"]

superpower: Optional[str] = None
"""The superhero superpower."""
Expand Down

0 comments on commit f228849

Please sign in to comment.