http://git-wip-us.apache.org/repos/asf/phoenix/blob/43b437a5/python/phoenixdb/types.py ---------------------------------------------------------------------- diff --git a/python/phoenixdb/types.py b/python/phoenixdb/types.py new file mode 100644 index 0000000..f41355a --- /dev/null +++ b/python/phoenixdb/types.py @@ -0,0 +1,202 @@ +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import sys +import time +import datetime +from decimal import Decimal +from phoenixdb.avatica.proto import common_pb2 + +__all__ = [ + 'Date', 'Time', 'Timestamp', 'DateFromTicks', 'TimeFromTicks', 'TimestampFromTicks', + 'Binary', 'STRING', 'BINARY', 'NUMBER', 'DATETIME', 'ROWID', 'BOOLEAN', + 'JAVA_CLASSES', 'JAVA_CLASSES_MAP', 'TypeHelper', +] + + +def Date(year, month, day): + """Constructs an object holding a date value.""" + return datetime.date(year, month, day) + + +def Time(hour, minute, second): + """Constructs an object holding a time value.""" + return datetime.time(hour, minute, second) + + +def Timestamp(year, month, day, hour, minute, second): + """Constructs an object holding a datetime/timestamp value.""" + return datetime.datetime(year, month, day, hour, minute, second) + + +def DateFromTicks(ticks): + """Constructs an object holding a date value from the given UNIX timestamp.""" + return Date(*time.localtime(ticks)[:3]) + + +def TimeFromTicks(ticks): + """Constructs an object holding a time value from the given UNIX timestamp.""" + return Time(*time.localtime(ticks)[3:6]) + + +def TimestampFromTicks(ticks): + """Constructs an object holding a datetime/timestamp value from the given UNIX timestamp.""" + return Timestamp(*time.localtime(ticks)[:6]) + + +def Binary(value): + """Constructs an object capable of holding a binary (long) string value.""" + return bytes(value) + + +def time_from_java_sql_time(n): + dt = datetime.datetime(1970, 1, 1) + datetime.timedelta(milliseconds=n) + return dt.time() + + +def time_to_java_sql_time(t): + return ((t.hour * 60 + t.minute) * 60 + t.second) * 1000 + t.microsecond // 1000 + + +def date_from_java_sql_date(n): + return datetime.date(1970, 1, 1) + datetime.timedelta(days=n) + + +def date_to_java_sql_date(d): + if isinstance(d, datetime.datetime): + d = d.date() + td = d - datetime.date(1970, 1, 1) + return td.days + + +def datetime_from_java_sql_timestamp(n): + return datetime.datetime(1970, 1, 1) + datetime.timedelta(milliseconds=n) + + +def datetime_to_java_sql_timestamp(d): + td = d - datetime.datetime(1970, 1, 1) + return td.microseconds // 1000 + (td.seconds + td.days * 24 * 3600) * 1000 + + +class ColumnType(object): + + def __init__(self, eq_types): + self.eq_types = tuple(eq_types) + self.eq_types_set = set(eq_types) + + def __eq__(self, other): + return other in self.eq_types_set + + def __cmp__(self, other): + if other in self.eq_types_set: + return 0 + if other < self.eq_types: + return 1 + else: + return -1 + + +STRING = ColumnType(['VARCHAR', 'CHAR']) +"""Type object that can be used to describe string-based columns.""" + +BINARY = ColumnType(['BINARY', 'VARBINARY']) +"""Type object that can be used to describe (long) binary columns.""" + +NUMBER = ColumnType([ + 'INTEGER', 'UNSIGNED_INT', 'BIGINT', 'UNSIGNED_LONG', 'TINYINT', 'UNSIGNED_TINYINT', + 'SMALLINT', 'UNSIGNED_SMALLINT', 'FLOAT', 'UNSIGNED_FLOAT', 'DOUBLE', 'UNSIGNED_DOUBLE', 'DECIMAL' +]) +"""Type object that can be used to describe numeric columns.""" + +DATETIME = ColumnType(['TIME', 'DATE', 'TIMESTAMP', 'UNSIGNED_TIME', 'UNSIGNED_DATE', 'UNSIGNED_TIMESTAMP']) +"""Type object that can be used to describe date/time columns.""" + +ROWID = ColumnType([]) +"""Only implemented for DB API 2.0 compatibility, not used.""" + +BOOLEAN = ColumnType(['BOOLEAN']) +"""Type object that can be used to describe boolean columns. This is a phoenixdb-specific extension.""" + + +# XXX ARRAY + +if sys.version_info[0] < 3: + _long = long # noqa: F821 +else: + _long = int + +JAVA_CLASSES = { + 'bool_value': [ + ('java.lang.Boolean', common_pb2.BOOLEAN, None, None), + ], + 'string_value': [ + ('java.lang.Character', common_pb2.CHARACTER, None, None), + ('java.lang.String', common_pb2.STRING, None, None), + ('java.math.BigDecimal', common_pb2.BIG_DECIMAL, str, Decimal), + ], + 'number_value': [ + ('java.lang.Integer', common_pb2.INTEGER, None, int), + ('java.lang.Short', common_pb2.SHORT, None, int), + ('java.lang.Long', common_pb2.LONG, None, _long), + ('java.lang.Byte', common_pb2.BYTE, None, int), + ('java.sql.Time', common_pb2.JAVA_SQL_TIME, time_to_java_sql_time, time_from_java_sql_time), + ('java.sql.Date', common_pb2.JAVA_SQL_DATE, date_to_java_sql_date, date_from_java_sql_date), + ('java.sql.Timestamp', common_pb2.JAVA_SQL_TIMESTAMP, datetime_to_java_sql_timestamp, datetime_from_java_sql_timestamp), + ], + 'bytes_value': [ + ('[B', common_pb2.BYTE_STRING, Binary, None), + ], + 'double_value': [ + # if common_pb2.FLOAT is used, incorrect values are sent + ('java.lang.Float', common_pb2.DOUBLE, float, float), + ('java.lang.Double', common_pb2.DOUBLE, float, float), + ] +} +"""Groups of Java classes.""" + +JAVA_CLASSES_MAP = dict((v[0], (k, v[1], v[2], v[3])) for k in JAVA_CLASSES for v in JAVA_CLASSES[k]) +"""Flips the available types to allow for faster lookup by Java class. + +This mapping should be structured as: + { + 'java.math.BigDecimal': ('string_value', common_pb2.BIG_DECIMAL, str, Decimal),), + ... + '<java class>': (<field_name>, <Rep enum>, <mutate_to function>, <cast_from function>), + } +""" + + +class TypeHelper(object): + @staticmethod + def from_class(klass): + """Retrieves a Rep and functions to cast to/from based on the Java class. + + :param klass: + The string of the Java class for the column or parameter. + + :returns: tuple ``(field_name, rep, mutate_to, cast_from)`` + WHERE + ``field_name`` is the attribute in ``common_pb2.TypedValue`` + ``rep`` is the common_pb2.Rep enum + ``mutate_to`` is the function to cast values into Phoenix values, if any + ``cast_from`` is the function to cast from the Phoenix value to the Python value, if any + + :raises: + NotImplementedError + """ + if klass not in JAVA_CLASSES_MAP: + raise NotImplementedError('type {} is not supported'.format(klass)) + + return JAVA_CLASSES_MAP[klass]
http://git-wip-us.apache.org/repos/asf/phoenix/blob/43b437a5/python/requirements.txt ---------------------------------------------------------------------- diff --git a/python/requirements.txt b/python/requirements.txt new file mode 100644 index 0000000..e188ff9 --- /dev/null +++ b/python/requirements.txt @@ -0,0 +1,20 @@ +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +-e git+https://bitbucket.org/lalinsky/python-sqlline.git#egg=sqlline +nose +protobuf>=3.0.0 +sphinx +flake8 http://git-wip-us.apache.org/repos/asf/phoenix/blob/43b437a5/python/setup.cfg ---------------------------------------------------------------------- diff --git a/python/setup.cfg b/python/setup.cfg new file mode 100644 index 0000000..ebc28c2 --- /dev/null +++ b/python/setup.cfg @@ -0,0 +1,34 @@ +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +[nosetests] +verbosity=2 +testmatch=^test_.+ +where=phoenixdb/tests + +[build_sphinx] +source-dir = doc +build-dir = doc/build +all_files = 1 + +[upload_sphinx] +upload-dir = doc/build/html + +[flake8] +max-line-length = 140 +exclude = + e,e3,env,venv,doc,build,dist,.tox,.idea, + ./phoenixdb/tests/dbapi20.py, + ./phoenixdb/avatica/proto/*_pb2.py http://git-wip-us.apache.org/repos/asf/phoenix/blob/43b437a5/python/setup.py ---------------------------------------------------------------------- diff --git a/python/setup.py b/python/setup.py new file mode 100644 index 0000000..8dd3379 --- /dev/null +++ b/python/setup.py @@ -0,0 +1,64 @@ +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from setuptools import setup, find_packages + +cmdclass = {} + +try: + from sphinx.setup_command import BuildDoc + cmdclass['build_sphinx'] = BuildDoc +except ImportError: + pass + + +def readme(): + with open('README.rst') as f: + return f.read() + + +version = "0.7" + +setup( + name="phoenixdb", + version=version, + description="Phoenix database adapter for Python", + long_description=readme(), + author="Lukas Lalinsky", + author_email="lu...@oxygene.sk", + url="https://bitbucket.org/lalinsky/python-phoenixdb", + license="Apache 2", + packages=find_packages(), + include_package_data=True, + cmdclass=cmdclass, + command_options={ + 'build_sphinx': { + 'version': ('setup.py', version), + 'release': ('setup.py', version), + }, + }, + classifiers=[ + 'Programming Language :: Python', + 'Programming Language :: Python :: 2', + 'Programming Language :: Python :: 2.7', + 'Programming Language :: Python :: 3', + 'Programming Language :: Python :: 3.4', + 'Programming Language :: Python :: 3.5', + 'Programming Language :: Python :: 3.6', + ], + install_requires=[ + 'protobuf>=3.0.0', + ] +) http://git-wip-us.apache.org/repos/asf/phoenix/blob/43b437a5/python/tox.ini ---------------------------------------------------------------------- diff --git a/python/tox.ini b/python/tox.ini new file mode 100644 index 0000000..908696a --- /dev/null +++ b/python/tox.ini @@ -0,0 +1,24 @@ +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +[tox] +envlist = py27,py35,py36 + +[testenv] +passenv = PHOENIXDB_TEST_DB_URL +commands = + flake8 + nosetests -v +deps = -rrequirements.txt