pyopenapi-gen 0.10.2__py3-none-any.whl → 0.12.0__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 (33) hide show
  1. pyopenapi_gen/__init__.py +1 -1
  2. pyopenapi_gen/core/exceptions.py +1 -6
  3. pyopenapi_gen/core/loader/loader.py +19 -3
  4. pyopenapi_gen/core/loader/operations/parser.py +12 -6
  5. pyopenapi_gen/core/loader/operations/post_processor.py +4 -2
  6. pyopenapi_gen/core/loader/operations/request_body.py +10 -5
  7. pyopenapi_gen/core/loader/parameters/parser.py +66 -10
  8. pyopenapi_gen/core/loader/responses/parser.py +14 -7
  9. pyopenapi_gen/core/loader/schemas/extractor.py +42 -11
  10. pyopenapi_gen/core/parsing/context.py +4 -2
  11. pyopenapi_gen/core/parsing/keywords/all_of_parser.py +8 -4
  12. pyopenapi_gen/core/parsing/keywords/any_of_parser.py +10 -5
  13. pyopenapi_gen/core/parsing/keywords/array_items_parser.py +6 -3
  14. pyopenapi_gen/core/parsing/keywords/one_of_parser.py +10 -5
  15. pyopenapi_gen/core/parsing/schema_finalizer.py +6 -3
  16. pyopenapi_gen/core/parsing/schema_parser.py +6 -4
  17. pyopenapi_gen/emitters/endpoints_emitter.py +2 -1
  18. pyopenapi_gen/emitters/models_emitter.py +12 -14
  19. pyopenapi_gen/generator/client_generator.py +20 -5
  20. pyopenapi_gen/helpers/type_resolution/named_resolver.py +6 -7
  21. pyopenapi_gen/helpers/type_resolution/object_resolver.py +18 -14
  22. pyopenapi_gen/types/resolvers/schema_resolver.py +18 -3
  23. pyopenapi_gen/visit/endpoint/generators/response_handler_generator.py +1 -1
  24. pyopenapi_gen/visit/endpoint/generators/signature_generator.py +3 -11
  25. pyopenapi_gen/visit/model/alias_generator.py +15 -8
  26. pyopenapi_gen/visit/model/dataclass_generator.py +25 -15
  27. pyopenapi_gen/visit/model/enum_generator.py +34 -22
  28. pyopenapi_gen/visit/model/model_visitor.py +7 -5
  29. {pyopenapi_gen-0.10.2.dist-info → pyopenapi_gen-0.12.0.dist-info}/METADATA +3 -3
  30. {pyopenapi_gen-0.10.2.dist-info → pyopenapi_gen-0.12.0.dist-info}/RECORD +33 -33
  31. {pyopenapi_gen-0.10.2.dist-info → pyopenapi_gen-0.12.0.dist-info}/WHEEL +0 -0
  32. {pyopenapi_gen-0.10.2.dist-info → pyopenapi_gen-0.12.0.dist-info}/entry_points.txt +0 -0
  33. {pyopenapi_gen-0.10.2.dist-info → pyopenapi_gen-0.12.0.dist-info}/licenses/LICENSE +0 -0
@@ -77,9 +77,10 @@ class ClientGenerator:
77
77
  else:
78
78
  log_msg = f"{timestamp} ({elapsed:.2f}s) {message}"
79
79
 
80
- # logger.info(log_msg) # Keep commented out to ensure test_gen_nonexistent_spec_path passes
81
- # Also print to stdout for CLI users
82
- # print(log_msg) # Keep commented out
80
+ logger.info(log_msg)
81
+ # Also print to stdout for CLI users when verbose mode is enabled
82
+ if self.verbose:
83
+ print(log_msg)
83
84
 
