mapepire-python 0.1.4__tar.gz → 0.1.6__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.
Files changed (37) hide show
  1. {mapepire_python-0.1.4 → mapepire_python-0.1.6}/PKG-INFO +283 -20
  2. mapepire_python-0.1.6/README.md +655 -0
  3. mapepire_python-0.1.6/mapepire_python/__init__.py +49 -0
  4. mapepire_python-0.1.6/mapepire_python/asyncio/__init__.py +47 -0
  5. mapepire_python-0.1.6/mapepire_python/asyncio/connection.py +82 -0
  6. mapepire_python-0.1.6/mapepire_python/asyncio/cursor.py +99 -0
  7. mapepire_python-0.1.6/mapepire_python/asyncio/utils.py +23 -0
  8. mapepire_python-0.1.6/mapepire_python/base_job.py +78 -0
  9. mapepire_python-0.1.6/mapepire_python/client/__init__.py +3 -0
  10. mapepire_python-0.1.6/mapepire_python/client/query.py +185 -0
  11. {mapepire_python-0.1.4 → mapepire_python-0.1.6}/mapepire_python/client/sql_job.py +89 -30
  12. mapepire_python-0.1.6/mapepire_python/client/websocket.py +37 -0
  13. mapepire_python-0.1.6/mapepire_python/core/__init__.py +27 -0
  14. mapepire_python-0.1.6/mapepire_python/core/connection.py +86 -0
  15. mapepire_python-0.1.6/mapepire_python/core/cursor.py +201 -0
  16. mapepire_python-0.1.6/mapepire_python/core/exceptions.py +97 -0
  17. mapepire_python-0.1.6/mapepire_python/core/utils.py +78 -0
  18. mapepire_python-0.1.4/mapepire_python/types.py → mapepire_python-0.1.6/mapepire_python/data_types.py +18 -12
  19. mapepire_python-0.1.6/mapepire_python/pool/__init__.py +4 -0
  20. mapepire_python-0.1.6/mapepire_python/pool/pool_client.py +145 -0
  21. mapepire_python-0.1.6/mapepire_python/pool/pool_job.py +318 -0
  22. mapepire_python-0.1.4/mapepire_python/client/query.py → mapepire_python-0.1.6/mapepire_python/pool/pool_query.py +38 -34
  23. mapepire_python-0.1.6/mapepire_python/query_manager.py +67 -0
  24. {mapepire_python-0.1.4 → mapepire_python-0.1.6}/mapepire_python/ssl.py +1 -1
  25. {mapepire_python-0.1.4 → mapepire_python-0.1.6}/mapepire_python/version.py +1 -1
  26. {mapepire_python-0.1.4 → mapepire_python-0.1.6}/mapepire_python.egg-info/PKG-INFO +283 -20
  27. mapepire_python-0.1.6/mapepire_python.egg-info/SOURCES.txt +32 -0
  28. {mapepire_python-0.1.4 → mapepire_python-0.1.6}/mapepire_python.egg-info/requires.txt +6 -0
  29. {mapepire_python-0.1.4 → mapepire_python-0.1.6}/pyproject.toml +6 -0
  30. mapepire_python-0.1.4/README.md +0 -398
  31. mapepire_python-0.1.4/mapepire_python/pool.py +0 -29
  32. mapepire_python-0.1.4/mapepire_python.egg-info/SOURCES.txt +0 -15
  33. {mapepire_python-0.1.4 → mapepire_python-0.1.6}/LICENSE +0 -0
  34. {mapepire_python-0.1.4 → mapepire_python-0.1.6}/mapepire_python/py.typed +0 -0
  35. {mapepire_python-0.1.4 → mapepire_python-0.1.6}/mapepire_python.egg-info/dependency_links.txt +0 -0
  36. {mapepire_python-0.1.4 → mapepire_python-0.1.6}/mapepire_python.egg-info/top_level.txt +0 -0
  37. {mapepire_python-0.1.4 → mapepire_python-0.1.6}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: mapepire-python
