From bd27527211c630f886e665bb4d0b76be78769edd Mon Sep 17 00:00:00 2001 From: Brandon Williams Date: Fri, 31 Aug 2012 07:42:31 -0500 Subject: [PATCH] cqlsh: update encoding for collections Patch by paul cannon reviewed by brandonwilliams for CASSANDRA-4500 --- bin/cqlsh | 254 ++++++-------------------------- lib/cql-internal-only-1.1.0.zip | Bin 0 -> 78637 bytes pylib/cqlshlib/cql3handling.py | 7 +- pylib/cqlshlib/cqlhandling.py | 42 +----- pylib/cqlshlib/displaying.py | 107 ++++++++++++++ pylib/cqlshlib/formatting.py | 192 ++++++++++++++++++++++++ pylib/cqlshlib/util.py | 5 + 7 files changed, 361 insertions(+), 246 deletions(-) create mode 100644 lib/cql-internal-only-1.1.0.zip create mode 100644 pylib/cqlshlib/displaying.py create mode 100644 pylib/cqlshlib/formatting.py diff --git a/bin/cqlsh b/bin/cqlsh index 7ea012850e..24217aed25 100755 --- a/bin/cqlsh +++ b/bin/cqlsh @@ -39,7 +39,6 @@ from itertools import groupby from contextlib import contextmanager, closing from glob import glob from functools import partial -from collections import defaultdict import cmd import sys @@ -49,19 +48,10 @@ import optparse import ConfigParser import codecs import locale -import re import platform import warnings import csv -# cqlsh should run correctly when run out of a Cassandra source tree, -# out of an unpacked Cassandra tarball, and after a proper package install. -cqlshlibdir = os.path.join(os.path.dirname(os.path.realpath(__file__)), '..', 'pylib') -if os.path.isdir(cqlshlibdir): - sys.path.insert(0, cqlshlibdir) - -from cqlshlib import cqlhandling, cql3handling, pylexotron, wcwidth - try: import readline except ImportError: @@ -105,7 +95,20 @@ except ImportError, e: import cql.decoders from cql.cursor import _COUNT_DESCRIPTION, _VOID_DESCRIPTION +from cql.cqltypes import (cql_types, cql_typename, lookup_casstype, lookup_cqltype, + CassandraType) +# cqlsh should run correctly when run out of a Cassandra source tree, +# out of an unpacked Cassandra tarball, and after a proper package install. +cqlshlibdir = os.path.join(os.path.dirname(os.path.realpath(__file__)), '..', 'pylib') +if os.path.isdir(cqlshlibdir): + sys.path.insert(0, cqlshlibdir) + +from cqlshlib import cqlhandling, cql3handling, pylexotron +from cqlshlib.displaying import (RED, BLUE, ANSI_RESET, COLUMN_NAME_COLORS, + FormattedValue, colorme) +from cqlshlib.formatting import format_by_type +from cqlshlib.util import trim_if_present CONFIG_FILE = os.path.expanduser(os.path.join('~', '.cqlshrc')) HISTORY = os.path.expanduser(os.path.join('~', '.cqlsh_history')) @@ -139,16 +142,6 @@ parser.add_option("-3", "--cql3", action="store_const", dest='cqlversion', const help="Shortcut notation for --cqlversion=3") -RED = '\033[0;1;31m' -GREEN = '\033[0;1;32m' -YELLOW = '\033[0;1;33m' -BLUE = '\033[0;1;34m' -MAGENTA = '\033[0;1;35m' -CYAN = '\033[0;1;36m' -WHITE = '\033[0;1;37m' -DARK_MAGENTA = '\033[0;35m' -ANSI_RESET = '\033[0m' - CQL_ERRORS = (cql.Error,) try: from thrift.Thrift import TException @@ -361,159 +354,18 @@ def full_cql_version(ver): vertuple = tuple(map(int, ver_parts[0].split('.')) + [ver_parts[1]]) return ver, vertuple -def trim_if_present(s, prefix): - if s.startswith(prefix): - return s[len(prefix):] - return s - -class FormattedValue: - def __init__(self, strval, coloredval, displaywidth): - self.strval = strval - self.coloredval = coloredval - self.displaywidth = displaywidth - - def __len__(self): - return len(self.strval) - - def _pad(self, width, fill=' '): - if width > self.displaywidth: - return fill * (width - self.displaywidth) +def format_value(val, typeclass, output_encoding, addcolor=False, time_format=None, + float_precision=None, colormap=None, nullval=None): + if isinstance(val, DecodeError): + if addcolor: + return colorme(val.thebytes, colormap, 'hex') else: - return '' - - def ljust(self, width, fill=' '): - """ - Similar to self.strval.ljust(width), but takes expected terminal - display width into account for special characters, and does not - take color escape codes into account. - """ - return self.strval + self._pad(width, fill) - - def rjust(self, width, fill=' '): - """ - Similar to self.strval.rjust(width), but takes expected terminal - display width into account for special characters, and does not - take color escape codes into account. - """ - return self._pad(width, fill) + self.strval - - def color_rjust(self, width, fill=' '): - """ - Similar to self.rjust(width), but uses this value's colored - representation, and does not take color escape codes into account - in determining width. - """ - return self._pad(width, fill) + self.coloredval - - def color_ljust(self, width, fill=' '): - """ - Similar to self.ljust(width), but uses this value's colored - representation, and does not take color escape codes into account - in determining width. - """ - return self.coloredval + self._pad(width, fill) - -unicode_controlchars_re = re.compile(r'[\x00-\x31\x7f-\xa0]') -controlchars_re = re.compile(r'[\x00-\x31\x7f-\xff]') - -def _show_control_chars(match): - txt = repr(match.group(0)) - if txt.startswith('u'): - txt = txt[2:-1] - else: - txt = txt[1:-1] - return txt - -bits_to_turn_red_re = re.compile(r'\\([^uUx]|u[0-9a-fA-F]{4}|x[0-9a-fA-F]{2}|U[0-9a-fA-F]{8})') - -def _make_turn_bits_red_f(color1, color2): - def _turn_bits_red(match): - txt = match.group(0) - if txt == '\\\\': - return '\\' - return color1 + txt + color2 - return _turn_bits_red - -DEFAULT_VALUE_COLORS = dict( - default=YELLOW, - text=YELLOW, - error=RED, - hex=DARK_MAGENTA, - timestamp=GREEN, - int=GREEN, - float=GREEN, - decimal=GREEN, - boolean=GREEN, - uuid=GREEN, -) - -COLUMN_NAME_COLORS = defaultdict(lambda: MAGENTA, - error=RED, - hex=DARK_MAGENTA, -) - -def unix_time_from_uuid1(u): - return (u.get_time() - 0x01B21DD213814000) / 10000000.0 - -def format_value(val, casstype, output_encoding, addcolor=False, time_format='', - float_precision=3, colormap=DEFAULT_VALUE_COLORS, nullval='null'): - casstype = trim_if_present(casstype, 'org.apache.cassandra.db.marshal.') - color = colormap['default'] - coloredval = None - displaywidth = None - - if val is None: - bval = nullval - color = colormap['error'] - elif isinstance(val, DecodeError): - casstype = 'BytesType' - bval = repr(val.thebytes) - color = colormap['hex'] - elif casstype == 'UTF8Type': - escapedval = val.replace(u'\\', u'\\\\') - escapedval = unicode_controlchars_re.sub(_show_control_chars, escapedval) - bval = escapedval.encode(output_encoding, 'backslashreplace') - displaywidth = wcwidth.wcswidth(bval.decode(output_encoding)) - if addcolor: - tbr = _make_turn_bits_red_f(colormap['hex'], colormap['text']) - coloredval = colormap['text'] + bits_to_turn_red_re.sub(tbr, bval) + ANSI_RESET - elif casstype in ('DateType', 'TimeUUIDType'): - if casstype == 'TimeUUIDType': - val = unix_time_from_uuid1(val) - timestamp = time.localtime(val) - bval = time.strftime(time_format, timestamp) - color = colormap['timestamp'] - elif casstype in ('LongType', 'Int32Type', 'IntegerType', 'CounterColumnType'): - # base-10 only for now; support others? - bval = str(val) - color = colormap['int'] - elif casstype in ('FloatType', 'DoubleType'): - bval = '%.*g' % (float_precision, val) - color = colormap['float'] - elif casstype in ('DecimalType', 'UUIDType', 'BooleanType'): - # let python do these for us - bval = str(val) - color = colormap[cqlruleset.cql_typename(casstype)] - elif casstype == 'BytesType': - bval = ''.join('%02x' % ord(c) for c in val) - color = colormap['hex'] - else: - # AsciiType is the only other one known right now, but handle others - val = str(val) - escapedval = val.replace('\\', '\\\\') - bval = controlchars_re.sub(_show_control_chars, escapedval) - if addcolor: - tbr = _make_turn_bits_red_f(colormap['hex'], colormap['text']) - coloredval = colormap['text'] + bits_to_turn_red_re.sub(tbr, bval) + ANSI_RESET - - if displaywidth is None: - displaywidth = len(bval) - if not addcolor: - coloredval = bval - elif coloredval is None: - coloredval = color + bval + ANSI_RESET - - return FormattedValue(bval, coloredval, displaywidth) + return FormattedValue(val.thebytes) + if not issubclass(typeclass, CassandraType): + typeclass = lookup_casstype(typeclass) + return format_by_type(typeclass, val, output_encoding, colormap=colormap, + addcolor=addcolor, nullval=nullval, time_format=time_format, + float_precision=float_precision) def show_warning_without_quoting_line(message, category, filename, lineno, file=None, line=None): if file is None: @@ -657,14 +509,14 @@ class Shell(cmd.Cmd): cf = self.cql_protect_name(cf) if override.default_name_type: print 'ASSUME %s NAMES ARE %s;' \ - % (cf, cqlruleset.cql_typename(override.default_name_type)) + % (cf, cql_typename(override.default_name_type)) if override.default_value_type: print 'ASSUME %s VALUES ARE %s;' \ - % (cf, cqlruleset.cql_typename(override.default_value_type)) + % (cf, cql_typename(override.default_value_type)) for colname, vtype in override.value_types.items(): colname = self.cql_protect_name(colname) print 'ASSUME %s(%s) VALUES ARE %s;' \ - % (cf, colname, cqlruleset.cql_typename(vtype)) + % (cf, colname, cql_typename(vtype)) print def get_cluster_versions(self): @@ -1059,15 +911,7 @@ class Shell(cmd.Cmd): This is necessary to differentiate some things like ascii vs. blob hex. """ - if getattr(cursor, 'supports_name_info', False): - return cursor.name_info[num][1] - - # This is a pretty big hack, but necessary until we can rely on - # python-cql 1.0.10 being around. - row = cursor.result[cursor.rs_idx - 1] - col = row.columns[num] - schema = cursor.decoder.schema - return schema.name_types.get(col.name, schema.default_name_type) + return cursor.name_info[num][1] def print_count_result(self, cursor): if not cursor.result: @@ -1077,21 +921,21 @@ class Shell(cmd.Cmd): self.writeresult(cursor.result[0]) self.writeresult("") - def print_result(self, cursor): - self.decoding_errors = [] - - # first pass: see if we have a static column set + def has_static_result_set(self, cursor): + if self.cqlver_atleast(3): + return True # all cql3 resultsets are static, don't bother scanning last_description = None for row in cursor: if last_description is not None and cursor.description != last_description: - static = False - break + return False last_description = cursor.description - else: - static = True cursor._reset() + return True - if static: + def print_result(self, cursor): + self.decoding_errors = [] + + if self.has_static_result_set(cursor): self.print_static_result(cursor) else: self.print_dynamic_result(cursor) @@ -1105,10 +949,10 @@ class Shell(cmd.Cmd): % (len(self.decoding_errors) - 2), color=RED) def print_static_result(self, cursor): - colnames, coltypes = zip(*cursor.description)[:2] + colnames = [d[0] for d in cursor.description] colnames_t = [(name, self.get_nametype(cursor, n)) for (n, name) in enumerate(colnames)] formatted_names = [self.myformat_colname(name, nametype) for (name, nametype) in colnames_t] - formatted_data = [map(self.myformat_value, row, coltypes) for row in cursor] + formatted_data = [map(self.myformat_value, row, cursor.column_types) for row in cursor] # determine column widths widths = [n.displaywidth for n in formatted_names] @@ -1128,10 +972,10 @@ class Shell(cmd.Cmd): def print_dynamic_result(self, cursor): for row in cursor: - colnames, coltypes = zip(*cursor.description)[:2] + colnames = [d[0] for d in cursor.description] colnames_t = [(name, self.get_nametype(cursor, n)) for (n, name) in enumerate(colnames)] colnames = [self.myformat_colname(name, nametype) for (name, nametype) in colnames_t] - colvals = [self.myformat_value(val, casstype) for (val, casstype) in zip(row, coltypes)] + colvals = map(self.myformat_value, row, cursor.column_types) line = ' | '.join('%s,%s' % (n.coloredval, v.coloredval) for (n, v) in zip(colnames, colvals)) self.writeresult(' ' + line) @@ -1234,12 +1078,12 @@ class Shell(cmd.Cmd): cfname = self.cql_protect_name(cfdef.name) out.write("CREATE TABLE %s (\n" % cfname) alias = self.cql_protect_name(cfdef.key_alias) if cfdef.key_alias else 'KEY' - keytype = cqlruleset.cql_typename(cfdef.key_validation_class) + keytype = cql_typename(cfdef.key_validation_class) out.write(" %s %s PRIMARY KEY" % (alias, keytype)) indexed_columns = [] for col in cfdef.column_metadata: colname = self.cql_protect_name(col.name) - out.write(",\n %s %s" % (colname, cqlruleset.cql_typename(col.validation_class))) + out.write(",\n %s %s" % (colname, cql_typename(col.validation_class))) if col.index_name is not None: indexed_columns.append(col) cf_opts = [] @@ -1248,7 +1092,7 @@ class Shell(cmd.Cmd): if optval is None: continue if option in ('comparator', 'default_validation'): - optval = cqlruleset.cql_typename(optval) + optval = cql_typename(optval) else: if option == 'row_cache_provider': optval = trim_if_present(optval, 'org.apache.cassandra.cache.') @@ -1612,11 +1456,11 @@ class Shell(cmd.Cmd): row = self.cursor.fetchone() if row is None: break - fmt = lambda v, d: \ - format_value(v, d[1], output_encoding=encoding, nullval=nullval, + fmt = lambda v, t: \ + format_value(v, t, output_encoding=encoding, nullval=nullval, time_format=self.display_time_format, float_precision=self.display_float_precision).strval - writer.writerow(map(fmt, row, self.cursor.description)) + writer.writerow(map(fmt, row, self.cursor.column_types)) rows += 1 finally: if do_close: @@ -1726,7 +1570,7 @@ class Shell(cmd.Cmd): if cqltype is None: continue try: - validator_class = cqlruleset.find_validator_class(cqltype) + validator_class = lookup_cqltype(cqltype).cass_parameterized_type() except KeyError: self.printerr('Error: validator type %s not found.' % cqltype) else: @@ -1868,7 +1712,7 @@ class Shell(cmd.Cmd): def help_types(self): print "\n CQL types recognized by this version of cqlsh:\n" - for t in cqlruleset.cql_types: + for t in cql_types: print ' ' + t print """ For information on the various recognizable input formats for these diff --git a/lib/cql-internal-only-1.1.0.zip b/lib/cql-internal-only-1.1.0.zip new file mode 100644 index 0000000000000000000000000000000000000000..52b1e61c44a745073ca83f284b85b65c7d841495 GIT binary patch literal 78637 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 X=>1Q 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%0DFb?l8!)*!^vCM+{YV%5poV)Ov_EBminIcl5 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 literal 0 HcmV?d00001 diff --git a/pylib/cqlshlib/cql3handling.py b/pylib/cqlshlib/cql3handling.py index 63a5d0cabb..107d443804 100644 --- a/pylib/cqlshlib/cql3handling.py +++ b/pylib/cqlshlib/cql3handling.py @@ -17,6 +17,7 @@ import re from warnings import warn from .cqlhandling import CqlParsingRuleSet, Hint +from cql.cqltypes import cql_types, cql_typename try: import json @@ -131,7 +132,7 @@ CqlRuleSet = Cql3ParsingRuleSet() shorthands = ('completer_for', 'explain_completion', 'dequote_value', 'dequote_name', 'escape_value', 'escape_name', - 'maybe_escape_name', 'cql_typename') + 'maybe_escape_name') for shorthand in shorthands: globals()[shorthand] = getattr(CqlRuleSet, shorthand) @@ -250,7 +251,7 @@ def token_word_completer(ctxt, cass): @completer_for('storageType', 'typename') def storagetype_completer(ctxt, cass): - return CqlRuleSet.cql_types + return cql_types @completer_for('keyspaceName', 'ksname') def ks_name_completer(ctxt, cass): @@ -611,7 +612,7 @@ def create_cf_option_val_completer(ctxt, cass): if any(this_opt == opt[0] for opt in CqlRuleSet.obsolete_cf_options): return ["''"] if this_opt in ('comparator', 'default_validation'): - return CqlRuleSet.cql_types + return cql_types if this_opt in ('read_repair_chance', 'bloom_filter_fp_chance'): return [Hint('')] if this_opt == 'replicate_on_write': diff --git a/pylib/cqlshlib/cqlhandling.py b/pylib/cqlshlib/cqlhandling.py index 715f6f9803..06f029fa8a 100644 --- a/pylib/cqlshlib/cqlhandling.py +++ b/pylib/cqlshlib/cqlhandling.py @@ -20,6 +20,7 @@ import re import traceback from . import pylexotron, util +from cql import cqltypes Hint = pylexotron.Hint @@ -77,27 +78,6 @@ class CqlParsingRuleSet(pylexotron.ParsingRuleSet): 'SizeTieredCompactionStrategy' ) - cql_type_to_apache_class = { - 'ascii': 'AsciiType', - 'bigint': 'LongType', - 'blob': 'BytesType', - 'boolean': 'BooleanType', - 'counter': 'CounterColumnType', - 'decimal': 'DecimalType', - 'double': 'DoubleType', - 'float': 'FloatType', - 'int': 'Int32Type', - 'text': 'UTF8Type', - 'timestamp': 'DateType', - 'uuid': 'UUIDType', - 'varchar': 'UTF8Type', - 'varint': 'IntegerType' - } - - apache_class_to_cql_type = dict((v,k) for (k,v) in cql_type_to_apache_class.items()) - - cql_types = sorted(cql_type_to_apache_class.keys()) - replication_strategies = ( 'SimpleStrategy', 'OldNetworkTopologyStrategy', @@ -361,20 +341,6 @@ class CqlParsingRuleSet(pylexotron.ParsingRuleSet): print "** New total completion: %r. Checking for further matches...\n" % (first,) return self.cql_complete_multiple(text, first, init_bindings, startsymbol=startsymbol) - @classmethod - def cql_typename(cls, classname): - fq_classname = 'org.apache.cassandra.db.marshal.' - if classname.startswith(fq_classname): - classname = classname[len(fq_classname):] - try: - return cls.apache_class_to_cql_type[classname] - except KeyError: - return cls.escape_value(classname) - - @classmethod - def find_validator_class(cls, cqlname): - return cls.cql_type_to_apache_class[cqlname] - @classmethod def is_valid_cql_word(cls, s): return cls.valid_cql_word_re.match(s) is not None and s.lower() not in cls.keywords @@ -410,7 +376,7 @@ class CqlParsingRuleSet(pylexotron.ParsingRuleSet): @classmethod def is_counter_col(cls, cfdef, colname): col_info = [cm for cm in cfdef.column_metadata if cm.name == colname] - return bool(col_info and cls.cql_typename(col_info[0].validation_class) == 'counter') + return bool(col_info and cqltypes.is_counter_type(col_info[0].validation_class)) @staticmethod def cql2_dequote_value(cqlword): @@ -543,7 +509,7 @@ def cl_completer(ctxt, cass): @completer_for('storageType', 'typename') def storagetype_completer(ctxt, cass): - return CqlRuleSet.cql_types + return cqltypes.cql_types @completer_for('keyspaceName', 'ksname') def ks_name_completer(ctxt, cass): @@ -850,7 +816,7 @@ def create_cf_option_val_completer(ctxt, cass): if any(this_opt == opt[0] for opt in CqlRuleSet.obsolete_cf_options): return ["''"] if this_opt in ('comparator', 'default_validation'): - return CqlRuleSet.cql_types + return cqltypes.cql_types if this_opt == 'read_repair_chance': return [Hint('')] if this_opt == 'replicate_on_write': diff --git a/pylib/cqlshlib/displaying.py b/pylib/cqlshlib/displaying.py new file mode 100644 index 0000000000..adeaefdb64 --- /dev/null +++ b/pylib/cqlshlib/displaying.py @@ -0,0 +1,107 @@ +# 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 re +from collections import defaultdict + +RED = '\033[0;1;31m' +GREEN = '\033[0;1;32m' +YELLOW = '\033[0;1;33m' +BLUE = '\033[0;1;34m' +MAGENTA = '\033[0;1;35m' +CYAN = '\033[0;1;36m' +WHITE = '\033[0;1;37m' +DARK_MAGENTA = '\033[0;35m' +ANSI_RESET = '\033[0m' + +def colorme(bval, colormap, colorkey): + if colormap is None: + colormap = DEFAULT_VALUE_COLORS + return FormattedValue(bval, colormap[colorkey] + bval + colormap['reset']) + +class FormattedValue: + def __init__(self, strval, coloredval=None, displaywidth=None): + self.strval = strval + if coloredval is None: + coloredval = strval + self.coloredval = coloredval + if displaywidth is None: + displaywidth = len(strval) + # displaywidth is useful for display of special unicode characters + # with + self.displaywidth = displaywidth + + def __len__(self): + return len(self.strval) + + def _pad(self, width, fill=' '): + if width > self.displaywidth: + return fill * (width - self.displaywidth) + else: + return '' + + def ljust(self, width, fill=' '): + """ + Similar to self.strval.ljust(width), but takes expected terminal + display width into account for special characters, and does not + take color escape codes into account. + """ + return self.strval + self._pad(width, fill) + + def rjust(self, width, fill=' '): + """ + Similar to self.strval.rjust(width), but takes expected terminal + display width into account for special characters, and does not + take color escape codes into account. + """ + return self._pad(width, fill) + self.strval + + def color_rjust(self, width, fill=' '): + """ + Similar to self.rjust(width), but uses this value's colored + representation, and does not take color escape codes into account + in determining width. + """ + return self._pad(width, fill) + self.coloredval + + def color_ljust(self, width, fill=' '): + """ + Similar to self.ljust(width), but uses this value's colored + representation, and does not take color escape codes into account + in determining width. + """ + return self.coloredval + self._pad(width, fill) + +DEFAULT_VALUE_COLORS = dict( + default=YELLOW, + text=YELLOW, + error=RED, + hex=DARK_MAGENTA, + timestamp=GREEN, + int=GREEN, + float=GREEN, + decimal=GREEN, + boolean=GREEN, + uuid=GREEN, + collection=BLUE, + reset=ANSI_RESET, +) + +COLUMN_NAME_COLORS = defaultdict(lambda: MAGENTA, + error=RED, + hex=DARK_MAGENTA, + reset=ANSI_RESET, +) diff --git a/pylib/cqlshlib/formatting.py b/pylib/cqlshlib/formatting.py new file mode 100644 index 0000000000..a5a0fd2201 --- /dev/null +++ b/pylib/cqlshlib/formatting.py @@ -0,0 +1,192 @@ +# 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 re +import time +from collections import defaultdict +from . import wcwidth +from .displaying import colorme, FormattedValue, DEFAULT_VALUE_COLORS +from cql import cqltypes + +unicode_controlchars_re = re.compile(r'[\x00-\x31\x7f-\xa0]') +controlchars_re = re.compile(r'[\x00-\x31\x7f-\xff]') + +def _show_control_chars(match): + txt = repr(match.group(0)) + if txt.startswith('u'): + txt = txt[2:-1] + else: + txt = txt[1:-1] + return txt + +bits_to_turn_red_re = re.compile(r'\\([^uUx]|u[0-9a-fA-F]{4}|x[0-9a-fA-F]{2}|U[0-9a-fA-F]{8})') + +def _make_turn_bits_red_f(color1, color2): + def _turn_bits_red(match): + txt = match.group(0) + if txt == '\\\\': + return '\\' + return color1 + txt + color2 + return _turn_bits_red + +default_null_placeholder = 'null' +default_time_format = '' +default_float_precision = 3 +default_colormap = DEFAULT_VALUE_COLORS +empty_colormap = defaultdict(lambda: '') + +def format_by_type(cqltype, val, encoding, colormap=None, addcolor=False, + nullval=None, time_format=None, float_precision=None): + if nullval is None: + nullval = default_null_placeholder + if val is None: + return colorme(nullval, colormap, 'error') + if addcolor is False: + colormap = empty_colormap + elif colormap is None: + colormap = default_colormap + if time_format is None: + time_format = default_time_format + if float_precision is None: + float_precision = default_float_precision + return format_value(cqltype, val, encoding=encoding, colormap=colormap, + time_format=time_format, float_precision=float_precision, + nullval=nullval) + +def format_value_default(val, colormap, **_): + val = str(val) + escapedval = val.replace('\\', '\\\\') + bval = controlchars_re.sub(_show_control_chars, escapedval) + tbr = _make_turn_bits_red_f(colormap['hex'], colormap['text']) + coloredval = colormap['text'] + bits_to_turn_red_re.sub(tbr, bval) + colormap['reset'] + return FormattedValue(bval, coloredval) + +# Mapping cql type base names ("int", "map", etc) to formatter functions, +# making format_value a generic function +_formatters = {} + +def format_value(cqltype, val, **kwargs): + formatter = _formatters.get(cqltype.typename, format_value_default) + return formatter(val, subtypes=cqltype.subtypes, **kwargs) + +def formatter_for(typname): + def registrator(f): + _formatters[typname] = f + return f + return registrator + +@formatter_for('bytes') +def format_value_bytes(val, colormap, **_): + bval = ''.join('%02x' % ord(c) for c in val) + return colorme(bval, colormap, 'hex') + +def format_python_formatted_type(val, colormap, color): + bval = str(val) + return colorme(bval, colormap, color) + +@formatter_for('decimal') +def format_value_decimal(val, colormap, **_): + return format_python_formatted_type(val, colormap, 'decimal') + +@formatter_for('uuid') +def format_value_uuid(val, colormap, **_): + return format_python_formatted_type(val, colormap, 'uuid') + +@formatter_for('boolean') +def format_value_boolean(val, colormap, **_): + return format_python_formatted_type(val, colormap, 'boolean') + +def format_floating_point_type(val, colormap, float_precision, **_): + bval = '%.*g' % (float_precision, val) + return colorme(bval, colormap, 'float') + +formatter_for('float')(format_floating_point_type) +formatter_for('double')(format_floating_point_type) + +def format_integer_type(val, colormap, **_): + # base-10 only for now; support others? + bval = str(val) + return colorme(bval, colormap, 'int') + +formatter_for('bigint')(format_integer_type) +formatter_for('int')(format_integer_type) +formatter_for('varint')(format_integer_type) +formatter_for('counter')(format_integer_type) + +@formatter_for('timestamp') +def format_value_timestamp(val, colormap, time_format, **_): + bval = time.strftime(time_format, time.localtime(val)) + return colorme(bval, colormap, 'timestamp') + +@formatter_for('timeuuid') +def format_value_timeuuid(val, colormap, time_format, **_): + utime = unix_time_from_uuid1(val) + bval = time.strftime(time_format, time.localtime(utime)) + return colorme(bval, colormap, 'timestamp') + +@formatter_for('text') +def format_value_text(val, encoding, colormap, **_): + escapedval = val.replace(u'\\', u'\\\\') + escapedval = unicode_controlchars_re.sub(_show_control_chars, escapedval) + bval = escapedval.encode(encoding, 'backslashreplace') + displaywidth = wcwidth.wcswidth(bval.decode(encoding)) + tbr = _make_turn_bits_red_f(colormap['hex'], colormap['text']) + coloredval = colormap['text'] + bits_to_turn_red_re.sub(tbr, bval) + colormap['reset'] + return FormattedValue(bval, coloredval) + +# name alias +formatter_for('varchar')(format_value_text) + +def format_simple_collection(subtype, val, lbracket, rbracket, encoding, + colormap, time_format, float_precision, nullval): + subs = [format_value(subtype, sval, encoding=encoding, colormap=colormap, + time_format=time_format, float_precision=float_precision, + nullval=nullval) + for sval in val] + bval = lbracket + ', '.join(sval.strval for sval in subs) + rbracket + lb, sep, rb = [colormap['collection'] + s + colormap['reset'] + for s in (lbracket, ', ', rbracket)] + coloredval = lb + sep.join(sval.coloredval for sval in subs) + rb + displaywidth = 2 * len(subs) + sum(sval.displaywidth for sval in subs) + return FormattedValue(bval, coloredval, displaywidth) + +@formatter_for('list') +def format_value_list(val, encoding, colormap, time_format, float_precision, subtypes, nullval, **_): + return format_simple_collection(subtypes[0], val, '[', ']', encoding, colormap, + time_format, float_precision, nullval) + +@formatter_for('set') +def format_value_set(val, encoding, colormap, time_format, float_precision, subtypes, nullval, **_): + return format_simple_collection(subtypes[0], val, '{', '}', encoding, colormap, + time_format, float_precision, nullval) + +@formatter_for('map') +def format_value_map(val, encoding, colormap, time_format, float_precision, subtypes, nullval, **_): + def subformat(v, subtype): + return format_value(subtype, v, encoding=encoding, colormap=colormap, + time_format=time_format, float_precision=float_precision, + nullval=nullval) + + subkeytype, subvaltype = subtypes + subs = [(subformat(k, subkeytype), subformat(v, subvaltype)) for (k, v) in val.items()] + bval = '{' + ', '.join(k.strval + ': ' + v.strval for (k, v) in subs) + '}' + lb, comma, colon, rb = [colormap['collection'] + s + colormap['reset'] + for s in ('{', ', ', ': ', '}')] + coloredval = lb \ + + comma.join(k.coloredval + colon + v.coloredval for (k, v) in subs) \ + + rb + displaywidth = 4 * len(subs) + sum(k.displaywidth + v.displaywidth for (k, v) in subs) + return FormattedValue(bval, coloredval, displaywidth) diff --git a/pylib/cqlshlib/util.py b/pylib/cqlshlib/util.py index ea0fbf45c3..e62ded4aed 100644 --- a/pylib/cqlshlib/util.py +++ b/pylib/cqlshlib/util.py @@ -72,3 +72,8 @@ def list_bifilter(pred, iterable): def identity(x): return x + +def trim_if_present(s, prefix): + if s.startswith(prefix): + return s[len(prefix):] + return s