Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Python driver implements DB-API. #8

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion Vagrantfile
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@ Vagrant.configure("2") do |config|
config.vm.provision "shell", inline: <<-SHELL
apt-get -qqy update

apt-get -qqy install make zip unzip git pkg-config libssl-dev zlib1g-dev
apt-get -qqy install make zip unzip git pkg-config libssl-dev zlib1g-dev
apt-get -qqy install python-dev python3-dev python3.7

echo "[vagrant provisioning] Downloading Bazel..."
wget --quiet https://github.com/bazelbuild/bazel/releases/download/0.29.1/bazel-0.29.1-installer-linux-x86_64.sh
Expand Down
13 changes: 11 additions & 2 deletions WORKSPACE
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,7 @@ http_archive(
git_repository(
name = "com_github_grpc_grpc",
remote = "https://github.com/grpc/grpc.git",
commit = "08fd59f039c7cf62614ab7741b3f34527af103c7",
shallow_since = "1562093080 -0700",
tag = "v1.24.3",
)

git_repository(
Expand Down Expand Up @@ -66,6 +65,16 @@ git_repository(
shallow_since = "1560490505 +0000",
)

# Python dependencies
load("@upb//bazel:workspace_deps.bzl", "upb_deps")
upb_deps()

load("@build_bazel_rules_apple//apple:repositories.bzl", "apple_rules_dependencies")
apple_rules_dependencies()

load("@build_bazel_apple_support//lib:repositories.bzl", "apple_support_dependencies")
apple_support_dependencies()

# GoLang main Bazel tools
http_archive(
name = "io_bazel_rules_go",
Expand Down
32 changes: 32 additions & 0 deletions client/python/BUILD
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
py_binary(
name = "main",
srcs = ["main.py",],
python_version = "PY3",
deps = [
"//driver/python:py_db_api",
":lib",
]
)

py_library(
name = "lib",
srcs = [
"__init__.py",
"optionparser.py",
"sfdb_cli.py",
],
visibility = ["//visibility:public"],
imports = ["."],
)

py_test(
name = "test/sfdbcli_test",
srcs = ["test/sfdbcli_test.py",],
python_version = "PY3",
visibility = ["//visibility:public"],
deps = [
"//driver/python:py_db_api",
"//driver/python:test/py_test_lib",
],
data = ["//sfdb:sfdb"],
)
1 change: 1 addition & 0 deletions client/python/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
__version__ = '0.0.1'
26 changes: 26 additions & 0 deletions client/python/main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import sys
from client.python.optionparser import create_parser
from client.python.sfdb_cli import SfdbCli


def run_cli_with(options):
if options.query:
options.interactive_mode = False
sfdbcli = SfdbCli(options)
try:
sfdbcli.connect_to_database()
cursor = sfdbcli.execute_query(str(options.query))
print(cursor.json)
print(f'Rows affected: {cursor.rowcount}', file=sys.stderr)
finally:
sfdbcli.shutdown()


def main():
sfdbcli_options_parser = create_parser()
sfdbcli_options = sfdbcli_options_parser.parse_args(sys.argv[1:])
run_cli_with(sfdbcli_options)


if __name__ == '__main__':
main()
50 changes: 50 additions & 0 deletions client/python/optionparser.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import argparse
import os

from client.python import __version__
from sfdb_cli import LOG_LEVEL_MAP

SFDB_CLI_SERVER = u'SFDB_CLI_SERVER'


def create_parser():
args_parser = argparse.ArgumentParser(
prog=u'sfdb-cli',
description=u'SFDB CLI. v.{}'.format(__version__)
)

args_parser.add_argument(
u'-S', u'--server',
dest='server',
default=os.environ.get(SFDB_CLI_SERVER, None),
metavar='',
help=u'server:port instance to connect e.g. -S \'localhost:27910\''
)

args_parser.add_argument(
u'-Q', u'--query',
dest='query',
default=False,
required=True,
metavar='',
help=u'Executes a query outputting results to STDOUT and exits.'
)

args_parser.add_argument(
u'--log_level',
dest='log_level',
default='INFO',
metavar='',
choices=list(LOG_LEVEL_MAP.keys()),
help=u'Log Level.'
)

args_parser.add_argument(
u'--log_file',
dest='log_file',
default=None,
metavar='',
help='Path to file to save logs.'
)

return args_parser
63 changes: 63 additions & 0 deletions client/python/sfdb_cli.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import os
import sys
import logging

from driver.python.connection import connect

LOG_LEVEL_MAP = {
'ERROR': logging.ERROR,
'WARN': logging.WARN,
'INFO': logging.INFO,
'DEBUG': logging.DEBUG,
}


class SfdbCli(object):

default_prompt = r'\d'

def __init__(self, options):
self.init_logging(options.log_level, options.log_file)
self.logger = logging.getLogger("sfdbcli.SfdbCli")
self.server = options.server
self.query = options.query

def init_logging(self, log_level, log_file=None):
formatter = logging.Formatter(
'%(asctime)s (%(process)d/%(threadName)s) '
'%(name)s %(levelname)s - %(message)s')
root_logger = logging.getLogger('')
root_logger.setLevel(LOG_LEVEL_MAP[log_level])

console_handler = logging.StreamHandler()
console_handler.setLevel(LOG_LEVEL_MAP[log_level])
console_handler.setFormatter(formatter)

root_logger.addHandler(console_handler)
if log_file:
logging_path, log_filename = os.path.split(log_file)
if os.path.isdir(logging_path) and log_filename:
file_handler = logging.FileHandler(log_file, encoding='utf-8')
file_handler.setLevel(LOG_LEVEL_MAP[log_level])
file_handler.setFormatter(formatter)

root_logger.addHandler(file_handler)
root_logger.info(f'Initalized logging in: {log_file}')
else:
root_logger.error(f'Invalid logging path: {logging_path}')
root_logger.debug('Initialized sfdbcli logging.')

def connect_to_database(self):
self.logger.debug("Connecting to database...")
self.conn = connect('/'.join([self.server, 'Test']))

def shutdown(self):
self.logger.debug("Shutting down...")
self.conn = None

def execute_query(self, query_text):
"""Process a query string and outputs to STDOUT/file"""
self.logger.debug(f'Executing query: \"{query_text}\"')
cursor = self.conn.cursor()
cursor.execute(query_text)
return cursor
34 changes: 34 additions & 0 deletions client/python/test/sfdbcli_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import unittest

from driver.python.connection import connect
from test.pylib import TestSFDB
from driver.python.test.test_data import QUERIES


class CLITest(unittest.TestCase):
_db = None

@classmethod
def setUpClass(cls):
cls._db = TestSFDB()
# spin up additional two instances for proper SFDB cluster init
TestSFDB()
TestSFDB()
for i in TestSFDB.instances:
i.start()

@classmethod
def tearDownClass(cls):
TestSFDB.shutdown_all()

def test_query(self):
# test assumes 5 rows exist in database
conn = connect("localhost:27910/test")
cur = conn.cursor()
for q, r in QUERIES.items():
cur.execute(q)
self.assertEqual(r, cur.rowcount)


if __name__ == '__main__':
unittest.main()
84 changes: 84 additions & 0 deletions driver/python/BUILD
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
# bazel test //driver/python:all_tests --test_output=streamed --runs_per_test=2
ipr0 marked this conversation as resolved.
Show resolved Hide resolved

py_library(
name = "py_db_api",
srcs = [
"__init__.py",
"connection.py",
"cursor.py",
"exceptions.py",
"dbtypes.py",
],
srcs_version = "PY3",
visibility = ["//visibility:public"],
imports = ["."],
deps = [
"//server:grpc_sfdb_service_py_pb2",
"//server:grpc_sfdb_service_py_pb2_grpc",
"//sfdb:api_py_pb2",
"//sfdb:api_pb2_grpc",
],
)

py_library(
name = "test/py_test_lib",
srcs = [
"test/pylib.py",
"test/test_data.py",
],
srcs_version = "PY3",
visibility = ["//visibility:public"],
)

py_test(
name = "test/connection_test",
srcs = [
"test/connection_test.py",
],
srcs_version = "PY3",
visibility = ["//visibility:public"],
deps = [
":py_db_api",
":test/py_test_lib",
],
data = ["//sfdb:sfdb"],
)

py_test(
name = "test/cursor_test",
srcs = [
"test/cursor_test.py",
],
srcs_version = "PY3",
visibility = ["//visibility:public"],
deps = [
":py_db_api",
":test/py_test_lib",
],
data = ["//sfdb:sfdb"],
)

test_suite(
name = "all_tests",
)

# python toolchain definition,
# see https://github.com/bazelbuild/bazel/issues/7899
load("@bazel_tools//tools/python:toolchain.bzl", "py_runtime_pair")
py_runtime(
name = "py3_runtime",
interpreter_path = "/usr/bin/python3.7",
ipr0 marked this conversation as resolved.
Show resolved Hide resolved
python_version = "PY3",
)

py_runtime_pair(
name = "py_runtime_pair",
py3_runtime = ":py3_runtime",
)

toolchain(
name = "py_toolchain",
#target_compatible_with = [...], # optional platform constraints
toolchain = ":py_runtime_pair",
toolchain_type = "@bazel_tools//tools/python:toolchain_type",
)
Loading