コード例 #1
0
    def __call__(self, form: "QuestionnaireForm", from_field: DateField,
                 to_field: DateField) -> None:
        from_date = parse_datetime(from_field.data)
        to_date = parse_datetime(to_field.data)

        if from_date and to_date:
            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)))
コード例 #2
0
def test_minimum_and_maximum_offset_dates(app, value_source_resolver, rule_evaluator):
    value_source_resolver.metadata = {"date": "2018-02-20"}
    answer_store = AnswerStore()

    test_answer_id = Answer(answer_id="date", value="2018-03-20")
    answer_store.add_or_update(test_answer_id)
    value_source_resolver.answer_store = answer_store
    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, value_source_resolver, rule_evaluator, error_messages)
    minimum_date = handler.get_date_value("minimum")
    maximum_date = handler.get_date_value("maximum")

    assert minimum_date == parse_datetime("2018-02-10")
    assert maximum_date == parse_datetime("2019-03-20")
def test_valid_single_date_period(mock_form, mock_field):
    minimum_date = parse_datetime("2016-03-20")
    maximum_date = parse_datetime("2016-03-31")
    validator = SingleDatePeriodCheck(
        minimum_date=minimum_date, maximum_date=maximum_date
    )

    mock_form.data = "2016-03-26"

    validator(mock_form, mock_field)
コード例 #4
0
def test_get_referenced_offset_value_with_list_item_id(
    app, value_source_resolver, rule_evaluator
):
    list_item_id = "abcde"

    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 = AnswerStore()

    answer_store.add_or_update(test_answer_id)
    value_source_resolver.answer_store = answer_store
    value_source_resolver.location = location
    value_source_resolver.list_item_id = list_item_id
    answer = {
        "maximum": {
            "value": {"identifier": "date", "source": "answers"},
            "offset_by": {"months": 1},
        }
    }

    handler = DateHandler(answer, value_source_resolver, rule_evaluator, error_messages)
    maximum_date = handler.get_date_value("maximum")

    assert maximum_date == parse_datetime("2018-04-20")
コード例 #5
0
def get_date_match_value(date_comparison, answer_store, schema, metadata):
    match_value = None

    if "value" in date_comparison:
        if date_comparison["value"] == "now":
            match_value = datetime.now(timezone.utc).strftime("%Y-%m-%d")
        else:
            match_value = date_comparison["value"]
    elif "id" in date_comparison:
        match_value = get_answer_value(date_comparison["id"], answer_store,
                                       schema)
    elif "meta" in date_comparison:
        match_value = get_metadata_value(metadata, date_comparison["meta"])

    match_value = parse_datetime(match_value)

    if "offset_by" in date_comparison and match_value:
        offset = date_comparison["offset_by"]
        match_value = match_value + relativedelta(
            days=offset.get("days", 0),
            months=offset.get("months", 0),
            years=offset.get("years", 0),
        )

    return match_value
コード例 #6
0
def test_get_referenced_offset_value_for_value(
    app, value_source_resolver, rule_evaluator
):
    answer = {"minimum": {"value": "2017-06-11"}}

    handler = DateHandler(answer, value_source_resolver, rule_evaluator, error_messages)
    minimum_date = handler.get_date_value("minimum")
    minimum_date = handler.transform_date_by_offset(minimum_date, {"days": 10})

    assert minimum_date == parse_datetime("2017-06-21")
def test_single_date_period_custom_message_invalid_raises(mock_form, mock_field):
    maximum_date = parse_datetime("2016-03-31")
    message = {"SINGLE_DATE_PERIOD_TOO_LATE": "Test %(max)s"}
    validator = SingleDatePeriodCheck(messages=message, maximum_date=maximum_date)
    mock_form.data = "2016-04-29"

    with pytest.raises(ValidationError) as exc:
        validator(mock_form, mock_field)

    assert "Test 1 April 2016" == str(exc.value)
コード例 #8
0
def test_get_referenced_offset_value_for_meta(
    app, value_source_resolver, rule_evaluator
):
    value_source_resolver.metadata = {"date": "2018-02-20"}
    answer = {"minimum": {"value": {"identifier": "date", "source": "metadata"}}}

    handler = DateHandler(answer, value_source_resolver, rule_evaluator, error_messages)
    minimum_date = handler.get_date_value("minimum")
    minimum_date = handler.transform_date_by_offset(minimum_date, {"days": -10})

    assert minimum_date == parse_datetime("2018-02-10")
コード例 #9
0
    def calculate_date_difference(first_date: str, second_date: str) -> str:

        time = relativedelta(
            parse_datetime(second_date),
            parse_datetime(first_date),
        )

        if time.years:
            year_string: str = ngettext("{number_of_years} year",
                                        "{number_of_years} years", time.years)
            return year_string.format(number_of_years=time.years)

        if time.months:
            month_string: str = ngettext("{number_of_months} month",
                                         "{number_of_months} months",
                                         time.months)
            return month_string.format(number_of_months=time.months)

        day_string: str = ngettext("{number_of_days} day",
                                   "{number_of_days} days", time.days)
        return day_string.format(number_of_days=time.days)
