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 3 Compatibility #108

Closed
wants to merge 6 commits into from
Closed
Show file tree
Hide file tree
Changes from all 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
13 changes: 13 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,25 @@ doc:
@echo Generated documentation: "file://"$$(readlink -f doc/build/html/index.html)
@echo

doc3:
python3 setup.py build_sphinx
@echo
@echo Generated documentation: "file://"$$(readlink -f doc/build/html/index.html)
@echo

test:
-find coverage/ -mindepth 1 -delete
python $$(which nosetests) $${TESTS}

test3:
-find coverage/ -mindepth 1 -delete
python3 $$(which nosetests3) $${TESTS}

clean:
find . -name '*.py[co]' -delete

dist: test
python setup.py sdist

dist3: test3
python3 setup.py sdist
6 changes: 0 additions & 6 deletions TODO.rst
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,3 @@ future, depending on time, demand, and technical possibilities.
* Port HappyBase over to the (still experimental) HBase Thrift2 API when it
becomes mainstream, and expose more of the underlying features nicely in the
HappyBase API.

* Python 3 support. This would be trivial for HappyBase, now that the
underlying Thrift library is Python 3 compatible. `Track`_ this
issue online.

.. _Track: https://github.com/wbolster/happybase/issues/40
11 changes: 7 additions & 4 deletions doc/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@
# All configuration values have a default; values that are commented out
# serve to show the default.

import sys, os
import imp
from os.path import dirname, join

# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
Expand Down Expand Up @@ -48,11 +49,13 @@
# built documents.
#
# The short X.Y version.
execfile(os.path.join(os.path.dirname(__file__), '../happybase/_version.py'))
version = __version__

version_path = join(dirname(__file__), '../happybase/_version.py')
with open(version_path) as fp:
version = imp.load_source("_version", version_path, fp).__version__

# The full version, including alpha/beta/rc tags.
release = __version__
release = version

# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
Expand Down
18 changes: 1 addition & 17 deletions happybase/Hbase.thrift
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ struct ColumnDescriptor {
6:i32 bloomFilterVectorSize = 0,
7:i32 bloomFilterNbHashes = 0,
8:bool blockCacheEnabled = 0,
9:i32 timeToLive = -1
9:i32 timeToLive = 0x7fffffff
}

/**
Expand Down Expand Up @@ -906,22 +906,6 @@ service Hbase {
1:ScannerID id
) throws (1:IOError io, 2:IllegalArgument ia)

/**
* Get the row just before the specified one.
*
* @return value for specified row/column
*/
list<TCell> getRowOrBefore(
/** name of table */
1:Text tableName,

/** row key */
2:Text row,

/** column name */
3:Text family
) throws (1:IOError io)

/**
* Get the regininfo for the specified row. It scans
* the metatable to find region's start and end keys.
Expand Down
18 changes: 10 additions & 8 deletions happybase/batch.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@

logger = logging.getLogger(__name__)


class Batch(object):
"""Batch mutation class.

Expand Down Expand Up @@ -45,17 +44,19 @@ def _reset_mutations(self):

def send(self):
"""Send the batch to the server."""
bms = [BatchMutation(row, m) for row, m in self._mutations.iteritems()]
bms = [BatchMutation(row.encode("utf-8"), m)
for row, m in self._mutations.items()]
if not bms:
return

logger.debug("Sending batch for '%s' (%d mutations on %d rows)",
self._table.name, self._mutation_count, len(bms))
name = self._table.name.encode("utf-8")
if self._timestamp is None:
self._table.connection.client.mutateRows(self._table.name, bms, {})
self._table.connection.client.mutateRows(name, bms, {})
else:
self._table.connection.client.mutateRowsTs(
self._table.name, bms, self._timestamp, {})
name, bms, self._timestamp, {})

self._reset_mutations()

Expand All @@ -77,10 +78,10 @@ def put(self, row, data, wal=None):
self._mutations[row].extend(
Mutation(
isDelete=False,
column=column,
value=value,
column=column.encode("utf-8"),
value=value.encode("utf-8"),
writeToWAL=wal)
for column, value in data.iteritems())
for column, value in data.items())

self._mutation_count += len(data)
if self._batch_size and self._mutation_count >= self._batch_size:
Expand All @@ -107,7 +108,8 @@ def delete(self, row, columns=None, wal=None):
wal = self._wal

self._mutations[row].extend(
Mutation(isDelete=True, column=column, writeToWAL=wal)
Mutation(
isDelete=True, column=column.encode("utf-8"), writeToWAL=wal)
for column in columns)

self._mutation_count += len(columns)
Expand Down
25 changes: 15 additions & 10 deletions happybase/connection.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
"""

import logging
import sys

from thrift.transport.TSocket import TSocket
from thrift.transport.TTransport import TBufferedTransport, TFramedTransport
Expand Down Expand Up @@ -33,6 +34,8 @@
DEFAULT_COMPAT = '0.96'
DEFAULT_PROTOCOL = 'binary'

if sys.version_info >= (3,):
basestring = str

class Connection(object):
"""Connection to an HBase Thrift server.
Expand Down Expand Up @@ -235,7 +238,7 @@ def tables(self):
:return: The table names
:rtype: List of strings
"""
names = self.client.getTableNames()
names = (n.decode("utf-8") for n in self.client.getTableNames())

# Filter using prefix, and strip prefix from names
if self.table_prefix is not None:
Expand Down Expand Up @@ -288,21 +291,23 @@ def create_table(self, name, families):
% name)

column_descriptors = []
for cf_name, options in families.iteritems():
for cf_name, options in families.items():
if options is None:
options = dict()

kwargs = dict()
for option_name, value in options.iteritems():
for option_name, value in options.items():
if isinstance(value, basestring):
value = value.encode("utf-8")
kwargs[pep8_to_camel_case(option_name)] = value

if not cf_name.endswith(':'):
cf_name += ':'
kwargs['name'] = cf_name
kwargs['name'] = cf_name.encode("utf-8")

column_descriptors.append(ColumnDescriptor(**kwargs))

self.client.createTable(name, column_descriptors)
self.client.createTable(name.encode("utf-8"), column_descriptors)

def delete_table(self, name, disable=False):
"""Delete the specified table.
Expand All @@ -321,23 +326,23 @@ def delete_table(self, name, disable=False):
self.disable_table(name)

name = self._table_name(name)
self.client.deleteTable(name)
self.client.deleteTable(name.encode("utf-8"))

def enable_table(self, name):
"""Enable the specified table.

:param str name: The table name
"""
name = self._table_name(name)
self.client.enableTable(name)
self.client.enableTable(name.encode("utf-8"))

def disable_table(self, name):
"""Disable the specified table.

:param str name: The table name
"""
name = self._table_name(name)
self.client.disableTable(name)
self.client.disableTable(name.encode("utf-8"))

def is_table_enabled(self, name):
"""Return whether the specified table is enabled.
Expand All @@ -348,15 +353,15 @@ def is_table_enabled(self, name):
:rtype: bool
"""
name = self._table_name(name)
return self.client.isTableEnabled(name)
return self.client.isTableEnabled(name.encode("utf-8"))

def compact_table(self, name, major=False):
"""Compact the specified table.

:param str name: The table name
:param bool major: Whether to perform a major compaction.
"""
name = self._table_name(name)
name = self._table_name(name).encode("utf-8")
if major:
self.client.majorCompact(name)
else:
Expand Down
Loading