mapepire-python 0.2.0__tar.gz → 0.3.1__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.1}/PKG-INFO +285 -48
- {mapepire_python-0.2.0 → mapepire_python-0.3.1}/README.md +270 -31
- mapepire_python-0.3.1/mapepire_python/__init__.py +77 -0
- mapepire_python-0.3.1/mapepire_python/async_base_job.py +216 -0
- {mapepire_python-0.2.0 → mapepire_python-0.3.1}/mapepire_python/asyncio/__init__.py +12 -3
- {mapepire_python-0.2.0 → mapepire_python-0.3.1}/mapepire_python/asyncio/connection.py +40 -14
- mapepire_python-0.3.1/mapepire_python/asyncio/cursor.py +156 -0
- mapepire_python-0.3.1/mapepire_python/authentication/kerberosTokenProvider.py +121 -0
- {mapepire_python-0.2.0 → mapepire_python-0.3.1}/mapepire_python/base_job.py +6 -4
- mapepire_python-0.3.1/mapepire_python/client/async_sql_job.py +14 -0
- mapepire_python-0.3.1/mapepire_python/client/query.py +205 -0
- {mapepire_python-0.2.0 → mapepire_python-0.3.1}/mapepire_python/client/sql_job.py +31 -18
- {mapepire_python-0.2.0 → mapepire_python-0.3.1}/mapepire_python/core/connection.py +7 -2
- {mapepire_python-0.2.0 → mapepire_python-0.3.1}/mapepire_python/core/cursor.py +48 -21
- {mapepire_python-0.2.0 → mapepire_python-0.3.1}/mapepire_python/core/exceptions.py +18 -20
- {mapepire_python-0.2.0 → mapepire_python-0.3.1}/mapepire_python/core/utils.py +38 -9
- mapepire_python-0.3.1/mapepire_python/data_types.py +528 -0
- {mapepire_python-0.2.0 → mapepire_python-0.3.1}/mapepire_python/pool/pool_client.py +42 -14
- mapepire_python-0.3.1/mapepire_python/pool/pool_job.py +36 -0
- mapepire_python-0.3.1/mapepire_python/pool/pool_query.py +168 -0
- {mapepire_python-0.2.0 → mapepire_python-0.3.1}/mapepire_python/query_manager.py +0 -3
- {mapepire_python-0.2.0 → mapepire_python-0.3.1}/mapepire_python/ssl.py +1 -0
- {mapepire_python-0.2.0 → mapepire_python-0.3.1}/mapepire_python/version.py +2 -2
- {mapepire_python-0.2.0 → mapepire_python-0.3.1}/mapepire_python/websocket.py +16 -3
- {mapepire_python-0.2.0 → mapepire_python-0.3.1}/mapepire_python.egg-info/PKG-INFO +285 -48
- {mapepire_python-0.2.0 → mapepire_python-0.3.1}/mapepire_python.egg-info/SOURCES.txt +3 -1
- mapepire_python-0.3.1/mapepire_python.egg-info/requires.txt +29 -0
- {mapepire_python-0.2.0 → mapepire_python-0.3.1}/pyproject.toml +48 -19
- 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.1}/LICENSE +0 -0
- {mapepire_python-0.2.0 → mapepire_python-0.3.1}/mapepire_python/client/__init__.py +0 -0
- {mapepire_python-0.2.0 → mapepire_python-0.3.1}/mapepire_python/client/websocket_client.py +0 -0
- {mapepire_python-0.2.0 → mapepire_python-0.3.1}/mapepire_python/core/__init__.py +0 -0
- {mapepire_python-0.2.0 → mapepire_python-0.3.1}/mapepire_python/pool/__init__.py +0 -0
- {mapepire_python-0.2.0 → mapepire_python-0.3.1}/mapepire_python/pool/async_websocket_client.py +0 -0
- {mapepire_python-0.2.0 → mapepire_python-0.3.1}/mapepire_python/py.typed +0 -0
- {mapepire_python-0.2.0 → mapepire_python-0.3.1}/mapepire_python.egg-info/dependency_links.txt +0 -0
- {mapepire_python-0.2.0 → mapepire_python-0.3.1}/mapepire_python.egg-info/top_level.txt +0 -0
- {mapepire_python-0.2.0 → mapepire_python-0.3.1}/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.1
|
|
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,39 @@ 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
|
+
Provides-Extra: kerberos
|
|
223
|
+
Requires-Dist: gssapi; sys_platform != "win32" and extra == "kerberos"
|
|
224
|
+
Requires-Dist: pywin32; sys_platform == "win32" and extra == "kerberos"
|
|
222
225
|
Provides-Extra: dev
|
|
223
|
-
Requires-Dist: ruff; extra == "dev"
|
|
224
|
-
Requires-Dist: mypy<
|
|
225
|
-
Requires-Dist: black<
|
|
226
|
-
Requires-Dist: isort<
|
|
227
|
-
Requires-Dist: pytest; extra == "dev"
|
|
228
|
-
Requires-Dist: pyee; extra == "dev"
|
|
226
|
+
Requires-Dist: ruff<0.16,>=0.15; extra == "dev"
|
|
227
|
+
Requires-Dist: mypy<2.4,>=1.0; extra == "dev"
|
|
228
|
+
Requires-Dist: black<27.0,>=24.3.0; extra == "dev"
|
|
229
|
+
Requires-Dist: isort<8.1,>=5.12; extra == "dev"
|
|
230
|
+
Requires-Dist: pytest>=9.0.3; extra == "dev"
|
|
229
231
|
Requires-Dist: pep249abc; extra == "dev"
|
|
230
232
|
Requires-Dist: pytest-asyncio; extra == "dev"
|
|
231
|
-
Requires-Dist: pytest-sphinx; extra == "dev"
|
|
232
233
|
Requires-Dist: pytest-cov; extra == "dev"
|
|
233
234
|
Requires-Dist: twine>=1.11.0; extra == "dev"
|
|
234
235
|
Requires-Dist: build; extra == "dev"
|
|
235
236
|
Requires-Dist: setuptools; extra == "dev"
|
|
236
237
|
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
238
|
Requires-Dist: packaging; extra == "dev"
|
|
244
239
|
Requires-Dist: pre-commit; extra == "dev"
|
|
240
|
+
Requires-Dist: python-dotenv; extra == "dev"
|
|
241
|
+
Requires-Dist: pytest-env; extra == "dev"
|
|
242
|
+
Dynamic: license-file
|
|
245
243
|
|
|
246
244
|
# mapepire-python
|
|
247
245
|
<div align="center">
|
|
@@ -264,11 +262,18 @@ Requires-Dist: pre-commit; extra == "dev"
|
|
|
264
262
|
- [Overview](#overview)
|
|
265
263
|
- [Setup](#setup)
|
|
266
264
|
- [Install with `pip`](#install-with-pip)
|
|
265
|
+
- [Optional: Kerberos authentication support](#optional-kerberos-authentication-support)
|
|
267
266
|
- [Server Component Setup](#server-component-setup)
|
|
268
|
-
- [
|
|
267
|
+
- [Quick Start](#quick-start)
|
|
268
|
+
- [Other Connection options](#other-connection-options)
|
|
269
269
|
- [1. Using the `DaemonServer` object](#1-using-the-daemonserver-object)
|
|
270
|
+
- [1.1 Authenticating with Kerberos](#11-authenticating-with-kerberos)
|
|
271
|
+
- [1.1.1 Windows](#111-windows)
|
|
272
|
+
- [1.1.2 Other Platforms](#112-other-platforms)
|
|
270
273
|
- [2. Passing the connection details as a dictionary](#2-passing-the-connection-details-as-a-dictionary)
|
|
271
274
|
- [3. Using a config file (`.ini`) to store the connection details](#3-using-a-config-file-ini-to-store-the-connection-details)
|
|
275
|
+
- [4. Using environment variables](#4-using-environment-variables)
|
|
276
|
+
- [TLS Configuration](#tls-configuration)
|
|
272
277
|
- [Usage](#usage)
|
|
273
278
|
- [1. Using the `SQLJob` object to run queries synchronously](#1-using-the-sqljob-object-to-run-queries-synchronously)
|
|
274
279
|
- [Query and run](#query-and-run)
|
|
@@ -329,46 +334,147 @@ Requires-Dist: pre-commit; extra == "dev"
|
|
|
329
334
|
pip install mapepire-python
|
|
330
335
|
```
|
|
331
336
|
|
|
337
|
+
#### Optional: Kerberos authentication support
|
|
338
|
+
|
|
339
|
+
Kerberos authentication (see [Authenticating with Kerberos](#11-authenticating-with-kerberos)) requires the optional `kerberos` extra, which pulls in `gssapi` on Linux/macOS or `pywin32` on Windows:
|
|
340
|
+
|
|
341
|
+
```bash
|
|
342
|
+
pip install mapepire-python[kerberos]
|
|
343
|
+
```
|
|
344
|
+
|
|
345
|
+
On Linux, building `gssapi` also requires Kerberos development headers to be available, e.g.:
|
|
346
|
+
|
|
347
|
+
```bash
|
|
348
|
+
sudo apt install libkrb5-dev # Debian/Ubuntu
|
|
349
|
+
sudo dnf install krb5-devel # Fedora/RHEL
|
|
350
|
+
```
|
|
351
|
+
|
|
352
|
+
If you don't use Kerberos authentication, you don't need this extra — the base `pip install mapepire-python` has no Kerberos dependencies.
|
|
353
|
+
|
|
332
354
|
### Server Component Setup
|
|
333
355
|
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
356
|
|
|
335
|
-
|
|
336
|
-
|
|
357
|
+
# Quick Start
|
|
358
|
+
|
|
359
|
+
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:
|
|
360
|
+
|
|
361
|
+
```python
|
|
362
|
+
from mapepire_python import connect
|
|
363
|
+
|
|
364
|
+
creds = {
|
|
365
|
+
"host": "SERVER",
|
|
366
|
+
"port": 8076,
|
|
367
|
+
"user": "USER",
|
|
368
|
+
"password": "PASSWORD",
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
with connect(creds) as conn:
|
|
372
|
+
with conn.execute("select * from sample.employee") as cursor:
|
|
373
|
+
result = cursor.fetchone()
|
|
374
|
+
print(result)
|
|
375
|
+
|
|
376
|
+
```
|
|
377
|
+
|
|
378
|
+
# Other Connection options
|
|
337
379
|
|
|
338
|
-
|
|
380
|
+
> [!NOTE]
|
|
381
|
+
> 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.
|
|
382
|
+
> - To update run `pip install -U mapepire-python`
|
|
383
|
+
>
|
|
384
|
+
> - More info TLS Configuration [here](#tls-configuration)
|
|
385
|
+
|
|
386
|
+
There are four ways to configure mapepire server connection details using `mapepire-python`:
|
|
339
387
|
|
|
340
388
|
1. Using the `DaemonServer` object
|
|
341
389
|
2. Passing the connection details as a dictionary
|
|
342
390
|
3. Using a config file (`.ini`) to store the connection details
|
|
391
|
+
4. Using environment variables
|
|
343
392
|
|
|
344
393
|
## 1. Using the `DaemonServer` object
|
|
345
394
|
|
|
346
|
-
|
|
395
|
+
`DaemonServer` is importable directly from `mapepire_python`:
|
|
347
396
|
|
|
348
397
|
```python
|
|
349
|
-
from mapepire_python
|
|
398
|
+
from mapepire_python import DaemonServer
|
|
350
399
|
|
|
351
400
|
creds = DaemonServer(
|
|
352
401
|
host="SERVER",
|
|
353
402
|
port="PORT",
|
|
354
403
|
user="USER",
|
|
355
|
-
password="PASSWORD"
|
|
356
|
-
ignoreUnauthorized=True
|
|
404
|
+
password="PASSWORD"
|
|
357
405
|
)
|
|
358
406
|
```
|
|
359
407
|
|
|
360
408
|
Once you have created the `DaemonServer` object, you can pass it to the `SQLJob` object to connect to the mapepire server:
|
|
361
409
|
|
|
362
410
|
```python
|
|
363
|
-
from mapepire_python
|
|
364
|
-
from mapepire_python.data_types import DaemonServer
|
|
411
|
+
from mapepire_python import SQLJob, DaemonServer
|
|
365
412
|
|
|
366
413
|
creds = DaemonServer(
|
|
367
414
|
host="SERVER",
|
|
368
415
|
port="PORT",
|
|
369
416
|
user="USER",
|
|
370
|
-
password="PASSWORD"
|
|
371
|
-
|
|
417
|
+
password="PASSWORD"
|
|
418
|
+
)
|
|
419
|
+
|
|
420
|
+
job = SQLJob(creds)
|
|
421
|
+
```
|
|
422
|
+
|
|
423
|
+
### 1.1 Authenticating with Kerberos
|
|
424
|
+
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.
|
|
425
|
+
|
|
426
|
+
> [!NOTE]
|
|
427
|
+
> Kerberos support requires the `kerberos` extra: `pip install mapepire-python[kerberos]`. See [Optional: Kerberos authentication support](#optional-kerberos-authentication-support).
|
|
428
|
+
|
|
429
|
+
#### 1.1.1 Windows
|
|
430
|
+
|
|
431
|
+
If your Windows machine is part of a Kerberos realm and supports SSPI authentication, you can authenticate by creating the `DaemonServer` as shown below:
|
|
432
|
+
```python
|
|
433
|
+
from mapepire_python import DaemonServer
|
|
434
|
+
from mapepire_python.authentication.kerberosTokenProvider import KerberosTokenProvider
|
|
435
|
+
|
|
436
|
+
creds = DaemonServer(
|
|
437
|
+
host="SERVER",
|
|
438
|
+
password=KerberosTokenProvider(host="SERVER"),
|
|
439
|
+
user="USER",
|
|
440
|
+
port="PORT",
|
|
441
|
+
)
|
|
442
|
+
|
|
443
|
+
job = SQLJob(creds)
|
|
444
|
+
```
|
|
445
|
+
|
|
446
|
+
#### 1.1.2 Other Platforms
|
|
447
|
+
|
|
448
|
+
For non-Windows platforms, Kerberos authentication requires a valid Ticket Granting Ticket (TGT) in your credential cache.
|
|
449
|
+
|
|
450
|
+
Required Parameters:
|
|
451
|
+
|
|
452
|
+
1. `host`: The IBM i host you are connecting to
|
|
453
|
+
2. `realm`: Your Kerberos realm
|
|
454
|
+
3. `realm_user`: Your Kerberos username
|
|
455
|
+
4. `krb5_path`: Path to your `krb5.conf` configuration file
|
|
456
|
+
|
|
457
|
+
Optional Parameters:
|
|
458
|
+
|
|
459
|
+
1. `ticket_cache`: Path to your ticket cache (if not default)
|
|
460
|
+
2. `krb5_mech`: The Kerberos 5 mechanism to use (if not default)
|
|
461
|
+
|
|
462
|
+
```python
|
|
463
|
+
from mapepire_python import DaemonServer
|
|
464
|
+
from mapepire_python.authentication.kerberosTokenProvider import KerberosTokenProvider
|
|
465
|
+
|
|
466
|
+
token_provider = KerberosTokenProvider(
|
|
467
|
+
realm="REALM",
|
|
468
|
+
realm_user="REALM_USER",
|
|
469
|
+
host="SERVER",
|
|
470
|
+
krb5_path="KRB5_PATH"
|
|
471
|
+
)
|
|
472
|
+
|
|
473
|
+
creds = DaemonServer(
|
|
474
|
+
host="SERVER",
|
|
475
|
+
password=token_provider,
|
|
476
|
+
user="USER",
|
|
477
|
+
port="PORT",
|
|
372
478
|
)
|
|
373
479
|
|
|
374
480
|
job = SQLJob(creds)
|
|
@@ -379,7 +485,7 @@ job = SQLJob(creds)
|
|
|
379
485
|
You can also use a dictionary to configure the connection details:
|
|
380
486
|
|
|
381
487
|
```python
|
|
382
|
-
from mapepire_python
|
|
488
|
+
from mapepire_python import SQLJob
|
|
383
489
|
|
|
384
490
|
creds = {
|
|
385
491
|
"host": "SERVER",
|
|
@@ -402,27 +508,96 @@ First create a `mapepire.ini` file in the root of your project with the followin
|
|
|
402
508
|
|
|
403
509
|
```ini title=mapepire.ini
|
|
404
510
|
[mapepire]
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
511
|
+
host=SERVER
|
|
512
|
+
port=PORT
|
|
513
|
+
user=USER
|
|
514
|
+
password=PASSWORD
|
|
409
515
|
```
|
|
410
516
|
|
|
517
|
+
> **Note:** The keys must match the `DaemonServer` fields (`host`, `port`, `user`, `password`), and values must **not** be quoted — write `host=myhost`, not `host="myhost"`.
|
|
518
|
+
|
|
411
519
|
Then you can create a `SQLJob` object by passing the path to the `.ini` file which will handle the connection details
|
|
412
520
|
|
|
413
521
|
|
|
414
522
|
```python
|
|
415
|
-
from mapepire_python
|
|
523
|
+
from mapepire_python import SQLJob
|
|
416
524
|
|
|
417
525
|
job = SQLJob("./mapepire.ini", section="mapepire")
|
|
418
526
|
```
|
|
419
527
|
|
|
420
528
|
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
529
|
|
|
530
|
+
## 4. Using environment variables
|
|
531
|
+
|
|
532
|
+
You can configure connection credentials through environment variables, avoiding the need to pass them explicitly in code:
|
|
533
|
+
|
|
534
|
+
| Variable | Required | Default | Description |
|
|
535
|
+
|---|---|---|---|
|
|
536
|
+
| `MAPEPIRE_HOST` | Yes | — | Server hostname |
|
|
537
|
+
| `MAPEPIRE_USER` | Yes | — | Database user |
|
|
538
|
+
| `MAPEPIRE_PASSWORD` | Yes | — | Database password |
|
|
539
|
+
| `MAPEPIRE_PORT` | No | `8076` | Server port |
|
|
540
|
+
| `MAPEPIRE_CA_PATH` | No | — | Path to CA certificate file |
|
|
541
|
+
|
|
542
|
+
Set the variables in your shell:
|
|
543
|
+
|
|
544
|
+
```bash
|
|
545
|
+
export MAPEPIRE_HOST=myibmi.example.com
|
|
546
|
+
export MAPEPIRE_USER=myuser
|
|
547
|
+
export MAPEPIRE_PASSWORD=mypassword
|
|
548
|
+
```
|
|
549
|
+
|
|
550
|
+
Then `connect()` and `async_connect()` can be called with no arguments:
|
|
551
|
+
|
|
552
|
+
```python
|
|
553
|
+
from mapepire_python import connect
|
|
554
|
+
|
|
555
|
+
with connect() as conn:
|
|
556
|
+
with conn.execute("select * from sample.employee") as cursor:
|
|
557
|
+
print(cursor.fetchone())
|
|
558
|
+
```
|
|
559
|
+
|
|
560
|
+
You can also create a `DaemonServer` directly from env vars:
|
|
561
|
+
|
|
562
|
+
```python
|
|
563
|
+
from mapepire_python import DaemonServer, SQLJob
|
|
564
|
+
|
|
565
|
+
creds = DaemonServer.from_env()
|
|
566
|
+
job = SQLJob(creds)
|
|
567
|
+
```
|
|
568
|
+
|
|
569
|
+
## TLS Configuration
|
|
570
|
+
|
|
571
|
+
Server certificate verification (`ssl.CERT_REQUIRED`) is enabled by default. To disable certificate verification, set the `ignoreUnauthorized` field to `True` in the connection details.
|
|
572
|
+
|
|
573
|
+
get the server certificate:
|
|
574
|
+
|
|
575
|
+
```python
|
|
576
|
+
from mapepire_python.data_types import DaemonServer
|
|
577
|
+
from mapepire_python.ssl import get_certificate
|
|
578
|
+
|
|
579
|
+
creds = DaemonServer(host=server, port=port, user=user, password=password)
|
|
580
|
+
cert = get_certificate(creds)
|
|
581
|
+
print(cert)
|
|
582
|
+
```
|
|
583
|
+
|
|
584
|
+
## Logging
|
|
585
|
+
|
|
586
|
+
`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:
|
|
587
|
+
|
|
588
|
+
```python
|
|
589
|
+
import logging
|
|
590
|
+
|
|
591
|
+
# Enable INFO-level logs from mapepire-python
|
|
592
|
+
logging.basicConfig(level=logging.INFO)
|
|
593
|
+
logging.getLogger("mapepire_python").setLevel(logging.DEBUG)
|
|
594
|
+
```
|
|
595
|
+
|
|
596
|
+
|
|
422
597
|
|
|
423
598
|
# Usage
|
|
424
599
|
|
|
425
|
-
Depending on your setup and use case, you can choose the most convenient way to configure the connection details. The following usage examples are compatible with all
|
|
600
|
+
Depending on your setup and use case, you can choose the most convenient way to configure the connection details. The following usage examples are compatible with all four connection options detailed above. For simplicity, we assume there is a `mapepire.ini` file in the root of the project with the connection details.
|
|
426
601
|
|
|
427
602
|
|
|
428
603
|
There are four main ways to run queries using `mapepire-python`:
|
|
@@ -436,7 +611,7 @@ There are four main ways to run queries using `mapepire-python`:
|
|
|
436
611
|
## 1. Using the `SQLJob` object to run queries synchronously
|
|
437
612
|
|
|
438
613
|
```python
|
|
439
|
-
from mapepire_python
|
|
614
|
+
from mapepire_python import SQLJob
|
|
440
615
|
|
|
441
616
|
with SQLJob("./mapepire.ini") as sql_job:
|
|
442
617
|
with sql_job.query("select * from sample.employee") as query:
|
|
@@ -580,7 +755,7 @@ In the ouput above, the query was successful and returned one row of data.
|
|
|
580
755
|
To create and run a query in a single step, use the `query_and_run` method:
|
|
581
756
|
|
|
582
757
|
```python
|
|
583
|
-
from mapepire_python
|
|
758
|
+
from mapepire_python import SQLJob
|
|
584
759
|
|
|
585
760
|
with SQLJob("./mapepire.ini") as sql_job:
|
|
586
761
|
# query automatically closed after running
|
|
@@ -594,7 +769,7 @@ The `PoolJob` object can be used to create and run queries asynchronously:
|
|
|
594
769
|
|
|
595
770
|
```python
|
|
596
771
|
import asyncio
|
|
597
|
-
from mapepire_python
|
|
772
|
+
from mapepire_python import PoolJob
|
|
598
773
|
|
|
599
774
|
async def main():
|
|
600
775
|
async with PoolJob("./mapepire.ini") as pool_job:
|
|
@@ -610,7 +785,7 @@ To run a create and run a query asynchronously in a single step, use the `query_
|
|
|
610
785
|
|
|
611
786
|
```python
|
|
612
787
|
import asyncio
|
|
613
|
-
from mapepire_python
|
|
788
|
+
from mapepire_python import PoolJob
|
|
614
789
|
|
|
615
790
|
async def main():
|
|
616
791
|
async with PoolJob("./mapepire.ini") as pool_job:
|
|
@@ -629,7 +804,7 @@ The `Pool` object can be used to create a pool of `PoolJob` objects to run queri
|
|
|
629
804
|
|
|
630
805
|
```python
|
|
631
806
|
import asyncio
|
|
632
|
-
from mapepire_python
|
|
807
|
+
from mapepire_python import Pool, PoolOptions
|
|
633
808
|
|
|
634
809
|
async def main():
|
|
635
810
|
async with Pool(
|
|
@@ -694,18 +869,57 @@ with connect("./mapepire.ini") as conn:
|
|
|
694
869
|
|
|
695
870
|
## PEP 249 Asynchronous Implementation
|
|
696
871
|
|
|
697
|
-
The PEP 249 implementation
|
|
872
|
+
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
873
|
|
|
699
874
|
```python
|
|
700
875
|
import asyncio
|
|
701
|
-
from mapepire_python
|
|
876
|
+
from mapepire_python import async_connect
|
|
702
877
|
|
|
703
878
|
async def main():
|
|
704
|
-
async with
|
|
879
|
+
async with async_connect("./mapepire.ini") as conn:
|
|
705
880
|
async with await conn.execute("select * from sample.employee") as cursor:
|
|
706
881
|
result = await cursor.fetchone()
|
|
707
882
|
print(result)
|
|
708
|
-
|
|
883
|
+
|
|
884
|
+
if __name__ == '__main__':
|
|
885
|
+
asyncio.run(main())
|
|
886
|
+
```
|
|
887
|
+
|
|
888
|
+
Fetch multiple rows at once with `fetchmany` or drain the full result set with `fetchall`:
|
|
889
|
+
|
|
890
|
+
```python
|
|
891
|
+
async def main():
|
|
892
|
+
async with async_connect("./mapepire.ini") as conn:
|
|
893
|
+
async with await conn.execute("select * from sample.employee") as cursor:
|
|
894
|
+
page = await cursor.fetchmany(10) # first 10 rows
|
|
895
|
+
rest = await cursor.fetchall() # remaining rows
|
|
896
|
+
|
|
897
|
+
if __name__ == '__main__':
|
|
898
|
+
asyncio.run(main())
|
|
899
|
+
```
|
|
900
|
+
|
|
901
|
+
Stream rows one at a time using `async for`:
|
|
902
|
+
|
|
903
|
+
```python
|
|
904
|
+
async def main():
|
|
905
|
+
async with async_connect("./mapepire.ini") as conn:
|
|
906
|
+
async for row in await conn.execute("select * from sample.employee"):
|
|
907
|
+
print(row)
|
|
908
|
+
|
|
909
|
+
if __name__ == '__main__':
|
|
910
|
+
asyncio.run(main())
|
|
911
|
+
```
|
|
912
|
+
|
|
913
|
+
Use `AsyncSQLJob` directly for lower-level access without a pool:
|
|
914
|
+
|
|
915
|
+
```python
|
|
916
|
+
from mapepire_python.client.async_sql_job import AsyncSQLJob
|
|
917
|
+
|
|
918
|
+
async def main():
|
|
919
|
+
async with AsyncSQLJob("./mapepire.ini") as job:
|
|
920
|
+
result = await job.query_and_run("select * from sample.employee")
|
|
921
|
+
print(result.data)
|
|
922
|
+
|
|
709
923
|
if __name__ == '__main__':
|
|
710
924
|
asyncio.run(main())
|
|
711
925
|
```
|
|
@@ -863,9 +1077,26 @@ conda deactivate
|
|
|
863
1077
|
```
|
|
864
1078
|
## Run local test suite
|
|
865
1079
|
|
|
866
|
-
|
|
1080
|
+
The suite is split in two:
|
|
1081
|
+
|
|
1082
|
+
- `tests/unit/` — offline unit tests. They mock the WebSocket transport and need
|
|
1083
|
+
**no** IBM i server or credentials, so they run anywhere (including CI on forks).
|
|
1084
|
+
- `tests/integration/` — live-server tests. They connect to a real Mapepire
|
|
1085
|
+
server and require credentials.
|
|
867
1086
|
|
|
868
|
-
|
|
1087
|
+
### Unit tests (no server required)
|
|
1088
|
+
|
|
1089
|
+
```bash
|
|
1090
|
+
# activate python development environment first
|
|
1091
|
+
|
|
1092
|
+
pytest tests/unit/
|
|
1093
|
+
```
|
|
1094
|
+
|
|
1095
|
+
### Integration tests (server required)
|
|
1096
|
+
|
|
1097
|
+
First, create a `pytest.ini` file in the `tests/integration` directory:
|
|
1098
|
+
|
|
1099
|
+
`tests/integration/pytest.ini`
|
|
869
1100
|
|
|
870
1101
|
```ini
|
|
871
1102
|
[pytest]
|
|
@@ -875,11 +1106,17 @@ env =
|
|
|
875
1106
|
VITE_DB_PASS=PASS
|
|
876
1107
|
```
|
|
877
1108
|
|
|
878
|
-
|
|
1109
|
+
Then run the integration suite from the `mapepire-python` directory:
|
|
879
1110
|
|
|
880
1111
|
```bash
|
|
881
1112
|
# activate python development environment first
|
|
882
1113
|
|
|
1114
|
+
pytest tests/integration/
|
|
1115
|
+
```
|
|
1116
|
+
|
|
1117
|
+
To run everything (unit + integration), just point pytest at `tests/`:
|
|
1118
|
+
|
|
1119
|
+
```bash
|
|
883
1120
|
pytest tests/
|
|
884
1121
|
```
|
|
885
1122
|
|