84
85
  def generate(
85
86
  self,
@@ -523,9 +524,23 @@ class ClientGenerator:
523
524
  """
524
525
  spec_path_obj = Path(path_or_url)
525
526
  if spec_path_obj.exists() and spec_path_obj.is_file(): # Added is_file() check
526
- import yaml
527
+ text = spec_path_obj.read_text()
528
+ # Prefer JSON for .json files to avoid optional PyYAML dependency in tests
529
+ if spec_path_obj.suffix.lower() == ".json":
530
+ import json
531
+
532
+ data = json.loads(text)
533
+ else:
534
+ try:
535
+ import yaml
536
+
537
+ data = yaml.safe_load(text)
538
+ except ModuleNotFoundError:
539
+ # Fallback: attempt JSON parsing if YAML is unavailable
540
+ import json
541
+
542
+ data = json.loads(text)
527
543
 
528
- data = yaml.safe_load(spec_path_obj.read_text())
529
544
  if not isinstance(data, dict):
530
545
  raise GenerationError("Loaded spec is not a dictionary.")
531
546
  return data
@@ -75,15 +75,14 @@ class NamedTypeResolver:
75
75
  if schema.name and schema.name in self.all_schemas:
76
76
  # This schema is a REFERENCE to a globally defined schema (e.g., in components/schemas)
77
77
  ref_schema = self.all_schemas[schema.name] # Get the actual definition
78
- assert ref_schema.name is not None, f"Schema '{schema.name}' resolved to ref_schema with None name."
78
+ if ref_schema.name is None:
79
+ raise RuntimeError(f"Schema '{schema.name}' resolved to ref_schema with None name.")
79
80
 
80
81
  # NEW: Use generation_name and final_module_stem from the referenced schema
81
- assert (
82
- ref_schema.generation_name is not None
83
- ), f"Referenced schema '{ref_schema.name}' must have generation_name set."
84
- assert (
85
- ref_schema.final_module_stem is not None
86
- ), f"Referenced schema '{ref_schema.name}' must have final_module_stem set."
82
+ if ref_schema.generation_name is None:
83
+ raise RuntimeError(f"Referenced schema '{ref_schema.name}' must have generation_name set.")
84
+ if ref_schema.final_module_stem is None:
85
+ raise RuntimeError(f"Referenced schema '{ref_schema.name}' must have final_module_stem set.")
87
86
 
88
87
  class_name_for_ref = ref_schema.generation_name
89
88
  module_name_for_ref = ref_schema.final_module_stem
@@ -113,12 +113,14 @@ class ObjectTypeResolver:
113
113
  # If this named object is a component schema, ensure it's imported.
114
114
  if schema.name and schema.name in self.all_schemas:
115
115
  actual_schema_def = self.all_schemas[schema.name]
116
- assert (
117
- actual_schema_def.generation_name is not None
118
- ), f"Actual schema '{actual_schema_def.name}' for '{schema.name}' must have generation_name."
119
- assert (
120
- actual_schema_def.final_module_stem is not None
121
- ), f"Actual schema '{actual_schema_def.name}' for '{schema.name}' must have final_module_stem."
116
+ if actual_schema_def.generation_name is None:
117
+ raise RuntimeError(
118
+ f"Actual schema '{actual_schema_def.name}' for '{schema.name}' must have generation_name."
119
+ )
120
+ if actual_schema_def.final_module_stem is None:
121
+ raise RuntimeError(
122
+ f"Actual schema '{actual_schema_def.name}' for '{schema.name}' must have final_module_stem."
123
+ )
122
124
 
123
125
  class_name_to_use = actual_schema_def.generation_name
124
126
  module_stem_to_use = actual_schema_def.final_module_stem
@@ -162,14 +164,16 @@ class ObjectTypeResolver:
162
164
  schema.name and schema.name in self.all_schemas
163
165
  ): # Named object, no properties, AND it's a known component
164
166
  actual_schema_def = self.all_schemas[schema.name]
165
- assert actual_schema_def.generation_name is not None, (
166
- f"Actual schema (no props) '{actual_schema_def.name}' "
167
- f"for '{schema.name}' must have generation_name."
168
- )
169
- assert actual_schema_def.final_module_stem is not None, (
170
- f"Actual schema (no props) '{actual_schema_def.name}' "
171
- f"for '{schema.name}' must have final_module_stem."
172
- )
167
+ if actual_schema_def.generation_name is None:
168
+ raise RuntimeError(
169
+ f"Actual schema (no props) '{actual_schema_def.name}' "
170
+ f"for '{schema.name}' must have generation_name."
171
+ )
172
+ if actual_schema_def.final_module_stem is None:
173
+ raise RuntimeError(
174
+ f"Actual schema (no props) '{actual_schema_def.name}' "
175
+ f"for '{schema.name}' must have final_module_stem."
176
+ )
173
177
 
174
178
  class_name_to_use = actual_schema_def.generation_name
175
179
  module_stem_to_use = actual_schema_def.final_module_stem
@@ -172,10 +172,25 @@ class OpenAPISchemaResolver(SchemaTypeResolver):
172
172
 
173
173
  def _resolve_string(self, schema: IRSchema, context: TypeContext, required: bool) -> ResolvedType:
174
174
  """Resolve string type, handling enums and formats."""
175
+ # Check if this is a properly processed enum (has generation_name)
175
176
  if hasattr(schema, "enum") and schema.enum:
176
- # This is an enum - should be promoted to named type
177
- logger.warning("Found inline enum in string schema - should be promoted")
178
- return ResolvedType(python_type="str", is_optional=not required)
177
+ # Check if this enum was properly processed (has generation_name)
178
+ if hasattr(schema, "generation_name") and schema.generation_name:
179
+ # This is a properly processed enum, it should have been handled earlier
180
+ # by _resolve_named_schema. If we're here, it might be during initial processing.
181
+ # Return the enum type name
182
+ return ResolvedType(python_type=schema.generation_name, is_optional=not required)
183
+ else:
184
+ # This is an unprocessed inline enum - log warning with details
185
+ enum_values = schema.enum[:5] if len(schema.enum) > 5 else schema.enum
186
+ more = f" (and {len(schema.enum) - 5} more)" if len(schema.enum) > 5 else ""
187
+ context_info = f"name='{schema.name}'" if schema.name else "unnamed"
188
+ logger.warning(
189
+ f"Found inline enum in string schema that wasn't promoted: "
190
+ f"{context_info}, type={schema.type}, enum_values={enum_values}{more}. "
191
+ f"This will be treated as plain 'str' instead of a proper Enum type."
192
+ )
193
+ return ResolvedType(python_type="str", is_optional=not required)
179
194
 
180
195
  # Handle string formats
181
196
  format_type = getattr(schema, "format", None)
@@ -388,7 +388,7 @@ class EndpointResponseHandlerGenerator:
388
388
  # All code paths should be covered by the match statement above
389
389
  writer.write_line("# All paths above should return or raise - this should never execute")
390
390
  context.add_import("typing", "NoReturn")
391
- writer.write_line("assert False, 'Unexpected code path' # pragma: no cover")
391
+ writer.write_line("raise RuntimeError('Unexpected code path') # pragma: no cover")
392
392
  writer.write_line("") # Add a blank line for readability
393
393
 
394
394
  def _write_strategy_based_return(
@@ -68,17 +68,9 @@ class EndpointMethodSignatureGenerator:
68
68
  p = p_orig.copy() # Work with a copy
69
69
  arg_str = f"{NameSanitizer.sanitize_method_name(p['name'])}: {p['type']}" # Ensure param name is sanitized
70
70
  if not p.get("required", False):
71
- # Default value handling: if default is None, it should be ' = None'
72
- # If default is a string, it should be ' = "default_value"'
73
- # Otherwise, ' = default_value'
74
- default_val = p.get("default")
75
- if default_val is None and not p.get("required", False): # Explicitly check for None for Optional types
76
- arg_str += f" = None"
77
- elif default_val is not None: # Only add if default is not None
78
- if isinstance(default_val, str):
79
- arg_str += f' = "{default_val}"'
80
- else:
81
- arg_str += f" = {default_val}"
71
+ # For optional parameters, always default to None to avoid type mismatches
72
+ # (e.g., enum-typed params with string defaults)
73
+ arg_str += " = None"
82
74
  args.append(arg_str)
83
75
 
84
76
  actual_return_type = return_type
@@ -24,7 +24,8 @@ class AliasGenerator:
24
24
  all_schemas: Optional[Dict[str, IRSchema]],
25
25
  ):
26
26
  # Pre-condition
27
- assert renderer is not None, "PythonConstructRenderer cannot be None"
27
+ if renderer is None:
28
+ raise ValueError("PythonConstructRenderer cannot be None")
28
29
  self.renderer = renderer
29
30
  self.all_schemas = all_schemas if all_schemas is not None else {}
30
31
  self.type_service = UnifiedTypeService(self.all_schemas)
@@ -58,10 +59,14 @@ class AliasGenerator:
58
59
  - ``TypeAlias`` is imported in the context if not already present.
59
60
  """
60
61
  # Pre-conditions
61
- assert schema is not None, "Schema cannot be None for alias generation."
62
- assert schema.name is not None, "Schema name must be present for alias generation."
63
- assert base_name, "Base name cannot be empty for alias generation."
64
- assert context is not None, "RenderContext cannot be None."
62
+ if schema is None:
63
+ raise ValueError("Schema cannot be None for alias generation.")
64
+ if schema.name is None:
65
+ raise ValueError("Schema name must be present for alias generation.")
66
+ if not base_name:
67
+ raise ValueError("Base name cannot be empty for alias generation.")
68
+ if context is None:
69
+ raise ValueError("RenderContext cannot be None.")
65
70
 
66
71
  alias_name = NameSanitizer.sanitize_class_name(base_name)
67
72
  target_type = self.type_service.resolve_schema_type(schema, context, required=True, resolve_underlying=True)
@@ -77,13 +82,15 @@ class AliasGenerator:
77
82
  )
