initial implementation

This commit is contained in:
Zac Medico
2016-02-23 18:43:46 -08:00
parent f343c21385
commit 20a2045512
8 changed files with 313 additions and 0 deletions

7
.gitignore vendored Normal file
View File

@@ -0,0 +1,7 @@
*.pyc
*.pyo
__pycache__
*.egg-info
/.cache
/.coverage
/htmlcov

21
LICENSE Normal file
View File

@@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2016 Zac Medico
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

51
README.rst Normal file
View File

@@ -0,0 +1,51 @@
rqlite dialect for SQLAlchemy
==============================
This is the rqlite dialect driver for SQLAlchemy.
installation
------------
To install this dialect run::
$ pip install sqlalchemy_rqlite
or from source::
$ pip install -r ./requirements.txt
$ python ./setup.py install
usage
-----
To start using this dialect::
from sqlalchemy import create_engine
engine = create_engine('rqlite:///demo:', echo=True)
If you don't want to install this library (for example during development) add
this folder to your PYTHONPATH and register this dialect with SQLAlchemy::
from sqlalchemy.dialects import registry
registry.register("rqlite", "sqlalchemy_rqlite.dialect", "RqliteDialect")
testing
-------
you need to have nose and mock installed::
$ pip install nose mock
Run the test suite::
$ ./run_tests.py
more info
---------
* http://www.sqlalchemy.org/
* https://github.com/otoolep/rqlite

109
setup.py Normal file
View File

@@ -0,0 +1,109 @@
#!/usr/bin/env python
import os
from os.path import isdir, islink, relpath, dirname
import subprocess
import sys
from setuptools import (
Command,
setup,
find_packages,
)
sys.path.insert(0, 'src')
from sqlalchemy_rqlite.constants import (
__author__,
__email__,
__license__,
__version__,
)
class PyTest(Command):
user_options = [('match=', 'k', 'Run only tests that match the provided expressions')]
def initialize_options(self):
self.match = None
def finalize_options(self):
pass
def run(self):
testpath = 'src/test'
buildlink = 'build/lib/test'
if isdir(dirname(buildlink)):
if islink(buildlink):
os.unlink(buildlink)
os.symlink(relpath(testpath, dirname(buildlink)), buildlink)
testpath = buildlink
try:
os.environ['EPYTHON'] = 'python{}.{}'.format(sys.version_info.major, sys.version_info.minor)
subprocess.check_call(['py.test', '-v', testpath,
'--cov-report=html', '--cov-report=term'] +
(['-k', self.match] if self.match else []) +
['--cov={}'.format(p) for p in find_packages(dirname(testpath), exclude=['test'])])
finally:
if islink(buildlink):
os.unlink(buildlink)
class PyLint(Command):
user_options = [('errorsonly', 'E', 'Check only errors with pylint'),
('format=', 'f', 'Change the output format')]
def initialize_options(self):
self.errorsonly = 0
self.format = 'colorized'
def finalize_options(self):
pass
def run(self):
cli_options = ['-E'] if self.errorsonly else []
cli_options.append('--output-format={0}'.format(self.format))
errno = subprocess.call(['pylint'] + cli_options + [
"--msg-template='{C}:{msg_id}:{path}:{line:3d},{column}: {obj}: {msg} ({symbol})'"] +
find_packages('src', exclude=['test']), cwd='./src')
raise SystemExit(errno)
setup_params = dict(
name="sqlalchemy_rqlite",
version=__version__,
description="SQLAlchemy dialect for rqlite",
author=__author__,
author_email=__email__,
maintainer=__author__,
maintainer_email=__email__,
classifiers=[
'Development Status :: 3 - Alpha',
'Environment :: Console',
'Intended Audience :: Developers',
'License :: OSI Approved :: MIT License',
'Programming Language :: Python',
'Programming Language :: Python :: 2',
'Programming Language :: Python :: 2.7',
'Programming Language :: Python :: 3',
'Programming Language :: Python :: 3.3',
'Programming Language :: Python :: 3.4',
'Programming Language :: Python :: 3.5',
'Programming Language :: Python :: Implementation :: CPython',
'Programming Language :: Python :: Implementation :: PyPy',
'Topic :: Database :: Front-Ends',
],
keywords='rqlite SQLAlchemy',
package_dir={'': 'src'},
packages=find_packages('src', exclude=['test']),
include_package_data=True,
platforms=['Posix'],
cmdclass={'test': PyTest, 'lint': PyLint},
entry_points={
"sqlalchemy.dialects":
["rqlite.pyrqlite = sqlalchemy_rqlite.pyrqlite:dialect"]
},
license=__license__,
)
if __name__ == '__main__':
setup(**setup_params)