3
- Version: 0.1.4
3
+ Version: 0.1.6
4
4
  Author-email: Allen Institute for Artificial Intelligence <contact@allenai.org>
5
5
  License: Apache License
6
6
  Version 2.0, January 2004
@@ -217,12 +217,18 @@ Description-Content-Type: text/markdown
217
217
  License-File: LICENSE
218
218
  Requires-Dist: dataclasses-json>=0.6.4
219
219
  Requires-Dist: websocket-client>=1.2.1
220
+ Requires-Dist: websockets
221
+ Requires-Dist: pyee
222
+ Requires-Dist: pep249abc
220
223
  Provides-Extra: dev
221
224
  Requires-Dist: ruff; extra == "dev"
222
225
  Requires-Dist: mypy<1.5,>=1.0; extra == "dev"
223
226
  Requires-Dist: black<24.0,>=23.0; extra == "dev"
224
227
  Requires-Dist: isort<5.13,>=5.12; extra == "dev"
225
228
  Requires-Dist: pytest; extra == "dev"
229
+ Requires-Dist: pyee; extra == "dev"
230
+ Requires-Dist: pep249abc; extra == "dev"
231
+ Requires-Dist: pytest-asyncio; extra == "dev"
226
232
  Requires-Dist: pytest-sphinx; extra == "dev"
227
233
  Requires-Dist: pytest-cov; extra == "dev"
228
234
  Requires-Dist: twine>=1.11.0; extra == "dev"
@@ -252,26 +258,49 @@ Requires-Dist: pre-commit; extra == "dev"
252
258
  <br/>
253
259
  </div>
254
260
 