78
83
 
79
84
  # Post-condition
80
- assert rendered_code.strip(), "Generated alias code cannot be empty."
85
+ if not rendered_code.strip():
86
+ raise RuntimeError("Generated alias code cannot be empty.")
81
87
  # PythonConstructRenderer is responsible for adding TypeAlias import
82
88
  # We can check if it was added to context if 'TypeAlias' is in the rendered code
83
89
  if "TypeAlias" in rendered_code:
84
- assert (
90
+ if not (
85
91
  "typing" in context.import_collector.imports
86
92
  and "TypeAlias" in context.import_collector.imports["typing"]
87
- ), "TypeAlias import was not added to context by renderer."
93
+ ):
94
+ raise RuntimeError("TypeAlias import was not added to context by renderer.")
88
95
 
89
96
  return rendered_code
@@ -31,7 +31,8 @@ class DataclassGenerator:
31
31
  Pre-conditions:
32
32
  - ``renderer`` is not None.
33
33
  """
34
- assert renderer is not None, "PythonConstructRenderer cannot be None."
34
+ if renderer is None:
35
+ raise ValueError("PythonConstructRenderer cannot be None.")
35
36
  self.renderer = renderer
36
37
  self.all_schemas = all_schemas if all_schemas is not None else {}
37
38
  self.type_service = UnifiedTypeService(self.all_schemas)
@@ -56,8 +57,10 @@ class DataclassGenerator:
56
57
  - Returns a valid Python default value string
57
58
  (e.g., "None", "field(default_factory=list)", "\"abc\"") or None.
58
59
  """
59
- assert ps is not None, "Property schema (ps) cannot be None."
60
- assert context is not None, "RenderContext cannot be None."
60
+ if ps is None:
61
+ raise ValueError("Property schema (ps) cannot be None.")
62
+ if context is None:
63
+ raise ValueError("RenderContext cannot be None.")
61
64
 
62
65
  if ps.type == "array":
63
66
  context.add_import("dataclasses", "field")
@@ -124,10 +127,14 @@ class DataclassGenerator:
124
127
  - Returns a non-empty string containing valid Python code for a dataclass.
125
128
  - ``@dataclass`` decorator is present, implying ``dataclasses.dataclass`` is imported.
126
129
  """
127
- assert schema is not None, "Schema cannot be None for dataclass generation."
128
- assert schema.name is not None, "Schema name must be present for dataclass generation."
129
- assert base_name, "Base name cannot be empty for dataclass generation."
130
- assert context is not None, "RenderContext cannot be None."
130
+ if schema is None:
131
+ raise ValueError("Schema cannot be None for dataclass generation.")
132
+ if schema.name is None:
133
+ raise ValueError("Schema name must be present for dataclass generation.")
134
+ if not base_name:
135
+ raise ValueError("Base name cannot be empty for dataclass generation.")
136
+ if context is None:
137
+ raise ValueError("RenderContext cannot be None.")
131
138
  # Additional check for schema type might be too strict here, as ModelVisitor decides eligibility.
132
139
 
133
140
  class_name = base_name
@@ -136,7 +143,8 @@ class DataclassGenerator:
136
143
 
137
144
  if schema.type == "array" and schema.items:
138
145
  field_name_for_array_content = "items"
139
- assert schema.items is not None, "Schema items must be present for array type dataclass field."
146
+ if schema.items is None:
147
+ raise ValueError("Schema items must be present for array type dataclass field.")
140
148
 
141
149
  list_item_py_type = self.type_service.resolve_schema_type(schema.items, context, required=True)
142
150
  list_item_py_type = TypeFinalizer(context)._clean_type(list_item_py_type)
@@ -213,16 +221,18 @@ class DataclassGenerator:
213
221
  field_mappings=field_mappings if field_mappings else None,
214
222
  )
215
223
 
216
- assert rendered_code.strip(), "Generated dataclass code cannot be empty."
224
+ if not rendered_code.strip():
225
+ raise RuntimeError("Generated dataclass code cannot be empty.")
217
226
  # PythonConstructRenderer adds the @dataclass decorator and import
218
- assert "@dataclass" in rendered_code, "Dataclass code missing @dataclass decorator."
219
- assert (
227
+ if "@dataclass" not in rendered_code:
228
+ raise RuntimeError("Dataclass code missing @dataclass decorator.")
229
+ if not (
220
230
  "dataclasses" in context.import_collector.imports
221
231
  and "dataclass" in context.import_collector.imports["dataclasses"]
222
- ), "dataclass import was not added to context by renderer."
232
+ ):
233
+ raise RuntimeError("dataclass import was not added to context by renderer.")
223
234
  if "default_factory" in rendered_code: # Check for field import if factory is used
224
- assert "field" in context.import_collector.imports.get(
225
- "dataclasses", set()
226
- ), "'field' import from dataclasses missing when default_factory is used."
235
+ if "field" not in context.import_collector.imports.get("dataclasses", set()):
236
+ raise RuntimeError("'field' import from dataclasses missing when default_factory is used.")
227
237
 
228
238
  return rendered_code
@@ -19,7 +19,8 @@ class EnumGenerator:
19
19
 
20
20
  def __init__(self, renderer: PythonConstructRenderer):
21
21
  # Pre-condition
22
- assert renderer is not None, "PythonConstructRenderer cannot be None"
22
+ if renderer is None:
23
+ raise ValueError("PythonConstructRenderer cannot be None")
23
24
  self.renderer = renderer
24
25
 
25
26
  def _generate_member_name_for_string_enum(self, value: str) -> str:
@@ -32,7 +33,8 @@ class EnumGenerator:
32
33
  Post-conditions:
33
34
  - Returns a non-empty string that is a valid Python identifier, typically uppercase.
34
35
  """
