Skip to content

Commit b098940

Browse files
committed
Add a shell to access hbase in terminal.
It is still simple now, but the overall framework is formed. We can add more functions later.
1 parent 0ac235d commit b098940

3 files changed

Lines changed: 171 additions & 4 deletions

File tree

hbase/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,5 @@
88
from .connection import ConnectionPool
99
from .connection import Connection
1010
from .client import *
11+
from .namespace import Namespace
12+
from .table import Table

hbase/shell.py

Lines changed: 163 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
1+
#!/usr/bin/env python3
2+
3+
"""
4+
@author: xi
5+
@since: 2018-04-14
6+
"""
7+
8+
import argparse
9+
import cmd
10+
import shlex
11+
import time
12+
13+
import hbase
14+
15+
16+
class ArgumentParser(argparse.ArgumentParser):
17+
18+
def error(self, message):
19+
raise RuntimeError(message)
20+
21+
22+
class HBaseShell(cmd.Cmd):
23+
24+
def __init__(self, args):
25+
self._args = args
26+
27+
super(HBaseShell, self).__init__()
28+
self.prompt = '?> '
29+
30+
self._zk = args.zk
31+
32+
self._parsers = dict()
33+
self._conn = None # type: hbase.Connection
34+
self._ns = None # type: hbase.Namespace
35+
36+
def __enter__(self):
37+
self._conn = hbase.ConnectionPool(self._zk).connect()
38+
return self
39+
40+
def __exit__(self, exc_type, exc_val, exc_tb):
41+
if self._conn is not None:
42+
self._conn.close()
43+
self._conn = None
44+
45+
def onecmd(self, line):
46+
try:
47+
super(HBaseShell, self).onecmd(line)
48+
except Exception as e:
49+
print(str(e))
50+
finally:
51+
if line:
52+
print()
53+
54+
def do_ls(self, line):
55+
parser_name = 'ls'
56+
if parser_name not in self._parsers:
57+
parser = ArgumentParser(prog=parser_name)
58+
self._parsers[parser_name] = parser
59+
parser.add_argument('--namespaces', '-n', action='store_true')
60+
parser.add_argument('--tables', '-t', action='store_true')
61+
args = self._parsers[parser_name].parse_args(shlex.split(line))
62+
63+
if args.namespaces or (not args.namespaces and not args.tables):
64+
for ns in self._conn.namespaces():
65+
print(ns)
66+
return
67+
68+
if args.tables:
69+
if self._ns is None:
70+
raise RuntimeError('No namespace selected. Please use "use [namespace]".')
71+
for tbl in self._ns.tables():
72+
print(tbl)
73+
74+
def do_use(self, line):
75+
parser_name = 'use'
76+
if parser_name not in self._parsers:
77+
parser = ArgumentParser(prog=parser_name)
78+
self._parsers[parser_name] = parser
79+
parser.add_argument('name', default=None, nargs='?')
80+
args = self._parsers[parser_name].parse_args(shlex.split(line))
81+
82+
if args.name is None:
83+
self._ns = None
84+
self.prompt = '?> '
85+
return
86+
87+
self._ns = self._conn.namespace(args.name, create_if_not_exists=False)
88+
self.prompt = self._ns.name + '> '
89+
90+
def do_get(self, line):
91+
parser_name = 'get'
92+
if parser_name not in self._parsers:
93+
parser = ArgumentParser(prog=parser_name)
94+
self._parsers[parser_name] = parser
95+
parser.add_argument('table')
96+
parser.add_argument('key', nargs='?')
97+
parser.add_argument('--full', '-f', action='store_true', default=False)
98+
args = self._parsers[parser_name].parse_args(shlex.split(line))
99+
100+
if self._ns is None:
101+
raise RuntimeError('No namespace selected. Please use "use [namespace]".')
102+
tbl = self._ns.table(args.table, create_if_not_exists=False)
103+
row = tbl.get(args.key) if args.key else tbl.get_one(not args.full)
104+
print(row)
105+
106+
def do_count(self, line):
107+
parser_name = 'count'
108+
if parser_name not in self._parsers:
109+
parser = ArgumentParser(prog=parser_name)
110+
self._parsers[parser_name] = parser
111+
parser.add_argument('table')
112+
args = self._parsers[parser_name].parse_args(shlex.split(line))
113+
114+
tbl = self._ns.table(args.table, create_if_not_exists=False)
115+
t = time.time()
116+
count = tbl.count(
117+
verbose=lambda c, r: print('%d: %s' % (c, r.key))
118+
)
119+
t = time.time() - t
120+
print('\nTotal count: %d.\n%d seconds used.' % (count, t))
121+
122+
def do_drop_namespace(self, line):
123+
parser_name = 'drop_namespace'
124+
if parser_name not in self._parsers:
125+
parser = ArgumentParser(prog=parser_name)
126+
self._parsers[parser_name] = parser
127+
parser.add_argument('namespace')
128+
args = self._parsers[parser_name].parse_args(shlex.split(line))
129+
130+
self._conn.delete_namespace(args.namespace)
131+
if self._ns.name == args.namespace:
132+
self._ns = None
133+
self.prompt = '?> '
134+
print('Namespace %s dropped.' % args.namespace)
135+
136+
def do_drop_table(self, line):
137+
parser_name = 'drop_table'
138+
if parser_name not in self._parsers:
139+
parser = ArgumentParser(prog=parser_name)
140+
self._parsers[parser_name] = parser
141+
parser.add_argument('table')
142+
args = self._parsers[parser_name].parse_args(shlex.split(line))
143+
144+
self._ns.delete_table(args.table)
145+
print('Table %s dropped.' % args.table)
146+
147+
def do_EOF(self, line):
148+
return True
149+
150+
151+
def main(args):
152+
if args.zk is None:
153+
args.zk = input('Please input zookeeper quorum: ')
154+
with HBaseShell(args) as shell:
155+
shell.cmdloop()
156+
return 0
157+
158+
159+
if __name__ == '__main__':
160+
_parser = argparse.ArgumentParser()
161+
_parser.add_argument('zk', nargs='?')
162+
_args = _parser.parse_args()
163+
exit(main(_args))

setup.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,14 @@
99
setup(
1010
name='hbase-python',
1111
packages=[
12-
'hbase_rest',
13-
'hbase_rest.protobuf_schema'
12+
'hbase',
13+
'hbase.client',
14+
'hbase.protobuf',
15+
'hbase.services'
1416
],
15-
version='0.4',
17+
version='0.5',
1618
keywords=('hbase', 'hbase-client', 'hadoop'),
17-
description='User friendly HBase client for Python 3.',
19+
description='User friendly HBase client for Python 3. (Pure python implementation)',
1820
long_description=long_description,
1921
license='Free',
2022
author='dm.ustc.edu.cn',

0 commit comments

Comments
 (0)