scry-run 0.1.0__tar.gz

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 (42) hide show
  1. scry_run-0.1.0/.claude/settings.local.json +12 -0
  2. scry_run-0.1.0/.gitignore +3 -0
  3. scry_run-0.1.0/PKG-INFO +282 -0
  4. scry_run-0.1.0/README.md +252 -0
  5. scry_run-0.1.0/pyproject.toml +59 -0
  6. scry_run-0.1.0/src/scry_run/__init__.py +102 -0
  7. scry_run-0.1.0/src/scry_run/backends/__init__.py +6 -0
  8. scry_run-0.1.0/src/scry_run/backends/base.py +65 -0
  9. scry_run-0.1.0/src/scry_run/backends/claude.py +404 -0
  10. scry_run-0.1.0/src/scry_run/backends/frozen.py +85 -0
  11. scry_run-0.1.0/src/scry_run/backends/registry.py +72 -0
  12. scry_run-0.1.0/src/scry_run/cache.py +441 -0
  13. scry_run-0.1.0/src/scry_run/cli/__init__.py +137 -0
  14. scry_run-0.1.0/src/scry_run/cli/apps.py +396 -0
  15. scry_run-0.1.0/src/scry_run/cli/cache.py +342 -0
  16. scry_run-0.1.0/src/scry_run/cli/config_cmd.py +84 -0
  17. scry_run-0.1.0/src/scry_run/cli/env.py +27 -0
  18. scry_run-0.1.0/src/scry_run/cli/init.py +375 -0
  19. scry_run-0.1.0/src/scry_run/cli/run.py +71 -0
  20. scry_run-0.1.0/src/scry_run/config.py +141 -0
  21. scry_run-0.1.0/src/scry_run/console.py +52 -0
  22. scry_run-0.1.0/src/scry_run/context.py +298 -0
  23. scry_run-0.1.0/src/scry_run/generator.py +698 -0
  24. scry_run-0.1.0/src/scry_run/home.py +60 -0
  25. scry_run-0.1.0/src/scry_run/logging.py +171 -0
  26. scry_run-0.1.0/src/scry_run/meta.py +1852 -0
  27. scry_run-0.1.0/src/scry_run/packages.py +175 -0
  28. scry_run-0.1.0/tests/conftest.py +75 -0
  29. scry_run-0.1.0/tests/test_cache.py +375 -0
  30. scry_run-0.1.0/tests/test_cli.py +557 -0
  31. scry_run-0.1.0/tests/test_cli_default.py +81 -0
  32. scry_run-0.1.0/tests/test_cli_env.py +56 -0
  33. scry_run-0.1.0/tests/test_cli_run.py +109 -0
  34. scry_run-0.1.0/tests/test_config.py +263 -0
  35. scry_run-0.1.0/tests/test_context.py +204 -0
  36. scry_run-0.1.0/tests/test_generator.py +346 -0
  37. scry_run-0.1.0/tests/test_home.py +84 -0
  38. scry_run-0.1.0/tests/test_integration.py +256 -0
  39. scry_run-0.1.0/tests/test_logging.py +140 -0
  40. scry_run-0.1.0/tests/test_meta.py +393 -0
  41. scry_run-0.1.0/tests/test_packages.py +226 -0
  42. scry_run-0.1.0/uv.lock +1176 -0
