python-datamodel 0.10.1__cp313-cp313-win32.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.
Files changed (78) hide show
  1. datamodel/__init__.py +13 -0
  2. datamodel/abstract.py +383 -0
  3. datamodel/adaptive/__init__.py +0 -0
  4. datamodel/adaptive/models.py +598 -0
  5. datamodel/aliases/__init__.py +26 -0
  6. datamodel/base.py +180 -0
  7. datamodel/converters.c +43471 -0
  8. datamodel/converters.cp313-win32.pyd +0 -0
  9. datamodel/converters.html +17387 -0
  10. datamodel/converters.pyx +1489 -0
  11. datamodel/exceptions.c +13455 -0
  12. datamodel/exceptions.cp313-win32.pyd +0 -0
  13. datamodel/exceptions.html +1261 -0
  14. datamodel/exceptions.pxd +13 -0
  15. datamodel/exceptions.pyx +50 -0
  16. datamodel/fields.cp313-win32.pyd +0 -0
  17. datamodel/fields.cpp +17401 -0
  18. datamodel/fields.html +3912 -0
  19. datamodel/fields.pyx +309 -0
  20. datamodel/functions.cp313-win32.pyd +0 -0
  21. datamodel/functions.cpp +9068 -0
  22. datamodel/functions.html +1766 -0
  23. datamodel/functions.pxd +9 -0
  24. datamodel/functions.pyx +82 -0
  25. datamodel/jsonld/__init__.py +45 -0
  26. datamodel/jsonld/models.py +500 -0
  27. datamodel/libs/__init__.py +1 -0
  28. datamodel/libs/mapping.c +15067 -0
  29. datamodel/libs/mapping.cp313-win32.pyd +0 -0
  30. datamodel/libs/mapping.html +2618 -0
  31. datamodel/libs/mapping.pxd +11 -0
  32. datamodel/libs/mapping.pyx +135 -0
  33. datamodel/libs/mutables.py +127 -0
  34. datamodel/models.py +814 -0
  35. datamodel/parsers/__init__.py +0 -0
  36. datamodel/parsers/encoders.py +15 -0
  37. datamodel/parsers/json.cp313-win32.pyd +0 -0
  38. datamodel/parsers/json.cpp +17004 -0
  39. datamodel/parsers/json.html +3365 -0
  40. datamodel/parsers/json.pyx +250 -0
  41. datamodel/profiler.py +21 -0
  42. datamodel/py.typed +0 -0
  43. datamodel/rs_core/Cargo.toml +17 -0
  44. datamodel/rs_core/src/lib.rs +294 -0
  45. datamodel/rs_parsers/Cargo.toml +22 -0
  46. datamodel/rs_parsers/src/lib.rs +571 -0
  47. datamodel/rs_parsers.cp313-win32.pyd +0 -0
  48. datamodel/rs_validators/Cargo.toml +17 -0
  49. datamodel/rs_validators/src/lib.rs +0 -0
  50. datamodel/typedefs/__init__.py +9 -0
  51. datamodel/typedefs/singleton.c +9169 -0
  52. datamodel/typedefs/singleton.cp313-win32.pyd +0 -0
  53. datamodel/typedefs/singleton.html +629 -0
  54. datamodel/typedefs/singleton.pxd +9 -0
  55. datamodel/typedefs/singleton.pyx +24 -0
  56. datamodel/typedefs/types.c +11716 -0
  57. datamodel/typedefs/types.cp313-win32.pyd +0 -0
  58. datamodel/typedefs/types.html +732 -0
  59. datamodel/typedefs/types.pxd +11 -0
  60. datamodel/typedefs/types.pyx +39 -0
  61. datamodel/types.c +7165 -0
  62. datamodel/types.cp313-win32.pyd +0 -0
  63. datamodel/types.html +716 -0
  64. datamodel/types.pyx +100 -0
  65. datamodel/validation.cp313-win32.pyd +0 -0
  66. datamodel/validation.cpp +17085 -0
  67. datamodel/validation.html +4769 -0
  68. datamodel/validation.pyx +315 -0
  69. datamodel/version.py +13 -0
  70. examples/nn/examples.py +311 -0
  71. examples/nn/stores.py +151 -0
  72. examples/tests/sp_types.py +294 -0
  73. examples/tests/speed_dates.py +26 -0
  74. python_datamodel-0.10.1.dist-info/LICENSE +29 -0
  75. python_datamodel-0.10.1.dist-info/METADATA +320 -0
  76. python_datamodel-0.10.1.dist-info/RECORD +78 -0
  77. python_datamodel-0.10.1.dist-info/WHEEL +5 -0
  78. python_datamodel-0.10.1.dist-info/top_level.txt +7 -0
