mapepire-python 0.2.0__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.2.0 → mapepire_python-0.3.0}/PKG-INFO +255 -42
- {mapepire_python-0.2.0 → mapepire_python-0.3.0}/README.md +242 -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.2.0 → mapepire_python-0.3.0}/mapepire_python/asyncio/__init__.py +12 -3
- {mapepire_python-0.2.0 → 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.2.0 → mapepire_python-0.3.0}/mapepire_python/base_job.py +6 -4
- 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.2.0 → mapepire_python-0.3.0}/mapepire_python/client/sql_job.py +31 -18
- {mapepire_python-0.2.0 → mapepire_python-0.3.0}/mapepire_python/core/connection.py +7 -2
- {mapepire_python-0.2.0 → mapepire_python-0.3.0}/mapepire_python/core/cursor.py +48 -21
- {mapepire_python-0.2.0 → mapepire_python-0.3.0}/mapepire_python/core/exceptions.py +18 -20
- {mapepire_python-0.2.0 → 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.2.0 → 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.2.0 → mapepire_python-0.3.0}/mapepire_python/query_manager.py +0 -3
- {mapepire_python-0.2.0 → mapepire_python-0.3.0}/mapepire_python/ssl.py +1 -0
- {mapepire_python-0.2.0 → mapepire_python-0.3.0}/mapepire_python/version.py +1 -1
- {mapepire_python-0.2.0 → mapepire_python-0.3.0}/mapepire_python/websocket.py +16 -3
- {mapepire_python-0.2.0 → mapepire_python-0.3.0}/mapepire_python.egg-info/PKG-INFO +255 -42
- {mapepire_python-0.2.0 → mapepire_python-0.3.0}/mapepire_python.egg-info/SOURCES.txt +3 -1
- mapepire_python-0.3.0/mapepire_python.egg-info/requires.txt +25 -0
- {mapepire_python-0.2.0 → mapepire_python-0.3.0}/pyproject.toml +44 -17
- mapepire_python-0.2.0/mapepire_python/__init__.py +0 -49
- mapepire_python-0.2.0/mapepire_python/asyncio/cursor.py +0 -99
- mapepire_python-0.2.0/mapepire_python/asyncio/utils.py +0 -23
- mapepire_python-0.2.0/mapepire_python/client/query.py +0 -190
- mapepire_python-0.2.0/mapepire_python/data_types.py +0 -245
- mapepire_python-0.2.0/mapepire_python/pool/pool_job.py +0 -296
- mapepire_python-0.2.0/mapepire_python/pool/pool_query.py +0 -136
- mapepire_python-0.2.0/mapepire_python.egg-info/requires.txt +0 -28
- {mapepire_python-0.2.0 → mapepire_python-0.3.0}/LICENSE +0 -0
- {mapepire_python-0.2.0 → mapepire_python-0.3.0}/mapepire_python/client/__init__.py +0 -0
- {mapepire_python-0.2.0 → mapepire_python-0.3.0}/mapepire_python/client/websocket_client.py +0 -0
- {mapepire_python-0.2.0 → mapepire_python-0.3.0}/mapepire_python/core/__init__.py +0 -0
- {mapepire_python-0.2.0 → mapepire_python-0.3.0}/mapepire_python/pool/__init__.py +0 -0
- {mapepire_python-0.2.0 → mapepire_python-0.3.0}/mapepire_python/pool/async_websocket_client.py +0 -0
- {mapepire_python-0.2.0 → mapepire_python-0.3.0}/mapepire_python/py.typed +0 -0
- {mapepire_python-0.2.0 → mapepire_python-0.3.0}/mapepire_python.egg-info/dependency_links.txt +0 -0
- {mapepire_python-0.2.0 → mapepire_python-0.3.0}/mapepire_python.egg-info/top_level.txt +0 -0
- {mapepire_python-0.2.0 → 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,41 +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
220
|
Requires-Dist: websockets>=14.0
|
|
220
|
-
Requires-Dist: pyee
|
|
221
221
|
Requires-Dist: pep249abc
|
|
222
222
|
Provides-Extra: dev
|
|
223
223
|
Requires-Dist: ruff; extra == "dev"
|
|
224
|
-
Requires-Dist: mypy<1.
|
|
225
|
-
Requires-Dist: black<
|
|
226
|
-
Requires-Dist: isort<
|
|
227
|
-
Requires-Dist: pytest; extra == "dev"
|
|
228
|
-
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"
|
|
229
228
|
Requires-Dist: pep249abc; extra == "dev"
|
|
230
229
|
Requires-Dist: pytest-asyncio; extra == "dev"
|
|
231
|
-
Requires-Dist: pytest-sphinx; extra == "dev"
|
|
232
230
|
Requires-Dist: pytest-cov; extra == "dev"
|
|
233
231
|
Requires-Dist: twine>=1.11.0; extra == "dev"
|
|
234
232
|
Requires-Dist: build; extra == "dev"
|
|
235
233
|
Requires-Dist: setuptools; extra == "dev"
|
|
236
234
|
Requires-Dist: wheel; extra == "dev"
|
|
237
|
-
Requires-Dist: Sphinx<7.1.0,>=4.3.0; extra == "dev"
|
|
238
|
-
Requires-Dist: furo==2023.7.26; extra == "dev"
|
|
239
|
-
Requires-Dist: myst-parser<2.1,>=1.0; extra == "dev"
|
|
240
|
-
Requires-Dist: sphinx-copybutton==0.5.2; extra == "dev"
|
|
241
|
-
Requires-Dist: sphinx-autobuild==2021.3.14; extra == "dev"
|
|
242
|
-
Requires-Dist: sphinx-autodoc-typehints==1.23.3; extra == "dev"
|
|
243
235
|
Requires-Dist: packaging; extra == "dev"
|
|
244
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
|
|
245
242
|
|
|
246
243
|
# mapepire-python
|
|
247
244
|
<div align="center">
|
|
@@ -265,10 +262,16 @@ Requires-Dist: pre-commit; extra == "dev"
|
|
|
265
262
|
- [Setup](#setup)
|
|
266
263
|
- [Install with `pip`](#install-with-pip)
|
|
267
264
|
- [Server Component Setup](#server-component-setup)
|
|
268
|
-
- [
|
|
265
|
+
- [Quick Start](#quick-start)
|
|
266
|
+
- [Other Connection options](#other-connection-options)
|
|
269
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)
|
|
270
271
|
- [2. Passing the connection details as a dictionary](#2-passing-the-connection-details-as-a-dictionary)
|
|
271
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)
|
|
272
275
|
- [Usage](#usage)
|
|
273
276
|
- [1. Using the `SQLJob` object to run queries synchronously](#1-using-the-sqljob-object-to-run-queries-synchronously)
|
|
274
277
|
- [Query and run](#query-and-run)
|
|
@@ -332,43 +335,124 @@ pip install mapepire-python
|
|
|
332
335
|
### Server Component Setup
|
|
333
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/)
|
|
334
337
|
|
|
335
|
-
|
|
336
|
-
# Connection options
|
|
338
|
+
# Quick Start
|
|
337
339
|
|
|
338
|
-
|
|
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)
|
|
366
|
+
|
|
367
|
+
There are four ways to configure mapepire server connection details using `mapepire-python`:
|
|
339
368
|
|
|
340
369
|
1. Using the `DaemonServer` object
|
|
341
370
|
2. Passing the connection details as a dictionary
|
|
342
371
|
3. Using a config file (`.ini`) to store the connection details
|
|
372
|
+
4. Using environment variables
|
|
343
373
|
|
|
344
374
|
## 1. Using the `DaemonServer` object
|
|
345
375
|
|
|
346
|
-
|
|
376
|
+
`DaemonServer` is importable directly from `mapepire_python`:
|
|
347
377
|
|
|
348
378
|
```python
|
|
349
|
-
from mapepire_python
|
|
379
|
+
from mapepire_python import DaemonServer
|
|
350
380
|
|
|
351
381
|
creds = DaemonServer(
|
|
352
382
|
host="SERVER",
|
|
353
383
|
port="PORT",
|
|
354
384
|
user="USER",
|
|
355
|
-
password="PASSWORD"
|
|
356
|
-
ignoreUnauthorized=True
|
|
385
|
+
password="PASSWORD"
|
|
357
386
|
)
|
|
358
387
|
```
|
|
359
388
|
|
|
360
389
|
Once you have created the `DaemonServer` object, you can pass it to the `SQLJob` object to connect to the mapepire server:
|
|
361
390
|
|
|
362
391
|
```python
|
|
363
|
-
from mapepire_python
|
|
364
|
-
from mapepire_python.data_types import DaemonServer
|
|
392
|
+
from mapepire_python import SQLJob, DaemonServer
|
|
365
393
|
|
|
366
394
|
creds = DaemonServer(
|
|
367
395
|
host="SERVER",
|
|
368
396
|
port="PORT",
|
|
369
397
|
user="USER",
|
|
370
|
-
password="PASSWORD"
|
|
371
|
-
|
|
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
|
|
413
|
+
|
|
414
|
+
creds = DaemonServer(
|
|
415
|
+
host="SERVER",
|
|
416
|
+
password=KerberosTokenProvider(host="SERVER"),
|
|
417
|
+
user="USER",
|
|
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,
|
|
454
|
+
user="USER",
|
|
455
|
+
port="PORT",
|
|
372
456
|
)
|
|
373
457
|
|
|
374
458
|
job = SQLJob(creds)
|
|
@@ -379,7 +463,7 @@ job = SQLJob(creds)
|
|
|
379
463
|
You can also use a dictionary to configure the connection details:
|
|
380
464
|
|
|
381
465
|
```python
|
|
382
|
-
from mapepire_python
|
|
466
|
+
from mapepire_python import SQLJob
|
|
383
467
|
|
|
384
468
|
creds = {
|
|
385
469
|
"host": "SERVER",
|
|
@@ -412,13 +496,80 @@ Then you can create a `SQLJob` object by passing the path to the `.ini` file whi
|
|
|
412
496
|
|
|
413
497
|
|
|
414
498
|
```python
|
|
415
|
-
from mapepire_python
|
|
499
|
+
from mapepire_python import SQLJob
|
|
416
500
|
|
|
417
501
|
job = SQLJob("./mapepire.ini", section="mapepire")
|
|
418
502
|
```
|
|
419
503
|
|
|
420
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.
|
|
421
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
|
+
|
|
422
573
|
|
|
423
574
|
# Usage
|
|
424
575
|
|
|
@@ -436,7 +587,7 @@ There are four main ways to run queries using `mapepire-python`:
|
|
|
436
587
|
## 1. Using the `SQLJob` object to run queries synchronously
|
|
437
588
|
|
|
438
589
|
```python
|
|
439
|
-
from mapepire_python
|
|
590
|
+
from mapepire_python import SQLJob
|
|
440
591
|
|
|
441
592
|
with SQLJob("./mapepire.ini") as sql_job:
|
|
442
593
|
with sql_job.query("select * from sample.employee") as query:
|
|
@@ -580,7 +731,7 @@ In the ouput above, the query was successful and returned one row of data.
|
|
|
580
731
|
To create and run a query in a single step, use the `query_and_run` method:
|
|
581
732
|
|
|
582
733
|
```python
|
|
583
|
-
from mapepire_python
|
|
734
|
+
from mapepire_python import SQLJob
|
|
584
735
|
|
|
585
736
|
with SQLJob("./mapepire.ini") as sql_job:
|
|
586
737
|
# query automatically closed after running
|
|
@@ -594,7 +745,7 @@ The `PoolJob` object can be used to create and run queries asynchronously:
|
|
|
594
745
|
|
|
595
746
|
```python
|
|
596
747
|
import asyncio
|
|
597
|
-
from mapepire_python
|
|
748
|
+
from mapepire_python import PoolJob
|
|
598
749
|
|
|
599
750
|
async def main():
|
|
600
751
|
async with PoolJob("./mapepire.ini") as pool_job:
|
|
@@ -610,7 +761,7 @@ To run a create and run a query asynchronously in a single step, use the `query_
|
|
|
610
761
|
|
|
611
762
|
```python
|
|
612
763
|
import asyncio
|
|
613
|
-
from mapepire_python
|
|
764
|
+
from mapepire_python import PoolJob
|
|
614
765
|
|
|
615
766
|
async def main():
|
|
616
767
|
async with PoolJob("./mapepire.ini") as pool_job:
|
|
@@ -629,7 +780,7 @@ The `Pool` object can be used to create a pool of `PoolJob` objects to run queri
|
|
|
629
780
|
|
|
630
781
|
```python
|
|
631
782
|
import asyncio
|
|
632
|
-
from mapepire_python
|
|
783
|
+
from mapepire_python import Pool, PoolOptions
|
|
633
784
|
|
|
634
785
|
async def main():
|
|
635
786
|
async with Pool(
|
|
@@ -694,18 +845,57 @@ with connect("./mapepire.ini") as conn:
|
|
|
694
845
|
|
|
695
846
|
## PEP 249 Asynchronous Implementation
|
|
696
847
|
|
|
697
|
-
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`:
|
|
698
849
|
|
|
699
850
|
```python
|
|
700
851
|
import asyncio
|
|
701
|
-
from mapepire_python
|
|
852
|
+
from mapepire_python import async_connect
|
|
702
853
|
|
|
703
854
|
async def main():
|
|
704
|
-
async with
|
|
855
|
+
async with async_connect("./mapepire.ini") as conn:
|
|
705
856
|
async with await conn.execute("select * from sample.employee") as cursor:
|
|
706
857
|
result = await cursor.fetchone()
|
|
707
858
|
print(result)
|
|
708
|
-
|
|
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
|
+
|
|
709
899
|
if __name__ == '__main__':
|
|
710
900
|
asyncio.run(main())
|
|
711
901
|
```
|
|
@@ -863,9 +1053,26 @@ conda deactivate
|
|
|
863
1053
|
```
|
|
864
1054
|
## Run local test suite
|
|
865
1055
|
|
|
866
|
-
|
|
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:
|
|
867
1074
|
|
|
868
|
-
`tests/pytest.ini`
|
|
1075
|
+
`tests/integration/pytest.ini`
|
|
869
1076
|
|
|
870
1077
|
```ini
|
|
871
1078
|
[pytest]
|
|
@@ -875,11 +1082,17 @@ env =
|
|
|
875
1082
|
VITE_DB_PASS=PASS
|
|
876
1083
|
```
|
|
877
1084
|
|
|
878
|
-
|
|
1085
|
+
Then run the integration suite from the `mapepire-python` directory:
|
|
879
1086
|
|
|
880
1087
|
```bash
|
|
881
1088
|
# activate python development environment first
|
|
882
1089
|
|
|
1090
|
+
pytest tests/integration/
|
|
1091
|
+
```
|
|
1092
|
+
|
|
1093
|
+
To run everything (unit + integration), just point pytest at `tests/`:
|
|
1094
|
+
|
|
1095
|
+
```bash
|
|
883
1096
|
pytest tests/
|
|
884
1097
|
```
|
|
885
1098
|
|