mirror of
https://github.com/rqlite/sqlalchemy-rqlite.git
synced 2022-10-30 02:38:33 +03:00
initial implementation
This commit is contained in:
7
.gitignore
vendored
Normal file
7
.gitignore
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
*.pyc
|
||||
*.pyo
|
||||
__pycache__
|
||||
*.egg-info
|
||||
/.cache
|
||||
/.coverage
|
||||
/htmlcov
|
||||
21
LICENSE
Normal file
21
LICENSE
Normal 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
51
README.rst
Normal 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
109
setup.py
Normal 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)
|
||||
11
src/sqlalchemy_rqlite/__init__.py
Normal file
11
src/sqlalchemy_rqlite/__init__.py
Normal 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')
|
||||
10
src/sqlalchemy_rqlite/constants.py
Normal file
10
src/sqlalchemy_rqlite/constants.py
Normal 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"
|
||||
91
src/sqlalchemy_rqlite/pyrqlite.py
Normal file
91
src/sqlalchemy_rqlite/pyrqlite.py
Normal 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
13
src/test/test_register.py
Normal 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()
|
||||
Reference in New Issue
Block a user