Skip to content

Commit 6a9d19c

Browse files
committed
codegen_py implementation, registry logic refactored
1 parent 853ef2e commit 6a9d19c

13 files changed

Lines changed: 1457 additions & 215 deletions

File tree

json_explorer/codegen/__init__.py

Lines changed: 7 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,19 @@
44
Generates code in various languages from JSON schema analysis.
55
"""
66

7+
# Import registry functions (this will trigger auto-registration)
78
from .registry import (
89
GeneratorRegistry,
910
get_generator,
1011
list_supported_languages,
1112
register_generator,
1213
get_language_info,
1314
list_all_language_info,
15+
is_language_supported,
16+
get_registry,
1417
)
18+
19+
# Import core interfaces
1520
from .core import (
1621
CodeGenerator,
1722
GeneratorError,
@@ -31,31 +36,6 @@
3136
create_template_engine,
3237
)
3338

34-
# Initialize global registry
35-
registry = GeneratorRegistry()
36-
37-
38-
# Auto-register available generators
39-
def _register_available_generators():
40-
"""Register all available language generators."""
41-
try:
42-
from .languages.go import GoGenerator
43-
44-
registry.register("go", GoGenerator, aliases=["golang"])
45-
except ImportError:
46-
pass
47-
48-
# Add more languages here as they become available
49-
# try:
50-
# from .languages.python import PythonGenerator
51-
# registry.register("python", PythonGenerator, aliases=["py"])
52-
# except ImportError:
53-
# pass
54-
55-
56-
# Initialize registry
57-
_register_available_generators()
58-
5939
# Version info
6040
__version__ = "0.1.0"
6141

@@ -147,9 +127,10 @@ def create_config(language="go", **kwargs) -> GeneratorConfig:
147127
"get_generator",
148128
"list_supported_languages",
149129
"register_generator",
150-
"registry",
151130
"get_language_info",
152131
"list_all_language_info",
132+
"is_language_supported",
133+
"get_registry",
153134
# Core interfaces
154135
"CodeGenerator",
155136
"GeneratorError",

json_explorer/codegen/cli_integration.py

Lines changed: 100 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,44 @@ def add_codegen_args(parser: argparse.ArgumentParser):
137137
help="Case style for JSON tag names in Go",
138138
)
139139

140+
# Python-specific options
141+
python_group = parser.add_argument_group("Python-specific options")
142+
python_group.add_argument(
143+
"--python-style",
144+
choices=["dataclass", "pydantic", "typeddict"],
145+
help="Python code style (default: dataclass)",
146+
)
147+
148+
python_group.add_argument(
149+
"--no-slots",
150+
action="store_true",
151+
help="Don't use __slots__ in dataclasses",
152+
)
153+
154+
python_group.add_argument(
155+
"--frozen",
156+
action="store_true",
157+
help="Make dataclasses frozen (immutable)",
158+
)
159+
160+
python_group.add_argument(
161+
"--kw-only",
162+
action="store_true",
163+
help="Make dataclass fields keyword-only",
164+
)
165+
166+
python_group.add_argument(
167+
"--no-pydantic-field",
168+
action="store_true",
169+
help="Don't use Field() in Pydantic models",
170+
)
171+
172+
python_group.add_argument(
173+
"--pydantic-forbid-extra",
174+
action="store_true",
175+
help="Forbid extra fields in Pydantic models",
176+
)
177+
140178

141179
def handle_codegen_command(args: argparse.Namespace, json_data=None) -> int:
142180
"""
@@ -203,7 +241,7 @@ def _list_languages() -> int:
203241
table.add_column("Language", style="bold green", no_wrap=True)
204242
table.add_column("Extension", style="cyan")
205243
table.add_column("Generator Class", style="dim")
206-
table.add_column("Aliases", style="gold1 ")
244+
table.add_column("Aliases", style="gold1")
207245

208246
for lang_name, info in sorted(language_info.items()):
209247
aliases = (
@@ -222,7 +260,8 @@ def _list_languages() -> int:
222260
console.print(
223261
Panel(
224262
"[bold]Usage:[/bold] json_explorer [dim]input.json[/dim] --generate [cyan]LANGUAGE[/cyan]\n"
225-
"[bold]Info:[/bold] json_explorer --language-info [cyan]LANGUAGE[/cyan]",
263+
"[bold]Info:[/bold] json_explorer --language-info [cyan]LANGUAGE[/cyan]\n"
264+
"[bold]Python:[/bold] json_explorer [dim]input.json[/dim] --generate [cyan]python[/cyan] --python-style [yellow]dataclass[/yellow]",
226265
title="💡 Quick Start",
227266
border_style="blue",
228267
)
@@ -263,59 +302,54 @@ def _show_language_info(language: str) -> int:
263302
)
264303
)
265304

