mapepire-python 0.1.8__tar.gz → 0.3.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.
- {mapepire_python-0.1.8 → mapepire_python-0.3.0}/PKG-INFO +263 -44
- {mapepire_python-0.1.8 → mapepire_python-0.3.0}/README.md +249 -26
- mapepire_python-0.3.0/mapepire_python/__init__.py +77 -0
- mapepire_python-0.3.0/mapepire_python/async_base_job.py +216 -0
- {mapepire_python-0.1.8 → mapepire_python-0.3.0}/mapepire_python/asyncio/__init__.py +12 -3
- {mapepire_python-0.1.8 → mapepire_python-0.3.0}/mapepire_python/asyncio/connection.py +40 -14
- mapepire_python-0.3.0/mapepire_python/asyncio/cursor.py +156 -0
- mapepire_python-0.3.0/mapepire_python/authentication/kerberosTokenProvider.py +115 -0
- {mapepire_python-0.1.8 → mapepire_python-0.3.0}/mapepire_python/base_job.py +15 -5
- mapepire_python-0.3.0/mapepire_python/client/async_sql_job.py +14 -0
- mapepire_python-0.3.0/mapepire_python/client/query.py +205 -0
- {mapepire_python-0.1.8 → mapepire_python-0.3.0}/mapepire_python/client/sql_job.py +39 -21
- mapepire_python-0.3.0/mapepire_python/client/websocket_client.py +20 -0
- {mapepire_python-0.1.8 → mapepire_python-0.3.0}/mapepire_python/core/connection.py +7 -2
- {mapepire_python-0.1.8 → mapepire_python-0.3.0}/mapepire_python/core/cursor.py +50 -24
- {mapepire_python-0.1.8 → mapepire_python-0.3.0}/mapepire_python/core/exceptions.py +18 -20
- {mapepire_python-0.1.8 → mapepire_python-0.3.0}/mapepire_python/core/utils.py +38 -9
- mapepire_python-0.3.0/mapepire_python/data_types.py +528 -0
- mapepire_python-0.3.0/mapepire_python/pool/async_websocket_client.py +18 -0
- {mapepire_python-0.1.8 → mapepire_python-0.3.0}/mapepire_python/pool/pool_client.py +42 -14
- mapepire_python-0.3.0/mapepire_python/pool/pool_job.py +36 -0
- mapepire_python-0.3.0/mapepire_python/pool/pool_query.py +168 -0
- {mapepire_python-0.1.8 → mapepire_python-0.3.0}/mapepire_python/query_manager.py +0 -3
- {mapepire_python-0.1.8 → mapepire_python-0.3.0}/mapepire_python/ssl.py +7 -1
- {mapepire_python-0.1.8 → mapepire_python-0.3.0}/mapepire_python/version.py +2 -2
- mapepire_python-0.3.0/mapepire_python/websocket.py +74 -0
- {mapepire_python-0.1.8 → mapepire_python-0.3.0}/mapepire_python.egg-info/PKG-INFO +263 -44
- {mapepire_python-0.1.8 → mapepire_python-0.3.0}/mapepire_python.egg-info/SOURCES.txt +6 -2
- mapepire_python-0.3.0/mapepire_python.egg-info/requires.txt +25 -0
- {mapepire_python-0.1.8 → mapepire_python-0.3.0}/pyproject.toml +45 -19
- mapepire_python-0.1.8/mapepire_python/__init__.py +0 -49
- mapepire_python-0.1.8/mapepire_python/asyncio/cursor.py +0 -99
- mapepire_python-0.1.8/mapepire_python/asyncio/utils.py +0 -23
- mapepire_python-0.1.8/mapepire_python/client/query.py +0 -185
- mapepire_python-0.1.8/mapepire_python/client/websocket.py +0 -40
- mapepire_python-0.1.8/mapepire_python/data_types.py +0 -245
- mapepire_python-0.1.8/mapepire_python/pool/pool_job.py +0 -318
- mapepire_python-0.1.8/mapepire_python/pool/pool_query.py +0 -136
- mapepire_python-0.1.8/mapepire_python.egg-info/requires.txt +0 -29
- {mapepire_python-0.1.8 → mapepire_python-0.3.0}/LICENSE +0 -0
- {mapepire_python-0.1.8 → mapepire_python-0.3.0}/mapepire_python/client/__init__.py +0 -0
- {mapepire_python-0.1.8 → mapepire_python-0.3.0}/mapepire_python/core/__init__.py +0 -0
- {mapepire_python-0.1.8 → mapepire_python-0.3.0}/mapepire_python/pool/__init__.py +0 -0
- {mapepire_python-0.1.8 → mapepire_python-0.3.0}/mapepire_python/py.typed +0 -0
- {mapepire_python-0.1.8 → mapepire_python-0.3.0}/mapepire_python.egg-info/dependency_links.txt +0 -0
- {mapepire_python-0.1.8 → mapepire_python-0.3.0}/mapepire_python.egg-info/top_level.txt +0 -0
- {mapepire_python-0.1.8 → mapepire_python-0.3.0}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: mapepire-python
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.3.0
|
|
4
4
|
Author-email: Adam Shedivy <adam.shedivy@ibm.com>, Irfan Sharif <IrfanSharif@ibm.com>
|
|
5
5
|
License: Apache License
|
|
6
6
|
Version 2.0, January 2004
|
|
@@ -207,42 +207,38 @@ License: Apache License
|
|
|
207
207
|
Project-URL: Homepage, https://github.com/Mapepire-IBMi/mapepire-python
|
|
208
208
|
Project-URL: Repository, https://github.com/Mapepire-IBMi/mapepire-python
|
|
209
209
|
Project-URL: Changelog, https://github.com/Mapepire-IBMi/mapepire-python/blob/main/CHANGELOG.md
|
|
210
|
+
Project-URL: Documentation, https://mapepire-ibmi.github.io/
|
|
210
211
|
Classifier: Intended Audience :: Science/Research
|
|
211
212
|
Classifier: Development Status :: 3 - Alpha
|
|
212
213
|
Classifier: License :: OSI Approved :: Apache Software License
|
|
213
214
|
Classifier: Programming Language :: Python :: 3
|
|
214
215
|
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
215
|
-
Requires-Python:
|
|
216
|
+
Requires-Python: >=3.10
|
|
216
217
|
Description-Content-Type: text/markdown
|
|
217
218
|
License-File: LICENSE
|
|
218
219
|
Requires-Dist: dataclasses-json>=0.6.4
|
|
219
|
-
Requires-Dist:
|
|
220
|
-
Requires-Dist: websockets==13.1
|
|
221
|
-
Requires-Dist: pyee
|
|
220
|
+
Requires-Dist: websockets>=14.0
|
|
222
221
|
Requires-Dist: pep249abc
|
|
223
222
|
Provides-Extra: dev
|
|
224
223
|
Requires-Dist: ruff; extra == "dev"
|
|
225
|
-
Requires-Dist: mypy<1.
|
|
226
|
-
Requires-Dist: black<
|
|
227
|
-
Requires-Dist: isort<
|
|
228
|
-
Requires-Dist: pytest; extra == "dev"
|
|
229
|
-
Requires-Dist: pyee; extra == "dev"
|
|
224
|
+
Requires-Dist: mypy<1.20,>=1.0; extra == "dev"
|
|
225
|
+
Requires-Dist: black<27.0,>=24.3.0; extra == "dev"
|
|
226
|
+
Requires-Dist: isort<6.2,>=5.12; extra == "dev"
|
|
227
|
+
Requires-Dist: pytest>=9.0.3; extra == "dev"
|
|
230
228
|
Requires-Dist: pep249abc; extra == "dev"
|
|
231
229
|
Requires-Dist: pytest-asyncio; extra == "dev"
|
|
232
|
-
Requires-Dist: pytest-sphinx; extra == "dev"
|
|
233
230
|
Requires-Dist: pytest-cov; extra == "dev"
|
|
234
231
|
Requires-Dist: twine>=1.11.0; extra == "dev"
|
|
235
232
|
Requires-Dist: build; extra == "dev"
|
|
236
233
|
Requires-Dist: setuptools; extra == "dev"
|
|
237
234
|
Requires-Dist: wheel; extra == "dev"
|
|
238
|
-
Requires-Dist: Sphinx<7.1.0,>=4.3.0; extra == "dev"
|
|
239
|
-
Requires-Dist: furo==2023.7.26; extra == "dev"
|
|
240
|
-
Requires-Dist: myst-parser<2.1,>=1.0; extra == "dev"
|
|
241
|
-
Requires-Dist: sphinx-copybutton==0.5.2; extra == "dev"
|
|
242
|
-
Requires-Dist: sphinx-autobuild==2021.3.14; extra == "dev"
|
|
243
|
-
Requires-Dist: sphinx-autodoc-typehints==1.23.3; extra == "dev"
|
|
244
235
|
Requires-Dist: packaging; extra == "dev"
|
|
245
236
|
Requires-Dist: pre-commit; extra == "dev"
|
|
237
|
+
Requires-Dist: python-dotenv; extra == "dev"
|
|
238
|
+
Requires-Dist: pytest-env; extra == "dev"
|
|
239
|
+
Requires-Dist: gssapi; extra == "dev"
|
|
240
|
+
Requires-Dist: pywin32; sys_platform == "win32" and extra == "dev"
|
|
241
|
+
Dynamic: license-file
|
|
246
242
|
|
|
247
243
|
# mapepire-python
|
|
248
244
|
<div align="center">
|
|
@@ -266,10 +262,16 @@ Requires-Dist: pre-commit; extra == "dev"
|
|
|
266
262
|
- [Setup](#setup)
|
|
267
263
|
- [Install with `pip`](#install-with-pip)
|
|
268
264
|
- [Server Component Setup](#server-component-setup)
|
|
269
|
-
- [
|
|
265
|
+
- [Quick Start](#quick-start)
|
|
266
|
+
- [Other Connection options](#other-connection-options)
|
|
270
267
|
- [1. Using the `DaemonServer` object](#1-using-the-daemonserver-object)
|
|
268
|
+
- [1.1 Authenticating with Kerberos](#11-authenticating-with-kerberos)
|
|
269
|
+
- [1.1.1 Windows](#111-windows)
|
|
270
|
+
- [1.1.2 Other Platforms](#112-other-platforms)
|
|
271
271
|
- [2. Passing the connection details as a dictionary](#2-passing-the-connection-details-as-a-dictionary)
|
|
272
272
|
- [3. Using a config file (`.ini`) to store the connection details](#3-using-a-config-file-ini-to-store-the-connection-details)
|
|
273
|
+
- [4. Using environment variables](#4-using-environment-variables)
|
|
274
|
+
- [TLS Configuration](#tls-configuration)
|
|
273
275
|
- [Usage](#usage)
|
|
274
276
|
- [1. Using the `SQLJob` object to run queries synchronously](#1-using-the-sqljob-object-to-run-queries-synchronously)
|
|
275
277
|
- [Query and run](#query-and-run)
|
|
@@ -315,6 +317,13 @@ Requires-Dist: pre-commit; extra == "dev"
|
|
|
315
317
|
|
|
316
318
|
`mapepire-python` requires Python 3.10 or later.
|
|
317
319
|
|
|
320
|
+
> [!NOTE]
|
|
321
|
+
> New websocket Implementation: As of version 0.2.0, `mapepire-python` uses the `websockets` library for websocket connections. If you are upgrading from a previous version, make sure to update your dependecies. The `websocket-client` library is no longer supported.
|
|
322
|
+
> - To update run `pip install -U mapepire-python`
|
|
323
|
+
>
|
|
324
|
+
> - More info on [websockets](https://websockets.readthedocs.io/en/stable/)
|
|
325
|
+
|
|
326
|
+
|
|
318
327
|
### Install with `pip`
|
|
319
328
|
|
|
320
329
|
`mapepire-python` is available on [PyPi](https://pypi.org/project/mapepire-python/). Just Run
|
|
@@ -326,43 +335,124 @@ pip install mapepire-python
|
|
|
326
335
|
### Server Component Setup
|
|
327
336
|
To use mapire-python, you will need to have the Mapepire Server Component running on your IBM i server. Follow these instructions to set up the server component: [Mapepire Server Installation](https://mapepire-ibmi.github.io/guides/sysadmin/)
|
|
328
337
|
|
|
329
|
-
|
|
330
|
-
|
|
338
|
+
# Quick Start
|
|
339
|
+
|
|
340
|
+
To get started with `mapepire-python`, you will need to setup a connection credentials for the Mapepire server. You can use a dictionary to store the connection details:
|
|
341
|
+
|
|
342
|
+
```python
|
|
343
|
+
from mapepire_python import connect
|
|
344
|
+
|
|
345
|
+
creds = {
|
|
346
|
+
"host": "SERVER",
|
|
347
|
+
"port": 8076,
|
|
348
|
+
"user": "USER",
|
|
349
|
+
"password": "PASSWORD",
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
with connect(creds) as conn:
|
|
353
|
+
with conn.execute("select * from sample.employee") as cursor:
|
|
354
|
+
result = cursor.fetchone()
|
|
355
|
+
print(result)
|
|
356
|
+
|
|
357
|
+
```
|
|
358
|
+
|
|
359
|
+
# Other Connection options
|
|
360
|
+
|
|
361
|
+
> [!NOTE]
|
|
362
|
+
> TLS support as of version 0.3.0 is now available. Server certificate verification is enabled by default. To disable certificate verification, set the `ignoreUnauthorized` field to `True` in the connection details.
|
|
363
|
+
> - To update run `pip install -U mapepire-python`
|
|
364
|
+
>
|
|
365
|
+
> - More info TLS Configuration [here](#tls-configuration)
|
|
331
366
|
|
|
332
|
-
There are
|
|
367
|
+
There are four ways to configure mapepire server connection details using `mapepire-python`:
|
|
333
368
|
|
|
334
369
|
1. Using the `DaemonServer` object
|
|
335
370
|
2. Passing the connection details as a dictionary
|
|
336
371
|
3. Using a config file (`.ini`) to store the connection details
|
|
372
|
+
4. Using environment variables
|
|
337
373
|
|
|
338
374
|
## 1. Using the `DaemonServer` object
|
|
339
375
|
|
|
340
|
-
|
|
376
|
+
`DaemonServer` is importable directly from `mapepire_python`:
|
|
341
377
|
|
|
342
378
|
```python
|
|
343
|
-
from mapepire_python
|
|
379
|
+
from mapepire_python import DaemonServer
|
|
344
380
|
|
|
345
381
|
creds = DaemonServer(
|
|
346
382
|
host="SERVER",
|
|
347
383
|
port="PORT",
|
|
348
384
|
user="USER",
|
|
349
|
-
password="PASSWORD"
|
|
350
|
-
ignoreUnauthorized=True
|
|
385
|
+
password="PASSWORD"
|
|
351
386
|
)
|
|
352
387
|
```
|
|
353
388
|
|
|
354
389
|
Once you have created the `DaemonServer` object, you can pass it to the `SQLJob` object to connect to the mapepire server:
|
|
355
390
|
|
|
356
391
|
```python
|
|
357
|
-
from mapepire_python
|
|
358
|
-
|
|
392
|
+
from mapepire_python import SQLJob, DaemonServer
|
|
393
|
+
|
|
394
|
+
creds = DaemonServer(
|
|
395
|
+
host="SERVER",
|
|
396
|
+
port="PORT",
|
|
397
|
+
user="USER",
|
|
398
|
+
password="PASSWORD"
|
|
399
|
+
)
|
|
400
|
+
|
|
401
|
+
job = SQLJob(creds)
|
|
402
|
+
```
|
|
403
|
+
|
|
404
|
+
### 1.1 Authenticating with Kerberos
|
|
405
|
+
If your IBM i is configured to support Kerberos authentication, you can authenticate using Kerberos instead of passing a plain-text password to the `DaemonServer` Object.
|
|
406
|
+
|
|
407
|
+
#### 1.1.1 Windows
|
|
408
|
+
|
|
409
|
+
If your Windows machine is part of a Kerberos realm and supports SSPI authentication, you can authenticate by creating the `DaemonServer` as shown below:
|
|
410
|
+
```python
|
|
411
|
+
from mapepire_python import DaemonServer
|
|
412
|
+
from mapepire_python.authentication.kerberosTokenProvider import KerberosTokenProvider
|
|
359
413
|
|
|
360
414
|
creds = DaemonServer(
|
|
361
415
|
host="SERVER",
|
|
416
|
+
password=KerberosTokenProvider(host="SERVER"),
|
|
417
|
+
user="USER",
|
|
362
418
|
port="PORT",
|
|
419
|
+
)
|
|
420
|
+
|
|
421
|
+
job = SQLJob(creds)
|
|
422
|
+
```
|
|
423
|
+
|
|
424
|
+
#### 1.1.2 Other Platforms
|
|
425
|
+
|
|
426
|
+
For non-Windows platforms, Kerberos authentication requires a valid Ticket Granting Ticket (TGT) in your credential cache.
|
|
427
|
+
|
|
428
|
+
Required Parameters:
|
|
429
|
+
|
|
430
|
+
1. `host`: The IBM i host you are connecting to
|
|
431
|
+
2. `realm`: Your Kerberos realm
|
|
432
|
+
3. `realm_user`: Your Kerberos username
|
|
433
|
+
4. `krb5_path`: Path to your `krb5.conf` configuration file
|
|
434
|
+
|
|
435
|
+
Optional Parameters:
|
|
436
|
+
|
|
437
|
+
1. `ticket_cache`: Path to your ticket cache (if not default)
|
|
438
|
+
2. `krb5_mech`: The Kerberos 5 mechanism to use (if not default)
|
|
439
|
+
|
|
440
|
+
```python
|
|
441
|
+
from mapepire_python import DaemonServer
|
|
442
|
+
from mapepire_python.authentication.kerberosTokenProvider import KerberosTokenProvider
|
|
443
|
+
|
|
444
|
+
token_provider = KerberosTokenProvider(
|
|
445
|
+
realm="REALM",
|
|
446
|
+
realm_user="REALM_USER",
|
|
447
|
+
host="SERVER",
|
|
448
|
+
krb5_path="KRB5_PATH"
|
|
449
|
+
)
|
|
450
|
+
|
|
451
|
+
creds = DaemonServer(
|
|
452
|
+
host="SERVER",
|
|
453
|
+
password=token_provider,
|
|
363
454
|
user="USER",
|
|
364
|
-
|
|
365
|
-
ignoreUnauthorized=True
|
|
455
|
+
port="PORT",
|
|
366
456
|
)
|
|
367
457
|
|
|
368
458
|
job = SQLJob(creds)
|
|
@@ -373,7 +463,7 @@ job = SQLJob(creds)
|
|
|
373
463
|
You can also use a dictionary to configure the connection details:
|
|
374
464
|
|
|
375
465
|
```python
|
|
376
|
-
from mapepire_python
|
|
466
|
+
from mapepire_python import SQLJob
|
|
377
467
|
|
|
378
468
|
creds = {
|
|
379
469
|
"host": "SERVER",
|
|
@@ -406,13 +496,80 @@ Then you can create a `SQLJob` object by passing the path to the `.ini` file whi
|
|
|
406
496
|
|
|
407
497
|
|
|
408
498
|
```python
|
|
409
|
-
from mapepire_python
|
|
499
|
+
from mapepire_python import SQLJob
|
|
410
500
|
|
|
411
501
|
job = SQLJob("./mapepire.ini", section="mapepire")
|
|
412
502
|
```
|
|
413
503
|
|
|
414
504
|
The `section` argument is optional and allows you to specify a specific section in the `.ini` file where the connection details are stored. This allows you to store multiple connection details to different systems in the same file. If you do not specify a `section`, the first section in the file will be used.
|
|
415
505
|
|
|
506
|
+
## 4. Using environment variables
|
|
507
|
+
|
|
508
|
+
You can configure connection credentials through environment variables, avoiding the need to pass them explicitly in code:
|
|
509
|
+
|
|
510
|
+
| Variable | Required | Default | Description |
|
|
511
|
+
|---|---|---|---|
|
|
512
|
+
| `MAPEPIRE_HOST` | Yes | — | Server hostname |
|
|
513
|
+
| `MAPEPIRE_USER` | Yes | — | Database user |
|
|
514
|
+
| `MAPEPIRE_PASSWORD` | Yes | — | Database password |
|
|
515
|
+
| `MAPEPIRE_PORT` | No | `8076` | Server port |
|
|
516
|
+
| `MAPEPIRE_CA_PATH` | No | — | Path to CA certificate file |
|
|
517
|
+
|
|
518
|
+
Set the variables in your shell:
|
|
519
|
+
|
|
520
|
+
```bash
|
|
521
|
+
export MAPEPIRE_HOST=myibmi.example.com
|
|
522
|
+
export MAPEPIRE_USER=myuser
|
|
523
|
+
export MAPEPIRE_PASSWORD=mypassword
|
|
524
|
+
```
|
|
525
|
+
|
|
526
|
+
Then `connect()` and `async_connect()` can be called with no arguments:
|
|
527
|
+
|
|
528
|
+
```python
|
|
529
|
+
from mapepire_python import connect
|
|
530
|
+
|
|
531
|
+
with connect() as conn:
|
|
532
|
+
with conn.execute("select * from sample.employee") as cursor:
|
|
533
|
+
print(cursor.fetchone())
|
|
534
|
+
```
|
|
535
|
+
|
|
536
|
+
You can also create a `DaemonServer` directly from env vars:
|
|
537
|
+
|
|
538
|
+
```python
|
|
539
|
+
from mapepire_python import DaemonServer, SQLJob
|
|
540
|
+
|
|
541
|
+
creds = DaemonServer.from_env()
|
|
542
|
+
job = SQLJob(creds)
|
|
543
|
+
```
|
|
544
|
+
|
|
545
|
+
## TLS Configuration
|
|
546
|
+
|
|
547
|
+
Server certificate verification (`ssl.CERT_REQUIRED`) is enabled by default. To disable certificate verification, set the `ignoreUnauthorized` field to `True` in the connection details.
|
|
548
|
+
|
|
549
|
+
get the server certificate:
|
|
550
|
+
|
|
551
|
+
```python
|
|
552
|
+
from mapepire_python.data_types import DaemonServer
|
|
553
|
+
from mapepire_python.ssl import get_certificate
|
|
554
|
+
|
|
555
|
+
creds = DaemonServer(host=server, port=port, user=user, password=password)
|
|
556
|
+
cert = get_certificate(creds)
|
|
557
|
+
print(cert)
|
|
558
|
+
```
|
|
559
|
+
|
|
560
|
+
## Logging
|
|
561
|
+
|
|
562
|
+
`mapepire-python` emits structured logs through the standard library `logging` module. Following library best practice, it does not configure any handlers itself, so logging is silent until your application opts in. Each module logs under the `mapepire_python` namespace, so you can enable and filter logs as needed:
|
|
563
|
+
|
|
564
|
+
```python
|
|
565
|
+
import logging
|
|
566
|
+
|
|
567
|
+
# Enable INFO-level logs from mapepire-python
|
|
568
|
+
logging.basicConfig(level=logging.INFO)
|
|
569
|
+
logging.getLogger("mapepire_python").setLevel(logging.DEBUG)
|
|
570
|
+
```
|
|
571
|
+
|
|
572
|
+
|
|
416
573
|
|
|
417
574
|
# Usage
|
|
418
575
|
|
|
@@ -430,7 +587,7 @@ There are four main ways to run queries using `mapepire-python`:
|
|
|
430
587
|
## 1. Using the `SQLJob` object to run queries synchronously
|
|
431
588
|
|
|
432
589
|
```python
|
|
433
|
-
from mapepire_python
|
|
590
|
+
from mapepire_python import SQLJob
|
|
434
591
|
|
|
435
592
|
with SQLJob("./mapepire.ini") as sql_job:
|
|
436
593
|
with sql_job.query("select * from sample.employee") as query:
|
|
@@ -574,7 +731,7 @@ In the ouput above, the query was successful and returned one row of data.
|
|
|
574
731
|
To create and run a query in a single step, use the `query_and_run` method:
|
|
575
732
|
|
|
576
733
|
```python
|
|
577
|
-
from mapepire_python
|
|
734
|
+
from mapepire_python import SQLJob
|
|
578
735
|
|
|
579
736
|
with SQLJob("./mapepire.ini") as sql_job:
|
|
580
737
|
# query automatically closed after running
|
|
@@ -588,7 +745,7 @@ The `PoolJob` object can be used to create and run queries asynchronously:
|
|
|
588
745
|
|
|
589
746
|
```python
|
|
590
747
|
import asyncio
|
|
591
|
-
from mapepire_python
|
|
748
|
+
from mapepire_python import PoolJob
|
|
592
749
|
|
|
593
750
|
async def main():
|
|
594
751
|
async with PoolJob("./mapepire.ini") as pool_job:
|
|
@@ -604,7 +761,7 @@ To run a create and run a query asynchronously in a single step, use the `query_
|
|
|
604
761
|
|
|
605
762
|
```python
|
|
606
763
|
import asyncio
|
|
607
|
-
from mapepire_python
|
|
764
|
+
from mapepire_python import PoolJob
|
|
608
765
|
|
|
609
766
|
async def main():
|
|
610
767
|
async with PoolJob("./mapepire.ini") as pool_job:
|
|
@@ -623,7 +780,7 @@ The `Pool` object can be used to create a pool of `PoolJob` objects to run queri
|
|
|
623
780
|
|
|
624
781
|
```python
|
|
625
782
|
import asyncio
|
|
626
|
-
from mapepire_python
|
|
783
|
+
from mapepire_python import Pool, PoolOptions
|
|
627
784
|
|
|
628
785
|
async def main():
|
|
629
786
|
async with Pool(
|
|
@@ -688,18 +845,57 @@ with connect("./mapepire.ini") as conn:
|
|
|
688
845
|
|
|
689
846
|
## PEP 249 Asynchronous Implementation
|
|
690
847
|
|
|
691
|
-
The PEP 249 implementation
|
|
848
|
+
The PEP 249 implementation provides a native async interface backed by non-blocking WebSocket I/O — no thread delegation. Use `async_connect` from the top-level package, or `connect` from `mapepire_python.asyncio`:
|
|
692
849
|
|
|
693
850
|
```python
|
|
694
851
|
import asyncio
|
|
695
|
-
from mapepire_python
|
|
852
|
+
from mapepire_python import async_connect
|
|
696
853
|
|
|
697
854
|
async def main():
|
|
698
|
-
async with
|
|
855
|
+
async with async_connect("./mapepire.ini") as conn:
|
|
699
856
|
async with await conn.execute("select * from sample.employee") as cursor:
|
|
700
857
|
result = await cursor.fetchone()
|
|
701
858
|
print(result)
|
|
702
|
-
|
|
859
|
+
|
|
860
|
+
if __name__ == '__main__':
|
|
861
|
+
asyncio.run(main())
|
|
862
|
+
```
|
|
863
|
+
|
|
864
|
+
Fetch multiple rows at once with `fetchmany` or drain the full result set with `fetchall`:
|
|
865
|
+
|
|
866
|
+
```python
|
|
867
|
+
async def main():
|
|
868
|
+
async with async_connect("./mapepire.ini") as conn:
|
|
869
|
+
async with await conn.execute("select * from sample.employee") as cursor:
|
|
870
|
+
page = await cursor.fetchmany(10) # first 10 rows
|
|
871
|
+
rest = await cursor.fetchall() # remaining rows
|
|
872
|
+
|
|
873
|
+
if __name__ == '__main__':
|
|
874
|
+
asyncio.run(main())
|
|
875
|
+
```
|
|
876
|
+
|
|
877
|
+
Stream rows one at a time using `async for`:
|
|
878
|
+
|
|
879
|
+
```python
|
|
880
|
+
async def main():
|
|
881
|
+
async with async_connect("./mapepire.ini") as conn:
|
|
882
|
+
async for row in await conn.execute("select * from sample.employee"):
|
|
883
|
+
print(row)
|
|
884
|
+
|
|
885
|
+
if __name__ == '__main__':
|
|
886
|
+
asyncio.run(main())
|
|
887
|
+
```
|
|
888
|
+
|
|
889
|
+
Use `AsyncSQLJob` directly for lower-level access without a pool:
|
|
890
|
+
|
|
891
|
+
```python
|
|
892
|
+
from mapepire_python.client.async_sql_job import AsyncSQLJob
|
|
893
|
+
|
|
894
|
+
async def main():
|
|
895
|
+
async with AsyncSQLJob("./mapepire.ini") as job:
|
|
896
|
+
result = await job.query_and_run("select * from sample.employee")
|
|
897
|
+
print(result.data)
|
|
898
|
+
|
|
703
899
|
if __name__ == '__main__':
|
|
704
900
|
asyncio.run(main())
|
|
705
901
|
```
|
|
@@ -857,9 +1053,26 @@ conda deactivate
|
|
|
857
1053
|
```
|
|
858
1054
|
## Run local test suite
|
|
859
1055
|
|
|
860
|
-
|
|
1056
|
+
The suite is split in two:
|
|
1057
|
+
|
|
1058
|
+
- `tests/unit/` — offline unit tests. They mock the WebSocket transport and need
|
|
1059
|
+
**no** IBM i server or credentials, so they run anywhere (including CI on forks).
|
|
1060
|
+
- `tests/integration/` — live-server tests. They connect to a real Mapepire
|
|
1061
|
+
server and require credentials.
|
|
1062
|
+
|
|
1063
|
+
### Unit tests (no server required)
|
|
1064
|
+
|
|
1065
|
+
```bash
|
|
1066
|
+
# activate python development environment first
|
|
1067
|
+
|
|
1068
|
+
pytest tests/unit/
|
|
1069
|
+
```
|
|
1070
|
+
|
|
1071
|
+
### Integration tests (server required)
|
|
1072
|
+
|
|
1073
|
+
First, create a `pytest.ini` file in the `tests/integration` directory:
|
|
861
1074
|
|
|
862
|
-
`tests/pytest.ini`
|
|
1075
|
+
`tests/integration/pytest.ini`
|
|
863
1076
|
|
|
864
1077
|
```ini
|
|
865
1078
|
[pytest]
|
|
@@ -869,11 +1082,17 @@ env =
|
|
|
869
1082
|
VITE_DB_PASS=PASS
|
|
870
1083
|
```
|
|
871
1084
|
|
|
872
|
-
|
|
1085
|
+
Then run the integration suite from the `mapepire-python` directory:
|
|
873
1086
|
|
|
874
1087
|
```bash
|
|
875
1088
|
# activate python development environment first
|
|
876
1089
|
|
|
1090
|
+
pytest tests/integration/
|
|
1091
|
+
```
|
|
1092
|
+
|
|
1093
|
+
To run everything (unit + integration), just point pytest at `tests/`:
|
|
1094
|
+
|
|
1095
|
+
```bash
|
|
877
1096
|
pytest tests/
|
|
878
1097
|
```
|
|
879
1098
|
|