python-infrakit-dev 0.1.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 (51) hide show
  1. infrakit/__init__.py +0 -0
  2. infrakit/cli/__init__.py +1 -0
  3. infrakit/cli/commands/__init__.py +1 -0
  4. infrakit/cli/commands/deps.py +530 -0
  5. infrakit/cli/commands/init.py +129 -0
  6. infrakit/cli/commands/llm.py +295 -0
  7. infrakit/cli/commands/logger.py +160 -0
  8. infrakit/cli/commands/module.py +342 -0
  9. infrakit/cli/commands/time.py +81 -0
  10. infrakit/cli/main.py +65 -0
  11. infrakit/core/__init__.py +0 -0
  12. infrakit/core/config/__init__.py +0 -0
  13. infrakit/core/config/converter.py +480 -0
  14. infrakit/core/config/exporter.py +304 -0
  15. infrakit/core/config/loader.py +713 -0
  16. infrakit/core/config/validator.py +389 -0
  17. infrakit/core/logger/__init__.py +21 -0
  18. infrakit/core/logger/formatters.py +143 -0
  19. infrakit/core/logger/handlers.py +322 -0
  20. infrakit/core/logger/retention.py +176 -0
  21. infrakit/core/logger/setup.py +314 -0
  22. infrakit/deps/__init__.py +239 -0
  23. infrakit/deps/clean.py +141 -0
  24. infrakit/deps/depfile.py +405 -0
  25. infrakit/deps/health.py +357 -0
  26. infrakit/deps/optimizer.py +642 -0
  27. infrakit/deps/scanner.py +550 -0
  28. infrakit/llm/__init__.py +35 -0
  29. infrakit/llm/batch.py +165 -0
  30. infrakit/llm/client.py +575 -0
  31. infrakit/llm/key_manager.py +728 -0
  32. infrakit/llm/llm_readme.md +306 -0
  33. infrakit/llm/models.py +148 -0
  34. infrakit/llm/providers/__init__.py +5 -0
  35. infrakit/llm/providers/base.py +112 -0
  36. infrakit/llm/providers/gemini.py +164 -0
  37. infrakit/llm/providers/openai.py +168 -0
  38. infrakit/llm/rate_limiter.py +54 -0
  39. infrakit/scaffolder/__init__.py +31 -0
  40. infrakit/scaffolder/ai.py +508 -0
  41. infrakit/scaffolder/backend.py +555 -0
  42. infrakit/scaffolder/cli_tool.py +386 -0
  43. infrakit/scaffolder/generator.py +338 -0
  44. infrakit/scaffolder/pipeline.py +562 -0
  45. infrakit/scaffolder/registry.py +121 -0
  46. infrakit/time/__init__.py +60 -0
  47. infrakit/time/profiler.py +511 -0
  48. python_infrakit_dev-0.1.0.dist-info/METADATA +124 -0
  49. python_infrakit_dev-0.1.0.dist-info/RECORD +51 -0
  50. python_infrakit_dev-0.1.0.dist-info/WHEEL +4 -0
  51. python_infrakit_dev-0.1.0.dist-info/entry_points.txt +3 -0
