qtype 0.0.10__py3-none-any.whl → 0.0.12__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.
Files changed (61) hide show
  1. qtype/application/__init__.py +12 -0
  2. qtype/application/commons/__init__.py +7 -0
  3. qtype/{converters → application/converters}/tools_from_module.py +2 -2
  4. qtype/application/converters/types.py +33 -0
  5. qtype/{dsl/document.py → application/documentation.py} +2 -0
  6. qtype/application/facade.py +160 -0
  7. qtype/base/__init__.py +14 -0
  8. qtype/base/exceptions.py +49 -0
  9. qtype/base/logging.py +39 -0
  10. qtype/base/types.py +29 -0
  11. qtype/commands/convert.py +64 -49
  12. qtype/commands/generate.py +59 -4
  13. qtype/commands/run.py +109 -72
  14. qtype/commands/serve.py +42 -28
  15. qtype/commands/validate.py +25 -42
  16. qtype/commands/visualize.py +51 -37
  17. qtype/dsl/__init__.py +9 -0
  18. qtype/dsl/base_types.py +8 -0
  19. qtype/dsl/custom_types.py +6 -4
  20. qtype/dsl/model.py +185 -50
  21. qtype/dsl/validator.py +9 -4
  22. qtype/interpreter/api.py +96 -40
  23. qtype/interpreter/auth/__init__.py +3 -0
  24. qtype/interpreter/auth/aws.py +234 -0
  25. qtype/interpreter/auth/cache.py +67 -0
  26. qtype/interpreter/auth/generic.py +103 -0
  27. qtype/interpreter/batch/flow.py +95 -0
  28. qtype/interpreter/batch/sql_source.py +95 -0
  29. qtype/interpreter/batch/step.py +63 -0
  30. qtype/interpreter/batch/types.py +41 -0
  31. qtype/interpreter/batch/utils.py +179 -0
  32. qtype/interpreter/conversions.py +21 -10
  33. qtype/interpreter/resource_cache.py +4 -2
  34. qtype/interpreter/steps/decoder.py +13 -9
  35. qtype/interpreter/steps/llm_inference.py +7 -9
  36. qtype/interpreter/steps/prompt_template.py +1 -1
  37. qtype/interpreter/streaming_helpers.py +3 -3
  38. qtype/interpreter/typing.py +47 -11
  39. qtype/interpreter/ui/404/index.html +1 -1
  40. qtype/interpreter/ui/404.html +1 -1
  41. qtype/interpreter/ui/index.html +1 -1
  42. qtype/interpreter/ui/index.txt +1 -1
  43. qtype/loader.py +15 -16
  44. qtype/semantic/generate.py +91 -39
  45. qtype/semantic/model.py +183 -52
  46. qtype/semantic/resolver.py +4 -4
  47. {qtype-0.0.10.dist-info → qtype-0.0.12.dist-info}/METADATA +5 -1
  48. {qtype-0.0.10.dist-info → qtype-0.0.12.dist-info}/RECORD +58 -44
  49. qtype/commons/generate.py +0 -93
  50. qtype/converters/types.py +0 -66
  51. qtype/semantic/errors.py +0 -4
  52. /qtype/{commons → application/commons}/tools.py +0 -0
  53. /qtype/{commons → application/converters}/__init__.py +0 -0
  54. /qtype/{converters → application/converters}/tools_from_api.py +0 -0
  55. /qtype/{converters → interpreter/batch}/__init__.py +0 -0
  56. /qtype/interpreter/ui/_next/static/{Jb2murBlt2XkN6punrQbE → OT8QJQW3J70VbDWWfrEMT}/_buildManifest.js +0 -0
  57. /qtype/interpreter/ui/_next/static/{Jb2murBlt2XkN6punrQbE → OT8QJQW3J70VbDWWfrEMT}/_ssgManifest.js +0 -0
  58. {qtype-0.0.10.dist-info → qtype-0.0.12.dist-info}/WHEEL +0 -0
  59. {qtype-0.0.10.dist-info → qtype-0.0.12.dist-info}/entry_points.txt +0 -0
  60. {qtype-0.0.10.dist-info → qtype-0.0.12.dist-info}/licenses/LICENSE +0 -0
  61. {qtype-0.0.10.dist-info → qtype-0.0.12.dist-info}/top_level.txt +0 -0
qtype/commands/run.py CHANGED
@@ -5,46 +5,41 @@ Command-line interface for running QType YAML spec files.
5
5
  from __future__ import annotations