@@ -0,0 +1,12 @@
1
+ {
2
+ "permissions": {
3
+ "allow": [
4
+ "Bash(find:*)",
5
+ "Bash(wc:*)",
6
+ "Bash(uv run pytest:*)",
7
+ "Bash(uv run python -m pytest:*)",
8
+ "Bash(uv sync:*)",
9
+ "Bash(uv lock:*)"
10
+ ]
11
+ }
12
+ }
@@ -0,0 +1,3 @@
1
+ *.pyc
2
+ __pycache__
3
+ tests/cache.json
@@ -0,0 +1,282 @@
1
+ Metadata-Version: 2.4
2
+ Name: scry-run
3
+ Version: 0.1.0
4
+ Summary: LLM-powered dynamic code generation via metaclasses. Define classes with docstrings, call any method—code generates automatically, caches persistently, and executes instantly.
5
+ Project-URL: Homepage, https://github.com/Tener/scry-run
6
+ Project-URL: Repository, https://github.com/Tener/scry-run
7
+ Author: Krzysztof Skrzętnicki
8
+ License: MIT
9
+ Keywords: ai,claude,code-generation,llm,metaclass
10
+ Classifier: Development Status :: 3 - Alpha
11
+ Classifier: Intended Audience :: Developers
12
+ Classifier: License :: OSI Approved :: MIT License
13
+ Classifier: Programming Language :: Python :: 3
14
+ Classifier: Programming Language :: Python :: 3.10
15
+ Classifier: Programming Language :: Python :: 3.11
16
+ Classifier: Programming Language :: Python :: 3.12
17
+ Classifier: Topic :: Software Development :: Code Generators
18
+ Requires-Python: >=3.10
19
+ Requires-Dist: claude-agent-sdk>=0.1.0
20
+ Requires-Dist: click>=8.0.0
21
+ Requires-Dist: jinja2>=3.0.0
22
+ Requires-Dist: rich>=13.0.0
23
+ Requires-Dist: tomli>=2.0.0; python_version < '3.11'
24
+ Provides-Extra: dev
25
+ Requires-Dist: pytest-asyncio>=0.21.0; extra == 'dev'
26
+ Requires-Dist: pytest-cov>=4.0.0; extra == 'dev'
27
+ Requires-Dist: pytest-timeout>=2.0.0; extra == 'dev'
28
+ Requires-Dist: pytest>=7.0.0; extra == 'dev'
29
+ Description-Content-Type: text/markdown
30
+
31
+ # scry-run
32
+
33
+ **Write class definitions, get working code.** A Python library where any method call automatically generates its implementation via LLM.
34
+
35
+ Define your application as a class with a docstring, then call any method you want—`scry-run` generates the code on-demand, caches it, and executes it. No boilerplate, no implementation required.
36
+
37
+ ## Features
38
+
39
+ - **Zero-boilerplate coding**: Define intent via class docstrings, methods generate automatically
40
+ - **Intelligent caching**: Generated code persists across runs—pay once, use forever
41
+ - **Production-ready**: Bake apps into standalone packages with frozen, pre-generated code
42
+ - **CLI-first**: Manage apps, inspect cache, and export generated code via intuitive commands
43
+
44
+ ## Installation
45
+
46
+ ```bash
47
+ pip install scry-run
48
+ # or with uv
49
+ uv pip install scry-run
50
+ ```
51
+
52
+ ### Run without installing (uvx)
53
+
54
+ ```bash
55
+ # From PyPI
56
+ uvx scry-run --help
57
+ uvx scry-run init --name=myapp --description="My app"
58
+
59
+ # From GitHub (latest)
60
+ uvx --from git+https://github.com/scry-run/scry-run scry-run --help
61
+ ```
62
+
63
+ ## Quick Start
64
+
65
+ ### 1. Set up your backend
66
+
67
+ Requires Claude Code CLI to be installed.
68
+
69
+ ```bash
70
+ # Verify claude CLI is available
71
+ claude --version
72
+ ```
73
+
74
+ ### 2. Initialize a project
75
+
76
+ ```bash
77
+ # Non-interactive
78
+ scry-run init --name=todoist --description='minimal web todo app'
79
+
80
+ # Interactive
81
+ scry-run init
82
+ ```
83
+
84
+ ### 3. Run your app
85
+
86
+ ```bash
87
+ scry-run run todoist
88
+ ```
89
+
90
+ Or use it directly in Python:
91
+
92
+ ```python
93
+ from scry_run import ScryClass
94
+
95
+ class Todoist(ScryClass):
96
+ """A minimal web todo app with task management."""
97
+ pass
98
+
99
+ app = Todoist()
100
+
101
+ # These methods will be generated automatically!
102
+ app.add_task("Buy groceries")
103
+ app.list_tasks()
104
+ app.complete_task(0)
105
+ ```
106
+
107
+ ## Demos
108
+
109
+ ### Creating a simple Hello World app
110
+
111
+ ![Hello Demo](demos/hello.gif)
112
+
113
+ ### Building a maze game with PyGame
114
+
115
+ ![Maze Demo](demos/maze.gif)
116
+
117
+
118
+ ## How It Works
119
+
120
+ 1. When you access an undefined attribute on an `ScryClass` subclass, the metaclass intercepts it
121
+ 2. The library collects the full codebase context and builds a prompt
122
+ 3. The configured backend generates code with structured JSON output (code, type, docstring, dependencies)
123
+ 4. The code is validated with Python's `ast.parse()` to ensure it's syntactically correct
124
+ 5. Valid code is cached and executed
125
+ 6. On subsequent accesses, the cached code is used directly
126
+
127
+ ## Backend
128
+
129
+ Uses Claude Code CLI with `--print` flag for non-interactive output.
130
+
131
+ ```bash
132
+ # If claude CLI is installed, it's used automatically
133
+ scry-run run myapp
134
+
135
+ # Optionally specify a model
136
+ export SCRY_RUN_MODEL=opus
137
+ ```
138
+
139
+ ## Configuration
140
+
141
+ ### Environment Variables
142
+
143
+ | Variable | Description | Default |
144
+ |----------|-------------|---------|
145
+ | `SCRY_RUN_BACKEND` | Backend to use: `claude`, `frozen`, or `auto` | `auto` |
146
+ | `SCRY_RUN_MODEL` | Model override (e.g., `opus`) | (backend default) |
147
+ | `SCRY_RUN_MAX_GENERATIONS` | Max code generations per process | `100` |
148
+
149
+ ### Class-level options
150
+
151
+ ```python
152
+ class MyApp(ScryClass):
153
+ """My application."""
154
+
155
+ # Disable LLM generation (raises AttributeError for missing attrs)
156
+ _llm_enabled = False
157
+
158
+ # Use minimal context instead of full codebase (faster)
159
+ _llm_use_full_context = False
160
+
161
+ # Suppress generation messages
162
+ _llm_quiet = True
163
+
164
+ # Override model for this class
165
+ _llm_model = "opus"
166
+ ```
167
+
168
+ ## CLI Commands
169
+
170
+ ### App Management
171
+
172
+ ```bash
173
+ # Initialize a new app
174
+ scry-run init --name=NAME --description=DESC
175
+
176
+ # List all apps
177
+ scry-run list
178
+
179
+ # Get path to an app's main file
180
+ scry-run which myapp
181
+
182
+ # Run an app
183
+ scry-run run myapp [args...]
184
+
185
+ # Remove an app
186
+ scry-run rm myapp
187
+ scry-run rm myapp --force # Skip confirmation
188
+
189
+ # Reset an app (clear code & cache, keep name/description)
190
+ scry-run reset myapp
191
+ scry-run reset myapp --force # Skip confirmation
192
+ ```
193
+
194
+ ### Cache Management
195
+
196
+ ```bash
197
+ # List cached entries for an app
198
+ scry-run cache list myapp
199
+
200
+ # Show a specific entry
201
+ scry-run cache show myapp MyClass.my_method
202
+
203
+ # Export cache
204
+ scry-run cache export myapp --output=generated.py --format=python
205
+ scry-run cache export myapp --output=cache.json --format=json
206
+
207
+ # Remove a specific entry
208
+ scry-run cache rm myapp MyClass.my_method
209
+
210
+ # Prune cache entries
211
+ scry-run cache prune myapp --class=MyClass --attr=my_method
212
+ scry-run cache prune myapp --class=MyClass # All methods of a class
213
+ scry-run cache prune myapp --all # Everything
214
+
215
+ # Reset cache (clear all entries)
216
+ scry-run cache reset myapp --force
217
+ ```
218
+
219
+ ## API
220
+
221
+ ### ScryClass
222
+
223
+ Base class to inherit from for LLM-powered code generation.
224
+
225
+ ```python
226
+ from scry_run import ScryClass
227
+
228
+ class MyApp(ScryClass):
229
+ """Description of your app - the LLM uses this!"""
230
+
231
+ def existing_method(self):
232
+ """Existing methods are used as context."""
233
+ return "hello"
234
+
235
+ # Class methods
236
+ MyApp.llm_export_cache("output.py") # Export generated code
237
+ MyApp.llm_prune_cache("method_name") # Remove cached entry
238
+ MyApp.llm_disable() # Disable generation
239
+ MyApp.llm_enable() # Re-enable generation
240
+ ```
241
+
242
+ ### ScryCache
243
+
244
+ Manage the code cache programmatically.
245
+
246
+ ```python
247
+ from scry_run import ScryCache
248
+
249
+ cache = ScryCache()
250
+
251
+ # Get cached code
252
+ entry = cache.get("MyClass", "my_method")
253
+ print(entry.code)
254
+
255
+ # List all entries
256
+ for entry in cache.list_entries():
257
+ print(f"{entry.class_name}.{entry.attr_name}: {entry.docstring}")
258
+
259
+ # Export
260
+ cache.export_to_file("all_generated_code.py")
261
+
262
+ # Prune
263
+ cache.prune(class_name="MyClass", attr_name="my_method")
264
+ ```
265
+
266
+ ## Development
267
+
268
+ ```bash
269
+ # Clone the repo
270
+ git clone https://github.com/scry-run/scry-run
271
+ cd scry-run
272
+
273
+ # Install with dev dependencies
274
+ uv sync --dev
275
+
276
+ # Run tests
277
+ uv run pytest tests/ -v
278
+ ```
279
+
280
+ ## License
281
+
282
+ MIT
@@ -0,0 +1,252 @@
1
+ # scry-run
2
+
3
+ **Write class definitions, get working code.** A Python library where any method call automatically generates its implementation via LLM.
4
+
5
+ Define your application as a class with a docstring, then call any method you want—`scry-run` generates the code on-demand, caches it, and executes it. No boilerplate, no implementation required.
6
+
7
+ ## Features
8
+
9
+ - **Zero-boilerplate coding**: Define intent via class docstrings, methods generate automatically
10
+ - **Intelligent caching**: Generated code persists across runs—pay once, use forever
11
+ - **Production-ready**: Bake apps into standalone packages with frozen, pre-generated code
12
+ - **CLI-first**: Manage apps, inspect cache, and export generated code via intuitive commands
13
+
14
+ ## Installation
15
+
16
+ ```bash
17
+ pip install scry-run
18
+ # or with uv
19
+ uv pip install scry-run
20
+ ```
21
+
22
+ ### Run without installing (uvx)
23
+
24
+ ```bash
25
+ # From PyPI
26
+ uvx scry-run --help
27
+ uvx scry-run init --name=myapp --description="My app"
28
+
29
+ # From GitHub (latest)
30
+ uvx --from git+https://github.com/scry-run/scry-run scry-run --help
31
+ ```
32
+
33
+ ## Quick Start
34
+
35
+ ### 1. Set up your backend
36
+
37
+ Requires Claude Code CLI to be installed.
38
+
39
+ ```bash
40
+ # Verify claude CLI is available
41
+ claude --version
42
+ ```
43
+
44
+ ### 2. Initialize a project
45
+
46
+ ```bash
47
+ # Non-interactive
48
+ scry-run init --name=todoist --description='minimal web todo app'
49
+
50
+ # Interactive
51
+ scry-run init
52
+ ```
53
+
54
+ ### 3. Run your app
55
+
56
+ ```bash
57
+ scry-run run todoist
58
+ ```
59
+
60
+ Or use it directly in Python:
61
+
62
+ ```python
63
+ from scry_run import ScryClass
64
+
65
+ class Todoist(ScryClass):
66
+ """A minimal web todo app with task management."""
67
+ pass
68
+
69
+ app = Todoist()
70
+
71
+ # These methods will be generated automatically!
72
+ app.add_task("Buy groceries")
73
+ app.list_tasks()
74
+ app.complete_task(0)
75
+ ```
76
+
77
+ ## Demos
78
+
79
+ ### Creating a simple Hello World app
80
+
81
+ ![Hello Demo](demos/hello.gif)
82
+
83
+ ### Building a maze game with PyGame
84
+
85
+ ![Maze Demo](demos/maze.gif)
86
+
87
+
88
+ ## How It Works
89
+
90
+ 1. When you access an undefined attribute on an `ScryClass` subclass, the metaclass intercepts it
91
+ 2. The library collects the full codebase context and builds a prompt
92
+ 3. The configured backend generates code with structured JSON output (code, type, docstring, dependencies)
93
+ 4. The code is validated with Python's `ast.parse()` to ensure it's syntactically correct
94
+ 5. Valid code is cached and executed
95
+ 6. On subsequent accesses, the cached code is used directly
96
+
97
+ ## Backend
98
+
99
+ Uses Claude Code CLI with `--print` flag for non-interactive output.
100
+
101
+ ```bash
102
+ # If claude CLI is installed, it's used automatically
103
+ scry-run run myapp
104
+
105
+ # Optionally specify a model
106
+ export SCRY_RUN_MODEL=opus
107
+ ```
108
+
109
+ ## Configuration
110
+
111
+ ### Environment Variables
112
+
113
+ | Variable | Description | Default |
114
+ |----------|-------------|---------|
115
+ | `SCRY_RUN_BACKEND` | Backend to use: `claude`, `frozen`, or `auto` | `auto` |
116
+ | `SCRY_RUN_MODEL` | Model override (e.g., `opus`) | (backend default) |
117
+ | `SCRY_RUN_MAX_GENERATIONS` | Max code generations per process | `100` |
118
+
119
+ ### Class-level options
120
+
121
+ ```python
122
+ class MyApp(ScryClass):
123
+ """My application."""
124
+
125
+ # Disable LLM generation (raises AttributeError for missing attrs)
126
+ _llm_enabled = False
127
+
128
+ # Use minimal context instead of full codebase (faster)
129
+ _llm_use_full_context = False
130
+
131
+ # Suppress generation messages
132
+ _llm_quiet = True
133
+
134
+ # Override model for this class
135
+ _llm_model = "opus"
136
+ ```
137
+
138
+ ## CLI Commands
139
+
140
+ ### App Management
141
+
142
+ ```bash
143
+ # Initialize a new app
144
+ scry-run init --name=NAME --description=DESC
145
+
146
+ # List all apps
147
+ scry-run list
148
+
149
+ # Get path to an app's main file
150
+ scry-run which myapp
151
+
152
+ # Run an app
153
+ scry-run run myapp [args...]
154
+
155
+ # Remove an app
156
+ scry-run rm myapp
157
+ scry-run rm myapp --force # Skip confirmation
158
+
159
+ # Reset an app (clear code & cache, keep name/description)
160
+ scry-run reset myapp
161
+ scry-run reset myapp --force # Skip confirmation
162
+ ```
163
+
164
+ ### Cache Management
165
+
166
+ ```bash
167
+ # List cached entries for an app
168
+ scry-run cache list myapp
169
+
170
+ # Show a specific entry
171
+ scry-run cache show myapp MyClass.my_method
172
+
173
+ # Export cache
174
+ scry-run cache export myapp --output=generated.py --format=python
175
+ scry-run cache export myapp --output=cache.json --format=json
176
+
177
+ # Remove a specific entry
178
+ scry-run cache rm myapp MyClass.my_method
179
+
180
+ # Prune cache entries
181
+ scry-run cache prune myapp --class=MyClass --attr=my_method
182
+ scry-run cache prune myapp --class=MyClass # All methods of a class
183
+ scry-run cache prune myapp --all # Everything
184
+
185
+ # Reset cache (clear all entries)
186
+ scry-run cache reset myapp --force
187
+ ```
188
+
189
+ ## API
190
+
191
+ ### ScryClass
192
+
193
+ Base class to inherit from for LLM-powered code generation.
194
+
195
+ ```python
196
+ from scry_run import ScryClass
197
+
198
+ class MyApp(ScryClass):
199
+ """Description of your app - the LLM uses this!"""
200
+
201
+ def existing_method(self):
202
+ """Existing methods are used as context."""
203
+ return "hello"
204
+
205
+ # Class methods
206
+ MyApp.llm_export_cache("output.py") # Export generated code
207
+ MyApp.llm_prune_cache("method_name") # Remove cached entry
208
+ MyApp.llm_disable() # Disable generation
209
+ MyApp.llm_enable() # Re-enable generation
210
+ ```
211
+
212
+ ### ScryCache
213
+
214
+ Manage the code cache programmatically.
215
+
216
+ ```python
217
+ from scry_run import ScryCache
218
+
219
+ cache = ScryCache()
220
+
221
+ # Get cached code
222
+ entry = cache.get("MyClass", "my_method")
223
+ print(entry.code)
224
+
225
+ # List all entries
226
+ for entry in cache.list_entries():
227
+ print(f"{entry.class_name}.{entry.attr_name}: {entry.docstring}")
228
+
229
+ # Export
230
+ cache.export_to_file("all_generated_code.py")
231
+
232
+ # Prune
233
+ cache.prune(class_name="MyClass", attr_name="my_method")
234
+ ```
235
+
236
+ ## Development
237
+
238
+ ```bash
239
+ # Clone the repo
240
+ git clone https://github.com/scry-run/scry-run
241
+ cd scry-run
242
+
243
+ # Install with dev dependencies
244
+ uv sync --dev
245
+
246
+ # Run tests
247
+ uv run pytest tests/ -v
248
+ ```
249
+
250
+ ## License
251
+
252
+ MIT
@@ -0,0 +1,59 @@
1
+ [project]
2
+ name = "scry-run"
3
+ version = "0.1.0"
4
+ description = "LLM-powered dynamic code generation via metaclasses. Define classes with docstrings, call any method—code generates automatically, caches persistently, and executes instantly."
5
+ readme = "README.md"
6
+ license = { text = "MIT" }
7
+ requires-python = ">=3.10"
8
+ authors = [{ name = "Krzysztof Skrzętnicki" }]
9
+ keywords = ["llm", "code-generation", "metaclass", "claude", "ai"]
10
+ classifiers = [
11
+ "Development Status :: 3 - Alpha",
12
+ "Intended Audience :: Developers",
13
+ "License :: OSI Approved :: MIT License",
14
+ "Programming Language :: Python :: 3",
15
+ "Programming Language :: Python :: 3.10",
16
+ "Programming Language :: Python :: 3.11",
17
+ "Programming Language :: Python :: 3.12",
18
+ "Topic :: Software Development :: Code Generators",
19
+ ]
20
+
21
+ dependencies = [
22
+ "click>=8.0.0",
23
+ "rich>=13.0.0",
24
+ "jinja2>=3.0.0",
25
+ "tomli>=2.0.0;python_version<'3.11'",
26
+ "claude-agent-sdk>=0.1.0",
27
+ ]
28
+
29
+ [project.optional-dependencies]
30
+ dev = [
31
+ "pytest>=7.0.0",
32
+ "pytest-cov>=4.0.0",
33
+ "pytest-asyncio>=0.21.0",
34
+ "pytest-timeout>=2.0.0",
35
+ ]
36
+
37
+ [project.scripts]
38
+ scry-run = "scry_run.cli:main"
39
+
40
+ [project.urls]
41
+ Homepage = "https://github.com/Tener/scry-run"
42
+ Repository = "https://github.com/Tener/scry-run"
43
+
44
+ [build-system]
45
+ requires = ["hatchling"]
46
+ build-backend = "hatchling.build"
47
+
48
+ [tool.hatch.build.targets.wheel]
49
+ packages = ["src/scry_run"]
50
+
51
+ [tool.hatch.build.targets.sdist]
52
+ exclude = ["demos/"]
53
+
54
+
55
+ [tool.pytest.ini_options]
56
+ testpaths = ["tests"]
57
+ pythonpath = ["src"]
58
+ timeout = 30
59
+ timeout_method = "thread"
@@ -0,0 +1,102 @@
1
+ """scry-run: LLM-powered dynamic code generation via metaclasses."""
2
+
3
+ from typing import Any
4
+
5
+ from scry_run.meta import ScryClass, ScryMeta
6
+ from scry_run.cache import ScryCache
7
+ from scry_run.home import get_home, get_app_dir, ensure_home_exists
8
+ from scry_run.config import Config, load_config
9
+ from scry_run.generator import (
10
+ CodeGenerator,
11
+ ScryRunError,
12
+ APIKeyError,
13
+ RateLimitError,
14
+ QuotaExceededError,
15
+ ModelNotFoundError,
16
+ ContentBlockedError,
17
+ NetworkError,
18
+ CodeGenerationError,
19
+ CodeValidationError,
20
+ )
21
+ from scry_run.context import ContextBuilder
22
+ from scry_run.backends.frozen import FrozenAppError
23
+
24
+
25
+ def scry_create(name: str, description: str = "") -> type:
26
+ """Create a new ScryClass subclass dynamically.
27
+
28
+ Use this to create multiple classes without manually defining them.
29
+
30
+ Args:
31
+ name: Class name (e.g., "TodoItem", "Database")
32
+ description: Docstring describing what this class does
33
+
34
+ Returns:
35
+ A new class inheriting from ScryClass
36
+
37
+ Example:
38
+ >>> TodoItem = scry_create("TodoItem", "A single todo item with title and status")
39
+ >>> item = TodoItem("Buy groceries")
40
+ >>> item.mark_done() # auto-generated!
41
+ """
42
+ doc = description or f"Auto-generated {name} class"
43
+ return type(name, (ScryClass,), {"__doc__": doc})
44
+
45
+
46
+ def is_generated(obj: Any) -> bool:
47
+ """Check if an object (function, method, property, class) was generated by scry-run.
48
+
49
+ This function reliably checks for internal metadata attached to generated code.
50
+ It handles unwrapping of properties, classmethods, and bound methods.
51
+
52
+ Args:
53
+ obj: The object to check
54
+
55
+ Returns:
56
+ True if the object was generated by LLM, False otherwise.
57
+ """
58
+ marker = "_llm_is_generated"
59
+
60
+ # Handle descriptors (property, classmethod, staticmethod)
61
+ if isinstance(obj, property) and obj.fget:
62
+ return getattr(obj.fget, marker, False)
63
+
64
+ if isinstance(obj, (classmethod, staticmethod)):
65
+ return getattr(obj.__func__, marker, False)
66
+
67
+ # Handle bound methods (e.g. instance.method)
68
+ if hasattr(obj, "__func__"):
69
+ return getattr(obj.__func__, marker, False)
70
+
71
+ # Handle plain functions/classes
72
+ return getattr(obj, marker, False)
73
+
74
+
75
+ __version__ = "0.1.0"
76
+ __all__ = [
77
+ "ScryClass",
78
+ "ScryMeta",
79
+ "ScryCache",
80
+ "CodeGenerator",
81
+ "ContextBuilder",
82
+ "scry_create",
83
+ "is_generated",
84
+ # Home directory
85
+ "get_home",
86
+ "get_app_dir",
87
+ "ensure_home_exists",
88
+ # Config
89
+ "Config",
90
+ "load_config",
91
+ # Exceptions
92
+ "ScryRunError",
93
+ "APIKeyError",
94
+ "RateLimitError",
95
+ "QuotaExceededError",
96
+ "ModelNotFoundError",
97
+ "ContentBlockedError",
98
+ "NetworkError",
99
+ "CodeGenerationError",
100
+ "CodeValidationError",
101
+ "FrozenAppError",
102
+ ]
@@ -0,0 +1,6 @@
1
+ """Pluggable backend system for LLM code generation."""
2
+
3
+ from scry_run.backends.base import GeneratorBackend
4
+ from scry_run.backends.registry import get_backend, register_backend
5
+
6
+ __all__ = ["GeneratorBackend", "get_backend", "register_backend"]