pygosqlx 1.16.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.
@@ -0,0 +1,202 @@
1
+
2
+ Apache License
3
+ Version 2.0, January 2004
4
+ http://www.apache.org/licenses/
5
+
6
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
7
+
8
+ 1. Definitions.
9
+
10
+ "License" shall mean the terms and conditions for use, reproduction,
11
+ and distribution as defined by Sections 1 through 9 of this document.
12
+
13
+ "Licensor" shall mean the copyright owner or entity authorized by
14
+ the copyright owner that is granting the License.
15
+
16
+ "Legal Entity" shall mean the union of the acting entity and all
17
+ other entities that control, are controlled by, or are under common
18
+ control with that entity. For the purposes of this definition,
19
+ "control" means (i) the power, direct or indirect, to cause the
20
+ direction or management of such entity, whether by contract or
21
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
22
+ outstanding shares, or (iii) beneficial ownership of such entity.
23
+
24
+ "You" (or "Your") shall mean an individual or Legal Entity
25
+ exercising permissions granted by this License.
26
+
27
+ "Source" form shall mean the preferred form for making modifications,
28
+ including but not limited to software source code, documentation
29
+ source, and configuration files.
30
+
31
+ "Object" form shall mean any form resulting from mechanical
32
+ transformation or translation of a Source form, including but
33
+ not limited to compiled object code, generated documentation,
34
+ and conversions to other media types.
35
+
36
+ "Work" shall mean the work of authorship, whether in Source or
37
+ Object form, made available under the License, as indicated by a
38
+ copyright notice that is included in or attached to the work
39
+ (an example is provided in the Appendix below).
40
+
41
+ "Derivative Works" shall mean any work, whether in Source or Object
42
+ form, that is based on (or derived from) the Work and for which the
43
+ editorial revisions, annotations, elaborations, or other modifications
44
+ represent, as a whole, an original work of authorship. For the purposes
45
+ of this License, Derivative Works shall not include works that remain
46
+ separable from, or merely link (or bind by name) to the interfaces of,
47
+ the Work and Derivative Works thereof.
48
+
49
+ "Contribution" shall mean any work of authorship, including
50
+ the original version of the Work and any modifications or additions
51
+ to that Work or Derivative Works thereof, that is intentionally
52
+ submitted to Licensor for inclusion in the Work by the copyright owner
53
+ or by an individual or Legal Entity authorized to submit on behalf of
54
+ the copyright owner. For the purposes of this definition, "submitted"
55
+ means any form of electronic, verbal, or written communication sent
56
+ to the Licensor or its representatives, including but not limited to
57
+ communication on electronic mailing lists, source code control systems,
58
+ and issue tracking systems that are managed by, or on behalf of, the
59
+ Licensor for the purpose of discussing and improving the Work, but
60
+ excluding communication that is conspicuously marked or otherwise
61
+ designated in writing by the copyright owner as "Not a Contribution."
62
+
63
+ "Contributor" shall mean Licensor and any individual or Legal Entity
64
+ on behalf of whom a Contribution has been received by Licensor and
65
+ subsequently incorporated within the Work.
66
+
67
+ 2. Grant of Copyright License. Subject to the terms and conditions of
68
+ this License, each Contributor hereby grants to You a perpetual,
69
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
70
+ copyright license to reproduce, prepare Derivative Works of,
71
+ publicly display, publicly perform, sublicense, and distribute the
72
+ Work and such Derivative Works in Source or Object form.
73
+
74
+ 3. Grant of Patent License. Subject to the terms and conditions of
75
+ this License, each Contributor hereby grants to You a perpetual,
76
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
77
+ (except as stated in this section) patent license to make, have made,
78
+ use, offer to sell, sell, import, and otherwise transfer the Work,
79
+ where such license applies only to those patent claims licensable
80
+ by such Contributor that are necessarily infringed by their
81
+ Contribution(s) alone or by combination of their Contribution(s)
82
+ with the Work to which such Contribution(s) was submitted. If You
83
+ institute patent litigation against any entity (including a
84
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
85
+ or a Contribution incorporated within the Work constitutes direct
86
+ or contributory patent infringement, then any patent licenses
87
+ granted to You under this License for that Work shall terminate
88
+ as of the date such litigation is filed.
89
+
90
+ 4. Redistribution. You may reproduce and distribute copies of the
91
+ Work or Derivative Works thereof in any medium, with or without
92
+ modifications, and in Source or Object form, provided that You
93
+ meet the following conditions:
94
+
95
+ (a) You must give any other recipients of the Work or
96
+ Derivative Works a copy of this License; and
97
+
98
+ (b) You must cause any modified files to carry prominent notices
99
+ stating that You changed the files; and
100
+
101
+ (c) You must retain, in the Source form of any Derivative Works
102
+ that You distribute, all copyright, patent, trademark, and
103
+ attribution notices from the Source form of the Work,
104
+ excluding those notices that do not pertain to any part of
105
+ the Derivative Works; and
106
+
107
+ (d) If the Work includes a "NOTICE" text file as part of its
108
+ distribution, then any Derivative Works that You distribute must
109
+ include a readable copy of the attribution notices contained
110
+ within such NOTICE file, excluding those notices that do not
111
+ pertain to any part of the Derivative Works, in at least one
112
+ of the following places: within a NOTICE text file distributed
113
+ as part of the Derivative Works; within the Source form or
114
+ documentation, if provided along with the Derivative Works; or,
115
+ within a display generated by the Derivative Works, if and
116
+ wherever such third-party notices normally appear. The contents
117
+ of the NOTICE file are for informational purposes only and
118
+ do not modify the License. You may add Your own attribution
119
+ notices within Derivative Works that You distribute, alongside
120
+ or as an addendum to the NOTICE text from the Work, provided
121
+ that such additional attribution notices cannot be construed
122
+ as modifying the License.
123
+
124
+ You may add Your own copyright statement to Your modifications and
125
+ may provide additional or different license terms and conditions
126
+ for use, reproduction, or distribution of Your modifications, or
127
+ for any such Derivative Works as a whole, provided Your use,
128
+ reproduction, and distribution of the Work otherwise complies with
129
+ the conditions stated in this License.
130
+
131
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
132
+ any Contribution intentionally submitted for inclusion in the Work
133
+ by You to the Licensor shall be under the terms and conditions of
134
+ this License, without any additional terms or conditions.
135
+ Notwithstanding the above, nothing herein shall supersede or modify
136
+ the terms of any separate license agreement you may have executed
137
+ with Licensor regarding such Contributions.
138
+
139
+ 6. Trademarks. This License does not grant permission to use the trade
140
+ names, trademarks, service marks, or product names of the Licensor,
141
+ except as required for reasonable and customary use in describing the
142
+ origin of the Work and reproducing the content of the NOTICE file.
143
+
144
+ 7. Disclaimer of Warranty. Unless required by applicable law or
145
+ agreed to in writing, Licensor provides the Work (and each
146
+ Contributor provides its Contributions) on an "AS IS" BASIS,
147
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
148
+ implied, including, without limitation, any warranties or conditions
149
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
150
+ PARTICULAR PURPOSE. You are solely responsible for determining the
151
+ appropriateness of using or redistributing the Work and assume any
152
+ risks associated with Your exercise of permissions under this License.
153
+
154
+ 8. Limitation of Liability. In no event and under no legal theory,
155
+ whether in tort (including negligence), contract, or otherwise,
156
+ unless required by applicable law (such as deliberate and grossly
157
+ negligent acts) or agreed to in writing, shall any Contributor be
158
+ liable to You for damages, including any direct, indirect, special,
159
+ incidental, or consequential damages of any character arising as a
160
+ result of this License or out of the use or inability to use the
161
+ Work (including but not limited to damages for loss of goodwill,
162
+ work stoppage, computer failure or malfunction, or any and all
163
+ other commercial damages or losses), even if such Contributor
164
+ has been advised of the possibility of such damages.
165
+
166
+ 9. Accepting Warranty or Additional Liability. While redistributing
167
+ the Work or Derivative Works thereof, You may choose to offer,
168
+ and charge a fee for, acceptance of support, warranty, indemnity,
169
+ or other liability obligations and/or rights consistent with this
170
+ License. However, in accepting such obligations, You may act only
171
+ on Your own behalf and on Your sole responsibility, not on behalf
172
+ of any other Contributor, and only if You agree to indemnify,
173
+ defend, and hold each Contributor harmless for any liability
174
+ incurred by, or claims asserted against, such Contributor by reason
175
+ of your accepting any such warranty or additional liability.
176
+
177
+ END OF TERMS AND CONDITIONS
178
+
179
+ APPENDIX: How to apply the Apache License to your work.
180
+
181
+ To apply the Apache License to your work, attach the following
182
+ boilerplate notice, with the fields enclosed by brackets "[]"
183
+ replaced with your own identifying information. (Don't include
184
+ the brackets!) The text should be enclosed in the appropriate
185
+ comment syntax for the file format. We also recommend that a
186
+ file or class name and description of purpose be included on the
187
+ same "printed page" as the copyright notice for easier
188
+ identification within third-party archives.
189
+
190
+ Copyright [yyyy] [name of copyright owner]
191
+
192
+ Licensed under the Apache License, Version 2.0 (the "License");
193
+ you may not use this file except in compliance with the License.
194
+ You may obtain a copy of the License at
195
+
196
+ http://www.apache.org/licenses/LICENSE-2.0
197
+
198
+ Unless required by applicable law or agreed to in writing, software
199
+ distributed under the License is distributed on an "AS IS" BASIS,
200
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
201
+ See the License for the specific language governing permissions and
202
+ limitations under the License.
@@ -0,0 +1,6 @@
1
+ include LICENSE
2
+ include README.md
3
+ include pyproject.toml
4
+ recursive-include pygosqlx *.py *.pyi py.typed
5
+ recursive-include pygosqlx/lib *.so *.dylib *.dll *.h
6
+ recursive-include tests *.py
@@ -0,0 +1,374 @@
1
+ Metadata-Version: 2.4
2
+ Name: pygosqlx
3
+ Version: 1.16.0
4
+ Summary: Python bindings for GoSQLX - High-performance SQL parser
5
+ Author: GoSQLX Contributors
6
+ License-Expression: Apache-2.0
7
+ Project-URL: Documentation, https://github.com/ajitpratap0/GoSQLX/tree/main/python#readme
8
+ Project-URL: Homepage, https://github.com/ajitpratap0/GoSQLX
9
+ Project-URL: Repository, https://github.com/ajitpratap0/GoSQLX
10
+ Project-URL: Issues, https://github.com/ajitpratap0/GoSQLX/issues
11
+ Classifier: Development Status :: 3 - Alpha
12
+ Classifier: Intended Audience :: Developers
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: Programming Language :: Python :: 3.13
18
+ Classifier: Programming Language :: Python :: 3.14
19
+ Classifier: Operating System :: MacOS
20
+ Classifier: Operating System :: Microsoft :: Windows
21
+ Classifier: Operating System :: POSIX :: Linux
22
+ Classifier: Topic :: Database
23
+ Classifier: Topic :: Software Development :: Libraries
24
+ Classifier: Typing :: Typed
25
+ Requires-Python: >=3.10
26
+ Description-Content-Type: text/markdown
27
+ License-File: LICENSE
28
+ Provides-Extra: dev
29
+ Requires-Dist: pytest>=7.0; extra == "dev"
30
+ Requires-Dist: pytest-cov; extra == "dev"
31
+ Dynamic: license-file
32
+
33
+ # PyGoSQLX
34
+
35
+ Python bindings for [GoSQLX](https://github.com/ajitpratap0/GoSQLX) -- a high-performance SQL parser written in Go. Parses, validates, formats, and analyzes SQL statements at native speed via a shared library (ctypes FFI).
36
+
37
+ Powered by Go's compiled performance, PyGoSQLX is 100x+ faster than pure Python SQL parsers while providing a simple, Pythonic API.
38
+
39
+ ## Installation
40
+
41
+ ```bash
42
+ pip install pygosqlx
43
+ ```
44
+
45
+ Prebuilt wheels bundle the native `libgosqlx` library, so no Go toolchain is
46
+ needed. pygosqlx is versioned in lockstep with GoSQLX: each GoSQLX release
47
+ (starting with 1.16.0) publishes the matching pygosqlx version, whose wheels
48
+ bundle the library built from that release.
49
+
50
+ Wheels are available for Python 3.10-3.14 on:
51
+
52
+ | Platform | Architectures | Wheel tag |
53
+ |---|---|---|
54
+ | Linux (glibc) | x86_64, aarch64 | `manylinux_2_17` (manylinux2014; glibc 2.17+, built on manylinux_2_28) |
55
+ | macOS 13+ | x86_64, arm64 | `macosx_13_0` |
56
+ | Windows | AMD64 | `win_amd64` |
57
+
58
+ There are no wheels for musl-based Linux (Alpine) or 32-bit platforms. On
59
+ those, pip falls back to the source distribution, which installs the Python
60
+ package without the native library; build it as described below and point
61
+ `GOSQLX_LIB_PATH` at it.
62
+
63
+ ### Building from source
64
+
65
+ Requires a Go toolchain matching the repository's `go.mod` (Go 1.26+) with cgo
66
+ enabled (a C compiler on `PATH`).
67
+
68
+ ```bash
69
+ git clone https://github.com/ajitpratap0/GoSQLX.git
70
+ cd GoSQLX/pkg/cbinding
71
+ ./build.sh # writes python/pygosqlx/lib/libgosqlx.{so,dylib}
72
+ cd ../../python
73
+ pip install . # or: pip install -e ".[dev]" for development
74
+ ```
75
+
76
+ `build.sh` compiles the Go code into a shared library (`libgosqlx.so` on
77
+ Linux, `libgosqlx.dylib` on macOS, `libgosqlx.dll` on Windows via MSYS2/MinGW)
78
+ and places it in `python/pygosqlx/lib/`, where `pip install .` bundles it. Use
79
+ `OUTPUT_DIR=/path/to/output ./build.sh` to write it elsewhere.
80
+
81
+ Building a wheel without the library fails on purpose, so `pip install` on a
82
+ platform with no prebuilt wheel (for example musl or 32-bit Linux) stops with
83
+ an error instead of installing a package that cannot load. To install without
84
+ a bundled library and supply one at runtime instead, set
85
+ `PYGOSQLX_ALLOW_MISSING_LIB=1` for the install and point `GOSQLX_LIB_PATH` at
86
+ the library:
87
+
88
+ ```bash
89
+ PYGOSQLX_ALLOW_MISSING_LIB=1 pip install pygosqlx
90
+ export GOSQLX_LIB_PATH=/path/to/libgosqlx.so
91
+ ```
92
+
93
+ ## Quick Start
94
+
95
+ ```python
96
+ import pygosqlx
97
+
98
+ # Parse SQL - raises ParseError on invalid SQL
99
+ result = pygosqlx.parse("SELECT id, name FROM users WHERE active = true")
100
+ print(result.statement_count) # 1
101
+ print(result.statement_types) # ['SELECT']
102
+
103
+ # Validate SQL syntax
104
+ is_valid = pygosqlx.validate("SELECT * FROM users")
105
+ print(is_valid) # True
106
+
107
+ is_valid = pygosqlx.validate("SELEC * FORM users")
108
+ print(is_valid) # False
109
+
110
+ # Validate with detailed error info
111
+ detail = pygosqlx.validate_detailed("SELEC * FORM users")
112
+ if not detail.valid:
113
+ print(detail.error) # Error message
114
+ print(detail.error_line) # Line number
115
+ print(detail.error_column) # Column number
116
+
117
+ # Format SQL
118
+ formatted = pygosqlx.format("select id,name from users where id=1")
119
+ print(formatted)
120
+
121
+ # Extract table names
122
+ tables = pygosqlx.extract_tables(
123
+ "SELECT u.name, o.total FROM users u JOIN orders o ON u.id = o.user_id"
124
+ )
125
+ print(tables) # ['users', 'orders']
126
+
127
+ # Extract column names
128
+ columns = pygosqlx.extract_columns("SELECT id, name, email FROM users")
129
+ print(columns) # ['id', 'name', 'email']
130
+
131
+ # Extract function calls
132
+ functions = pygosqlx.extract_functions(
133
+ "SELECT COUNT(*), AVG(price) FROM orders"
134
+ )
135
+ print(functions) # ['COUNT', 'AVG']
136
+
137
+ # Extract all metadata at once
138
+ meta = pygosqlx.extract_metadata(
139
+ "SELECT u.name, COUNT(o.id) FROM users u JOIN orders o ON u.id = o.user_id GROUP BY u.name"
140
+ )
141
+ print(meta.tables) # ['users', 'orders']
142
+ print(meta.columns) # ['name', 'id']
143
+ print(meta.functions) # ['COUNT']
144
+ # Qualified names available too:
145
+ for qn in meta.tables_qualified:
146
+ print(f"{qn.schema}.{qn.name}" if qn.schema else qn.name)
147
+ ```
148
+
149
+ ### Dialects
150
+
151
+ Every parsing function takes an optional keyword-only `dialect=` argument.
152
+ Without it (or with `dialect=None`) the default parser is used, exactly as in
153
+ earlier releases.
154
+
155
+ ```python
156
+ print(pygosqlx.dialects())
157
+ # ['generic', 'postgresql', 'mysql', 'mariadb', 'sqlserver', 'oracle',
158
+ # 'sqlite', 'snowflake', 'bigquery', 'redshift', 'clickhouse']
159
+
160
+ sql = "SELECT TOP 5 [id] FROM [dbo].[users]"
161
+ pygosqlx.validate(sql) # False - not generic SQL
162
+ pygosqlx.validate(sql, dialect="sqlserver") # True
163
+ pygosqlx.extract_tables(sql, dialect="sqlserver") # ['dbo.users']
164
+ pygosqlx.format("SELECT `id` FROM `users`", dialect="mysql")
165
+
166
+ # An unknown dialect raises UnsupportedDialectError (also a ValueError)
167
+ pygosqlx.parse("SELECT 1", dialect="postgres") # use "postgresql"
168
+ ```
169
+
170
+ ### Linting
171
+
172
+ `lint()` runs the same rule set as the `gosqlx lint` CLI command (L001-L010:
173
+ whitespace, indentation, line length, column alignment, keyword case, comma
174
+ placement, aliasing). SQL that does not parse is still linted by the text and
175
+ token rules.
176
+
177
+ ```python
178
+ result = pygosqlx.lint("select id from users ", max_line_length=100)
179
+ for v in result.violations:
180
+ print(v.rule, v.severity, v.line, v.column, v.message)
181
+ # L001 warning 1 21 Line has trailing whitespace
182
+ # L007 warning 1 1 Keyword 'select' should be uppercase: 'SELECT'
183
+ # ...
184
+ print(result.is_clean, result.violation_count)
185
+ ```
186
+
187
+ ### Security scanning
188
+
189
+ `security_scan()` looks for SQL injection patterns (tautologies, comment
190
+ bypasses, stacked queries, UNION injection, time-based and out-of-band
191
+ techniques, dangerous functions). The scan works on the raw text, so payloads
192
+ that are not valid SQL are scanned too.
193
+
194
+ ```python
195
+ scan = pygosqlx.security_scan("SELECT * FROM users WHERE id = 1 OR 1=1 --")
196
+ print(scan.is_clean, scan.has_critical) # False True
197
+ for f in scan.findings:
198
+ print(f.severity, f.pattern, f.description)
199
+ ```
200
+
201
+ ### Transpiling
202
+
203
+ ```python
204
+ pygosqlx.transpile(
205
+ "CREATE TABLE t (id INT AUTO_INCREMENT PRIMARY KEY)", "mysql", "postgresql"
206
+ )
207
+ # 'CREATE TABLE t (id SERIAL PRIMARY KEY)'
208
+ ```
209
+
210
+ Dedicated rewrites exist for MySQL to PostgreSQL, PostgreSQL to MySQL and
211
+ PostgreSQL to SQLite. Other pairs are parsed with the source dialect and
212
+ re-rendered without rewrites.
213
+
214
+ ### Library compatibility
215
+
216
+ The functions and the `dialect=` argument added in 1.16.0 need a shared
217
+ library built from a matching GoSQLX checkout. With an older library, calls
218
+ without `dialect=` keep working, while `dialect=`, `lint()`,
219
+ `security_scan()`, `transpile()` and `dialects()` raise `GoSQLXError` asking
220
+ you to rebuild the library.
221
+
222
+ ### Error Handling
223
+
224
+ ```python
225
+ from pygosqlx import parse, validate, extract_tables
226
+ from pygosqlx.exceptions import ParseError, FormatError, GoSQLXError
227
+
228
+ # parse() raises ParseError on invalid SQL
229
+ try:
230
+ result = parse("SELECT * FORM users")
231
+ except ParseError as e:
232
+ print(f"Error: {e.message}")
233
+ print(f"At line {e.line}, column {e.column}")
234
+
235
+ # validate() returns a boolean (never raises)
236
+ if not validate("BAD SQL"):
237
+ print("Invalid SQL")
238
+
239
+ # extract_*() functions raise ParseError on invalid SQL
240
+ try:
241
+ tables = extract_tables("NOT VALID SQL")
242
+ except ParseError as e:
243
+ print(f"Parse error: {e}")
244
+
245
+ # All exceptions inherit from GoSQLXError
246
+ try:
247
+ parse("???")
248
+ except GoSQLXError as e:
249
+ print(f"Caught: {e}")
250
+ ```
251
+
252
+ ## API Reference
253
+
254
+ | Function | Returns | Description |
255
+ |---|---|---|
256
+ | `parse(sql, *, dialect=None)` | `ParseResult` | Parse SQL; raises `ParseError` on failure |
257
+ | `validate(sql, *, dialect=None)` | `bool` | Check if SQL is syntactically valid |
258
+ | `validate_detailed(sql, *, dialect=None)` | `ValidationResult` | Validate with error line/column details |
259
+ | `format(sql, *, dialect=None)` | `str` | Format/pretty-print a SQL statement |
260
+ | `extract_tables(sql, *, dialect=None)` | `list[str]` | Extract all table names |
261
+ | `extract_columns(sql, *, dialect=None)` | `list[str]` | Extract all column names |
262
+ | `extract_functions(sql, *, dialect=None)` | `list[str]` | Extract all function calls |
263
+ | `extract_metadata(sql, *, dialect=None)` | `Metadata` | Extract tables, columns, functions, and qualified names |
264
+ | `lint(sql, *, dialect=None, max_line_length=None)` | `LintResult` | Lint with the `gosqlx lint` rule set (L001-L010); `max_line_length` defaults to 100 |
265
+ | `security_scan(sql)` | `SecurityScanResult` | Scan for SQL injection patterns |
266
+ | `transpile(sql, from_dialect, to_dialect)` | `str` | Convert SQL between dialects; raises `TranspileError` on failure |
267
+ | `dialects()` | `list[str]` | Names accepted by every `dialect` argument |
268
+ | `version()` | `str` | Get the GoSQLX library version |
269
+
270
+ `dialect` must be one of the names returned by `dialects()`; an unknown name
271
+ raises `UnsupportedDialectError`.
272
+
273
+ ### Data Types
274
+
275
+ | Type | Fields |
276
+ |---|---|
277
+ | `ParseResult` | `statement_count: int`, `statement_types: list[str]` |
278
+ | `ValidationResult` | `valid: bool`, `error: str?`, `error_line: int?`, `error_column: int?` |
279
+ | `Metadata` | `tables`, `columns`, `functions`, `tables_qualified`, `columns_qualified` |
280
+ | `QualifiedName` | `name: str`, `schema: str`, `table: str` |
281
+ | `LintResult` | `violations: list[LintViolation]`; properties `violation_count`, `is_clean` |
282
+ | `LintViolation` | `rule`, `rule_name`, `severity`, `message`, `line`, `column`, `suggestion`, `can_auto_fix` |
283
+ | `SecurityScanResult` | `findings: list[SecurityFinding]`, `total_count`, `critical_count`, `high_count`, `medium_count`, `low_count`; properties `is_clean`, `has_critical`, `has_high` |
284
+ | `SecurityFinding` | `severity`, `pattern`, `description`, `risk`, `line: int?`, `column: int?`, `sql`, `suggestion` |
285
+
286
+ ### Exceptions
287
+
288
+ | Exception | Base | When |
289
+ |---|---|---|
290
+ | `GoSQLXError` | `Exception` | Base for all PyGoSQLX errors |
291
+ | `ParseError` | `GoSQLXError` | SQL parsing fails |
292
+ | `FormatError` | `GoSQLXError` | SQL formatting fails |
293
+ | `ValidationError` | `GoSQLXError` | SQL validation fails |
294
+ | `TranspileError` | `GoSQLXError` | `transpile()` cannot parse or rewrite the SQL |
295
+ | `UnsupportedDialectError` | `GoSQLXError`, `ValueError` | A `dialect` argument is not a supported dialect (`code` is `E4002`) |
296
+
297
+ All exceptions have `message`, `code`, `line`, and `column` attributes.
298
+
299
+ ## Platform Support
300
+
301
+ | Platform | Library | Prebuilt wheel | From source |
302
+ |---|---|---|---|
303
+ | Linux x86_64, aarch64 (glibc) | `.so` | Yes (glibc 2.17+) | Yes |
304
+ | macOS x86_64, arm64 | `.dylib` | Yes (macOS 13+) | Yes |
305
+ | Windows AMD64 | `.dll` | Yes | Yes (MSYS2/MinGW) |
306
+ | Other (musl, 32-bit, ...) | - | No | Where Go supports `-buildmode=c-shared` |
307
+
308
+ ## Performance
309
+
310
+ PyGoSQLX calls into compiled Go code via ctypes, avoiding the overhead of pure Python parsing. Typical performance characteristics:
311
+
312
+ - **1M+ operations/sec** for simple queries
313
+ - **Sub-microsecond** validation for short SQL statements
314
+ - **Zero-copy** tokenization in the Go layer
315
+ - **Object pooling** for minimal GC pressure
316
+
317
+ This makes PyGoSQLX suitable for high-throughput use cases such as SQL proxies, query analyzers, and CI/CD validation pipelines.
318
+
319
+ ## Development
320
+
321
+ ### Running tests
322
+
323
+ ```bash
324
+ cd python
325
+ pytest -v # All tests
326
+ pytest tests/test_types.py # Type/exception tests (no shared library needed)
327
+ pytest tests/test_integration.py # Integration tests (requires shared library)
328
+ pytest --cov=pygosqlx # With coverage
329
+ ```
330
+
331
+ To run the suite against an installed wheel instead of the checkout (as the
332
+ release CI does):
333
+
334
+ ```bash
335
+ pip install pygosqlx pytest # or a locally built wheel
336
+ cd /tmp && PYGOSQLX_TEST_INSTALLED=1 python -m pytest --import-mode=importlib /path/to/GoSQLX/python/tests
337
+ ```
338
+
339
+ ### Releasing
340
+
341
+ Wheels for every supported platform and an sdist are built and tested by
342
+ `.github/workflows/pygosqlx-release.yml` on each pull request that touches
343
+ `python/` or `pkg/`. Pushing the GoSQLX release tag `vX.Y.Z` publishes them to
344
+ PyPI through Trusted Publishing, so bump `pyproject.toml` and `__version__`
345
+ in the release PR. Python-only follow-ups use a `pygosqlx-vX.Y.Z.postN` tag.
346
+ Either tag must match `pyproject.toml` and point at a commit on `main`; tag
347
+ pushes are the only path to PyPI. A manual dispatch
348
+ can publish a dry run to TestPyPI. See the workflow header for the one-time PyPI setup.
349
+
350
+ ### Project structure
351
+
352
+ ```
353
+ python/
354
+ pygosqlx/
355
+ __init__.py # Package entry point, public API
356
+ core.py # ctypes bindings to the Go shared library
357
+ exceptions.py # Custom exception hierarchy
358
+ py.typed # PEP 561 type hint marker
359
+ lib/ # Shared library output directory (built artifacts)
360
+ tests/
361
+ test_types.py # Type and exception tests (no shared library needed)
362
+ test_package_version.py # Version metadata consistency
363
+ test_integration.py # Integration tests with shared library
364
+ test_dialect_and_analysis.py # dialect=, lint, security_scan, transpile, dialects
365
+ test_installed_wheel.py # Installed-wheel checks (PYGOSQLX_TEST_INSTALLED=1)
366
+ scripts/
367
+ install-go-linux.sh # Pinned, checksum-verified Go install for manylinux CI
368
+ pyproject.toml # Package metadata and build config
369
+ setup.py # Shim that tags wheels per platform (no metadata)
370
+ ```
371
+
372
+ ## License
373
+
374
+ Apache-2.0. See the [LICENSE](https://github.com/ajitpratap0/GoSQLX/blob/main/LICENSE) file.