35
- assert isinstance(value, str), "Input value must be a string."
36
+ if not isinstance(value, str):
37
+ raise TypeError("Input value must be a string.")
36
38
  base_member_name = str(value).upper().replace("-", "_").replace(" ", "_")
37
39
  sanitized_member_name = re.sub(r"[^A-Z0-9_]", "", base_member_name)
38
40
 
@@ -58,10 +60,11 @@ class EnumGenerator:
58
60
  if not re.match(r"^[A-Z_]", sanitized_member_name.upper()):
59
61
  sanitized_member_name = f"MEMBER_{sanitized_member_name}"
60
62
 
61
- assert sanitized_member_name and re.match(r"^[A-Z_][A-Z0-9_]*$", sanitized_member_name.upper()), (
62
- f"Generated string enum member name '{sanitized_member_name}' "
63
- f"is not a valid Python identifier from value '{value}'."
64
- )
63
+ if not (sanitized_member_name and re.match(r"^[A-Z_][A-Z0-9_]*$", sanitized_member_name.upper())):
64
+ raise ValueError(
65
+ f"Generated string enum member name '{sanitized_member_name}' "
66
+ f"is not a valid Python identifier from value '{value}'."
67
+ )
65
68
  return sanitized_member_name
66
69
 
67
70
  def _generate_member_name_for_integer_enum(self, value: str | int, int_value_for_fallback: int) -> str:
@@ -75,8 +78,10 @@ class EnumGenerator:
75
78
  Post-conditions:
76
79
  - Returns a non-empty string that is a valid Python identifier, typically uppercase.
77
80
  """
78
- assert isinstance(value, (str, int)), "Input value for integer enum naming must be str or int."
79
- assert isinstance(int_value_for_fallback, int), "Fallback integer value must be an int."
81
+ if not isinstance(value, (str, int)):
82
+ raise TypeError("Input value for integer enum naming must be str or int.")
83
+ if not isinstance(int_value_for_fallback, int):
84
+ raise TypeError("Fallback integer value must be an int.")
80
85
 
81
86
  name_basis = str(value) # Use string representation as basis for name
82
87
  base_member_name = name_basis.upper().replace("-", "_").replace(" ", "_").replace(".", "_DOT_")
@@ -105,10 +110,11 @@ class EnumGenerator:
105
110
  if not sanitized_member_name: # Should be impossible
106
111
  sanitized_member_name = f"ENUM_MEMBER_UNKNOWN_{abs(int_value_for_fallback)}"
107
112
 
108
- assert sanitized_member_name and re.match(r"^[A-Z_][A-Z0-9_]*$", sanitized_member_name.upper()), (
109
- f"Generated integer enum member name '{sanitized_member_name}' "
110
- f"is not a valid Python identifier from value '{value}'."
111
- )
113
+ if not (sanitized_member_name and re.match(r"^[A-Z_][A-Z0-9_]*$", sanitized_member_name.upper())):
114
+ raise ValueError(
115
+ f"Generated integer enum member name '{sanitized_member_name}' "
116
+ f"is not a valid Python identifier from value '{value}'."
117
+ )
112
118
  return sanitized_member_name
113
119
 
114
120
  def generate(
@@ -138,12 +144,18 @@ class EnumGenerator:
138
144
  - Returns a non-empty string containing valid Python code for an enum.
139
145
  - ``Enum`` from the ``enum`` module is imported in the context.
140
146
  """
141
- assert schema is not None, "Schema cannot be None for enum generation."
142
- assert schema.name is not None, "Schema name must be present for enum generation."
143
- assert base_name, "Base name cannot be empty for enum generation."
144
- assert context is not None, "RenderContext cannot be None."
145
- assert schema.enum, "Schema must have enum values for enum generation."
146
- assert schema.type in ("string", "integer"), "Enum schema type must be 'string' or 'integer'."
147
+ if schema is None:
148
+ raise ValueError("Schema cannot be None for enum generation.")
149
+ if schema.name is None:
150
+ raise ValueError("Schema name must be present for enum generation.")
151
+ if not base_name:
152
+ raise ValueError("Base name cannot be empty for enum generation.")
153
+ if context is None:
154
+ raise ValueError("RenderContext cannot be None.")
155
+ if not schema.enum:
156
+ raise ValueError("Schema must have enum values for enum generation.")
157
+ if schema.type not in ("string", "integer"):
158
+ raise ValueError("Enum schema type must be 'string' or 'integer'.")
147
159
 
148
160
  enum_class_name = base_name # PythonConstructRenderer will sanitize this class name
149
161
  base_type = "str" if schema.type == "string" else "int"
@@ -192,9 +204,9 @@ class EnumGenerator:
192
204
  context=context,
193
205
  )
194
206
 
195
- assert rendered_code.strip(), "Generated enum code cannot be empty."
196
- assert (
197
- "enum" in context.import_collector.imports and "Enum" in context.import_collector.imports["enum"]
198
- ), "Enum import was not added to context by renderer."
207
+ if not rendered_code.strip():
208
+ raise RuntimeError("Generated enum code cannot be empty.")
209
+ if not ("enum" in context.import_collector.imports and "Enum" in context.import_collector.imports["enum"]):
210
+ raise RuntimeError("Enum import was not added to context by renderer.")
199
211
 
200
212
  return rendered_code
@@ -114,7 +114,7 @@ class ModelVisitor(Visitor[IRSchema, str]):
114
114
  logger.error(
115
115
  f"ModelVisitor: Schema has no usable name (name or generation_name) for model generation: {schema}"
116
116
  )
117
- assert False, "Schema must have a name or generation_name for model code generation at this point."
117
+ raise RuntimeError("Schema must have a name or generation_name for model code generation at this point.")
118
118
  # return "" # Should not reach here if assertions are active
119
119
 
120
120
  # --- Import Registration ---
@@ -144,13 +144,15 @@ class ModelVisitor(Visitor[IRSchema, str]):
144
144
  # "alias, enum, or dataclass. No standalone model generated by ModelVisitor."
145
145
  # )
146
146
  # Post-condition: returns empty string if no specific generator called
147
- assert not rendered_code, "Rendered code should be empty if no generator was matched."
147
+ if rendered_code:
148
+ raise RuntimeError("Rendered code should be empty if no generator was matched.")
148
149
  return ""
149
150
 
150
151
  # Post-condition: ensure some code was generated if a generator was called
