Skip to content

Commit

Permalink
Merge branch 'master' into new-drivers
Browse files Browse the repository at this point in the history
  • Loading branch information
phenobarbital authored Oct 24, 2024
2 parents bb0a447 + 9ae076c commit 3c70420
Show file tree
Hide file tree
Showing 56 changed files with 701 additions and 2,175 deletions.
3 changes: 2 additions & 1 deletion INSTALL → INSTALL.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
gcc python3.9-dev python3.9-venv libmemcached-dev zlib1g-dev build-essential libffi-dev unixodbc unixodbc-dev libsqliteodbc libev4 libev-dev
sudo apt install python3-cassandra
apt install pkg-config
# For MySQL is required:
sudo apt-get install python3-dev default-libmysqlclient-dev build-essential
sudo apt-get install python3-dev default-libmysqlclient-dev build-essential libmariadb-dev libmysqlclient-dev
### For JDBC is required:
sudo apt install openjdk-17-jre java-package
# adding the keys certs
Expand Down
20 changes: 20 additions & 0 deletions MANIFEST.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
include LICENSE
include CHANGELOG.md
include CONTRIBUTING.md
include SECURITY.md
include INSTALL.md
include README.md
include Makefile

graft asyncdb
graft tests

# Exclude tests, settings, env, examples, and bin folders
global-exclude *.pyc
prune docs
prune settings
prune env
prune examples
prune bin
recursive-exclude */__pycache__
prune */__pycache__
2 changes: 0 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,9 @@ venv:
echo 'run `source .venv/bin/activate` to start develop asyncDB'

install:
pip install wheel==0.42.0
pip install -e .

develop:
pip install wheel==0.42.0
pip install -e .[all]
pip install -Ur docs/requirements-dev.txt
flit install --symlink
Expand Down
14 changes: 6 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
# AsyncDB #

AsyncDB is a collection of different Database Drivers using asyncio-based connections, binary-connectors (as asyncpg) but providing an abstraction layer to easily connect to different data sources, a high-level abstraction layer for various non-blocking database connectors,
AsyncDB is a collection of different Database Drivers using asyncio-based connections and binary connectors (as asyncpg) but providing an abstraction layer to easily connect to different data sources, a high-level abstraction layer for various non-blocking database connectors,
on other blocking connectors (like MS SQL Server) we are using ThreadPoolExecutors to run in a non-blocking manner.

### Why AsyncDB? ###

The finality of AsyncDB is to provide us a subset of drivers (connectors) for accessing different databases and data sources for data interaction.
The main goal of AsyncDB is using asyncio-based technologies.
The finality of AsyncDB is to provide us with a subset of drivers (connectors) for accessing different databases and data sources for data interaction.
The main goal of AsyncDB is to use asyncio-based technologies.

### Getting Started ###

Expand Down Expand Up @@ -53,8 +53,9 @@ Currently AsyncDB supports the following databases:
* Apache Cassandra (requires official cassandra driver)
* InfluxDB (using influxdb)
* CouchBase (using aiocouch)
* MongoDB (using motor)
* MongoDB (using motor and pymongo)
* SQLAlchemy (requires sqlalchemy async (+3.14))
* Oracle (requires oracledb)

### Quick Tutorial ###

Expand Down Expand Up @@ -87,10 +88,7 @@ Every Driver has a simple name to call it:
* redis: redis-py (Redis)
* mcache: aiomcache (Memcache)
* odbc: aiodbc (ODBC)

#### Future work: ####

* Prometheus
* oracle: oracle (oracledb)

### Output Support ###

Expand Down
8 changes: 1 addition & 7 deletions asyncdb/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,7 @@
from pathlib import Path

from .connections import AsyncDB, AsyncPool
from .version import (
__author__,
__author_email__,
__description__,
__title__,
__version__
)
from .version import __author__, __author_email__, __description__, __title__, __version__


def get_project_root() -> Path:
Expand Down
32 changes: 9 additions & 23 deletions asyncdb/connections.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
from .utils import install_uvloop


