asyncpg-typed 0.1.3__tar.gz → 0.1.4__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.
- {asyncpg_typed-0.1.3 → asyncpg_typed-0.1.4}/LICENSE +1 -1
- {asyncpg_typed-0.1.3/asyncpg_typed.egg-info → asyncpg_typed-0.1.4}/PKG-INFO +47 -18
- {asyncpg_typed-0.1.3 → asyncpg_typed-0.1.4}/README.md +46 -17
- {asyncpg_typed-0.1.3 → asyncpg_typed-0.1.4}/asyncpg_typed/__init__.py +265 -60
- {asyncpg_typed-0.1.3 → asyncpg_typed-0.1.4/asyncpg_typed.egg-info}/PKG-INFO +47 -18
- {asyncpg_typed-0.1.3 → asyncpg_typed-0.1.4}/tests/test_code.py +11 -16
- {asyncpg_typed-0.1.3 → asyncpg_typed-0.1.4}/tests/test_data.py +53 -0
- asyncpg_typed-0.1.4/tests/test_sql.py +428 -0
- {asyncpg_typed-0.1.3 → asyncpg_typed-0.1.4}/tests/test_vector.py +2 -2
- asyncpg_typed-0.1.3/tests/test_sql.py +0 -229
- {asyncpg_typed-0.1.3 → asyncpg_typed-0.1.4}/MANIFEST.in +0 -0
- {asyncpg_typed-0.1.3 → asyncpg_typed-0.1.4}/asyncpg_typed/py.typed +0 -0
- {asyncpg_typed-0.1.3 → asyncpg_typed-0.1.4}/asyncpg_typed.egg-info/SOURCES.txt +0 -0
- {asyncpg_typed-0.1.3 → asyncpg_typed-0.1.4}/asyncpg_typed.egg-info/dependency_links.txt +0 -0
- {asyncpg_typed-0.1.3 → asyncpg_typed-0.1.4}/asyncpg_typed.egg-info/requires.txt +0 -0
- {asyncpg_typed-0.1.3 → asyncpg_typed-0.1.4}/asyncpg_typed.egg-info/top_level.txt +0 -0
- {asyncpg_typed-0.1.3 → asyncpg_typed-0.1.4}/asyncpg_typed.egg-info/zip-safe +0 -0
- {asyncpg_typed-0.1.3 → asyncpg_typed-0.1.4}/pyproject.toml +0 -0
- {asyncpg_typed-0.1.3 → asyncpg_typed-0.1.4}/setup.cfg +0 -0
- {asyncpg_typed-0.1.3 → asyncpg_typed-0.1.4}/tests/__init__.py +0 -0
- {asyncpg_typed-0.1.3 → asyncpg_typed-0.1.4}/tests/connection.py +0 -0
- {asyncpg_typed-0.1.3 → asyncpg_typed-0.1.4}/tests/test_template.py +0 -0
- {asyncpg_typed-0.1.3 → asyncpg_typed-0.1.4}/tests/test_type.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: asyncpg_typed
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.4
|
|
4
4
|
Summary: Type-safe queries for asyncpg
|
|
5
5
|
Author-email: Levente Hunyadi <hunyadi@gmail.com>
|
|
6
6
|
Maintainer-email: Levente Hunyadi <hunyadi@gmail.com>
|
|
@@ -45,6 +45,8 @@ This Python library provides "compile-time" validation for SQL queries that lint
|
|
|
45
45
|
|
|
46
46
|
## Motivating example
|
|
47
47
|
|
|
48
|
+
### Using a plain tuple
|
|
49
|
+
|
|
48
50
|
```python
|
|
49
51
|
# create a typed object, setting expected and returned types
|
|
50
52
|
select_where_sql = sql(
|
|
@@ -66,7 +68,7 @@ try:
|
|
|
66
68
|
# ✅ Type of "rows" is "list[tuple[bool, int, str | None]]"
|
|
67
69
|
reveal_type(rows)
|
|
68
70
|
|
|
69
|
-
# ⚠️
|
|
71
|
+
# ⚠️ Expected 1 more positional argument
|
|
70
72
|
rows = await select_where_sql.fetch(conn, False)
|
|
71
73
|
|
|
72
74
|
# ⚠️ Argument of type "float" cannot be assigned to parameter "arg2" of type "int" in function "fetch"; "float" is not assignable to "int"
|
|
@@ -74,27 +76,52 @@ try:
|
|
|
74
76
|
|
|
75
77
|
finally:
|
|
76
78
|
await conn.close()
|
|
79
|
+
```
|
|
77
80
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
+
### Using a named tuple
|
|
82
|
+
|
|
83
|
+
```python
|
|
84
|
+
# capture resultset column names and data types as fields of a named tuple
|
|
85
|
+
class Resultset(NamedTuple):
|
|
81
86
|
boolean_value: bool
|
|
82
87
|
integer_value: int
|
|
83
88
|
string_value: str | None
|
|
84
89
|
|
|
85
|
-
# ✅ Valid initializer call
|
|
86
|
-
items = [DataObject(*row) for row in rows]
|
|
87
90
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
integer_value
|
|
92
|
-
|
|
91
|
+
# create a typed object, declaring return types with the named tuple
|
|
92
|
+
select_sql = sql(
|
|
93
|
+
"""--sql
|
|
94
|
+
SELECT boolean_value, integer_value, string_value
|
|
95
|
+
FROM sample_data
|
|
96
|
+
ORDER BY integer_value;
|
|
97
|
+
""",
|
|
98
|
+
resultset=Resultset,
|
|
99
|
+
)
|
|
93
100
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
101
|
+
conn = await asyncpg.connect(host="localhost", port=5432, user="postgres", password="postgres")
|
|
102
|
+
try:
|
|
103
|
+
rows = await select_sql.fetch(conn)
|
|
104
|
+
|
|
105
|
+
# ✅ Type of "rows" is "list[Resultset]"
|
|
106
|
+
reveal_type(rows)
|
|
107
|
+
|
|
108
|
+
for row in rows:
|
|
109
|
+
# use dot notation to access properties
|
|
110
|
+
if row.string_value is not None:
|
|
111
|
+
print(f"#{row.integer_value}: {row.string_value}")
|
|
112
|
+
|
|
113
|
+
# ✅ Type of "row.boolean_value" is "bool"
|
|
114
|
+
reveal_type(row.boolean_value)
|
|
97
115
|
|
|
116
|
+
# unpack named tuple
|
|
117
|
+
b, i, s = row
|
|
118
|
+
|
|
119
|
+
# ✅ Type of "s" is "str | None"
|
|
120
|
+
reveal_type(s)
|
|
121
|
+
|
|
122
|
+
finally:
|
|
123
|
+
await conn.close()
|
|
124
|
+
```
|
|
98
125
|
|
|
99
126
|
## Syntax
|
|
100
127
|
|
|
@@ -284,10 +311,12 @@ Only those functions are prompted on code completion that make sense in the cont
|
|
|
284
311
|
|
|
285
312
|
#### Run-time behavior
|
|
286
313
|
|
|
287
|
-
When a call such as `sql.executemany(conn, records)` or `sql.fetch(conn, param1, param2)` is made on a `SQL` object at run time, the library invokes `connection.prepare(sql)` to create a `PreparedStatement` and compares the actual statement signature against the expected Python types. If the expected and actual signatures don't match,
|
|
314
|
+
When a call such as `sql.executemany(conn, records)` or `sql.fetch(conn, param1, param2)` is made on a `SQL` object at run time, the library invokes `connection.prepare(sql)` to create a `PreparedStatement` and compares the actual statement signature against the expected Python types. If the expected and actual signatures don't match, a `TypeMismatchError` exception is raised.
|
|
315
|
+
|
|
316
|
+
If the resultset type has been declared with a subclass of `NamedTuple`, the field names of the tuple are compared against the column names of the PostgreSQL resultset. Should there be a mismatch, a `NameMismatchError` is raised. Field and column order is relevant.
|
|
288
317
|
|
|
289
|
-
The set of values for an enumeration type is validated when a prepared statement is created. The string values declared in a Python `StrEnum` are compared against the values listed in PostgreSQL `CREATE TYPE ... AS ENUM` by querying the system table `pg_enum`. If there are missing or extra values on either side, an
|
|
318
|
+
The set of values for an enumeration type is validated when a prepared statement is created. The string values declared in a Python `StrEnum` are compared against the values listed in PostgreSQL `CREATE TYPE ... AS ENUM` by querying the system table `pg_enum`. If there are missing or extra values on either side, an `EnumMismatchError` exception is raised.
|
|
290
319
|
|
|
291
|
-
Unfortunately, PostgreSQL doesn't propagate nullability via prepared statements: resultset types that are declared as required (e.g. `T` as opposed to `T | None`)
|
|
320
|
+
Unfortunately, PostgreSQL doesn't propagate nullability via prepared statements: resultset types that are declared as required (e.g. `T` as opposed to `T | None`) have to be validated at run time. When a `None` value is encountered for a required type, a `NoneTypeError` exception is raised.
|
|
292
321
|
|
|
293
322
|
PostgreSQL doesn't differentiate between IPv4 and IPv6 network definitions, or IPv4 and IPv6 addresses in the types `cidr` and `inet`. This means that semantically a union type is returned. If you specify a more restrictive type, the resultset data is validated dynamically at run time.
|
|
@@ -7,6 +7,8 @@ This Python library provides "compile-time" validation for SQL queries that lint
|
|
|
7
7
|
|
|
8
8
|
## Motivating example
|
|
9
9
|
|
|
10
|
+
### Using a plain tuple
|
|
11
|
+
|
|
10
12
|
```python
|
|
11
13
|
# create a typed object, setting expected and returned types
|
|
12
14
|
select_where_sql = sql(
|
|
@@ -28,7 +30,7 @@ try:
|
|
|
28
30
|
# ✅ Type of "rows" is "list[tuple[bool, int, str | None]]"
|
|
29
31
|
reveal_type(rows)
|
|
30
32
|
|
|
31
|
-
# ⚠️
|
|
33
|
+
# ⚠️ Expected 1 more positional argument
|
|
32
34
|
rows = await select_where_sql.fetch(conn, False)
|
|
33
35
|
|
|
34
36
|
# ⚠️ Argument of type "float" cannot be assigned to parameter "arg2" of type "int" in function "fetch"; "float" is not assignable to "int"
|
|
@@ -36,27 +38,52 @@ try:
|
|
|
36
38
|
|
|
37
39
|
finally:
|
|
38
40
|
await conn.close()
|
|
41
|
+
```
|
|
39
42
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
+
### Using a named tuple
|
|
44
|
+
|
|
45
|
+
```python
|
|
46
|
+
# capture resultset column names and data types as fields of a named tuple
|
|
47
|
+
class Resultset(NamedTuple):
|
|
43
48
|
boolean_value: bool
|
|
44
49
|
integer_value: int
|
|
45
50
|
string_value: str | None
|
|
46
51
|
|
|
47
|
-
# ✅ Valid initializer call
|
|
48
|
-
items = [DataObject(*row) for row in rows]
|
|
49
52
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
integer_value
|
|
54
|
-
|
|
53
|
+
# create a typed object, declaring return types with the named tuple
|
|
54
|
+
select_sql = sql(
|
|
55
|
+
"""--sql
|
|
56
|
+
SELECT boolean_value, integer_value, string_value
|
|
57
|
+
FROM sample_data
|
|
58
|
+
ORDER BY integer_value;
|
|
59
|
+
""",
|
|
60
|
+
resultset=Resultset,
|
|
61
|
+
)
|
|
55
62
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
63
|
+
conn = await asyncpg.connect(host="localhost", port=5432, user="postgres", password="postgres")
|
|
64
|
+
try:
|
|
65
|
+
rows = await select_sql.fetch(conn)
|
|
66
|
+
|
|
67
|
+
# ✅ Type of "rows" is "list[Resultset]"
|
|
68
|
+
reveal_type(rows)
|
|
69
|
+
|
|
70
|
+
for row in rows:
|
|
71
|
+
# use dot notation to access properties
|
|
72
|
+
if row.string_value is not None:
|
|
73
|
+
print(f"#{row.integer_value}: {row.string_value}")
|
|
74
|
+
|
|
75
|
+
# ✅ Type of "row.boolean_value" is "bool"
|
|
76
|
+
reveal_type(row.boolean_value)
|
|
59
77
|
|
|
78
|
+
# unpack named tuple
|
|
79
|
+
b, i, s = row
|
|
80
|
+
|
|
81
|
+
# ✅ Type of "s" is "str | None"
|
|
82
|
+
reveal_type(s)
|
|
83
|
+
|
|
84
|
+
finally:
|
|
85
|
+
await conn.close()
|
|
86
|
+
```
|
|
60
87
|
|
|
61
88
|
## Syntax
|
|
62
89
|
|
|
@@ -246,10 +273,12 @@ Only those functions are prompted on code completion that make sense in the cont
|
|
|
246
273
|
|
|
247
274
|
#### Run-time behavior
|
|
248
275
|
|
|
249
|
-
When a call such as `sql.executemany(conn, records)` or `sql.fetch(conn, param1, param2)` is made on a `SQL` object at run time, the library invokes `connection.prepare(sql)` to create a `PreparedStatement` and compares the actual statement signature against the expected Python types. If the expected and actual signatures don't match,
|
|
276
|
+
When a call such as `sql.executemany(conn, records)` or `sql.fetch(conn, param1, param2)` is made on a `SQL` object at run time, the library invokes `connection.prepare(sql)` to create a `PreparedStatement` and compares the actual statement signature against the expected Python types. If the expected and actual signatures don't match, a `TypeMismatchError` exception is raised.
|
|
277
|
+
|
|
278
|
+
If the resultset type has been declared with a subclass of `NamedTuple`, the field names of the tuple are compared against the column names of the PostgreSQL resultset. Should there be a mismatch, a `NameMismatchError` is raised. Field and column order is relevant.
|
|
250
279
|
|
|
251
|
-
The set of values for an enumeration type is validated when a prepared statement is created. The string values declared in a Python `StrEnum` are compared against the values listed in PostgreSQL `CREATE TYPE ... AS ENUM` by querying the system table `pg_enum`. If there are missing or extra values on either side, an
|
|
280
|
+
The set of values for an enumeration type is validated when a prepared statement is created. The string values declared in a Python `StrEnum` are compared against the values listed in PostgreSQL `CREATE TYPE ... AS ENUM` by querying the system table `pg_enum`. If there are missing or extra values on either side, an `EnumMismatchError` exception is raised.
|
|
252
281
|
|
|
253
|
-
Unfortunately, PostgreSQL doesn't propagate nullability via prepared statements: resultset types that are declared as required (e.g. `T` as opposed to `T | None`)
|
|
282
|
+
Unfortunately, PostgreSQL doesn't propagate nullability via prepared statements: resultset types that are declared as required (e.g. `T` as opposed to `T | None`) have to be validated at run time. When a `None` value is encountered for a required type, a `NoneTypeError` exception is raised.
|
|
254
283
|
|
|
255
284
|
PostgreSQL doesn't differentiate between IPv4 and IPv6 network definitions, or IPv4 and IPv6 addresses in the types `cidr` and `inet`. This means that semantically a union type is returned. If you specify a more restrictive type, the resultset data is validated dynamically at run time.
|