コード例 #10
0
def evaluate_date_rule(when, answer_store, schema, metadata, answer_value):
    date_comparison = when["date_comparison"]

    answer_value = parse_datetime(answer_value)
    match_value = get_date_match_value(date_comparison, answer_store, schema,
                                       metadata)
    condition = when.get("condition")

    if not answer_value or not match_value or not condition:
        return False

    # Evaluate the condition on the routing rule
    return evaluate_condition(condition, answer_value, match_value)
コード例 #11
0
def test_operation_date(date_string: str, offset, get_operator):
    operands = (date_string, offset)
    operator = get_operator(Operator.DATE)

    offset = offset or {}

    expected_result = (parse_datetime(date_string).date() + relativedelta(
        days=offset.get("days", 0),
        months=offset.get("months", 0),
        years=offset.get("years", 0),
    ) if date_string else None)

    assert operator.evaluate(operands) == expected_result
コード例 #12
0
def test_get_referenced_offset_value_for_answer_id(
    app, value_source_resolver, rule_evaluator
):
    answer_store = AnswerStore()

    test_answer_id = Answer(answer_id="date", value="2018-03-20")
    answer_store.add_or_update(test_answer_id)
    value_source_resolver.answer_store = answer_store
    answer = {"maximum": {"value": {"identifier": "date", "source": "answers"}}}

    handler = DateHandler(answer, value_source_resolver, rule_evaluator, error_messages)
    maximum_date = handler.get_date_value("maximum")
    maximum_date = handler.transform_date_by_offset(maximum_date, {"months": 1})

    assert maximum_date == parse_datetime("2018-04-20")
コード例 #13
0
    def __call__(self, form: "QuestionnaireForm", field: StringField) -> None:
        date = parse_datetime(form.data)

        if self.minimum_date and date and 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 and date and 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)))
コード例 #14
0
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 = parse_datetime(value).date()

    date = flask_babel.format_date(date_to_format, format=date_format)

    return f"<span class='date'>{date}</span>"
コード例 #15
0
    def resolve_date_from_string(
        date_string: Optional[str],
        offset: Optional[DateOffset] = None,
        offset_by_full_weeks: bool = False,
    ) -> Optional[date]:
        datetime_value = parse_datetime(date_string)
        if not datetime_value:
            return None

        value_as_date = datetime_value.date()

        if offset:
            days_offset = offset.get("days", 0)

            if day_of_week_offset := offset.get("day_of_week"):
                if 0 > days_offset > -7:
                    raise ValueError(
                        "Negative days offset must be less than or equal to -7 when used with `day_of_week` offset"
                    )

                days_difference = (
                    value_as_date.weekday() - DAYS_OF_WEEK[day_of_week_offset]
                )
                days_to_reduce = days_difference % 7

                if not offset_by_full_weeks and (
                    days_offset < 0 and days_difference < 0
                ):
                    # A negative day difference means that the `day_of_week` offset went back to the previous week;
                    # therefore, if we also have a negative days offset,
                    # then the no. of days we reduce the offset by must be adjusted by 7 to prevent going back two weeks.
                    days_to_reduce -= 7

                days_offset -= days_to_reduce

            value_as_date += relativedelta(
                days=days_offset,
                months=offset.get("months", 0),
                years=offset.get("years", 0),
            )
コード例 #16
0
def test_parse_datetime(date_string, date_format):
    expected_date = (parser.isoparse(date_string) if date_format == "iso8601"
                     else datetime.strptime(date_string, date_format))

    assert parse_datetime(date_string) == expected_date.replace(
        tzinfo=timezone.utc)
import pytest
from wtforms.validators import ValidationError

from app.forms import error_messages
from app.forms.validators import SingleDatePeriodCheck
from app.questionnaire.rules.utils import parse_datetime


@pytest.mark.parametrize(
    "validator,data,error_type,error_message",
    (
        (
            SingleDatePeriodCheck(minimum_date=parse_datetime("2016-03-31")),
            "2016-01-29",
            "SINGLE_DATE_PERIOD_TOO_EARLY",
            {"min": "30 March 2016"},
        ),
        (
            SingleDatePeriodCheck(maximum_date=parse_datetime("2016-03-31")),
            "2016-04-29",
            "SINGLE_DATE_PERIOD_TOO_LATE",
            {"max": "1 April 2016"},
        ),
    ),
)
@pytest.mark.usefixtures("app")
def test_single_date_period_invalid_raises_ValidationError(
    validator, data, error_type, error_message, mock_form, mock_field
):

    mock_form.data = data
コード例 #18
0
def test_parse_date_exception(date_string):
    with pytest.raises(ValueError):
        parse_datetime(date_string)
コード例 #19
0
def test_parse_datetime_now():
    assert parse_datetime("now") == datetime.now(timezone.utc)