diff --git a/examples/tutorial/type_list.pdl b/examples/tutorial/type_list.pdl index 4c19c0eca..270d37af1 100644 --- a/examples/tutorial/type_list.pdl +++ b/examples/tutorial/type_list.pdl @@ -2,5 +2,3 @@ description: test spec: {"list": {"minItems": 0, "maxItems": 0, "str": {}}} data: ["hello", "world"] - - \ No newline at end of file diff --git a/pdl-live-react/src/pdl_ast.d.ts b/pdl-live-react/src/pdl_ast.d.ts index 1bca4fc79..bf4cfa320 100644 --- a/pdl-live-react/src/pdl_ast.d.ts +++ b/pdl-live-react/src/pdl_ast.d.ts @@ -40,6 +40,38 @@ export type Program = * */ export type Description = string | null +export type PdlTypeType = + | ("null" | "bool" | "str" | "float" | "int" | "list" | "obj") + | EnumPdlType + | StrPdlType + | FloatPdlType + | IntPdlType + | ListPdlType + | PdlTypeType[] + | OptionalPdlType + | ObjPdlType + | { + [k: string]: PdlTypeType + } +export type Enum = unknown[] +export type Minlength = number | null +export type Maxlength = number | null +export type Pattern = string | null +export type Multipleof = number | null +export type Minimum = number | null +export type Exclusiveminimum = number | null +export type Maximum = number | null +export type Exclusivemaximum = number | null +export type Minimum1 = number | null +export type Exclusiveminimum1 = number | null +export type Maximum1 = number | null +export type Exclusivemaximum1 = number | null +export type List = PdlTypeType | ListPdlTypeConstraints +export type Minitems = number | null +export type Maxitems = number | null +export type Obj = { + [k: string]: PdlTypeType +} | null /** * Documentation associated to the block. * @@ -168,9 +200,6 @@ export type Parser = | RegexParser | null export type Description21 = string | null -export type Spec21 = { - [k: string]: unknown -} | null export type Pdl = | boolean | number @@ -198,9 +227,6 @@ export type Pdl = | EmptyBlock | null export type Description22 = string | null -export type Spec22 = { - [k: string]: unknown -} | null export type Regex = string export type Mode = "search" | "match" | "fullmatch" | "split" | "findall" /** @@ -2597,7 +2623,7 @@ export type Kind20 = "function" * */ export type Function = { - [k: string]: unknown + [k: string]: PdlTypeType } | null /** * Body of the function @@ -2661,7 +2687,11 @@ export type PdlBlock = */ export interface FunctionBlock { description?: Description - spec?: Spec + /** + * Type specification of the result of the block. + * + */ + spec?: PdlTypeType | null defs?: Defs def?: Def24 contribute?: Contribute20 @@ -2679,12 +2709,82 @@ export interface FunctionBlock { return: Return } /** - * Type specification of the result of the block. - * + * Enumerated type. + */ +export interface EnumPdlType { + enum: Enum +} +/** + * String type. */ -export interface Spec { +export interface StrPdlType { + str: StrPdlTypeConstraints | null +} +/** + * Constraints on string type. + */ +export interface StrPdlTypeConstraints { + minLength?: Minlength + maxLength?: Maxlength + pattern?: Pattern +} +/** + * Float type. + */ +export interface FloatPdlType { + float: FloatPdlTypeConstraints | null +} +/** + * Constraints on float type. + */ +export interface FloatPdlTypeConstraints { + multipleOf?: Multipleof + minimum?: Minimum + exclusiveMinimum?: Exclusiveminimum + maximum?: Maximum + exclusiveMaximum?: Exclusivemaximum +} +/** + * Integer type. + */ +export interface IntPdlType { + int: IntPdlTypeConstraints | null +} +/** + * Constraints on integer type. + */ +export interface IntPdlTypeConstraints { + minimum?: Minimum1 + exclusiveMinimum?: Exclusiveminimum1 + maximum?: Maximum1 + exclusiveMaximum?: Exclusivemaximum1 +} +/** + * List type. + */ +export interface ListPdlType { + list: List +} +/** + * Constraints on list type. + */ +export interface ListPdlTypeConstraints { + minItems?: Minitems + maxItems?: Maxitems [k: string]: unknown } +/** + * Optional type. + */ +export interface OptionalPdlType { + optional: PdlTypeType +} +/** + * Optional type. + */ +export interface ObjPdlType { + obj: Obj +} /** * Set of definitions executed before the execution of the block. * @@ -2722,7 +2822,11 @@ export interface Defs { */ export interface CallBlock { description?: Description1 - spec?: Spec1 + /** + * Type specification of the result of the block. + * + */ + spec?: PdlTypeType | null defs?: Defs1 def?: Def23 contribute?: Contribute19 @@ -2740,13 +2844,6 @@ export interface CallBlock { args?: unknown pdl__trace?: PdlTrace3 } -/** - * Type specification of the result of the block. - * - */ -export interface Spec1 { - [k: string]: unknown -} /** * Set of definitions executed before the execution of the block. * @@ -2791,7 +2888,11 @@ export interface Defs1 { */ export interface LitellmModelBlock { description?: Description2 - spec?: Spec2 + /** + * Type specification of the result of the block. + * + */ + spec?: PdlTypeType | null defs?: Defs2 def?: Def22 contribute?: Contribute18 @@ -2817,13 +2918,6 @@ export interface LitellmModelBlock { platform?: Platform1 parameters?: Parameters1 } -/** - * Type specification of the result of the block. - * - */ -export interface Spec2 { - [k: string]: unknown -} /** * Set of definitions executed before the execution of the block. * @@ -2861,7 +2955,11 @@ export interface Defs2 { */ export interface GraniteioModelBlock { description?: Description3 - spec?: Spec3 + /** + * Type specification of the result of the block. + * + */ + spec?: PdlTypeType | null defs?: Defs3 def?: Def21 contribute?: Contribute17 @@ -2889,13 +2987,6 @@ export interface GraniteioModelBlock { processor?: Processor parameters?: Parameters } -/** - * Type specification of the result of the block. - * - */ -export interface Spec3 { - [k: string]: unknown -} /** * Set of definitions executed before the execution of the block. * @@ -2942,7 +3033,11 @@ export interface Defs3 { */ export interface CodeBlock { description?: Description4 - spec?: Spec4 + /** + * Type specification of the result of the block. + * + */ + spec?: PdlTypeType | null defs?: Defs4 def?: Def20 contribute?: Contribute16 @@ -2959,13 +3054,6 @@ export interface CodeBlock { lang: Lang1 code: Code } -/** - * Type specification of the result of the block. - * - */ -export interface Spec4 { - [k: string]: unknown -} /** * Set of definitions executed before the execution of the block. * @@ -3011,7 +3099,11 @@ export interface Defs4 { */ export interface ArgsBlock { description?: Description5 - spec?: Spec5 + /** + * Type specification of the result of the block. + * + */ + spec?: PdlTypeType | null defs?: Defs5 def?: Def19 contribute?: Contribute15 @@ -3028,13 +3120,6 @@ export interface ArgsBlock { lang?: Lang args: Args } -/** - * Type specification of the result of the block. - * - */ -export interface Spec5 { - [k: string]: unknown -} /** * Set of definitions executed before the execution of the block. * @@ -3074,7 +3159,11 @@ export interface Defs5 { */ export interface GetBlock { description?: Description6 - spec?: Spec6 + /** + * Type specification of the result of the block. + * + */ + spec?: PdlTypeType | null defs?: Defs6 def?: Def18 contribute?: Contribute14 @@ -3090,13 +3179,6 @@ export interface GetBlock { kind?: Kind14 get: Get } -/** - * Type specification of the result of the block. - * - */ -export interface Spec6 { - [k: string]: unknown -} /** * Set of definitions executed before the execution of the block. * @@ -3155,7 +3237,11 @@ export interface Defs6 { */ export interface DataBlock { description?: Description7 - spec?: Spec7 + /** + * Type specification of the result of the block. + * + */ + spec?: PdlTypeType | null defs?: Defs7 def?: Def17 contribute?: Contribute13 @@ -3172,13 +3258,6 @@ export interface DataBlock { data: unknown raw?: Raw } -/** - * Type specification of the result of the block. - * - */ -export interface Spec7 { - [k: string]: unknown -} /** * Set of definitions executed before the execution of the block. * @@ -3226,7 +3305,11 @@ export interface Defs7 { */ export interface IfBlock { description?: Description8 - spec?: Spec8 + /** + * Type specification of the result of the block. + * + */ + spec?: PdlTypeType | null defs?: Defs8 def?: Def16 contribute?: Contribute12 @@ -3246,13 +3329,6 @@ export interface IfBlock { else?: Else if_result?: IfResult } -/** - * Type specification of the result of the block. - * - */ -export interface Spec8 { - [k: string]: unknown -} /** * Set of definitions executed before the execution of the block. * @@ -3307,7 +3383,11 @@ export interface Defs8 { */ export interface MatchBlock { description?: Description9 - spec?: Spec9 + /** + * Type specification of the result of the block. + * + */ + spec?: PdlTypeType | null defs?: Defs9 def?: Def11 contribute?: Contribute11 @@ -3325,13 +3405,6 @@ export interface MatchBlock { match: unknown with: With1 } -/** - * Type specification of the result of the block. - * - */ -export interface Spec9 { - [k: string]: unknown -} /** * Set of definitions executed before the execution of the block. * @@ -3378,7 +3451,11 @@ export interface Defs9 { */ export interface RepeatBlock { description?: Description10 - spec?: Spec10 + /** + * Type specification of the result of the block. + * + */ + spec?: PdlTypeType | null defs?: Defs10 def?: Def10 contribute?: Contribute10 @@ -3401,13 +3478,6 @@ export interface RepeatBlock { join?: Join pdl__trace?: PdlTrace2 } -/** - * Type specification of the result of the block. - * - */ -export interface Spec10 { - [k: string]: unknown -} /** * Set of definitions executed before the execution of the block. * @@ -3445,7 +3515,11 @@ export interface Defs10 { */ export interface TextBlock { description?: Description11 - spec?: Spec11 + /** + * Type specification of the result of the block. + * + */ + spec?: PdlTypeType | null defs?: Defs11 def?: Def9 contribute?: Contribute9 @@ -3462,13 +3536,6 @@ export interface TextBlock { kind?: Kind9 text: Text } -/** - * Type specification of the result of the block. - * - */ -export interface Spec11 { - [k: string]: unknown -} /** * Set of definitions executed before the execution of the block. * @@ -3506,7 +3573,11 @@ export interface Defs11 { */ export interface LastOfBlock { description?: Description12 - spec?: Spec12 + /** + * Type specification of the result of the block. + * + */ + spec?: PdlTypeType | null defs?: Defs12 def?: Def8 contribute?: Contribute8 @@ -3523,13 +3594,6 @@ export interface LastOfBlock { kind?: Kind8 lastOf: Lastof } -/** - * Type specification of the result of the block. - * - */ -export interface Spec12 { - [k: string]: unknown -} /** * Set of definitions executed before the execution of the block. * @@ -3567,7 +3631,11 @@ export interface Defs12 { */ export interface ArrayBlock { description?: Description13 - spec?: Spec13 + /** + * Type specification of the result of the block. + * + */ + spec?: PdlTypeType | null defs?: Defs13 def?: Def7 contribute?: Contribute7 @@ -3584,13 +3652,6 @@ export interface ArrayBlock { kind?: Kind7 array: Array } -/** - * Type specification of the result of the block. - * - */ -export interface Spec13 { - [k: string]: unknown -} /** * Set of definitions executed before the execution of the block. * @@ -3628,7 +3689,11 @@ export interface Defs13 { */ export interface ObjectBlock { description?: Description14 - spec?: Spec14 + /** + * Type specification of the result of the block. + * + */ + spec?: PdlTypeType | null defs?: Defs14 def?: Def6 contribute?: Contribute6 @@ -3645,13 +3710,6 @@ export interface ObjectBlock { kind?: Kind6 object: Object } -/** - * Type specification of the result of the block. - * - */ -export interface Spec14 { - [k: string]: unknown -} /** * Set of definitions executed before the execution of the block. * @@ -3689,7 +3747,11 @@ export interface Defs14 { */ export interface MessageBlock { description?: Description15 - spec?: Spec15 + /** + * Type specification of the result of the block. + * + */ + spec?: PdlTypeType | null defs?: Defs15 def?: Def5 contribute?: Contribute5 @@ -3707,13 +3769,6 @@ export interface MessageBlock { name?: Name tool_call_id?: ToolCallId } -/** - * Type specification of the result of the block. - * - */ -export interface Spec15 { - [k: string]: unknown -} /** * Set of definitions executed before the execution of the block. * @@ -3763,7 +3818,11 @@ export interface Defs15 { */ export interface ReadBlock { description?: Description16 - spec?: Spec16 + /** + * Type specification of the result of the block. + * + */ + spec?: PdlTypeType | null defs?: Defs16 def?: Def4 contribute?: Contribute4 @@ -3781,13 +3840,6 @@ export interface ReadBlock { message?: Message multiline?: Multiline } -/** - * Type specification of the result of the block. - * - */ -export interface Spec16 { - [k: string]: unknown -} /** * Set of definitions executed before the execution of the block. * @@ -3825,7 +3877,11 @@ export interface Defs16 { */ export interface IncludeBlock { description?: Description17 - spec?: Spec17 + /** + * Type specification of the result of the block. + * + */ + spec?: PdlTypeType | null defs?: Defs17 def?: Def3 contribute?: Contribute3 @@ -3843,13 +3899,6 @@ export interface IncludeBlock { include: Include pdl__trace?: PdlTrace1 } -/** - * Type specification of the result of the block. - * - */ -export interface Spec17 { - [k: string]: unknown -} /** * Set of definitions executed before the execution of the block. * @@ -3887,7 +3936,11 @@ export interface Defs17 { */ export interface ImportBlock { description?: Description18 - spec?: Spec18 + /** + * Type specification of the result of the block. + * + */ + spec?: PdlTypeType | null defs?: Defs18 def?: Def2 contribute?: Contribute2 @@ -3904,13 +3957,6 @@ export interface ImportBlock { import: Import pdl__trace?: PdlTrace } -/** - * Type specification of the result of the block. - * - */ -export interface Spec18 { - [k: string]: unknown -} /** * Set of definitions executed before the execution of the block. * @@ -3948,7 +3994,11 @@ export interface Defs18 { */ export interface ErrorBlock { description?: Description19 - spec?: Spec19 + /** + * Type specification of the result of the block. + * + */ + spec?: PdlTypeType | null defs?: Defs19 def?: Def1 contribute?: Contribute1 @@ -3965,13 +4015,6 @@ export interface ErrorBlock { msg: Msg program: Program1 } -/** - * Type specification of the result of the block. - * - */ -export interface Spec19 { - [k: string]: unknown -} /** * Set of definitions executed before the execution of the block. * @@ -4009,7 +4052,11 @@ export interface Defs19 { */ export interface EmptyBlock { description?: Description20 - spec?: Spec20 + /** + * Type specification of the result of the block. + * + */ + spec?: PdlTypeType | null defs?: Defs20 def?: Def contribute?: Contribute @@ -4024,13 +4071,6 @@ export interface EmptyBlock { pdl__is_leaf?: PdlIsLeaf kind?: Kind } -/** - * Type specification of the result of the block. - * - */ -export interface Spec20 { - [k: string]: unknown -} /** * Set of definitions executed before the execution of the block. * @@ -4087,7 +4127,7 @@ export interface Table { } export interface PdlParser { description?: Description21 - spec?: Spec21 + spec?: PdlTypeType | null pdl: Pdl } /** @@ -4095,7 +4135,7 @@ export interface PdlParser { */ export interface RegexParser { description?: Description22 - spec?: Spec22 + spec?: PdlTypeType | null regex: Regex mode?: Mode } diff --git a/src/pdl/pdl-schema.json b/src/pdl/pdl-schema.json index b1ef1079f..b466cea9e 100644 --- a/src/pdl/pdl-schema.json +++ b/src/pdl/pdl-schema.json @@ -45,9 +45,16 @@ "title": "Description" }, "spec": { + "anyOf": [ + { + "$ref": "#/$defs/PdlTypeType" + }, + { + "type": "null" + } + ], "default": null, - "description": "Type specification of the result of the block.\n ", - "title": "Spec" + "description": "Type specification of the result of the block.\n " }, "defs": { "additionalProperties": { @@ -415,9 +422,16 @@ "title": "Description" }, "spec": { + "anyOf": [ + { + "$ref": "#/$defs/PdlTypeType" + }, + { + "type": "null" + } + ], "default": null, - "description": "Type specification of the result of the block.\n ", - "title": "Spec" + "description": "Type specification of the result of the block.\n " }, "defs": { "additionalProperties": { @@ -912,9 +926,16 @@ "title": "Description" }, "spec": { + "anyOf": [ + { + "$ref": "#/$defs/PdlTypeType" + }, + { + "type": "null" + } + ], "default": null, - "description": "Type specification of the result of the block.\n ", - "title": "Spec" + "description": "Type specification of the result of the block.\n " }, "defs": { "additionalProperties": { @@ -1372,9 +1393,16 @@ "title": "Description" }, "spec": { + "anyOf": [ + { + "$ref": "#/$defs/PdlTypeType" + }, + { + "type": "null" + } + ], "default": null, - "description": "Type specification of the result of the block.\n ", - "title": "Spec" + "description": "Type specification of the result of the block.\n " }, "defs": { "additionalProperties": { @@ -1850,9 +1878,16 @@ "title": "Description" }, "spec": { + "anyOf": [ + { + "$ref": "#/$defs/PdlTypeType" + }, + { + "type": "null" + } + ], "default": null, - "description": "Type specification of the result of the block.\n ", - "title": "Spec" + "description": "Type specification of the result of the block.\n " }, "defs": { "additionalProperties": { @@ -2218,9 +2253,16 @@ "title": "Description" }, "spec": { + "anyOf": [ + { + "$ref": "#/$defs/PdlTypeType" + }, + { + "type": "null" + } + ], "default": null, - "description": "Type specification of the result of the block.\n ", - "title": "Spec" + "description": "Type specification of the result of the block.\n " }, "defs": { "additionalProperties": { @@ -2546,6 +2588,22 @@ "title": "EmptyBlock", "type": "object" }, + "EnumPdlType": { + "additionalProperties": false, + "description": "Enumerated type.", + "properties": { + "enum": { + "items": {}, + "title": "Enum", + "type": "array" + } + }, + "required": [ + "enum" + ], + "title": "EnumPdlType", + "type": "object" + }, "ErrorBlock": { "additionalProperties": false, "description": "Block representing an error generated at runtime.", @@ -2564,9 +2622,16 @@ "title": "Description" }, "spec": { + "anyOf": [ + { + "$ref": "#/$defs/PdlTypeType" + }, + { + "type": "null" + } + ], "default": null, - "description": "Type specification of the result of the block.\n ", - "title": "Spec" + "description": "Type specification of the result of the block.\n " }, "defs": { "additionalProperties": { @@ -2985,6 +3050,95 @@ "title": "ErrorBlock", "type": "object" }, + "FloatPdlType": { + "additionalProperties": false, + "description": "Float type.", + "properties": { + "float": { + "anyOf": [ + { + "$ref": "#/$defs/FloatPdlTypeConstraints" + }, + { + "type": "null" + } + ] + } + }, + "required": [ + "float" + ], + "title": "FloatPdlType", + "type": "object" + }, + "FloatPdlTypeConstraints": { + "additionalProperties": false, + "description": "Constraints on float type.", + "properties": { + "multipleOf": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Multipleof" + }, + "minimum": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Minimum" + }, + "exclusiveMinimum": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Exclusiveminimum" + }, + "maximum": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Maximum" + }, + "exclusiveMaximum": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Exclusivemaximum" + } + }, + "title": "FloatPdlTypeConstraints", + "type": "object" + }, "FunctionBlock": { "additionalProperties": false, "description": "Function declaration.", @@ -3003,9 +3157,16 @@ "title": "Description" }, "spec": { + "anyOf": [ + { + "$ref": "#/$defs/PdlTypeType" + }, + { + "type": "null" + } + ], "default": null, - "description": "Type specification of the result of the block.\n ", - "title": "Spec" + "description": "Type specification of the result of the block.\n " }, "defs": { "additionalProperties": { @@ -3330,7 +3491,9 @@ "function": { "anyOf": [ { - "additionalProperties": true, + "additionalProperties": { + "$ref": "#/$defs/PdlTypeType" + }, "type": "object" }, { @@ -3450,9 +3613,16 @@ "title": "Description" }, "spec": { + "anyOf": [ + { + "$ref": "#/$defs/PdlTypeType" + }, + { + "type": "null" + } + ], "default": null, - "description": "Type specification of the result of the block.\n ", - "title": "Spec" + "description": "Type specification of the result of the block.\n " }, "defs": { "additionalProperties": { @@ -3804,9 +3974,16 @@ "title": "Description" }, "spec": { + "anyOf": [ + { + "$ref": "#/$defs/PdlTypeType" + }, + { + "type": "null" + } + ], "default": null, - "description": "Type specification of the result of the block.\n ", - "title": "Spec" + "description": "Type specification of the result of the block.\n " }, "defs": { "additionalProperties": { @@ -4352,9 +4529,16 @@ "title": "Description" }, "spec": { + "anyOf": [ + { + "$ref": "#/$defs/PdlTypeType" + }, + { + "type": "null" + } + ], "default": null, - "description": "Type specification of the result of the block.\n ", - "title": "Spec" + "description": "Type specification of the result of the block.\n " }, "defs": { "additionalProperties": { @@ -4902,9 +5086,16 @@ "title": "Description" }, "spec": { + "anyOf": [ + { + "$ref": "#/$defs/PdlTypeType" + }, + { + "type": "null" + } + ], "default": null, - "description": "Type specification of the result of the block.\n ", - "title": "Spec" + "description": "Type specification of the result of the block.\n " }, "defs": { "additionalProperties": { @@ -5340,9 +5531,16 @@ "title": "Description" }, "spec": { + "anyOf": [ + { + "$ref": "#/$defs/PdlTypeType" + }, + { + "type": "null" + } + ], "default": null, - "description": "Type specification of the result of the block.\n ", - "title": "Spec" + "description": "Type specification of the result of the block.\n " }, "defs": { "additionalProperties": { @@ -5772,6 +5970,83 @@ "title": "IndependentEnum", "type": "string" }, + "IntPdlType": { + "additionalProperties": false, + "description": "Integer type.", + "properties": { + "int": { + "anyOf": [ + { + "$ref": "#/$defs/IntPdlTypeConstraints" + }, + { + "type": "null" + } + ] + } + }, + "required": [ + "int" + ], + "title": "IntPdlType", + "type": "object" + }, + "IntPdlTypeConstraints": { + "additionalProperties": false, + "description": "Constraints on integer type.", + "properties": { + "minimum": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Minimum" + }, + "exclusiveMinimum": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Exclusiveminimum" + }, + "maximum": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Maximum" + }, + "exclusiveMaximum": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Exclusivemaximum" + } + }, + "title": "IntPdlTypeConstraints", + "type": "object" + }, "JoinArray": { "additionalProperties": false, "properties": { @@ -5858,9 +6133,16 @@ "title": "Description" }, "spec": { + "anyOf": [ + { + "$ref": "#/$defs/PdlTypeType" + }, + { + "type": "null" + } + ], "default": null, - "description": "Type specification of the result of the block.\n ", - "title": "Spec" + "description": "Type specification of the result of the block.\n " }, "defs": { "additionalProperties": { @@ -6280,6 +6562,60 @@ "title": "LastOfBlock", "type": "object" }, + "ListPdlType": { + "additionalProperties": false, + "description": "List type.", + "properties": { + "list": { + "anyOf": [ + { + "$ref": "#/$defs/PdlTypeType" + }, + { + "$ref": "#/$defs/ListPdlTypeConstraints" + } + ], + "title": "List" + } + }, + "required": [ + "list" + ], + "title": "ListPdlType", + "type": "object" + }, + "ListPdlTypeConstraints": { + "additionalProperties": true, + "description": "Constraints on list type.", + "properties": { + "minItems": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Minitems" + }, + "maxItems": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Maxitems" + } + }, + "title": "ListPdlTypeConstraints", + "type": "object" + }, "LitellmModelBlock": { "additionalProperties": false, "description": "Call an LLM through [the LiteLLM API](https://docs.litellm.ai/).\n\nExample:\n```PDL\n- model: ollama/granite-code:8b\n parameters:\n stop: ['!']\n```", @@ -6298,9 +6634,16 @@ "title": "Description" }, "spec": { + "anyOf": [ + { + "$ref": "#/$defs/PdlTypeType" + }, + { + "type": "null" + } + ], "default": null, - "description": "Type specification of the result of the block.\n ", - "title": "Spec" + "description": "Type specification of the result of the block.\n " }, "defs": { "additionalProperties": { @@ -7251,9 +7594,16 @@ "title": "Description" }, "spec": { + "anyOf": [ + { + "$ref": "#/$defs/PdlTypeType" + }, + { + "type": "null" + } + ], "default": null, - "description": "Type specification of the result of the block.\n ", - "title": "Spec" + "description": "Type specification of the result of the block.\n " }, "defs": { "additionalProperties": { @@ -7807,9 +8157,16 @@ "title": "Description" }, "spec": { + "anyOf": [ + { + "$ref": "#/$defs/PdlTypeType" + }, + { + "type": "null" + } + ], "default": null, - "description": "Type specification of the result of the block.\n ", - "title": "Spec" + "description": "Type specification of the result of the block.\n " }, "defs": { "additionalProperties": { @@ -8254,6 +8611,31 @@ "title": "MessageBlock", "type": "object" }, + "ObjPdlType": { + "additionalProperties": false, + "description": "Optional type.", + "properties": { + "obj": { + "anyOf": [ + { + "additionalProperties": { + "$ref": "#/$defs/PdlTypeType" + }, + "type": "object" + }, + { + "type": "null" + } + ], + "title": "Obj" + } + }, + "required": [ + "obj" + ], + "title": "ObjPdlType", + "type": "object" + }, "ObjectBlock": { "additionalProperties": false, "description": "Return the object where the value of each field is defined by a block. If the body of the object is an array, the resulting object is the union of the objects computed by each element of the array.", @@ -8272,9 +8654,16 @@ "title": "Description" }, "spec": { + "anyOf": [ + { + "$ref": "#/$defs/PdlTypeType" + }, + { + "type": "null" + } + ], "default": null, - "description": "Type specification of the result of the block.\n ", - "title": "Spec" + "description": "Type specification of the result of the block.\n " }, "defs": { "additionalProperties": { @@ -8839,6 +9228,20 @@ "title": "ObjectPattern", "type": "object" }, + "OptionalPdlType": { + "additionalProperties": false, + "description": "Optional type.", + "properties": { + "optional": { + "$ref": "#/$defs/PdlTypeType" + } + }, + "required": [ + "optional" + ], + "title": "OptionalPdlType", + "type": "object" + }, "OrPattern": { "additionalProperties": false, "properties": { @@ -9028,15 +9431,13 @@ "spec": { "anyOf": [ { - "additionalProperties": true, - "type": "object" + "$ref": "#/$defs/PdlTypeType" }, { "type": "null" } ], - "default": null, - "title": "Spec" + "default": null }, "pdl": { "anyOf": [ @@ -9184,6 +9585,55 @@ "title": "PdlTiming", "type": "object" }, + "PdlTypeType": { + "anyOf": [ + { + "enum": [ + "null", + "bool", + "str", + "float", + "int", + "list", + "obj" + ], + "type": "string" + }, + { + "$ref": "#/$defs/EnumPdlType" + }, + { + "$ref": "#/$defs/StrPdlType" + }, + { + "$ref": "#/$defs/FloatPdlType" + }, + { + "$ref": "#/$defs/IntPdlType" + }, + { + "$ref": "#/$defs/ListPdlType" + }, + { + "items": { + "$ref": "#/$defs/PdlTypeType" + }, + "type": "array" + }, + { + "$ref": "#/$defs/OptionalPdlType" + }, + { + "$ref": "#/$defs/ObjPdlType" + }, + { + "additionalProperties": { + "$ref": "#/$defs/PdlTypeType" + }, + "type": "object" + } + ] + }, "PdlUsage": { "description": "Internal data structure to record token consumption usage information.", "properties": { @@ -9317,9 +9767,16 @@ "title": "Description" }, "spec": { + "anyOf": [ + { + "$ref": "#/$defs/PdlTypeType" + }, + { + "type": "null" + } + ], "default": null, - "description": "Type specification of the result of the block.\n ", - "title": "Spec" + "description": "Type specification of the result of the block.\n " }, "defs": { "additionalProperties": { @@ -9701,15 +10158,13 @@ "spec": { "anyOf": [ { - "additionalProperties": true, - "type": "object" + "$ref": "#/$defs/PdlTypeType" }, { "type": "null" } ], - "default": null, - "title": "Spec" + "default": null }, "regex": { "title": "Regex", @@ -9752,9 +10207,16 @@ "title": "Description" }, "spec": { + "anyOf": [ + { + "$ref": "#/$defs/PdlTypeType" + }, + { + "type": "null" + } + ], "default": null, - "description": "Type specification of the result of the block.\n ", - "title": "Spec" + "description": "Type specification of the result of the block.\n " }, "defs": { "additionalProperties": { @@ -10365,6 +10827,71 @@ "title": "RepeatBlock", "type": "object" }, + "StrPdlType": { + "additionalProperties": false, + "description": "String type.", + "properties": { + "str": { + "anyOf": [ + { + "$ref": "#/$defs/StrPdlTypeConstraints" + }, + { + "type": "null" + } + ] + } + }, + "required": [ + "str" + ], + "title": "StrPdlType", + "type": "object" + }, + "StrPdlTypeConstraints": { + "additionalProperties": false, + "description": "Constraints on string type.", + "properties": { + "minLength": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Minlength" + }, + "maxLength": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Maxlength" + }, + "pattern": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Pattern" + } + }, + "title": "StrPdlTypeConstraints", + "type": "object" + }, "TextBlock": { "additionalProperties": false, "description": "Create the concatenation of the stringify version of the result of each block of the list of blocks.", @@ -10383,9 +10910,16 @@ "title": "Description" }, "spec": { + "anyOf": [ + { + "$ref": "#/$defs/PdlTypeType" + }, + { + "type": "null" + } + ], "default": null, - "description": "Type specification of the result of the block.\n ", - "title": "Spec" + "description": "Type specification of the result of the block.\n " }, "defs": { "additionalProperties": { diff --git a/src/pdl/pdl_ast.py b/src/pdl/pdl_ast.py index 4afbb7db1..de8c0d34c 100644 --- a/src/pdl/pdl_ast.py +++ b/src/pdl/pdl_ast.py @@ -14,11 +14,18 @@ Union, ) -from pydantic import BaseModel, BeforeValidator, ConfigDict, Field, RootModel +from pydantic import ( + BaseModel, + BeforeValidator, + ConfigDict, + Field, + RootModel, + TypeAdapter, +) from pydantic.json_schema import SkipJsonSchema +from typing_extensions import TypeAliasType from .pdl_lazy import PdlDict, PdlLazy -from .pdl_schema_utils import pdltype_to_jsonschema def _ensure_lower(value): @@ -134,6 +141,119 @@ class AnyPattern(Pattern): ) +BasePdlType: TypeAlias = Literal["null", "bool", "str", "float", "int", "list", "obj"] + + +class PdlType(BaseModel): + """Common fields for PDL types.""" + + model_config = ConfigDict(extra="forbid") + + +class EnumPdlType(PdlType): + """Enumerated type.""" + + enum: list[Any] + """List of allowed values in the type.""" + + +class StrPdlTypeConstraints(BaseModel): + """Constraints on string type.""" + + model_config = ConfigDict(extra="forbid") + minLength: Optional[int] = None + """Minimal length of the string.""" + maxLength: Optional[int] = None + """Maximal length of the string.""" + pattern: Optional[str] = None + """Regular expression that values of the type must match.""" + + +class StrPdlType(PdlType): + """String type.""" + + str: Optional[StrPdlTypeConstraints] + + +class FloatPdlTypeConstraints(BaseModel): + """Constraints on float type.""" + + model_config = ConfigDict(extra="forbid") + multipleOf: Optional[float] = None + minimum: Optional[float] = None + exclusiveMinimum: Optional[float] = None + maximum: Optional[float] = None + exclusiveMaximum: Optional[float] = None + + +class FloatPdlType(PdlType): + """Float type.""" + + float: Optional[FloatPdlTypeConstraints] + + +class IntPdlTypeConstraints(BaseModel): + """Constraints on integer type.""" + + model_config = ConfigDict(extra="forbid") + minimum: Optional[float] = None + exclusiveMinimum: Optional[float] = None + maximum: Optional[float] = None + exclusiveMaximum: Optional[float] = None + + +class IntPdlType(PdlType): + """Integer type.""" + + int: Optional[IntPdlTypeConstraints] + + +class ListPdlTypeConstraints(BaseModel): + """Constraints on list type.""" + + model_config = ConfigDict(extra="allow") + minItems: Optional[int] = None + maxItems: Optional[int] = None + + +class ListPdlType(PdlType): + """List type.""" + + list: Union["PdlTypeType", ListPdlTypeConstraints] + + +class OptionalPdlType(PdlType): + """Optional type.""" + + optional: "PdlTypeType" + + +class ObjPdlType(PdlType): + """Optional type.""" + + obj: Optional[dict[str, "PdlTypeType"]] + + +PdlTypeType = TypeAliasType( + "PdlTypeType", + Annotated[ + "Union[BasePdlType," # pyright: ignore + " EnumPdlType," + " StrPdlType," + " FloatPdlType," + " IntPdlType," + " ListPdlType," + " list['PdlTypeType']," + " OptionalPdlType," + " ObjPdlType," + " dict[str, 'PdlTypeType']]", + Field(union_mode="left_to_right"), + ], +) + +pdl_type_adapter = TypeAdapter(PdlTypeType) + + class Parser(BaseModel): """Common fields for all parsers (`parser` field).""" @@ -141,7 +261,7 @@ class Parser(BaseModel): description: Optional[str] = None """Documentation associated to the parser. """ - spec: Optional[dict[str, Any]] = None + spec: Optional[PdlTypeType] = None """Expected type of the parsed value. """ @@ -220,7 +340,7 @@ class Block(BaseModel): description: Optional[str] = None """Documentation associated to the block. """ - spec: Any = None + spec: Optional[PdlTypeType] = None """Type specification of the result of the block. """ defs: dict[str, "BlockType"] = {} @@ -278,7 +398,7 @@ class FunctionBlock(LeafBlock): """Function declaration.""" kind: Literal[BlockKind.FUNCTION] = BlockKind.FUNCTION - function: Optional[dict[str, Any]] + function: Optional[dict[str, PdlTypeType]] """Functions parameters with their types. """ returns: "BlockType" = Field(..., alias="return") @@ -925,33 +1045,6 @@ def __init__( DECODING_METHOD = "greedy" -def set_structured_decoding_parameters( - spec: Any, - parameters: Optional[dict[str, Any]], -) -> dict[str, Any]: - if parameters is None: - parameters = {} - - if ( - spec is not None - and "response_format" not in parameters - and "guided_decoding_backend" not in parameters - ): - schema = pdltype_to_jsonschema(spec, True) - - parameters["guided_decoding_backend"] = "lm-format-enforcer" - parameters["guided_json"] = schema - parameters["response_format"] = { - "type": "json_schema", - "json_schema": { - "name": "schema", - "schema": schema, - "strict": True, - }, - } - return parameters - - def get_default_model_parameters() -> list[dict[str, Any]]: """Model-specific defaults to apply""" return [ diff --git a/src/pdl/pdl_dumper.py b/src/pdl/pdl_dumper.py index 95f96d0a6..f30100780 100644 --- a/src/pdl/pdl_dumper.py +++ b/src/pdl/pdl_dumper.py @@ -17,17 +17,22 @@ ContributeValue, DataBlock, EmptyBlock, + EnumPdlType, ErrorBlock, ExpressionType, + FloatPdlType, FunctionBlock, GetBlock, GraniteioModelBlock, IfBlock, ImportBlock, IncludeBlock, + IntPdlType, JoinText, JoinType, LastOfBlock, + ListPdlType, + ListPdlTypeConstraints, LitellmModelBlock, LitellmParameters, LocalizedExpression, @@ -35,16 +40,20 @@ MessageBlock, ObjectBlock, ObjectPattern, + ObjPdlType, + OptionalPdlType, OrPattern, ParserType, PatternType, PdlLocationType, PdlParser, PdlTiming, + PdlTypeType, PdlUsage, ReadBlock, RegexParser, RepeatBlock, + StrPdlType, StructuredBlock, TextBlock, ) @@ -107,7 +116,7 @@ def block_to_dict( # noqa: C901 if block.role is not None: d["role"] = block.role if block.spec is not None: - d["spec"] = block.spec + d["spec"] = type_to_dict(block.spec) if block.defs is not None: d["defs"] = { x: block_to_dict(b, json_compatible) for x, b in block.defs.items() @@ -227,7 +236,10 @@ def block_to_dict( # noqa: C901 block_to_dict(b, json_compatible) for b in block.pdl__trace ] case FunctionBlock(): - d["function"] = block.function + if block.function is None: + d["function"] = None + else: + d["function"] = {x: type_to_dict(t) for x, t in block.function.items()} d["return"] = block_to_dict(block.returns, json_compatible) # if block.scope is not None: # d["scope"] = scope_to_dict(block.scope, json_compatible) @@ -245,7 +257,10 @@ def block_to_dict( # noqa: C901 d["msg"] = block.msg if block.def_ is not None: d["def"] = block.def_ - if set(block.contribute) != {ContributeTarget.RESULT, ContributeTarget.CONTEXT}: + if block.contribute not in [ + [ContributeTarget.RESULT, ContributeTarget.CONTEXT], + [ContributeTarget.CONTEXT, ContributeTarget.RESULT], + ]: d["contribute"] = contribute_to_list(block.contribute) if block.pdl__result is not None: if isinstance(block.pdl__result, FunctionBlock): @@ -291,6 +306,86 @@ def expr_to_dict(expr: ExpressionType, json_compatible: bool): return d +def type_to_dict(t: PdlTypeType): + d: str | list | dict + match t: + case "null" | "bool" | "str" | "float" | "int" | "list" | "obj": + d = t + case EnumPdlType(): + d = {"enum": t.enum} + case StrPdlType(): + if t.str is None: + d = "str" + else: + cstr: dict = {} + if t.str.minLength is not None: + cstr["minLength"] = t.str.minLength + if t.str.maxLength is not None: + cstr["maxLength"] = t.str.maxLength + if t.str.pattern is not None: + cstr["pattern"] = t.str.pattern + d = {"str": cstr} + case FloatPdlType(): + if t.float is None: + d = "float" + else: + cstr = {} + if t.float.multipleOf is not None: + cstr["multipleOf"] = t.float.multipleOf + if t.float.minimum is not None: + cstr["minimum"] = t.float.minimum + if t.float.exclusiveMinimum is not None: + cstr["exclusiveMinimum"] = t.float.exclusiveMinimum + if t.float.maximum is not None: + cstr["maximum"] = t.float.maximum + if t.float.exclusiveMaximum is not None: + cstr["exclusiveMaximum"] = t.float.exclusiveMaximum + d = {"float": cstr} + case IntPdlType(): + if t.int is None: + d = "int" + else: + cstr = {} + if t.int.minimum is not None: + cstr["minimum"] = t.int.minimum + if t.int.exclusiveMinimum is not None: + cstr["exclusiveMinimum"] = t.int.exclusiveMinimum + if t.int.maximum is not None: + cstr["maximum"] = t.int.maximum + if t.int.exclusiveMaximum is not None: + cstr["exclusiveMaximum"] = t.int.exclusiveMaximum + d = {"int": cstr} + case ListPdlType(): + if t.list is None: + d = "list" + else: + if isinstance(t.list, ListPdlTypeConstraints): + cstr = type_to_dict(t.list.__pydantic_extra__) + if t.list.minItems is not None: + cstr["minItems"] = t.list.minItems + if t.list.maxItems is not None: + cstr["maxItems"] = t.list.maxItems + d = {"list": cstr} + else: + d = {"list": type_to_dict(t.list)} + case [elem]: + d = [type_to_dict(elem)] # type:ignore + case list(): + assert False, "list must have only one element" + case OptionalPdlType(): + d = {"optional": type_to_dict(t.optional)} + case ObjPdlType(): + if t.obj is None: + d = "obj" + else: + d = {"obj": {x: type_to_dict(t_x) for x, t_x in t.obj.items()}} + case dict(): + d = {x: type_to_dict(t_x) for x, t_x in t.items()} + case _: + assert False + return d + + def timing_to_dict(timing: PdlTiming) -> dict: d: dict = {} if timing.start_nanos != 0: @@ -369,11 +464,13 @@ def parser_to_dict(parser: ParserType) -> str | dict[str, Any]: case "json" | "yaml" | "jsonl": p = parser case RegexParser(): - p = parser.model_dump() + p = parser.model_dump(exclude_unset=True) case PdlParser(): p = {} - p["description"] = parser.description - p["spec"] = parser.spec + if parser.description is not None: + p["description"] = parser.description + if parser.spec is not None: + p["spec"] = type_to_dict(parser.spec) p["pdl"] = block_to_dict(parser.pdl, False) case _: assert False diff --git a/src/pdl/pdl_interpreter.py b/src/pdl/pdl_interpreter.py index 14c3f9f53..f2eb67b53 100644 --- a/src/pdl/pdl_interpreter.py +++ b/src/pdl/pdl_interpreter.py @@ -70,6 +70,7 @@ ModelInput, ObjectBlock, ObjectPattern, + ObjPdlType, OrPattern, ParserType, Pattern, @@ -1923,19 +1924,20 @@ def parse_result(parser: ParserType, text: str) -> JSONReturnType: raise PDLRuntimeParserError(msg) from exc if m is None: return None - if parser.spec is None: - result = list(m.groups()) - else: - current_group_name = "" - try: - result = {} - for x in parser.spec.keys(): - current_group_name = x - result[x] = m.group(x) - return result - except IndexError as exc: - msg = f"No group named {current_group_name} found by {regex} in {text}" - raise PDLRuntimeParserError(msg) from exc + match parser.spec: + case ObjPdlType(obj=dict() as spec) | (dict() as spec): + current_group_name = "" + try: + result = {} + for x in spec.keys(): + current_group_name = x + result[x] = m.group(x) + return result + except IndexError as exc: + msg = f"No group named {current_group_name} found by {regex} in {text}" + raise PDLRuntimeParserError(msg) from exc + case _: + result = list(m.groups()) case RegexParser(mode="split" | "findall"): regex = parser.regex match parser.mode: diff --git a/src/pdl/pdl_llms.py b/src/pdl/pdl_llms.py index 34c0a62a6..5c0db1a0c 100644 --- a/src/pdl/pdl_llms.py +++ b/src/pdl/pdl_llms.py @@ -4,7 +4,7 @@ from concurrent.futures import Future from os import environ from sys import stderr -from typing import Any, Callable, Generator, TypeVar +from typing import Any, Callable, Generator, Optional, TypeVar import httpx from dotenv import load_dotenv @@ -15,9 +15,10 @@ LitellmModelBlock, ModelInput, PDLRuntimeError, - set_structured_decoding_parameters, + PdlTypeType, ) from .pdl_lazy import PdlConst, PdlLazy, lazy_apply +from .pdl_schema_utils import pdltype_to_jsonschema from .pdl_utils import remove_none_values_from_message # Load environment variables @@ -181,6 +182,33 @@ def generate_text_stream( return result +def set_structured_decoding_parameters( + spec: Optional[PdlTypeType], + parameters: Optional[dict[str, Any]], +) -> dict[str, Any]: + if parameters is None: + parameters = {} + + if ( + spec is not None + and "response_format" not in parameters + and "guided_decoding_backend" not in parameters + ): + schema = pdltype_to_jsonschema(spec, True) + + parameters["guided_decoding_backend"] = "lm-format-enforcer" + parameters["guided_json"] = schema + parameters["response_format"] = { + "type": "json_schema", + "json_schema": { + "name": "schema", + "schema": schema, + "strict": True, + }, + } + return parameters + + MapInputT = TypeVar("MapInputT") MapOutputT = TypeVar("MapOutputT") diff --git a/src/pdl/pdl_schema_utils.py b/src/pdl/pdl_schema_utils.py index 9920b0c46..402c38a76 100644 --- a/src/pdl/pdl_schema_utils.py +++ b/src/pdl/pdl_schema_utils.py @@ -1,6 +1,19 @@ import warnings from typing import Any, Optional +from .pdl_ast import ( + EnumPdlType, + FloatPdlType, + IntPdlType, + ListPdlType, + ListPdlTypeConstraints, + ObjPdlType, + OptionalPdlType, + PdlTypeType, + StrPdlType, + pdl_type_adapter, +) + json_types_convert = { "string": str, "boolean": bool, @@ -29,59 +42,96 @@ def convert_to_json_type(a_type): } -def pdltype_to_jsonschema( # pylint: disable=too-many-return-statements - pdl_type: str | dict[str, Any] | list, additional_properties: bool +def pdltype_to_jsonschema( + pdl_type: Optional[PdlTypeType], additional_properties: bool ) -> dict[str, Any]: + schema: dict[str, Any] match pdl_type: - case {"enum": choices}: - return {"enum": choices} case None: - return {"type": "null"} - case "bool" | "str" | "float" | "int" | "list" | "obj": - return {"type": _PDLTYPE_TO_JSONSCHEMA_NAME[pdl_type]} - case {"str": dict() as details}: - return {"type": "string", **details} - case {"float": dict() as details}: - return {"type": "number", **details} - case {"int": dict() as details}: - return {"type": "integer", **details} - case {"list": str() as type_name}: - return { + schema = {} # Any type + case "null" | "bool" | "str" | "float" | "int" | "list" | "obj": + schema = {"type": _PDLTYPE_TO_JSONSCHEMA_NAME[pdl_type]} + case EnumPdlType(enum=choices): + schema = {"enum": choices} + case StrPdlType(str=None): + schema = {"type": "string"} + case StrPdlType(str=constraints): + if constraints is None: + details = {} + else: + details = constraints.model_dump(exclude_defaults=True) + schema = {"type": "string", **details} + case FloatPdlType(float=constraints): + if constraints is None: + details = {} + else: + details = constraints.model_dump(exclude_defaults=True) + schema = {"type": "number", **details} + case IntPdlType(int=constraints): + if constraints is None: + details = {} + else: + details = constraints.model_dump(exclude_defaults=True) + schema = {"type": "integer", **details} + case ListPdlType(list=ListPdlTypeConstraints() as cstr): + items_type = pdl_type_adapter.validate_python(cstr.__pydantic_extra__) + details = {} + if cstr.minItems is not None: + details["minItems"] = cstr.minItems + if cstr.maxItems is not None: + details["maxItems"] = cstr.maxItems + schema = { "type": "array", - "items": pdltype_to_jsonschema(type_name, additional_properties), + "items": pdltype_to_jsonschema(items_type, additional_properties), + **details, } - case {"list": dict() as details}: - ikws = ["enum", *_PDLTYPE_TO_JSONSCHEMA_NAME.keys()] - items_details = {k: v for k, v in details.items() if k in ikws} - if len(items_details) != 1: - raise ValueError(f"invalid PDL type {pdl_type}") - other_details = {k: v for k, v in details.items() if k not in ikws} - return { + case ListPdlType(list=items_type): + schema = { "type": "array", - "items": pdltype_to_jsonschema(items_details, additional_properties), - **other_details, + "items": pdltype_to_jsonschema(items_type, additional_properties), } + # case {"list": dict() as details}: + # ikws = ["enum", *_PDLTYPE_TO_JSONSCHEMA_NAME.keys()] + # items_details = {k: v for k, v in details.items() if k in ikws} + # if len(items_details) != 1: + # raise ValueError(f"invalid PDL type {pdl_type}") + # other_details = {k: v for k, v in details.items() if k not in ikws} + # return { + # "type": "array", + # "items": pdltype_to_jsonschema(items_details, additional_properties), + # **other_details, + # } case list() as type_list: if len(type_list) != 1: raise ValueError(f"invalid PDL type {pdl_type}") - return { + schema = { "type": "array", "items": pdltype_to_jsonschema(type_list[0], additional_properties), } - case {"obj": dict() as pdl_props}: - return get_json_schema_object(pdl_props, additional_properties) + case OptionalPdlType(optional=t): + t_schema = pdltype_to_jsonschema(t, additional_properties) + schema = {"anyOf": [t_schema, "null"]} + case ObjPdlType(obj=pdl_props): + if pdl_props is None: + schema = {"type": "object"} + else: + schema = get_json_schema_object(pdl_props, additional_properties) case dict() as pdl_props: return get_json_schema_object(pdl_props, additional_properties) - raise ValueError(f"invalid PDL type {pdl_type}") + case _: + raise ValueError(f"invalid PDL type {pdl_type}") + return schema -def get_json_schema_object(pdl_props: dict, additional_properties) -> dict[str, Any]: +def get_json_schema_object( + pdl_props: dict[str, PdlTypeType], additional_properties +) -> dict[str, Any]: props = {} required = [] for name, prop_type in pdl_props.items(): - if isinstance(prop_type, dict) and "optional" in prop_type: + if isinstance(prop_type, OptionalPdlType): props[name] = pdltype_to_jsonschema( - prop_type["optional"], additional_properties + prop_type.optional, additional_properties ) else: props[name] = pdltype_to_jsonschema(prop_type, additional_properties) @@ -98,10 +148,12 @@ def get_json_schema_object(pdl_props: dict, additional_properties) -> dict[str, def get_json_schema( - params: dict[str, Any], additional_properties + params: dict[str, PdlTypeType], additional_properties ) -> Optional[dict[str, Any]]: try: - result = pdltype_to_jsonschema({"obj": params}, additional_properties) + result = pdltype_to_jsonschema( + ObjPdlType.model_validate({"obj": params}), additional_properties + ) return result except ValueError as e: warnings.warn(e.args[0]) diff --git a/src/pdl/pdl_schema_validator.py b/src/pdl/pdl_schema_validator.py index b29f14161..160a1e8c4 100644 --- a/src/pdl/pdl_schema_validator.py +++ b/src/pdl/pdl_schema_validator.py @@ -1,7 +1,7 @@ # pylint: disable=import-outside-toplevel from typing import Any, Optional -from .pdl_ast import FunctionBlock +from .pdl_ast import FunctionBlock, PdlTypeType from .pdl_location_utils import get_loc_string from .pdl_schema_error_analyzer import analyze_errors from .pdl_schema_utils import get_json_schema, pdltype_to_jsonschema @@ -35,7 +35,7 @@ def type_check_args( return type_check(args_copy, schema, loc) -def type_check_spec(result: Any, spec: str | dict[str, Any] | list, loc) -> list[str]: +def type_check_spec(result: Any, spec: Optional[PdlTypeType], loc) -> list[str]: schema = pdltype_to_jsonschema(spec, False) if schema is None: return ["Error obtaining a valid schema from spec"] diff --git a/tests/test_type_checking.py b/tests/test_type_checking.py index e25c5e809..b82e5823d 100644 --- a/tests/test_type_checking.py +++ b/tests/test_type_checking.py @@ -2,12 +2,18 @@ import yaml from pdl.pdl import exec_dict +from pdl.pdl_ast import pdl_type_adapter from pdl.pdl_interpreter import PDLRuntimeError +from pdl.pdl_parser import PDLParseError from pdl.pdl_schema_utils import pdltype_to_jsonschema _PDLTYPE_TO_JSONSCHEMA_TESTS = [ { "pdl_type": "null", + "json_schema": {}, + }, + { + "pdl_type": '"null"', "json_schema": {"type": "null"}, }, { @@ -139,7 +145,11 @@ def test_pdltype_to_jsonschema(): for t in _PDLTYPE_TO_JSONSCHEMA_TESTS: - pdl_type = yaml.safe_load(t["pdl_type"]) + t_data = yaml.safe_load(t["pdl_type"]) + if t_data is None: + pdl_type = None + else: + pdl_type = pdl_type_adapter.validate_python(t_data) json_schema = pdltype_to_jsonschema(pdl_type, False) assert json_schema == t["json_schema"] @@ -314,7 +324,7 @@ def test_function_call7(): def test_function_call8(): - with pytest.raises(PDLRuntimeError): + with pytest.raises(PDLParseError): exec_dict(function_call8)