6
6
 
7
7
  import argparse
8
+ import json
8
9
  import logging
10
+ from pathlib import Path
9
11
  from typing import Any
10
12
 
11
- from qtype.dsl.domain_types import ChatMessage
12
- from qtype.interpreter.flow import execute_flow
13
- from qtype.interpreter.typing import create_input_type_model
14
- from qtype.loader import load
15
- from qtype.semantic.model import Application, Flow, Step
16
-
17
- logger = logging.getLogger(__name__)
13
+ import magic
14
+ import pandas as pd
18
15
 
16
+ from qtype.application.facade import QTypeFacade
17
+ from qtype.base.exceptions import InterpreterError, LoadError, ValidationError
19
18
 
20
- def _get_flow(app: Application, flow_id: str | None) -> Flow:
21
- if len(app.flows) == 0:
22
- raise ValueError(
23
- "No flows found in the application."
24
- " Please ensure the spec contains at least one flow."
25
- )
19
+ logger = logging.getLogger(__name__)
26
20
 
27
- if flow_id is not None:
28
- # find the first flow in the list with the given flow_id
29
- flow = next((f for f in app.flows if f.id == flow_id), None)
30
- if flow is None:
31
- raise ValueError(f"Flow not found: {flow_id}")
32
21
 
22
+ def read_data_from_file(file_path: str) -> pd.DataFrame:
23
+ """
24
+ Reads a file into a pandas DataFrame based on its MIME type.
25
+ """
26
+ mime_type = magic.Magic(mime=True).from_file(file_path)
27
+
28
+ if mime_type == "text/csv":
29
+ return pd.read_csv(file_path)
30
+ elif mime_type == "application/json":
31
+ return pd.read_json(file_path)
32
+ elif mime_type in [
33
+ "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
34
+ "application/vnd.ms-excel",
35
+ ]:
36
+ return pd.read_excel(file_path)
37
+ elif mime_type in ["application/vnd.parquet", "application/octet-stream"]:
38
+ return pd.read_parquet(file_path)
33
39
  else:
34
- flow = app.flows[0]
35
-
36
- return flow
37
-
38
-
39
- def _telemetry(spec: Application) -> None:
40
- if spec.telemetry:
41
- logger.info(
42
- f"Telemetry enabled with endpoint: {spec.telemetry.endpoint}"
40
+ raise ValueError(
41
+ f"Unsupported MIME type for file {file_path}: {mime_type}"
43
42
  )
44
- # Register telemetry if needed
45
- from qtype.interpreter.telemetry import register
46
-
47
- register(spec.telemetry, spec.id)
48
43
 
49
44
 
50
45
  def run_flow(args: Any) -> None:
@@ -53,45 +48,70 @@ def run_flow(args: Any) -> None:
53
48
  Args:
54
49
  args: Arguments passed from the command line or calling context.
55
50
  """
56
- spec, _ = load(args.spec)
57
-
58
- flow = _get_flow(spec, args.flow)
59
- logger.info(f"Executing flow: {flow.id}")
60
- input_type = create_input_type_model(flow)
61
- inputs = input_type.model_validate_json(args.input)
62
- for var in flow.inputs:
63
- # Get the value from the request using the variable ID
64
- inputs_dict = inputs.model_dump() # type: ignore
65
- if var.id in inputs_dict:
66
- var.value = getattr(inputs, var.id)
67
- _telemetry(spec)
68
-
69
- was_streamed = False
70
- previous: str = ""
71
-
72
- def stream_fn(step: Step, msg: ChatMessage | str) -> None:
73
- """Stream function to handle step outputs."""
74
- nonlocal was_streamed, previous
75
- if step == flow.steps[-1]:
76
- was_streamed = True
77
- if isinstance(msg, ChatMessage):
78
- content = " ".join(
79
- [m.content for m in msg.blocks if m.content]
80
- )
81
- # Note: streaming chat messages accumulate the content...
82
- content = content.removeprefix(previous)
83
- print(content, end="", flush=True)
84
- previous += content
85
- else:
86
- print(msg, end="", flush=True)
87
-
88
- result = execute_flow(flow, stream_fn=stream_fn) # type: ignore
89
- if not was_streamed:
90
- logger.info(
91
- f"Flow execution result: {', '.join([f'{var.id}: {var.value}' for var in result])}"
51
+ facade = QTypeFacade()
52
+ spec_path = Path(args.spec)
53
+
54
+ try:
55
+ logger.info(f"Running flow from {spec_path}")
56
+
57
+ if args.input_file:
58
+ logger.info(f"Loading input data from file: {args.input_file}")
59
+ input: Any = read_data_from_file(args.input_file)
60
+ else:
61
+ # Parse input JSON
62
+ try:
63
+ input = json.loads(args.input) if args.input else {}
64
+ except json.JSONDecodeError as e:
65
+ logger.error(f"❌ Invalid JSON input: {e}")
66
+ return
67
+
68
+ # Execute the workflow using the facade
69
+ result = facade.execute_workflow(
70
+ spec_path, flow_name=args.flow, inputs=input, batch_config=None
92
71
  )
93
- else:
94
- print("\n")
72
+
73
+ logger.info("✅ Flow execution completed successfully")
74
+
75
+ # Print results
76
+ if isinstance(result, pd.DataFrame):
77
+ logging.info("Output DataFrame:")
78
+ logging.info(result)
79
+ elif (
80
+ result
81
+ and hasattr(result, "__iter__")
82
+ and not isinstance(result, str)
83
+ ):
84
+ # If result is a list of variables or similar
85
+ try:
86
+ for item in result:
87
+ if hasattr(item, "id") and hasattr(item, "value"):
88
+ logger.info(f"Output {item.id}: {item.value}")
89
+ else:
90
+ logger.info(f"Result: {item}")
91
+ except TypeError:
92
+ logger.info(f"Result: {result}")
93
+ elif isinstance(result, str):
94
+ logger.info(f"Result: {result}")
95
+ else:
96
+ logger.info("Flow completed with no output")
97
+
98
+ # save the output
99
+ if isinstance(result, pd.DataFrame) and args.output:
100
+ result.to_parquet(args.output)
101
+ logger.info(f"Output DataFrame saved to {args.output}")
102
+ elif args.output:
103
+ with open(args.output, "w") as f:
104
+ json.dump(result, f, indent=2)
105
+ logger.info(f"Output saved to {args.output}")
106
+
107
+ except LoadError as e:
108
+ logger.error(f"❌ Failed to load document: {e}")
109
+ except ValidationError as e:
110
+ logger.error(f"❌ Validation failed: {e}")
111
+ except InterpreterError as e:
112
+ logger.error(f"❌ Execution failed: {e}")
113
+ except Exception as e:
114
+ logger.error(f"❌ Unexpected error: {e}", exc_info=True)
95
115
 
96
116
 
97
117
  def parser(subparsers: argparse._SubParsersAction) -> None:
@@ -110,14 +130,31 @@ def parser(subparsers: argparse._SubParsersAction) -> None:
110
130
  default=None,
111
131
  help="The name of the flow to run. If not specified, runs the first flow found.",
112
132
  )
133
+ # Allow either a direct JSON string or an input file
134
+ input_group = cmd_parser.add_mutually_exclusive_group()
135
+ input_group.add_argument(
136
+ "-i",
137
+ "--input",
138
+ type=str,
139
+ default="{}",
140
+ help="JSON blob of input values for the flow (default: {}).",
141
+ )
142
+ input_group.add_argument(
143
+ "-I",
144
+ "--input-file",
145
+ type=str,
146
+ default=None,
147
+ help="Path to a file (e.g., CSV, JSON, Parquet) with input data for batch processing.",
148
+ )
113
149
  cmd_parser.add_argument(
114
- "input",
150
+ "-o",
151
+ "--output",
115
152
  type=str,
116
- help="JSON blob of input values for the flow.",
153
+ default=None,
154
+ help="Path to save output data. If input is a DataFrame, output will be saved as parquet. If single result, saved as JSON.",
117
155
  )
118
156
 
119
157
  cmd_parser.add_argument(
120
158
  "spec", type=str, help="Path to the QType YAML spec file."
121
159
  )
122
-
123
160
  cmd_parser.set_defaults(func=run_flow)
qtype/commands/serve.py CHANGED
@@ -1,17 +1,18 @@
1
1
  """
2
- Command-line interface for running QType YAML spec files.
2
+ Command-line interface for serving QType YAML spec files as web APIs.
3
3
  """
4
4
 
5
5
  from __future__ import annotations
6
6
 
7
7
  import argparse
8
8
  import logging
9
+ from pathlib import Path
9
10
  from typing import Any
10
11
 
11
12
  import uvicorn
12
13
 
13
- from qtype.commands.run import _telemetry
14
- from qtype.loader import load
14
+ from qtype.application.facade import QTypeFacade
15
+ from qtype.base.exceptions import LoadError, ValidationError
15
16
 
16
17
  logger = logging.getLogger(__name__)
17
18
 
@@ -22,31 +23,44 @@ def serve(args: Any) -> None:
22
23
  Args:
23
24
  args: Arguments passed from the command line or calling context.
24
25
  """
25
- spec, _ = load(args.spec)
26
- logger.info(f"Running API for spec: {args.spec}")
27
- from qtype.interpreter.api import APIExecutor
28
-
29
- # Get the name from the spec filename.
30
- # so if filename is tests/specs/full_application_test.qtype.yaml, name should be "Full Application Test"
31
- name = (
32
- args.spec.split("/")[-1]
33
- .replace(".qtype.yaml", "")
34
- .replace("_", " ")
35
- .title()
36
- )
37
-
38
- _telemetry(spec)
39
- api_executor = APIExecutor(spec)
40
- fastapi_app = api_executor.create_app(
41
- name=name, ui_enabled=not args.disable_ui
42
- )
43
-
44
- uvicorn.run(
45
- fastapi_app,
46
- host=args.host,
47
- port=args.port,
48
- log_level="info",
49
- )
26
+ facade = QTypeFacade()
27
+
28
+ try:
29
+ # Use facade to load and validate the document
30
+ spec_path = Path(args.spec)
31
+ logger.info(f"Loading and validating spec: {spec_path}")
32
+
33
+ semantic_model, type_registry = facade.load_semantic_model(spec_path)
34
+ logger.info(f" Successfully loaded spec: {spec_path}")
35
+
36
+ # Import APIExecutor and create the FastAPI app
37
+ from qtype.interpreter.api import APIExecutor
38
+
39
+ # Get the name from the spec filename
40
+ name = (
41
+ spec_path.name.replace(".qtype.yaml", "").replace("_", " ").title()
42
+ )
43
+
44
+ logger.info(f"Starting server for: {name}")
45
+ api_executor = APIExecutor(semantic_model)
46
+ fastapi_app = api_executor.create_app(
47
+ name=name, ui_enabled=not args.disable_ui
48
+ )
49
+
50
+ # Start the server
51
+ uvicorn.run(
52
+ fastapi_app, host=args.host, port=args.port, log_level="info"
53
+ )
54
+
55
+ except LoadError as e:
56
+ logger.error(f"❌ Failed to load document: {e}")
57
+ exit(1)
58
+ except ValidationError as e:
59
+ logger.error(f"❌ Validation failed: {e}")
60
+ exit(1)
61
+ except Exception as e:
62
+ logger.error(f"❌ Unexpected error starting server: {e}")
63
+ exit(1)
50
64
 
51
65
 
52
66
  def parser(subparsers: argparse._SubParsersAction) -> None:
@@ -2,23 +2,16 @@
2
2
  Command-line interface for validating QType YAML spec files.
3
3
  """
4
4
 
5
+ from __future__ import annotations
6
+
5
7
  import argparse
6
8
  import logging
7
9
  import sys
10
+ from pathlib import Path
8
11
  from typing import Any
9
12
 
10
- from pydantic import ValidationError
11
-
12
- from qtype import dsl
13
- from qtype.dsl.custom_types import build_dynamic_types
14
- from qtype.dsl.validator import QTypeValidationError, validate
15
- from qtype.loader import (
16
- _list_dynamic_types_from_document,
17
- _resolve_root,
18
- load_yaml,
19
- )
20
- from qtype.semantic.errors import SemanticResolutionError
21
- from qtype.semantic.resolver import resolve
13
+ from qtype.application.facade import QTypeFacade
14
+ from qtype.base.exceptions import LoadError, SemanticError, ValidationError
22
15
 
23
16
  logger = logging.getLogger(__name__)
24
17
 
@@ -33,42 +26,32 @@ def main(args: Any) -> None:
33
26
  Exits:
34
27
  Exits with code 1 if validation fails.
35
28
  """
29
+ facade = QTypeFacade()
30
+ spec_path = Path(args.spec)
31
+
36
32
  try:
37
- yaml_data = load_yaml(args.spec)
38
- dynamic_types_lists = _list_dynamic_types_from_document(yaml_data)
39
- dynamic_types_registry = build_dynamic_types(dynamic_types_lists)
40
- logging.info("✅ Schema validation successful.")
33
+ # Use the facade for validation - it will raise exceptions on errors
34
+ loaded_data = facade.load_and_validate(spec_path)
35
+ logger.info("✅ Validation successful - document is valid.")
41
36
 
42
- document = dsl.Document.model_validate(
43
- yaml_data, context={"custom_types": dynamic_types_registry}
44
- )
45
- logging.info("✅ Model validation successful.")
46
- root = _resolve_root(document)
47
- if not isinstance(root, dsl.Application):
48
- logging.warning(
49
- "🟨 Spec is not an Application, skipping semantic resolution."
50
- )
51
- else:
52
- root = validate(root)
53
- logger.info("✅ Language validation successful")
54
- app = resolve(root)
55
- logger.info("✅ Semantic validation successful")
37
+ # If printing is requested, load and print the document
56
38
  if args.print:
57
- logger.info(
58
- (app if "app" in locals() else root).model_dump_json( # type: ignore
59
- indent=2,
60
- exclude_none=True,
61
- )
62
- )
39
+ try:
40
+ print(loaded_data.model_dump_json(indent=2, exclude_none=True)) # type: ignore
41
+ except Exception as e:
42
+ logger.warning(f"Could not print document: {e}")
63
43
 
64
- except ValidationError as exc:
65
- logger.error("❌ Validation failed:\n%s", exc)
44
+ except LoadError as e:
45
+ logger.error(f"❌ Failed to load document: {e}")
46
+ sys.exit(1)
47
+ except ValidationError as e:
48
+ logger.error(f"❌ Validation failed: {e}")
66
49
  sys.exit(1)
67
- except QTypeValidationError as exc:
68
- logger.error("❌ DSL validation failed:\n%s", exc)
50
+ except SemanticError as e:
51
+ logger.error(f"❌ Semantic validation failed: {e}")
69
52
  sys.exit(1)
70
- except SemanticResolutionError as exc:
71
- logger.error("❌ Semantic resolution failed:\n%s", exc)
53
+ except Exception as e:
54
+ logger.error(f"❌ Unexpected error during validation: {e}")
72
55
  sys.exit(1)
73
56
 
74
57
 
@@ -2,61 +2,75 @@
2
2
  Command-line interface for visualizing QType YAML spec files.
3
3
  """
4
4
 
5
+ from __future__ import annotations
6
+
5
7
  import argparse
6
8
  import logging
7
9
  import tempfile
8
10
  import webbrowser
11
+ from pathlib import Path
9
12
  from typing import Any
10
13
 
11
- from qtype.loader import load
12
- from qtype.semantic.visualize import visualize_application
14
+ from qtype.application.facade import QTypeFacade
15
+ from qtype.base.exceptions import LoadError, ValidationError
13
16
 
14
17
  logger = logging.getLogger(__name__)
15
18
 
16
19
 
17
20
  def main(args: Any) -> None:
18
21
  """
19
- visualize a QType YAML spec file against the QTypeSpec schema and semantics.
22
+ Visualize a QType YAML spec file.
20
23
 
21
24
  Args:
22
25
  args: Arguments passed from the command line or calling context.
23
26
 
24
27
  Exits:
25
- Exits with code 1 if validation fails.
28
+ Exits with code 1 if visualization fails.
26
29
  """
27
- import mermaid as md
28
-
29
- application, _ = load(args.spec)
30
-
31
- diagram = visualize_application(application)
32
-
33
- render = None
34
- if args.output:
35
- if args.output.endswith(".mmd") or args.output.endswith(".mermaid"):
36
- with open(args.output, "w") as f:
37
- f.write(diagram)
38
- logger.info(f"Mermaid diagram written to {args.output}")
39
- elif args.output.endswith(".svg"):
40
- render = md.Mermaid(diagram)
41
- render.to_svg(args.output)
42
- logger.info(f"SVG diagram written to {args.output}")
43
-
44
- elif args.output.endswith(".png"):
45
- render = md.Mermaid(diagram)
46
- render.to_png(args.output)
47
- logger.info(f"PNG diagram written to {args.output}")
48
-
49
- if not args.no_display:
50
- if not render:
51
- render = md.Mermaid(diagram)
52
-
53
- html_content = render._repr_html_()
54
- # Create a temporary HTML file to display the diagram
55
- with tempfile.NamedTemporaryFile(
56
- delete=False, suffix=".html"
57
- ) as temp_file:
58
- temp_file.write(html_content.encode("utf-8"))
59
- webbrowser.open(temp_file.name)
30
+ facade = QTypeFacade()
31
+ spec_path = Path(args.spec)
32
+
33
+ try:
34
+ # Generate visualization using the facade
35
+ mermaid_content = facade.visualize_application(spec_path)
36
+
37
+ if args.output:
38
+ # Write to file
39
+ output_path = Path(args.output)
40
+ output_path.write_text(mermaid_content, encoding="utf-8")
41
+ logger.info(f" Visualization saved to {output_path}")
42
+
43
+ if not args.no_display:
44
+ # Create temporary HTML file and open in browser
45
+ try:
46
+ import mermaid as md # type: ignore[import-untyped]
47
+
48
+ mm = md.Mermaid(mermaid_content)
49
+ html_content = mm._repr_html_()
50
+
51
+ with tempfile.NamedTemporaryFile(
52
+ mode="w", suffix=".html", delete=False, encoding="utf-8"
53
+ ) as f:
54
+ f.write(html_content)
55
+ temp_file = f.name
56
+
57
+ logger.info(f"Opening visualization in browser: {temp_file}")
58
+ webbrowser.open(f"file://{temp_file}")
59
+ except ImportError:
60
+ logger.warning(
61
+ "❌ Mermaid library not installed. Cannot display in browser."
62
+ )
63
+ logger.info("Install with: pip install mermaid")
64
+
65
+ except LoadError as e:
66
+ logger.error(f"❌ Failed to load document: {e}")
67
+ exit(1)
68
+ except ValidationError as e:
69
+ logger.error(f"❌ Visualization failed: {e}")
70
+ exit(1)
71
+ except Exception as e:
72
+ logger.error(f"❌ Unexpected error: {e}")
73
+ exit(1)
60
74
 
61
75
 
62
76
  def parser(subparsers: argparse._SubParsersAction) -> None:
qtype/dsl/__init__.py CHANGED
@@ -1 +1,10 @@
1
+ """DSL package - core data models only."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from .base_types import * # noqa: F403
6
+ from .domain_types import * # noqa: F403
1
7
  from .model import * # noqa: F403
8
+
9
+ # Note: Validation logic has been moved to qtype.semantic package
10
+ # to avoid circular dependencies
qtype/dsl/base_types.py CHANGED
@@ -24,6 +24,14 @@ class PrimitiveTypeEnum(str, Enum):
24
24
  video = "video"
25
25
 
26
26
 
27
+ class StepCardinality(str, Enum):
28
+ """Does this step emit 1 (one) or 0...N (many) items?"""
29
+
30
+ one = "one"
31
+ many = "many"
32
+ auto = "auto" # Let's the step determine this in semantic resolution. Currently only Flows can do this..
33
+
34
+
27
35
  class StrictBaseModel(BaseModel):
28
36
  """Base model with extra fields forbidden."""
29
37
 
qtype/dsl/custom_types.py CHANGED
@@ -2,13 +2,13 @@ from typing import Any, ForwardRef, Type, Union
2
2
 
3
3
  from pydantic import BaseModel, create_model
4
4
 
5
- from qtype.converters.types import PRIMITIVE_TO_PYTHON_TYPE
5
+ from qtype.application.converters.types import PRIMITIVE_TO_PYTHON_TYPE
6
6
 
7
7
  # --- This would be in your interpreter's logic ---
8
8
 
9
9
 
10
10
  def build_dynamic_types(
11
- type_definitions: list[dict]
11
+ type_definitions: list[dict],
12
12
  ) -> dict[str, Type[BaseModel]]:
13
13
  """
14
14
  Parses a list of simplified type definitions and dynamically creates
@@ -32,7 +32,7 @@ def build_dynamic_types(
32
32
  if type_str.startswith("list[") and type_str.endswith("]"):
33
33
  inner_type_name = type_str[5:-1]
34
34
  inner_type, _ = _parse_type_string(inner_type_name)
35
- resolved_type = list[inner_type]
35
+ resolved_type: Any = list[inner_type] # type: ignore[misc, valid-type]
36
36
  elif type_str in PRIMITIVE_MAP:
37
37
  resolved_type = PRIMITIVE_MAP[type_str]
38
38
  elif type_str in created_models:
@@ -60,7 +60,9 @@ def build_dynamic_types(
60
60
 
61
61
  # Pass the created_models dict as the local namespace for resolution
62
62
  DynamicModel = create_model(
63
- model_name, **field_definitions, __localns=created_models
63
+ model_name,
64
+ **field_definitions,
65
+ __localns=created_models, # type: ignore[call-overload]
64
66
  )
65
67
  created_models[model_name] = DynamicModel
66
68