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.
- infrakit/__init__.py +0 -0
- infrakit/cli/__init__.py +1 -0
- infrakit/cli/commands/__init__.py +1 -0
- infrakit/cli/commands/deps.py +530 -0
- infrakit/cli/commands/init.py +129 -0
- infrakit/cli/commands/llm.py +295 -0
- infrakit/cli/commands/logger.py +160 -0
- infrakit/cli/commands/module.py +342 -0
- infrakit/cli/commands/time.py +81 -0
- infrakit/cli/main.py +65 -0
- infrakit/core/__init__.py +0 -0
- infrakit/core/config/__init__.py +0 -0
- infrakit/core/config/converter.py +480 -0
- infrakit/core/config/exporter.py +304 -0
- infrakit/core/config/loader.py +713 -0
- infrakit/core/config/validator.py +389 -0
- infrakit/core/logger/__init__.py +21 -0
- infrakit/core/logger/formatters.py +143 -0
- infrakit/core/logger/handlers.py +322 -0
- infrakit/core/logger/retention.py +176 -0
- infrakit/core/logger/setup.py +314 -0
- infrakit/deps/__init__.py +239 -0
- infrakit/deps/clean.py +141 -0
- infrakit/deps/depfile.py +405 -0
- infrakit/deps/health.py +357 -0
- infrakit/deps/optimizer.py +642 -0
- infrakit/deps/scanner.py +550 -0
- infrakit/llm/__init__.py +35 -0
- infrakit/llm/batch.py +165 -0
- infrakit/llm/client.py +575 -0
- infrakit/llm/key_manager.py +728 -0
- infrakit/llm/llm_readme.md +306 -0
- infrakit/llm/models.py +148 -0
- infrakit/llm/providers/__init__.py +5 -0
- infrakit/llm/providers/base.py +112 -0
- infrakit/llm/providers/gemini.py +164 -0
- infrakit/llm/providers/openai.py +168 -0
- infrakit/llm/rate_limiter.py +54 -0
- infrakit/scaffolder/__init__.py +31 -0
- infrakit/scaffolder/ai.py +508 -0
- infrakit/scaffolder/backend.py +555 -0
- infrakit/scaffolder/cli_tool.py +386 -0
- infrakit/scaffolder/generator.py +338 -0
- infrakit/scaffolder/pipeline.py +562 -0
- infrakit/scaffolder/registry.py +121 -0
- infrakit/time/__init__.py +60 -0
- infrakit/time/profiler.py +511 -0
- python_infrakit_dev-0.1.0.dist-info/METADATA +124 -0
- python_infrakit_dev-0.1.0.dist-info/RECORD +51 -0
- python_infrakit_dev-0.1.0.dist-info/WHEEL +4 -0
- python_infrakit_dev-0.1.0.dist-info/entry_points.txt +3 -0
|
@@ -0,0 +1,338 @@
|
|
|
1
|
+
"""
|
|
2
|
+
infrakit.scaffolder.generator
|
|
3
|
+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
4
|
+
Core scaffolding logic for the ``basic`` project template.
|
|
5
|
+
|
|
6
|
+
Idempotent — any file or directory that already exists is left untouched.
|
|
7
|
+
Every action (created / skipped) is reported back to the caller via
|
|
8
|
+
``ScaffoldResult`` so the CLI can render it however it likes.
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
from __future__ import annotations
|
|
12
|
+
|
|
13
|
+
from dataclasses import dataclass, field
|
|
14
|
+
from pathlib import Path
|
|
15
|
+
from typing import Literal
|
|
16
|
+
|
|
17
|
+
# ── types ─────────────────────────────────────────────────────────────────────
|
|
18
|
+
|
|
19
|
+
Status = Literal["created", "skipped"]
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
@dataclass
|
|
23
|
+
class ScaffoldEntry:
|
|
24
|
+
path: Path
|
|
25
|
+
status: Status
|
|
26
|
+
kind: Literal["file", "dir"]
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
@dataclass
|
|
30
|
+
class ScaffoldResult:
|
|
31
|
+
project_dir: Path
|
|
32
|
+
entries: list[ScaffoldEntry] = field(default_factory=list)
|
|
33
|
+
|
|
34
|
+
# convenience views
|
|
35
|
+
@property
|
|
36
|
+
def created(self) -> list[ScaffoldEntry]:
|
|
37
|
+
return [e for e in self.entries if e.status == "created"]
|
|
38
|
+
|
|
39
|
+
@property
|
|
40
|
+
def skipped(self) -> list[ScaffoldEntry]:
|
|
41
|
+
return [e for e in self.entries if e.status == "skipped"]
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
# ── helpers ───────────────────────────────────────────────────────────────────
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def _write(result: ScaffoldResult, path: Path, content: str) -> None:
|
|
48
|
+
"""Write a file only if it doesn't exist yet; record the outcome."""
|
|
49
|
+
if path.exists():
|
|
50
|
+
result.entries.append(ScaffoldEntry(path=path, status="skipped", kind="file"))
|
|
51
|
+
return
|
|
52
|
+
path.parent.mkdir(parents=True, exist_ok=True)
|
|
53
|
+
path.write_text(content, encoding="utf-8")
|
|
54
|
+
result.entries.append(ScaffoldEntry(path=path, status="created", kind="file"))
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def _mkdir(result: ScaffoldResult, path: Path) -> None:
|
|
58
|
+
"""Create a directory only if it doesn't exist yet; record the outcome."""
|
|
59
|
+
if path.exists():
|
|
60
|
+
result.entries.append(ScaffoldEntry(path=path, status="skipped", kind="dir"))
|
|
61
|
+
return
|
|
62
|
+
path.mkdir(parents=True, exist_ok=True)
|
|
63
|
+
result.entries.append(ScaffoldEntry(path=path, status="created", kind="dir"))
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
# ── template content ──────────────────────────────────────────────────────────
|
|
67
|
+
|
|
68
|
+
def _pyproject_toml(
|
|
69
|
+
project_name: str,
|
|
70
|
+
version: str,
|
|
71
|
+
description: str,
|
|
72
|
+
author: str,
|
|
73
|
+
) -> str:
|
|
74
|
+
author_line = f' "{author}",' if author else ' # "Your Name <you@example.com>",'
|
|
75
|
+
return f"""\
|
|
76
|
+
[project]
|
|
77
|
+
name = "{project_name}"
|
|
78
|
+
version = "{version}"
|
|
79
|
+
description = "{description}"
|
|
80
|
+
readme = "README.md"
|
|
81
|
+
requires-python = ">=3.10"
|
|
82
|
+
authors = [
|
|
83
|
+
{author_line}
|
|
84
|
+
]
|
|
85
|
+
|
|
86
|
+
dependencies = [
|
|
87
|
+
"infrakit",
|
|
88
|
+
]
|
|
89
|
+
|
|
90
|
+
[project.optional-dependencies]
|
|
91
|
+
dev = [
|
|
92
|
+
"pytest",
|
|
93
|
+
"pytest-cov",
|
|
94
|
+
]
|
|
95
|
+
"""
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
def _requirements_txt(project_name: str) -> str:
|
|
99
|
+
return f"""\
|
|
100
|
+
# requirements.txt — {project_name}
|
|
101
|
+
# Add your dependencies below.
|
|
102
|
+
infrakit
|
|
103
|
+
"""
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
def _env_config() -> str:
|
|
107
|
+
return """\
|
|
108
|
+
# Application configuration
|
|
109
|
+
# Copy this file to .env and fill in the values.
|
|
110
|
+
APP_ENV=development
|
|
111
|
+
APP_DEBUG=false
|
|
112
|
+
APP_SECRET=YOUR_VALUE_HERE
|
|
113
|
+
"""
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
def _yaml_config() -> str:
|
|
117
|
+
return """\
|
|
118
|
+
# Application configuration
|
|
119
|
+
app:
|
|
120
|
+
env: development
|
|
121
|
+
debug: false
|
|
122
|
+
secret: YOUR_VALUE_HERE
|
|
123
|
+
"""
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
def _json_config() -> str:
|
|
127
|
+
return """\
|
|
128
|
+
{
|
|
129
|
+
"app": {
|
|
130
|
+
"env": "development",
|
|
131
|
+
"debug": false,
|
|
132
|
+
"secret": "YOUR_VALUE_HERE"
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
"""
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
def _config_content(fmt: str) -> tuple[str, str]:
|
|
139
|
+
"""Return (filename, content) for the chosen config format."""
|
|
140
|
+
if fmt == "yaml":
|
|
141
|
+
return "config.yaml", _yaml_config()
|
|
142
|
+
if fmt == "json":
|
|
143
|
+
return "config.json", _json_config()
|
|
144
|
+
return ".env", _env_config() # default
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
def _logger_util() -> str:
|
|
148
|
+
return """\
|
|
149
|
+
\"\"\"
|
|
150
|
+
utils.logger
|
|
151
|
+
~~~~~~~~~~~~
|
|
152
|
+
Thin wrapper that boots the infrakit logger once and exports ``get_logger``.
|
|
153
|
+
|
|
154
|
+
Usage
|
|
155
|
+
-----
|
|
156
|
+
from utils.logger import get_logger
|
|
157
|
+
|
|
158
|
+
log = get_logger(__name__)
|
|
159
|
+
log.info("hello")
|
|
160
|
+
\"\"\"
|
|
161
|
+
|
|
162
|
+
import os
|
|
163
|
+
from infrakit.core.logger import setup, get_logger # re-export get_logger
|
|
164
|
+
|
|
165
|
+
_booted = False
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
def _boot() -> None:
|
|
169
|
+
global _booted
|
|
170
|
+
if _booted:
|
|
171
|
+
return
|
|
172
|
+
setup(
|
|
173
|
+
log_dir=os.getenv("LOG_DIR", "logs"),
|
|
174
|
+
strategy=os.getenv("LOG_STRATEGY", "date"),
|
|
175
|
+
stream=os.getenv("LOG_STREAM", "stdout"),
|
|
176
|
+
fmt=os.getenv("LOG_FORMAT", "human"),
|
|
177
|
+
level=os.getenv("LOG_LEVEL", "DEBUG"),
|
|
178
|
+
)
|
|
179
|
+
_booted = True
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
_boot()
|
|
183
|
+
|
|
184
|
+
__all__ = ["get_logger"]
|
|
185
|
+
"""
|
|
186
|
+
|
|
187
|
+
|
|
188
|
+
def _readme(project_name: str, description: str) -> str:
|
|
189
|
+
title = project_name.replace("-", " ").replace("_", " ").title()
|
|
190
|
+
desc_line = f"\n{description}\n" if description else ""
|
|
191
|
+
return f"""\
|
|
192
|
+
# {title}
|
|
193
|
+
{desc_line}
|
|
194
|
+
## Setup
|
|
195
|
+
|
|
196
|
+
```bash
|
|
197
|
+
pip install -e .
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
## Usage
|
|
201
|
+
|
|
202
|
+
```python
|
|
203
|
+
from utils.logger import get_logger
|
|
204
|
+
|
|
205
|
+
log = get_logger(__name__)
|
|
206
|
+
log.info("hello")
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
## Development
|
|
210
|
+
|
|
211
|
+
```bash
|
|
212
|
+
pip install -e ".[dev]"
|
|
213
|
+
pytest
|
|
214
|
+
```
|
|
215
|
+
"""
|
|
216
|
+
|
|
217
|
+
|
|
218
|
+
def _gitignore() -> str:
|
|
219
|
+
return """\
|
|
220
|
+
# Python
|
|
221
|
+
__pycache__/
|
|
222
|
+
*.py[cod]
|
|
223
|
+
*.pyo
|
|
224
|
+
*.pyd
|
|
225
|
+
.Python
|
|
226
|
+
*.egg-info/
|
|
227
|
+
dist/
|
|
228
|
+
build/
|
|
229
|
+
.eggs/
|
|
230
|
+
|
|
231
|
+
# Virtual envs
|
|
232
|
+
.venv/
|
|
233
|
+
venv/
|
|
234
|
+
env/
|
|
235
|
+
|
|
236
|
+
# Logs
|
|
237
|
+
logs/
|
|
238
|
+
*.log
|
|
239
|
+
|
|
240
|
+
# Env files
|
|
241
|
+
.env
|
|
242
|
+
.env.*.local
|
|
243
|
+
|
|
244
|
+
# IDE
|
|
245
|
+
.vscode/
|
|
246
|
+
.idea/
|
|
247
|
+
*.swp
|
|
248
|
+
|
|
249
|
+
# Testing
|
|
250
|
+
.pytest_cache/
|
|
251
|
+
.coverage
|
|
252
|
+
htmlcov/
|
|
253
|
+
|
|
254
|
+
# uv
|
|
255
|
+
uv.lock
|
|
256
|
+
"""
|
|
257
|
+
|
|
258
|
+
|
|
259
|
+
def _src_init(version: str) -> str:
|
|
260
|
+
return f'__version__ = "{version}"\n'
|
|
261
|
+
|
|
262
|
+
|
|
263
|
+
def _tests_init() -> str:
|
|
264
|
+
return '"""Test suite."""\n'
|
|
265
|
+
|
|
266
|
+
|
|
267
|
+
# ── public API ────────────────────────────────────────────────────────────────
|
|
268
|
+
|
|
269
|
+
def scaffold_basic(
|
|
270
|
+
project_dir: Path,
|
|
271
|
+
*,
|
|
272
|
+
version: str = "0.1.0",
|
|
273
|
+
description: str = "",
|
|
274
|
+
author: str = "",
|
|
275
|
+
config_fmt: str = "env",
|
|
276
|
+
deps: str = "toml",
|
|
277
|
+
include_llm: bool = False,
|
|
278
|
+
) -> ScaffoldResult:
|
|
279
|
+
"""
|
|
280
|
+
Scaffold a basic project layout under ``project_dir``.
|
|
281
|
+
|
|
282
|
+
Parameters
|
|
283
|
+
----------
|
|
284
|
+
project_dir:
|
|
285
|
+
Root directory for the project (will be created if absent).
|
|
286
|
+
version:
|
|
287
|
+
Starting version string, e.g. ``"0.1.0"``.
|
|
288
|
+
description:
|
|
289
|
+
Short project description used in pyproject.toml / README.
|
|
290
|
+
author:
|
|
291
|
+
Author string, e.g. ``"Jane Doe <jane@example.com>"``.
|
|
292
|
+
config_fmt:
|
|
293
|
+
Config file format — ``"env"`` (default), ``"yaml"``, or ``"json"``.
|
|
294
|
+
deps:
|
|
295
|
+
Dependency file style — ``"toml"`` (default) or ``"requirements"``.
|
|
296
|
+
"""
|
|
297
|
+
result = ScaffoldResult(project_dir=project_dir)
|
|
298
|
+
project_name = project_dir.name
|
|
299
|
+
|
|
300
|
+
# ── directories ───────────────────────────────────────────────────────────
|
|
301
|
+
_mkdir(result, project_dir)
|
|
302
|
+
_mkdir(result, project_dir / "src")
|
|
303
|
+
_mkdir(result, project_dir / "utils")
|
|
304
|
+
_mkdir(result, project_dir / "tests")
|
|
305
|
+
_mkdir(result, project_dir / "logs")
|
|
306
|
+
|
|
307
|
+
# ── src ───────────────────────────────────────────────────────────────────
|
|
308
|
+
_write(result, project_dir / "src" / "__init__.py", _src_init(version))
|
|
309
|
+
|
|
310
|
+
# ── utils ─────────────────────────────────────────────────────────────────
|
|
311
|
+
_write(result, project_dir / "utils" / "__init__.py", '"""Shared utilities."""\n')
|
|
312
|
+
_write(result, project_dir / "utils" / "logger.py", _logger_util())
|
|
313
|
+
if include_llm:
|
|
314
|
+
from infrakit.scaffolder.ai import _llm_util, _keys_json_template
|
|
315
|
+
_write(result, project_dir / "utils" / "llm.py", _llm_util(project_name))
|
|
316
|
+
_write(result, project_dir / "keys.json", _keys_json_template())
|
|
317
|
+
# ── tests ─────────────────────────────────────────────────────────────────
|
|
318
|
+
_write(result, project_dir / "tests" / "__init__.py", _tests_init())
|
|
319
|
+
|
|
320
|
+
# ── config file ───────────────────────────────────────────────────────────
|
|
321
|
+
cfg_name, cfg_content = _config_content(config_fmt)
|
|
322
|
+
_write(result, project_dir / cfg_name, cfg_content)
|
|
323
|
+
|
|
324
|
+
# ── dependency file ───────────────────────────────────────────────────────
|
|
325
|
+
if deps == "requirements":
|
|
326
|
+
_write(result, project_dir / "requirements.txt", _requirements_txt(project_name))
|
|
327
|
+
else:
|
|
328
|
+
_write(
|
|
329
|
+
result,
|
|
330
|
+
project_dir / "pyproject.toml",
|
|
331
|
+
_pyproject_toml(project_name, version, description, author),
|
|
332
|
+
)
|
|
333
|
+
|
|
334
|
+
# ── repo files ────────────────────────────────────────────────────────────
|
|
335
|
+
_write(result, project_dir / "README.md", _readme(project_name, description))
|
|
336
|
+
_write(result, project_dir / ".gitignore", _gitignore())
|
|
337
|
+
|
|
338
|
+
return result
|