the-grid-cc 1.3.0 → 1.5.0

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.
@@ -0,0 +1,206 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ JSON/YAML Converter CLI
4
+
5
+ Converts between JSON and YAML formats with support for nested structures.
6
+
7
+ Usage:
8
+ converter.py <input_file> --to yaml|json [-o output_file] [--indent N]
9
+ converter.py <input_file> -t yaml|json [-o output_file] [--indent N]
10
+
11
+ Examples:
12
+ converter.py config.json --to yaml
13
+ converter.py data.yaml --to json -o output.json
14
+ converter.py nested.json -t yaml --indent 4
15
+ """
16
+
17
+ import argparse
18
+ import json
19
+ import sys
20
+ from pathlib import Path
21
+
22
+ try:
23
+ import yaml
24
+ except ImportError:
25
+ print("Error: PyYAML is required. Install with: pip install pyyaml", file=sys.stderr)
26
+ sys.exit(1)
27
+
28
+
29
+ def detect_format(file_path: Path) -> str:
30
+ """Detect file format from extension."""
31
+ suffix = file_path.suffix.lower()
32
+ if suffix in ('.json',):
33
+ return 'json'
34
+ elif suffix in ('.yaml', '.yml'):
35
+ return 'yaml'
36
+ else:
37
+ return 'unknown'
38
+
39
+
40
+ def load_json(file_path: Path) -> dict:
41
+ """Load and parse JSON file."""
42
+ try:
43
+ with open(file_path, 'r', encoding='utf-8') as f:
44
+ return json.load(f)
45
+ except json.JSONDecodeError as e:
46
+ raise ValueError(f"Invalid JSON: {e.msg} at line {e.lineno}, column {e.colno}")
47
+ except FileNotFoundError:
48
+ raise FileNotFoundError(f"File not found: {file_path}")
49
+ except PermissionError:
50
+ raise PermissionError(f"Permission denied: {file_path}")
51
+
52
+
53
+ def load_yaml(file_path: Path) -> dict:
54
+ """Load and parse YAML file."""
55
+ try:
56
+ with open(file_path, 'r', encoding='utf-8') as f:
57
+ return yaml.safe_load(f)
58
+ except yaml.YAMLError as e:
59
+ if hasattr(e, 'problem_mark'):
60
+ mark = e.problem_mark
61
+ raise ValueError(f"Invalid YAML at line {mark.line + 1}, column {mark.column + 1}: {e.problem}")
62
+ raise ValueError(f"Invalid YAML: {e}")
63
+ except FileNotFoundError:
64
+ raise FileNotFoundError(f"File not found: {file_path}")
65
+ except PermissionError:
66
+ raise PermissionError(f"Permission denied: {file_path}")
67
+
68
+
69
+ def to_json(data: dict, indent: int = 2) -> str:
70
+ """Convert data to pretty-printed JSON string."""
71
+ return json.dumps(data, indent=indent, ensure_ascii=False, sort_keys=False)
72
+
73
+
74
+ def to_yaml(data: dict, indent: int = 2) -> str:
75
+ """Convert data to pretty-printed YAML string."""
76
+ return yaml.dump(
77
+ data,
78
+ default_flow_style=False,
79
+ allow_unicode=True,
80
+ indent=indent,
81
+ sort_keys=False,
82
+ width=120
83
+ )
84
+
85
+
86
+ def convert(input_path: Path, output_format: str, indent: int = 2) -> str:
87
+ """
88
+ Convert file between JSON and YAML formats.
89
+
90
+ Args:
91
+ input_path: Path to input file
92
+ output_format: Target format ('json' or 'yaml')
93
+ indent: Indentation level for pretty printing
94
+
95
+ Returns:
96
+ Converted content as string
97
+ """
98
+ input_format = detect_format(input_path)
99
+
100
+ # Load input file
101
+ if input_format == 'json':
102
+ data = load_json(input_path)
103
+ elif input_format == 'yaml':
104
+ data = load_yaml(input_path)
105
+ else:
106
+ # Try JSON first, then YAML
107
+ try:
108
+ data = load_json(input_path)
109
+ input_format = 'json'
110
+ except ValueError:
111
+ try:
112
+ data = load_yaml(input_path)
113
+ input_format = 'yaml'
114
+ except ValueError as e:
115
+ raise ValueError(f"Could not parse file as JSON or YAML: {e}")
116
+
117
+ # Handle None/empty content
118
+ if data is None:
119
+ data = {}
120
+
121
+ # Convert to output format
122
+ if output_format == 'json':
123
+ return to_json(data, indent)
124
+ elif output_format == 'yaml':
125
+ return to_yaml(data, indent)
126
+ else:
127
+ raise ValueError(f"Unknown output format: {output_format}")
128
+
129
+
130
+ def main():
131
+ parser = argparse.ArgumentParser(
132
+ description='Convert between JSON and YAML formats',
133
+ formatter_class=argparse.RawDescriptionHelpFormatter,
134
+ epilog="""
135
+ Examples:
136
+ %(prog)s config.json --to yaml Convert JSON to YAML (stdout)
137
+ %(prog)s data.yaml --to json -o out.json Convert YAML to JSON file
138
+ %(prog)s nested.json -t yaml --indent 4 Convert with 4-space indent
139
+ """
140
+ )
141
+
142
+ parser.add_argument(
143
+ 'input',
144
+ type=Path,
145
+ help='Input file (JSON or YAML)'
146
+ )
147
+
148
+ parser.add_argument(
149
+ '-t', '--to',
150
+ choices=['json', 'yaml'],
151
+ required=True,
152
+ dest='format',
153
+ help='Output format (json or yaml)'
154
+ )
155
+
156
+ parser.add_argument(
157
+ '-o', '--output',
158
+ type=Path,
159
+ help='Output file (defaults to stdout)'
160
+ )
161
+
162
+ parser.add_argument(
163
+ '--indent',
164
+ type=int,
165
+ default=2,
166
+ help='Indentation level (default: 2)'
167
+ )
168
+
169
+ args = parser.parse_args()
170
+
171
+ # Validate input file exists
172
+ if not args.input.exists():
173
+ print(f"Error: Input file not found: {args.input}", file=sys.stderr)
174
+ sys.exit(1)
175
+
176
+ if not args.input.is_file():
177
+ print(f"Error: Not a file: {args.input}", file=sys.stderr)
178
+ sys.exit(1)
179
+
180
+ # Validate indent
181
+ if args.indent < 0:
182
+ print("Error: Indent must be non-negative", file=sys.stderr)
183
+ sys.exit(1)
184
+
185
+ try:
186
+ # Perform conversion
187
+ result = convert(args.input, args.format, args.indent)
188
+
189
+ # Output result
190
+ if args.output:
191
+ with open(args.output, 'w', encoding='utf-8') as f:
192
+ f.write(result)
193
+ print(f"Converted: {args.input} -> {args.output}", file=sys.stderr)
194
+ else:
195
+ print(result)
196
+
197
+ except (ValueError, FileNotFoundError, PermissionError) as e:
198
+ print(f"Error: {e}", file=sys.stderr)
199
+ sys.exit(1)
200
+ except Exception as e:
201
+ print(f"Unexpected error: {e}", file=sys.stderr)
202
+ sys.exit(1)
203
+
204
+
205
+ if __name__ == '__main__':
206
+ main()
@@ -0,0 +1,39 @@
1
+ {
2
+ "name": "Grid Test Project",
3
+ "version": "1.0.0",
4
+ "config": {
5
+ "database": {
6
+ "host": "localhost",
7
+ "port": 5432,
8
+ "credentials": {
9
+ "username": "admin",
10
+ "password": "secret"
11
+ }
12
+ },
13
+ "features": {
14
+ "auth": true,
15
+ "logging": true,
16
+ "cache": {
17
+ "enabled": true,
18
+ "ttl": 3600
19
+ }
20
+ }
21
+ },
22
+ "servers": [
23
+ {
24
+ "name": "primary",
25
+ "host": "192.168.1.1",
26
+ "ports": [80, 443, 8080]
27
+ },
28
+ {
29
+ "name": "backup",
30
+ "host": "192.168.1.2",
31
+ "ports": [80, 443]
32
+ }
33
+ ],
34
+ "metadata": {
35
+ "created": "2024-01-23",
36
+ "tags": ["production", "critical", "monitored"],
37
+ "notes": null
38
+ }
39
+ }
@@ -0,0 +1,35 @@
1
+ application:
2
+ name: YAML Test App
3
+ environment: production
4
+
5
+ services:
6
+ api:
7
+ enabled: true
8
+ endpoints:
9
+ - path: /users
10
+ methods:
11
+ - GET
12
+ - POST
13
+ - path: /orders
14
+ methods:
15
+ - GET
16
+ - POST
17
+ - DELETE
18
+
19
+ worker:
20
+ enabled: true
21
+ concurrency: 4
22
+ queues:
23
+ - name: high_priority
24
+ weight: 10
25
+ - name: default
26
+ weight: 5
27
+
28
+ settings:
29
+ debug: false
30
+ timeout: 30
31
+ retries: 3
32
+ nested:
33
+ deeply:
34
+ structured:
35
+ value: "found it"