redblack-python-sdk 0.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,150 @@
1
+ """Shared behavior for generated RedBlack wire models.
2
+
3
+ This module is hand maintained. The concrete models in :mod:`generated` are
4
+ created from the captured API contract.
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ from collections.abc import Iterator
10
+ from datetime import datetime
11
+ from enum import IntEnum
12
+ from typing import Any, Self
13
+
14
+ from pydantic import BaseModel, ConfigDict, PrivateAttr, model_validator
15
+
16
+ from ..response import HttpMetadata
17
+
18
+
19
+ class UnsetType:
20
+ """Marker used when an optional request field was not supplied.
21
+
22
+ ``None`` is a real JSON value. A separate marker lets PATCH and other
23
+ request models distinguish an omitted field from an explicitly-null field.
24
+ """
25
+
26
+ __slots__ = ()
27
+
28
+ def __copy__(self) -> UnsetType:
29
+ return self
30
+
31
+ def __deepcopy__(self, memo: dict[int, Any]) -> UnsetType:
32
+ del memo
33
+ return self
34
+
35
+ def __repr__(self) -> str:
36
+ return "UNSET"
37
+
38
+
39
+ UNSET = UnsetType()
40
+
41
+
42
+ def _walk_values(value: Any) -> Iterator[Any]:
43
+ """Yield values nested in supported request containers."""
44
+
45
+ yield value
46
+ if isinstance(value, BaseModel):
47
+ for field_name in value.model_fields_set:
48
+ yield from _walk_values(getattr(value, field_name))
49
+ elif isinstance(value, dict):
50
+ for child in value.values():
51
+ yield from _walk_values(child)
52
+ elif isinstance(value, list | tuple | set | frozenset):
53
+ for child in value:
54
+ yield from _walk_values(child)
55
+
56
+
57
+ class RequestModel(BaseModel):
58
+ """Base for outbound bodies.
59
+
60
+ Request models reject unknown keys and accept either Python field names or
61
+ their exact wire aliases. Datetimes must carry a timezone so local wall
62
+ time can never be sent accidentally.
63
+ """
64
+
65
+ model_config = ConfigDict(
66
+ arbitrary_types_allowed=True,
67
+ extra="forbid",
68
+ hide_input_in_errors=True,
69
+ populate_by_name=True,
70
+ protected_namespaces=(),
71
+ )
72
+
73
+ @model_validator(mode="after")
74
+ def _reject_naive_datetimes(self) -> Self:
75
+ for value in _walk_values(self):
76
+ if isinstance(value, datetime) and (value.tzinfo is None or value.utcoffset() is None):
77
+ raise ValueError("request datetimes must include an explicit UTC offset")
78
+ return self
79
+
80
+
81
+ class ResponseModel(BaseModel):
82
+ """Base for inbound bodies.
83
+
84
+ Response models preserve unknown properties because RedBlack documents
85
+ additive response fields as a non-breaking API change.
86
+ """
87
+
88
+ model_config = ConfigDict(
89
+ arbitrary_types_allowed=True,
90
+ extra="allow",
91
+ hide_input_in_errors=True,
92
+ populate_by_name=True,
93
+ protected_namespaces=(),
94
+ )
95
+
96
+ _http: HttpMetadata | None = PrivateAttr(default=None)
97
+
98
+ @property
99
+ def http(self) -> HttpMetadata | None:
100
+ """Non-wire HTTP metadata attached by the client, if available."""
101
+
102
+ return self._http
103
+
104
+ def _attach_http(self, metadata: HttpMetadata) -> Self:
105
+ """Attach transport metadata without adding it to model serialization."""
106
+
107
+ self._http = metadata
108
+ return self
109
+
110
+
111
+ class ODataPageModel(ResponseModel):
112
+ """Common conveniences for generated OData collection envelopes."""
113
+
114
+ @property
115
+ def items(self) -> list[Any]:
116
+ value = getattr(self, "value", None)
117
+ return value if isinstance(value, list) else []
118
+
119
+ @property
120
+ def total_count(self) -> int | None:
121
+ value = getattr(self, "odata_count", None)
122
+ return value if isinstance(value, int) and not isinstance(value, bool) else None
123
+
124
+
125
+ class OpenIntEnum(IntEnum):
126
+ """Integer enum that retains response values added by a newer API."""
127
+
128
+ @classmethod
129
+ def _missing_(cls, value: object) -> OpenIntEnum | None:
130
+ if not isinstance(value, int) or isinstance(value, bool):
131
+ return None
132
+
133
+ # Enum's supported extension hook is `_missing_`. Creating a
134
+ # pseudo-member retains the integer and keeps future values comparable
135
+ # without pretending that the SDK knows their vendor name.
136
+ pseudo_member = int.__new__(cls, value)
137
+ pseudo_member._name_ = f"UNKNOWN_{value}".replace("-", "NEG_")
138
+ pseudo_member._value_ = value
139
+ cls._value2member_map_[value] = pseudo_member
140
+ return pseudo_member
141
+
142
+
143
+ __all__ = [
144
+ "OpenIntEnum",
145
+ "ODataPageModel",
146
+ "RequestModel",
147
+ "ResponseModel",
148
+ "UNSET",
149
+ "UnsetType",
150
+ ]