T_aobj = TypeVar('T_aobj', bound='Asyncdb')
T_aobj = TypeVar("T_aobj", bound="Asyncdb")
install_uvloop()


Expand All @@ -16,11 +16,8 @@ class AsyncPool:
Base class for Asyncio-based DB Pools.
Factory interface for Pool-based connectors.
"""
def __new__(
cls: Type[T_aobj],
driver: str = "dummy",
**kwargs
) -> AbstractDriver:

def __new__(cls: Type[T_aobj], driver: str = "dummy", **kwargs) -> AbstractDriver:
classpath = f"asyncdb.drivers.{driver}"
pool = f"{driver}Pool"
try:
Expand All @@ -29,31 +26,24 @@ def __new__(
return obj
except Exception as err:
logging.exception(err)
raise DriverError(
message=f"Cannot Load Backend Pool: {pool}"
) from err
raise DriverError(message=f"Cannot Load Backend Pool: {pool}") from err


class AsyncDB:
"""AsyncDB.
Factory Proxy Interface for Database Providers.
"""
def __new__(
cls: Type[T_aobj],
driver: str = "dummy",
**kwargs
) -> AbstractDriver:

def __new__(cls: Type[T_aobj], driver: str = "dummy", **kwargs) -> AbstractDriver:
classpath = f"asyncdb.drivers.{driver}"
try:
mdl = module_exists(driver, classpath)
obj = mdl(**kwargs)
return obj
except Exception as err:
logging.exception(err)
raise DriverError(
message=f"Cannot Load Backend {driver}"
) from err
raise DriverError(message=f"Cannot Load Backend {driver}") from err


class Asyncdb:
Expand All @@ -62,12 +52,8 @@ class Asyncdb:
Getting a Database Driver Connection.
"""
async def __new__(
cls: Type[T_aobj],
driver: str,
*args,
**kwargs
) -> T_aobj:

async def __new__(cls: Type[T_aobj], driver: str, *args, **kwargs) -> T_aobj:
clspath = f"asyncdb.drivers.{driver}"
mdl = module_exists(driver, clspath)
obj = mdl(**kwargs)
Expand Down
8 changes: 1 addition & 7 deletions asyncdb/drivers/_template/tpl.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,13 +31,7 @@ class template_driver(SQLDriver):
_syntax: str = "sql"
_dsn: str = "{database}"

