Skip to content

Commit 3be229f

Browse files
authored
Merge pull request #8 from GoodManWEN/dev
Dev
2 parents fff3dd4 + 5fe8302 commit 3be229f

File tree

6 files changed

+228
-34
lines changed

6 files changed

+228
-34
lines changed

.github/workflows/python-package.yml

Lines changed: 45 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,14 @@ name: Build
55

66
on:
77
push:
8-
branches: [ main ]
8+
branches:
9+
- 'master'
10+
- '[0-9].[0-9]+' # matches to backport branches, e.g. 3.6
11+
- dev
912
pull_request:
10-
branches: [ main ]
13+
branches:
14+
- 'master'
15+
- '[0-9].[0-9]+'
1116
schedule:
1217
- cron: '0 9 1 * *' # Runs at 09:00 UTC on the 1st of every month
1318

@@ -17,26 +22,44 @@ jobs:
1722
runs-on: ${{ matrix.os }}
1823
strategy:
1924
matrix:
20-
os: [macos-latest, ubuntu-latest, windows-latest]
25+
os: [ubuntu-latest]
2126
python-version: ['3.7' , '3.8' , '3.9']
2227

2328
steps:
24-
- uses: actions/checkout@v2
25-
- name: Set up Python ${{ matrix.python-version }}
26-
uses: actions/setup-python@v2
27-
with:
28-
python-version: ${{ matrix.python-version }}
29-
- name: Install dependencies
30-
run: |
31-
python -m pip install --upgrade pip
32-
python -m pip install flake8 pytest pytest-asyncio
33-
pip install -r requirements.txt
34-
- name: Lint with flake8
35-
run: |
36-
# stop the build if there are Python syntax errors or undefined names
37-
flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics
38-
# exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide
39-
flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics
40-
- name: Test with pytest
41-
run: |
42-
pytest
29+
- name: Checkout
30+
uses: actions/checkout@v2 # You need to checkout first, then you can use your repo in following actions.
31+
with:
32+
repository: GoodManWEN/oracle-client-action
33+
- name: Setup Oracledb client
34+
uses: GoodManWEN/oracle-client-action@main
35+
- name: Checkout
36+
uses: actions/checkout@v2
37+
with:
38+
repository: GoodManWEN/oracle-11g-server-action
39+
- name: Setup Oracledb 11gR2 server
40+
uses: GoodManWEN/oracle-11g-server-action@main
41+
with:
42+
host port: 1521
43+
oracle version: '1.0.0'
44+
- name: Checkout
45+
uses: actions/checkout@v2
46+
- name: Set up Python ${{ matrix.python-version }}
47+
uses: actions/setup-python@v2
48+
with:
49+
python-version: ${{ matrix.python-version }}
50+
- name: Install dependencies
51+
run: | # sleep to make sure Oracle server is fully loaded
52+
sleep 60
53+
python -m pip install --upgrade pip
54+
python -m pip install flake8 pytest pytest-asyncio
55+
pip install -r requirements.txt
56+
- name: Lint with flake8
57+
run: |
58+
# stop the build if there are Python syntax errors or undefined names
59+
flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics
60+
# exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide
61+
flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics
62+
- name: Test with pytest
63+
run: |
64+
sleep 30
65+
pytest

README.md

Lines changed: 31 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,8 @@ Easy to use , buy may not the best practice for efficiency concern.
1818
pip install cx_Oracle_async
1919

