def __call__(self, form, from_field, to_field): from_date = convert_to_datetime(from_field.data) to_date = convert_to_datetime(to_field.data) if from_date >= to_date: raise validators.ValidationError( self.messages['INVALID_DATE_RANGE']) answered_range_relative = relativedelta(to_date, from_date) if self.period_min: min_range = self._return_relative_delta(self.period_min) if self._is_first_relative_delta_largest(min_range, answered_range_relative): raise validators.ValidationError( self.messages['DATE_PERIOD_TOO_SMALL'] % dict(min=self._build_range_length_error(self.period_min))) if self.period_max: max_range = self._return_relative_delta(self.period_max) if self._is_first_relative_delta_largest(answered_range_relative, max_range): raise validators.ValidationError( self.messages['DATE_PERIOD_TOO_LARGE'] % dict(max=self._build_range_length_error(self.period_max)))
def test_minimum_and_maximum_offset_dates(self, mock1): test_metadata = {'date': '2018-02-20'} store = AnswerStore() test_answer_id = Answer( answer_id='date', answer_instance=1, group_instance=0, value='2018-03-20', ) store.add_or_update(test_answer_id) answer = { 'id': 'date_answer', 'type': 'Date', 'minimum': { 'meta': 'date', 'offset_by': { 'days': -10 } }, 'maximum': { 'answer_id': 'date', 'offset_by': { 'years': 1 } } } offset_dates = get_dates_for_single_date_period_validation( answer, store, metadata=test_metadata) self.assertEqual(offset_dates, (convert_to_datetime('2018-02-10'), convert_to_datetime('2019-03-20')))
def test_valid_single_date_period(): minimum_date = convert_to_datetime("2016-03-20") maximum_date = convert_to_datetime("2016-03-31") validator = SingleDatePeriodCheck(minimum_date=minimum_date, maximum_date=maximum_date) mock_form = Mock() mock_form.data = "2016-03-26" mock_field = Mock() validator(mock_form, mock_field)
def calculate_years_difference(from_str, to_str): if from_str is None or to_str is None: raise Exception( 'Valid date(s) not passed to calculate_years_difference filter') to_date = datetime.now() if to_str == 'now' else convert_to_datetime( to_str) from_date = convert_to_datetime(from_str) difference = relativedelta.relativedelta(to_date, from_date) year_string = flask_babel.ngettext('%(num)s year', '%(num)s years', difference.years) return year_string
def get_referenced_offset_value(answer_min_or_max, answer_store, metadata, group_instance=0): """ Gets value of the referenced date type, whether it is a value, id of an answer or a meta date. Then adds/subtracts offset from that value and returns the new offset value :param answer_min_or_max: The minimum or maximum object which contains the referenced value. :param answer_store: The current answer store :param metadata: metadata for reference meta dates :return: date value """ value = None if 'value' in answer_min_or_max: if answer_min_or_max['value'] == 'now': value = datetime.utcnow().strftime('%Y-%m-%d') else: value = answer_min_or_max['value'] elif 'meta' in answer_min_or_max: value = get_metadata_value(metadata, answer_min_or_max['meta']) elif 'answer_id' in answer_min_or_max: schema = load_schema_from_metadata(metadata) value = get_answer_store_value(answer_min_or_max['answer_id'], answer_store, schema, group_instance=group_instance) value = convert_to_datetime(value) if 'offset_by' in answer_min_or_max: offset = answer_min_or_max['offset_by'] value += relativedelta(years=offset.get('years', 0), months=offset.get('months', 0), days=offset.get('days', 0)) return value
def test_get_referenced_offset_value_with_list_item_id(app, schema_mock): list_item_id = "abcde" answer_store = AnswerStore() test_answer_id = Answer(answer_id="date", value="2018-03-20", list_item_id=list_item_id) location = Location(section_id="test", list_item_id=list_item_id) answer_store.add_or_update(test_answer_id) answer = { "maximum": { "value": { "identifier": "date", "source": "answers" }, "offset_by": { "months": 1 }, } } handler = DateHandler(answer, answer_store=answer_store, location=location) maximum_date = handler.get_date_value("maximum") assert maximum_date == convert_to_datetime("2018-04-20")
def format_date_range_no_repeated_month_year(context, start_date, end_date, date_format='d MMMM YYYY'): """ Format a date range, ensuring months and years are not repeated. If the dates are in the same year, the first year (YYYY) will be removed. If the dates are in the same month and year, the first year (YYYY) and month will be removed. e.g. Friday 1 to Sunday 3 October or Thursday 30 September to Sunday 3 October Assumptions: - The date format uses space as a seperator - The date format can have leading and trailing whitespace stripped :param (jinja2.nodes.EvalContext) context: Evaluation context. :param (str) start_date : The date format that should be used for output. MMMM, YYYY will be removed if necessary :param (str) end_date: The date format that should be used for output. MMMM, YYYY will be removed if necessary :param (str) date_format: The date format that should be used for output. MMMM, YYYY will be removed if necessary :returns (str): The formatted range. """ start_datetime = convert_to_datetime(start_date) end_datetime = convert_to_datetime(end_date) first_date_format = date_format if start_datetime.year == end_datetime.year: first_date_format = date_format.replace('YYYY', '') if start_datetime.month == end_datetime.month: first_date_format = first_date_format.replace('MMMM', '') # Cleanup any extra spaces in the new format string first_date_format = first_date_format.replace(' ', ' ').strip() if not first_date_format: # If the date format was entirely removed, leave it alone first_date_format = date_format output = flask_babel.gettext( '%(from_date)s to %(to_date)s', from_date=format_date_custom(context, start_date, first_date_format), to_date=format_date_custom(context, end_date, date_format)) return mark_safe(context, output)
def test_get_referenced_offset_value_with_no_offset(self): answer_minimum = { 'value': '2017-06-11', } value = get_referenced_offset_value(answer_minimum, AnswerStore(), {}) self.assertEqual(value, convert_to_datetime('2017-06-11'))
def test_get_referenced_offset_value_for_value(app): answer = {"minimum": {"value": "2017-06-11"}} handler = DateHandler(answer) minimum_date = handler.get_date_value("minimum") minimum_date = handler.transform_date_by_offset(minimum_date, {"days": 10}) assert minimum_date == convert_to_datetime("2017-06-21")
def test_get_referenced_offset_value_for_meta(self): test_metadata = {'date': '2018-02-20'} answer_minimum = {'meta': 'date', 'offset_by': {'days': -10}} value = get_referenced_offset_value(answer_minimum, AnswerStore(), test_metadata) self.assertEqual(value, convert_to_datetime('2018-02-10'))
def get_referenced_date(self, key): """ Gets value of the referenced date type, whether it is a value, id of an answer or a meta date. :return: date value """ value = self.get_schema_value(self.answer_schema[key]) if value == "now": value = datetime.utcnow().strftime("%Y-%m-%d") return convert_to_datetime(value)
def test_minimum_and_maximum_offset_dates(app): test_metadata = {"date": "2018-02-20"} store = AnswerStore() test_answer_id = Answer(answer_id="date", value="2018-03-20") store.add_or_update(test_answer_id) answer = { "id": "date_answer", "type": "Date", "minimum": { "value": { "identifier": "date", "source": "metadata" }, "offset_by": { "days": -10 }, }, "maximum": { "value": { "identifier": "date", "source": "answers" }, "offset_by": { "years": 1 }, }, } handler = DateHandler(answer, answer_store=store, metadata=test_metadata) minimum_date = handler.get_date_value("minimum") maximum_date = handler.get_date_value("maximum") assert minimum_date == convert_to_datetime("2018-02-10") assert maximum_date == convert_to_datetime("2019-03-20")
def test_get_referenced_offset_value_for_answer_id(self, mock1): store = AnswerStore() test_answer_id = Answer( answer_id='date', answer_instance=1, group_instance=0, value='2018-03-20', ) store.add_or_update(test_answer_id) answer_maximum = {'answer_id': 'date', 'offset_by': {'months': 1}} value = get_referenced_offset_value(answer_maximum, store, {}) self.assertEqual(value, convert_to_datetime('2018-04-20'))
def test_invalid_single_date_period_maximum_date(self): maximum_date = convert_to_datetime('2016-03-31') validator = SingleDatePeriodCheck(maximum_date=maximum_date) mock_form = Mock() mock_form.data = '2016-04-29' mock_field = Mock() with self.app_request_context('/'): with self.assertRaises(ValidationError) as ite: validator(mock_form, mock_field) self.assertEqual( error_messages['SINGLE_DATE_PERIOD_TOO_LATE'] % dict(max='1 April 2016'), str(ite.exception))
def test_invalid_single_date_period_with_bespoke_message(self): maximum_date = convert_to_datetime("2016-03-31") message = {"SINGLE_DATE_PERIOD_TOO_LATE": "Test %(max)s"} validator = SingleDatePeriodCheck(messages=message, maximum_date=maximum_date) mock_form = Mock() mock_form.data = "2016-04-29" mock_field = Mock() with self.app_request_context("/"): with self.assertRaises(ValidationError) as ite: validator(mock_form, mock_field) self.assertEqual("Test 1 April 2016", str(ite.exception))
def test_get_referenced_offset_value_for_meta(app): test_metadata = {"date": "2018-02-20"} answer = { "minimum": { "value": { "identifier": "date", "source": "metadata" } } } handler = DateHandler(answer, metadata=test_metadata) minimum_date = handler.get_date_value("minimum") minimum_date = handler.transform_date_by_offset(minimum_date, {"days": -10}) assert minimum_date == convert_to_datetime("2018-02-10")
def __call__(self, form, field): date = convert_to_datetime(form.data) if self.minimum_date: if date < self.minimum_date: raise validators.ValidationError( self.messages['SINGLE_DATE_PERIOD_TOO_EARLY'] % dict(min=self._format_playback_date( self.minimum_date + relativedelta(days=-1), self.date_format))) if self.maximum_date: if date > self.maximum_date: raise validators.ValidationError( self.messages['SINGLE_DATE_PERIOD_TOO_LATE'] % dict(max=self._format_playback_date( self.maximum_date + relativedelta(days=+1), self.date_format)))
def test_invalid_single_date_period_minimum_date(self): minimum_date = convert_to_datetime("2016-03-31") validator = SingleDatePeriodCheck(minimum_date=minimum_date) mock_form = Mock() mock_form.data = "2016-01-29" mock_field = Mock() with self.app_request_context("/"): with self.assertRaises(ValidationError) as ite: validator(mock_form, mock_field) self.assertEqual( error_messages["SINGLE_DATE_PERIOD_TOO_EARLY"] % dict(min="30 March 2016"), str(ite.exception), )
def test_invalid_single_date_period_maximum_date(self): maximum_date = convert_to_datetime("2016-03-31") validator = SingleDatePeriodCheck(maximum_date=maximum_date) mock_form = Mock() mock_form.data = "2016-04-29" mock_field = Mock() with self.app_request_context("/"): with self.assertRaises(ValidationError) as ite: validator(mock_form, mock_field) self.assertEqual( error_messages["SINGLE_DATE_PERIOD_TOO_LATE"] % {"max": "1 April 2016"}, str(ite.exception), )
def get_format_date(value): """Format a datetime string. :param (jinja2.nodes.EvalContext) context: Evaluation context. :param (any) value: Value representing a datetime. :returns (str): Formatted datetime. """ value = value[0] if isinstance(value, list) else value date_format = "d MMMM yyyy" if value and re.match(r"\d{4}-\d{2}$", value): date_format = "MMMM yyyy" if value and re.match(r"\d{4}$", value): date_format = "yyyy" date_to_format = convert_to_datetime(value).date() result = "<span class='date'>{date}</span>".format( date=flask_babel.format_date(date_to_format, format=date_format)) return result
def format_date(context, value): """Format a datetime string. :param (jinja2.nodes.EvalContext) context: Evaluation context. :param (any) value: Value representing a datetime. :returns (str): Formatted datetime. """ value = value[0] if isinstance(value, list) else value if not isinstance(value, str): return value date_format = 'd MMMM YYYY' if value and re.match(r'\d{4}-\d{2}$', value): date_format = 'MMMM YYYY' if value and re.match(r'\d{4}$', value): date_format = 'YYYY' result = "<span class='date'>{date}</span>".format( date=flask_babel.format_date(convert_to_datetime(value), format=date_format)) return mark_safe(context, result)
def test_get_referenced_offset_value_for_answer_id(app): answer_store = AnswerStore() test_answer_id = Answer(answer_id="date", value="2018-03-20") answer_store.add_or_update(test_answer_id) answer = { "maximum": { "value": { "identifier": "date", "source": "answers" } } } handler = DateHandler(answer, answer_store=answer_store) maximum_date = handler.get_date_value("maximum") maximum_date = handler.transform_date_by_offset(maximum_date, {"months": 1}) assert maximum_date == convert_to_datetime("2018-04-20")
def test_get_referenced_offset_value_for_value(self): answer_minimum = {'value': '2017-06-11', 'offset_by': {'days': 10}} value = get_referenced_offset_value(answer_minimum, AnswerStore(), {}) self.assertEqual(value, convert_to_datetime('2017-06-21'))