Skip to content

Commit

Permalink
Merged in rs-fix-parsing-logic-2 (pull request #29)
Browse files Browse the repository at this point in the history
Rs fix parsing logic 2
  • Loading branch information
RomainMapado committed Sep 15, 2016
2 parents 4fe7bb8 + 972414d commit 5fbc09a
Show file tree
Hide file tree
Showing 3 changed files with 154 additions and 6 deletions.
6 changes: 6 additions & 0 deletions datection/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -340,3 +340,9 @@ def unlimited_date_interval(self):
if not end_date:
return False
return (end_date - start_date).days > 8 * 30

@property
def has_timings(self):
return (
self.duration < ALL_DAY
)
87 changes: 81 additions & 6 deletions datection/render.py
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,18 @@ def groupby_date(dt_intervals):
for group in dates.values()]


def group_recurring_by_date_interval(recurrings):
"""
Groups the given WeeklyRecurences by date interval
@param recurrings: list(WeeklyRecurences)
"""
out = defaultdict(list)
for rec in recurrings:
out[rec.date_interval].append(rec)
return [value for (key, value) in sorted(out.items())]


def group_recurring_by_day(recurrings):
"""
Groups the given WeeklyRecurences by weekay index
Expand Down Expand Up @@ -952,9 +964,9 @@ def format_weekday_interval(self):
self._('and'), self.day_name(end_idx))
return fmt

def format_date_interval(self, *args, **kwargs):
def format_date_interval(self, no_date=False, *args, **kwargs):
"""Format the rrule date interval using the current locale."""
if not self.drr.bounded:
if not self.drr.bounded or no_date:
return u''
formatter = DateIntervalFormatter(
self.drr.start_datetime, self.drr.end_datetime)
Expand All @@ -968,16 +980,48 @@ def format_time_interval(self):
return formatter.display(prefix=True)

@postprocess(lstrip_pattern=',')
def display(self, *args, **kwargs):
def display(self, no_date=False, *args, **kwargs):
"""Display a weekday recurrence using the current locale."""
template = self.get_template('weekday_reccurence')
weekdays = self.format_weekday_interval()
dates = self.format_date_interval()
dates = self.format_date_interval(no_date)
time = self.format_time_interval()
fmt = template.format(weekdays=weekdays, dates=dates, time=time)
return fmt


class WeekdayReccurenceGroupFormatter(BaseFormatter):
"""
Formats the group of weekday recurrence sharing the same date interval
"""

def __init__(self, drr_list):
"""
@param drr_list: list(WeeklyRecurences) sharing the same date interval
"""
super(WeekdayReccurenceGroupFormatter, self).__init__()
self.drr_list = [get_drr(drr) for drr in drr_list]
self.drr_grouped_by_days = group_recurring_by_day(self.drr_list)

def display(self, *args, **kwargs):
"""
Formats the group of weekday recurrence sharing the same date interval
"""
if len(self.drr_grouped_by_days) == 1:
fmt = WeekdayReccurenceFormatter(self.drr_grouped_by_days[0])
return fmt.display()
else:
start_date = self.drr_list[0].date_interval[0]
end_date = self.drr_list[0].date_interval[1]
date_fmt = DateIntervalFormatter(start_date, end_date)
date_str = date_fmt.display()
output = date_str + ":\n"
for rec_grp in self.drr_grouped_by_days:
fmt = WeekdayReccurenceFormatter(rec_grp)
output += "- %s\n" % fmt.display(no_date=True)
return output


class NextOccurenceFormatter(BaseFormatter, NextDateMixin, NextChangesMixin):

"""Object in charge of generating the shortest human readable
Expand Down Expand Up @@ -1147,6 +1191,7 @@ def __init__(self, schedule, apply_exlusion=True, format_exclusion=True):
self.schedule = [
DurationRRule(drr, apply_exlusion) for drr in schedule]
self.schedule = self.deduplicate(self.schedule)
self.schedule = self.filter_non_informative(self.schedule)
self.format_exclusion = format_exclusion
self.templates = {
'fr_FR': u'{dates} {time}',
Expand All @@ -1158,6 +1203,18 @@ def recurring(self):
"""Select recurring rrules from self.schedule"""
return [drr for drr in self.schedule if drr.is_recurring]

@cached_property
def bounded_recurrings(self):
"""Select recurring rrules from self.schedule"""
return [drr for drr in self.schedule if drr.is_recurring and
drr.bounded]

@cached_property
def unlimited_recurrings(self):
"""Select recurring rrules from self.schedule"""
return [drr for drr in self.schedule if drr.is_recurring and
drr.unlimited]

@cached_property
def non_special(self):
"""Return all the non-continuous, non-recurring, non-excluded
Expand Down Expand Up @@ -1204,6 +1261,22 @@ def _filterby_year_and_month(dates, year, month):
if date['start'].year == year
if date['start'].month == month]

def filter_non_informative(self, schedules):
"""
Removes schedules which do not add any information to the
schedule list. (e.g: more vague than the others).
@param schedules: list(DurationRRule)
"""
output = schedules
has_time_lvl_schedule = any([sched for sched in output if
sched.has_timings])

if has_time_lvl_schedule:
output = [sched for sched in output if sched.has_timings]

return output

def format_single_dates_and_interval(self, conseq_groups, *args, **kwargs):
""" First formatting technique, using dates interval
Expand Down Expand Up @@ -1323,10 +1396,12 @@ def display(self, *args, **kwargs):
out.append(ExclusionFormatter(exc).display(*args, **kwargs))

# format recurring rrules
for rec_group in group_recurring_by_day(self.recurring):
for rec_group in group_recurring_by_day(self.unlimited_recurrings):
out.append(
WeekdayReccurenceFormatter(rec_group).display(*args, **kwargs))

for rec_group in group_recurring_by_date_interval(self.bounded_recurrings):
out.append(
WeekdayReccurenceGroupFormatter(rec_group).display(*args, **kwargs))
# format continuous rrules
for con in self.continuous:
start, end = con.start_datetime, con.end_datetime
Expand Down
67 changes: 67 additions & 0 deletions datection/test/test_render.py
Original file line number Diff line number Diff line change
Expand Up @@ -1070,6 +1070,73 @@ def test_display_excluded_datetime(self):
fmt.display(),
u"Du jeudi 5 au samedi 28 mars 2015 de 8 h à 9 h, sauf le 17 mars 2015")

