def wizard_ranges(launch_date_unrounded): """ Return the active_when ranges to be used by the wizard Returns (active_all, active_call_text, active_forward_to) where: - active_forward_text runs from 8am on launch day, or 3 hours before the launch (whichever is earlier), until 3 hours after the launch - active_call_text runs from midnight 3 days in advance (round down to midnight) until active_forward_text starts - active_all covers both Lower bounds are rounded down, and upper bounds up, to whole hours. """ hours = lambda n: datetime.timedelta(hours=n) launch_date = launch_date_unrounded \ .replace(minute=0, second=0, microsecond=0) start_forward_to = min(launch_date - hours(3), launch_date.replace(hour=8)) end_forward_to = launch_date + hours(3) if launch_date != launch_date_unrounded: end_forward_to += hours(1) # round up start_call_text = launch_date.replace(hour=0) - datetime.timedelta(days=3) return (DateTimeRange(start_call_text, end_forward_to, bounds='[)'), DateTimeRange(start_call_text, start_forward_to, bounds='[)'), DateTimeRange(start_forward_to, end_forward_to, bounds='[)'))
def test_register_serializer_for_migrations(self): tests = ( (DateRange(empty=True), DateRangeField), (DateTimeRange(empty=True), DateRangeField), (DateTimeTZRange(None, None, '[]'), DateTimeRangeField), (NumericRange(Decimal('1.0'), Decimal('5.0'), '()'), DecimalRangeField), (NumericRange(1, 10), IntegerRangeField), ) def assertNotSerializable(): for default, test_field in tests: with self.subTest(default=default): field = test_field(default=default) with self.assertRaisesMessage(ValueError, 'Cannot serialize: %s' % default.__class__.__name__): MigrationWriter.serialize(field) assertNotSerializable() with self.modify_settings(INSTALLED_APPS={'append': 'django.contrib.postgres'}): for default, test_field in tests: with self.subTest(default=default): field = test_field(default=default) serialized_field, imports = MigrationWriter.serialize(field) self.assertEqual(imports, { 'import django.contrib.postgres.fields.ranges', 'import psycopg2.extras', }) self.assertIn( '%s.%s(default=psycopg2.extras.%r)' % ( field.__module__, field.__class__.__name__, default, ), serialized_field ) assertNotSerializable()
def get_date_time_range(date_string, schedule_string, duration_string): # DETERMINE DAY MONTH YEAR match = re.match(from_to_regex, date_string) if match is not None: matches = match.group(1, 2, 3, 4) if all(matches): month = matches[2] year = matches[3] day_strings = [ year + '-' + parse_datetime(month, date_formats=['%B']).strftime('%m') + '-' + str(day) for day in range(int(matches[0]), int(matches[1])) ] else: day_string = parse_datetime(date_string, date_formats=['%E %dd %B %Y']) if day_string is not None: day_strings = [day_string.strftime(DAY_FORMAT)] # DETERMINE START AND END SCHEDULE end_hour_string = None if 'et' in schedule_string: return [DateTimeRange()] if '-' in schedule_string: (start_hour_string, end_hour_string) = schedule_string.split('-') format_end_hour_string = get_format_timedelta_string(end_hour_string) else: start_hour_string = schedule_string format_start_hour_string = get_format_timedelta_string(start_hour_string) # DETERMINE DURATION duration = parse_timedelta(duration_string) # CONCAT date_time_ranges = [None] * (len(day_strings)) for (index, day_string) in list(enumerate(day_strings)): start_date_string = day_string + 'T' + format_start_hour_string + 'Z' start_date = read_date(start_date_string) if end_hour_string is not None: end_date_string = day_string + 'T' + format_end_hour_string + 'Z' end_date = read_date(end_date_string) else: end_date = start_date + duration date_time_ranges[index] = DateTimeRange(start_date, end_date) # RETURN return date_time_ranges
def parse_message_edit_form(): """ Parse message_edit.html's form from request.form into a message dict Tolerates: - active_when missing: ignored (the active_when key is ommitted) Parse failure actions: - forward_to integer parsing fails: 400 Bad Request (from intbrq) - datetime parse failure: Store active_when as a dict (rather than DateTimeRange) in form {"lower": string, "upper": string} for repopulating the form (attributes vs items is not an issue for jinja2); set message["active_when_invalid"] to true. It's up to the caller to check call_text xor forward_to, whether "active_when" is present, and whether active_when_invalid is set, as appropriate. """ message = {} for key in ("short_name", "web_short_text", "web_long_text", "call_text", "forward_to"): message[key] = request.form[key] if message["call_text"] == "": message["call_text"] = None if message["forward_to"] == "": message["forward_to"] = None else: message["forward_to"] = intbrq(message["forward_to"]) try: lower = parse_datetime(request.form["active_when_lower"]) upper = parse_datetime(request.form["active_when_upper"]) if lower >= upper: raise ValueError except KeyError: pass except ValueError: # Note that we could produce a KeyError here if _lower is present # but _upper is not. This is not an issue, since a client sending # only is clearly a bad client and deserves the HTTP 400 it will get. message["active_when"] = { "lower": request.form["active_when_lower"], "upper": request.form["active_when_upper"] } message["active_when_invalid"] = True else: message["active_when"] = DateTimeRange(lower, upper, bounds='[)') return message
def __init__(self, **kw): value_from = kw.pop('value_from', None) value_to = kw.pop('value_to', None) if value_from or value_to: if 'period' in kw: raise TypeError( 'period not allowed if value_from or value_to used') period = DateTimeRange(value_from, value_to) else: period = kw.pop('period', None) super(Temporal, self).__init__(period=period, **kw)
def test_write_tsrange(self): test_value = DateTimeRange(datetime.datetime(2014, 6, 8, 12, 12, 45), datetime.datetime(2016, 7, 6, 14, 12, 8)) test_columns_info = [] col = DbColumn() col.data_type = datatypes.DATATYPE_TSRANGE test_columns_info.append(col) mock_storage_data_reader = MockStorageDataReader(self._cursor, test_columns_info) mock_storage_data_reader.get_value = mock.MagicMock(return_value=test_value) res = self._writer.write_row(mock_storage_data_reader) self.assertEqual(self.get_expected_length_with_additional_buffer_for_size(len("[2014-06-08T12:12:45,2016-07-06T14:12:08)")), res)
def write_nap(cur, guard_id, nap_start, nap_end): during = DateTimeRange(lower=nap_start, upper=nap_end, bounds="[)") cur.execute( """ insert into naps (guard_id, during) values (%s, %s) """, (guard_id, during), ) global WROTE WROTE += 1
def default_active_when(): """ Return a default DateTimeRange to popualate new message row forms The lower bound is tomorrow at midnight, the upper is the midnight after. """ today = datetime.datetime.now() \ .replace(hour=0, minute=0, second=0, microsecond=0) days = lambda n: datetime.timedelta(days=n) lower = today + days(1) upper = today + days(2) return DateTimeRange(lower, upper, bounds='[)')
def _apply_time_range_filters(query, start_time, end_time): if type(start_time) is date: start_time = datetime(start_time.year, start_time.month, start_time.day) if type(end_time) is date: end_time = datetime(end_time.year, end_time.month, end_time.day, 23, 59, 59) if start_time or end_time: return query.filter( func.tsrange(Activity.start_time, Activity.end_time, "[]").op("&&")(DateTimeRange(start_time, end_time, "[)"))) return query
def parse_datetimerange(s): tok = Token(s) t, x = tok.next() if t != 'b_bound': raise ParseError("Expected %s in the beginning; found '%s'" % (tuple2str(B_BOUND), x)) bounds = x t, x = tok.next() if t not in ('delim', 'datetime'): raise ParseError( "Expected datetime string or ',' after '%s'; found '%s'" % (bounds, x)) if t == 'datetime': t1 = parse_datetime(x) t, x = tok.next() if t != 'delim': raise ParseError( "Expected ',' after first datetime string; found '%s'" % x) else: t1 = None t, x = tok.next() if t not in ('datetime', 'e_bound'): raise ParseError( "Expected datetime string or %s after ','; found '%s'" % (tuple2str(E_BOUND), x)) if t == 'datetime': t2 = parse_datetime(x) t, x = tok.next() else: t2 = None if t != 'e_bound': raise ParseError("Expected %s at the end" % tuple2str(E_BOUND)) bounds += x return DateTimeRange(t1, t2, bounds)
def test_register_serializer_for_migrations(self): tests = ( (DateRange(empty=True), DateRangeField), (DateTimeRange(empty=True), DateRangeField), (DateTimeTZRange(None, None, "[]"), DateTimeRangeField), (NumericRange(Decimal("1.0"), Decimal("5.0"), "()"), DecimalRangeField), (NumericRange(1, 10), IntegerRangeField), ) def assertNotSerializable(): for default, test_field in tests: with self.subTest(default=default): field = test_field(default=default) with self.assertRaisesMessage( ValueError, "Cannot serialize: %s" % default.__class__.__name__): MigrationWriter.serialize(field) assertNotSerializable() with self.modify_settings( INSTALLED_APPS={"append": "django.contrib.postgres"}): for default, test_field in tests: with self.subTest(default=default): field = test_field(default=default) serialized_field, imports = MigrationWriter.serialize( field) self.assertEqual( imports, { "import django.contrib.postgres.fields.ranges", "import psycopg2.extras", }, ) self.assertIn( "%s.%s(default=psycopg2.extras.%r)" % ( field.__module__, field.__class__.__name__, default, ), serialized_field, ) assertNotSerializable()
def _normalize_coerce_tsrange(self, value): datetimes = map( lambda x: datetime.datetime.strptime(x, '%Y-%m-%d %H:%M:%S'), value) return DateTimeRange(*datetimes)
def value_to(self, timestamp): if self.period is None: lower = None else: lower = self.period.lower self.period = DateTimeRange(lower, timestamp)
def process(value): if value: return DateTimeRange(value[0], value[1])
def test_normalise_hypothesis_tsrange(self, a): a = DateTimeRange(*a) cursor = connection.cursor() cursor.execute("SELECT %s::tsrange", [a]) self.assertEqual(cursor.fetchone()[0], normalise(a), a)
def test_with_hypothesis_datetimes(self, a, b): a = DateTimeRange(*a) b = DateTimeRange(*b) cursor = connection.cursor() cursor.execute("SELECT %s::tsrange && %s::tsrange", [a, b]) self.assertEqual(cursor.fetchone()[0], a & b, "{} && {}".format(a, b))
class TestTableTypes(TrackedTable): name = 'test_table_types' default_values = OrderedDict([ ('test_table_types_bool', True), ('test_table_types_real', 9.99), ('test_table_types_double', 9.99), ('test_table_types_smallint', 9), ('test_table_types_integer', 50000), ('test_table_types_bigint', 5000000000), ('test_table_types_numeric', Decimal('1.1')), ('test_table_types_varchar', 'hi there'), ('test_table_types_text', 'hi there'), ('test_table_types_bytea', b'hi there'), ('test_table_types_date', date(year=1991, month=11, day=11)), ('test_table_types_time', time(hour=11, minute=39, second=22)), ('test_table_types_timetz', time(hour=11, minute=39, second=22, tzinfo=pytz.utc)), ('test_table_types_timestamp', datetime(year=1991, month=11, day=11, hour=11, minute=39, second=22)), ('test_table_types_timestamptz', datetime(year=1991, month=11, day=11, hour=11, minute=39, second=22, tzinfo=pytz.utc)), ('test_table_types_interval', timedelta(hours=15)), ('test_table_types_array', ['a', 'b', 'c', 'd', 'e']), # ('test_table_types_hstore', {'a': 1, 'b': 2, 'c': 3}), this dict would be passed to test_table_types_hstore ('test_table_types_int4range', NumericRange(lower=1, upper=10)), ('test_table_types_int8range', NumericRange(lower=1, upper=50000)), ('test_table_types_numrange', NumericRange(lower=Decimal('0.1'), upper=Decimal('1.1'))), ('test_table_types_daterange', DateRange( lower=date(year=1991, month=11, day=11), upper=date(year=1991, month=11, day=21), )), ('test_table_types_tsrange', DateTimeRange( lower=datetime(year=1991, month=11, day=11, hour=11, minute=39, second=22), upper=datetime(year=1991, month=11, day=21, hour=11, minute=39, second=22), )), ('test_table_types_tstzrange', DateTimeTZRange( lower=datetime(year=1991, month=11, day=11, hour=11, minute=39, second=22, tzinfo=pytz.utc), upper=datetime(year=1991, month=11, day=21, hour=11, minute=39, second=22, tzinfo=pytz.utc), )), # ('test_table_types_uuid', UUID(bytes=b'1234567890123456')), # ('test_table_types_inet', ip_network('192.168.0.0')), # ('test_table_types_cidr', ip_network('192.168.0.0')), ('test_table_types_json', json.dumps(['a', {'b': 2}, 2])), ('test_table_types_jsonb', json.dumps(['a', {'b': 2}, 2])), ]) def build(self, cursor=None): if not cursor: cursor = self.get_cursor() cursor.execute( "CREATE TABLE test_table_types (" "test_table_types_bool bool DEFAULT %s, " "test_table_types_real real DEFAULT %s, " "test_table_types_double double precision DEFAULT %s, " "test_table_types_smallint smallint DEFAULT %s, " "test_table_types_integer integer DEFAULT %s, " "test_table_types_bigint bigint DEFAULT %s, " "test_table_types_numeric numeric DEFAULT %s, " "test_table_types_varchar varchar DEFAULT %s, " "test_table_types_text text DEFAULT %s, " "test_table_types_bytea bytea DEFAULT %s, " "test_table_types_date date DEFAULT %s, " "test_table_types_time time DEFAULT %s, " "test_table_types_timetz timetz DEFAULT %s, " "test_table_types_timestamp timestamp DEFAULT %s, " "test_table_types_timestamptz timestamptz DEFAULT %s, " "test_table_types_interval interval DEFAULT %s, " "test_table_types_array text[] DEFAULT %s, " # "test_table_types_hstore hstore DEFAULT %s, " hstore is unused. "test_table_types_int4range int4range DEFAULT %s, " "test_table_types_int8range int8range DEFAULT %s, " "test_table_types_numrange numrange DEFAULT %s, " "test_table_types_daterange daterange DEFAULT %s, " "test_table_types_tsrange tsrange DEFAULT %s, " "test_table_types_tstzrange tstzrange DEFAULT %s, " # "test_table_types_uuid uuid DEFAULT %s, " uuid is unused. # "test_table_types_inet inet DEFAULT %s, " inet types are unused. # "test_table_types_cidr cidr DEFAULT %s, " "test_table_types_json json DEFAULT %s, " "test_table_types_jsonb jsonb DEFAULT %s " ")", list(self.default_values.values()) ) for i in range(1000): cursor.execute("INSERT INTO test_table_types DEFAULT VALUES")
def value_from(self, timestamp): if self.period is None: upper = None else: upper = self.period.upper self.period = DateTimeRange(timestamp, upper)