Skip to content

Commit

Permalink
Update docs & weakref
Browse files Browse the repository at this point in the history
  • Loading branch information
GoodManWEN committed Jan 26, 2021
1 parent cf349ce commit 1efd5d5
Show file tree
Hide file tree
Showing 26 changed files with 1,144 additions and 368 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -127,3 +127,6 @@ dmypy.json

# Pyre type checker
.pyre/

# Spinx
/docs/build
48 changes: 11 additions & 37 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
[![pyversions](https://img.shields.io/pypi/pyversions/cx-Oracle-async.svg)](https://pypi.org/project/cx-Oracle-async/)
[![Publish](https://github.com/GoodManWEN/cx_Oracle_async/workflows/Publish/badge.svg)](https://github.com/GoodManWEN/cx_Oracle_async/actions?query=workflow:Publish)
[![Build](https://github.com/GoodManWEN/cx_Oracle_async/workflows/Build/badge.svg)](https://github.com/GoodManWEN/cx_Oracle_async/actions?query=workflow:Build)
[![Docs](https://readthedocs.org/projects/cx-oracle-async/badge/?version=latest)](https://readthedocs.org/projects/cx-oracle-async/)

A very simple asynchronous wrapper that allows you to get access to the Oracle database in asyncio programs.

Expand All @@ -16,15 +17,19 @@ Easy to use , buy may not the best practice for efficiency concern.
## Install

pip install cx_Oracle_async
## Usage

## Feature
- Nearly all the same as aiomysql in asynchronous operational approach , with limited cx_Oracle feature support.
- No automaticly date format transition built-in.
- AQ feature added , check [docs here](https://github.com/GoodManWEN/cx_Oracle_async/blob/main/docs/temporary_document_of_AQ.md) for further information.
- AQ feature added , check [docs here](https://cx_oracle_async.readthedocs.io/en/latest/user_guide/advancedfeatures.html#oracle-advanced-queuing-aq) for further information.
- You can modify some of the connection properties simply like you're using cx_Oracle.
- You can do basic insert / select / delete etc.
- If you're connecting to database which is on a different machine from 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) for further information.

## Documentation

[https://cx_oracle_async.readthedocs.io](https://cx_oracle_async.readthedocs.io)

## Performance
query type | asynchronous multithreading | synchronous multithreading | synchronous single thread
-|-|-|-
Expand All @@ -38,7 +43,7 @@ single line insertion | 1341.88 q/s | 1898 q/s | 1685.17 q/s
*You can find performance test codes [here](https://github.com/GoodManWEN/cx_Oracle_async/blob/main/misc).*

## Examples
Before running examples , make sure you've already installed a [oracle client](https://github.com/GoodManWEN/cx_Oracle_async#usage) on your machine.
Before running examples , make sure you've already installed a [Oracle Client](https://cx-oracle-async.readthedocs.io/en/latest/user_guide/quickstart.html#install-oracle-client) on your machine.
```Python
# basic_usages.py
import asyncio
Expand All @@ -57,42 +62,11 @@ async def main():

async with oracle_pool.acquire() as connection:
async with connection.cursor() as cursor:
# single fetch
sql_1 = "SELECT * FROM SCOTT.DEPT WHERE deptno = :a"
await cursor.execute(sql_1 , (10 , ))
print(await cursor.fetchone())

# multiple inert
sql_2 = "INSERT INTO SCOTT.DEPT(deptno , dname) VALUES (:a , :b)"
sql_2_data = [
[60 , "Hello"],
[70 , "World"],
]
await cursor.executemany(sql_2 , sql_2_data)
await connection.commit()

# multiple fetch
sql_3 = "SELECT * FROM SCOTT.DEPT WHERE deptno >= :a"
await cursor.execute(sql_3 , (60 , ))
await cursor.execute("SELECT * FROM V$SESSION")
print(await cursor.fetchall())

await oracle_pool.close()

if __name__ == '__main__':
asyncio.run(main())
```

Or you can connect to database via dsn style:
```Python
# makedsn.py
import asyncio
import cx_Oracle_async

async def main():
# same api as cx_Oracle.makedsn with 4 limited parameters(host , port , sid , service_name).
dsn = cx_Oracle_async.makedsn(host = 'localhost' , port = '1521' , service_name = 'orcl')
async with cx_Oracle_async.create_pool(user='', password='',dsn = dsn) as pool:
...

asyncio.run(main())
```
```
2 changes: 1 addition & 1 deletion cx_Oracle_async/connections.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ async def commit(self):
return await self._loop.run_in_executor(self._thread_pool , self._conn.commit)

async def release(self):
self._pool_wrapper._unoccupied(self._conn)
self._pool_wrapper._ofree(self)
return await self._loop.run_in_executor(self._thread_pool , self._pool.release , self._conn)

async def cancel(self):
Expand Down
5 changes: 5 additions & 0 deletions cx_Oracle_async/cursors.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,11 @@ def __init__(self , cursor : Cursor, loop : 'ProactorEventLoop' , thread_pool :
self._thread_pool = thread_pool

async def execute(self , sql , *args , **kwargs):
if kwargs:
return await self._loop.run_in_executor(
self._thread_pool ,
lambda : self._cursor.execute(sql , *args , **kwargs)
)
return await self._loop.run_in_executor(self._thread_pool , self._cursor.execute , sql , *args , **kwargs)

async def executemany(self , sql , *args , **kwargs):
Expand Down
25 changes: 14 additions & 11 deletions cx_Oracle_async/pools.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
from .connections import AsyncConnectionWrapper , AsyncConnectionWrapper_context
from ThreadPoolExecutorPlus import ThreadPoolExecutor
from cx_Oracle import Connection , SessionPool
from weakref import WeakSet
from types import CoroutineType
import asyncio
import platform
Expand Down Expand Up @@ -38,22 +39,24 @@ def __init__(self , pool : SessionPool, loop : 'ProactorEventLoop' = None):
self._thread_pool.set_daemon_opts(min_workers = max(4 , pool.min << 1))
self._loop = loop
self._pool = pool
self._occupied = set()
self._occupied = WeakSet()

def acquire(self):
coro = self._loop.run_in_executor(self._thread_pool , self._acquire)
return AsyncConnectionWrapper_context(coro)

def _acquire(self):
_conn = self._pool.acquire()
self._occupied.update((_conn , ))
return AsyncConnectionWrapper(_conn , self._loop , self._thread_pool , self._pool , self)
wrapper = AsyncConnectionWrapper(self._pool.acquire() , self._loop , self._thread_pool , self._pool , self)
self._occupied.add(wrapper)
return wrapper

def _unoccupied(self , obj: Connection):
self._occupied.remove(obj)
def _ofree(self , obj: AsyncConnectionWrapper):
if obj in self._occupied:
self._occupied.remove(obj)

async def release(self , conn: Connection):
return await self._loop.run_in_executor(self._thread_pool , self._pool.release , conn)
async def release(self , conn: AsyncConnectionWrapper):
self._ofree(conn)
return await self._loop.run_in_executor(self._thread_pool , self._pool.release , conn._conn)

async def drop(self , conn: Connection):
return await self._loop.run_in_executor(self._thread_pool , self._pool.drop , conn)
Expand All @@ -67,8 +70,8 @@ async def close(self , force: bool = False , interrupt: bool = False):
Do make sure this option works fine with your working enviornment.
'''
while self._occupied:
_conn = self._occupied.pop()
wrapper = self._occupied.pop()
if interrupt:
await self._loop.run_in_executor(self._thread_pool , _conn.cancel)
await self._loop.run_in_executor(self._thread_pool , wrapper._conn.cancel)

return await self._loop.run_in_executor(self._thread_pool , self._pool.close , force)
return await self._loop.run_in_executor(self._thread_pool , self._pool.close , force)
20 changes: 20 additions & 0 deletions docs/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Minimal makefile for Sphinx documentation
#

# You can set these variables from the command line, and also
# from the environment for the first two.
SPHINXOPTS ?=
SPHINXBUILD ?= sphinx-build
SOURCEDIR = source
BUILDDIR = build

# Put it first so that "make" without argument is like "make help".
help:
@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)

.PHONY: help Makefile

# Catch-all target: route all unknown targets to Sphinx using the new
# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
%: Makefile
@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
13 changes: 13 additions & 0 deletions docs/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
The generated cx_Oracle_async documentation is at https://cx_oracle_async.readthedocs.io/

This directory contains the documentation source. It is written using reST
(re-Structured Text) format source files which are processed using Sphinx and
turned into HTML, PDF or ePub documents. If you wish to build these yourself,
you need to install Sphinx. Sphinx is available on many Linux distributions as a
pre-built package. You can also install Sphinx on all platforms using the Python
package manager "pip". For more information on Sphinx, please visit this page:

http://www.sphinx-doc.org

Once Sphinx is installed, the supplied Makefile can be used to build the
different targets.
35 changes: 35 additions & 0 deletions docs/make.bat
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
@ECHO OFF

pushd %~dp0

REM Command file for Sphinx documentation

if "%SPHINXBUILD%" == "" (
set SPHINXBUILD=sphinx-build
)
set SOURCEDIR=source
set BUILDDIR=build

if "%1" == "" goto help

%SPHINXBUILD% >NUL 2>NUL
if errorlevel 9009 (
echo.
echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
echo.installed, then set the SPHINXBUILD environment variable to point
echo.to the full path of the 'sphinx-build' executable. Alternatively you
echo.may add the Sphinx directory to PATH.
echo.
echo.If you don't have Sphinx installed, grab it from
echo.http://sphinx-doc.org/
exit /b 1
)

%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
goto end

:help
%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%

:end
popd
5 changes: 5 additions & 0 deletions docs/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
Sphinx
sphinx-autobuild
recommonmark
sphinx-rtd-theme
sphinx_markdown_tables
1 change: 1 addition & 0 deletions docs/serve.bat
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
sphinx-autobuild source build/html
Empty file added docs/source/_static/BLANK
Empty file.
Empty file added docs/source/_templates/BLANK
Empty file.
147 changes: 147 additions & 0 deletions docs/source/api_manual/connections.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
.. _connobj:

*****************************
AsyncConnectionWrapper Object
*****************************

Wraps a cx_Oracle.Connection object.

.. method:: AsyncConnectionWrapper.cursor()

Return a new :ref:`async cursor wrapper object <cursorobj>` using the connection.

This is a asynchronous method.

.. method:: AsyncConnectionWrapper.msgproperties(payload, correlation, delay, exceptionq, \
expiration, priority)

Returns an object specifying the properties of messages used in advanced
queuing.

This is a synchronous method.

.. versionadded:: 0.2.0

.. note::

This method is an extension to the cx_Oracle's DB API definition.

.. method:: AsyncConnectionWrapper.queue(name, payloadType=None)

Creates a :ref:`queue <queue>` which is used to enqueue and dequeue
messages in Advanced Queueing.

The name parameter is expected to be a string identifying the queue in
which messages are to be enqueued or dequeued.

This is a asynchronous method.

.. versionadded:: 0.2.0

.. note::

This method is an extension to the cx_Oracle's DB API definition.

.. method:: AsyncConnectionWrapper.gettype(name)

Return a ``cx_Oracle.type object`` given its name. This can then be
used to create objects which can be bound to cursors created by this
connection.

This is a asynchronous method.

.. versionadded:: 0.2.0

.. note::

This method is an extension to the cx_Oracle's DB API definition.

.. method:: AsyncConnectionWrapper.commit()

Commit any pending transactions to the database.

This is a asynchronous method.

.. method:: AsyncConnectionWrapper.release()

Equals to cx_Oracle.SessionPool.release(connection) , by using this equivalent
you don't need to operate with another ``AsyncPoolWrapper`` object.

This is a asynchronous method.

.. method:: AsyncConnectionWrapper.cancel()

Break a long-running transaction.

This is a asynchronous method.

.. note::

This method is an extension to the cx_Oracle's DB API definition.

.. method:: AsyncConnectionWrapper.rollback()

Rollback any pending transactions.

This is a asynchronous method.

.. method:: AsyncConnectionWrapper.ping()

Ping the server which can be used to test if the connection is still
active.

.. note::

This method is an extension to the cx_Oracle's DB API definition.

.. attribute:: AsyncConnectionWrapper.encoding

This read-only attribute returns the IANA character set name of the
character set in use by the Oracle client for regular strings.

.. note::

This attribute is an extension to the cx_Oracle's DB API definition.

.. attribute:: AsyncConnectionWrapper.dsn

This read-only attribute returns the TNS entry of the database to which a
connection has been established.

.. attribute:: AsyncConnectionWrapper.module

This write-only attribute sets the module column in the v$session table.
The maximum length for this string is 48 and if you exceed this length you
will get ORA-24960.

.. note:
This attribute is an extension to the cx_Oracle's DB API definition.
.. attribute:: AsyncConnectionWrapper.action

This write-only attribute sets the action column in the v$session table. It
is a string attribute and cannot be set to None -- use the empty string
instead.

.. note::

This attribute is an extension to the cx_Oracle's DB API definition.

.. attribute:: AsyncConnectionWrapper.client_identifier

This write-only attribute sets the client_identifier column in the
v$session table.

.. note::

This attribute is an extension to the cx_Oracle's DB API definition.

.. attribute:: AsyncConnectionWrapper.clientinfo

This write-only attribute sets the client_info column in the v$session
table.

.. note::

This attribute is an extension to the cx_Oracle's DB API definition.
Loading

0 comments on commit 1efd5d5

Please sign in to comment.