├── app
└── index.html
├── .gitignore
├── pytest.ini
├── src
└── spew
│ ├── __init__.py
│ ├── randomcycle.py
│ ├── names.py
│ ├── __main__.py
│ └── generate.py
├── api
├── function.py
└── function.json
├── .vscode
└── settings.json
├── pyproject.toml
├── LICENSE
├── .github
└── workflows
│ ├── python-package.yml
│ └── azure-static-web-apps-kind-dune-0f668560f.yml
├── README.md
├── tests
└── test_generate.py
└── examples
└── output_default.py
/app/index.html:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | [.]venv/
2 | *.py[co]
3 | dist/
--------------------------------------------------------------------------------
/pytest.ini:
--------------------------------------------------------------------------------
1 | [pytest]
2 | minversion = 6.0
3 | addopts = --count=10
4 | testpaths = tests
5 |
--------------------------------------------------------------------------------
/src/spew/__init__.py:
--------------------------------------------------------------------------------
1 | """
2 | Spew - A generator for Python. It uses Python to generate valid Python code.
3 | """
4 |
5 | __version__ = "1.0.2"
6 |
--------------------------------------------------------------------------------
/api/function.py:
--------------------------------------------------------------------------------
1 | import azure.functions as func
2 | import logging
3 |
4 |
5 | def main(req: func.HttpRequest) -> func.HttpResponse:
6 | logging.info("Python HTTP trigger function processed a request.")
7 | return func.HttpResponse("Hello, world!")
8 |
--------------------------------------------------------------------------------
/api/function.json:
--------------------------------------------------------------------------------
1 | {
2 | "scriptFile": "function.py",
3 | "bindings": [
4 | {
5 | "authLevel": "anonymous",
6 | "type": "httpTrigger",
7 | "direction": "in",
8 | "name": "req",
9 | "methods": [
10 | "post"
11 | ]
12 | },
13 | {
14 | "type": "http",
15 | "direction": "out",
16 | "name": "$return"
17 | }
18 | ]
19 | }
--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "python.testing.pytestArgs": [
3 | "tests"
4 | ],
5 | "python.testing.unittestEnabled": false,
6 | "python.testing.pytestEnabled": true,
7 | "python.testing.cwd": "${workspaceFolder}",
8 | "python.analysis.diagnosticMode": "workspace",
9 | "python.analysis.typeCheckingMode": "basic",
10 | "[python]": {
11 | "editor.formatOnSave": true,
12 | }
13 | }
--------------------------------------------------------------------------------
/src/spew/randomcycle.py:
--------------------------------------------------------------------------------
1 | import random as _random
2 | import typing
3 |
4 | TCycle = typing.TypeVar("TCycle")
5 |
6 |
7 | # Define a cycle that yields a random element in a list until it is exhausted then starts again
8 | def rcycle(l: typing.Iterable[TCycle]) -> typing.Generator[TCycle, None, None]:
9 | while True:
10 | items = list(l)
11 | _random.shuffle(items)
12 | for item in items:
13 | yield item
14 |
--------------------------------------------------------------------------------
/src/spew/names.py:
--------------------------------------------------------------------------------
1 | import random
2 |
3 | FIRST_CHARS = "abcdefghijklmnopqrstuvwxyz"
4 | OTHER_CHARS = "abcdefghijklmnopqrstuvwxyz1234567890_"
5 |
6 |
7 | def generate(ctx, new: bool = False) -> str:
8 | # TODO: create unique names
9 | if not new and ctx.names:
10 | return random.choice(ctx.names)
11 |
12 | name = random.choice(FIRST_CHARS)
13 | for _ in range(10):
14 | name += random.choice(OTHER_CHARS)
15 | ctx.names.append(name)
16 | return name
17 |
--------------------------------------------------------------------------------
/pyproject.toml:
--------------------------------------------------------------------------------
1 | [build-system]
2 | requires = ["flit_core >=3.2,<4"]
3 | build-backend = "flit_core.buildapi"
4 |
5 | [project]
6 | name = "spew"
7 | authors = [{name = "Anthony Shaw"}]
8 | license = {file = "LICENSE"}
9 | classifiers = ["License :: OSI Approved :: MIT License"]
10 | dynamic = ["version", "description"]
11 | requires-python = ">=3.10"
12 | dependencies = ["rich"]
13 |
14 | [project.optional-dependencies]
15 | test = [
16 | "pytest",
17 | "pytest-repeat",
18 | ]
19 |
20 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2023 Anthony Shaw
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in
13 | all copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 | THE SOFTWARE.
22 |
--------------------------------------------------------------------------------
/.github/workflows/python-package.yml:
--------------------------------------------------------------------------------
1 | # This workflow will install Python dependencies, run tests and lint with a variety of Python versions
2 | # For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-python
3 |
4 | name: Python package
5 |
6 | on:
7 | push:
8 | branches: [ "master" ]
9 | pull_request:
10 | branches: [ "master" ]
11 |
12 | jobs:
13 | build:
14 |
15 | runs-on: ubuntu-latest
16 | strategy:
17 | fail-fast: false
18 | matrix:
19 | python-version: ["3.10", "3.11", "3.12-dev"]
20 |
21 | steps:
22 | - uses: actions/checkout@v3
23 | - name: Set up Python ${{ matrix.python-version }}
24 | uses: actions/setup-python@v3
25 | with:
26 | python-version: ${{ matrix.python-version }}
27 | - name: Install dependencies
28 | run: |
29 | python -m pip install --upgrade pip flit pytest-cov codecov
30 | flit install --deps=all
31 | - name: Test with pytest
32 | run: |
33 | pytest
34 | - name: Run tests and collect coverage
35 | run: pytest --cov=spew --cov-report=xml
36 | - name: Upload coverage reports to Codecov with GitHub Action
37 | uses: codecov/codecov-action@v3
38 | env:
39 | CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
40 |
--------------------------------------------------------------------------------
/src/spew/__main__.py:
--------------------------------------------------------------------------------
1 | import spew.generate
2 | import ast
3 | from rich.console import Console
4 | from rich.syntax import Syntax
5 | import argparse
6 | import logging
7 |
8 | logging.basicConfig(level=logging.INFO)
9 | logger = logging.getLogger(__name__)
10 |
11 | parser = argparse.ArgumentParser()
12 | parser.add_argument(
13 | "--depth", type=int, default=4, help="Maximum depth (nesting) of the module"
14 | )
15 | parser.add_argument("--width", type=int, default=10)
16 | parser.add_argument("--log-level", type=str, default="INFO")
17 | parser.add_argument(
18 | "--output",
19 | type=argparse.FileType("w", encoding="utf-8"),
20 | default=None,
21 | help="Output file. If not specified, the output will be printed to the console.",
22 | )
23 | parser.add_argument(
24 | "--check", action="store_true", help="Check if the code is valid Python"
25 | )
26 | args = parser.parse_args()
27 |
28 | console = Console()
29 | logger.setLevel(args.log_level)
30 | logger.debug("Generating module with depth %s and width %s", args.depth, args.width)
31 | m = spew.generate.generate_module(
32 | depth=args.depth, width=args.width, log_level=args.log_level
33 | )
34 | code = ast.unparse(m)
35 |
36 |
37 | if args.output:
38 | args.output.write(code)
39 | else:
40 | syntax = Syntax(code, "python")
41 | console.print(syntax)
42 |
43 | if args.check:
44 | ast.parse(code, "test.py")
45 | logger.info("Code is valid Python")
46 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # spew
2 |
3 | A tool for generating random, syntactically-correct Python code. Designed for fuzzing and testing of tools that parse Python code.
4 |
5 | Designed for Python 3.10 and above, this is for testing the latest syntax.
6 |
7 | Supports:
8 |
9 | - Functions
10 | - For, If, While
11 | - Async With, For, FunctionDef
12 | - All constant expressions
13 | - Match statements
14 | - Many expression types
15 | - Decorators
16 | - Classes
17 |
18 | ## Usage
19 |
20 | You can use at the command line:
21 |
22 | ```console
23 | > python -m spew --depth=4
24 | ```
25 |
26 | Caution, depths higher than 5 creating a huge recursive computing load. (A depth of 6 creates a file ~40,000 lines of code.)
27 |
28 | Also, you can generate specific nodes, like modules or functions:
29 |
30 | ```python
31 | import spew.generate as g
32 |
33 | context = g.Context()
34 | func = g.generate_function(context) # returns an ast.FunctionDef object
35 | ```
36 |
37 | To generate AST objects back into Python code you can use the `ast.unparse()` function.
38 |
39 | The full list of command-line options:
40 |
41 | ```default
42 | python -m spew --help
43 | usage: __main__.py [-h] [--depth DEPTH] [--width WIDTH] [--log-level LOG_LEVEL] [--output OUTPUT] [--check]
44 |
45 | options:
46 | -h, --help show this help message and exit
47 | --depth DEPTH Maximum depth (nesting) of the module
48 | --width WIDTH
49 | --log-level LOG_LEVEL
50 | --output OUTPUT Output file. If not specified, the output will be printed to the console.
51 | --check Check if the code is valid Python
52 | ```
53 |
--------------------------------------------------------------------------------
/.github/workflows/azure-static-web-apps-kind-dune-0f668560f.yml:
--------------------------------------------------------------------------------
1 | name: Azure Static Web Apps CI/CD
2 |
3 | on:
4 | push:
5 | branches:
6 | - master
7 | pull_request:
8 | types: [opened, synchronize, reopened, closed]
9 | branches:
10 | - master
11 |
12 | jobs:
13 | build_and_deploy_job:
14 | if: github.event_name == 'push' || (github.event_name == 'pull_request' && github.event.action != 'closed')
15 | runs-on: ubuntu-latest
16 | name: Build and Deploy Job
17 | steps:
18 | - uses: actions/checkout@v3
19 | with:
20 | submodules: true
21 | - name: Build And Deploy
22 | id: builddeploy
23 | uses: Azure/static-web-apps-deploy@v1
24 | with:
25 | azure_static_web_apps_api_token: ${{ secrets.AZURE_STATIC_WEB_APPS_API_TOKEN_KIND_DUNE_0F668560F }}
26 | repo_token: ${{ secrets.GITHUB_TOKEN }} # Used for Github integrations (i.e. PR comments)
27 | action: "upload"
28 | ###### Repository/Build Configurations - These values can be configured to match your app requirements. ######
29 | # For more information regarding Static Web App workflow configurations, please visit: https://aka.ms/swaworkflowconfig
30 | app_location: "app" # App source code path
31 | api_location: "api" # Api source code path - optional
32 | # output_location: "/" # Built app content directory - optional
33 | ###### End of Repository/Build Configurations ######
34 |
35 | close_pull_request_job:
36 | if: github.event_name == 'pull_request' && github.event.action == 'closed'
37 | runs-on: ubuntu-latest
38 | name: Close Pull Request Job
39 | steps:
40 | - name: Close Pull Request
41 | id: closepullrequest
42 | uses: Azure/static-web-apps-deploy@v1
43 | with:
44 | azure_static_web_apps_api_token: ${{ secrets.AZURE_STATIC_WEB_APPS_API_TOKEN_KIND_DUNE_0F668560F }}
45 | action: "close"
46 |
--------------------------------------------------------------------------------
/tests/test_generate.py:
--------------------------------------------------------------------------------
1 | import spew.generate as g
2 | import ast
3 | import pytest
4 | import compileall
5 | import tempfile
6 |
7 |
8 | @pytest.fixture
9 | def ctx():
10 | context = g.Context()
11 | context.max_depth = 1
12 | return context
13 |
14 |
15 | def compiles(code: str):
16 | ast.parse(code)
17 | with tempfile.NamedTemporaryFile("w", suffix=".py") as f:
18 | f.write(code)
19 | result = compileall.compile_file(f.name)
20 | return result
21 |
22 |
23 | @pytest.mark.parametrize("depth", [1, 2, 3, 4, 5])
24 | def test_nested_generate_module(depth):
25 | module = g.generate_module(depth=depth, width=3)
26 | assert module
27 | code = ast.unparse(module)
28 | assert compiles(code)
29 |
30 |
31 | def test_generate_arg(ctx):
32 | arg = g.generate_arg(ctx)
33 | assert arg
34 | code = ast.unparse(arg)
35 | assert compiles(code)
36 |
37 |
38 | def test_generate_function(ctx):
39 | ctx.max_depth = 1
40 | func = g.generate_function(ctx)
41 | assert func
42 | code = ast.unparse(func)
43 | assert compiles(code)
44 |
45 |
46 | def test_generate_asyncfunction(ctx):
47 | ctx.max_depth = 1
48 | func = g.generate_asyncfunction(ctx)
49 | assert func
50 | code = ast.unparse(func)
51 | assert compiles(code)
52 |
53 |
54 | def test_generate_class(ctx):
55 | ctx.max_depth = 1
56 | class_ = g.generate_class(ctx)
57 | assert class_
58 | code = ast.unparse(class_)
59 | assert compiles(code)
60 |
61 |
62 | def test_generate_ellipsis(ctx):
63 | ellipsis = g.generate_ellipsis(ctx)
64 | assert ellipsis
65 | code = ast.unparse(ellipsis)
66 | assert compiles(code)
67 |
68 |
69 | def test_generate_pass(ctx):
70 | pass_ = g.generate_pass(ctx)
71 | assert pass_
72 | code = ast.unparse(pass_)
73 | assert compiles(code)
74 |
75 |
76 | def test_generate_break(ctx):
77 | break_ = g.generate_break(ctx)
78 | assert break_
79 | code = ast.unparse(break_)
80 | assert compiles(code)
81 |
82 |
83 | def test_generate_continue(ctx):
84 | continue_ = g.generate_continue(ctx)
85 | assert continue_
86 | code = ast.unparse(continue_)
87 | assert compiles(code)
88 |
89 |
90 | def test_generate_assign(ctx):
91 | assign = g.generate_assign(ctx)
92 | assert assign
93 | code = ast.unparse(assign)
94 | assert compiles(code)
95 |
96 |
97 | def test_generate_augassign(ctx):
98 | augassign = g.generate_augassign(ctx)
99 | assert augassign
100 | code = ast.unparse(augassign)
101 | assert compiles(code)
102 |
103 |
104 | def test_generate_annassign(ctx):
105 | annassign = g.generate_annassign(ctx)
106 | assert annassign
107 | code = ast.unparse(annassign)
108 | assert compiles(code)
109 |
110 |
111 | def test_generate_import(ctx):
112 | import_ = g.generate_import(ctx)
113 | assert import_
114 | code = ast.unparse(import_)
115 | assert compiles(code)
116 |
117 |
118 | def test_generate_importfrom(ctx):
119 | importfrom = g.generate_importfrom(ctx)
120 | assert importfrom
121 | code = ast.unparse(importfrom)
122 | assert compiles(code)
123 |
124 |
125 | def test_generate_name(ctx):
126 | name = g.generate_name(ctx)
127 | assert name
128 | code = ast.unparse(name)
129 | assert compiles(code)
130 |
131 |
132 | def test_generate_constant(ctx):
133 | constant = g.generate_constant(ctx)
134 | assert constant
135 | code = ast.unparse(constant)
136 | assert compiles(code)
137 |
138 |
139 | def test_generate_delete(ctx):
140 | delete = g.generate_delete(ctx)
141 | assert delete
142 | code = ast.unparse(delete)
143 | assert compiles(code)
144 |
145 |
146 | def test_generate_raise(ctx):
147 | raise_ = g.generate_raise(ctx)
148 | assert raise_
149 | code = ast.unparse(raise_)
150 | assert compiles(code)
151 |
152 |
153 | def test_generate_global(ctx):
154 | global_ = g.generate_global(ctx)
155 | assert global_
156 | code = ast.unparse(global_)
157 | assert compiles(code)
158 |
159 |
160 | def test_generate_nonlocal(ctx):
161 | nonlocal_ = g.generate_nonlocal(ctx)
162 | assert nonlocal_
163 | code = ast.unparse(nonlocal_)
164 | assert compiles(code)
165 |
166 |
167 | def test_generate_for(ctx):
168 | ctx.max_depth = 1
169 | for_ = g.generate_for(ctx)
170 | assert for_
171 | code = ast.unparse(for_)
172 | assert compiles(code)
173 |
174 |
175 | def test_generate_asyncfor(ctx):
176 | ctx.max_depth = 1
177 | asyncfor = g.generate_asyncfor(ctx)
178 | assert asyncfor
179 | code = ast.unparse(asyncfor)
180 | assert compiles(code)
181 |
182 |
183 | def test_generate_while(ctx):
184 | ctx.max_depth = 1
185 | while_ = g.generate_while(ctx)
186 | assert while_
187 | code = ast.unparse(while_)
188 | assert compiles(code)
189 |
190 |
191 | def test_generate_if(ctx):
192 | ctx.max_depth = 1
193 | if_ = g.generate_if(ctx)
194 | assert if_
195 | code = ast.unparse(if_)
196 | assert compiles(code)
197 |
198 |
199 | def test_generate_with(ctx):
200 | ctx.max_depth = 1
201 | with_ = g.generate_with(ctx)
202 | assert with_
203 | code = ast.unparse(with_)
204 | assert compiles(code)
205 |
206 |
207 | def test_generate_asyncwith(ctx):
208 | ctx.max_depth = 1
209 | asyncwith = g.generate_asyncwith(ctx)
210 | assert asyncwith
211 | code = ast.unparse(asyncwith)
212 | assert compiles(code)
213 |
214 |
215 | def test_generate_assert(ctx):
216 | assert_ = g.generate_assert(ctx)
217 | assert assert_
218 | code = ast.unparse(assert_)
219 | assert compiles(code)
220 |
221 |
222 | def test_generate_expression(ctx):
223 | expression = g.generate_expression(ctx)
224 | assert expression
225 | code = ast.unparse(expression)
226 | assert compiles(code)
227 |
228 |
229 | def test_generate_try(ctx):
230 | ctx.max_depth = 1
231 | try_ = g.generate_try(ctx)
232 | assert try_
233 | code = ast.unparse(try_)
234 | assert compiles(code)
235 |
236 |
237 | def test_generate_trystar(ctx):
238 | ctx.max_depth = 1
239 | try_ = g.generate_trystar(ctx)
240 | assert try_
241 | code = ast.unparse(try_)
242 | assert compiles(code)
243 |
244 |
245 | def test_generate_matchvalue(ctx):
246 | matchvalue = g.generate_matchvalue(ctx)
247 | assert matchvalue
248 | case = ast.unparse(matchvalue)
249 | code = f"match x:\n case {case}: pass"
250 | assert compiles(code)
251 |
252 |
253 | def test_generate_matchsingleton(ctx):
254 | singleton = g.generate_matchsingleton(ctx)
255 | assert singleton
256 | case = ast.unparse(singleton)
257 | code = f"match x:\n case {case}: pass"
258 | assert compiles(code)
259 |
260 |
261 | def test_generate_matchsequence(ctx):
262 | matchsequence = g.generate_matchsequence(ctx)
263 | assert matchsequence
264 | case = ast.unparse(matchsequence)
265 | code = f"match x:\n case {case}: pass"
266 | assert compiles(code)
267 |
268 |
269 | def test_generate_matchmapping(ctx):
270 | matchmapping = g.generate_matchmapping(ctx)
271 | assert matchmapping
272 | case = ast.unparse(matchmapping)
273 | code = f"match x:\n case {case}: pass"
274 | assert compiles(code)
275 |
276 |
277 | def test_generate_matchclass(ctx):
278 | matchclass = g.generate_matchclass(ctx)
279 | assert matchclass
280 | case = ast.unparse(matchclass)
281 | code = f"match x:\n case {case}: pass"
282 | assert compiles(code)
283 |
284 |
285 | def test_generate_matchas(ctx):
286 | matchas = g.generate_matchas(ctx)
287 | assert matchas
288 | case = ast.unparse(matchas)
289 | code = f"match x:\n case {case}: pass"
290 | assert compiles(code)
291 |
292 |
293 | def test_generate_matchor(ctx):
294 | matchor = g.generate_matchor(ctx)
295 | assert matchor
296 | case = ast.unparse(matchor)
297 | code = f"match x:\n case {case}: pass"
298 | assert compiles(code)
299 |
300 |
301 | def test_generate_match(ctx):
302 | match = g.generate_match(ctx)
303 | assert match
304 | code = ast.unparse(match)
305 | assert compiles(code), match
306 |
307 |
308 | def test_generate_list(ctx):
309 | list_ = g.generate_list(ctx)
310 | assert list_
311 | code = ast.unparse(list_)
312 | assert compiles(code)
313 |
314 |
315 | def test_generate_tuple(ctx):
316 | tuple_ = g.generate_tuple(ctx)
317 | assert tuple_
318 | code = ast.unparse(tuple_)
319 | assert compiles(code)
320 |
321 |
322 | def test_generate_boolop(ctx):
323 | boolop = g.generate_boolop(ctx)
324 | assert boolop
325 | code = ast.unparse(boolop)
326 | assert compiles(code)
327 |
328 |
329 | def test_generate_binop(ctx):
330 | binop = g.generate_binop(ctx)
331 | assert binop
332 | code = ast.unparse(binop)
333 | assert compiles(code)
334 |
335 |
336 | def test_generate_unaryop(ctx):
337 | unaryop = g.generate_unaryop(ctx)
338 | assert unaryop
339 | code = ast.unparse(unaryop)
340 | assert compiles(code)
341 |
342 |
343 | def test_generate_lambda(ctx):
344 | lambda_ = g.generate_lambda(ctx)
345 | assert lambda_
346 | code = ast.unparse(lambda_)
347 | assert compiles(code)
348 |
349 |
350 | def test_generate_ifexp(ctx):
351 | ifexp = g.generate_ifexp(ctx)
352 | assert ifexp
353 | code = ast.unparse(ifexp)
354 | assert compiles(code)
355 |
356 |
357 | def test_generate_dict(ctx):
358 | dict_ = g.generate_dict(ctx)
359 | assert dict_
360 | code = ast.unparse(dict_)
361 | assert compiles(code)
362 |
363 |
364 | def test_generate_set(ctx):
365 | set_ = g.generate_set(ctx)
366 | assert set_
367 | code = ast.unparse(set_)
368 | assert compiles(code)
369 |
370 |
371 | def test_generate_listcomp(ctx):
372 | listcomp = g.generate_listcomp(ctx)
373 | assert listcomp
374 | code = ast.unparse(listcomp)
375 | assert compiles(code)
376 |
377 |
378 | def test_generate_setcomp(ctx):
379 | setcomp = g.generate_setcomp(ctx)
380 | assert setcomp
381 | code = ast.unparse(setcomp)
382 | assert compiles(code)
383 |
384 |
385 | def test_generate_dictcomp(ctx):
386 | dictcomp = g.generate_dictcomp(ctx)
387 | assert dictcomp
388 | code = ast.unparse(dictcomp)
389 | assert compiles(code)
390 |
391 |
392 | def test_generate_generatorexp(ctx):
393 | generatorexp = g.generate_generatorexp(ctx)
394 | assert generatorexp
395 | code = ast.unparse(generatorexp)
396 | assert compiles(code)
397 |
398 |
399 | def test_generate_await(ctx):
400 | await_ = g.generate_await(ctx)
401 | assert await_
402 | code = ast.unparse(await_)
403 | assert compiles(code)
404 |
405 |
406 | def test_generate_yield(ctx):
407 | yield_ = g.generate_yield(ctx)
408 | assert yield_
409 | code = ast.unparse(yield_)
410 | assert compiles(code)
411 |
412 |
413 | def test_generate_yieldfrom(ctx):
414 | yieldfrom = g.generate_yieldfrom(ctx)
415 | assert yieldfrom
416 | code = ast.unparse(yieldfrom)
417 | assert compiles(code)
418 |
419 |
420 | def test_generate_compare(ctx):
421 | compare = g.generate_compare(ctx)
422 | assert compare
423 | code = ast.unparse(compare)
424 | assert compiles(code)
425 |
426 |
427 | def test_generate_call(ctx):
428 | call = g.generate_call(ctx)
429 | assert call
430 | code = ast.unparse(call)
431 | assert compiles(code)
432 |
433 |
434 | def test_generate_formattedvalue(ctx):
435 | formattedvalue = g.generate_formattedvalue(ctx)
436 | assert formattedvalue
437 | code = ast.unparse(formattedvalue)
438 | assert code # isn't valid syntax
439 |
440 |
441 | def test_generate_joinedstr(ctx):
442 | joinedstr = g.generate_joinedstr(ctx)
443 | assert joinedstr
444 | code = ast.unparse(joinedstr)
445 | assert compiles(code)
446 |
447 |
448 | def test_generate_attribute(ctx):
449 | attribute = g.generate_attribute(ctx)
450 | assert attribute
451 | code = ast.unparse(attribute)
452 | assert compiles(code)
453 |
454 |
455 | def test_generate_subscript(ctx):
456 | subscript = g.generate_subscript(ctx)
457 | assert subscript
458 | code = ast.unparse(subscript)
459 | assert compiles(code)
460 |
--------------------------------------------------------------------------------
/examples/output_default.py:
--------------------------------------------------------------------------------
1 | for e8m0xd0kbvx in {(yield from False): [e8m0xd0kbvx for sl6bqcxwh3g in 0j if '' if sl6bqcxwh3g if None], e8m0xd0kbvx.e8m0xd0kbvx: sl6bqcxwh3g[0.0:sl6bqcxwh3g:sl6bqcxwh3g]}:
2 |
3 | class adqa8j00i8q:
4 | assert 0, e8m0xd0kbvx
5 | from adqa8j00i8q import adqa8j00i8q, adqa8j00i8q as ozi1xls5irl, sl6bqcxwh3g
6 | break
7 | global ozi1xls5irl
8 | pass
9 | None.ozi1xls5irl: adqa8j00i8q = ozi1xls5irl
10 | ''.ozi1xls5irl *= sl6bqcxwh3g
11 | continue
12 | raise False
13 | n2rw5o0_ibu = b64jkd1qw0z = j56uuem5c4b = r4mfejds1d4 = stuupwa4r6p = j56uuem5c4b
14 | del ozi1xls5irl
15 | import j56uuem5c4b
16 | b'' in 0.0
17 | async for iss31fgiec6 in (owoqq2r81rf := ozi1xls5irl):
18 | from stuupwa4r6p import ozi1xls5irl, r4mfejds1d4 as e9u01zfk5lh, b64jkd1qw0z, adqa8j00i8q as d60cbfao387, r4mfejds1d4, ozi1xls5irl as o0nivw17yvy
19 | assert ''
20 | import iss31fgiec6 as wme4lewmk12, wme4lewmk12 as xjb71zv5fqg, o0nivw17yvy
21 | pass
22 | continue
23 | break
24 | r4mfejds1d4.owoqq2r81rf: n2rw5o0_ibu = sl6bqcxwh3g
25 | False
26 | raise None
27 | mwsdpq37crn = rff8otu0myw = q744lreapf_ = xzsg25pn5bw = igqsd94p2x4 = qkxleheyu_o = t8j4qkavho3 = gk8c_p6is18 = r4mfejds1d4
28 | else:
29 | del e8m0xd0kbvx
30 | global owoqq2r81rf
31 | 0 .owoqq2r81rf //= e8m0xd0kbvx
32 | 0j[0] += wme4lewmk12
33 | import qkxleheyu_o, stuupwa4r6p as vsrjv34ecrq, sl6bqcxwh3g as pwwfecvfukw, igqsd94p2x4, qkxleheyu_o, iss31fgiec6 as tvskrpouyiy, qkxleheyu_o, mwsdpq37crn as cbcyh1a0isw
34 | continue
35 | global r4mfejds1d4
36 | False
37 | pass
38 | break
39 | try:
40 | raise t8j4qkavho3
41 | m460w3d2sjm = ''
42 | e9u01zfk5lh[0j]: None = igqsd94p2x4
43 | assert owoqq2r81rf
44 | from adqa8j00i8q import owoqq2r81rf, tvskrpouyiy as tz5gipltlcg
45 | del tvskrpouyiy
46 | pass
47 | from sl6bqcxwh3g import adqa8j00i8q as wj64n383w03, pwwfecvfukw, b64jkd1qw0z, igqsd94p2x4 as m9x8d_brcb2, cbcyh1a0isw as v0ezxz7bq01, r4mfejds1d4
48 | b''.m9x8d_brcb2: wj64n383w03 = n2rw5o0_ibu
49 | global wme4lewmk12
50 | except* (yield 0.0) as d72g739amja:
51 | raise b''
52 | sn3m3x92h8t = stuupwa4r6p
53 | rff8otu0myw.q744lreapf_ >>= ''
54 | del d72g739amja
55 | import tvskrpouyiy, pwwfecvfukw, vsrjv34ecrq as zg7yptztz5y, b64jkd1qw0z as yw5173o3n04, b64jkd1qw0z, qkxleheyu_o as oedi_4_u4mr, stuupwa4r6p, stuupwa4r6p
56 | assert None, v0ezxz7bq01
57 | continue
58 | False
59 | break
60 | import e8m0xd0kbvx, q744lreapf_ as ww77mwsdqe8, adqa8j00i8q as dp4ng79zg_x, n2rw5o0_ibu, vsrjv34ecrq as pha75rfng_a, xjb71zv5fqg, stuupwa4r6p, n2rw5o0_ibu as ff98c09yrgf, adqa8j00i8q as j0z0aikypoa
61 | match adqa8j00i8q(pha75rfng_a, 0.0, tz5gipltlcg, q744lreapf_=0, mwsdpq37crn=adqa8j00i8q, gk8c_p6is18=0j):
62 | case b'' if 0.0 % o0nivw17yvy:
63 | rc4ybrorlt3 = n1qjscf498h = tz5gipltlcg
64 | assert False, xzsg25pn5bw
65 | break
66 | del tvskrpouyiy
67 | from ww77mwsdqe8 import v0ezxz7bq01, rff8otu0myw as gq6a9efplsp, gk8c_p6is18, d60cbfao387 as x6e7chjmif5, dp4ng79zg_x, oedi_4_u4mr as zqcxv3pnr7n, wj64n383w03, m460w3d2sjm as v9r2xh2c74_, ww77mwsdqe8
68 | pass
69 | continue
70 | xkcw7273it4: '' = qkxleheyu_o
71 | raise 0j
72 | n2rw5o0_ibu[0] &= None
73 | case {0j: None, '': b'', **q744lreapf_}:
74 | ff98c09yrgf
75 | global o0nivw17yvy
76 | pass
77 | del tz5gipltlcg
78 | raise 0
79 | import ff98c09yrgf, sl6bqcxwh3g as eer2_awzvxs
80 | break
81 | assert d60cbfao387, n2rw5o0_ibu
82 | e773lvh7ye9 = s2wskspqubw = 0.0
83 | (ghx6vhg091d): None = n2rw5o0_ibu
84 | continue
85 | with False:
86 | 0.0
87 | mf2g99q33my ^= ozi1xls5irl
88 | from wme4lewmk12 import d60cbfao387, v9r2xh2c74_ as zq5vxx9b3ef, mwsdpq37crn as wsookixdihh, wsookixdihh, e8m0xd0kbvx as dx3qhmw8one, v0ezxz7bq01, sn3m3x92h8t as q33crm4ctrs
89 | global rc4ybrorlt3
90 | 0 .sl6bqcxwh3g: False = ww77mwsdqe8
91 | from m9x8d_brcb2 import zqcxv3pnr7n as v9tyf5oxpmq, j0z0aikypoa, tz5gipltlcg as zky2nv7x_3g, wme4lewmk12
92 | continue
93 | import b64jkd1qw0z, b64jkd1qw0z as w7kkz6n_ty7, xjb71zv5fqg as ekluthtvudg, v9tyf5oxpmq, r4mfejds1d4, w7kkz6n_ty7 as kikjuv3g1v6, zg7yptztz5y
94 | break
95 | pass
96 | with [w7kkz6n_ty7, b64jkd1qw0z, b'', '', mf2g99q33my], {qkxleheyu_o for fsubws9zk27 in None if 0j} as mrmy6h1mwaz:
97 | iss31fgiec6
98 | assert ozi1xls5irl
99 | global xkcw7273it4
100 | del gq6a9efplsp
101 | raise None
102 | m6vsa648znz = tvskrpouyiy
103 | vqv5y1n4o7e -= 0j
104 | q33crm4ctrs
105 | del ghx6vhg091d
106 | break
107 | (lambda nb7nlr22eru, jgv773b368g: ('', 0.0, eer2_awzvxs)).o0nivw17yvy: (q33crm4ctrs for y5nv91qitlf in qkxleheyu_o if {False: b'' for k5r_l841o7v in sn3m3x92h8t if r4mfejds1d4} if f'wzv2t3ch87q{0}gmvp78fierq{False}s6k508db933{s6k508db933}{fsubws9zk27}l5yi4_su1e5y4223s_784ic0mbb1xpgvy' if (b'' if 0.0 else sl6bqcxwh3g) for l2icuz3bh1v in adqa8j00i8q.r4mfejds1d4) = wj64n383w03
108 | while {None if 0 else igqsd94p2x4 for sj4duil0hib in {e9u01zfk5lh: rff8otu0myw, 0j: zg7yptztz5y, '': 0}}:
109 | assert ('' for a24tg2x2w7g in tvskrpouyiy if None)
110 |
111 | class dm9hs0exqh8:
112 | from xkcw7273it4 import dp4ng79zg_x, b64jkd1qw0z, yw5173o3n04 as pww1c1m6210, owoqq2r81rf as s836e6eo88x, y5nv91qitlf
113 | continue
114 | pass
115 | dghae4ztn5b = s836e6eo88x
116 | raise 0.0
117 | global v9tyf5oxpmq
118 | zky2nv7x_3g.rc4ybrorlt3 |= y5nv91qitlf
119 | import pwwfecvfukw, zqcxv3pnr7n as mxpnplwy4ir, m6vsa648znz, r4mfejds1d4 as dqbq7bt3s0p, s2wskspqubw, rc4ybrorlt3 as o9xfyjs8l_u, m6vsa648znz, k5r_l841o7v, vqv5y1n4o7e as qoqv83j3lvl
120 | import v0ezxz7bq01 as ry4u18ffe7s, tz5gipltlcg, t8j4qkavho3
121 | 0j
122 | from dm9hs0exqh8 import nb7nlr22eru, q744lreapf_ as c4f_kxa8jxl, dp4ng79zg_x, w7kkz6n_ty7 as ytvellnkm_b, stuupwa4r6p, sj4duil0hib as lw85fzg4qvi
123 | for st10j7i65fy in (yield from b''):
124 | ekluthtvudg.l5yi4_su1e5: False = rc4ybrorlt3
125 | pcvm5gyaemt **= iss31fgiec6
126 | pass
127 | raise 0
128 | global ytvellnkm_b
129 | dx1_yj_poj_ = v9r2xh2c74_
130 | assert 0.0
131 | break
132 | continue
133 | del l2icuz3bh1v
134 | else:
135 | continue
136 | break
137 | raise y5nv91qitlf
138 | import gmvp78fierq, sj4duil0hib as y3to7lx4rb1, pcvm5gyaemt, ytvellnkm_b as hv2v5ub0krr, o9xfyjs8l_u, mf2g99q33my, ekluthtvudg as hiknzgdzbiw, zq5vxx9b3ef as u1ednx0raid, pww1c1m6210
139 | False .c4f_kxa8jxl <<= dghae4ztn5b
140 | 0j
141 | (gv9zs51nck7): b'' = d60cbfao387
142 | swwsouxrfbj = hujg90i38hk = xna2g_rdia8 = wsbq1685t7w = rx0w_4k1lj8 = psm8ns1hl2c = f5rp768g0q4 = e0s_yjy_89x = l7k_5zqok75 = sib2opklrs8 = None
143 | pass
144 | del dqbq7bt3s0p
145 | assert hujg90i38hk('', o0nivw17yvy, c4f_kxa8jxl=None), await pww1c1m6210
146 | global dx1_yj_poj_
147 | with (yield gq6a9efplsp):
148 | from w7kkz6n_ty7 import n2rw5o0_ibu as cpf7bxjgktk
149 | global fsubws9zk27
150 | uithkt3896m %= 0.0
151 | import jgv773b368g, t8j4qkavho3, v9r2xh2c74_ as ev1vadvc7uv, iss31fgiec6 as h9563e13uco, gv9zs51nck7
152 | continue
153 | from k5r_l841o7v import qkxleheyu_o, wzv2t3ch87q as bjfdl3t0u5v, psm8ns1hl2c as wupxpybil0g, sib2opklrs8, gk8c_p6is18, dm9hs0exqh8 as qhqyds4gf65, dghae4ztn5b
154 | t3c3yl4x53f = lw85fzg4qvi
155 | del r4mfejds1d4
156 | assert 0
157 | pass
158 | (dwa6kpw6ony): sj4duil0hib[''] = xkcw7273it4 // False
159 | while b'':
160 | 0j
161 | break
162 | raise kikjuv3g1v6
163 | from vsrjv34ecrq import mxpnplwy4ir, bjfdl3t0u5v as kkv6rxik4wq, wsbq1685t7w, l5yi4_su1e5 as jh963tkphph
164 | fhw0kyw83xg = a0b7ip50k79 = lirpo3vz3x8 = None
165 | 0.0
166 | raise c4f_kxa8jxl
167 | import m460w3d2sjm as mukqj25ywy9, zqcxv3pnr7n as jwpik32rz1f, psm8ns1hl2c, s2wskspqubw, pwwfecvfukw as egxsrew7fp2, hv2v5ub0krr as mp6t75_at61, igqsd94p2x4, mxpnplwy4ir as x5qztb9ec5i, st10j7i65fy, gmvp78fierq
168 | (nt4o5389vih): 0 = ytvellnkm_b
169 | assert l5yi4_su1e5, b''
170 | else:
171 | False .a0b7ip50k79 @= gmvp78fierq
172 | pass
173 | del s6k508db933
174 | continue
175 | break
176 | global dp4ng79zg_x
177 | from xkcw7273it4 import pcvm5gyaemt, zg7yptztz5y, sl6bqcxwh3g as hv88r6ypand, j0z0aikypoa, hv2v5ub0krr as aokhvgcll8s, qhqyds4gf65 as s5iyymimp6a
178 | global e8m0xd0kbvx
179 | raise d60cbfao387
180 | break
181 | jwpik32rz1f
182 | b8sn2os54yz = {{0j, e9u01zfk5lh, '', 0, o0nivw17yvy, '', d72g739amja, yw5173o3n04, b'', False}: (hujg90i38hk, 0.0, x5qztb9ec5i, d60cbfao387, None, 0j) for r9t0xlzboh8 in (ljhq7p2ti1s := d72g739amja) if b'' for kfz8ug_e_xj in f'{gk8c_p6is18}nxvj2gvsudm{0.0}cayliek309v{ekluthtvudg}{0j}{jgv773b368g}{uithkt3896m}ztb3ss70hc0{None}' if [0 for x3k9ecx3jgs in x6e7chjmif5 if False] if ww77mwsdqe8 not in ''}
183 | for yhgs9h8ngy9 in {[oedi_4_u4mr, 0, zky2nv7x_3g, hiknzgdzbiw, 0j, None]}:
184 | with lambda l_3g7_f1jcl, tmi5cqn3nxy, cqqycrk921z, z2jzrg0z7pq, cfdxooipr_s, uezho48j317, flfzmjvwqhk: cpf7bxjgktk as aj1zhuytprt, ~z2jzrg0z7pq as dnw4nenn41g, (b'', owoqq2r81rf, False, 0.0, dghae4ztn5b, pwwfecvfukw, '', 0, gv9zs51nck7, b''):
185 | assert owoqq2r81rf, ev1vadvc7uv
186 | import tz5gipltlcg
187 | ''.iss31fgiec6 /= None
188 | del sib2opklrs8
189 | pass
190 | (kx6vtv2it7q): rc4ybrorlt3 = eer2_awzvxs
191 | del r9t0xlzboh8
192 | from a24tg2x2w7g import l5yi4_su1e5 as kwm1wbdmfos, jwpik32rz1f
193 | helkt8hptfg -= False
194 | continue
195 | assert lambda e0lu_8k7t9v, t_5yi76od_1, zo2vy1eu_vc: ghx6vhg091d
196 | async for g5bpo2t0793 in [0.0, d72g739amja]:
197 | raise 0j
198 | osbia2zt1tp = hv2v5ub0krr
199 | import wsookixdihh
200 | break
201 | global n1qjscf498h
202 | (z9mthql_7ny): 0.0 = False
203 | j0z0aikypoa
204 | pass
205 | ''.x3k9ecx3jgs: sl6bqcxwh3g = m6vsa648znz
206 | del u1ednx0raid
207 | global s5iyymimp6a
208 | continue
209 | (yield from None).aokhvgcll8s <<= await oedi_4_u4mr
210 | from kx6vtv2it7q import wzv2t3ch87q as pboghp36fx0, a24tg2x2w7g, g5bpo2t0793
211 | ymz7rw8oqhn = {b'' for t2tikye27jw in cayliek309v if 0j if z9mthql_7ny if lw85fzg4qvi}
212 | assert [0 for ji3uwn0uayd in q744lreapf_ for s10k447gwe_ in b'' if False if v9tyf5oxpmq if zq5vxx9b3ef]
213 | if 0:
214 | 0j
215 | raise None
216 | pass
217 | import uezho48j317 as dqsh5wh2w92, s6k508db933 as rmcf5npf95z, l2icuz3bh1v, tmi5cqn3nxy as tgk3bopwomh, swwsouxrfbj, l5yi4_su1e5 as o4qwvm7xnqd, m6vsa648znz
218 | break
219 | continue
220 | pass
221 | from kx6vtv2it7q import pcvm5gyaemt, wme4lewmk12 as ch_ph3gagrz, rc4ybrorlt3, x6e7chjmif5 as groitmuc6w9, x6e7chjmif5 as q60gbbtrht6, ev1vadvc7uv, hv88r6ypand as g2qrqvggi9e
222 | del tmi5cqn3nxy
223 | break
224 | with {e0lu_8k7t9v, yhgs9h8ngy9, '', 0.0, c4f_kxa8jxl, '', q744lreapf_, groitmuc6w9, 0j, nt4o5389vih}(not b'', t_5yi76od_1=False .wzv2t3ch87q, b8sn2os54yz=o9xfyjs8l_u > z9mthql_7ny, e9u01zfk5lh=wj64n383w03[None]) as c6oljvl29_x, (flfzmjvwqhk for fg9boku0oap in 0.0 if ozi1xls5irl for jmaofb1cjl9 in False) / (cayliek309v if 0j else b''):
225 | {vqv5y1n4o7e}.fg9boku0oap ^= mukqj25ywy9
226 | global dm9hs0exqh8
227 | match (yield ''):
228 | case False if {q33crm4ctrs: None}:
229 | 0j
230 | import gv9zs51nck7, rmcf5npf95z as j64o8_sphkf, stuupwa4r6p
231 | raise t_5yi76od_1
232 | assert 0, rx0w_4k1lj8
233 | wme4lewmk12[False]: flfzmjvwqhk = ''
234 | zk22f4ild08 = 0.0
235 | import zo2vy1eu_vc
236 | from zqcxv3pnr7n import t8j4qkavho3 as s06ng4eeiia, rx0w_4k1lj8, n1qjscf498h as u4jg0nnhs6m, kx6vtv2it7q as ignfn6bnst_, t2tikye27jw, y5nv91qitlf
237 | (thxobe51di7): b'' = dwa6kpw6ony
238 | kxl68_098sk = psm8ns1hl2c
239 | match dwa6kpw6ony:
240 | case bha8g3_q7y9 if (w1_juwcd_wm := 0):
241 | global m9x8d_brcb2
242 | del dghae4ztn5b
243 | ry4u18ffe7s[0j] &= None
244 | b''
245 | assert cpf7bxjgktk, pwwfecvfukw
246 | pass
247 | raise False
248 | dx1_yj_poj_[0.0]: '' = j56uuem5c4b
249 | xkcw7273it4
250 | pass
251 |
252 | @mp6t75_at61 if 0j else None
253 | @(jyy35lg9r5_ := eer2_awzvxs)
254 | @False(j0z0aikypoa, b'', g2qrqvggi9e, hiknzgdzbiw='', z9mthql_7ny=0.0, em8qm503o0w=cayliek309v)
255 | @{0}
256 | @(yield vqv5y1n4o7e)
257 | @zg7yptztz5y
258 | class t58di28mkkk(f'em8qm503o0wm1a1kz6515s{None}vurmq85cyhezdpxospod1x{0j}{m6vsa648znz}bu99miw2zte{j56uuem5c4b}{False}', {0: jwpik32rz1f for s8ah057o8hr in qkxleheyu_o if '' if b'' if fsubws9zk27 for jdxe_2jvsd1 in 0.0 for c2l8a3szw_9 in groitmuc6w9 if None if tvskrpouyiy if ji3uwn0uayd}, 0.0 < False == a0b7ip50k79):
259 | import w1_juwcd_wm, l2icuz3bh1v as gtu94sj313x
260 | assert x3k9ecx3jgs
261 | global sib2opklrs8
262 | del u1ednx0raid
263 | jciuc0h7qya = b''
264 | raise 0
265 | e0lu_8k7t9v.pwwfecvfukw |= x3k9ecx3jgs
266 | from mp6t75_at61 import e0lu_8k7t9v as s8ibu2s3prk, cqqycrk921z, c6oljvl29_x as gkyx45tyxi6, g5bpo2t0793
267 | assert ''
268 | m0io2dsoeoi: zky2nv7x_3g = hv2v5ub0krr
269 |
270 | class f2v6r68rklf({0j, f2v6r68rklf, 0, e0lu_8k7t9v}, '', rx0w_4k1lj8):
271 | r6e1nq409ey = False
272 | vurmq85cyhe
273 | global bjfdl3t0u5v
274 | pass
275 | lhny2o8uyrs @= None
276 | import u4jg0nnhs6m, n1qjscf498h, nb7nlr22eru as lgn4im7x65a, e9u01zfk5lh, zdpxospod1x as ts8dqxo37i8, n2rw5o0_ibu, s5iyymimp6a as ewol2c5jo55, sl6bqcxwh3g as ledizl_ecv3, u1ednx0raid
277 | from zqcxv3pnr7n import adqa8j00i8q
278 | del dx1_yj_poj_
279 | raise k5r_l841o7v
280 | del ch_ph3gagrz
281 | h506z90o968 += {0.0: 0j}
282 | for lr5f6wu2k_6 in -t58di28mkkk:
283 | from l_3g7_f1jcl import c6oljvl29_x, j64o8_sphkf, stuupwa4r6p as fzjj34_390n, yw5173o3n04 as w82zq6nhxv4, q33crm4ctrs
284 | pass
285 | ''
286 | evx_d5b0upd = jzna3_5nexa = jf2t2ykjl32 = n0yx2gqdt0y = csabf1r0pqq = w9cb50eeshi = i8yx3qiq8gg = gicr4f60ai7 = g6320bhpger = nig5sqvlhha = None
287 | assert ch_ph3gagrz, b''
288 | break
289 | (q57oo23qalq): 0.0 = zdpxospod1x
290 | global e9u01zfk5lh
291 | import cqqycrk921z as khu6_hi8ui8, vqv5y1n4o7e, ztb3ss70hc0, q57oo23qalq as wtg5ni43ls8, l_3g7_f1jcl
292 | raise n1qjscf498h
293 | else:
294 | pass
295 | vsrjv34ecrq
296 | global ljhq7p2ti1s
297 | raise 0
298 | import vqv5y1n4o7e as gcmn39yo8c0, cbcyh1a0isw, ghx6vhg091d as ooqbkn19df0, dx1_yj_poj_
299 | assert 0
300 | (lew29ewqq62): 0j = ry4u18ffe7s
301 | del zqcxv3pnr7n
302 | pyq0_q9th5g = ewol2c5jo55
303 | from stuupwa4r6p import vqv5y1n4o7e, dghae4ztn5b as f8zpwz5qc54
304 | try:
305 | vor7a1d0h_6 >>= mxpnplwy4ir
306 | global gicr4f60ai7
307 | pass
308 | del g5bpo2t0793
309 | ''.groitmuc6w9 **= t_5yi76od_1
310 | raise None
311 | import jh963tkphph, lw85fzg4qvi, zg7yptztz5y as losh5rbax00, uezho48j317, ljhq7p2ti1s as lxdj66958uh, g5bpo2t0793 as flexl9omwj0, jyy35lg9r5_
312 | wdvk4ighadb = mvu_wx3or1w = p2wmxiamgs2 = lhxj1yvibmp = vlknyfvmyls = naujsum571b = nomlxpc3hlv = adqjyul1tmb = False
313 | zq5vxx9b3ef
314 | (h13pq_zaurf): r9t0xlzboh8 = b''
315 | except {s6k508db933: 0.0 for ps9d215n001 in b'' if dwa6kpw6ony if nomlxpc3hlv if 0j} as as5klbea4uz:
316 | from lhxj1yvibmp import gmvp78fierq, ytvellnkm_b as j4kkturivgi, owoqq2r81rf as cf5qxvdl629
317 | assert None
318 | pass
319 | assert dqbq7bt3s0p, ''
320 | qoqv83j3lvl
321 | import dp4ng79zg_x, tvskrpouyiy, kx6vtv2it7q as d0ujnhwvs2w, jzna3_5nexa
322 | from z9mthql_7ny import s8ibu2s3prk as fdub4b1a3p_, zo2vy1eu_vc as bnc33fegodk, y4223s_784i, g2qrqvggi9e, fhw0kyw83xg as wzipmh_us4k, gkyx45tyxi6 as okaaa53ktzf, qkxleheyu_o
323 | del w9cb50eeshi
324 | iz4h1nzg5x8 *= fdub4b1a3p_
325 | global gq6a9efplsp
326 | except [0.0, False, w1_juwcd_wm, hv2v5ub0krr, 0, cpf7bxjgktk, 0, False]:
327 | wk_95owxlkm = wme4lewmk12
328 | raise nt4o5389vih
329 | 0.0.o9xfyjs8l_u: '' = q57oo23qalq
330 | global o4qwvm7xnqd
331 | eer2_awzvxs
332 | pass
333 | del s2wskspqubw
334 | 0j[b''] //= stuupwa4r6p
335 | dl4q1ccr0o7 = gq6a9efplsp
336 | from o9xfyjs8l_u import y5nv91qitlf, nxvj2gvsudm, tvskrpouyiy as k8m6ermkqz_, ch_ph3gagrz as pvwqup5iqbq, f5rp768g0q4
337 | else:
338 | None[None]: rmcf5npf95z = False
339 | import vurmq85cyhe as u0px4icce0p, pcvm5gyaemt, j64o8_sphkf as kt7jfh9rl15, jdxe_2jvsd1 as m8x21lligl6
340 | raise ''
341 | assert aokhvgcll8s
342 | pass
343 | raise rx0w_4k1lj8
344 | ym7z7qw022s /= b''
345 | del rff8otu0myw
346 | import hiknzgdzbiw, psm8ns1hl2c as n2oigs1v6qt, cfdxooipr_s, wk_95owxlkm, iz4h1nzg5x8 as rwwr5cbnq9n, ozi1xls5irl as uw9r_v0r6ta, cqqycrk921z, s2wskspqubw as qh_cmqbmoyy, aokhvgcll8s
347 | xawp6dtqrcy = 0j
348 | assert (u0px4icce0p, 0.0, cbcyh1a0isw, w1_juwcd_wm, 0, None, s8ah057o8hr, b'', e9u01zfk5lh, q57oo23qalq)
349 | async with lambda mietjgxusai, rvfeu_2_82m, r12we63jiqz: 0j[False], {kx6vtv2it7q for iigxzj3c3j5 in 0.0 if vqv5y1n4o7e if 0 if '' for sf4mky85ouq in rx0w_4k1lj8 if nxvj2gvsudm for c_6lxxujv6q in 0j if mukqj25ywy9 if b''}.thxobe51di7:
350 | try:
351 | hoievan1rvn: '' = psm8ns1hl2c
352 | global ts8dqxo37i8
353 | d60cbfao387
354 | from wj64n383w03 import rx0w_4k1lj8, m9x8d_brcb2 as w9ve8d1zm3_, rc4ybrorlt3, hoievan1rvn, s2wskspqubw as ccezh1ewx1i, pww1c1m6210 as bylne2m33ud, ts8dqxo37i8, xawp6dtqrcy as z47s9pyfwxh, as5klbea4uz, jmaofb1cjl9
355 | raise None
356 | assert xkcw7273it4, 0
357 | v0ezxz7bq01
358 | mz_g9tyak26 %= y4223s_784i
359 | global sj4duil0hib
360 | pass
361 | except await 0.0:
362 | import sj4duil0hib, jgv773b368g as nux_x4e7jps
363 | xpjutbj8ky9 = False
364 | from s836e6eo88x import dwa6kpw6ony, s8ibu2s3prk as bqj84_qdnnt, gq6a9efplsp, bylne2m33ud as ax3jnwv3d42, lr5f6wu2k_6, jwpik32rz1f, bylne2m33ud as zf_gk2c62ye
365 | v9tyf5oxpmq.egxsrew7fp2: b'' = aokhvgcll8s
366 | del ji3uwn0uayd
367 | from cbcyh1a0isw import s10k447gwe_, tgk3bopwomh, jdxe_2jvsd1 as cbvazddwdpt, dx3qhmw8one as jjveg6uz3ky, ljhq7p2ti1s, gcmn39yo8c0, mwsdpq37crn as agvyrf6z4we, lirpo3vz3x8
368 | del pvwqup5iqbq
369 | assert qoqv83j3lvl, 0
370 | pass
371 | global a0b7ip50k79
372 | finally:
373 | d72g739amja
374 | raise ry4u18ffe7s
375 | import hv2v5ub0krr, ccezh1ewx1i as hy_pfrrplcz, p2wmxiamgs2, ts8dqxo37i8 as fi7b2s1rs7s, egxsrew7fp2, cbvazddwdpt as ay82xr1ukbs, gmvp78fierq as je3yzh0hs1t, qkxleheyu_o
376 | z9s97pgxohk = yqalyvt87iv = 0.0
377 | uetikbg_mvi //= ''
378 | ccezh1ewx1i.qhqyds4gf65: r12we63jiqz = m460w3d2sjm
379 | raise None
380 | False
381 | btxlwhsu2jd = ryr2d9v8owl = be5n4ptiseo = xqnai0onv3l = aj88o8hol1s = zo2vy1eu_vc
382 | zg7yptztz5y.nux_x4e7jps *= 0j
383 | import g5bpo2t0793, wsookixdihh as ga70jaesyro, b8sn2os54yz, nomlxpc3hlv as xyzvn1fotdf, l2icuz3bh1v, ledizl_ecv3 as o5il0klocll, hujg90i38hk as b90km2c52df
384 | with [0.0 for n5zanflvaf5 in fi7b2s1rs7s if iss31fgiec6 if False], f'{''}wu9_9amkasf{e8m0xd0kbvx}h7jih5rzrznej7v2_tinc2{b''}{agvyrf6z4we}{j0z0aikypoa}{0}{rmcf5npf95z}' as omrefdyzdpn, (yield from None):
385 | from c2l8a3szw_9 import tmi5cqn3nxy, mvu_wx3or1w as he5z5ps3iqv, zdpxospod1x, lgn4im7x65a as tv4ax2ye8i7, a0b7ip50k79 as wg7iglvw1j3
386 | del mxpnplwy4ir
387 | assert ps9d215n001
388 | pass
389 | 0j.dqsh5wh2w92: ch_ph3gagrz = nxvj2gvsudm
390 | global omrefdyzdpn
391 | pass
392 | 0.0
393 | import l5yi4_su1e5, vor7a1d0h_6 as fp0atc_2_12, iigxzj3c3j5, losh5rbax00, adqa8j00i8q as vxm4mw69j33, ay82xr1ukbs as x0utw0pi62q, c4f_kxa8jxl, he5z5ps3iqv
394 | m0z88tho37_ = False
395 | (igqsd94p2x4 for p17zx55j3yy in 0 if ljhq7p2ti1s for rgv4e8xcvmf in 0j).qh_cmqbmoyy /= helkt8hptfg ^ hiknzgdzbiw
396 | del rvfeu_2_82m
397 | if {'', None, n5zanflvaf5}:
398 | assert flfzmjvwqhk
399 | from aokhvgcll8s import ztb3ss70hc0 as f5htjbapwee, hv2v5ub0krr, gv9zs51nck7 as rplg3ic2vo9, fg9boku0oap as lnleyjsfg3g, cfdxooipr_s, e9u01zfk5lh, v9tyf5oxpmq as rnctcq4u4t5
400 | raise b''
401 | global rvfeu_2_82m
402 | (hb3416l1uc0): c4f_kxa8jxl = b''
403 | import k5r_l841o7v as z7gbbthiyfu, sib2opklrs8, qhqyds4gf65 as vmry3gmsxsk, uw9r_v0r6ta, mietjgxusai as tg3cg7nfh1i, cbcyh1a0isw, n2oigs1v6qt, s836e6eo88x as pvtmoru5x3s, n2oigs1v6qt as puep3tko1ep, sl6bqcxwh3g
404 | del qhqyds4gf65
405 | raise False
406 | pass
407 | global yw5173o3n04
408 | match 0j if d72g739amja else khu6_hi8ui8:
409 | case 0.0 | l1c1dwf0lt7 | wzg002nbh97.llxo6yxsvre if None:
410 | (chvnwwps9ry): as5klbea4uz = 0
411 | y_kdr8nhjnl = tvskrpouyiy
412 | from l5yi4_su1e5 import wj64n383w03, r4mfejds1d4, j0z0aikypoa as jntzp0qf0so, zk22f4ild08, hb3416l1uc0 as avaqs699fkt, iigxzj3c3j5 as xdh4mru7so5, u1ednx0raid
413 | ''
414 | rx0w_4k1lj8.d0ujnhwvs2w **= ''
415 | assert i8yx3qiq8gg, b''
416 | del cayliek309v
417 | import wtg5ni43ls8, hb3416l1uc0, stuupwa4r6p as vdmqhpnx4ie, cfdxooipr_s as vs66sbzf4n4, iigxzj3c3j5
418 | assert None
419 | qgwuyg8n67b = s8ah057o8hr
420 |
421 | @b'' >> lnleyjsfg3g
422 | @None[fg9boku0oap:False:n1qjscf498h]
423 | def zo9kah0g57e(c6tv6ua8z3f: wtg5ni43ls8, st9ahnanzpu, owjffj6epvx, socjywcem1l: ryr2d9v8owl, zj578lc2jqb: wk_95owxlkm, wsawiqop4ez, fhzeoq9rf_k: mf2g99q33my, cj1p4htdhcy, a96bl_c6wcq: cj1p4htdhcy):
424 | raise hv2v5ub0krr
425 | (m0xjk6tf5zu): 0.0 = 0
426 | g2qrqvggi9e
427 | from mvu_wx3or1w import flfzmjvwqhk as zf6iza57y1g, ignfn6bnst_, n2oigs1v6qt as m579ta6728h
428 | global b90km2c52df
429 | pass
430 | lnleyjsfg3g[False] >>= 0j
431 | return ax3jnwv3d42
432 | pass
433 | del t2tikye27jw
434 | try:
435 | global lhxj1yvibmp
436 | zdyp3gncot4: 0j = psm8ns1hl2c
437 | fdub4b1a3p_[''] &= 0.0
438 | cayliek309v
439 | raise 0
440 | from r9t0xlzboh8 import ignfn6bnst_, zf6iza57y1g as rsm2yj5y4_9
441 | import avaqs699fkt, zo2vy1eu_vc as thmdb5mj_da, adqjyul1tmb as lj17b9hev75, vs66sbzf4n4, a96bl_c6wcq, owjffj6epvx as ls4nsh52c52
442 | assert 0.0, llxo6yxsvre
443 | nsw09zjry5h = tjtswqplthe = bm7wm41vrq2 = ai598802x1t = qhsar04g9h8 = wr5dt4ku6x9 = wr5dt4ku6x9
444 | raise 0j
445 | except await vdmqhpnx4ie as q4_e519i70t:
446 | assert 0
447 | import gkyx45tyxi6, q744lreapf_ as zfjfh3usxqu, gq6a9efplsp as qre0e1c3i9j, ts8dqxo37i8, cj1p4htdhcy as pcdntz__1_l, uw9r_v0r6ta, g5bpo2t0793 as gxuv125em_z, aj1zhuytprt, dwa6kpw6ony
448 | q4k8eu5nn4r ^= ''
449 | del groitmuc6w9
450 | global jgv773b368g
451 | kt7jfh9rl15.pcvm5gyaemt: False = zdpxospod1x
452 | pass
453 | p850prhfubm = wsbq1685t7w
454 | None
455 | from nux_x4e7jps import osbia2zt1tp, gmvp78fierq as t37hfzpmiqv, t8j4qkavho3, f5rp768g0q4 as e3r1e7txrjq, bjfdl3t0u5v as sypvelvakx4, n2oigs1v6qt, vxm4mw69j33 as aln2eghvzf8, dp4ng79zg_x, a24tg2x2w7g as xgzlf1uffgu
456 | finally:
457 | assert k5r_l841o7v
458 | pfkzec7x4d_ = b''
459 | False[0.0] @= hoievan1rvn
460 | from oedi_4_u4mr import c6tv6ua8z3f as v7s8uk70h9f, f8zpwz5qc54
461 | 0 .s6k508db933: dx3qhmw8one = avaqs699fkt
462 | ''
463 | del wupxpybil0g
464 | global g2qrqvggi9e
465 | pass
466 | raise None
467 | import ozi1xls5irl as wa7yfltjtcp, n2rw5o0_ibu, xna2g_rdia8 as t8lmp9ih9xu
468 | with {zo2vy1eu_vc: ledizl_ecv3 for j9zfoe0gb93 in 0j if b'' if u0px4icce0p if False} <= (lambda l_qm7dbwwc5, dqrgwdpg4aw, nqbihhb3b23, vz_bi45n4q6, hg5lum7lmc7, ku5hb5f4j28, ggz5v81oazr, hvuxjelvfb2, gk7u3usy9vs: d72g739amja) >= (o9xfyjs8l_u, None, 0, mf2g99q33my) as oetmtusvms3:
469 |
470 | class vn1c6qfsxyu:
471 | pass
472 | ''
473 | raise mxpnplwy4ir
474 | import jh963tkphph as g01_ihf0xse, xpjutbj8ky9 as cwucxs1jbfz, qre0e1c3i9j, osbia2zt1tp as yzck6f9tqcz, xawp6dtqrcy, w1_juwcd_wm
475 | al9c66wdt14 -= b''
476 | del je3yzh0hs1t
477 | xs9_w76qgdc = kthv1mgc4iz = f8iwq4kicwb = k01t2b879o1 = d59j77cl9g3 = pr6x3k23055 = rolc6apto2g = ga70jaesyro
478 | (zzk0sgv0zb7): l7k_5zqok75 = 0j
479 | assert g5bpo2t0793, 0.0
480 | from mxpnplwy4ir import fi7b2s1rs7s as byk_7xe6d1u, qre0e1c3i9j, s06ng4eeiia, dwa6kpw6ony as ddpcw6t_fjv, je3yzh0hs1t
481 | match (n1qjscf498h for qmw2e_w2mvx in False for spp1q494kzg in 0.0):
482 | case [0, True, None, *_]:
483 | global t2tikye27jw
484 | pass
485 | from hiknzgdzbiw import wtg5ni43ls8 as j0gn61f1efk, x6e7chjmif5 as ap228ed0_k6, cj1p4htdhcy, al9c66wdt14 as mgkkethw9w0, osbia2zt1tp, ledizl_ecv3 as vukel6iovq9, n0yx2gqdt0y, agvyrf6z4we
486 | assert m1a1kz6515s, None
487 | je76cjnyb99 = q4_e519i70t
488 | raise b''
489 | rgv4e8xcvmf.lj17b9hev75: f5htjbapwee = 0j
490 | import m8x21lligl6, y5nv91qitlf as iaykpjo_2yl, lhxj1yvibmp as v78vdlvb5ij, jwpik32rz1f, egxsrew7fp2, vn1c6qfsxyu as j90l2c9ddzo
491 | v9r2xh2c74_
492 | ''.ewol2c5jo55 |= t2tikye27jw
493 | with ''.yhgs9h8ngy9 as l46c9tw2zn7, [qmw2e_w2mvx for p7p54c601b2 in b'' if lj17b9hev75 if 0.0 for gra5wh53k22 in ts8dqxo37i8 if False]:
494 | global v9tyf5oxpmq
495 | del zf_gk2c62ye
496 | (cyhyt_ylpoj): zq5vxx9b3ef = None
497 | from q33crm4ctrs import q60gbbtrht6 as g764s94xcg2, rplg3ic2vo9, z9mthql_7ny, l5yi4_su1e5 as li_gja9_ht9, adqjyul1tmb, mgkkethw9w0 as rnusr7j4tai, r6e1nq409ey, r4mfejds1d4 as mijdzvh56ml
498 | del thxobe51di7
499 | pass
500 | raise 0j
501 | import x3k9ecx3jgs, pyq0_q9th5g as voueiuslcsg, t2tikye27jw, kt7jfh9rl15 as t1bvna2zq92, nux_x4e7jps, h506z90o968 as po8uoqdpk7h
502 | r9t0xlzboh8.cwucxs1jbfz += ai598802x1t
503 | vt7akg7mxt7 = 0
504 | yield from b''
505 | global gq6a9efplsp
506 | assert [m9x8d_brcb2, n0yx2gqdt0y, False, jf2t2ykjl32, None, m460w3d2sjm, 0.0, sypvelvakx4]
507 | del rx0w_4k1lj8
508 | pass
509 | if (us6jdkcw40g := 0):
510 | assert c_6lxxujv6q, 0j
511 | gyzks8ae1sy = bha8g3_q7y9
512 | ''.xqnai0onv3l: 0.0 = agvyrf6z4we
513 | global po8uoqdpk7h
514 | import nsw09zjry5h, rx0w_4k1lj8 as ppnq0zpuk4w, eer2_awzvxs, tvskrpouyiy as r5nsn7l3vjr
515 | z13v6nua8g_ %= ''
516 | j9zfoe0gb93
517 | raise 0j
518 | from cayliek309v import aj88o8hol1s, xjb71zv5fqg, rvfeu_2_82m as l2uzv6m9wgy, wsookixdihh as rcactxle2_3, f5rp768g0q4, hoievan1rvn, he5z5ps3iqv as ed02d0ibere, i8yx3qiq8gg as cmnlwyrse5e, lgn4im7x65a
519 | bdgnj1q6foh = nxvj2gvsudm
520 | async with (yield jf2t2ykjl32) as sxt0grc1rok:
521 | raise 0
522 | d72g739amja.a96bl_c6wcq <<= False
523 | pass
524 | global zg7yptztz5y
525 | dghae4ztn5b[None]: cj1p4htdhcy = b''
526 | None
527 | from kkv6rxik4wq import pyq0_q9th5g as bzgqj66aoyn, jh963tkphph, gmvp78fierq as a51virub46x
528 | import o4qwvm7xnqd, as5klbea4uz as wzwm3bcywad, k01t2b879o1 as whiozynq7y_
529 | del b8sn2os54yz
530 | assert 0
531 | xxwb0z6tq9i = {not m1a1kz6515s}
532 | {False for yc3oer5o936 in vurmq85cyhe if bdgnj1q6foh if '' if b'' for kud_xk90olp in jgv773b368g if xpjutbj8ky9 if 0j}(h506z90o968, f'{0.0}{ymz7rw8oqhn}jxgvicggyfu{b''}o1wsiqbge_5fbqjpok7zxw{kud_xk90olp}{None}udockmn3pgfg3j4o18g67y', {l5yi4_su1e5: e3r1e7txrjq, l2uzv6m9wgy: 0, 0j: jntzp0qf0so, 0.0: '', m0z88tho37_: us6jdkcw40g, False: kwm1wbdmfos}, l1c1dwf0lt7=None, zk22f4ild08=hy_pfrrplcz - b'', b8sn2os54yz=(0, a51virub46x, al9c66wdt14, '', zk22f4ild08, 0.0, bnc33fegodk, 0j))
--------------------------------------------------------------------------------
/src/spew/generate.py:
--------------------------------------------------------------------------------
1 | import ast
2 | import random as _random
3 | import sys
4 | from contextlib import contextmanager
5 | import typing
6 | from spew.names import generate as make_name
7 | import logging
8 | import enum
9 | from spew.randomcycle import rcycle
10 |
11 | logging.basicConfig(level=logging.INFO)
12 | logger = logging.getLogger(__name__)
13 | MAX_DEPTH = 3
14 | DEFAULT_WIDTH = 20
15 |
16 |
17 | class GeneratorConstraints(enum.Flag):
18 | ANY = enum.auto()
19 | ONLY_IN_LOOPS = enum.auto()
20 | ONLY_IN_FUNCTIONS = enum.auto()
21 |
22 |
23 | OPERATORS = [
24 | ast.Add,
25 | ast.BitAnd,
26 | ast.BitOr,
27 | ast.BitXor,
28 | ast.Div,
29 | ast.FloorDiv,
30 | ast.LShift,
31 | ast.Mod,
32 | ast.Mult,
33 | ast.MatMult,
34 | ast.Pow,
35 | ast.RShift,
36 | ast.Sub,
37 | ]
38 | CMPOPS = [
39 | ast.Eq,
40 | ast.NotEq,
41 | ast.Lt,
42 | ast.LtE,
43 | ast.Gt,
44 | ast.GtE,
45 | ast.Is,
46 | ast.IsNot,
47 | ast.In,
48 | ast.NotIn,
49 | ]
50 |
51 |
52 | class Context:
53 | depth: int
54 | in_loop: bool
55 | names: list[str]
56 | max_depth: int = MAX_DEPTH
57 | width: int = DEFAULT_WIDTH
58 |
59 | def __init__(self):
60 | self.depth = 0
61 | self.width = DEFAULT_WIDTH
62 | self.in_loop = False
63 | self.in_function = False
64 | self.names = []
65 |
66 | @contextmanager
67 | def nested(self):
68 | if self.depth + 1 > self.max_depth:
69 | logger.debug("Max depth exceeded", stack_info=True)
70 | self.depth += 1
71 | yield
72 | self.depth -= 1
73 |
74 | @contextmanager
75 | def inloop(self):
76 | _prev_state = self.in_loop
77 | self.in_loop = True
78 | yield
79 | self.in_loop = _prev_state
80 |
81 | @contextmanager
82 | def infunction(self):
83 | _prev_state = self.in_function
84 | self.in_function = True
85 | yield
86 | self.in_function = _prev_state
87 |
88 |
89 | def make_text(ctx: Context) -> str:
90 | return make_name(ctx, new=True) # TODO : Do better
91 |
92 |
93 | boolcycle = rcycle([True, False])
94 |
95 |
96 | def randbool(ctx: Context) -> bool:
97 | return next(boolcycle)
98 |
99 |
100 | T = typing.TypeVar("T")
101 |
102 |
103 | def randchoice(ctx: Context, choices: typing.Sequence[T]) -> T:
104 | return _random.choice(choices)
105 |
106 |
107 | def randint(ctx: Context, a: int, b: int) -> int:
108 | # TODO: Use context for reproducible results
109 | return _random.randint(a, b)
110 |
111 |
112 | def generate_arg(ctx: Context, allow_annotations=False) -> ast.arg:
113 | arg = ast.arg()
114 | arg.arg = make_name(ctx, new=True)
115 | if randbool(ctx) and allow_annotations:
116 | arg.annotation = generate_name(ctx)
117 | return arg
118 |
119 |
120 | TFunc = typing.TypeVar("TFunc", ast.FunctionDef, ast.AsyncFunctionDef)
121 |
122 |
123 | def _generate_function(f: TFunc, ctx: Context) -> TFunc:
124 | f.args = ast.arguments()
125 | n_args = randint(ctx, 0, ctx.width)
126 | f.args.args = [generate_arg(ctx, True) for _ in range(n_args)]
127 | f.args.posonlyargs = []
128 | f.args.kwonlyargs = []
129 | if randbool(ctx):
130 | f.args.defaults = [
131 | generate_constant(ctx, values_only=True) for _ in range(n_args)
132 | ]
133 | else:
134 | f.args.defaults = []
135 | f.name = make_name(ctx, new=True)
136 | with ctx.infunction():
137 | f.body = generate_nested_stmts(ctx)
138 | if randbool(ctx):
139 | f.decorator_list = []
140 | else:
141 | f.decorator_list = [
142 | generate_expr(ctx) for _ in range(randint(ctx, 1, 3))
143 | ] # TODO: vary length
144 | f.lineno = 1
145 | return f
146 |
147 |
148 | def generate_function(ctx: Context) -> ast.FunctionDef:
149 | f = ast.FunctionDef()
150 | return _generate_function(f, ctx)
151 |
152 |
153 | def generate_asyncfunction(ctx: Context) -> ast.AsyncFunctionDef:
154 | f = ast.AsyncFunctionDef()
155 | return _generate_function(f, ctx)
156 |
157 |
158 | def generate_class(ctx: Context) -> ast.ClassDef:
159 | c = ast.ClassDef()
160 | c.name = make_name(ctx, new=True)
161 | if randbool(ctx): # 50/50 chance of no bases
162 | c.bases = []
163 | else:
164 | c.bases = [generate_expr(ctx) for _ in range(randint(ctx, 0, 3))]
165 | c.keywords = []
166 | c.body = generate_nested_stmts(ctx)
167 | if randbool(ctx): # 50/50 chance of no decorator list
168 | c.decorator_list = []
169 | else:
170 | c.decorator_list = [
171 | generate_expr(ctx) for _ in range(randint(ctx, 1, ctx.width))
172 | ]
173 | c.lineno = 1
174 | return c
175 |
176 |
177 | def generate_ellipsis(ctx: Context) -> ast.Ellipsis:
178 | return ast.Ellipsis()
179 |
180 |
181 | def generate_pass(ctx: Context) -> ast.Pass:
182 | return ast.Pass()
183 |
184 |
185 | def generate_break(ctx: Context) -> ast.Break:
186 | return ast.Break()
187 |
188 |
189 | def generate_continue(ctx: Context) -> ast.Continue:
190 | return ast.Continue()
191 |
192 |
193 | gen_cycle = rcycle([ast.Load, ast.Store, ast.Del])
194 |
195 |
196 | def generate_attribute(ctx: Context) -> ast.Attribute:
197 | a = ast.Attribute()
198 | a.value = generate_expr(ctx)
199 | a.attr = make_name(ctx)
200 | a.ctx = next(gen_cycle)()
201 | return a
202 |
203 |
204 | generate_subscript_ctx = rcycle([ast.Load, ast.Store, ast.Del])
205 |
206 |
207 | def generate_subscript(ctx: Context) -> ast.Subscript:
208 | s = ast.Subscript()
209 | s.value = generate_expr(ctx)
210 | if randbool(ctx):
211 | s.slice = generate_constant(ctx) # TODO : Generate Tuple elts slice
212 | else:
213 | s.slice = generate_slice(ctx)
214 | s.ctx = next(generate_subscript_ctx)()
215 | return s
216 |
217 |
218 | def generate_assign(ctx: Context) -> ast.Assign:
219 | asgn = ast.Assign()
220 | asgn.lineno = 1
221 | if randbool(ctx):
222 | asgn.targets = [generate_name(ctx, new=True)]
223 | else:
224 | asgn.targets = [
225 | generate_name(ctx, new=True) for _ in range(randint(ctx, 1, ctx.width))
226 | ]
227 | asgn.value = generate_expr(ctx)
228 | return asgn
229 |
230 |
231 | operators_cycle = rcycle(OPERATORS)
232 |
233 |
234 | def generate_augassign(ctx: Context) -> ast.AugAssign:
235 | asgn = ast.AugAssign()
236 | asgn.lineno = 1
237 | if randbool(ctx):
238 | asgn.target = generate_name(ctx, new=True)
239 | else:
240 | if randbool(ctx):
241 | asgn.target = generate_attribute(ctx)
242 | else:
243 | asgn.target = generate_subscript(ctx)
244 | asgn.value = generate_expr(ctx)
245 | asgn.op = next(operators_cycle)()
246 | return asgn
247 |
248 |
249 | def generate_annassign(ctx: Context) -> ast.AnnAssign:
250 | asgn = ast.AnnAssign()
251 | asgn.lineno = 1
252 | if randbool(ctx):
253 | asgn.target = generate_name(ctx, new=True)
254 | else:
255 | if randbool(ctx):
256 | asgn.target = generate_attribute(ctx)
257 | else:
258 | asgn.target = generate_subscript(ctx)
259 |
260 | # simple is a boolean integer set to True for a Name node in target
261 | # that do not appear in between parenthesis and are hence pure names
262 | # and not expressions.
263 | if randbool(ctx):
264 | asgn.simple = 1
265 | asgn.value = generate_name(ctx)
266 | else:
267 | asgn.simple = 0
268 | # value is a single optional node
269 | asgn.value = generate_expr(ctx)
270 | asgn.annotation = generate_expr(ctx)
271 | return asgn
272 |
273 |
274 | def generate_import(ctx: Context) -> ast.Import:
275 | im = ast.Import()
276 | im.names = []
277 | for _ in range(randint(ctx, 1, ctx.width)):
278 | alias = ast.alias()
279 | alias.name = make_name(ctx)
280 | if randbool(ctx):
281 | alias.asname = make_name(ctx, new=True)
282 |
283 | im.names.append(alias)
284 | return im
285 |
286 |
287 | def generate_importfrom(ctx: Context) -> ast.ImportFrom:
288 | im = ast.ImportFrom()
289 | im.module = make_name(ctx)
290 | im.names = []
291 | for _ in range(randint(ctx, 1, ctx.width)):
292 | alias = ast.alias()
293 | alias.name = make_name(ctx)
294 | if randbool(ctx):
295 | alias.asname = make_name(ctx, new=True)
296 |
297 | im.names.append(alias)
298 | return im
299 |
300 |
301 | def generate_name(ctx: Context, new: bool = False) -> ast.Name:
302 | name = ast.Name()
303 | name.id = make_name(ctx, new=new)
304 | return name
305 |
306 |
307 | constant_values_cycle = rcycle(
308 | [None, str(), bytes(), bool(), int(), float(), complex()]
309 | )
310 | constant_values_with_ellipsis_cycle = rcycle(
311 | [None, str(), bytes(), bool(), int(), float(), complex(), Ellipsis]
312 | )
313 |
314 |
315 | def generate_constant(ctx: Context, values_only=False) -> ast.Constant:
316 | c = ast.Constant()
317 | c.value = next(constant_values_cycle)
318 | return c
319 |
320 |
321 | def generate_str_constant(ctx: Context) -> ast.Constant:
322 | c = ast.Constant()
323 | c.value = str(make_text(ctx))
324 | return c
325 |
326 |
327 | def generate_return(ctx: Context) -> ast.Return:
328 | r = ast.Return()
329 | if randbool(ctx):
330 | r.value = generate_expr(ctx)
331 | return r
332 |
333 |
334 | def generate_delete(ctx: Context) -> ast.Delete:
335 | d = ast.Delete()
336 | # TODO : Is expr, but jst doing name
337 | d.targets = [generate_name(ctx)] # TODO: Vary targets
338 | return d
339 |
340 |
341 | def generate_raise(ctx: Context) -> ast.Raise:
342 | r = ast.Raise()
343 | r.exc = generate_expr(ctx)
344 | return r
345 |
346 |
347 | def generate_global(ctx: Context) -> ast.Global:
348 | g = ast.Global()
349 | g.names = [make_name(ctx)] # TODO: Vary length
350 | return g
351 |
352 |
353 | def generate_nonlocal(ctx: Context) -> ast.Nonlocal:
354 | n = ast.Nonlocal()
355 | n.names = [make_name(ctx)] # TODO: Vary length
356 | return n
357 |
358 |
359 | TFor = typing.TypeVar("TFor", ast.For, ast.AsyncFor)
360 |
361 |
362 | def _generate_for(ctx: Context, f: TFor) -> TFor:
363 | # TODO : Set tuple or collection as target
364 | f.target = generate_name(ctx, new=True) # Can be expr, but just doing name
365 | f.iter = generate_expr(ctx)
366 | f.lineno = 1
367 | with ctx.inloop():
368 | f.body = generate_nested_stmts(ctx)
369 | if randbool(ctx):
370 | f.orelse = generate_nested_stmts(ctx)
371 | else:
372 | f.orelse = [] # TODO: Raise bug report about this?
373 | return f
374 |
375 |
376 | def generate_for(ctx: Context) -> ast.For:
377 | return _generate_for(ctx, ast.For())
378 |
379 |
380 | def generate_asyncfor(ctx: Context) -> ast.AsyncFor:
381 | return _generate_for(ctx, ast.AsyncFor())
382 |
383 |
384 | def generate_while(ctx: Context) -> ast.While:
385 | w = ast.While()
386 | w.test = generate_expr(ctx)
387 | w.lineno = 1
388 | with ctx.inloop():
389 | w.body = generate_nested_stmts(ctx)
390 | if randbool(ctx):
391 | w.orelse = generate_nested_stmts(ctx)
392 | else:
393 | w.orelse = []
394 | return w
395 |
396 |
397 | def generate_if(ctx: Context) -> ast.If:
398 | i = ast.If()
399 | i.test = generate_expr(ctx)
400 | i.lineno = 1
401 | i.body = generate_nested_stmts(ctx)
402 | if randbool(ctx):
403 | i.orelse = generate_nested_stmts(ctx)
404 | else:
405 | i.orelse = []
406 | return i
407 |
408 |
409 | TWith = typing.TypeVar("TWith", ast.With, ast.AsyncWith)
410 |
411 |
412 | def _generate_with(ctx: Context, w: TWith) -> TWith:
413 | w.lineno = 1
414 | w.items = []
415 | for _ in range(randint(ctx, 1, 3)): # TODO: Vary length
416 | withitem = ast.withitem()
417 | withitem.context_expr = generate_expr(ctx)
418 | if randbool(ctx):
419 | withitem.optional_vars = generate_name(
420 | ctx, new=True
421 | ) # TODO : Can be expr, but just doing name
422 | w.items.append(withitem)
423 | w.body = generate_nested_stmts(ctx)
424 | return w
425 |
426 |
427 | def generate_with(ctx: Context) -> ast.With:
428 | return _generate_with(ctx, ast.With())
429 |
430 |
431 | def generate_asyncwith(ctx: Context) -> ast.AsyncWith:
432 | return _generate_with(ctx, ast.AsyncWith())
433 |
434 |
435 | def generate_assert(ctx: Context) -> ast.Assert:
436 | a = ast.Assert()
437 | a.test = generate_expr(ctx)
438 | if randbool(ctx):
439 | a.msg = generate_expr(ctx)
440 | return a
441 |
442 |
443 | def generate_expression(ctx: Context) -> ast.Expr:
444 | e = ast.Expr()
445 | e.value = generate_expr(ctx)
446 | return e
447 |
448 |
449 | if sys.version_info < (3, 11):
450 | TTry = typing.TypeVar("TTry")
451 | else:
452 | TTry = typing.TypeVar("TTry", ast.Try, ast.TryStar)
453 |
454 |
455 | def _generate_try(ctx: Context, t: TTry) -> TTry:
456 | t.lineno = 1
457 | t.body = generate_nested_stmts(ctx)
458 | t.handlers = []
459 | for _ in range(randint(ctx, 1, 3)): # TODO: Vary length
460 | handler = ast.ExceptHandler()
461 | handler.lineno = 1
462 | handler.type = generate_expr(ctx)
463 | if randbool(ctx):
464 | handler.name = make_name(ctx, new=True)
465 | handler.body = generate_nested_stmts(ctx)
466 | t.handlers.append(handler)
467 | if randbool(ctx):
468 | t.orelse = generate_nested_stmts(ctx)
469 | else:
470 | t.orelse = []
471 | if randbool(ctx):
472 | t.finalbody = generate_nested_stmts(ctx)
473 | else:
474 | t.finalbody = []
475 | return t
476 |
477 |
478 | def generate_try(ctx: Context) -> ast.Try:
479 | return _generate_try(ctx, ast.Try())
480 |
481 |
482 | def generate_trystar(ctx: Context) -> ast.TryStar:
483 | return _generate_try(ctx, ast.TryStar())
484 |
485 |
486 | def generate_literal_pattern(ctx: Context) -> ast.Constant:
487 | return generate_constant(ctx, values_only=True)
488 |
489 |
490 | def generate_capture_pattern(ctx: Context) -> ast.Name:
491 | name = generate_name(ctx, new=True) # Must not start with _ but doesnt anyway
492 | return name
493 |
494 |
495 | def generate_wildcard_pattern(ctx: Context) -> ast.Name:
496 | name = ast.Name()
497 | name.id = "_"
498 | return name
499 |
500 |
501 | def generate_value_pattern(ctx: Context) -> ast.Name:
502 | name = ast.Name()
503 | name1 = make_name(ctx, new=True)
504 | name2 = make_name(ctx, new=True)
505 | name.id = f"{name1}.{name2}" # TODO : Vary length and depth
506 | return name
507 |
508 |
509 | CLOSED_PATTERNS = [
510 | generate_literal_pattern,
511 | generate_capture_pattern,
512 | generate_wildcard_pattern,
513 | generate_value_pattern,
514 | # TODO...
515 | # group_pattern
516 | # sequence_pattern
517 | # mapping_pattern
518 | # class_pattern
519 | ]
520 |
521 | closed_patterns_cycle = rcycle(CLOSED_PATTERNS)
522 |
523 |
524 | def generate_closed_pattern(ctx: Context) -> typing.Union[ast.pattern, ast.Constant]:
525 | return next(closed_patterns_cycle)(ctx)
526 |
527 |
528 | def generate_matchvalue(ctx: Context) -> ast.MatchValue:
529 | m = ast.MatchValue()
530 | m.value = generate_constant(ctx, values_only=True)
531 | return m
532 |
533 |
534 | singleton_cycle = rcycle([None, True, False])
535 |
536 |
537 | def generate_matchsingleton(ctx: Context) -> ast.MatchSingleton:
538 | m = ast.MatchSingleton()
539 | m.value = next(singleton_cycle)
540 | return m
541 |
542 |
543 | def generate_matchstar(ctx: Context) -> ast.MatchStar:
544 | m = ast.MatchStar()
545 | if randbool(ctx):
546 | m.name = make_name(ctx)
547 | return m
548 |
549 |
550 | MATCH_CONST_GENERATORS = [
551 | generate_matchvalue,
552 | generate_matchsingleton,
553 | ]
554 |
555 | match_const_cycle = rcycle(MATCH_CONST_GENERATORS)
556 |
557 |
558 | def generate_matchsequence(ctx: Context) -> ast.MatchSequence:
559 | m = ast.MatchSequence()
560 | m.patterns = [
561 | next(match_const_cycle)(ctx)
562 | for _ in range(randint(ctx, 1, 3)) # TODO: Vary length
563 | ]
564 | if randbool(ctx):
565 | m.patterns.append(generate_matchstar(ctx))
566 | return m
567 |
568 |
569 | mapping_generator_cycle = rcycle(
570 | [
571 | generate_matchvalue,
572 | generate_matchsingleton,
573 | ]
574 | )
575 |
576 |
577 | def generate_matchmapping(ctx: Context) -> ast.MatchMapping:
578 | m = ast.MatchMapping()
579 | m.keys = []
580 | m.patterns = []
581 | for _ in range(randint(ctx, 1, 3)): # TODO: Vary length
582 | with ctx.nested():
583 | m.keys.append(
584 | generate_constant(ctx, values_only=True)
585 | ) # TODO: Handle value_pattern tokens
586 | m.patterns.append(next(mapping_generator_cycle)(ctx))
587 | if randbool(ctx):
588 | m.rest = make_name(ctx)
589 | return m
590 |
591 |
592 | def generate_matchclass(ctx: Context) -> ast.MatchClass:
593 | m = ast.MatchClass()
594 | m.cls = generate_name(ctx) # TODO: Can be expr in ASDL but not in reality
595 | m.patterns = []
596 | for _ in range(randint(ctx, 1, 3)): # TODO: Vary length
597 | with ctx.nested():
598 | m.patterns.append(next(match_const_cycle)(ctx))
599 | m.kwd_attrs = []
600 | m.kwd_patterns = []
601 | for _ in range(randint(ctx, 1, 3)): # TODO: Vary length
602 | with ctx.nested():
603 | m.kwd_attrs.append(make_name(ctx))
604 | m.kwd_patterns.append(next(match_const_cycle)(ctx))
605 | return m
606 |
607 |
608 | def generate_matchas(ctx: Context) -> ast.MatchAs:
609 | m = ast.MatchAs()
610 | if randbool(ctx):
611 | m.pattern = next(closed_patterns_cycle)(ctx)
612 | if randbool(ctx):
613 | m.name = make_name(ctx, new=True)
614 | return m
615 |
616 |
617 | def generate_matchor(ctx: Context) -> ast.MatchOr:
618 | m = ast.MatchOr()
619 | m.patterns = []
620 | for _ in range(randint(ctx, 1, 3)): # TODO: Vary length
621 | m.patterns.append(next(closed_patterns_cycle)(ctx))
622 | return m
623 |
624 |
625 | MATCH_GENERATORS = [
626 | generate_matchvalue,
627 | generate_matchsingleton,
628 | generate_matchsequence,
629 | generate_matchmapping,
630 | generate_matchclass,
631 | # generate_matchstar, # Causes lots of problems with syntax?
632 | generate_matchas,
633 | generate_matchor,
634 | ]
635 |
636 | match_cycle = rcycle(MATCH_GENERATORS)
637 |
638 |
639 | def generate_matchpattern(ctx: Context) -> ast.pattern:
640 | """
641 | MatchValue(expr value)
642 | | MatchSingleton(constant value)
643 | | MatchSequence(pattern* patterns)
644 | | MatchMapping(expr* keys, pattern* patterns, identifier? rest)
645 | | MatchClass(expr cls, pattern* patterns, identifier* kwd_attrs, pattern* kwd_patterns)
646 |
647 | | MatchStar(identifier? name)
648 | -- The optional "rest" MatchMapping parameter handles capturing extra mapping keys
649 |
650 | | MatchAs(pattern? pattern, identifier? name)
651 | | MatchOr(pattern* patterns)
652 | """
653 | return next(match_cycle)(ctx)
654 |
655 |
656 | def generate_match(ctx: Context) -> ast.Match:
657 | m = ast.Match()
658 | m.subject = generate_expr(ctx)
659 | m.cases = []
660 | for _ in range(randint(ctx, 1, 3)): # TODO: Vary length
661 | case = ast.match_case()
662 | case.pattern = generate_matchpattern(ctx)
663 | if randbool(ctx):
664 | case.guard = generate_expr(ctx)
665 | case.body = generate_nested_stmts(ctx)
666 | m.cases.append(case)
667 | return m
668 |
669 |
670 | # Constraint, is nested, generator
671 | STMT_GENERATORS = (
672 | (GeneratorConstraints.ANY, False, generate_assign),
673 | (GeneratorConstraints.ANY, False, generate_augassign),
674 | (GeneratorConstraints.ANY, False, generate_annassign),
675 | (GeneratorConstraints.ANY, True, generate_function),
676 | (GeneratorConstraints.ANY, True, generate_asyncfunction),
677 | (GeneratorConstraints.ANY, True, generate_class),
678 | (GeneratorConstraints.ONLY_IN_FUNCTIONS, False, generate_return),
679 | (GeneratorConstraints.ANY, False, generate_delete),
680 | (GeneratorConstraints.ANY, True, generate_for),
681 | (GeneratorConstraints.ANY, True, generate_asyncfor),
682 | (GeneratorConstraints.ANY, True, generate_while),
683 | (GeneratorConstraints.ANY, True, generate_if),
684 | (GeneratorConstraints.ANY, True, generate_with),
685 | (GeneratorConstraints.ANY, True, generate_asyncwith),
686 | (GeneratorConstraints.ANY, True, generate_match),
687 | (GeneratorConstraints.ANY, False, generate_raise),
688 | (GeneratorConstraints.ANY, True, generate_try),
689 | (GeneratorConstraints.ANY, True, generate_trystar),
690 | (GeneratorConstraints.ANY, False, generate_assert),
691 | (GeneratorConstraints.ANY, False, generate_import),
692 | (GeneratorConstraints.ANY, False, generate_importfrom),
693 | (GeneratorConstraints.ANY, False, generate_global),
694 | (GeneratorConstraints.ONLY_IN_FUNCTIONS, False, generate_nonlocal),
695 | (GeneratorConstraints.ANY, False, generate_expression),
696 | (GeneratorConstraints.ANY, False, generate_pass),
697 | (GeneratorConstraints.ONLY_IN_LOOPS, False, generate_break),
698 | (GeneratorConstraints.ONLY_IN_LOOPS, False, generate_continue),
699 | # (GeneratorConstraints.ANY, generate_ellipsis), # This causes chaos
700 | )
701 |
702 | list_ctx_cycle = rcycle([ast.Load, ast.Store, ast.Del])
703 |
704 |
705 | def generate_list(ctx: Context) -> ast.List:
706 | l = ast.List()
707 | l.elts = generate_exprs(ctx)
708 | if randbool(ctx):
709 | l.ctx = next(list_ctx_cycle)()
710 | return l
711 |
712 |
713 | def generate_tuple(ctx: Context) -> ast.Tuple:
714 | t = ast.Tuple()
715 | t.elts = generate_exprs(ctx)
716 | return t
717 |
718 |
719 | bool_op_cycle = rcycle([ast.And, ast.Or])
720 |
721 |
722 | def generate_boolop(ctx: Context) -> ast.BoolOp:
723 | b = ast.BoolOp()
724 | b.values = [generate_expr(ctx)] # TODO Vary length
725 | b.op = next(bool_op_cycle)()
726 | return b
727 |
728 |
729 | binop_cycle = rcycle(OPERATORS)
730 |
731 |
732 | def generate_binop(ctx: Context) -> ast.BinOp:
733 | b = ast.BinOp()
734 | b.left = generate_expr(ctx)
735 | b.right = generate_expr(ctx)
736 | b.op = next(binop_cycle)()
737 | return b
738 |
739 |
740 | unary_cycle = rcycle([ast.Invert, ast.Not, ast.UAdd, ast.USub])
741 |
742 |
743 | def generate_unaryop(ctx: Context) -> ast.UnaryOp:
744 | u = ast.UnaryOp()
745 | u.operand = generate_expr(ctx)
746 | u.op = next(unary_cycle)()
747 | return u
748 |
749 |
750 | def generate_lambda(ctx: Context) -> ast.Lambda:
751 | l = ast.Lambda()
752 | l.args = ast.arguments()
753 | l.args.args = [generate_arg(ctx) for _ in range(randint(ctx, 0, ctx.width))]
754 | l.args.posonlyargs = []
755 | l.args.kwonlyargs = []
756 | l.args.defaults = []
757 | l.body = generate_expr(ctx)
758 | return l
759 |
760 |
761 | def generate_ifexp(ctx: Context) -> ast.IfExp:
762 | i = ast.IfExp()
763 | i.test = generate_expr(ctx)
764 | i.body = generate_expr(ctx)
765 | i.orelse = generate_expr(ctx)
766 | return i
767 |
768 |
769 | def generate_dict(ctx: Context) -> ast.Dict:
770 | d = ast.Dict()
771 | d.keys = generate_exprs(ctx)
772 | d.values = generate_exprs(ctx)
773 | return d
774 |
775 |
776 | def generate_set(ctx: Context) -> ast.Set:
777 | s = ast.Set()
778 | s.elts = generate_exprs(ctx)
779 | return s
780 |
781 |
782 | def generate_comprehension(ctx: Context) -> ast.comprehension:
783 | c = ast.comprehension()
784 | c.target = generate_name(ctx, new=True)
785 | c.iter = generate_expr(ctx)
786 | c.ifs = []
787 | for _ in range(randint(ctx, 0, 3)): # TODO: Vary length
788 | c.ifs.append(generate_expr(ctx))
789 | c.is_async = False # TODO: Vary?
790 | return c
791 |
792 |
793 | def generate_listcomp(ctx: Context) -> ast.ListComp:
794 | l = ast.ListComp()
795 | l.elt = generate_expr(ctx)
796 | l.generators = []
797 | for _ in range(randint(ctx, 1, 3)): # TODO: Vary length
798 | l.generators.append(generate_comprehension(ctx))
799 | return l
800 |
801 |
802 | def generate_setcomp(ctx: Context) -> ast.SetComp:
803 | s = ast.SetComp()
804 | s.elt = generate_expr(ctx)
805 | s.generators = []
806 | for _ in range(randint(ctx, 1, 3)): # TODO: Vary length
807 | s.generators.append(generate_comprehension(ctx))
808 | return s
809 |
810 |
811 | def generate_dictcomp(ctx: Context) -> ast.DictComp:
812 | d = ast.DictComp()
813 | d.key = generate_expr(ctx)
814 | d.value = generate_expr(ctx)
815 | d.generators = []
816 | for _ in range(randint(ctx, 1, 3)): # TODO: Vary length
817 | d.generators.append(generate_comprehension(ctx))
818 | return d
819 |
820 |
821 | def generate_generatorexp(ctx: Context) -> ast.GeneratorExp:
822 | g = ast.GeneratorExp()
823 | g.elt = generate_expr(ctx)
824 | g.generators = []
825 | for _ in range(randint(ctx, 1, 3)): # TODO: Vary length
826 | g.generators.append(generate_comprehension(ctx))
827 | return g
828 |
829 |
830 | def generate_await(ctx: Context) -> ast.Await:
831 | a = ast.Await()
832 | a.value = generate_expr(ctx)
833 | return a
834 |
835 |
836 | def generate_yield(ctx: Context) -> ast.Yield:
837 | y = ast.Yield()
838 | y.value = generate_expr(ctx)
839 | return y
840 |
841 |
842 | def generate_yieldfrom(ctx: Context) -> ast.YieldFrom:
843 | y = ast.YieldFrom()
844 | y.value = generate_expr(ctx)
845 | return y
846 |
847 |
848 | cmpop_cycle = rcycle(CMPOPS)
849 |
850 |
851 | def generate_compare(ctx: Context) -> ast.Compare:
852 | c = ast.Compare()
853 | c.left = generate_expr(ctx)
854 | c.comparators = [
855 | generate_expr(ctx) for _ in range(randint(ctx, 1, 3))
856 | ] # TODO: Use width or varied length
857 | c.ops = [
858 | next(cmpop_cycle)() for _ in range(randint(ctx, 1, 3))
859 | ] # TODO: Vary length
860 | return c
861 |
862 |
863 | def generate_call(ctx: Context) -> ast.Call:
864 | c = ast.Call()
865 | c.func = generate_expr(ctx)
866 | c.args = []
867 | for _ in range(randint(ctx, 0, ctx.width // 2)):
868 | c.args.append(generate_expr(ctx))
869 | c.keywords = []
870 | for _ in range(randint(ctx, 0, ctx.width // 2)):
871 | kw = ast.keyword()
872 | kw.arg = make_name(ctx, new=True)
873 | kw.value = generate_expr(ctx)
874 | c.keywords.append(kw)
875 | return c
876 |
877 |
878 | def generate_formattedvalue(ctx: Context) -> ast.FormattedValue:
879 | f = ast.FormattedValue()
880 | # Use generate_name when Python < 3.12
881 | if sys.version_info < (3, 12):
882 | f.value = generate_name(ctx, new=True)
883 | else:
884 | f.value = generate_expr(ctx)
885 | f.format_spec = None # TODO : Generate format specs
886 | f.conversion = -1 # TODO : Work out what this is?
887 | return f
888 |
889 |
890 | def generate_joinedstr(ctx: Context) -> ast.JoinedStr:
891 | j = ast.JoinedStr()
892 | j.values = [
893 | randchoice(ctx, [generate_str_constant, generate_formattedvalue])(ctx)
894 | for _ in range(ctx.width)
895 | ]
896 | return j
897 |
898 |
899 | def generate_namedexpr(ctx: Context) -> ast.NamedExpr:
900 | n = ast.NamedExpr()
901 | n.target = generate_name(ctx, new=True)
902 | n.value = generate_expr(ctx)
903 | return n
904 |
905 |
906 | def generate_slice(ctx: Context) -> ast.Slice:
907 | s = ast.Slice()
908 | s.lower = generate_expr(ctx)
909 | s.upper = generate_expr(ctx)
910 | s.step = generate_expr(ctx)
911 | return s
912 |
913 |
914 | EXPR_GENERATORS = (
915 | generate_boolop,
916 | generate_namedexpr,
917 | generate_binop,
918 | generate_unaryop,
919 | generate_lambda,
920 | generate_ifexp,
921 | generate_dict,
922 | generate_set,
923 | generate_listcomp,
924 | generate_setcomp,
925 | generate_dictcomp,
926 | generate_generatorexp,
927 | generate_await,
928 | generate_yield,
929 | generate_yieldfrom,
930 | generate_compare,
931 | generate_call,
932 | generate_formattedvalue,
933 | generate_joinedstr,
934 | generate_constant,
935 | generate_attribute,
936 | generate_subscript,
937 | # generate_starred,
938 | generate_name,
939 | generate_list,
940 | generate_tuple,
941 | )
942 |
943 | """ Expressions that don't themselves contain expressions. """
944 | FLAT_EXPR_GENERATORS = [
945 | generate_name,
946 | generate_constant,
947 | ]
948 |
949 |
950 | # Create another list with the first item in the tuple for each item in STMT_GENERATORS
951 | STMT_ALL_GENERATORS_ITER = rcycle(STMT_GENERATORS)
952 |
953 |
954 | def _generate_stmts(ctx: Context) -> list[ast.stmt]:
955 | if ctx.depth >= ctx.max_depth:
956 | logger.debug("Hit max depth for stmt")
957 | return [generate_pass(ctx)]
958 | stmts = []
959 | while len(stmts) < ctx.width:
960 | next_stmt = next(STMT_ALL_GENERATORS_ITER)
961 | if next_stmt[1] and ctx.depth >= ctx.max_depth - 1:
962 | logger.debug("Hit max depth for nested stmt")
963 | continue
964 | if next_stmt[0] == GeneratorConstraints.ANY:
965 | stmts.append(next_stmt[2](ctx))
966 | elif next_stmt[0] == GeneratorConstraints.ONLY_IN_FUNCTIONS and ctx.in_function:
967 | stmts.append(next_stmt[2](ctx))
968 | elif next_stmt[0] == GeneratorConstraints.ONLY_IN_LOOPS and ctx.in_loop:
969 | stmts.append(next_stmt[2](ctx))
970 | return stmts
971 |
972 |
973 | def generate_nested_stmts(ctx: Context) -> list[ast.stmt]:
974 | with ctx.nested():
975 | return _generate_stmts(ctx)
976 |
977 |
978 | flat_expr_generators_cycle = rcycle(FLAT_EXPR_GENERATORS)
979 | expr_generators_cycle = rcycle(EXPR_GENERATORS)
980 |
981 |
982 | def generate_expr(ctx: Context) -> ast.expr:
983 | with ctx.nested():
984 | if ctx.depth >= ctx.max_depth:
985 | logger.debug("Hit max depth")
986 | return next(flat_expr_generators_cycle)(ctx)
987 | return next(expr_generators_cycle)(ctx)
988 |
989 |
990 | def generate_exprs(ctx: Context) -> list[ast.expr]:
991 | if ctx.depth >= ctx.max_depth:
992 | return []
993 | return [generate_expr(ctx) for _ in range(randint(ctx, 1, ctx.width))]
994 |
995 |
996 | def generate_module(depth: int, width: int, log_level: str | None = None) -> ast.Module:
997 | if log_level is not None:
998 | logger.setLevel(log_level)
999 | ctx = Context()
1000 | ctx.max_depth = depth
1001 | ctx.width = width
1002 | mod = ast.Module()
1003 | mod.type_ignores = []
1004 | mod.body = generate_nested_stmts(ctx)
1005 | return mod
1006 |
--------------------------------------------------------------------------------