266-
# Try to get configuration details
267-
try:
268-
generator = get_generator(language)
269-
270-
# Create configuration table
271-
config_table = Table(
272-
title="⚙️ Default Configuration",
273-
box=box.SIMPLE,
274-
show_header=True,
275-
header_style="bold cyan",
276-
)
305+
# Show language-specific examples
306+
if language == "python":
307+
_show_python_examples()
308+
elif language == "go":
309+
_show_go_examples()
277310

278-
config_table.add_column("Setting", style="bold")
279-
config_table.add_column("Value", style="green")
311+
return 0
280312

281-
config_table.add_row("Package Name", str(generator.config.package_name))
282-
config_table.add_row("Indent Size", str(generator.config.indent_size))
283-
config_table.add_row(
284-
"Generate JSON Tags", str(generator.config.generate_json_tags)
285-
)
286-
config_table.add_row("Add Comments", str(generator.config.add_comments))
287-
config_table.add_row(
288-
"JSON Tag Omitempty", str(generator.config.json_tag_omitempty)
289-
)
313+
except Exception as e:
314+
console.print(f"[red]❌ Error getting language info:[/red] {e}")
315+
return 1
290316

291-
console.print()
292-
console.print(config_table)
293317

294-
except Exception:
295-
console.print(
296-
"\n[yellow]⚠️ Could not retrieve configuration details[/yellow]"
297-
)
318+
def _show_python_examples():
319+
"""Show Python-specific CLI examples."""
320+
examples_text = """Generate dataclass:
321+
[cyan]json_explorer data.json --generate python --python-style dataclass[/cyan]
298322
299-
# Add examples panel
300-
examples_text = f"""Generate basic structure:
301-
[cyan]json_explorer data.json --generate {language}[/cyan]
323+
Generate Pydantic model:
324+
[cyan]json_explorer data.json --generate python --python-style pydantic[/cyan]
302325
303-
Generate to file:
304-
[cyan]json_explorer data.json --generate {language} --output output{info['file_extension']}[/cyan]
326+
Generate TypedDict:
327+
[cyan]json_explorer data.json --generate python --python-style typeddict[/cyan]
305328
306-
Custom package name:
307-
[cyan]json_explorer data.json --generate {language} --package-name mypackage[/cyan]"""
329+
Frozen dataclass with slots:
330+
[cyan]json_explorer data.json --generate python --frozen --python-style dataclass[/cyan]"""
308331

309-
console.print()
310-
console.print(
311-
Panel(examples_text, title="💡 Usage Examples", border_style="blue")
312-
)
332+
console.print()
333+
console.print(
334+
Panel(examples_text, title="💡 Python Usage Examples", border_style="blue")
335+
)
313336

314-
return 0
315337

316-
except Exception as e:
317-
console.print(f"[red]❌ Error getting language info:[/red] {e}")
318-
return 1
338+
def _show_go_examples():
339+
"""Show Go-specific CLI examples."""
340+
examples_text = """Generate basic structure:
341+
[cyan]json_explorer data.json --generate go[/cyan]
342+
343+
Generate to file:
344+
[cyan]json_explorer data.json --generate go --output output.go[/cyan]
345+
346+
Custom package name:
347+
[cyan]json_explorer data.json --generate go --package-name mypackage[/cyan]"""
348+
349+
console.print()
350+
console.print(
351+
Panel(examples_text, title="💡 Go Usage Examples", border_style="blue")
352+
)
319353

320354

321355
def _validate_language(language: str, silent: bool = False) -> bool:
@@ -390,6 +424,25 @@ def _build_config(args: argparse.Namespace, language: str) -> GeneratorConfig:
390424
if hasattr(args, "json_tag_case") and args.json_tag_case:
391425
config_dict["json_tag_case"] = args.json_tag_case
392426