151
- assert rendered_code.strip() or not (
152
- is_type_alias or is_enum or is_dataclass
153
- ), f"Code generation resulted in an empty string for schema '{schema.name}' which was matched as a model type."
152
+ if not rendered_code.strip() and (is_type_alias or is_enum or is_dataclass):
153
+ raise RuntimeError(
154
+ f"Code generation resulted in an empty string for schema '{schema.name}' which was matched as a model type."
155
+ )
154
156
 
155
157
  return self.formatter.format(rendered_code)
156
158
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pyopenapi-gen
3
- Version: 0.10.2
3
+ Version: 0.12.0
4
4
  Summary: Modern, async-first Python client generator for OpenAPI specifications with advanced cycle detection and unified type resolution
5
5
  Project-URL: Homepage, https://github.com/your-org/pyopenapi-gen
6
6
  Project-URL: Documentation, https://github.com/your-org/pyopenapi-gen/blob/main/README.md
@@ -32,13 +32,13 @@ Classifier: Topic :: Software Development :: Libraries :: Python Modules
32
32
  Classifier: Topic :: System :: Networking
33
33
  Classifier: Typing :: Typed
34
34
  Requires-Python: <4.0.0,>=3.12
35
- Requires-Dist: click<9.0.0,>=8.0.0
35
+ Requires-Dist: click>=8.0.0
36
36
  Requires-Dist: dataclass-wizard>=0.22.0
37
37
  Requires-Dist: httpx>=0.24.0
38
38
  Requires-Dist: openapi-core>=0.19
39
39
  Requires-Dist: openapi-spec-validator>=0.7
40
40
  Requires-Dist: pyyaml>=6.0
41
- Requires-Dist: typer<0.14.0,>=0.12.0
41
+ Requires-Dist: typer>=0.14.0
42
42
  Provides-Extra: dev
43
43
  Requires-Dist: bandit[toml]>=1.7.0; extra == 'dev'
44
44
  Requires-Dist: black>=23.0; extra == 'dev'
@@ -1,4 +1,4 @@
1
- pyopenapi_gen/__init__.py,sha256=9DJOZ8R4qQ3tHN0XxuSOK0PWXBtbpjaNEJAgzfUVTeE,3016
1
+ pyopenapi_gen/__init__.py,sha256=jU5GYbWa4MBDeDzOzwUHl_8eLGtotxRGLj42d2yskUo,3017
2
2
  pyopenapi_gen/__main__.py,sha256=4-SCaCNhBd7rtyRK58uoDbdl93J0KhUeajP_b0CPpLE,110
3
3
  pyopenapi_gen/cli.py,sha256=_ewksNDaA5st3TJJMZJWgCZdBGOQp__tkMVqr_6U3vs,2339
4
4
  pyopenapi_gen/http_types.py,sha256=EMMYZBt8PNVZKPFu77TQija-JI-nOKyXvpiQP9-VSWE,467
@@ -10,7 +10,7 @@ pyopenapi_gen/context/import_collector.py,sha256=rnOgR5-GsHs_oS1iUVbOF3tagcH5nam
10
10
  pyopenapi_gen/context/render_context.py,sha256=AS08ha9WVjgRUsM1LFPjMCgrsHbczHH7c60Z5PbojhY,30320
11
11
  pyopenapi_gen/core/CLAUDE.md,sha256=bz48K-PSrhxCq5ScmiLiU9kfpVVzSWRKOA9RdKk_pbg,6482
12
12
  pyopenapi_gen/core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
13
- pyopenapi_gen/core/exceptions.py,sha256=KemyLDXl8pBgzxxV6ZhsGi7WjwKGooKU6Idy63eC2ko,553
13
+ pyopenapi_gen/core/exceptions.py,sha256=HYFiYdmzsZUl46vB8M3B6Vpp6m8iqjUcKDWdL4yEKHo,498
14
14
  pyopenapi_gen/core/http_transport.py,sha256=77ZOTyl0_CLuDtSCOVDQoxHDQBnclJgz6f3Hs6cy7hY,9675
15
15
  pyopenapi_gen/core/pagination.py,sha256=aeDOKo-Lu8mcSDqv0TlPXV9Ul-Nca76ZuKhQHKlsMUs,2301
16
16
  pyopenapi_gen/core/postprocess_manager.py,sha256=ky27ijbq6zEo43aqe-odz9CR3vFD_3XHhQR35XgMZo0,6879
@@ -22,22 +22,22 @@ pyopenapi_gen/core/warning_collector.py,sha256=DYl9D7eZYs04mDU84KeonS-5-d0aM7hNq
22
22
  pyopenapi_gen/core/auth/base.py,sha256=E2KUerA_mYv9D7xulUm-lenIxqZHqanjA4oRKpof2ZE,792
23
23
  pyopenapi_gen/core/auth/plugins.py,sha256=bDWx4MTRFsCKp1i__BsQtZEvQPGU-NKI137-zoxmrgs,3465
24
24
  pyopenapi_gen/core/loader/__init__.py,sha256=bt-MQ35fbq-f1YnCcopPg53TuXCI9_7wcMzQZoWVpjU,391
25
- pyopenapi_gen/core/loader/loader.py,sha256=bogAgDr2XvJWmMAFE006b3K_5AmC8eg2uj_TpYtLAfg,5591
25
+ pyopenapi_gen/core/loader/loader.py,sha256=fjRw6ZrG6hRS2RBWJY5IOv9e1ULc6tnxVGagqXhMmpk,6374
26
26
  pyopenapi_gen/core/loader/operations/__init__.py,sha256=7se21D-BOy7Qw6C9auJ9v6D3NCuRiDpRlhqxGq11fJs,366
27
- pyopenapi_gen/core/loader/operations/parser.py,sha256=ai5iZZA2nicouC77iEvo8jKGXbHKbX_NcTy44lkwOVQ,6896
28
- pyopenapi_gen/core/loader/operations/post_processor.py,sha256=3FZ5o59J2bSpZP-tNIec0A2hw095cC27GKqkhGrgHZA,2437
29
- pyopenapi_gen/core/loader/operations/request_body.py,sha256=qz-wh014ejb1SGTuVRNODSXc95_iOLAjw05aDRhbXoo,3099
27
+ pyopenapi_gen/core/loader/operations/parser.py,sha256=QHg3o8TRaReYofEEcBwuDuNxGDxZjkWXRDqOxKFiRtk,7046
28
+ pyopenapi_gen/core/loader/operations/post_processor.py,sha256=Rzb3GSiLyJk-0hTBZ6s6iWAj4KqE4Rfo3w-q2wm_R7w,2487
29
+ pyopenapi_gen/core/loader/operations/request_body.py,sha256=r-jscZEfOmqFA-E4i1Uj3S66rNEf1gDTlBiGUiA0P9k,3224
30
30
  pyopenapi_gen/core/loader/parameters/__init__.py,sha256=p13oSibCRC5RCfsP6w7yD9MYs5TXcdI4WwPv7oGUYKk,284