2020
## Usage
21-
- Nearly all the same with aiomysql (with very limited functions of cource)
21+
- Nearly all the same with aiomysql (with very limited functions of cource).
22+
- If you're connecting to database which is on a different machine with python process , you need to install oracle client module in order to use this library. Check [cx-Oracle's installation guide](https://cx-oracle.readthedocs.io/en/latest/user_guide/installation.html).
2223
- No automaticly date format transition built-in.
2324

2425
## Performance
@@ -33,24 +34,22 @@ single line insertion | N/A (todo) | N/A | N/A
3334
*Oracle 19c*<br>
3435
*You can find performance test codes [here](https://github.com/GoodManWEN/cx_Oracle_async/blob/main/misc).*
3536

36-
## Example
37+
## Examples
38+
Before running examples , make sure you've already installed a [oracle client](https://github.com/GoodManWEN/cx_Oracle_async#usage) on your machine.
3739
```Python3
3840
# all_usages.py
3941
import asyncio
4042
import cx_Oracle_async
4143

4244
async def main():
43-
loop = asyncio.get_running_loop()
4445
oracle_pool = await cx_Oracle_async.create_pool(
4546
host='localhost',
4647
port='1521',
4748
user='user',
4849
password='password',
49-
db='orcl',
50-
loop=loop,
51-
autocommit=False, # this option has no use.
52-
minsize = 2,
53-
maxsize = 4,
50+
service_name='orcl',
51+
min = 2,
52+
max = 4,
5453
)
5554

5655
async with oracle_pool.acquire() as connection:
@@ -74,6 +73,30 @@ async def main():
7473
await cursor.execute(sql_3 , (60 , ))
7574
print(await cursor.fetchall())
7675

76+
await oracle_pool.close()
77+
7778
if __name__ == '__main__':
7879
asyncio.run(main())
7980
```
81+
82+
Or you can connect to database via makedsn style:
83+
```Python3
84+
# makedsn.py
85+
import asyncio
86+
import cx_Oracle_async
87+
88+
async def main():
89+
# same api as cx_Oracle.makedsn with 4 limited parameters(host , port , sid , service_name).
90+
dsn = cx_Oracle_async.makedsn(host = 'localhost' , port = '1521' , service_name = 'orcl')
91+
oracle_pool = await cx_Oracle_async.create_pool(
92+
user='user',
93+
password='password',
94+
dsn = dsn
95+
)
96+
97+
...
98+
99+
await oracle_pool.close()
100+
101+
asyncio.run(main())
102+
```

cx_Oracle_async/__init__.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
__version__ = ''
22

3-
from .utils import create_pool
3+
from .utils import create_pool , makedsn
44

55
__all__ = (
66
'create_pool',
7+
'makedsn'
78
)

cx_Oracle_async/utils.py

Lines changed: 54 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
from ThreadPoolExecutorPlus import ThreadPoolExecutor
2-
import cx_Oracle as csor
2+
import cx_Oracle as cxor
33
import platform
44
import asyncio
55
import os
@@ -12,6 +12,8 @@
1212
DEFAULT_MAXIMUM_WORKER_NUM = (os.cpu_count() or 1) * 32
1313
DEFAULT_MAXIMUM_WORKER_TIMES = 3
1414

15+
makedsn = cxor.makedsn
16+
1517
class AsyncCursorWrapper:
1618

1719
def __init__(self , loop , thread_pool , cursor):
@@ -115,10 +117,59 @@ def _test():
115117

116118
await self._loop.run_in_executor(self._thread_pool , _test)
117119

118-
async def create_pool(host = 'localhost', port = '1521' , user = 'sys', password = '', db = 'orcl', loop = None, minsize = 2 , maxsize = 4 , encoding = 'UTF-8' , autocommit=False):
120+
async def create_pool(
121+
user=None,
122+
password=None,
123+
dsn=None,
124+
min=2,
125+
max=4,
126+
increment=1,
127+
connectiontype=cxor.Connection,
128+
threaded=True,
129+
getmode=cxor.SPOOL_ATTRVAL_NOWAIT,
130+
events=False,
131+
homogeneous=True,
132+
externalauth=False,
133+
encoding='UTF-8',
134+
edition=None,
135+
timeout=0,
136+
waitTimeout=0,
137+
maxLifetimeSession=0,
138+
sessionCallback=None,
139+
maxSessionsPerShard=0,
140+
host=None,
141+
port=None,
142+
service_name=None,
143+
sid=None,
144+
loop=None
145+
):
119146
if loop == None:
120147
loop = asyncio.get_running_loop()
121-
pool = csor.SessionPool(user , password , f"{host}:{port}/{db}", min = minsize , max = maxsize , increment = 1 , threaded = True , encoding = encoding)
148+
if dsn == None:
149+
if service_name != None:
150+
dsn = makedsn(host = host, port = port, sid = sid , service_name = service_name)
151+
else:
152+
dsn = makedsn(host = host, port = port, sid = sid)
153+
pool = cxor.SessionPool(
154+
user=user,
155+
password=password,
156+
dsn=dsn,
157+
min=min,
158+
max=max,
159+
increment=increment,
160+
connectiontype=connectiontype,
161+
threaded=threaded,
162+
getmode=getmode,
163+
events=events,
164+
homogeneous=homogeneous,
165+
externalauth=externalauth,
166+
encoding=encoding,
167+
edition=edition,
168+
timeout=timeout,
169+
waitTimeout=waitTimeout,
170+
maxLifetimeSession=maxLifetimeSession,
171+
sessionCallback=sessionCallback,
172+
maxSessionsPerShard=maxSessionsPerShard)
122173
pool = AsyncPoolWrapper(pool)
123174
await pool.preexciting()
124175
return pool

tests/test_behavior.py

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
import os , sys
2+
sys.path.append(os.getcwd())
3+
import pytest
4+
import asyncio
5+
from cx_Oracle_async import *
6+
7+
@pytest.mark.asyncio
8+
async def test_new_table():
9+
dsn = makedsn(
10+
host = 'localhost',
11+
port = '1521',
12+
sid = 'xe'
13+
)
14+
oracle_pool = await create_pool(
15+
user = 'system',
16+
password = 'oracle',
17+
dsn = dsn
18+
)
19+
20+
async with oracle_pool.acquire() as connection:
21+
async with connection.cursor() as cursor:
22+
# check if dept exesits
23+
await cursor.execute("SELECT COUNT(*) FROM USER_TABLES WHERE TABLE_NAME = UPPER(:a)" , ('DEPT' , ))
24+
ret = await cursor.fetchone()
25+
assert ret
26+
if ret[0] > 0:
27+
await cursor.execute("DTOP TABLE DEPT")
28+
29+
sql = f"""
30+
CREATE TABLE DEPT
31+
(DEPTNO NUMBER(2) CONSTRAINT PK_DEPT PRIMARY KEY,
32+
DNAME VARCHAR2(14),
33+
LOC VARCHAR2(13)
34+
)
35+
"""
36+
await cursor.execute(sql)
37+
38+
# Single Insertion
39+
sql = "INSERT INTO DEPT(DEPTNO , DNAME , LOC) VALUES (:a , :b , :c)"
40+
await cursor.execute(sql , (10 ,'ACCOUNTING','NEW YORK'))
41+
await connection.commit()
42+
43+
# Multiple Insertion
44+
data = [
45+
(30,'SALES','CHICAGO'),
46+
(40,'OPERATIONS','BOSTON'),
47+
]
48+
await cursor.executemany(sql , data)
49+
await connection.commit()
50+
51+
# Check
52+
await cursor.execute("SELECT DNAME , LOC FROM DEPT WHERE DEPTNO BETWEEN :a AND :b" , (10 , 30))
53+
ret = await cursor.fetchall()
54+
assert len(ret) == 2
55+
assert ret[0][0] == 'ACCOUNTING'
56+
assert ret[1][1] == 'CHICAGO'
57+
58+
await oracle_pool.close()

tests/test_connection.py

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import os , sys
2+
sys.path.append(os.getcwd())
3+
import pytest
4+
import asyncio
5+
from cx_Oracle_async import *
6+
7+
@pytest.mark.asyncio
8+
async def test_different_connect_ways():
9+
dsn = makedsn(
10+
host = 'localhost',
11+
port = '1521',
12+
sid = 'xe'
13+
)
14+
oracle_pool = await create_pool(
15+
user = 'system',
16+
password = 'oracle',
17+
dsn = dsn
18+
)
19+
ret = await oracle_pool.close()
20+
assert ret == None
21+
22+
oracle_pool = await create_pool(
23+
host = 'localhost',
24+
port = '1521',
25+
user = 'system',
26+
password = 'oracle',
27+
sid = 'xe',
28+
min = 2 ,
29+
max = 4
30+
)
31+
32+
async with oracle_pool.acquire() as connection:
33+
async with connection.cursor() as cursor:
34+
pass
35+
36+
ret = await oracle_pool.close()
37+
assert ret == None
38+

0 commit comments

Comments
 (0)