427+
elif language.lower() in ["python", "py"]:
428+
if hasattr(args, "python_style") and args.python_style:
429+
config_dict["style"] = args.python_style
430+
431+
if hasattr(args, "no_slots") and args.no_slots:
432+
config_dict["dataclass_slots"] = False
433+
434+
if hasattr(args, "frozen") and args.frozen:
435+
config_dict["dataclass_frozen"] = True
436+
437+
if hasattr(args, "kw_only") and args.kw_only:
438+
config_dict["dataclass_kw_only"] = True
439+
440+
if hasattr(args, "no_pydantic_field") and args.no_pydantic_field:
441+
config_dict["pydantic_use_field"] = False
442+
443+
if hasattr(args, "pydantic_forbid_extra") and args.pydantic_forbid_extra:
444+
config_dict["pydantic_extra_forbid"] = True
445+
393446
return load_config(custom_config=config_dict)
394447

395448

@@ -474,6 +527,8 @@ def _display_generated_code(code: str, language: str):
474527
syntax_lang = language.lower()
475528
if syntax_lang == "golang":
476529
syntax_lang = "go"
530+
elif syntax_lang == "py":
531+
syntax_lang = "python"
477532

478533
syntax = Syntax(code, syntax_lang, theme="monokai", padding=1)
479534
console.print(syntax)

json_explorer/codegen/interactive.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -553,9 +553,9 @@ def _show_language_usage_examples(self):
553553
554554
[bold]Currently Available:[/bold]
555555
• Go - Structs with JSON tags, configurable types and pointers
556+
• Python - Dataclasses, Pydantic, and Typeddict models
556557
557558
[bold]Coming Soon:[/bold]
558-
• Python - Dataclasses and Pydantic models
559559
• TypeScript - Interfaces and types
560560
• Rust - Structs with Serde
561561
• Java - POJOs with annotations

json_explorer/codegen/languages/__init__.py

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,42 @@
2424
"create_strict_generator",
2525
]
2626
)
27-
except ImportError:
27+
except ImportError as e:
28+
# Go generator not available
2829
pass
30+
except Exception as e:
31+
# Other errors during import
32+
import sys
33+
34+
print(f"Warning: Failed to import Go generator: {e}", file=sys.stderr)
35+
36+
# Python generators
37+
try:
38+
from .python import (
39+
PythonGenerator,
40+
create_python_generator,
41+
create_dataclass_generator,
42+
create_pydantic_generator,
43+
create_typeddict_generator,
44+
)
45+
46+
__all__.extend(
47+
[
48+
"PythonGenerator",
49+
"create_python_generator",
50+
"create_dataclass_generator",
51+
"create_pydantic_generator",
52+
"create_typeddict_generator",
53+
]
54+
)
55+
except ImportError as e:
56+
# Python generator not available - this is expected if not installed yet
57+
pass
58+
except Exception as e:
59+
# Other errors during import
60+
import sys
61+
62+
print(f"Warning: Failed to import Python generator: {e}", file=sys.stderr)
2963

3064
# Add more languages here as they are implemented
3165
# try:
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
"""
2+
Python code generator module.
3+
4+
Generates Python dataclasses, Pydantic models, and TypedDict from JSON schema analysis.
5+
"""
6+
7+
from .generator import (
8+
PythonGenerator,
9+
create_python_generator,
10+
create_dataclass_generator,
11+
create_pydantic_generator,
12+
create_typeddict_generator,
13+
)
14+
from .naming import create_python_sanitizer
15+
from .config import (
16+
PythonConfig,
17+
PythonStyle,
18+
get_python_reserved_words,
19+
get_python_builtin_types,
20+
get_dataclass_config,
21+
get_pydantic_config,
22+
get_typeddict_config,
23+
get_strict_dataclass_config,
24+
)
25+
from .interactive import PythonInteractiveHandler
26+
27+
__all__ = [
28+
# Generator
29+
"PythonGenerator",
30+
"create_python_generator",
31+
"create_dataclass_generator",
32+
"create_pydantic_generator",
33+
"create_typeddict_generator",
34+
# Naming
35+
"create_python_sanitizer",
36+
# Configuration
37+
"PythonConfig",
38+
"PythonStyle",
39+
"get_python_reserved_words",
40+
"get_python_builtin_types",
41+
"get_dataclass_config",
42+
"get_pydantic_config",
43+
"get_typeddict_config",
44+
"get_strict_dataclass_config",
45+
# Interactive
46+
"PythonInteractiveHandler",
47+
]

0 commit comments

Comments
 (0)