31
- pyopenapi_gen/core/loader/parameters/parser.py,sha256=4-p9s8VRm2hukXvvMF8zkd2YqSZsB18NYccVS3rwqIg,4773
31
+ pyopenapi_gen/core/loader/parameters/parser.py,sha256=rOZWbykHQy7MH1gTHI61460mFG1nPKdU9A4hOsYAiIc,7505
32
32
  pyopenapi_gen/core/loader/responses/__init__.py,sha256=6APWoH3IdNkgVmI0KsgZoZ6knDaG-S-pnUCa6gkzT8E,216
33
- pyopenapi_gen/core/loader/responses/parser.py,sha256=T0QXH_3c-Y6_S6DvveKHPfV_tID7qhBoX0nFtdLCa0A,3896
33
+ pyopenapi_gen/core/loader/responses/parser.py,sha256=F9otAn6ncQiY3C25Fq4mEJ5UFNgN83eujcX20Vd_nPU,4069
34
34
  pyopenapi_gen/core/loader/schemas/__init__.py,sha256=rlhujYfw_IzWgzhVhYMJ3eIhE6C5Vi1Ylba-BHEVqOg,296
35
- pyopenapi_gen/core/loader/schemas/extractor.py,sha256=7-lpDhs9W9wVhG1OCASdyft_V1kUH7NdP8D4x-raGjk,8364
35
+ pyopenapi_gen/core/loader/schemas/extractor.py,sha256=n2jF_g8ZjA4GQiSKEWGAt35Hw7Ek93cnxFaS4Ld21Sc,9889
36
36
  pyopenapi_gen/core/parsing/__init__.py,sha256=RJsIR6cHaNoI4tBcpMlAa0JsY64vsHb9sPxPg6rd8FQ,486
37
- pyopenapi_gen/core/parsing/context.py,sha256=crn5oTkzEvnSzYdPuHBA_s72kmq0RKzXpyaqNh67k68,7947
37
+ pyopenapi_gen/core/parsing/context.py,sha256=8cM8mPItvDvJr8ZiukvdHBumlQl9hK1gUZL4BDpHaBk,8005
38
38
  pyopenapi_gen/core/parsing/cycle_helpers.py,sha256=nG5ysNavL_6lpnHWFUZR9qraBxqOzuNfI6NgSEa8a5M,5939
39
- pyopenapi_gen/core/parsing/schema_finalizer.py,sha256=fsyuOenLJA3TndzYVETqKkSlo2Qz3TsD1YDtlbyOATQ,6839
40
- pyopenapi_gen/core/parsing/schema_parser.py,sha256=qFdan2djgdRBtzVCLiDBooVqXgcuWy_JbzDGLTJpPeE,30502
39
+ pyopenapi_gen/core/parsing/schema_finalizer.py,sha256=qRTHUoVBQTgGmdfLuBuWxtWdj_SG71STGC3rn-tJvnA,6914
40
+ pyopenapi_gen/core/parsing/schema_parser.py,sha256=W0kCV0ucq6Wybr7x1wZl-nMSRXVWAqI4T57ASSabZsM,30557
41
41
  pyopenapi_gen/core/parsing/unified_cycle_detection.py,sha256=3nplaCVh2dFwBPbmDc2kiU0SzTPXXktdQ5Rc0Q9Uu9s,10873
42
42
  pyopenapi_gen/core/parsing/common/__init__.py,sha256=U3sHMO-l6S3Cm04CVOYmBCpqLEZvCylUI7yQfcTwxYU,27
43
43
  pyopenapi_gen/core/parsing/common/type_parser.py,sha256=cK7xtxhoD43K2WjLP9TGip3As3akYeYW7L2XztXCecg,2562
@@ -52,10 +52,10 @@ pyopenapi_gen/core/parsing/common/ref_resolution/helpers/missing_ref.py,sha256=B
52
52
  pyopenapi_gen/core/parsing/common/ref_resolution/helpers/new_schema.py,sha256=MTaxiyqoPEaNFqF7tQHii3IH41M05wPKt6lBQi1SCDU,1625
53
53
  pyopenapi_gen/core/parsing/common/ref_resolution/helpers/stripped_suffix.py,sha256=ukKU64ozHINPiVlHE9YBDz1Nq2i6Xh64jhoWSEqbK5c,1774
54
54
  pyopenapi_gen/core/parsing/keywords/__init__.py,sha256=enTLacWXGXLIOjSJ3j7KNUDzU27Kq3Ww79sFElz02cM,27
55
- pyopenapi_gen/core/parsing/keywords/all_of_parser.py,sha256=s0aav49R4LYAwfEimWa0ZuFwbNWkYpRAJmcmSVDsO-s,3594
56
- pyopenapi_gen/core/parsing/keywords/any_of_parser.py,sha256=r9_0opPM75p0rPgdcRTBmae7Td3jPkJouuL_ksuFWtM,2856
57
- pyopenapi_gen/core/parsing/keywords/array_items_parser.py,sha256=dIb3_VsEkqsR9W4rwXoTT9IW313TnH66sQzJL4K7EQQ,2645
58
- pyopenapi_gen/core/parsing/keywords/one_of_parser.py,sha256=82SUPd0hk0QF4-hMr0QJmRSFa9nnJL8ncYmvgkIKKXs,2601
55
+ pyopenapi_gen/core/parsing/keywords/all_of_parser.py,sha256=ZH8rkxdDjldd226UGw5tv853ONXKaoqvWj5FfbgSoRY,3699
56
+ pyopenapi_gen/core/parsing/keywords/any_of_parser.py,sha256=HQ4iBBPgox48KIPPhM6VVZTXHIUVqpMoHkCbqcebXOw,2982
57
+ pyopenapi_gen/core/parsing/keywords/array_items_parser.py,sha256=nk9AFbx5ANLdDeGsxSTeYHhd8MqqrQwDRMzJ8FJmJxY,2723
58
+ pyopenapi_gen/core/parsing/keywords/one_of_parser.py,sha256=TUiT1dH1r8GEPExzlR3zdgnYpGxilH8yvnSWOvQmKmY,2727
59
59
  pyopenapi_gen/core/parsing/keywords/properties_parser.py,sha256=bm248ApsNskFPQF4fXq7mT5oJf6FF9yAcdVLmK6el3E,4426
