Hello community,
here is the log from the commit of package python-happybase for
openSUSE:Factory checked in at 2019-09-27 14:45:54
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-happybase (Old)
and /work/SRC/openSUSE:Factory/.python-happybase.new.2352 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-happybase"
Fri Sep 27 14:45:54 2019 rev:14 rq:730343 version:1.2.0
Changes:
--------
--- /work/SRC/openSUSE:Factory/python-happybase/python-happybase.changes
2018-12-24 11:38:00.465632305 +0100
+++
/work/SRC/openSUSE:Factory/.python-happybase.new.2352/python-happybase.changes
2019-09-27 14:45:57.253153911 +0200
@@ -1,0 +2,6 @@
+Thu Sep 12 09:02:50 UTC 2019 - Tomáš Chvátal <[email protected]>
+
+- Update to 1.2.0:
+ * Switch from thriftpy to its successor thriftpy2, which supports Python 3.7.
+
+-------------------------------------------------------------------
Old:
----
happybase-1.1.0.tar.gz
New:
----
1.2.0.tar.gz
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Other differences:
------------------
++++++ python-happybase.spec ++++++
--- /var/tmp/diff_new_pack.x2z9ev/_old 2019-09-27 14:45:57.813152454 +0200
+++ /var/tmp/diff_new_pack.x2z9ev/_new 2019-09-27 14:45:57.821152434 +0200
@@ -1,7 +1,7 @@
#
# spec file for package python-happybase
#
-# Copyright (c) 2018 SUSE LINUX GmbH, Nuernberg, Germany.
+# Copyright (c) 2019 SUSE LINUX GmbH, Nuernberg, Germany.
#
# All modifications and additions to the file contributed by third parties
# remain the property of their copyright owners, unless otherwise agreed
@@ -18,19 +18,21 @@
%{?!python_module:%define python_module() python-%{**} python3-%{**}}
Name: python-happybase
-Version: 1.1.0
+Version: 1.2.0
Release: 0
Summary: A Python library to interact with Apache HBase
License: MIT
Group: Development/Languages/Python
URL: https://github.com/wbolster/happybase
-Source:
https://files.pythonhosted.org/packages/source/h/happybase/happybase-%{version}.tar.gz
+Source: https://github.com/wbolster/happybase/archive/%{version}.tar.gz
+BuildRequires: %{python_module nose}
BuildRequires: %{python_module setuptools}
-BuildRequires: %{python_module thriftpy}
+BuildRequires: %{python_module thriftpy2}
+BuildRequires: fdupes
BuildRequires: python-rpm-macros
BuildRequires: python3-Sphinx
Requires: python-six
-Requires: python-thriftpy >= 0.3.8
+Requires: python-thriftpy2 >= 0.4
BuildArch: noarch
%python_subpackages
@@ -56,10 +58,12 @@
%install
%python_install
-rm docs/build/html/.doctrees/environment.pickle
+%python_expand %fdupes %{buildroot}%{$python_sitelib}
+rm -r docs/build/html/.[a-z]*
%check
-%python_exec setup.py test
+# the api tests need running thrift server
+%python_expand nosetests-%{$python_bin_suffix} -v tests/test_util.py
%files %{python_files}
%license LICENSE.rst
++++++ happybase-1.1.0.tar.gz -> 1.2.0.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/happybase-1.1.0/.gitignore
new/happybase-1.2.0/.gitignore
--- old/happybase-1.1.0/.gitignore 1970-01-01 01:00:00.000000000 +0100
+++ new/happybase-1.2.0/.gitignore 2019-05-14 16:16:06.000000000 +0200
@@ -0,0 +1,8 @@
+*.py[co]
+*.egg-info/
+.coverage
+.tox/
+build/
+coverage/
+dist/
+doc/build/
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/happybase-1.1.0/NEWS.rst new/happybase-1.2.0/NEWS.rst
--- old/happybase-1.1.0/NEWS.rst 2017-04-03 23:08:55.000000000 +0200
+++ new/happybase-1.2.0/NEWS.rst 2019-05-14 16:16:06.000000000 +0200
@@ -4,6 +4,17 @@
.. py:currentmodule:: happybase
+HappyBase 1.2.0
+---------------
+
+Release date: 2019-05-14
+
+* Switch from ``thriftpy`` to its successor ``thriftpy2``,
+ which supports Python 3.7.
+ (`issue #221 <https://github.com/wbolster/happybase/issues/221>`_,
+ `pr 222 <https://github.com/wbolster/happybase/pull/222>`_,
+
+
HappyBase 1.1.0
---------------
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/happybase-1.1.0/PKG-INFO new/happybase-1.2.0/PKG-INFO
--- old/happybase-1.1.0/PKG-INFO 2017-04-03 23:12:57.000000000 +0200
+++ new/happybase-1.2.0/PKG-INFO 1970-01-01 01:00:00.000000000 +0100
@@ -1,38 +0,0 @@
-Metadata-Version: 1.1
-Name: happybase
-Version: 1.1.0
-Summary: A developer-friendly Python library to interact with Apache HBase
-Home-page: https://github.com/wbolster/happybase
-Author: Wouter Bolsterlee
-Author-email: [email protected]
-License: MIT
-Description: HappyBase
- =========
-
- **HappyBase** is a developer-friendly Python_ library to interact with
Apache
- HBase_.
-
- * `Documentation <https://happybase.readthedocs.io/>`_ (Read the Docs)
- * `Downloads <http://pypi.python.org/pypi/happybase/>`_ (PyPI)
- * `Source code <https://github.com/wbolster/happybase>`_ (Github)
-
- .. _Python: http://python.org/
- .. _HBase: http://hbase.apache.org/
-
- .. If you're reading this from the README.rst file in a source tree,
- you can generate the HTML documentation by running "make doc" and
browsing
- to doc/build/html/index.html to see the result.
-
-
- .. image::
https://d2weczhvl823v0.cloudfront.net/wbolster/happybase/trend.png
- :alt: Bitdeli badge
- :target: https://bitdeli.com/free
-
-Platform: UNKNOWN
-Classifier: Development Status :: 4 - Beta
-Classifier: Intended Audience :: Developers
-Classifier: License :: OSI Approved :: MIT License
-Classifier: Programming Language :: Python :: 2
-Classifier: Programming Language :: Python :: 3
-Classifier: Topic :: Database
-Classifier: Topic :: Software Development :: Libraries :: Python Modules
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/happybase-1.1.0/README.rst
new/happybase-1.2.0/README.rst
--- old/happybase-1.1.0/README.rst 2016-07-27 19:16:20.000000000 +0200
+++ new/happybase-1.2.0/README.rst 2019-05-14 16:16:06.000000000 +0200
@@ -14,8 +14,3 @@
.. If you're reading this from the README.rst file in a source tree,
you can generate the HTML documentation by running "make doc" and browsing
to doc/build/html/index.html to see the result.
-
-
-.. image:: https://d2weczhvl823v0.cloudfront.net/wbolster/happybase/trend.png
- :alt: Bitdeli badge
- :target: https://bitdeli.com/free
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/happybase-1.1.0/doc/user.rst
new/happybase-1.2.0/doc/user.rst
--- old/happybase-1.1.0/doc/user.rst 2016-08-01 22:27:35.000000000 +0200
+++ new/happybase-1.2.0/doc/user.rst 2019-05-14 16:16:06.000000000 +0200
@@ -435,7 +435,7 @@
with table.batch(batch_size=1000) as b:
for i in range(1200):
# this put() will result in two mutations (two cells)
- b.put(b'row-%04d'.format(i), {
+ b.put(b'row-%04d' % i, {
b'cf1:col1': b'v1',
b'cf1:col2': b'v2',
})
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/happybase-1.1.0/happybase/__init__.py
new/happybase-1.2.0/happybase/__init__.py
--- old/happybase-1.1.0/happybase/__init__.py 2016-08-01 22:43:10.000000000
+0200
+++ new/happybase-1.2.0/happybase/__init__.py 2019-05-14 16:16:06.000000000
+0200
@@ -4,7 +4,7 @@
"""
import pkg_resources as _pkg_resources
-import thriftpy as _thriftpy
+import thriftpy2 as _thriftpy
_thriftpy.load(
_pkg_resources.resource_filename('happybase', 'Hbase.thrift'),
'Hbase_thrift')
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/happybase-1.1.0/happybase/_version.py
new/happybase-1.2.0/happybase/_version.py
--- old/happybase-1.1.0/happybase/_version.py 2017-04-03 23:01:23.000000000
+0200
+++ new/happybase-1.2.0/happybase/_version.py 2019-05-14 16:16:06.000000000
+0200
@@ -5,4 +5,4 @@
setup.py.
"""
-__version__ = '1.1.0'
+__version__ = '1.2.0'
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/happybase-1.1.0/happybase/connection.py
new/happybase-1.2.0/happybase/connection.py
--- old/happybase-1.1.0/happybase/connection.py 2017-04-03 23:01:23.000000000
+0200
+++ new/happybase-1.2.0/happybase/connection.py 2019-05-14 16:16:06.000000000
+0200
@@ -7,9 +7,9 @@
import logging
import six
-from thriftpy.thrift import TClient
-from thriftpy.transport import TBufferedTransport, TFramedTransport, TSocket
-from thriftpy.protocol import TBinaryProtocol, TCompactProtocol
+from thriftpy2.thrift import TClient
+from thriftpy2.transport import TBufferedTransport, TFramedTransport, TSocket
+from thriftpy2.protocol import TBinaryProtocol, TCompactProtocol
from Hbase_thrift import Hbase, ColumnDescriptor
@@ -53,7 +53,7 @@
The optional `table_prefix` and `table_prefix_separator` arguments
specify a prefix and a separator string to be prepended to all table
names, e.g. when :py:meth:`Connection.table` is invoked. For
- example, if `table_prefix` is ``myproject``, all tables tables will
+ example, if `table_prefix` is ``myproject``, all tables will
have names like ``myproject_XYZ``.
The optional `compat` argument sets the compatibility level for
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/happybase-1.1.0/happybase/pool.py
new/happybase-1.2.0/happybase/pool.py
--- old/happybase-1.1.0/happybase/pool.py 2016-08-01 22:27:35.000000000
+0200
+++ new/happybase-1.2.0/happybase/pool.py 2019-05-14 16:16:06.000000000
+0200
@@ -9,7 +9,7 @@
from six.moves import queue, range
-from thriftpy.thrift import TException
+from thriftpy2.thrift import TException
from .connection import Connection
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/happybase-1.1.0/happybase/table.py
new/happybase-1.2.0/happybase/table.py
--- old/happybase-1.1.0/happybase/table.py 2017-04-03 23:01:23.000000000
+0200
+++ new/happybase-1.2.0/happybase/table.py 2019-05-14 16:16:06.000000000
+0200
@@ -285,7 +285,7 @@
* The `reverse` argument is only available when using HBase 0.98
(or up).
- .. versionadded:: TODO
+ .. versionadded:: 1.1.0
`reverse` argument
.. versionadded:: 0.8
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/happybase-1.1.0/happybase.egg-info/PKG-INFO
new/happybase-1.2.0/happybase.egg-info/PKG-INFO
--- old/happybase-1.1.0/happybase.egg-info/PKG-INFO 2017-04-03
23:12:56.000000000 +0200
+++ new/happybase-1.2.0/happybase.egg-info/PKG-INFO 1970-01-01
01:00:00.000000000 +0100
@@ -1,38 +0,0 @@
-Metadata-Version: 1.1
-Name: happybase
-Version: 1.1.0
-Summary: A developer-friendly Python library to interact with Apache HBase
-Home-page: https://github.com/wbolster/happybase
-Author: Wouter Bolsterlee
-Author-email: [email protected]
-License: MIT
-Description: HappyBase
- =========
-
- **HappyBase** is a developer-friendly Python_ library to interact with
Apache
- HBase_.
-
- * `Documentation <https://happybase.readthedocs.io/>`_ (Read the Docs)
- * `Downloads <http://pypi.python.org/pypi/happybase/>`_ (PyPI)
- * `Source code <https://github.com/wbolster/happybase>`_ (Github)
-
- .. _Python: http://python.org/
- .. _HBase: http://hbase.apache.org/
-
- .. If you're reading this from the README.rst file in a source tree,
- you can generate the HTML documentation by running "make doc" and
browsing
- to doc/build/html/index.html to see the result.
-
-
- .. image::
https://d2weczhvl823v0.cloudfront.net/wbolster/happybase/trend.png
- :alt: Bitdeli badge
- :target: https://bitdeli.com/free
-
-Platform: UNKNOWN
-Classifier: Development Status :: 4 - Beta
-Classifier: Intended Audience :: Developers
-Classifier: License :: OSI Approved :: MIT License
-Classifier: Programming Language :: Python :: 2
-Classifier: Programming Language :: Python :: 3
-Classifier: Topic :: Database
-Classifier: Topic :: Software Development :: Libraries :: Python Modules
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/happybase-1.1.0/happybase.egg-info/SOURCES.txt
new/happybase-1.2.0/happybase.egg-info/SOURCES.txt
--- old/happybase-1.1.0/happybase.egg-info/SOURCES.txt 2017-04-03
23:12:57.000000000 +0200
+++ new/happybase-1.2.0/happybase.egg-info/SOURCES.txt 1970-01-01
01:00:00.000000000 +0100
@@ -1,32 +0,0 @@
-LICENSE.rst
-MANIFEST.in
-Makefile
-NEWS.rst
-README.rst
-TODO.rst
-requirements.txt
-setup.cfg
-setup.py
-doc/api.rst
-doc/conf.py
-doc/development.rst
-doc/faq.rst
-doc/index.rst
-doc/installation.rst
-doc/license.rst
-doc/news.rst
-doc/todo.rst
-doc/user.rst
-happybase/Hbase.thrift
-happybase/__init__.py
-happybase/_version.py
-happybase/batch.py
-happybase/connection.py
-happybase/pool.py
-happybase/table.py
-happybase/util.py
-happybase.egg-info/PKG-INFO
-happybase.egg-info/SOURCES.txt
-happybase.egg-info/dependency_links.txt
-happybase.egg-info/requires.txt
-happybase.egg-info/top_level.txt
\ No newline at end of file
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/happybase-1.1.0/happybase.egg-info/dependency_links.txt
new/happybase-1.2.0/happybase.egg-info/dependency_links.txt
--- old/happybase-1.1.0/happybase.egg-info/dependency_links.txt 2017-04-03
23:12:56.000000000 +0200
+++ new/happybase-1.2.0/happybase.egg-info/dependency_links.txt 1970-01-01
01:00:00.000000000 +0100
@@ -1 +0,0 @@
-
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/happybase-1.1.0/happybase.egg-info/requires.txt
new/happybase-1.2.0/happybase.egg-info/requires.txt
--- old/happybase-1.1.0/happybase.egg-info/requires.txt 2017-04-03
23:12:56.000000000 +0200
+++ new/happybase-1.2.0/happybase.egg-info/requires.txt 1970-01-01
01:00:00.000000000 +0100
@@ -1,2 +0,0 @@
-six
-thriftpy>=0.3.8
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/happybase-1.1.0/happybase.egg-info/top_level.txt
new/happybase-1.2.0/happybase.egg-info/top_level.txt
--- old/happybase-1.1.0/happybase.egg-info/top_level.txt 2017-04-03
23:12:56.000000000 +0200
+++ new/happybase-1.2.0/happybase.egg-info/top_level.txt 1970-01-01
01:00:00.000000000 +0100
@@ -1 +0,0 @@
-happybase
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/happybase-1.1.0/requirements.txt
new/happybase-1.2.0/requirements.txt
--- old/happybase-1.1.0/requirements.txt 2016-08-01 22:27:35.000000000
+0200
+++ new/happybase-1.2.0/requirements.txt 2019-05-14 16:16:06.000000000
+0200
@@ -1,2 +1,2 @@
six
-thriftpy>=0.3.8
+thriftpy2>=0.4
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/happybase-1.1.0/setup.cfg
new/happybase-1.2.0/setup.cfg
--- old/happybase-1.1.0/setup.cfg 2017-04-03 23:12:57.000000000 +0200
+++ new/happybase-1.2.0/setup.cfg 2019-05-14 16:16:06.000000000 +0200
@@ -3,7 +3,7 @@
verbosity = 2
with-coverage = 1
cover-erase = 1
-cover-package =
happybase.connection,happybase.table,happybase.batch,happybase.pool,happybase.util,tests
+cover-package=happybase.connection,happybase.table,happybase.batch,happybase.pool,happybase.util,tests
cover-tests = 1
cover-html = 1
cover-html-dir = coverage/
@@ -13,10 +13,4 @@
build-dir = doc/build/
[wheel]
-universal = 1
-
-[egg_info]
-tag_build =
-tag_date = 0
-tag_svn_revision = 0
-
+universal = 1
\ No newline at end of file
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/happybase-1.1.0/setup.py new/happybase-1.2.0/setup.py
--- old/happybase-1.1.0/setup.py 2016-08-01 22:27:35.000000000 +0200
+++ new/happybase-1.2.0/setup.py 2019-05-14 16:16:06.000000000 +0200
@@ -34,7 +34,7 @@
include_package_data=True,
license="MIT",
classifiers=(
- "Development Status :: 4 - Beta",
+ "Development Status :: 5 - Production/Stable",
"Intended Audience :: Developers",
"License :: OSI Approved :: MIT License",
"Programming Language :: Python :: 2",
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/happybase-1.1.0/test-requirements.txt
new/happybase-1.2.0/test-requirements.txt
--- old/happybase-1.1.0/test-requirements.txt 1970-01-01 01:00:00.000000000
+0100
+++ new/happybase-1.2.0/test-requirements.txt 2019-05-14 16:16:06.000000000
+0200
@@ -0,0 +1,4 @@
+-r requirements.txt
+coverage
+nose
+sphinx
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/happybase-1.1.0/tests/test_api.py
new/happybase-1.2.0/tests/test_api.py
--- old/happybase-1.1.0/tests/test_api.py 1970-01-01 01:00:00.000000000
+0100
+++ new/happybase-1.2.0/tests/test_api.py 2019-05-14 16:16:06.000000000
+0200
@@ -0,0 +1,606 @@
+"""
+HappyBase tests.
+"""
+
+import collections
+import os
+import random
+import threading
+
+import six
+from six.moves import range
+
+from nose.tools import (
+ assert_dict_equal,
+ assert_equal,
+ assert_false,
+ assert_in,
+ assert_is_instance,
+ assert_is_not_none,
+ assert_list_equal,
+ assert_not_in,
+ assert_raises,
+ assert_true,
+)
+
+from happybase import Connection, ConnectionPool, NoConnectionsAvailable
+
+HAPPYBASE_HOST = os.environ.get('HAPPYBASE_HOST')
+HAPPYBASE_PORT = os.environ.get('HAPPYBASE_PORT')
+HAPPYBASE_COMPAT = os.environ.get('HAPPYBASE_COMPAT', '0.98')
+HAPPYBASE_TRANSPORT = os.environ.get('HAPPYBASE_TRANSPORT', 'buffered')
+KEEP_TABLE = ('HAPPYBASE_NO_CLEANUP' in os.environ)
+
+TABLE_PREFIX = b'happybase_tests_tmp'
+TEST_TABLE_NAME = b'test1'
+
+connection_kwargs = dict(
+ host=HAPPYBASE_HOST,
+ port=HAPPYBASE_PORT,
+ table_prefix=TABLE_PREFIX,
+ compat=HAPPYBASE_COMPAT,
+ transport=HAPPYBASE_TRANSPORT,
+)
+
+
+# Yuck, globals
+connection = table = None
+
+
+def maybe_delete_table():
+ if KEEP_TABLE:
+ return
+
+ if TEST_TABLE_NAME in connection.tables():
+ print("Test table already exists; removing it...")
+ connection.delete_table(TEST_TABLE_NAME, disable=True)
+
+
+def setup_module():
+ global connection, table
+ connection = Connection(**connection_kwargs)
+
+ assert_is_not_none(connection)
+
+ maybe_delete_table()
+ cfs = {
+ 'cf1': {},
+ 'cf2': None,
+ 'cf3': {'max_versions': 1},
+ }
+ connection.create_table(TEST_TABLE_NAME, families=cfs)
+
+ table = connection.table(TEST_TABLE_NAME)
+ assert_is_not_none(table)
+
+
+def teardown_module():
+ if not KEEP_TABLE:
+ connection.delete_table(TEST_TABLE_NAME, disable=True)
+ connection.close()
+
+
+def test_connection_compat():
+ with assert_raises(ValueError):
+ Connection(compat='0.1.invalid.version')
+
+
+def test_timeout_arg():
+ Connection(
+ timeout=5000,
+ autoconnect=False)
+
+
+def test_enabling():
+ assert_true(connection.is_table_enabled(TEST_TABLE_NAME))
+ connection.disable_table(TEST_TABLE_NAME)
+ assert_false(connection.is_table_enabled(TEST_TABLE_NAME))
+ connection.enable_table(TEST_TABLE_NAME)
+ assert_true(connection.is_table_enabled(TEST_TABLE_NAME))
+
+
+def test_compaction():
+ connection.compact_table(TEST_TABLE_NAME)
+ connection.compact_table(TEST_TABLE_NAME, major=True)
+
+
+def test_prefix():
+ assert_equal(TABLE_PREFIX + b'_', connection._table_name(''))
+ assert_equal(TABLE_PREFIX + b'_foo', connection._table_name('foo'))
+
+ assert_equal(connection.table('foobar').name, TABLE_PREFIX + b'_foobar')
+ assert_equal(connection.table('foobar', use_prefix=False).name, b'foobar')
+
+ c = Connection(autoconnect=False)
+ assert_equal(b'foo', c._table_name('foo'))
+
+ with assert_raises(TypeError):
+ Connection(autoconnect=False, table_prefix=123)
+
+ with assert_raises(TypeError):
+ Connection(autoconnect=False, table_prefix_separator=2.1)
+
+
+def test_stringify():
+ str(connection)
+ repr(connection)
+ str(table)
+ repr(table)
+
+
+def test_table_listing():
+ names = connection.tables()
+ assert_is_instance(names, list)
+ assert_in(TEST_TABLE_NAME, names)
+
+
+def test_table_regions():
+ regions = table.regions()
+ assert_is_instance(regions, list)
+
+
+def test_invalid_table_create():
+ with assert_raises(ValueError):
+ connection.create_table('sometable', families={})
+ with assert_raises(TypeError):
+ connection.create_table('sometable', families=0)
+ with assert_raises(TypeError):
+ connection.create_table('sometable', families=[])
+
+
+def test_families():
+ families = table.families()
+ for name, fdesc in six.iteritems(families):
+ assert_is_instance(name, bytes)
+ assert_is_instance(fdesc, dict)
+ assert_in('name', fdesc)
+ assert_is_instance(fdesc['name'], six.binary_type)
+ assert_in('max_versions', fdesc)
+
+
+def test_put():
+ table.put(b'r1', {b'cf1:c1': b'v1', b'cf1:c2': b'v2', b'cf2:c3': b'v3'})
+ table.put(b'r1', {b'cf1:c4': b'v2'}, timestamp=2345678)
+ table.put(b'r1', {b'cf1:c4': b'v2'}, timestamp=1369168852994)
+
+
+def test_atomic_counters():
+ row = b'row-with-counter'
+ column = 'cf1:counter'
+
+ assert_equal(0, table.counter_get(row, column))
+
+ assert_equal(10, table.counter_inc(row, column, 10))
+ assert_equal(10, table.counter_get(row, column))
+
+ table.counter_set(row, column, 0)
+ assert_equal(1, table.counter_inc(row, column))
+ assert_equal(4, table.counter_inc(row, column, 3))
+ assert_equal(4, table.counter_get(row, column))
+
+ table.counter_set(row, column, 3)
+ assert_equal(3, table.counter_get(row, column))
+ assert_equal(8, table.counter_inc(row, column, 5))
+ assert_equal(6, table.counter_inc(row, column, -2))
+ assert_equal(5, table.counter_dec(row, column))
+ assert_equal(3, table.counter_dec(row, column, 2))
+ assert_equal(10, table.counter_dec(row, column, -7))
+
+
+def test_batch():
+ with assert_raises(TypeError):
+ table.batch(timestamp='invalid')
+
+ b = table.batch()
+ b.put(b'row1', {b'cf1:col1': b'value1',
+ b'cf1:col2': b'value2'})
+ b.put(b'row2', {b'cf1:col1': b'value1',
+ b'cf1:col2': b'value2',
+ b'cf1:col3': b'value3'})
+ b.delete(b'row1', [b'cf1:col4'])
+ b.delete(b'another-row')
+ b.send()
+
+ b = table.batch(timestamp=1234567)
+ b.put(b'row1', {b'cf1:col5': b'value5'})
+ b.send()
+
+ with assert_raises(ValueError):
+ b = table.batch(batch_size=0)
+
+ with assert_raises(TypeError):
+ b = table.batch(transaction=True, batch_size=10)
+
+
+def test_batch_context_managers():
+ with table.batch() as b:
+ b.put(b'row4', {b'cf1:col3': b'value3'})
+ b.put(b'row5', {b'cf1:col4': b'value4'})
+ b.put(b'row', {b'cf1:col1': b'value1'})
+ b.delete(b'row', [b'cf1:col4'])
+ b.put(b'row', {b'cf1:col2': b'value2'})
+
+ with table.batch(timestamp=87654321) as b:
+ b.put(b'row', {b'cf1:c3': b'somevalue',
+ b'cf1:c5': b'anothervalue'})
+ b.delete(b'row', [b'cf1:c3'])
+
+ with assert_raises(ValueError):
+ with table.batch(transaction=True) as b:
+ b.put(b'fooz', {b'cf1:bar': b'baz'})
+ raise ValueError
+ assert_dict_equal({}, table.row(b'fooz', [b'cf1:bar']))
+
+ with assert_raises(ValueError):
+ with table.batch(transaction=False) as b:
+ b.put(b'fooz', {b'cf1:bar': b'baz'})
+ raise ValueError
+ assert_dict_equal({b'cf1:bar': b'baz'}, table.row(b'fooz', [b'cf1:bar']))
+
+ with table.batch(batch_size=5) as b:
+ for i in range(10):
+ b.put(('row-batch1-%03d' % i).encode('ascii'),
+ {b'cf1:': str(i).encode('ascii')})
+
+ with table.batch(batch_size=20) as b:
+ for i in range(95):
+ b.put(('row-batch2-%03d' % i).encode('ascii'),
+ {b'cf1:': str(i).encode('ascii')})
+ assert_equal(95, len(list(table.scan(row_prefix=b'row-batch2-'))))
+
+ with table.batch(batch_size=20) as b:
+ for i in range(95):
+ b.delete(('row-batch2-%03d' % i).encode('ascii'))
+ assert_equal(0, len(list(table.scan(row_prefix=b'row-batch2-'))))
+
+
+def test_row():
+ row = table.row
+ put = table.put
+ row_key = b'row-test'
+
+ with assert_raises(TypeError):
+ row(row_key, 123)
+
+ with assert_raises(TypeError):
+ row(row_key, timestamp='invalid')
+
+ put(row_key, {b'cf1:col1': b'v1old'}, timestamp=1234)
+ put(row_key, {b'cf1:col1': b'v1new'}, timestamp=3456)
+ put(row_key, {b'cf1:col2': b'v2',
+ b'cf2:col1': b'v3'})
+ put(row_key, {b'cf2:col2': b'v4'}, timestamp=1234)
+
+ exp = {b'cf1:col1': b'v1new',
+ b'cf1:col2': b'v2',
+ b'cf2:col1': b'v3',
+ b'cf2:col2': b'v4'}
+ assert_dict_equal(exp, row(row_key))
+
+ exp = {b'cf1:col1': b'v1new',
+ b'cf1:col2': b'v2'}
+ assert_dict_equal(exp, row(row_key, [b'cf1']))
+
+ exp = {b'cf1:col1': b'v1new',
+ b'cf2:col2': b'v4'}
+ assert_dict_equal(exp, row(row_key, [b'cf1:col1', b'cf2:col2']))
+
+ exp = {b'cf1:col1': b'v1old',
+ b'cf2:col2': b'v4'}
+ assert_dict_equal(exp, row(row_key, timestamp=2345))
+
+ assert_dict_equal({}, row(row_key, timestamp=123))
+
+ res = row(row_key, include_timestamp=True)
+ assert_equal(len(res), 4)
+ assert_equal(b'v1new', res[b'cf1:col1'][0])
+ assert_is_instance(res[b'cf1:col1'][1], int)
+
+
+def test_rows():
+ row_keys = [b'rows-row1', b'rows-row2', b'rows-row3']
+ data_old = {b'cf1:col1': b'v1old', b'cf1:col2': b'v2old'}
+ data_new = {b'cf1:col1': b'v1new', b'cf1:col2': b'v2new'}
+
+ with assert_raises(TypeError):
+ table.rows(row_keys, object())
+
+ with assert_raises(TypeError):
+ table.rows(row_keys, timestamp='invalid')
+
+ for row_key in row_keys:
+ table.put(row_key, data_old, timestamp=4000)
+
+ for row_key in row_keys:
+ table.put(row_key, data_new)
+
+ assert_dict_equal({}, table.rows([]))
+
+ rows = dict(table.rows(row_keys))
+ for row_key in row_keys:
+ assert_in(row_key, rows)
+ assert_dict_equal(data_new, rows[row_key])
+
+ rows = dict(table.rows(row_keys, timestamp=5000))
+ for row_key in row_keys:
+ assert_in(row_key, rows)
+ assert_dict_equal(data_old, rows[row_key])
+
+
+def test_cells():
+ row_key = b'cell-test'
+ col = b'cf1:col1'
+
+ table.put(row_key, {col: b'old'}, timestamp=1234)
+ table.put(row_key, {col: b'new'})
+
+ with assert_raises(TypeError):
+ table.cells(row_key, col, versions='invalid')
+
+ with assert_raises(TypeError):
+ table.cells(row_key, col, versions=3, timestamp='invalid')
+
+ with assert_raises(ValueError):
+ table.cells(row_key, col, versions=0)
+
+ results = table.cells(row_key, col, versions=1)
+ assert_equal(len(results), 1)
+ assert_equal(b'new', results[0])
+
+ results = table.cells(row_key, col)
+ assert_equal(len(results), 2)
+ assert_equal(b'new', results[0])
+ assert_equal(b'old', results[1])
+
+ results = table.cells(row_key, col, timestamp=2345, include_timestamp=True)
+ assert_equal(len(results), 1)
+ assert_equal(b'old', results[0][0])
+ assert_equal(1234, results[0][1])
+
+
+def test_scan():
+ with assert_raises(TypeError):
+ list(table.scan(row_prefix='foobar', row_start='xyz'))
+
+ if connection.compat == '0.90':
+ with assert_raises(NotImplementedError):
+ list(table.scan(filter='foo'))
+
+ with assert_raises(ValueError):
+ list(table.scan(limit=0))
+
+ with table.batch() as b:
+ for i in range(2000):
+ b.put(('row-scan-a%05d' % i).encode('ascii'),
+ {b'cf1:col1': b'v1',
+ b'cf1:col2': b'v2',
+ b'cf2:col1': b'v1',
+ b'cf2:col2': b'v2'})
+ b.put(('row-scan-b%05d' % i).encode('ascii'),
+ {b'cf1:col1': b'v1',
+ b'cf1:col2': b'v2'})
+
+ def calc_len(scanner):
+ d = collections.deque(maxlen=1)
+ d.extend(enumerate(scanner, 1))
+ if d:
+ return d[0][0]
+ return 0
+
+ scanner = table.scan(row_start=b'row-scan-a00012',
+ row_stop=b'row-scan-a00022')
+ assert_equal(10, calc_len(scanner))
+
+ scanner = table.scan(row_start=b'xyz')
+ assert_equal(0, calc_len(scanner))
+
+ scanner = table.scan(row_start=b'xyz', row_stop=b'zyx')
+ assert_equal(0, calc_len(scanner))
+
+ scanner = table.scan(row_start=b'row-scan-', row_stop=b'row-scan-a999',
+ columns=[b'cf1:col1', b'cf2:col2'])
+ row_key, row = next(scanner)
+ assert_equal(row_key, b'row-scan-a00000')
+ assert_dict_equal(row, {b'cf1:col1': b'v1',
+ b'cf2:col2': b'v2'})
+ assert_equal(2000 - 1, calc_len(scanner))
+
+ scanner = table.scan(row_prefix=b'row-scan-a', batch_size=499, limit=1000)
+ assert_equal(1000, calc_len(scanner))
+
+ scanner = table.scan(row_prefix=b'row-scan-b', batch_size=1, limit=10)
+ assert_equal(10, calc_len(scanner))
+
+ scanner = table.scan(row_prefix=b'row-scan-b', batch_size=5, limit=10)
+ assert_equal(10, calc_len(scanner))
+
+ scanner = table.scan(timestamp=123)
+ assert_equal(0, calc_len(scanner))
+
+ scanner = table.scan(row_prefix=b'row', timestamp=123)
+ assert_equal(0, calc_len(scanner))
+
+ scanner = table.scan(batch_size=20)
+ next(scanner)
+ next(scanner)
+ scanner.close()
+ with assert_raises(StopIteration):
+ next(scanner)
+
+
+def test_scan_sorting():
+ if connection.compat < '0.96':
+ return # not supported
+
+ input_row = {}
+ for i in range(100):
+ input_row[('cf1:col-%03d' % i).encode('ascii')] = b''
+ input_key = b'row-scan-sorted'
+ table.put(input_key, input_row)
+
+ scan = table.scan(row_start=input_key, sorted_columns=True)
+ key, row = next(scan)
+ assert_equal(key, input_key)
+ assert_list_equal(
+ sorted(input_row.items()),
+ list(row.items()))
+
+
+def test_scan_reverse():
+
+ if connection.compat < '0.98':
+ with assert_raises(NotImplementedError):
+ list(table.scan(reverse=True))
+ return
+
+ with table.batch() as b:
+ for i in range(2000):
+ b.put(('row-scan-reverse-%04d' % i).encode('ascii'),
+ {b'cf1:col1': b'v1',
+ b'cf1:col2': b'v2'})
+
+ scan = table.scan(row_prefix=b'row-scan-reverse', reverse=True)
+ assert_equal(2000, len(list(scan)))
+
+ scan = table.scan(limit=10, reverse=True)
+ assert_equal(10, len(list(scan)))
+
+ scan = table.scan(row_start=b'row-scan-reverse-1999',
+ row_stop=b'row-scan-reverse-0000', reverse=True)
+ key, data = next(scan)
+ assert_equal(b'row-scan-reverse-1999', key)
+
+ key, data = list(scan)[-1]
+ assert_equal(b'row-scan-reverse-0001', key)
+
+
+def test_scan_filter_and_batch_size():
+ # See issue #54 and #56
+ filter = b"SingleColumnValueFilter ('cf1', 'qual1', =, 'binary:val1')"
+ for k, v in table.scan(filter=filter):
+ print(v)
+
+
+def test_delete():
+ row_key = b'row-test-delete'
+ data = {b'cf1:col1': b'v1',
+ b'cf1:col2': b'v2',
+ b'cf1:col3': b'v3'}
+ table.put(row_key, {b'cf1:col2': b'v2old'}, timestamp=1234)
+ table.put(row_key, data)
+
+ table.delete(row_key, [b'cf1:col2'], timestamp=2345)
+ assert_equal(1, len(table.cells(row_key, b'cf1:col2', versions=2)))
+ assert_dict_equal(data, table.row(row_key))
+
+ table.delete(row_key, [b'cf1:col1'])
+ res = table.row(row_key)
+ assert_not_in(b'cf1:col1', res)
+ assert_in(b'cf1:col2', res)
+ assert_in(b'cf1:col3', res)
+
+ table.delete(row_key, timestamp=12345)
+ res = table.row(row_key)
+ assert_in(b'cf1:col2', res)
+ assert_in(b'cf1:col3', res)
+
+ table.delete(row_key)
+ assert_dict_equal({}, table.row(row_key))
+
+
+def test_connection_pool_construction():
+ with assert_raises(TypeError):
+ ConnectionPool(size='abc')
+
+ with assert_raises(ValueError):
+ ConnectionPool(size=0)
+
+
+def test_connection_pool():
+
+ from thriftpy2.thrift import TException
+
+ def run():
+ name = threading.current_thread().name
+ print("Thread %s starting" % name)
+
+ def inner_function():
+ # Nested connection requests must return the same connection
+ with pool.connection() as another_connection:
+ assert connection is another_connection
+
+ # Fake an exception once in a while
+ if random.random() < .25:
+ print("Introducing random failure")
+ connection.transport.close()
+ raise TException("Fake transport exception")
+
+ for i in range(50):
+ with pool.connection() as connection:
+ connection.tables()
+
+ try:
+ inner_function()
+ except TException:
+ # This error should have been picked up by the
+ # connection pool, and the connection should have
+ # been replaced by a fresh one
+ pass
+
+ connection.tables()
+
+ print("Thread %s done" % name)
+
+ N_THREADS = 10
+
+ pool = ConnectionPool(size=3, **connection_kwargs)
+ threads = [threading.Thread(target=run) for i in range(N_THREADS)]
+
+ for t in threads:
+ t.start()
+
+ while threads:
+ for t in threads:
+ t.join(timeout=.1)
+
+ # filter out finished threads
+ threads = [t for t in threads if t.is_alive()]
+ print("%d threads still alive" % len(threads))
+
+
+def test_pool_exhaustion():
+ pool = ConnectionPool(size=1, **connection_kwargs)
+
+ def run():
+ with assert_raises(NoConnectionsAvailable):
+ with pool.connection(timeout=.1) as connection:
+ connection.tables()
+
+ with pool.connection():
+ # At this point the only connection is assigned to this thread,
+ # so another thread cannot obtain a connection at this point.
+
+ t = threading.Thread(target=run)
+ t.start()
+ t.join()
+
+
+if __name__ == '__main__':
+ import logging
+ import sys
+
+ # Dump stacktraces using 'kill -USR1', useful for debugging hanging
+ # programs and multi threading issues.
+ try:
+ import faulthandler
+ except ImportError:
+ pass
+ else:
+ import signal
+ faulthandler.register(signal.SIGUSR1)
+
+ logging.basicConfig(level=logging.DEBUG)
+
+ method_name = 'test_%s' % sys.argv[1]
+ method = globals()[method_name]
+ method()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/happybase-1.1.0/tests/test_util.py
new/happybase-1.2.0/tests/test_util.py
--- old/happybase-1.1.0/tests/test_util.py 1970-01-01 01:00:00.000000000
+0100
+++ new/happybase-1.2.0/tests/test_util.py 2019-05-14 16:16:06.000000000
+0200
@@ -0,0 +1,56 @@
+"""
+HappyBase utility tests.
+"""
+
+from codecs import decode, encode
+
+from nose.tools import assert_equal, assert_less
+
+import happybase.util as util
+
+
+def test_camel_case_to_pep8():
+ def check(lower_cc, upper_cc, correct):
+
+ x1 = util.camel_case_to_pep8(lower_cc)
+ x2 = util.camel_case_to_pep8(upper_cc)
+ assert_equal(correct, x1)
+ assert_equal(correct, x2)
+
+ y1 = util.pep8_to_camel_case(x1, True)
+ y2 = util.pep8_to_camel_case(x2, False)
+ assert_equal(upper_cc, y1)
+ assert_equal(lower_cc, y2)
+
+ examples = [('foo', 'Foo', 'foo'),
+ ('fooBar', 'FooBar', 'foo_bar'),
+ ('fooBarBaz', 'FooBarBaz', 'foo_bar_baz'),
+ ('fOO', 'FOO', 'f_o_o')]
+
+ for a, b, c in examples:
+ yield check, a, b, c
+
+
+def test_bytes_increment():
+ def check(s_hex, expected):
+ s = decode(s_hex, 'hex')
+ v = util.bytes_increment(s)
+ v_hex = encode(v, 'hex')
+ assert_equal(expected, v_hex)
+ assert_less(s, v)
+
+ test_values = [
+ (b'00', b'01'),
+ (b'01', b'02'),
+ (b'fe', b'ff'),
+ (b'1234', b'1235'),
+ (b'12fe', b'12ff'),
+ (b'12ff', b'13'),
+ (b'424242ff', b'424243'),
+ (b'4242ffff', b'4243'),
+ ]
+
+ assert util.bytes_increment(b'\xff\xff\xff') is None
+
+ for s, expected in test_values:
+ yield check, s, expected
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/happybase-1.1.0/tox.ini new/happybase-1.2.0/tox.ini
--- old/happybase-1.1.0/tox.ini 1970-01-01 01:00:00.000000000 +0100
+++ new/happybase-1.2.0/tox.ini 2019-05-14 16:16:06.000000000 +0200
@@ -0,0 +1,8 @@
+[tox]
+envlist = py27,py34,py35
+
+[testenv]
+deps=
+ nose
+ coverage
+commands=nosetests