255
- - [Overview](#overview)
256
- - [Setup](#setup)
257
- - [Install with `pip`](#install-with-pip)
258
- - [Server Component Setup (Forthcoming)](#server-component-setup-forthcoming)
259
- - [Example usage](#example-usage)
261
+ <details>
262
+ <summary> Table of Contents </summary>
263
+
264
+ - [mapepire-python](#mapepire-python)
265
+ - [Overview](#overview)
266
+ - [Setup](#setup)
267
+ - [Install with `pip`](#install-with-pip)
268
+ - [Server Component Setup](#server-component-setup)
269
+ - [Connection options](#connection-options)
270
+ - [1. Using the `DaemonServer` object](#1-using-the-daemonserver-object)
271
+ - [2. Passing the connection details as a dictionary](#2-passing-the-connection-details-as-a-dictionary)
272
+ - [3. Using a config file (`.ini`) to store the connection details](#3-using-a-config-file-ini-to-store-the-connection-details)
273
+ - [Usage](#usage)
274
+ - [1. Using the `SQLJob` object to run queries synchronously](#1-using-the-sqljob-object-to-run-queries-synchronously)
275
+ - [Query and run](#query-and-run)
276
+ - [2. Using the `PoolJob` object to run queries asynchronously](#2-using-the-pooljob-object-to-run-queries-asynchronously)
277
+ - [3. Using the `Pool` object to run queries "concurrently"](#3-using-the-pool-object-to-run-queries-concurrently)
278
+ - [4. Using PEP 249 Implementation](#4-using-pep-249-implementation)
279
+ - [`fetchmany()` and `fetchall()` methods](#fetchmany-and-fetchall-methods)
280
+ - [PEP 249 Asynchronous Implementation](#pep-249-asynchronous-implementation)
260
281
  - [Development Setup](#development-setup)
261
282
  - [Setup python virtual environment with pip and venv](#setup-python-virtual-environment-with-pip-and-venv)
262
283
  - [Create a new virtual environment](#create-a-new-virtual-environment)
263
284
  - [Unix/macOS](#unixmacos)
264
285
  - [Windows](#windows)
265
286
  - [Activate the virtual environment:](#activate-the-virtual-environment)
287
+ - [Unix.macOS](#unixmacos-1)
288
+ - [Windows](#windows-1)
289
+ - [Unix/macOS](#unixmacos-2)
290
+ - [Windows](#windows-2)
266
291
  - [Prepare pip](#prepare-pip)
292
+ - [Unix/macOS](#unixmacos-3)
293
+ - [Windows](#windows-3)
267
294
  - [Install Dependencies using `requirements-dev.txt`](#install-dependencies-using-requirements-devtxt)
295
+ - [Unix/macOS](#unixmacos-4)
296
+ - [Windows](#windows-4)
268
297
  - [Setup Python virtual environment with Conda](#setup-python-virtual-environment-with-conda)
269
298
  - [Create an environment from an environment-dev.yml file](#create-an-environment-from-an-environment-devyml-file)
270
299
  - [1. Activate the new environment:](#1-activate-the-new-environment)
271
300
  - [2. Verify the new environment was installed:](#2-verify-the-new-environment-was-installed)
272
- - [Run local test suite](#run-local-test-suite)
273
-
301
+ - [Run local test suite](#run-local-test-suite)
274
302
 
303
+ </details>
275
304
 
276
305
  ## Overview
277
306
 
@@ -284,7 +313,7 @@ Requires-Dist: pre-commit; extra == "dev"
284
313
 
285
314
  ## Setup
286
315
 
287
- `mapepire-python` requires Python 3.9 or later.
316
+ `mapepire-python` requires Python 3.10 or later.
288
317
 
289
318
  ### Install with `pip`
290
319
 
@@ -297,28 +326,116 @@ pip install mapepire-python
297
326
  ### Server Component Setup
298
327
  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/)
299
328
 
300
- ## Example usage
329
+
330
+ # Connection options
331
+
332
+ There are three ways to configure mapepire server connection details using `mapepire-python`:
333
+
334
+ 1. Using the `DaemonServer` object
335
+ 2. Passing the connection details as a dictionary
336
+ 3. Using a config file (`.ini`) to store the connection details
337
+
338
+ ## 1. Using the `DaemonServer` object
339
+
340
+ to use the `DaemonServer` object, you will need to import the `DaemonServer` class from the `mapepire_python.data_types` module:
341
+
342
+ ```python
343
+ from mapepire_python.data_types import DaemonServer
344
+
345
+ creds = DaemonServer(
346
+ host="SERVER",
347
+ port="PORT",
348
+ user="USER",
349
+ password="PASSWORD",
350
+ ignoreUnauthorized=True
351
+ )
352
+ ```
301
353
 
302
- The following script sets up a `DaemonServer` object that will be used to connect with the Server Component. Then a single `SQLJob` is created to facilitate the connection from the client side.
354
+ Once you have created the `DaemonServer` object, you can pass it to the `SQLJob` object to connect to the mapepire server:
303
355
 
304
356
  ```python
305
357
  from mapepire_python.client.sql_job import SQLJob
306
- from mapepire_python.types import DaemonServer
358
+ from mapepire_python.data_types import DaemonServer
307
359
 
308
360
  creds = DaemonServer(
309
- host="localhost",
310
- port=8085,
361
+ host="SERVER",
362
+ port="PORT",
311
363
  user="USER",
312
364
  password="PASSWORD",
313
365
  ignoreUnauthorized=True
314
366
  )
315
367
 
368
+ job = SQLJob(creds)
369
+ ```
370
+
371
+ ## 2. Passing the connection details as a dictionary
372
+
373
+ You can also use a dictionary to configure the connection details:
374
+
375
+ ```python
376
+ from mapepire_python.client.sql_job import SQLJob
377
+
378
+ creds = {
379
+ "host": "SERVER",
380
+ "port": "port",
381
+ "user": "USER",
382
+ "password": "PASSWORD",
383
+ }
384
+
385
+ job = SQLJob(creds)
386
+ ```
387
+
388
+ this is a convenient way to pass the connection details to the mapepire server.
389
+
390
+ ## 3. Using a config file (`.ini`) to store the connection details
316
391
 
317
- job = SQLJob()
318
- res = job.connect(creds)
319
- query = job.query("select * from sample.employee")
320
- result = query.run(rows_to_fetch=3)
321
- print(result)
392
+
393
+ If you use a config file (`.ini`), you can pass the path to the file as an argument:
394
+
395
+ First create a `mapepire.ini` file in the root of your project with the following required fields:
396
+
397
+ ```ini title=mapepire.ini
398
+ [mapepire]
399
+ SERVER="SERVER"
400
+ PORT="PORT"
401
+ USER="USER"
402
+ PASSWORD="PASSWORD"
403
+ ```
404
+
405
+ Then you can create a `SQLJob` object by passing the path to the `.ini` file which will handle the connection details
406
+
407
+
408
+ ```python
409
+ from mapepire_python.client.sql_job import SQLJob
410
+
411
+ job = SQLJob("./mapepire.ini", section="mapepire")
412
+ ```
413
+
414
+ 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
+
416
+
417
+ # Usage
418
+
419
+ 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 three connection options detailed above. For simplicity, we assume there is a `mapepire.ini` file in the root of the project with the connection details.
420
+
421
+
422
+ There are four main ways to run queries using `mapepire-python`:
423
+ 1. Using the `SQLJob` object to run queries synchronously
424
+ 2. Using the `PoolJob` object to run queries asynchronously
425
+ 3. Using the `Pool` object to run queries "concurrently"
426
+ 4. Using PEP 249 Implementation
427
+
428
+
429
+
430
+ ## 1. Using the `SQLJob` object to run queries synchronously
431
+
432
+ ```python
433
+ from mapepire_python.client.sql_job import SQLJob
434
+
435
+ with SQLJob("./mapepire.ini") as sql_job:
436
+ with sql_job.query("select * from sample.employee") as query:
437
+ result = query.run(rows_to_fetch=1)
438
+ print(result)
322
439
  ```
323
440
 
324
441
  Here is the output from the script above:
@@ -441,6 +558,152 @@ Here is the output from the script above:
441
558
  }
442
559
 
443
560
  ```
561
+ The results object is a JSON object that contains the metadata and data from the query. Here are the different fields returned:
562
+ - `id` field contains the query ID
563
+ - `has_results` field indicates whether the query returned any results
564
+ - `update_count` field indicates the number of rows updated by the query (-1 if the query did not update any rows)
565
+ - `metadata` field contains information about the columns returned by the query
566
+ - `data` field contains the results of the query
567
+ - `is_done` field indicates whether the query has finished executing
568
+ - `success` field indicates whether the query was successful.
569
+
570
+ In the ouput above, the query was successful and returned one row of data.
571
+
572
+ ### Query and run
573
+
574
+ To create and run a query in a single step, use the `query_and_run` method:
575
+
576
+ ```python
577
+ from mapepire_python.client.sql_job import SQLJob
578
+
579
+ with SQLJob("./mapepire.ini") as sql_job:
580
+ # query automatically closed after running
581
+ results = sql_job.query_and_run("select * from sample.employee", rows_to_fetch=1)
582
+ print(result)
583
+ ```
584
+
585
+ ## 2. Using the `PoolJob` object to run queries asynchronously
586
+
587
+ The `PoolJob` object can be used to create and run queries asynchronously:
588
+
589
+ ```python
590
+ import asyncio
591
+ from mapepire_python.pool.pool_job import PoolJob
592
+
593
+ async def main():
594
+ async with PoolJob("./mapepire.ini") as pool_job:
595
+ async with pool_job.query('select * from sample.employee') as query:
596
+ res = await query.run(rows_to_fetch=1)
597
+
598
+ if __name__ == '__main__':
599
+ asyncio.run(main())
600
+
601
+ ```
602
+
603
+ To run a create and run a query asynchronously in a single step, use the `query_and_run` method:
604
+
605
+ ```python
606
+ import asyncio
607
+ from mapepire_python.pool.pool_job import PoolJob
608
+
609
+ async def main():
610
+ async with PoolJob("./mapepire.ini") as pool_job:
611
+ res = await pool_job.query_and_run("select * from sample.employee", rows_to_fetch=1)
612
+ print(res)
613
+
614
+ if __name__ == '__main__':
615
+ asyncio.run(main())
616
+
617
+ ```
618
+
619
+
620
+ ## 3. Using the `Pool` object to run queries "concurrently"
621
+
622
+ The `Pool` object can be used to create a pool of `PoolJob` objects to run queries concurrently.
623
+
624
+ ```python
625
+ import asyncio
626
+ from mapepire_python.pool.pool_client import Pool, PoolOptions
627
+
628
+ async def main():
629
+ async with Pool(
630
+ options=PoolOptions(
631
+ creds="./mapepire.ini",
632
+ opts=None,
633
+ max_size=5,
634
+ starting_size=3
635
+ )
636
+ ) as pool:
637
+ job_names = []
638
+ resultsA = await asyncio.gather(
639
+ pool.execute('values (job_name)'),
640
+ pool.execute('values (job_name)'),
641
+ pool.execute('values (job_name)')
642
+ )
643
+ job_names = [res['data'][0]['00001'] for res in resultsA]
644
+
645
+ print(job_names)
646
+
647
+
648
+ if __name__ == '__main__':
649
+ asyncio.run(main())
650
+ ```
651
+ This script will create a pool of 3 `PoolJob` objects and run the query `values (job_name)` concurrently. The results will be printed to the console.
652
+
653
+ ```bash
654
+ ['004460/QUSER/QZDASOINIT', '005096/QUSER/QZDASOINIT', '005319/QUSER/QZDASOINIT']
655
+ ```
656
+
657
+ ## 4. Using PEP 249 Implementation
658
+
659
+ PEP 249 is the Python Database API Specification v2.0. The `mapepire-python` client provides a PEP 249 implementation that allows you to use the `Connection` and `Cursor` objects to interact with the Mapepire server. Like the examples above, we can pass the `mapepire.ini` file to the `connect` function to create a connection to the server:
660
+
661
+ ```python
662
+ from mapepire_python import connect
663
+
664
+ with connect("./mapepire.ini") as conn:
665
+ with conn.execute("select * from sample.employee") as cursor:
666
+ result = cursor.fetchone()
667
+ print(result)
668
+ ```
669
+
670
+ ### `fetchmany()` and `fetchall()` methods
671
+
672
+ The `Cursor` object provides the `fetchmany()` and `fetchall()` methods to fetch multiple rows from the result set:
673
+
674
+ ```python
675
+ with connect("./mapepire.ini") as conn:
676
+ with conn.execute("select * from sample.employee") as cursor:
677
+ results = cursor.fetchmany(size=2)
678
+ print(results)
679
+ ```
680
+ ---
681
+
682
+ ```python
683
+ with connect("./mapepire.ini") as conn:
684
+ with conn.execute("select * from sample.employee") as cursor:
685
+ results = cursor.fetchall()
686
+ print(results)
687
+ ```
688
+
689
+ ## PEP 249 Asynchronous Implementation
690
+
691
+ The PEP 249 implementation also provides an asynchronous interface for running queries. The `connect` function returns an asynchronous context manager that can be used with the `async with` statement:
692
+
693
+ ```python
694
+ import asyncio
695
+ from mapepire_python.asycnio import connect
696
+
697
+ async def main():
698
+ async with connect("./mapepire.ini") as conn:
699
+ async with await conn.execute("select * from sample.employee") as cursor:
700
+ result = await cursor.fetchone()
701
+ print(result)
702
+
703
+ if __name__ == '__main__':
704
+ asyncio.run(main())
705
+ ```
706
+
444
707
 
445
708
  # Development Setup
446
709
 
@@ -454,7 +717,7 @@ This guide provides instructions for setting up a Python virtual environment usi
454
717
 
455
718
  ### Create a new virtual environment
456
719
 
457
- **Note**: This applies to supported versions of Python 3.8 and higher
720
+ **Note**: This applies to supported versions of Python 3.10 and higher
458
721
 
459
722
  navigate to the project's directory and run the following command. This will create a new virtual environment in a local folder named `.venv`
460
723