60
60
  pyopenapi_gen/core/parsing/transformers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
61
61
  pyopenapi_gen/core/parsing/transformers/inline_enum_extractor.py,sha256=hXuht-t0Syi5vPO8qn9GcjEpyDcZnfFVHVIlwfMa8L0,13461
@@ -70,11 +70,11 @@ pyopenapi_gen/emitters/CLAUDE.md,sha256=iZYEZq1a1h033rxuh97cMpsKUElv72ysvTm3-QQU
70
70
  pyopenapi_gen/emitters/client_emitter.py,sha256=kmMVnG-wAOJm7TUm0xOQ5YnSJfYxz1SwtpiyoUCbcCA,1939
71
71
  pyopenapi_gen/emitters/core_emitter.py,sha256=RcBsAYQ3ZKcWwtkzQmyHkL7VtDQjbIObFLXD9M_GdpI,8020
72
72
  pyopenapi_gen/emitters/docs_emitter.py,sha256=aouKqhRdtVvYfGVsye_uqM80nONRy0SqN06cr1l3OgA,1137
73
- pyopenapi_gen/emitters/endpoints_emitter.py,sha256=2VuJJF0hpzyN-TqY9XVLQtTJ-QgedZe5Vj8ITBGsJYE,9558
73
+ pyopenapi_gen/emitters/endpoints_emitter.py,sha256=tzSLUzlZle2Lih_aZc4cJ-Y1ItjN5H_rABEWcDwECXA,9586
74
74
  pyopenapi_gen/emitters/exceptions_emitter.py,sha256=qPTIPXDyqSUtpmBIp-V4ap1uMHUPmYziCSN62t7qcAE,1918
75
- pyopenapi_gen/emitters/models_emitter.py,sha256=I3IKwtKVocD3UVrI7cINXI8NjLwUZqHuGgvS3hjWUJ8,22192
75
+ pyopenapi_gen/emitters/models_emitter.py,sha256=Gd0z2Xoze1XkVnajkOptW90ti7197wQ15I7vIITnULM,22243
76
76
  pyopenapi_gen/generator/CLAUDE.md,sha256=BS9KkmLvk2WD-Io-_apoWjGNeMU4q4LKy4UOxYF9WxM,10870
77
- pyopenapi_gen/generator/client_generator.py,sha256=avYz5GCp7t6vRAFJCvXw0ipLQGX2QfgWtfOwr3QlOqY,28880
77
+ pyopenapi_gen/generator/client_generator.py,sha256=MULKJY9SdRuYjt_R4XCXh3vJSW-92rsxOu-MVpIklho,29333
78
78
  pyopenapi_gen/helpers/CLAUDE.md,sha256=GyIJ0grp4SkD3plAUzyycW4nTUZf9ewtvvsdAGkmIZw,10609
79
79
  pyopenapi_gen/helpers/__init__.py,sha256=m4jSQ1sDH6CesIcqIl_kox4LcDFabGxBpSIWVwbHK0M,39
80
80
  pyopenapi_gen/helpers/endpoint_utils.py,sha256=bkRu6YddIPQQD3rZLbB8L5WYzG-2Bd_JgMbxMUYY2wY,22198
@@ -85,8 +85,8 @@ pyopenapi_gen/helpers/type_resolution/__init__.py,sha256=TbaQZp7jvBiYgmuzuG8Wp56
85
85
  pyopenapi_gen/helpers/type_resolution/array_resolver.py,sha256=dFppBtA6CxmiWAMR6rwGnQPv4AibL3nxtzw1LbeXVn4,2023
86
86
  pyopenapi_gen/helpers/type_resolution/composition_resolver.py,sha256=wq6CRGxGgOKK470ln5Tpk9SzHtMuwB22TXHsRLtUFyw,3015
87
87
  pyopenapi_gen/helpers/type_resolution/finalizer.py,sha256=_BcOBmOvadhBTUAvIc0Ak8FNxFw1uYL4rkKWtU68_m4,4332
88
- pyopenapi_gen/helpers/type_resolution/named_resolver.py,sha256=akHVthcD7cp9lHI-TCeABMacwQ2Z1gGp8zMGNsI_b5A,9403
89
- pyopenapi_gen/helpers/type_resolution/object_resolver.py,sha256=jayEjBr4evzIVMMAPc7g_gKb6BShFbAXG1oHMgskOcI,12373
88
+ pyopenapi_gen/helpers/type_resolution/named_resolver.py,sha256=hXu6Gao92EVV0jyHRqf9cIhoAFn3suuEw5ye9nRTFks,9423
89
+ pyopenapi_gen/helpers/type_resolution/object_resolver.py,sha256=Jm4m5QgzWU-4joPqfUSC0Y-za3Yx0ROdJjyv5J8VNk0,12557
90
90
  pyopenapi_gen/helpers/type_resolution/primitive_resolver.py,sha256=qTshZaye5ohibVfcJYCzh4v3CAshguMGWPt2FgvQeNM,1960
91
91
  pyopenapi_gen/helpers/type_resolution/resolver.py,sha256=qQY6wAitBluA-tofiyJ67Gxx8ol1W528zDWd9izYN5s,1982
92
92
  pyopenapi_gen/types/CLAUDE.md,sha256=xRYlHdLhw3QGIfIlWqPt9pewRs736H1YCzwmslKtzZc,4255
@@ -97,7 +97,7 @@ pyopenapi_gen/types/contracts/types.py,sha256=-Qvbx3N_14AaN-1BeyocrvsjiwXPn_eWQh
97
97
  pyopenapi_gen/types/resolvers/__init__.py,sha256=_5kA49RvyOTyXgt0GbbOfHJcdQw2zHxvU9af8GGyNWc,295
98
98
  pyopenapi_gen/types/resolvers/reference_resolver.py,sha256=qnaZeLmtyh4_NBMcKib58s6o5ycUJaattYt8F38_qIo,2053
99
99
  pyopenapi_gen/types/resolvers/response_resolver.py,sha256=Kb1a2803lyoukoZy06ztPBlUw-A1lHiZ6NlJmsixxA8,6500
