Merge branch 'master' of ssh://lausser,shinken@shinken.git.sourceforge.net/gitroot...
[shinken.git] / shinken / objects / timeperiod.py
blob512a2ef4c2a5adeca94e2bf226714ab7577eb680
1 #!/usr/bin/env python
2 #Copyright (C) 2009-2010 :
3 # Gabes Jean, naparuba@gmail.com
4 # Gerhard Lausser, Gerhard.Lausser@consol.de
5 # Gregory Starck, g.starck@gmail.com
6 # Hartmut Goebel, h.goebel@goebel-consult.de
8 #This file is part of Shinken.
10 #Shinken is free software: you can redistribute it and/or modify
11 #it under the terms of the GNU Affero General Public License as published by
12 #the Free Software Foundation, either version 3 of the License, or
13 #(at your option) any later version.
15 #Shinken is distributed in the hope that it will be useful,
16 #but WITHOUT ANY WARRANTY; without even the implied warranty of
17 #MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 #GNU Affero General Public License for more details.
20 #You should have received a copy of the GNU Affero General Public License
21 #along with Shinken. If not, see <http://www.gnu.org/licenses/>.
24 #Calendar date: '(\d{4})-(\d{2})-(\d{2}) - (\d{4})-(\d{2})-(\d{2}) / (\d+) ([0-9:, -]+)' => len = 8 => CALENDAR_DATE
25 # '(\d{4})-(\d{2})-(\d{2}) / (\d+) ([0-9:, -]+)' => len = 5 => CALENDAR_DATE
26 # '(\d{4})-(\d{2})-(\d{2}) - (\d{4})-(\d{2})-(\d{2}) ([0-9:, -]+)' => len = 7 => CALENDAR_DATE
27 # '(\d{4})-(\d{2})-(\d{2}) ([0-9:, -]+)' => len = 4 => CALENDAR_DATE
29 #Month week day:'([a-z]*) (\d+) ([a-z]*) - ([a-z]*) (\d+) ([a-z]*) / (\d+) ([0-9:, -]+)' => len = 8 => MONTH WEEK DAY
30 # ex: wednesday 1 january - thursday 2 july / 3
32 # '([a-z]*) (\d+) - ([a-z]*) (\d+) / (\d+) ([0-9:, -]+)' => len = 6
33 # ex: february 1 - march 15 / 3 => MONTH DATE
34 # ex: monday 2 - thusday 3 / 2 => WEEK DAY
35 # ex: day 2 - day 6 / 3 => MONTH DAY
37 # '([a-z]*) (\d+) - (\d+) / (\d+) ([0-9:, -]+)' => len = 6
38 # ex: february 1 - 15 / 3 => MONTH DATE
39 # ex: thursday 2 - 4 => WEEK DAY
40 # ex: day 1 - 4 => MONTH DAY
42 # '([a-z]*) (\d+) ([a-z]*) - ([a-z]*) (\d+) ([a-z]*) ([0-9:, -]+)' => len = 7
43 # ex: wednesday 1 january - thursday 2 july => MONTH WEEK DAY
45 # '([a-z]*) (\d+) - (\d+) ([0-9:, -]+)' => len = 7
46 # ex: thursday 2 - 4 => WEEK DAY
47 # ex: february 1 - 15 / 3 => MONTH DATE
48 # ex: day 1 - 4 => MONTH DAY
50 # '([a-z]*) (\d+) - ([a-z]*) (\d+) ([0-9:, -]+)' => len = 5
51 # ex: february 1 - march 15 => MONTH DATE
52 # ex: monday 2 - thusday 3 => WEEK DAY
53 # ex: day 2 - day 6 => MONTH DAY
55 # '([a-z]*) (\d+) ([0-9:, -]+)' => len = 3
56 # ex: february 3 => MONTH DATE
57 # ex: thursday 2 => WEEK DAY
58 # ex: day 3 => MONTH DAY
60 # '([a-z]*) (\d+) ([a-z]*) ([0-9:, -]+)' => len = 4
61 # ex: thusday 3 february => MONTH WEEK DAY
63 # '([a-z]*) ([0-9:, -]+)' => len = 6
64 # ex: thusday => normal values
66 #Types: CALENDAR_DATE
67 # MONTH WEEK DAY
68 # WEEK DAY
69 # MONTH DATE
70 # MONTH DAY
72 import re
73 import time
75 from item import Item, Items
76 from shinken.util import *
79 from shinken.daterange import Daterange,CalendarDaterange,StandardDaterange,MonthWeekDayDaterange
80 from shinken.daterange import MonthDateDaterange,WeekDayDaterange,MonthDayDaterange
81 from shinken.brok import Brok
82 from shinken.property import IntegerProp, StringProp, ListProp
85 class Timeperiod(Item):
86 id = 1
87 my_type = 'timeperiod'
89 properties = {
90 'timeperiod_name': StringProp (fill_brok=['full_status']),
91 'alias': StringProp (default='',fill_brok=['full_status']),
92 'use': StringProp (default=''),
93 'exclude': StringProp (default=''),
94 'register': IntegerProp(default='1'),
95 #All errors and warning raised during the configuration parsing
96 #and taht will raised real warning/errors during the is_correct
97 'configuration_warnings': ListProp(default=[]),
98 'configuration_errors': ListProp(default=[]),
99 # These are needed if a broker module calls methods on timeperiod objects
100 'dateranges': ListProp (fill_brok=['full_status'], default=[]),
101 'exclude': ListProp (fill_brok=['full_status'], default=[]),
105 def __init__(self, params={}):
106 self.id = Timeperiod.id
107 Timeperiod.id = Timeperiod.id + 1
108 self.unresolved = []
109 self.dateranges = []
110 self.exclude = ''
111 self.customs = {}
112 self.plus = {}
113 self.invalid_entries = []
114 for key in params:
115 if key in ['name', 'alias', 'timeperiod_name', 'exclude', 'use', 'register']:
116 setattr(self, key, params[key])
117 else:
118 self.unresolved.append(key+' '+params[key])
120 self.cache = {} #For tunning purpose only
121 self.configuration_errors = []
122 self.configuration_warnings = []
125 def get_name(self):
126 return self.timeperiod_name
129 def clean(self):
130 pass
133 #We fillfull properties with template ones if need
134 #for the unresolved values (like sunday ETCETC)
135 def get_unresolved_properties_by_inheritance(self, items):
136 #Ok, I do not have prop, Maybe my templates do?
137 #Same story for plus
138 for i in self.templates:
139 self.unresolved.extend(i.unresolved)
143 def is_time_valid(self, t):
144 if self.has('exclude'):
145 for dr in self.exclude:
146 if dr.is_time_valid(t):
147 return False
148 for dr in self.dateranges:
149 if dr.is_time_valid(t):
150 return True
151 return False
154 #will give the first time > t which is valid
155 def get_min_from_t(self, t):
156 mins_incl = []
157 for dr in self.dateranges:
158 mins_incl.append(dr.get_min_from_t(t))
159 return min(mins_incl)
162 #will give the first time > t which is not valid
163 def get_not_in_min_from_t(self, f):
164 pass
167 def find_next_valid_time_from_cache(self, t):
168 try:
169 return self.cache[t]
170 except KeyError:
171 return None
174 #clean the get_next_valid_time_from_t cache
175 #The entries are a dict on t. t < now are useless
176 #Because we do not care about past anymore.
177 #If not, it's not important, it's just a cache after all :)
178 def clean_cache(self):
179 now = int(time.time())
180 t_to_del = []
181 for t in self.cache:
182 if t < now:
183 t_to_del.append(t)
184 for t in t_to_del:
185 del self.cache[t]
188 def get_next_valid_time_from_t(self, t):
189 #first find from cache
190 t = int(t)
191 original_t = t
193 #print self.get_name(), "Check valid time for", time.asctime(time.localtime(t))
195 res_from_cache = self.find_next_valid_time_from_cache(t)
196 if res_from_cache is not None:
197 return res_from_cache
199 still_loop = True
201 local_min = None
202 #Loop for all minutes...
203 while still_loop:
204 #print self.get_name(), '\nLoop'
205 #Ok, not in cache...
206 dr_mins = []
207 for dr in self.dateranges:
208 dr_mins.append(dr.get_next_valid_time_from_t(t))
210 #print "TOTO", self.get_name(), 'Mins:', dr_mins
211 #for o in dr_mins:
212 # print "FUCK",time.asctime(time.localtime(o)), "\n"
214 #Min but not the None valus...
215 try:
216 local_min = min([d for d in dr_mins if d is not None])
217 except ValueError: #dr_mins if full of None, not good
218 local_min = None
220 #if local_min != None:
221 # print "Poposed?", local_min
222 # print "Proposed local min", time.asctime(time.localtime(local_min))
225 #We do not loop unless the local_min is not valid
226 still_loop = False
228 #if we've got a real value, we check it with the exclude
229 if local_min is not None:
230 #Now check if local_min is not valid
231 for tp in self.exclude:
232 #print self.get_name(), "Check in TP"
233 if tp.is_time_valid(local_min):
234 still_loop = True
235 #t = local_min + 60
236 #print self.get_name(), "TP pas content:", tp.get_name(), time.asctime(time.localtime(local_min))
237 local_min = tp.get_next_invalid_time_from_t(local_min+60)
238 #if local_min != None:
239 # print "Exclude TP proposed new local min", time.asctime(time.localtime(local_min))
240 # print local_min
241 #print "Is it really a invalid date?", tp.is_time_valid(local_min), "if true FUCK"
242 #print self.get_name(), "Apres content:", tp.get_name(), time.asctime(time.localtime(local_min))
243 #else:
244 # print self.get_name(), "Tp ca lui va", tp.get_name()
246 if local_min is None:
247 still_loop = False
248 else:
249 t = local_min
250 #No loop more than one year
251 if t > original_t + 3600*24*366 + 1:
252 still_loop = False
253 local_min = None
255 #print "We got it!"
256 #Ok, we update the cache...
257 self.cache[original_t] = local_min
258 return local_min
261 def get_next_invalid_time_from_t(self, t):
262 #print '\n\n', self.get_name(), 'search for next invalid from', time.asctime(time.localtime(t))
263 t = int(t)
264 original_t = t
265 still_loop = True
267 if not self.is_time_valid(t):
268 return t
270 local_min = t
271 res = None
272 #Loop for all minutes...
273 while still_loop:
274 #print "Invalid loop with", time.asctime(time.localtime(local_min))
276 # #Ok, not in cache...
277 # #print self.get_name(), "Begin loop with", time.asctime(time.localtime(local_min))
278 # next_exclude = None
279 # for dr in self.exclude:
280 # m = dr.get_next_valid_time_from_t(local_min)
281 # if m != None:
282 # #print time.asctime(time.localtime(m))
283 # if next_exclude == None or m <= next_exclude:
284 # next_exclude = m
286 # #Maybe the min of exclude is not valid, it is the min we can find.
287 # if next_exclude != None and not self.is_time_valid(next_exclude):
288 # #print self.get_name(), "find a possible early exit for invalid ! with", time.asctime(time.localtime(next_exclude))
289 # res = next_exclude
290 # still_loop = False
292 dr_mins = []
293 #But maybe we can find a better solution with next invalid of standart dateranges
294 #print self.get_name(), "After valid of exclude, local_min =", time.asctime(time.localtime(local_min))
295 for dr in self.dateranges:
296 #print self.get_name(), "Search a next invalid from DR", time.asctime(time.localtime(local_min))
297 #print dr.__dict__
298 m = dr.get_next_invalid_time_from_t(local_min)
300 #print self.get_name(), "Dr give me next invalid", time.asctime(time.localtime(m))
301 if m is not None:
302 #But maybe it's invalid for this dr, but valid for other ones.
303 if not self.is_time_valid(m):
304 #print "Final : Got a next invalid at", time.asctime(time.localtime(m))
305 dr_mins.append(m)
306 #print "Add a m", time.asctime(time.localtime(m))
307 # else:
308 # print dr.__dict__
309 # print "FUCK bad result\n\n\n"
311 if dr_mins != []:
312 local_min = min(dr_mins)
313 #print "After dr : found invalid local min:", time.asctime(time.localtime(local_min)), "is valid", self.is_time_valid(local_min)
315 #print self.get_name(), 'Invalid: local min', time.asctime(time.localtime(local_min))
316 #We do not loop unless the local_min is not valid
317 still_loop = False
319 #if we've got a real value, we check it with the exclude
320 if local_min is not None:
321 #Now check if local_min is not valid
322 for tp in self.exclude:
323 #print self.get_name(),"we check for invalid", time.asctime(time.localtime(local_min)), 'with tp', tp.name
324 if tp.is_time_valid(local_min):
325 still_loop = True
326 #local_min + 60
327 local_min = tp.get_next_invalid_time_from_t(local_min+60)
328 #No loop more than one year
329 if local_min > original_t + 60*24*366 + 1:
330 still_loop = False
331 res = None
333 if not still_loop:#We find a possible value
334 #We take the result the minimal possible
335 if res is None or local_min < res:
336 res = local_min
338 #print "Finished Return the next invalid", time.asctime(time.localtime(local_min))
339 return local_min
342 def has(self, prop):
343 return hasattr(self, prop)
346 #We are correct only if our daterange are
347 #and if we have no unmatch entries
348 def is_correct(self):
349 b = True
350 for dr in self.dateranges:
351 b &= dr.is_correct()
353 #Even one invalid is non correct
354 for e in self.invalid_entries:
355 b = False
356 print "Error : The timeperiod %s got an invalid entry '%s'" % (self.get_name(), e)
357 return b
360 def __str__(self):
361 s = ''
362 s += str(self.__dict__)+'\n'
363 for elt in self.dateranges:
364 s += str(elt)
365 (start,end) = elt.get_start_and_end_time()
366 start = time.asctime(time.localtime(start))
367 end = time.asctime(time.localtime(end))
368 s += "\nStart and end:"+str((start, end))
369 s += '\nExclude'
370 for elt in self.exclude:
371 s += str(elt)
373 return s
376 def resolve_daterange(self, dateranges, entry):
377 #print "Trying to resolve ", entry
379 res = re.search('(\d{4})-(\d{2})-(\d{2}) - (\d{4})-(\d{2})-(\d{2}) / (\d+)[\s\t]*([0-9:, -]+)', entry)
380 if res is not None:
381 #print "Googd catch 1"
382 (syear, smon, smday, eyear, emon, emday, skip_interval, other) = res.groups()
383 dateranges.append(CalendarDaterange(syear, smon, smday, 0, 0, eyear, emon, emday, 0, 0, skip_interval, other))
384 return
386 res = re.search('(\d{4})-(\d{2})-(\d{2}) / (\d+)[\s\t]*([0-9:, -]+)', entry)
387 if res is not None:
388 #print "Good catch 2"
389 (syear, smon, smday, skip_interval, other) = res.groups()
390 eyear = syear
391 emon = smon
392 emday = smday
393 dateranges.append(CalendarDaterange(syear, smon, smday, 0, 0, eyear, emon, emday, 0, 0, skip_interval, other))
394 return
396 res = re.search('(\d{4})-(\d{2})-(\d{2}) - (\d{4})-(\d{2})-(\d{2})[\s\t]*([0-9:, -]+)', entry)
397 if res is not None:
398 #print "Googd catch 3"
399 (syear, smon, smday, eyear, emon, emday, other) = res.groups()
400 dateranges.append(CalendarDaterange(syear, smon, smday, 0, 0, eyear, emon, emday, 0, 0, 0, other))
401 return
403 res = re.search('(\d{4})-(\d{2})-(\d{2})[\s\t]*([0-9:, -]+)', entry)
404 if res is not None:
405 #print "Googd catch 4"
406 (syear, smon, smday, other) = res.groups()
407 eyear = syear
408 emon = smon
409 emday = smday
410 dateranges.append(CalendarDaterange(syear, smon, smday, 0, 0, eyear, emon, emday, 0, 0, 0, other))
411 return
413 res = re.search('([a-z]*) ([\d-]+) ([a-z]*) - ([a-z]*) ([\d-]+) ([a-z]*) / (\d+)[\s\t]*([0-9:, -]+)', entry)
414 if res is not None:
415 #print "Googd catch 5"
416 (swday, swday_offset, smon, ewday, ewday_offset, emon, skip_interval, other) = res.groups()
417 dateranges.append(MonthWeekDayDaterange(0, smon, 0, swday, swday_offset, 0, emon, 0, ewday, ewday_offset, skip_interval, other))
418 return
420 res = re.search('([a-z]*) ([\d-]+) - ([a-z]*) ([\d-]+) / (\d+)[\s\t]*([0-9:, -]+)', entry)
421 if res is not None:
422 #print "Googd catch 6"
423 (t0, smday, t1, emday, skip_interval, other) = res.groups()
424 if t0 in Daterange.weekdays and t1 in Daterange.weekdays:
425 swday = t0
426 ewday = t1
427 swday_offset = smday
428 ewday_offset = emday
429 dateranges.append(WeekDayDaterange(0, 0, 0, swday, swday_offset, 0,0,0, ewday, ewday_offset, skip_interval, other))
430 return
431 elif t0 in Daterange.months and t1 in Daterange.months:
432 smon = t0
433 emon = t1
434 dateranges.append(MonthDateDaterange(0, smon, smday, 0,0,0,emon,emday,0,0,skip_interval,other))
435 return
436 elif t0 == 'day' and t1 == 'day':
437 dateranges.append(MonthDayDaterange(0,0,smday,0,0,0,0,emday, 0,0,skip_interval, other))
438 return
440 res = re.search('([a-z]*) ([\d-]+) - ([\d-]+) / (\d+)[\s\t]*([0-9:, -]+)', entry)
441 if res is not None:
442 #print "Googd catch 7"
443 (t0, smday, emday, skip_interval, other) = res.groups()
444 if t0 in Daterange.weekdays:
445 swday = t0
446 swday_offset = smday
447 ewday = swday
448 ewday_offset = emday
449 dateranges.append(WeekDayDaterange(0, 0, 0, swday, swday_offset, 0,0,0, ewday, ewday_offset, skip_interval, other))
450 return
451 elif t0 in Daterange.months:
452 smon = t0
453 emon = smon
454 dateranges.append(MonthDateDaterange(0, smon, smday, 0,0,0,emon,emday,0,0,skip_interval, other))
455 return
456 elif t0 == 'day':
457 dateranges.append(MonthDayDaterange(0,0,smday,0,0,0,0,emday,0,0,skip_interval,other))
458 return
461 res = re.search('([a-z]*) ([\d-]+) ([a-z]*) - ([a-z]*) ([\d-]+) ([a-z]*) [\s\t]*([0-9:, -]+)', entry)
462 if res is not None:
463 #print "Googd catch 8"
464 (swday, swday_offset, smon, ewday, ewday_offset, emon, other) = res.groups()
465 #print "Debug:", (swday, swday_offset, smon, ewday, ewday_offset, emon, other)
466 dateranges.append(MonthWeekDayDaterange(0, smon, 0, swday, swday_offset, 0, emon, 0, ewday, ewday_offset, 0, other))
467 return
470 res = re.search('([a-z]*) ([\d-]+) - ([\d-]+)[\s\t]*([0-9:, -]+)', entry)
471 if res is not None:
472 #print "Googd catch 9"
473 (t0, smday, emday, other) = res.groups()
474 if t0 in Daterange.weekdays:
475 swday = t0
476 swday_offset = smday
477 ewday = swday
478 ewday_offset = emday
479 dateranges.append(WeekDayDaterange(0, 0, 0, swday, swday_offset, 0,0,0, ewday, ewday_offset, 0, other))
480 return
481 elif t0 in Daterange.months:
482 smon = t0
483 emon = smon
484 dateranges.append(MonthDateDaterange(0, smon, smday, 0,0,0,emon,emday,0,0, 0, other))
485 return
486 elif t0 == 'day':
487 dateranges.append(MonthDayDaterange(0,0,smday,0,0,0,0,emday,0,0,0,other))
488 return
490 res = re.search('([a-z]*) ([\d-]+) - ([a-z]*) ([\d-]+)[\s\t]*([0-9:, -]+)', entry)
491 if res is not None:
492 #print "Googd catch 10"
493 (t0, smday, t1, emday, other) = res.groups()
494 if t0 in Daterange.weekdays and t1 in Daterange.weekdays:
495 swday = t0
496 ewday = t1
497 swday_offset = smday
498 ewday_offset = emday
499 dateranges.append(WeekDayDaterange(0, 0, 0, swday, swday_offset, 0,0,0, ewday, ewday_offset, 0, other))
500 return
501 elif t0 in Daterange.months and t1 in Daterange.months:
502 smon = t0
503 emon = t1
504 dateranges.append(MonthDateDaterange(0, smon, smday, 0,0,0,emon,emday,0,0, 0,other))
505 return
506 elif t0 == 'day' and t1 == 'day':
507 dateranges.append(MonthDayDaterange(0,0,smday,0,0,0,0,emday, 0,0, 0, other))
508 return
510 res = re.search('([a-z]*) ([\d-]+) ([a-z]*)[\s\t]*([0-9:, -]+)', entry)
511 if res is not None:
512 #print "Good catch 11"
513 (t0, swday_offset, t1,other) = res.groups()
514 if t0 in Daterange.weekdays and t1 in Daterange.months:
515 swday = t0
516 smon = t1
517 emon = smon
518 ewday = swday
519 ewday_offset = swday_offset
520 dateranges.append(MonthWeekDayDaterange(0, smon, 0, swday, swday_offset,0,emon,0,ewday,ewday_offset,0,other))
521 return
523 res = re.search('([a-z]*) ([\d-]+)[\s\t]+([0-9:, -]+)', entry)
524 if res is not None:
525 #print "Good catch 12"
526 (t0, smday, other) = res.groups()
527 if t0 in Daterange.weekdays:
528 swday = t0
529 swday_offset = smday
530 ewday = swday
531 ewday_offset = swday_offset
532 dateranges.append(WeekDayDaterange(0,0,0,swday,swday_offset,0,0,0,ewday,ewday_offset,0,other))
533 return
534 if t0 in Daterange.months:
535 smon = t0
536 emon = smon
537 emday = smday
538 dateranges.append(MonthDateDaterange(0, smon, smday, 0,0,0,emon,emday,0,0, 0,other))
539 return
540 if t0 == 'day':
541 emday = smday
542 dateranges.append(MonthDayDaterange(0,0,smday,0,0,0,0,emday, 0,0, 0, other))
543 return
545 res = re.search('([a-z]*)[\s\t]+([0-9:, -]+)', entry)
546 if res is not None:
547 #print "Good catch 13"
548 (t0, other) = res.groups()
549 if t0 in Daterange.weekdays:
550 day = t0
551 dateranges.append(StandardDaterange(day, other))
552 return
553 print "No match for", entry
554 self.invalid_entries.append(entry)
557 def apply_inheritance(self):
558 pass
561 #create daterange from unresolved param
562 def explode(self, timeperiods):
563 for entry in self.unresolved:
564 #print "Revolving entry", entry
565 self.resolve_daterange(self.dateranges, entry)
566 self.unresolved = []
569 #Will make tp in exclude with id of the timeperiods
570 def linkify(self, timeperiods):
571 new_exclude = []
572 if self.has('exclude') and self.exclude != '':
573 print "I have excluded"
574 print self.get_name(), self.exclude
575 excluded_tps = self.exclude.split(',')
576 #print "I will exclude from:", excluded_tps
577 for tp_name in excluded_tps:
578 tp = timeperiods.find_by_name(tp_name.strip())
579 if tp is not None:
580 new_exclude.append(tp)
581 else:
582 print "Error : the timeperiod", tp_name, "is unknown!"
583 self.exclude = new_exclude
586 def check_exclude_rec(self):
587 if self.rec_tag:
588 print "Error :", self.get_name(), "is in a loop in exclude parameter"
589 return False
590 self.rec_tag = True
591 for tp in self.exclude:
592 tp.check_exclude_rec()
593 return True
596 def fill_data_brok_from(self, data, brok_type):
597 cls = self.__class__
598 #Now config properties
599 for prop, entry in cls.properties.items():
600 #Is this property intended for brokking?
601 # if 'fill_brok' in entry:
602 if brok_type in entry.fill_brok:
603 if hasattr(self, prop):
604 data[prop] = getattr(self, prop)
605 elif 'default' in entry:
606 data[prop] = entry.default
609 #Get a brok with initial status
610 def get_initial_status_brok(self):
611 cls = self.__class__
612 my_type = cls.my_type
613 data = {'id' : self.id}
615 self.fill_data_brok_from(data, 'full_status')
616 b = Brok('initial_'+my_type+'_status', data)
617 return b
621 class Timeperiods(Items):
622 name_property = "timeperiod_name"
623 inner_class = Timeperiod
626 def explode(self):
627 for id in self.items:
628 tp = self.items[id]
629 tp.explode(self)
632 def linkify(self):
633 for id in self.items:
634 tp = self.items[id]
635 tp.linkify(self)
638 def apply_inheritance(self):
639 #The only interesting property to inherit is exclude
640 self.apply_partial_inheritance('exclude')
641 for i in self:
642 i.get_customs_properties_by_inheritance(self)
644 #And now apply inheritance for unresolved properties
645 #like the dateranges in fact
646 for tp in self:
647 tp.get_unresolved_properties_by_inheritance(self.items)
650 #check for loop in definition
651 def is_correct(self):
652 r = True
653 #We do not want a same hg to be explode again and again
654 #so we tag it
655 for tp in self.items.values():
656 tp.rec_tag = False
658 for tp in self.items.values():
659 for tmp_tp in self.items.values():
660 tmp_tp.rec_tag = False
661 r &= tp.check_exclude_rec()
663 #We clean the tags
664 for tp in self.items.values():
665 del tp.rec_tag
667 #And check all timeperiods for correct (sounday is false)
668 for tp in self:
669 r &= tp.is_correct()
672 return r
676 if __name__ == '__main__':
677 t = Timeperiod()
678 test = ['1999-01-28 00:00-24:00',
679 'monday 3 00:00-24:00 ',
680 'day 2 00:00-24:00',
681 'february 10 00:00-24:00',
682 'february -1 00:00-24:00',
683 'friday -2 00:00-24:00',
684 'thursday -1 november 00:00-24:00',
685 '2007-01-01 - 2008-02-01 00:00-24:00',
686 'monday 3 - thursday 4 00:00-24:00',
687 'day 1 - 15 00:00-24:00',
688 'day 20 - -1 00:00-24:00',
689 'july -10 - -1 00:00-24:00',
690 'april 10 - may 15 00:00-24:00',
691 'tuesday 1 april - friday 2 may 00:00-24:00',
692 '2007-01-01 - 2008-02-01 / 3 00:00-24:00',
693 '2008-04-01 / 7 00:00-24:00',
694 'day 1 - 15 / 5 00:00-24:00',
695 'july 10 - 15 / 2 00:00-24:00',
696 'tuesday 1 april - friday 2 may / 6 00:00-24:00',
697 'tuesday 1 october - friday 2 may / 6 00:00-24:00',
698 'monday 3 - thursday 4 / 2 00:00-24:00',
699 'monday 4 - thursday 3 / 2 00:00-24:00',
700 'day -1 - 15 / 5 01:00-24:00,00:30-05:60',
701 'tuesday 00:00-24:00',
702 'sunday 00:00-24:00',
703 'saturday 03:00-24:00,00:32-01:02',
704 'wednesday 09:00-15:46,00:00-21:00',
705 'may 7 - february 2 00:00-10:00',
706 'day -1 - 5 00:00-10:00',
707 'tuesday 1 february - friday 1 may 01:00-24:00,00:30-05:60',
708 'december 2 - may -15 00:00-24:00',
710 for entry in test:
711 print "**********************"
712 print entry
713 t = Timeperiod()
714 t.timeperiod_name = ''
715 t.resolve_daterange(t.dateranges, entry)
716 #t.exclude = []
717 #t.resolve_daterange(t.exclude, 'monday 00:00-19:00')
718 #t.check_valid_for_today()
719 now = time.time()
720 #print "Is valid NOW?", t.is_time_valid(now)
721 t_next = t.get_next_valid_time_from_t(now + 5*60)
722 if t_next is not None:
723 print "Get next valid for now + 5 min ==>", time.asctime(time.localtime(t_next)),"<=="
724 else:
725 print "===> No future time!!!"
726 #print "End date:", t.get_end_time()
727 #print "Next valid", time.asctime(time.localtime(t.get_next_valid_time()))
728 print str(t)+'\n\n'
730 print "*************************************************************"
731 t3 = Timeperiod()
732 t3.timeperiod_name = 't3'
733 t3.resolve_daterange(t3.dateranges, 'day 1 - 10 10:30-15:00')
734 t3.exclude = []
736 t2 = Timeperiod()
737 t2.timeperiod_name = 't2'
738 t2.resolve_daterange(t2.dateranges, 'day 1 - 10 12:00-17:00')
739 t2.exclude = [t3]
742 t = Timeperiod()
743 t.timeperiod_name = 't'
744 t.resolve_daterange(t.dateranges, 'day 1 - 10 14:00-15:00')
745 t.exclude = [t2]
747 print "Mon T", str(t)+'\n\n'
748 t_next = t.get_next_valid_time_from_t(now)
749 t_no_next = t.get_next_invalid_time_from_t(now)
750 print "Get next valid for now ==>", time.asctime(time.localtime(t_next)),"<=="
751 print "Get next invalid for now ==>", time.asctime(time.localtime(t_no_next)),"<=="