Skip to content

Commit 0652d36

Browse files
authored
support KubeSpawner profile_options (#2937)
1 parent 13af52c commit 0652d36

File tree

1 file changed

+44
-1
lines changed

1 file changed

+44
-1
lines changed

src/_nebari/stages/kubernetes_services/__init__.py

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,13 @@
55
from typing import Any, Dict, List, Optional, Type, Union
66
from urllib.parse import urlencode
77

8-
from pydantic import ConfigDict, Field, field_validator, model_validator
8+
from pydantic import (
9+
ConfigDict,
10+
Field,
11+
field_validator,
12+
model_serializer,
13+
model_validator,
14+
)
915
from typing_extensions import Self
1016

1117
from _nebari import constants
@@ -109,6 +115,42 @@ class KubeSpawner(schema.Base):
109115
model_config = ConfigDict(extra="allow")
110116

111117

118+
class ProfileOptionUnlistedChoice(schema.Base):
119+
enabled: bool = False
120+
display_name: str
121+
display_name_in_choices: Optional[str] = None
122+
validation_regex: Optional[str] = None
123+
validation_message: Optional[str] = None
124+
kubespawner_override: Dict[str, Any]
125+
126+
127+
class ProfileOptionChoice(schema.Base):
128+
display_name: str
129+
default: Optional[bool] = False
130+
kubespawner_override: Dict[str, Any]
131+
132+
133+
class ProfileOption(schema.Base):
134+
display_name: str
135+
unlisted_choice: Optional[ProfileOptionUnlistedChoice] = None
136+
choices: Dict[str, ProfileOptionChoice]
137+
138+
@field_validator("choices")
139+
def validate_choices(cls, v):
140+
defaults = [choice for choice in v.values() if choice.default]
141+
if len(defaults) > 1:
142+
raise ValueError("Only one choice can be marked as default")
143+
return v
144+
145+
# We need to exclude unlisted_choice if not set.
146+
# This was the recommended solution without affecting the parent.
147+
# reference: https://github.com/pydantic/pydantic/discussions/7315
148+
@model_serializer(mode="wrap")
149+
def serialize_model(self, handler) -> dict[str, Any]:
150+
result = handler(self)
151+
return {k: v for k, v in result.items() if v is not None}
152+
153+
112154
class JupyterLabProfile(schema.Base):
113155
access: AccessEnum = AccessEnum.all
114156
display_name: str
@@ -117,6 +159,7 @@ class JupyterLabProfile(schema.Base):
117159
users: Optional[List[str]] = None
118160
groups: Optional[List[str]] = None
119161
kubespawner_override: Optional[KubeSpawner] = None
162+
profile_options: Optional[dict[str, ProfileOption]] = None
120163

121164
@model_validator(mode="after")
122165
def only_yaml_can_have_groups_and_users(self):

0 commit comments

Comments
 (0)