100
- pyopenapi_gen/types/resolvers/schema_resolver.py,sha256=R0N03MDLVzaFBQcrFOOTre1zqIg6APiWdHAT96ldgQ0,16898
100
+ pyopenapi_gen/types/resolvers/schema_resolver.py,sha256=PsSF-DE8-GDXmvbAJz-tHlTCR-1UATGhT4dHf6kUDQQ,17988
101
101
  pyopenapi_gen/types/services/__init__.py,sha256=inSUKmY_Vnuym6tC-AhvjCTj16GbkfxCGLESRr_uQPE,123
102
102
  pyopenapi_gen/types/services/type_service.py,sha256=-LQj7oSx1mxb10Zi6DpawS8uyoUrUbnYhmUA0GuKZTc,4402
103
103
  pyopenapi_gen/types/strategies/__init__.py,sha256=bju8_KEPNIow1-woMO-zJCgK_E0M6JnFq0NFsK1R4Ss,171
@@ -113,19 +113,19 @@ pyopenapi_gen/visit/endpoint/generators/__init__.py,sha256=-X-GYnJZ9twiEBr_U0obW
113
113
  pyopenapi_gen/visit/endpoint/generators/docstring_generator.py,sha256=U02qvuYtFElQNEtOHuTNXFl2NxUriIiuZMkmUsapOg4,5913
114
114
  pyopenapi_gen/visit/endpoint/generators/endpoint_method_generator.py,sha256=wUJ4_gaA1gRrFCHYFCObBIankxGQu0MNqiOSoZOZmoA,4352
115
115
  pyopenapi_gen/visit/endpoint/generators/request_generator.py,sha256=OnkrkRk39_BrK9ZDvyWqJYLz1mocD2zY7j70yIpS0J4,5374
116
- pyopenapi_gen/visit/endpoint/generators/response_handler_generator.py,sha256=VuyYpUUQ3hIOwM0X_hrMk9qmQTC0P6xRQdC2HTTIyQw,22828
117
- pyopenapi_gen/visit/endpoint/generators/signature_generator.py,sha256=VC9Q_exZMpUh46hn1JXaDRlgVm3Gb-D2v36h9SDF10k,4390
116
+ pyopenapi_gen/visit/endpoint/generators/response_handler_generator.py,sha256=xbh4GQcA-fA98mOZxVSylLbZADse-7RLcLIbjnVAmlE,22834
117
+ pyopenapi_gen/visit/endpoint/generators/signature_generator.py,sha256=CYtfsPMlTZN95g2WxrdnTloGx2RmqeNQRiyP9fOkUEQ,3892
118
118
  pyopenapi_gen/visit/endpoint/generators/url_args_generator.py,sha256=EsmNuVSkGfUqrmV7-1GiLPzdN86V5UqLfs1SVY0jsf0,9590
119
119
  pyopenapi_gen/visit/endpoint/processors/__init__.py,sha256=_6RqpOdDuDheArqDBi3ykhsaetACny88WUuuAJvr_ME,29
120
120
  pyopenapi_gen/visit/endpoint/processors/import_analyzer.py,sha256=tNmhgWwt-CjLE774TC8sPVH1-yaTKKm6JmfgBT2-iRk,3386
121
121
  pyopenapi_gen/visit/endpoint/processors/parameter_processor.py,sha256=BygP8yzSTrxfvNpEQIHERjd2NpEXDiwpCtmMseJKRq0,7700
122
122
  pyopenapi_gen/visit/model/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
123
- pyopenapi_gen/visit/model/alias_generator.py,sha256=3iPFDjCXU0Vm59Hfp64jTDfHoUL8ouXTTfoEwiOVm4Q,3558
124
- pyopenapi_gen/visit/model/dataclass_generator.py,sha256=WtcQNx6l2sxVyTlH1MdQ-UFYWVMsxQk5nyJr1Mk02iM,9999
125
- pyopenapi_gen/visit/model/enum_generator.py,sha256=QWsD-IAxGOxKQuC6LLNUvbT8Ot3NWrLFsaYT0DI16DU,9670
126
- pyopenapi_gen/visit/model/model_visitor.py,sha256=PZeQd7-dlxZf5gY10BW-DhswmAGF903NccV6L56mjoE,9439
127
- pyopenapi_gen-0.10.2.dist-info/METADATA,sha256=zLVA0bddsSae8-JDBuvPKE1YjQtr-_X4AEodEKzA-DA,14040
128
- pyopenapi_gen-0.10.2.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
129
- pyopenapi_gen-0.10.2.dist-info/entry_points.txt,sha256=gxSlNiwom50T3OEZnlocA6qRjGdV0bn6hN_Xr-Ub5wA,56
130
- pyopenapi_gen-0.10.2.dist-info/licenses/LICENSE,sha256=UFAyTWKa4w10-QerlJaHJeep7G2gcwpf-JmvI2dS2Gc,1088
131
- pyopenapi_gen-0.10.2.dist-info/RECORD,,
123
+ pyopenapi_gen/visit/model/alias_generator.py,sha256=TGL3AMq_PkBWFWeeXbNnA8hgO9hvp0flwBA00Gr6S3o,3744
124
+ pyopenapi_gen/visit/model/dataclass_generator.py,sha256=nyTvBph6rtbJlCwTiDW_Y2UJmLLiA6D2QJUpA2xE0m8,10289
125
+ pyopenapi_gen/visit/model/enum_generator.py,sha256=AXqKUFuWUUjUF_6_HqBKY8vB5GYu35Pb2C2WPFrOw1k,10061
126
+ pyopenapi_gen/visit/model/model_visitor.py,sha256=4kAQSWsI4XumVYB3aAE7Ts_31hGfDlbytRalxyMFV3g,9510
127
+ pyopenapi_gen-0.12.0.dist-info/METADATA,sha256=do9Qt8fZ_bOvewCqxXYsCYbNE0qs7BtvC5Xe-AhBnBQ,14025
128
+ pyopenapi_gen-0.12.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
129
+ pyopenapi_gen-0.12.0.dist-info/entry_points.txt,sha256=gxSlNiwom50T3OEZnlocA6qRjGdV0bn6hN_Xr-Ub5wA,56
130
+ pyopenapi_gen-0.12.0.dist-info/licenses/LICENSE,sha256=UFAyTWKa4w10-QerlJaHJeep7G2gcwpf-JmvI2dS2Gc,1088
131
+ pyopenapi_gen-0.12.0.dist-info/RECORD,,