-
Notifications
You must be signed in to change notification settings - Fork 3
Expand file tree
/
Copy pathpython-type.ts
More file actions
101 lines (84 loc) · 2.97 KB
/
Copy pathpython-type.ts
File metadata and controls
101 lines (84 loc) · 2.97 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
// Maps blueprint parameter and property formats to Python types.
import type { Parameter, Property } from '@seamapi/blueprint'
type ScalarFormat = Exclude<(Parameter | Property)['format'], 'list'>
type ListItemFormat = Extract<
Parameter | Property,
{ format: 'list' }
>['itemFormat']
export const mapParameterToPythonType = (parameter: Parameter): string => {
if (parameter.format === 'list') {
return `List[${mapListItemFormatToPythonType(parameter.itemFormat)}]`
}
if (parameter.format === 'number') {
return parameter.isInt ? 'int' : 'float'
}
if (parameter.format === 'boolean') {
return mapBooleanToPythonType(parameter.values)
}
return mapScalarFormatToPythonType(parameter.format)
}
// from_dict reads every property with dict.get, so a property the API may omit
// or send as null arrives as None. Declaring those fields Optional keeps the
// dataclass honest about what a caller can actually find on it.
export const mapPropertyToPythonType = (
property: Property,
nestedClassName?: string,
isOptional = false,
): string => {
const type = mapRequiredPropertyToPythonType(property, nestedClassName)
return isOptional || property.isOptional || property.isNullable
? `Optional[${type}]`
: type
}
// The type a property has before optionality is taken into account. Callers
// that match on the shape of the type, rather than render it, want this one.
export const mapRequiredPropertyToPythonType = (
property: Property,
nestedClassName?: string,
): string => {
if (property.format === 'list') {
return `List[${
nestedClassName ?? mapListItemFormatToPythonType(property.itemFormat)
}]`
}
if (property.format === 'number') {
return property.isInt ? 'int' : 'float'
}
if (property.format === 'boolean') {
return mapBooleanToPythonType(property.values)
}
// Batch resource properties are lists of the named resource on the wire,
// though the blueprint types them as records.
if (property.format === 'record' && 'resourceType' in property) {
return 'List[Dict[str, Any]]'
}
if (property.format === 'object' && nestedClassName != null) {
return nestedClassName
}
return mapScalarFormatToPythonType(property.format)
}
const mapBooleanToPythonType = (values?: boolean[]): string =>
values == null || values.length === 0
? 'bool'
: `Literal[${values.map((value) => (value ? 'True' : 'False')).join(', ')}]`
const mapScalarFormatToPythonType = (format: ScalarFormat): string => {
switch (format) {
case 'string':
case 'datetime':
case 'id':
case 'enum':
return 'str'
// List items have no isInt flag, so numbers in lists stay floats.
case 'number':
return 'float'
case 'boolean':
return 'bool'
case 'record':
case 'object':
return 'Dict[str, Any]'
}
}
const mapListItemFormatToPythonType = (itemFormat: ListItemFormat): string =>
itemFormat === 'discriminated_object'
? 'Dict[str, Any]'
: mapScalarFormatToPythonType(itemFormat)