@@ -0,0 +1,598 @@
1
+ from uuid import UUID, uuid4
2
+ from enum import Enum
3
+ from typing import List, Dict, Any, Optional, Union
4
+ import contextlib
5
+ from ..base import BaseModel, Field, register_renderer
6
+
7
+ # https://adaptivecards.io/explorer/Media.html
8
+
9
+ def auto_uuid(*args, **kwargs): # pylint: disable=W0613
10
+ return uuid4()
11
+
12
+ class ContainerStyle(str, Enum):
13
+ """Shared Style for all containers in a Adaptive Card."""
14
+ default = 'default'
15
+ accent = 'accent'
16
+ good = 'good'
17
+ attention = 'attention'
18
+ warning = 'warning'
19
+ emphasis = 'emphasis'
20
+
21
+ class ContainerColor(str, Enum):
22
+ """Shared Color for all containers in a Adaptive Card."""
23
+ default = 'default'
24
+ dark = 'dark'
25
+ light = 'light'
26
+ accent = 'accent'
27
+ good = 'good'
28
+ attention = 'attention'
29
+ warning = 'warning'
30
+
31
+
32
+ class FontType(str, Enum):
33
+ """Font Type for TextBlock."""
34
+ default = 'default'
35
+ monospace = 'monospace'
36
+
37
+ class FontSize(str, Enum):
38
+ """Font Size for TextBlock."""
39
+ default = 'default'
40
+ small = 'small'
41
+ medium = 'medium'
42
+ large = 'large'
43
+ extraLarge = 'extraLarge'
44
+
45
+ class FontWeight(str, Enum):
46
+ """Font Weight for TextBlock."""
47
+ default = 'default'
48
+ lighter = 'lighter'
49
+ bolder = 'bolder'
50
+
51
+
52
+ class SelectAction(str, Enum):
53
+ """Action to be taken when a cell is selected."""
54
+ exectute = 'Action.Execute'
55
+ submit = 'Action.Submit'
56
+ openUrl = 'Action.OpenUrl'
57
+ toggleVisibility = 'Action.ToggleVisibility'
58
+
59
+
60
+ class CardElement(BaseModel):
61
+ """Base class for Adaptive card elements."""
62
+ type: str
63
+
64
+ class Meta:
65
+ as_objects: True
66
+ remove_nulls = True
67
+
68
+ def __post_init__(self):
69
+ if not self.type:
70
+ self.type = self.__class__.__name__
71
+ return super().__post_init__()
72
+
73
+ def to_adaptive(self) -> Dict[str, Any]:
74
+ """Convert to AdaptiveCard JSON-representation."""
75
+ return self.to_dict()
76
+
77
+ class TextBlock(CardElement):
78
+ text: str
79
+ size: Optional[str] = None
80
+ weight: Optional[str] = None
81
+ horizontalAlignment: Optional[str] = None
82
+ wrap: Optional[bool] = Field(default=True)
83
+ style: Optional[str] = None
84
+ isSubtle: Optional[bool] = None
85
+
86
+
87
+ class TextRun(CardElement):
88
+ """Defines a single run of formatted text."""
89
+ type: str = Field(default='TextRun')
90
+ text: str
91
+ color: Optional[ContainerStyle] = Field(ContainerStyle.default)
92
+ fontType: Optional[FontType] = Field(FontType.default)
93
+ highlight: bool = Field(default=False)
94
+ isSubtle: bool = Field(default=False)
95
+ italic: bool = Field(default=False)
96
+ strikethrough: bool = Field(default=False)
97
+ underline: bool = Field(default=False)
98
+ selectAction: Optional[SelectAction] = Field(default=None)
99
+ size: Optional[FontSize] = Field(default=None)
100
+ weight: Optional[FontWeight] = Field(default=FontWeight.default)
101
+
102
+
103
+ class RichTextBlock(CardElement):
104
+ type: str = Field(default='RichTextBlock')
105
+ inlines: List[Union[str, TextRun]] = Field(default_factory=list)
106
+ horizontalAlignment: Optional[str] = Field(default='left')
107
+
108
+
109
+ class Column(CardElement):
110
+ items: Optional[List[CardElement]] = Field(default_factory=list)
111
+ width: Optional[str] = Field(default='auto')
112
+
113
+ def add_item(self, item: Union[CardElement, List[CardElement]]):
114
+ if isinstance(item, list):
115
+ self.items.extend(item)
116
+ else:
117
+ self.items.append(item)
118
+
119
+ def to_adaptive(self) -> Dict[str, Any]:
120
+ """Ensure proper JSON serialization."""
121
+ return {
122
+ "type": "Column",
123
+ "items": [
124
+ item.to_adaptive() for item in self.items if isinstance(item, CardElement) # noqa
125
+ ], # Prevent duplicates
126
+ "width": self.width
127
+ }
128
+
129
+
130
+ class InputElement(CardElement):
131
+ """Base class for input elements."""
132
+ type: str = Field(default='Input.Text')
133
+ id: str
134
+ label: Optional[str] = None
135
+ placeholder: Optional[str] = None
136
+
137
+ class InputText(InputElement):
138
+ style: Optional[str] = None
139
+ isRequired: Optional[bool] = None
140
+ errorMessage: Optional[str] = None
141
+ isMultiline: Optional[bool] = None
142
+
143
+ class InputNumber(InputElement):
144
+ min: Optional[int] = None
145
+ max: Optional[int] = None
146
+ value: Optional[int] = None
147
+ errorMessage: Optional[str] = None
148
+
149
+ class InputDate(InputElement):
150
+ value: Optional[str] = None
151
+
152
+ class InputTime(InputElement):
153
+ value: Optional[str] = None
154
+
155
+ class Choice(BaseModel):
156
+ title: str
157
+ value: str
158
+
159
+ class InputChoiceSet(InputElement):
160
+ choices: List[Choice]
161
+ value: Optional[str] = None
162
+ isMultiSelect: Optional[bool] = None
163
+ style: Optional[str] = None
164
+
165
+ class InputToggle(InputElement):
166
+ title: str
167
+ valueOn: str
168
+ valueOff: str
169
+ isRequired: Optional[bool] = None
170
+ errorMessage: Optional[str] = None
171
+
172
+ class FactElement(BaseModel):
173
+ """A single fact."""
174
+ title: str
175
+ value: str
176
+
177
+ class Image(CardElement):
178
+ type: str = Field(default='Image')
179
+ url: str
180
+ size: Optional[str] = None
181
+ style: Optional[str] = None
182
+ altText: Optional[str] = None
183
+
184
+
185
+ class MediaSource(CardElement):
186
+ mimeType: str
187
+ url: str
188
+
189
+ class CaptionSource(CardElement):
190
+ mimeType: str = Field(default='vtt')
191
+ label: str = Field(default='English')
192
+ url: str
193
+
194
+ class Media(CardElement):
195
+ type: str = Field(default='Media')
196
+ sources: List[MediaSource] = Field(default_factory=list)
197
+ poster: Optional[str] = None
198
+ captionSources: List[CaptionSource] = Field(default_factory=list)
199
+
200
+ def add_source(self, source: Union[str, MediaSource]):
201
+ if isinstance(source, str):
202
+ source = MediaSource(url=source, mimeType='video/mp4')
203
+ self.sources.append(source)
204
+ return self
205
+
206
+ class ImageFillMode(str, Enum):
207
+ """Describes how the image should be filled."""
208
+ cover = 'cover'
209
+ repeatHorizontally = 'repeatHorizontally'
210
+ repeatVertically = 'repeatVertically'
211
+ repeat = 'repeat'
212
+
213
+ class BackgroundImage(CardElement):
214
+ type: str = Field(default='BackgroundImage')
215
+ url: str
216
+ fillMode: Optional[ImageFillMode] = Field(default=ImageFillMode.cover)
217
+
218
+ ## Table structure:
219
+
220
+ class TableCell(BaseModel):
221
+ """A single cell in a TableRow."""
222
+ type: str = Field(default='TableCell')
223
+ style: Optional[ContainerStyle] = Field(default=ContainerStyle.default)
224
+ selectAction: Optional[SelectAction] = Field(default=None)
225
+ items: List[CardElement] = Field(default_factory=list)
226
+ backgroundImage: Union[BackgroundImage, str] = Field(default=None)
227
+
228
+ def to_adaptive(self) -> Dict[str, Any]:
229
+ return {
230
+ "type": self.type,
231
+ "items": [item.to_adaptive() for item in self.items]
232
+ }
233
+
234
+
235
+ class TableRow(BaseModel):
236
+ """A row in a Table."""
237
+ type: str = Field(default='TableRow')
238
+ cells: List[TableCell] = Field(default_factory=list)
239
+
240
+ def add_cell(self, cell: TableCell):
241
+ self.cells.append(cell)
242
+
243
+ def new_cell(self, block: Union[CardElement, List[CardElement]]):
244
+ if isinstance(block, CardElement):
245
+ block = [block]
246
+ cell = TableCell(items=block)
247
+ self.cells.append(cell)
248
+
249
+ def to_adaptive(self) -> Dict[str, Any]:
250
+ return {
251
+ "type": self.type,
252
+ "cells": [cell.to_adaptive() for cell in self.cells]
253
+ }
254
+
255
+ ## Containers:
256
+ class FactSet(CardElement):
257
+ """A set of facts."""
258
+ type: str = Field(default='FactSet')
259
+ facts: List[FactElement] = Field(default_factory=list)
260
+
261
+ def to_adaptive(self) -> Dict[str, Any]:
262
+ return {
263
+ "type": self.type,
264
+ "facts": [fact.to_dict() for fact in self.facts]
265
+ }
266
+
267
+ class ColumnSet(CardElement):
268
+ """A set of columns."""
269
+ type: str = Field(default='ColumnSet')
270
+ columns: List[Column] = Field(default_factory=list)
271
+
272
+ def add_column(self, column: Union[Column, List[Column]]):
273
+ if isinstance(column, Column):
274
+ column = [column]
275
+ self.columns.extend(column)
276
+ # return the collection added of columns
277
+ return column
278
+
279
+ def create_column(self, content: CardElement):
280
+ """Create a new column with a single item."""
281
+ column = Column()
282
+ column.add_item(content)
283
+ self.columns.append(column)
284
+ return column
285
+
286
+ def to_adaptive(self) -> Dict[str, Any]:
287
+ return {
288
+ "type": self.type,
289
+ "columns": [column.to_adaptive() for column in self.columns]
290
+ }
291
+
292
+ class CardSection(CardElement):
293
+ type: str = Field(default='Container')
294
+ items: List[CardElement] = Field(default_factory=list)
295
+ facts: list[FactSet] = Field(default_factory=list)
296
+
297
+ def addFacts(self, facts: Union[FactSet, List[FactSet]]):
298
+ if isinstance(facts, FactSet):
299
+ facts = [facts]
300
+ self.facts.extend(facts)
301
+
302
+ def addItem(self, item: CardElement):
303
+ self.items.append(item)
304
+
305
+ def to_adaptive(self) -> Dict[str, Any]:
306
+ return {
307
+ "type": self.type,
308
+ "items": [item.to_adaptive() for item in self.items]
309
+ }
310
+
311
+ class ColumnDefinition(BaseModel):
312
+ """A column definition in a Table."""
313
+ width: str = Field(default='auto')
314
+
315
+ def to_adaptive(self) -> Dict[str, Any]:
316
+ return {
317
+ "width": self.width
318
+ }
319
+
320
+ class Table(CardElement):
321
+ """A table layout containing multiple rows."""
322
+ type: str = Field(default='Table')
323
+ columns: List[ColumnDefinition] = Field(default_factory=list)
324
+ rows: List[TableRow] = Field(default_factory=list)
325
+ firstRowAsHeader: bool = Field(default=True)
326
+ showGridLines: bool = Field(default=True)
327
+ gridStyle: Optional[ContainerStyle] = Field(default=ContainerStyle.default)
328
+
329
+ def add_row(self, row: TableRow):
330
+ self.rows.append(row)
331
+
332
+ def new_row(self, cells: Union[TableCell, List[TableCell]]):
333
+ if isinstance(cells, TableCell):
334
+ cells = [cells]
335
+ row = TableRow(cells=cells)
336
+ self.rows.append(row)
337
+ return row
338
+
339
+ def to_adaptive(self) -> Dict[str, Any]:
340
+ # Ensure columns are generated based on the number of cells in the first row
341
+ num_columns = max(len(row.cells) for row in self.rows) if self.rows else 0
342
+ self.columns = [ColumnDefinition() for _ in range(num_columns)]
343
+
344
+ return {
345
+ "type": self.type,
346
+ "gridStyle": self.gridStyle,
347
+ "firstRowAsHeader": self.firstRowAsHeader,
348
+ "showGridLines": self.showGridLines,
349
+ "columns": [column.to_adaptive() for column in self.columns],
350
+ "rows": [row.to_adaptive() for row in self.rows]
351
+ }
352
+
353
+ # Define a Enum for Image Sizes:
354
+ class ImageSize(str, Enum):
355
+ auto = 'auto'
356
+ stretch = 'stretch'
357
+ small = 'small'
358
+ medium = 'medium'
359
+ large = 'large'
360
+
361
+
362
+ class ImageSet(CardElement):
363
+ """A set of images displayed together."""
364
+ type: str = Field(default='ImageSet')
365
+ images: List['Image'] = Field(default_factory=list)
366
+ imageSize: Optional[ImageSize] = Field(default=ImageSize.auto)
367
+
368
+ def add_image(self, image: Union[Image, List[Image]]):
369
+ if isinstance(image, Image):
370
+ image = [image]
371
+ self.images.extend(image)
372
+
373
+ def new_image(self, images: Union[str, Image, tuple]):
374
+ if isinstance(images, str):
375
+ img = Image(
376
+ url=images,
377
+ altText=images
378
+ )
379
+ elif isinstance(images, tuple):
380
+ img = Image(
381
+ url=images[0],
382
+ altText=images[1]
383
+ )
384
+ else:
385
+ img = images
386
+ self.images.append(img)
387
+
388
+ def to_adaptive(self) -> Dict[str, Any]:
389
+ return {
390
+ "type": self.type,
391
+ "images": [image.to_adaptive() for image in self.images],
392
+ "imageSize": self.imageSize
393
+ }
394
+
395
+
396
+ class CardAction(BaseModel):
397
+ """Base class for Adaptive card actions."""
398
+ type: str
399
+ title: str
400
+ data: Optional[Dict[str, Any]] = Field(default=None)
401
+ card: Optional['AdaptiveCard'] = Field(default=None)
402
+
403
+ class Meta:
404
+ as_objects: True
405
+ remove_nulls = True
406
+
407
+ def __post_init__(self):
408
+ if not self.type:
409
+ self.type = f"Action.{self.__class__.__name__}"
410
+ return super().__post_init__()
411
+
412
+ def to_adaptive(self) -> Dict[str, Any]:
413
+ """Convert to AdaptiveCard JSON-representation."""
414
+ return self.to_dict()
415
+
416
+ ### Main Class: AdaptiveCard
417
+ class AdaptiveCard(BaseModel):
418
+ card_id: UUID = Field(required=False, default=auto_uuid, repr=False)
419
+ content_type: str = Field(
420
+ default="application/vnd.microsoft.card.adaptive",
421
+ repr=False
422
+ )
423
+ schema: str = "http://adaptivecards.io/schemas/adaptive-card.json"
424
+ card_type: str = "AdaptiveCard"
425
+ title: str
426
+ summary: str
427
+ minHeight: Optional[str] = None
428
+ body: List[CardElement] = Field(default_factory=list)
429
+ backgroundImage: Optional[BackgroundImage] = Field(default=None)
430
+ body_objects: List[Dict[str, Any]] = Field(default_factory=list, repr=False)
431
+ actions: List[CardAction] = Field(default_factory=list)
432
+ sections: List[CardSection] = Field(default_factory=list)
433
+ version: str = Field(default="1.5")
434
+
435
+ def __post_init__(self):
436
+ if self.version == "1.6": # Forcing Version to MS Teams
437
+ self.version = "1.5"
438
+ return super().__post_init__()
439
+
440
+ def add_text(self, text: str, **kwargs):
441
+ self.body.append(
442
+ TextBlock(type="TextBlock", text=text, **kwargs)
443
+ )
444
+
445
+ def add_body_element(self, element: CardElement):
446
+ self.body.append(element)
447
+ return element
448
+
449
+ def add_background(self, background: Union[str, BackgroundImage]):
450
+ """Adding a Background Image to the Card."""
451
+ if isinstance(background, str):
452
+ background = BackgroundImage(url=background)
453
+ self.backgroundImage = background
454
+ return background
455
+
456
+ def add_action(self, action: CardAction):
457
+ self.actions.append(action)
458
+
459
+ def add_section(self, **kwargs):
460
+ section = CardSection(**kwargs)
461
+ self.sections.append(section)
462
+ return section
463
+
464
+ def add_input(
465
+ self,
466
+ id: str,
467
+ label: str,
468
+ is_required: bool = False,
469
+ error_message: str = None,
470
+ input_type: str = 'Text',
471
+ style: str = None
472
+ ):
473
+ element = {
474
+ "type": f"Input.{input_type}",
475
+ "id": id,
476
+ "label": label,
477
+ "isRequired": is_required
478
+ }
479
+ if error_message is not None:
480
+ element["errorMessage"] = error_message
481
+ if style is not None:
482
+ element["style"] = style
483
+ if element:
484
+ self.body_objects.append(
485
+ element
486
+ )
487
+
488
+ def to_dict(self) -> dict:
489
+ data = super().to_dict(remove_nulls=True)
490
+ del data['card_id']
491
+ del data['body_objects']
492
+ del data['actions']
493
+ del data['content_type']
494
+ del data['version']
495
+ data['type'] = data.pop('card_type')
496
+ data['@type'] = "MessageCard"
497
+ data['@context'] = "http://schema.org/extensions"
498
+ return data
499
+
500
+ def to_adaptive(self) -> Dict[str, Any]:
501
+ """Convert to AdaptiveCard JSON-representation."""
502
+ # Build Body based on content:
503
+ body = []
504
+ properties = {}
505
+ if self.backgroundImage:
506
+ properties["backgroundImage"] = self.backgroundImage.to_dict()
507
+ if self.minHeight:
508
+ properties["minHeight"] = self.minHeight
509
+ if self.title:
510
+ body.append({
511
+ "type": "TextBlock",
512
+ "size": "Medium",
513
+ "weight": "Bolder",
514
+ "text": self.title,
515
+ "horizontalAlignment": "Center",
516
+ "wrap": True,
517
+ "style": "heading"
518
+ })
519
+ if self.summary:
520
+ body.append({
521
+ "type": "TextBlock",
522
+ "size": "large",
523
+ "weight": "bolder",
524
+ "text": self.summary
525
+ })
526
+ if self.body:
527
+ body.extend(element.to_adaptive() for element in self.body)
528
+ if self.sections:
529
+ body.extend(
530
+ {
531
+ "type": "Container",
532
+ "items": [section.to_adaptive() for section in self.sections]
533
+ }
534
+ )
535
+ if self.body_objects:
536
+ body.extend(iter(self.body_objects))
537
+ actions = {}
538
+ if self.actions:
539
+ actions = {
540
+ "actions": [action.to_dict() for action in self.actions]
541
+ }
542
+ # Iterate over each section, actions or body elements
543
+ return {
544
+ "$schema": self.schema,
545
+ "type": self.card_type,
546
+ "version": self.version,
547
+ "contentType": self.content_type,
548
+ "metadata": {
549
+ "webUrl": "https://contoso.com/tab"
550
+ },
551
+ **properties,
552
+ "body": body,
553
+ **actions
554
+ }
555
+
556
+
557
+ # Actions:
558
+ class Submit(CardAction):
559
+ type: str = Field(default='Action.Submit')
560
+ title: str = Field(default='Submit')
561
+
562
+ class OpenUrl(CardAction):
563
+ type: str = Field(default='Action.OpenUrl')
564
+ title: str
565
+ url: str
566
+ # role: str = Field(default='button')
567
+
568
+ class ShowCard(CardAction):
569
+ type: str = Field(default='Action.ShowCard')
570
+ title: str
571
+ card: AdaptiveCard
572
+
573
+ @property
574
+ def body(self):
575
+ return self.card.body
576
+
577
+ def to_dict(self) -> Dict[str, Any]:
578
+ data = super().to_dict()
579
+ card = self.card.to_adaptive()
580
+ with contextlib.suppress(KeyError):
581
+ del card['version']
582
+ del card['contentType']
583
+ del card['metadata']
584
+ card['@type'] = "MessageCard"
585
+ card['@context'] = "http://schema.org/extensions"
586
+ data['card'] = card
587
+ return data
588
+
589
+ class ToggleVisibility(CardAction):
590
+ type: str = Field(default='Action.ToggleVisibility')
591
+ targetElements: List[str] = Field(default_factory=list)
592
+
593
+ class ActionSet(CardElement):
594
+ type: str = Field(default='ActionSet')
595
+ actions: List[CardAction] = Field(default_factory=list)
596
+
597
+ def to_adaptive(self):
598
+ return super().to_adaptive()
@@ -0,0 +1,26 @@
1
+ # Aliases Functions:
2
+ import re
3
+
4
+ _RE_FIRST_CAP = re.compile(r"(.)([A-Z][a-z]+)")
5
+ _RE_ALL_CAPS = re.compile(r"([a-z0-9])([A-Z])")
6
+
7
+
8
+ def to_snakecase(name: str) -> str:
9
+ """
10
+ Convert a CamelCase or PascalCase string into snake_case.
11
+ Example: "EmailAddress" -> "email_address"
12
+ """
13
+ # Insert underscores before capital letters, then lower-case
14
+ s1 = _RE_FIRST_CAP.sub(r"\1_\2", name)
15
+ return _RE_ALL_CAPS.sub(r"\1_\2", s1).lower()
16
+
17
+
18
+ def to_pascalcase(s: str) -> str:
19
+ """
20
+ Convert a snake_case string into PascalCase.
21
+ Example:
22
+ store_id -> StoreId
23
+ email_address -> EmailAddress
24
+ """
25
+ parts = s.split("_")
26
+ return "".join(word.capitalize() for word in parts)