View File

@@ -0,0 +1,11 @@
from sqlalchemy.dialects.sqlite import base, pysqlite, pysqlcipher
from sqlalchemy.dialects.sqlite.base import (
BLOB, BOOLEAN, CHAR, DATE, DATETIME, DECIMAL, FLOAT, INTEGER, REAL,
NUMERIC, SMALLINT, TEXT, TIME, TIMESTAMP, VARCHAR, dialect,
)
__all__ = ('BLOB', 'BOOLEAN', 'CHAR', 'DATE', 'DATETIME', 'DECIMAL',
'FLOAT', 'INTEGER', 'NUMERIC', 'SMALLINT', 'TEXT', 'TIME',
'TIMESTAMP', 'VARCHAR', 'REAL', 'dialect')

View File

@@ -0,0 +1,10 @@
__version__ = "HEAD"
__project__ = "sqlalchemy-rqlite"
__author__ = "Zac Medico"
__email__ = "zmedico@gmail.com"
__copyright__ = "Copyright (C) 2016 Zac Medico"
__license__ = "MIT"
__description__ = "A SQLAlchemy dialect for rqlite"

View File

@@ -0,0 +1,91 @@
from sqlalchemy.dialects.sqlite.base import SQLiteDialect, DATETIME, DATE
from sqlalchemy import exc, pool
from sqlalchemy import types as sqltypes
from sqlalchemy import util
import os
class _SQLite_rqliteTimeStamp(DATETIME):
def bind_processor(self, dialect):
if dialect.native_datetime:
return None
else:
return DATETIME.bind_processor(self, dialect)
def result_processor(self, dialect, coltype):
if dialect.native_datetime:
return None
else:
return DATETIME.result_processor(self, dialect, coltype)
class _SQLite_rqliteDate(DATE):
def bind_processor(self, dialect):
if dialect.native_datetime:
return None
else:
return DATE.bind_processor(self, dialect)
def result_processor(self, dialect, coltype):
if dialect.native_datetime:
return None
else:
return DATE.result_processor(self, dialect, coltype)
class SQLiteDialect_rqlite(SQLiteDialect):
default_paramstyle = 'qmark'
colspecs = util.update_copy(
SQLiteDialect.colspecs,
{
sqltypes.Date: _SQLite_rqliteDate,
sqltypes.TIMESTAMP: _SQLite_rqliteTimeStamp,
}
)
if not util.py2k:
description_encoding = None
driver = 'pyrqlite'
# pylint: disable=method-hidden
@classmethod
def dbapi(cls):
try:
# pylint: disable=no-name-in-module
from pyrqlite import dbapi2 as sqlite
#from sqlite3 import dbapi2 as sqlite # try 2.5+ stdlib name.
except ImportError:
#raise e
raise
return sqlite
@classmethod
def get_pool_class(cls, url):
if url.database and url.database != ':memory:':
return pool.NullPool
else:
return pool.SingletonThreadPool
def create_connect_args(self, url):
if url.username or url.password:
raise exc.ArgumentError(
"Invalid RQLite URL: %s\n"
"Valid RQLite URL forms are:\n"
" rqlite+pyrqlite://host:port/[?params]" % (url,))
opts = url.query.copy()
util.coerce_kw_type(opts, 'connect_timeout', float)
util.coerce_kw_type(opts, 'detect_types', int)
opts['port'] = url.port
opts['host'] = url.host
return ([], opts)
def is_disconnect(self, e, connection, cursor):
return False
dialect = SQLiteDialect_rqlite

13
src/test/test_register.py Normal file
View File

@@ -0,0 +1,13 @@
from sqlalchemy import (
create_engine,
)
from sqlalchemy_rqlite import pyrqlite
from sqlalchemy.dialects import registry
def test_register():
registry.register("rqlite.pyrqlite", "sqlalchemy_rqlite.pyrqlite", "dialect")
#engine = create_engine('rqlite+pyrqlite://localhost:4001/?detect_types=0&connect_timeout=3.0')
#engine.dispose()