def __init__(
self,
dsn: str = "",
loop: asyncio.AbstractEventLoop = None,
params: dict = None,
**kwargs
) -> None:
def __init__(self, dsn: str = "", loop: asyncio.AbstractEventLoop = None, params: dict = None, **kwargs) -> None:
"""
Initializes the template_driver with the given DSN,
event loop, and optional parameters.
Expand Down
20 changes: 3 additions & 17 deletions asyncdb/drivers/aioch.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,13 +32,7 @@ class aioch(SQLDriver):
_dsn: str = "{database}"
_test_query: str = "SELECT version()"

def __init__(
self,
dsn: str = "",
loop: asyncio.AbstractEventLoop = None,
params: dict = None,
**kwargs
) -> None:
def __init__(self, dsn: str = "", loop: asyncio.AbstractEventLoop = None, params: dict = None, **kwargs) -> None:
"""
Initializes the clickhouse with the given DSN,
event loop, and optional parameters.
Expand All @@ -55,13 +49,7 @@ def __init__(
Additional keyword arguments to pass to the base SQLDriver.
"""
self._session: Awaitable = None
SQLDriver.__init__(
self,
dsn=dsn,
loop=loop,
params=params,
**kwargs
)
SQLDriver.__init__(self, dsn=dsn, loop=loop, params=params, **kwargs)

async def connection(self, **kwargs):
"""
Expand Down Expand Up @@ -91,9 +79,7 @@ async def connection(self, **kwargs):
self._connected = True
return self
except Exception as exc:
raise DriverError(
f"clickhouse Error: {exc}"
) from exc
raise DriverError(f"clickhouse Error: {exc}") from exc

connect = connection

Expand Down
75 changes: 16 additions & 59 deletions asyncdb/drivers/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,7 @@
from collections.abc import Iterable
import traceback
from ..exceptions import EmptyStatement
from ..interfaces import (
PoolBackend,
ConnectionDSNBackend,
ConnectionBackend,
DatabaseBackend
)
from ..interfaces import PoolBackend, ConnectionDSNBackend, ConnectionBackend, DatabaseBackend
from .outputs import OutputFactory


Expand All @@ -23,24 +18,16 @@ class BasePool(PoolBackend, ConnectionDSNBackend, ABC):
Abstract Class to create Pool-based database connectors with DSN support.
"""

def __init__(
self,
dsn: Union[str, None] = None,
loop: asyncio.AbstractEventLoop = None,
params: Optional[Union[dict, None]] = None,
**kwargs
**kwargs,
):
ConnectionDSNBackend.__init__(
self,
dsn=dsn,
params=params
)
PoolBackend.__init__(
self,
loop=loop,
params=params,
**kwargs
)
ConnectionDSNBackend.__init__(self, dsn=dsn, params=params)
PoolBackend.__init__(self, loop=loop, params=params, **kwargs)


class InitDriver(ConnectionBackend, DatabaseBackend, ABC):
Expand All @@ -49,36 +36,25 @@ class InitDriver(ConnectionBackend, DatabaseBackend, ABC):
Abstract Class for Simple Connections.
----
"""

_provider: str = "init"
_syntax: str = "init"

def __init__(
self,
loop: Union[asyncio.AbstractEventLoop, None] = None,
params: Union[dict, None] = None,
**kwargs
):
def __init__(self, loop: Union[asyncio.AbstractEventLoop, None] = None, params: Union[dict, None] = None, **kwargs):
if params is None:
params = {}
self._max_connections = 4
self._parameters = ()
# noinspection PyTypeChecker
self._serializer: OutputFactory = None
self._row_format = "native"
ConnectionBackend.__init__(
self,
loop=loop,
params=params,
**kwargs
)
ConnectionBackend.__init__(self, loop=loop, params=params, **kwargs)
DatabaseBackend.__init__(self)
self._initialized_on = None
# always starts output format to native:
self.output_format("native")
if self._loop.get_debug():
self._source_traceback = traceback.extract_stack(
sys._getframe(1)
)
self._source_traceback = traceback.extract_stack(sys._getframe(1))

def __enter__(self):
return self
Expand All @@ -99,28 +75,16 @@ async def output(self, result, error):
self._result = result
return [result, error]

def output_format(
self,
frmt: str = "native",
*args,
**kwargs
): # pylint: disable=W1113
self._serializer = OutputFactory(
self,
frmt=frmt,
*args,
**kwargs
)
def output_format(self, frmt: str = "native", *args, **kwargs): # pylint: disable=W1113
self._serializer = OutputFactory(self, frmt=frmt, *args, **kwargs)

async def valid_operation(self, sentence: Any):
"""
Returns if is a valid operation.
TODO: add some validations.
"""
if not sentence:
raise EmptyStatement(
f"{__name__!s} Error: cannot use an empty sentence"
)
raise EmptyStatement(f"{__name__!s} Error: cannot use an empty sentence")
if not self._connection:
await self.connection()

Expand All @@ -131,6 +95,7 @@ class BaseDriver(InitDriver, ConnectionDSNBackend, ABC):
Abstract Class for Database Connections.
----
"""

_provider: str = "base"
_syntax: str = "base" # can use QueryParser for parsing SQL queries

Expand All @@ -140,18 +105,10 @@ def __init__(
loop: asyncio.AbstractEventLoop = None,
pool: Optional[BasePool] = None,
params: dict = None,
**kwargs
**kwargs,
):
InitDriver.__init__(
self, loop=loop,
params=params,
**kwargs
)
ConnectionDSNBackend.__init__(
self,
dsn=dsn,
params=params
)
InitDriver.__init__(self, loop=loop, params=params, **kwargs)
ConnectionDSNBackend.__init__(self, dsn=dsn, params=params)
# always starts output format to native:
self.output_format("native")
self._pool = None
Expand Down
Loading

0 comments on commit 3c70420

Please sign in to comment.