def test_regrouping_weekdays_by_interval(self):
# Du 30 septembre au 11 octobre 2015:
# - du mercredi au samedi, de 20 h à 21 h
# - le dimanche, de 17 h à 18 h
#
# Du 20 au 22 octobre 2015:
# - du mardi au samedi, de 20 h à 21 h
# - le dimanche, de 17 h à 18 h
schedule = [
{
"duration": 60,
"rrule": ("DTSTART:20151020\nRRULE:FREQ=DAILY;"
"UNTIL=20151022T235959;INTERVAL=1;BYMINUTE=00;"
"BYHOUR=20;BYDAY=TU,WE,TH,FR,SA")
},
{
"duration": 60,
"rrule": ("DTSTART:20151020\nRRULE:FREQ=DAILY;"
"UNTIL=20151022T235959;INTERVAL=1;BYMINUTE=00;"
"BYHOUR=17;BYDAY=SU")
},
{
"duration": 60,
"rrule": ("DTSTART:20150930\nRRULE:FREQ=DAILY;"
"UNTIL=20151011T235959;INTERVAL=1;BYMINUTE=00;"
"BYHOUR=20;BYDAY=WE,TH,FR,SA")
},
{
"duration": 60,
"rrule": ("DTSTART:20150930\nRRULE:FREQ=DAILY;"
"UNTIL=20151011T235959;INTERVAL=1;BYMINUTE=00;"
"BYHOUR=17;BYDAY=SU")
},
]
fmt = LongFormatter(schedule)
self.assertEqual(
fmt.display(),
u'Du 30 septembre au 11 octobre 2015:\n'
u'- du mercredi au samedi, de 20 h \xe0 21 h\n'
u'- le dimanche, de 17 h \xe0 18 h\n'
u'\n'
u'Du 20 au 22 octobre 2015:\n'
u'- du mardi au samedi, de 20 h \xe0 21 h\n'
u'- le dimanche, de 17 h \xe0 18 h\n')

def test_filter_non_informative(self):
# test the filtering of the rrule without time information
# in case there is a more precise rule
schedule = [
{
"duration": 0,
"rrule": ("DTSTART:20151223\nRRULE:FREQ=DAILY;COUNT=1;"
"INTERVAL=1;BYMINUTE=00;BYHOUR=20;"
"BYDAY=MO,TU,WE,TH,FR,SA,SU")
},
{
"duration": 1439,
"rrule": ("DTSTART:20151215\nRRULE:FREQ=DAILY;"
"UNTIL=20151231T235959;INTERVAL=1;BYMINUTE=0;"
"BYHOUR=0;BYDAY=MO,TU,WE,TH,FR,SA,SU")
},
]
fmt = LongFormatter(schedule)
self.assertEqual(
fmt.display(),
u'Le mercredi 23 décembre 2015 à 20 h')


class TestSeoFormatter_fr_FR(GetCurrentDayMocker):

Expand Down

0 comments on commit 5fbc09a

Please sign in to comment.