blob: c58879e4d74aa42b912e771acb9dbe496f043a31 [file] [log] [blame]
import datetime
import logging
import re
from collections import namedtuple
from cassandra.util import SortedSet
logger = logging.getLogger(__name__)
def maybe_quote(s):
"""
Return a quoted string representation for strings, unicode and date time parameters,
otherwise return a string representation of the parameter.
"""
return "'{}'".format(s) if isinstance(s, (str, Datetime)) else str(s)
class Address(namedtuple('Address', ('name', 'number', 'street', 'phones'))):
__slots__ = ()
def __repr__(self):
phones_str = "{{{}}}".format(', '.join(maybe_quote(p) for p in sorted(self.phones)))
return "{{name: {}, number: {}, street: '{}', phones: {}}}".format(self.name,
self.number,
self.street,
phones_str)
def __str__(self):
phones_str = "{{{}}}".format(', '.join(maybe_quote(p) for p in sorted(self.phones)))
return "{{name: {}, number: {}, street: '{}', phones: {}}}".format(self.name,
self.number,
self.street,
phones_str)
def drop_microseconds(val):
"""
For COPY TO, we need to round microsecond to milliseconds because server side
TimestampSerializer.dateStringPatterns only parses milliseconds. If we keep microseconds,
users may try to import with COPY FROM a file generated with COPY TO and have problems if
prepared statements are disabled, see CASSANDRA-11631.
"""
def drop_micros(m):
return m.group(0)[:12] + '+'
# Matches H:MM:SS.000000+ and drops the last 3 digits before the +
ret = re.sub('\\d{2}\\:\\d{2}\\:\\d{2}\\.(\\d{6})\\+', drop_micros, val)
logger.debug("Rounded microseconds: {} -> {}".format(val, ret))
return ret
class Datetime(datetime.datetime):
"""
Extend standard datetime.datetime class with cql formatting.
This could be cleaner if this class was declared inside TestCqlshCopy, but then pickle
wouldn't have access to the class.
"""
def __new__(cls, year, month, day, hour=0, minute=0, second=0, microsecond=0, tzinfo=None,
time_format='%Y-%m-%d %H:%M:%S%z', round_timestamp=True):
self = datetime.datetime.__new__(cls, year, month, day, hour, minute, second, microsecond, tzinfo)
self.default_time_format = time_format
self.round_timestamp = round_timestamp
return self
def __repr__(self):
return self._format_for_csv()
def __str__(self):
return self._format_for_csv()
def _format_for_csv(self):
ret = self.strftime(self.default_time_format)
return drop_microseconds(ret) if self.round_timestamp else ret
class ImmutableDict(frozenset):
"""
Immutable dictionary implementation to represent map types.
We need to pass BoundStatement.bind() a dict() because it calls iteritems(),
except we can't create a dict with another dict as the key, hence we use a class
that adds iteritems to a frozen set of tuples (which is how dict are normally made
immutable in python).
Must be declared in the top level of the module to be available for pickling.
"""
iteritems = frozenset.__iter__
def items(self):
for k, v in self.iteritems():
yield k, v
def __repr__(self):
return '{{{}}}'.format(', '.join(['{0}: {1}'.format(maybe_quote(k), maybe_quote(v)) for k, v in sorted(self.items())]))
class ImmutableSet(SortedSet):
def __repr__(self):
return '{{{}}}'.format(', '.join([maybe_quote(t) for t in sorted(self._items)]))
def __str__(self):
return '{{{}}}'.format(', '.join([maybe_quote(t) for t in sorted(self._items)]))
def __hash__(self):
return hash(tuple([e for e in self]))
class Name(namedtuple('Name', ('firstname', 'lastname'))):
__slots__ = ()
def __repr__(self):
return "{{firstname: '{}', lastname: '{}'}}".format(self.firstname, self.lastname)
def __str__(self):
return "{{firstname: '{}', lastname: '{}'}}".format(self.firstname, self.lastname)
class UTC(datetime.tzinfo):
"""
A utility class to specify a UTC timezone.
"""
def utcoffset(self, dt):
return datetime.timedelta(0)
def tzname(self, dt):
return "UTC"
def dst(self, dt):
return datetime.timedelta(0)