@@ -0,0 +1,304 @@
1
+ """
2
+ infrakit.core.config.exporter
3
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4
+ Export a config file or dict with all values replaced by YOUR_VALUE_HERE —
5
+ safe to share without leaking real credentials.
6
+
7
+ The output format is always an explicit input — nothing is inferred.
8
+
9
+ Output style:
10
+ DATABASE_URL=YOUR_VALUE_HERE
11
+ PORT=YOUR_VALUE_HERE
12
+ DEBUG=YOUR_VALUE_HERE
13
+
14
+ Usage:
15
+ from infrakit.core.config.exporter import export_file, export_dict, export_string
16
+
17
+ # File -> sanitized file, choose output format explicitly
18
+ export_file("config.yaml", ".env.example", to_format="env")
19
+ export_file(".env", "config.example.yaml", to_format="yaml")
20
+
21
+ # Dict -> sanitized string
22
+ result = export_dict({"PORT": 8080, "DEBUG": True}, to_format="env")
23
+ print(result)
24
+
25
+ # Raw string -> sanitized string
26
+ result = export_string(raw_env_text, from_format="env", to_format="ini")
27
+ """
28
+
29
+ from __future__ import annotations
30
+
31
+ import json
32
+ from configparser import ConfigParser
33
+ from pathlib import Path
34
+ from typing import Any
35
+
36
+ try:
37
+ import yaml
38
+ _YAML_AVAILABLE = True
39
+ except ImportError:
40
+ _YAML_AVAILABLE = False
41
+
42
+
43
+ # ---------------------------------------------------------------------------
44
+ # Public types
45
+ # ---------------------------------------------------------------------------
46
+
47
+ ConfigDict = dict[str, Any]
48
+ Format = str # "json" | "yaml" | "ini" | "env"
49
+
50
+ SUPPORTED_FORMATS = {"json", "yaml", "ini", "env"}
51
+
52
+ PLACEHOLDER = "YOUR_VALUE_HERE"
53
+
54
+ _EXT_TO_FORMAT: dict[str, Format] = {
55
+ ".json": "json",
56
+ ".yaml": "yaml",
57
+ ".yml": "yaml",
58
+ ".ini": "ini",
59
+ ".cfg": "ini",
60
+ ".env": "env",
61
+ }
62
+
63
+
64
+ # ---------------------------------------------------------------------------
65
+ # Public API
66
+ # ---------------------------------------------------------------------------
67
+
68
+ def export_file(
69
+ source: str | Path,
70
+ target: str | Path,
71
+ *,
72
+ to_format: Format,
73
+ overwrite: bool = False,
74
+ ) -> None:
75
+ """Read *source*, replace all values with YOUR_VALUE_HERE, write to *target*.
76
+
77
+ Parameters
78
+ ----------
79
+ source:
80
+ Path to the real config file (e.g. ``.env``, ``config.yaml``).
81
+ target:
82
+ Path to write the sanitized output (e.g. ``.env.example``).
83
+ to_format:
84
+ Output format — one of ``"env"``, ``"ini"``, ``"json"``, ``"yaml"``.
85
+ Always required; never inferred from the filename.
86
+ overwrite:
87
+ If False (default), raises :exc:`FileExistsError` when *target* exists.
88
+
89
+ Raises
90
+ ------
91
+ FileNotFoundError
92
+ If *source* does not exist.
93
+ FileExistsError
94
+ If *target* exists and *overwrite* is False.
95
+ ValueError
96
+ If *to_format* is not a supported format.
97
+ """
98
+ source = Path(source)
99
+ target = Path(target)
100
+
101
+ if not source.exists():
102
+ raise FileNotFoundError(f"Source config not found: '{source}'")
103
+ if target.exists() and not overwrite:
104
+ raise FileExistsError(
105
+ f"Target '{target}' already exists. Pass overwrite=True to replace."
106
+ )
107
+
108
+ _validate_format(to_format)
109
+ from_fmt = _infer_format(source)
110
+
111
+ raw = source.read_text(encoding="utf-8")
112
+ data = _parse(raw, from_fmt)
113
+ output = export_dict(data, to_format=to_format)
114
+
115
+ target.parent.mkdir(parents=True, exist_ok=True)
116
+ target.write_text(output, encoding="utf-8")
117
+
118
+
119
+ def export_string(
120
+ raw: str,
121
+ *,
122
+ from_format: Format,
123
+ to_format: Format,
124
+ ) -> str:
125
+ """Parse *raw* as *from_format*, sanitize all values, return as *to_format*.
126
+
127
+ Parameters
128
+ ----------
129
+ raw:
130
+ The raw config string to sanitize.
131
+ from_format:
132
+ Format of *raw* — one of ``"env"``, ``"ini"``, ``"json"``, ``"yaml"``.
133
+ to_format:
134
+ Desired output format — one of ``"env"``, ``"ini"``, ``"json"``, ``"yaml"``.
135
+
136
+ Returns
137
+ -------
138
+ str
139
+ Sanitized config string in *to_format*.
140
+ """
141
+ _validate_format(from_format)
142
+ _validate_format(to_format)
143
+ data = _parse(raw, from_format)
144
+ return export_dict(data, to_format=to_format)
145
+
146
+
147
+ def export_dict(data: ConfigDict, *, to_format: Format) -> str:
148
+ """Sanitize *data* and serialize to *to_format*.
149
+
150
+ All values — at every nesting level — are replaced with YOUR_VALUE_HERE.
151
+ Keys and structure are preserved exactly.
152
+
153
+ Parameters
154
+ ----------
155
+ data:
156
+ A config dict, as returned by the loader.
157
+ to_format:
158
+ Output format — one of ``"env"``, ``"ini"``, ``"json"``, ``"yaml"``.
159
+
160
+ Returns
161
+ -------
162
+ str
163
+ The sanitized, serialized config string.
164
+
165
+ Raises
166
+ ------
167
+ ValueError
168
+ If *to_format* is not supported.
169
+ """
170
+ _validate_format(to_format)
171
+ if to_format == "env":
172
+ return _export_as_env(data)
173
+ if to_format == "ini":
174
+ return _export_as_ini(data)
175
+ if to_format == "json":
176
+ return _export_as_json(data)
177
+ if to_format == "yaml":
178
+ return _export_as_yaml(data)
179
+
180
+
181
+ # ---------------------------------------------------------------------------
182
+ # Format serializers
183
+ # ---------------------------------------------------------------------------
184
+
185
+ def _export_as_env(data: ConfigDict) -> str:
186
+ lines: list[str] = []
187
+
188
+ def _add(key: str) -> None:
189
+ lines.append(f"{key}={PLACEHOLDER}")
190
+
191
+ for k, v in data.items():
192
+ if isinstance(v, dict):
193
+ lines.append(f"\n# [{k}]")
194
+ for nested_k in v:
195
+ _add(f"{k.upper()}__{nested_k.upper()}")
196
+ else:
197
+ _add(k)
198
+
199
+ return "\n".join(lines) + "\n"
200
+
201
+
202
+ def _export_as_ini(data: ConfigDict) -> str:
203
+ lines: list[str] = []
204
+
205
+ for k, v in data.items():
206
+ if isinstance(v, dict):
207
+ lines.append(f"[{k}]")
208
+ for nested_k in v:
209
+ lines.append(f"{nested_k} = {PLACEHOLDER}")
210
+ lines.append("")
211
+ else:
212
+ lines.append(f"{k} = {PLACEHOLDER}")
213
+
214
+ return "\n".join(lines).rstrip() + "\n"
215
+
216
+
217
+ def _export_as_json(data: ConfigDict) -> str:
218
+ return json.dumps(_sanitize_dict(data), indent=2) + "\n"
219
+
220
+
221
+ def _export_as_yaml(data: ConfigDict) -> str:
222
+ if not _YAML_AVAILABLE:
223
+ raise ValueError("PyYAML is required for YAML export. pip install pyyaml")
224
+ header = "# generated by infrakit exporter — safe to share\n"
225
+ return header + yaml.dump(
226
+ _sanitize_dict(data),
227
+ default_flow_style=False,
228
+ allow_unicode=True,
229
+ sort_keys=False,
230
+ )
231
+
232
+
233
+ def _sanitize_dict(data: ConfigDict) -> ConfigDict:
234
+ """Recursively replace every leaf value with PLACEHOLDER."""
235
+ result: ConfigDict = {}
236
+ for k, v in data.items():
237
+ if isinstance(v, dict):
238
+ result[k] = _sanitize_dict(v)
239
+ else:
240
+ result[k] = PLACEHOLDER
241
+ return result
242
+
243
+
244
+ # ---------------------------------------------------------------------------
245
+ # Internal helpers
246
+ # ---------------------------------------------------------------------------
247
+
248
+ def _validate_format(fmt: Format) -> None:
249
+ if fmt not in SUPPORTED_FORMATS:
250
+ raise ValueError(
251
+ f"Unsupported format '{fmt}'. "
252
+ f"Choose one of: {', '.join(sorted(SUPPORTED_FORMATS))}"
253
+ )
254
+
255
+
256
+ def _infer_format(path: Path) -> Format:
257
+ """Infer format from file extension, handling dotfiles like .env."""
258
+ suffix = path.suffix.lower()
259
+ if not suffix:
260
+ name = path.name.lower()
261
+ if name.startswith(".") and "." not in name[1:]:
262
+ suffix = name
263
+ fmt = _EXT_TO_FORMAT.get(suffix)
264
+ if fmt is None:
265
+ raise ValueError(
266
+ f"Cannot infer format from '{path.name}'. "
267
+ f"Supported extensions: {', '.join(sorted(_EXT_TO_FORMAT))}"
268
+ )
269
+ return fmt
270
+
271
+
272
+ def _parse(raw: str, fmt: Format) -> ConfigDict:
273
+ if fmt == "json":
274
+ data = json.loads(raw)
275
+ return data if isinstance(data, dict) else {}
276
+ if fmt == "yaml":
277
+ if not _YAML_AVAILABLE:
278
+ raise ValueError("PyYAML required. pip install pyyaml")
279
+ return yaml.safe_load(raw) or {}
280
+ if fmt == "ini":
281
+ parser = ConfigParser()
282
+ parser.read_string(raw)
283
+ result: ConfigDict = {}
284
+ if parser.defaults():
285
+ result["DEFAULT"] = dict(parser.defaults())
286
+ for section in parser.sections():
287
+ result[section] = {
288
+ k: parser.get(section, k)
289
+ for k in parser.options(section)
290
+ if k not in parser.defaults()
291
+ }
292
+ return result
293
+ if fmt == "env":
294
+ result = {}
295
+ for line in raw.splitlines():
296
+ line = line.strip()
297
+ if not line or line.startswith("#"):
298
+ continue
299
+ if "=" not in line:
300
+ continue
301
+ key, _, value = line.partition("=")
302
+ result[key.strip()] = value.strip().strip('"').strip("'")
303
+ return result
304
+ raise ValueError(f"Unknown format '{fmt}'")