pyastq 0.1.2__py3-none-win_amd64.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Binary file
@@ -0,0 +1,277 @@
1
+ Metadata-Version: 2.4
2
+ Name: pyastq
3
+ Version: 0.1.2
4
+ Classifier: Environment :: Console
5
+ Classifier: Programming Language :: Python :: 3
6
+ Classifier: Programming Language :: Rust
7
+ Classifier: Topic :: Software Development :: Quality Assurance
8
+ Summary: Structural Python search and lightweight AST-based rule checking
9
+ Keywords: ast,cli,linting,python,structural-search
10
+ Author: Petar Mishov
11
+ Requires-Python: >=3.8
12
+ Description-Content-Type: text/markdown; charset=UTF-8; variant=GFM
13
+ Project-URL: Repository, https://github.com/PetarMishov/pyastq
14
+
15
+ # pyastq
16
+
17
+ `pyastq` is a structural Python searcher and lightweight rule runner. It searches
18
+ the Python AST rather than raw text, making it suitable for local scripts,
19
+ pre-commit hooks, and CI checks.
20
+
21
+ ## Build
22
+
23
+ ```sh
24
+ cargo build --release
25
+ ```
26
+
27
+ The binary is written to `target/release/pyastq`.
28
+
29
+ ## Install
30
+
31
+ `pyastq` is a Rust executable distributed as the `pyastq` Python package. Install
32
+ it as an isolated command-line tool:
33
+
34
+ ```sh
35
+ uv tool install pyastq
36
+ # or
37
+ pipx install pyastq
38
+ ```
39
+
40
+ For local development:
41
+
42
+ ```sh
43
+ uv tool install .
44
+ pyastq --help
45
+ ```
46
+
47
+ The PyPI package is only a distribution mechanism for the executable; it does
48
+ not provide an importable Python module.
49
+
50
+ ### Versions
51
+
52
+ Release tags are the source of truth for published package versions. To publish
53
+ a new release:
54
+
55
+ 1. Tag the commit, for example `git tag v0.2.0`.
56
+ 2. Push the tag with `git push origin v0.2.0`.
57
+
58
+ The release workflow validates the tag, changes the package version in its
59
+ temporary checkout, builds wheels for Linux, macOS, and Windows, publishes them
60
+ to PyPI, and creates a GitHub release. `Cargo.toml` may therefore still show the
61
+ development version from the tagged commit.
62
+
63
+ An existing tag can be released from GitHub Actions by running the `Release`
64
+ workflow manually and entering the tag.
65
+
66
+ PyPI retains previously published versions, so users can select one explicitly:
67
+
68
+ ```sh
69
+ uv tool install 'pyastq==0.1.0'
70
+ pipx install 'pyastq==0.1.0'
71
+ ```
72
+
73
+ Uploading another build with the same version is not a replacement mechanism.
74
+ Fixes require a new version such as `0.1.1`.
75
+
76
+ ## Structural Search
77
+
78
+ ```sh
79
+ pyastq find src 'call:eval'
80
+ pyastq find src 'class:* -> function:regex:^[A-Z]'
81
+ pyastq find src 'call:request AND argument:timeout:>30'
82
+ pyastq find src 'function:* AND descendant(call:open) AND NOT descendant(call:close)'
83
+ pyastq find src 'call:print AND ancestor(function:*)'
84
+ ```
85
+
86
+ The first pattern is the node reported as the finding. Conditions inspect its
87
+ structure:
88
+
89
+ - `pattern` and `descendant(pattern)` search all nested nodes.
90
+ - `child(pattern)` searches direct AST children.
91
+ - `ancestor(pattern)` and `inside(pattern)` search enclosing nodes.
92
+ - `->` is shorthand for `AND descendant`.
93
+ - `AND`, `OR`, `NOT`, and parentheses compose conditions.
94
+
95
+ Supported node patterns:
96
+
97
+ ```text
98
+ call:<value>
99
+ class:<value>
100
+ function:<value>
101
+ import:<value>
102
+ argument:<key>:<value>
103
+ ```
104
+
105
+ Argument keys are keyword names, zero-based positional indexes, or `*`:
106
+
107
+ ```text
108
+ argument:timeout:30
109
+ argument:0:"input.txt"
110
+ argument:*:None
111
+ ```
112
+
113
+ Value predicates:
114
+
115
+ ```text
116
+ * any value
117
+ User exact value
118
+ exact:User exact value
119
+ contains:User substring
120
+ starts_with:test_ prefix
121
+ ends_with:_unsafe suffix
122
+ regex:^[A-Z] regular expression
123
+ >3 >=3 <10 <=10 numeric comparison
124
+ ```
125
+
126
+ Quote a complete query when invoking it from a shell. Quotes inside a value
127
+ allow spaces, for example `argument:0:"hello world"`.
128
+
129
+ ## Automation
130
+
131
+ `find` returns `0` unless parsing or execution fails. Use `--fail-on-match` to
132
+ make matches return `1`:
133
+
134
+ ```sh
135
+ pyastq find . 'call:eval' --fail-on-match --quiet
136
+ ```
137
+
138
+ Exit codes:
139
+
140
+ - `0`: successful and clean
141
+ - `1`: findings were detected when failure-on-match applies
142
+ - `2`: invalid query, configuration, or execution error
143
+
144
+ Output and filtering options:
145
+
146
+ ```sh
147
+ pyastq find . 'call:eval' --format json
148
+ pyastq find . 'call:eval' --format jsonl
149
+ pyastq find . 'call:eval' --format sarif
150
+ pyastq find . 'call:eval' --include 'src/**/*.py' --exclude '**/generated/**'
151
+ pyastq find . 'call:eval' --changed --max-matches 10
152
+ pyastq find . 'call:eval' --no-cache
153
+ ```
154
+
155
+ `--changed` includes staged, unstaged, and untracked Python files reported by
156
+ Git.
157
+
158
+ Directory searches store one content hash per file and findings per query or
159
+ rule in `.pyastq-cache.json`. Unchanged files reuse cached findings. Changed files
160
+ are read, hashed, and parsed once, then all applicable rules run against the
161
+ same syntax tree. Use `--no-cache` to force a full scan. Cache failures fall
162
+ back to a full scan, and `--changed` or `--max-matches` searches do not use the
163
+ cache.
164
+
165
+ ## Rule Files
166
+
167
+ Rules use TOML. See [`pyastq.example.toml`](pyastq.example.toml).
168
+
169
+ ```toml
170
+ exclude = ["**/generated/**"]
171
+
172
+ [[rules]]
173
+ id = "no-eval"
174
+ query = "call:eval"
175
+ message = "Avoid eval(); parse the expected input explicitly."
176
+ severity = "error"
177
+ include = ["src/**/*.py"]
178
+ valid = ["parse(value)"]
179
+ invalid = ["eval(value)"]
180
+
181
+ [[rules]]
182
+ id = "method-name-case"
183
+ query = "class:* -> function:regex:^[A-Z]"
184
+ message = "Method names must start with a lowercase letter."
185
+ severity = "warning"
186
+ ```
187
+
188
+ Run rules:
189
+
190
+ ```sh
191
+ pyastq check . --rules pyastq.toml
192
+ pyastq check . --rules pyastq.toml --format json --changed
193
+ pyastq test-rules --rules pyastq.toml
194
+ ```
195
+
196
+ `check` returns `1` when any rule matches. `test-rules` verifies that each
197
+ `valid` example does not match and each `invalid` example does.
198
+
199
+ Rules can also live in `pyproject.toml`:
200
+
201
+ ```toml
202
+ [tool.pyastq]
203
+ exclude = ["generated/**", "migrations/**"]
204
+
205
+ [[tool.pyastq.rules]]
206
+ id = "no-eval"
207
+ query = "call:eval"
208
+ message = "Avoid eval(); parse the expected input explicitly."
209
+ severity = "error"
210
+ valid = ["parse(value)"]
211
+ invalid = ["eval(value)"]
212
+ ```
213
+
214
+ Alternatively, reference a standalone rule file:
215
+
216
+ ```toml
217
+ [tool.pyastq]
218
+ rules-file = "config/pyastq.toml"
219
+ exclude = ["build/**"]
220
+ ```
221
+
222
+ `rules-file` is resolved relative to `pyproject.toml`. External and inline
223
+ rules may be used together: external rules are loaded first, inline rules are
224
+ appended, and exclusions from both configurations are combined. Rule IDs must
225
+ remain unique across both sources.
226
+
227
+ When `--rules` is omitted, `check` searches from the analyzed path toward the
228
+ filesystem root for a `pyproject.toml` containing `[tool.pyastq]`:
229
+
230
+ ```sh
231
+ pyastq check .
232
+ pyastq test-rules
233
+ ```
234
+
235
+ Passing `--rules` continues to support standalone rule files and explicit
236
+ `pyproject.toml` files:
237
+
238
+ ```sh
239
+ pyastq check . --rules pyastq.toml
240
+ pyastq check . --rules pyproject.toml
241
+ ```
242
+
243
+ SARIF 2.1.0 output is suitable for code-scanning systems:
244
+
245
+ ```sh
246
+ pyastq check . --format sarif > pyastq.sarif
247
+ ```
248
+
249
+ ## Suppressions
250
+
251
+ Suppress one line, the following line, or an entire file:
252
+
253
+ ```python
254
+ eval(value) # pyastq: ignore no-eval
255
+
256
+ # pyastq: ignore no-eval
257
+ eval(value)
258
+
259
+ # pyastq: ignore-file no-eval
260
+ ```
261
+
262
+ Omitting the rule ID suppresses every rule at that location. Multiple IDs can
263
+ be separated by spaces or commas.
264
+
265
+ ## Pre-commit Example
266
+
267
+ ```yaml
268
+ repos:
269
+ - repo: local
270
+ hooks:
271
+ - id: pyastq
272
+ name: pyastq structural rules
273
+ entry: target/release/pyastq check . --rules pyastq.toml --changed
274
+ language: system
275
+ pass_filenames: false
276
+ ```
277
+
@@ -0,0 +1,4 @@
1
+ pyastq-0.1.2.data\scripts\pyastq.exe,sha256=iPfc--2C1WTtQWR6py8G6uJOpR-2yZLP7QhxPVWLhog,3711488
2
+ pyastq-0.1.2.dist-info\METADATA,sha256=O5pOrQTd-e1iKAMsmwej1fRzR_GTvP3x_gM5LxLn4FA,7471
3
+ pyastq-0.1.2.dist-info\WHEEL,sha256=jsSEiVNsW1dJj5gDaReR40i7mhgBjWtms6nAD6EViXU,94
4
+ pyastq-0.1.2.dist-info\RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: maturin (1.11.5)
3
+ Root-Is-Purelib: false
4
+ Tag: py3-none-win_amd64