*redesign: moved classes for configuration objects to "objects" subpackage.
[shinken.git] / shinken / objects / timeperiod.py
blob624685e3ef8f05b66fc1afa0387d43e9ea4edac4
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
7 #This file is part of Shinken.
9 #Shinken is free software: you can redistribute it and/or modify
10 #it under the terms of the GNU Affero General Public License as published by
11 #the Free Software Foundation, either version 3 of the License, or
12 #(at your option) any later version.
14 #Shinken is distributed in the hope that it will be useful,
15 #but WITHOUT ANY WARRANTY; without even the implied warranty of
16 #MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 #GNU Affero General Public License for more details.
19 #You should have received a copy of the GNU Affero General Public License
20 #along with Shinken. If not, see <http://www.gnu.org/licenses/>.
23 #Calendar date: '(\d{4})-(\d{2})-(\d{2}) - (\d{4})-(\d{2})-(\d{2}) / (\d+) ([0-9:, -]+)' => len = 8 => CALENDAR_DATE
24 # '(\d{4})-(\d{2})-(\d{2}) / (\d+) ([0-9:, -]+)' => len = 5 => CALENDAR_DATE
25 # '(\d{4})-(\d{2})-(\d{2}) - (\d{4})-(\d{2})-(\d{2}) ([0-9:, -]+)' => len = 7 => CALENDAR_DATE
26 # '(\d{4})-(\d{2})-(\d{2}) ([0-9:, -]+)' => len = 4 => CALENDAR_DATE
28 #Month week day:'([a-z]*) (\d+) ([a-z]*) - ([a-z]*) (\d+) ([a-z]*) / (\d+) ([0-9:, -]+)' => len = 8 => MONTH WEEK DAY
29 # ex: wednesday 1 january - thursday 2 july / 3
31 # '([a-z]*) (\d+) - ([a-z]*) (\d+) / (\d+) ([0-9:, -]+)' => len = 6
32 # ex: february 1 - march 15 / 3 => MONTH DATE
33 # ex: monday 2 - thusday 3 / 2 => WEEK DAY
34 # ex: day 2 - day 6 / 3 => MONTH DAY
36 # '([a-z]*) (\d+) - (\d+) / (\d+) ([0-9:, -]+)' => len = 6
37 # ex: february 1 - 15 / 3 => MONTH DATE
38 # ex: thursday 2 - 4 => WEEK DAY
39 # ex: day 1 - 4 => MONTH DAY
41 # '([a-z]*) (\d+) ([a-z]*) - ([a-z]*) (\d+) ([a-z]*) ([0-9:, -]+)' => len = 7
42 # ex: wednesday 1 january - thursday 2 july => MONTH WEEK DAY
44 # '([a-z]*) (\d+) - (\d+) ([0-9:, -]+)' => len = 7
45 # ex: thursday 2 - 4 => WEEK DAY
46 # ex: february 1 - 15 / 3 => MONTH DATE
47 # ex: day 1 - 4 => MONTH DAY
49 # '([a-z]*) (\d+) - ([a-z]*) (\d+) ([0-9:, -]+)' => len = 5
50 # ex: february 1 - march 15 => MONTH DATE
51 # ex: monday 2 - thusday 3 => WEEK DAY
52 # ex: day 2 - day 6 => MONTH DAY
54 # '([a-z]*) (\d+) ([0-9:, -]+)' => len = 3
55 # ex: february 3 => MONTH DATE
56 # ex: thursday 2 => WEEK DAY
57 # ex: day 3 => MONTH DAY
59 # '([a-z]*) (\d+) ([a-z]*) ([0-9:, -]+)' => len = 4
60 # ex: thusday 3 february => MONTH WEEK DAY
62 # '([a-z]*) ([0-9:, -]+)' => len = 6
63 # ex: thusday => normal values
65 #Types: CALENDAR_DATE
66 # MONTH WEEK DAY
67 # WEEK DAY
68 # MONTH DATE
69 # MONTH DAY
71 import re, time
73 from .item import Item, Items
74 from shinken.util import *
77 from shinken.daterange import Daterange,CalendarDaterange,StandardDaterange,MonthWeekDayDaterange
78 from shinken.daterange import MonthDateDaterange,WeekDayDaterange,MonthDayDaterange
79 from shinken.brok import Brok
80 from shinken.property import UnusedProp, BoolProp, IntegerProp, FloatProp, CharProp, StringProp, ListProp
83 class Timeperiod(Item):
84 id = 1
85 my_type = 'timeperiod'
87 properties={
88 'timeperiod_name' : StringProp(fill_brok=['full_status']),
89 'alias' : StringProp(default='',fill_brok=['full_status']),
90 'use' : StringProp(default=''),
91 'exclude' : StringProp(default=''),
92 'register' : IntegerProp(default='1'),
93 #All errors and warning raised during the configuration parsing
94 #and taht will raised real warning/errors during the is_correct
95 'configuration_warnings' : ListProp(default=[]),
96 'configuration_errors' : ListProp(default=[]),
97 # These are needed if a broker module calls methods on timeperiod objects
98 'dateranges' : ListProp(fill_brok=['full_status'], default=[]),
99 'exclude' : ListProp(fill_brok=['full_status'], default=[]),
103 def __init__(self, params={}):
104 self.id = Timeperiod.id
105 Timeperiod.id = Timeperiod.id + 1
106 self.unresolved = []
107 self.dateranges = []
108 self.exclude = ''
109 self.customs = {}
110 self.plus = {}
111 self.invalid_entries = []
112 for key in params:
113 if key in ['name', 'alias', 'timeperiod_name', 'exclude', 'use', 'register']:
114 setattr(self, key, params[key])
115 else:
116 self.unresolved.append(key+' '+params[key])
118 self.cache = {} #For tunning purpose only
119 self.configuration_errors = []
120 self.configuration_warnings = []
123 def get_name(self):
124 return self.timeperiod_name
127 def clean(self):
128 pass
131 #We fillfull properties with template ones if need
132 #for the unresolved values (like sunday ETCETC)
133 def get_unresolved_properties_by_inheritance(self, items):
134 #Ok, I do not have prop, Maybe my templates do?
135 #Same story for plus
136 for i in self.templates:
137 self.unresolved.extend(i.unresolved)
141 def is_time_valid(self, t):
142 if self.has('exclude'):
143 for dr in self.exclude:
144 if dr.is_time_valid(t):
145 return False
146 for dr in self.dateranges:
147 if dr.is_time_valid(t):
148 return True
149 return False
152 #will give the first time > t which is valid
153 def get_min_from_t(self, t):
154 mins_incl = []
155 for dr in self.dateranges:
156 mins_incl.append(dr.get_min_from_t(t))
157 return min(mins_incl)
160 #will give the first time > t which is not valid
161 def get_not_in_min_from_t(self, f):
162 pass
165 def find_next_valid_time_from_cache(self, t):
166 try:
167 return self.cache[t]
168 except KeyError:
169 return None
172 #clean the get_next_valid_time_from_t cache
173 #The entries are a dict on t. t < now are useless
174 #Because we do not care about past anymore.
175 #If not, it's not important, it's just a cache after all :)
176 def clean_cache(self):
177 now = int(time.time())
178 t_to_del = []
179 for t in self.cache:
180 if t < now:
181 t_to_del.append(t)
182 for t in t_to_del:
183 del self.cache[t]
186 def get_next_valid_time_from_t(self, t):
187 #first find from cache
188 t = int(t)
189 original_t = t
191 #print self.get_name(), "Check valid time for", time.asctime(time.localtime(t))
193 res_from_cache = self.find_next_valid_time_from_cache(t)
194 if res_from_cache is not None:
195 return res_from_cache
197 still_loop = True
199 local_min = None
200 #Loop for all minutes...
201 while still_loop:
202 #print self.get_name(), '\nLoop'
203 #Ok, not in cache...
204 dr_mins = []
205 for dr in self.dateranges:
206 dr_mins.append(dr.get_next_valid_time_from_t(t))
208 #print "TOTO", self.get_name(), 'Mins:', dr_mins
209 #for o in dr_mins:
210 # print "FUCK",time.asctime(time.localtime(o)), "\n"
212 #Min but not the None valus...
213 try:
214 local_min = min([d for d in dr_mins if d!=None])
215 except ValueError: #dr_mins if full of None, not good
216 local_min = None
218 #if local_min != None:
219 # print "Poposed?", local_min
220 # print "Proposed local min", time.asctime(time.localtime(local_min))
223 #We do not loop unless the local_min is not valid
224 still_loop = False
226 #if we've got a real value, we check it with the exclude
227 if local_min != None:
228 #Now check if local_min is not valid
229 for tp in self.exclude:
230 #print self.get_name(), "Check in TP"
231 if tp.is_time_valid(local_min):
232 still_loop = True
233 #t = local_min + 60
234 #print self.get_name(), "TP pas content:", tp.get_name(), time.asctime(time.localtime(local_min))
235 local_min = tp.get_next_invalid_time_from_t(local_min+60)
236 #if local_min != None:
237 # print "Exclude TP proposed new local min", time.asctime(time.localtime(local_min))
238 # print local_min
239 #print "Is it really a invalid date?", tp.is_time_valid(local_min), "if true FUCK"
240 #print self.get_name(), "Apres content:", tp.get_name(), time.asctime(time.localtime(local_min))
241 #else:
242 # print self.get_name(), "Tp ca lui va", tp.get_name()
244 if local_min == None:
245 still_loop = False
246 else:
247 t = local_min
248 #No loop more than one year
249 if t > original_t + 3600*24*366 + 1:
250 still_loop = False
251 local_min = None
253 #print "We got it!"
254 #Ok, we update the cache...
255 self.cache[original_t] = local_min
256 return local_min
259 def get_next_invalid_time_from_t(self, t):
260 #print '\n\n', self.get_name(), 'search for next invalid from', time.asctime(time.localtime(t))
261 t = int(t)
262 original_t = t
263 still_loop = True
265 if not self.is_time_valid(t):
266 return t
268 local_min = t
269 res = None
270 #Loop for all minutes...
271 while still_loop:
272 #print "Invalid loop with", time.asctime(time.localtime(local_min))
274 # #Ok, not in cache...
275 # #print self.get_name(), "Begin loop with", time.asctime(time.localtime(local_min))
276 # next_exclude = None
277 # for dr in self.exclude:
278 # m = dr.get_next_valid_time_from_t(local_min)
279 # if m != None:
280 # #print time.asctime(time.localtime(m))
281 # if next_exclude == None or m <= next_exclude:
282 # next_exclude = m
284 # #Maybe the min of exclude is not valid, it is the min we can find.
285 # if next_exclude != None and not self.is_time_valid(next_exclude):
286 # #print self.get_name(), "find a possible early exit for invalid ! with", time.asctime(time.localtime(next_exclude))
287 # res = next_exclude
288 # still_loop = False
290 dr_mins = []
291 #But maybe we can find a better solution with next invalid of standart dateranges
292 #print self.get_name(), "After valid of exclude, local_min =", time.asctime(time.localtime(local_min))
293 for dr in self.dateranges:
294 #print self.get_name(), "Search a next invalid from DR", time.asctime(time.localtime(local_min))
295 #print dr.__dict__
296 m = dr.get_next_invalid_time_from_t(local_min)
298 #print self.get_name(), "Dr give me next invalid", time.asctime(time.localtime(m))
299 if m != None:
300 #But maybe it's invalid for this dr, but valid for other ones.
301 if not self.is_time_valid(m):
302 #print "Final : Got a next invalid at", time.asctime(time.localtime(m))
303 dr_mins.append(m)
304 #print "Add a m", time.asctime(time.localtime(m))
305 # else:
306 # print dr.__dict__
307 # print "FUCK bad result\n\n\n"
309 if dr_mins != []:
310 local_min = min(dr_mins)
311 #print "After dr : found invalid local min:", time.asctime(time.localtime(local_min)), "is valid", self.is_time_valid(local_min)
313 #print self.get_name(), 'Invalid: local min', time.asctime(time.localtime(local_min))
314 #We do not loop unless the local_min is not valid
315 still_loop = False
317 #if we've got a real value, we check it with the exclude
318 if local_min != None:
319 #Now check if local_min is not valid
320 for tp in self.exclude:
321 #print self.get_name(),"we check for invalid", time.asctime(time.localtime(local_min)), 'with tp', tp.name
322 if tp.is_time_valid(local_min):
323 still_loop = True
324 #local_min + 60
325 local_min = tp.get_next_invalid_time_from_t(local_min+60)
326 #No loop more than one year
327 if local_min > original_t + 60*24*366 + 1:
328 still_loop = False
329 res = None
331 if not still_loop:#We find a possible value
332 #We take the result the minimal possible
333 if res == None or local_min < res:
334 res = local_min
336 #print "Finished Return the next invalid", time.asctime(time.localtime(local_min))
337 return local_min
340 def has(self, prop):
341 return hasattr(self, prop)
344 #We are correct only if our daterange are
345 #and if we have no unmatch entries
346 def is_correct(self):
347 b = True
348 for dr in self.dateranges:
349 b &= dr.is_correct()
351 #Even one invalid is non correct
352 for e in self.invalid_entries:
353 b = False
354 print "Error : The timeperiod %s got an invalid entry '%s'" % (self.get_name(), e)
355 return b
358 def __str__(self):
359 s = ''
360 s += str(self.__dict__)+'\n'
361 for elt in self.dateranges:
362 s += str(elt)
363 (start,end) = elt.get_start_and_end_time()
364 start = time.asctime(time.localtime(start))
365 end = time.asctime(time.localtime(end))
366 s += "\nStart and end:"+str((start, end))
367 s += '\nExclude'
368 for elt in self.exclude:
369 s += str(elt)
371 return s
374 def resolve_daterange(self, dateranges, entry):
375 #print "Trying to resolve ", entry
377 res = re.search('(\d{4})-(\d{2})-(\d{2}) - (\d{4})-(\d{2})-(\d{2}) / (\d+)[\s\t]*([0-9:, -]+)', entry)
378 if res is not None:
379 #print "Googd catch 1"
380 (syear, smon, smday, eyear, emon, emday, skip_interval, other) = res.groups()
381 dateranges.append(CalendarDaterange(syear, smon, smday, 0, 0, eyear, emon, emday, 0, 0, skip_interval, other))
382 return
384 res = re.search('(\d{4})-(\d{2})-(\d{2}) / (\d+)[\s\t]*([0-9:, -]+)', entry)
385 if res is not None:
386 #print "Good catch 2"
387 (syear, smon, smday, skip_interval, other) = res.groups()
388 eyear = syear
389 emon = smon
390 emday = smday
391 dateranges.append(CalendarDaterange(syear, smon, smday, 0, 0, eyear, emon, emday, 0, 0, skip_interval, other))
392 return
394 res = re.search('(\d{4})-(\d{2})-(\d{2}) - (\d{4})-(\d{2})-(\d{2})[\s\t]*([0-9:, -]+)', entry)
395 if res is not None:
396 #print "Googd catch 3"
397 (syear, smon, smday, eyear, emon, emday, other) = res.groups()
398 dateranges.append(CalendarDaterange(syear, smon, smday, 0, 0, eyear, emon, emday, 0, 0, 0, other))
399 return
401 res = re.search('(\d{4})-(\d{2})-(\d{2})[\s\t]*([0-9:, -]+)', entry)
402 if res is not None:
403 #print "Googd catch 4"
404 (syear, smon, smday, other) = res.groups()
405 eyear = syear
406 emon = smon
407 emday = smday
408 dateranges.append(CalendarDaterange(syear, smon, smday, 0, 0, eyear, emon, emday, 0, 0, 0, other))
409 return
411 res = re.search('([a-z]*) ([\d-]+) ([a-z]*) - ([a-z]*) ([\d-]+) ([a-z]*) / (\d+)[\s\t]*([0-9:, -]+)', entry)
412 if res is not None:
413 #print "Googd catch 5"
414 (swday, swday_offset, smon, ewday, ewday_offset, emon, skip_interval, other) = res.groups()
415 dateranges.append(MonthWeekDayDaterange(0, smon, 0, swday, swday_offset, 0, emon, 0, ewday, ewday_offset, skip_interval, other))
416 return
418 res = re.search('([a-z]*) ([\d-]+) - ([a-z]*) ([\d-]+) / (\d+)[\s\t]*([0-9:, -]+)', entry)
419 if res is not None:
420 #print "Googd catch 6"
421 (t0, smday, t1, emday, skip_interval, other) = res.groups()
422 if t0 in Daterange.weekdays and t1 in Daterange.weekdays:
423 swday = t0
424 ewday = t1
425 swday_offset = smday
426 ewday_offset = emday
427 dateranges.append(WeekDayDaterange(0, 0, 0, swday, swday_offset, 0,0,0, ewday, ewday_offset, skip_interval, other))
428 return
429 elif t0 in Daterange.months and t1 in Daterange.months:
430 smon = t0
431 emon = t1
432 dateranges.append(MonthDateDaterange(0, smon, smday, 0,0,0,emon,emday,0,0,skip_interval,other))
433 return
434 elif t0 == 'day' and t1 == 'day':
435 dateranges.append(MonthDayDaterange(0,0,smday,0,0,0,0,emday, 0,0,skip_interval, other))
436 return
438 res = re.search('([a-z]*) ([\d-]+) - ([\d-]+) / (\d+)[\s\t]*([0-9:, -]+)', entry)
439 if res is not None:
440 #print "Googd catch 7"
441 (t0, smday, emday, skip_interval, other) = res.groups()
442 if t0 in Daterange.weekdays:
443 swday = t0
444 swday_offset = smday
445 ewday = swday
446 ewday_offset = emday
447 dateranges.append(WeekDayDaterange(0, 0, 0, swday, swday_offset, 0,0,0, ewday, ewday_offset, skip_interval, other))
448 return
449 elif t0 in Daterange.months:
450 smon = t0
451 emon = smon
452 dateranges.append(MonthDateDaterange(0, smon, smday, 0,0,0,emon,emday,0,0,skip_interval, other))
453 return
454 elif t0 == 'day':
455 dateranges.append(MonthDayDaterange(0,0,smday,0,0,0,0,emday,0,0,skip_interval,other))
456 return
459 res = re.search('([a-z]*) ([\d-]+) ([a-z]*) - ([a-z]*) ([\d-]+) ([a-z]*) [\s\t]*([0-9:, -]+)', entry)
460 if res is not None:
461 #print "Googd catch 8"
462 (swday, swday_offset, smon, ewday, ewday_offset, emon, other) = res.groups()
463 #print "Debug:", (swday, swday_offset, smon, ewday, ewday_offset, emon, other)
464 dateranges.append(MonthWeekDayDaterange(0, smon, 0, swday, swday_offset, 0, emon, 0, ewday, ewday_offset, 0, other))
465 return
468 res = re.search('([a-z]*) ([\d-]+) - ([\d-]+)[\s\t]*([0-9:, -]+)', entry)
469 if res is not None:
470 #print "Googd catch 9"
471 (t0, smday, emday, other) = res.groups()
472 if t0 in Daterange.weekdays:
473 swday = t0
474 swday_offset = smday
475 ewday = swday
476 ewday_offset = emday
477 dateranges.append(WeekDayDaterange(0, 0, 0, swday, swday_offset, 0,0,0, ewday, ewday_offset, 0, other))
478 return
479 elif t0 in Daterange.months:
480 smon = t0
481 emon = smon
482 dateranges.append(MonthDateDaterange(0, smon, smday, 0,0,0,emon,emday,0,0, 0, other))
483 return
484 elif t0 == 'day':
485 dateranges.append(MonthDayDaterange(0,0,smday,0,0,0,0,emday,0,0,0,other))
486 return
488 res = re.search('([a-z]*) ([\d-]+) - ([a-z]*) ([\d-]+)[\s\t]*([0-9:, -]+)', entry)
489 if res is not None:
490 #print "Googd catch 10"
491 (t0, smday, t1, emday, other) = res.groups()
492 if t0 in Daterange.weekdays and t1 in Daterange.weekdays:
493 swday = t0
494 ewday = t1
495 swday_offset = smday
496 ewday_offset = emday
497 dateranges.append(WeekDayDaterange(0, 0, 0, swday, swday_offset, 0,0,0, ewday, ewday_offset, 0, other))
498 return
499 elif t0 in Daterange.months and t1 in Daterange.months:
500 smon = t0
501 emon = t1
502 dateranges.append(MonthDateDaterange(0, smon, smday, 0,0,0,emon,emday,0,0, 0,other))
503 return
504 elif t0 == 'day' and t1 == 'day':
505 dateranges.append(MonthDayDaterange(0,0,smday,0,0,0,0,emday, 0,0, 0, other))
506 return
508 res = re.search('([a-z]*) ([\d-]+) ([a-z]*)[\s\t]*([0-9:, -]+)', entry)
509 if res is not None:
510 #print "Good catch 11"
511 (t0, swday_offset, t1,other) = res.groups()
512 if t0 in Daterange.weekdays and t1 in Daterange.months:
513 swday = t0
514 smon = t1
515 emon = smon
516 ewday = swday
517 ewday_offset = swday_offset
518 dateranges.append(MonthWeekDayDaterange(0, smon, 0, swday, swday_offset,0,emon,0,ewday,ewday_offset,0,other))
519 return
521 res = re.search('([a-z]*) ([\d-]+)[\s\t]+([0-9:, -]+)', entry)
522 if res is not None:
523 #print "Good catch 12"
524 (t0, smday, other) = res.groups()
525 if t0 in Daterange.weekdays:
526 swday = t0
527 swday_offset = smday
528 ewday = swday
529 ewday_offset = swday_offset
530 dateranges.append(WeekDayDaterange(0,0,0,swday,swday_offset,0,0,0,ewday,ewday_offset,0,other))
531 return
532 if t0 in Daterange.months:
533 smon = t0
534 emon = smon
535 emday = smday
536 dateranges.append(MonthDateDaterange(0, smon, smday, 0,0,0,emon,emday,0,0, 0,other))
537 return
538 if t0 == 'day':
539 emday = smday
540 dateranges.append(MonthDayDaterange(0,0,smday,0,0,0,0,emday, 0,0, 0, other))
541 return
543 res = re.search('([a-z]*)[\s\t]+([0-9:, -]+)', entry)
544 if res is not None:
545 #print "Good catch 13"
546 (t0, other) = res.groups()
547 if t0 in Daterange.weekdays:
548 day = t0
549 dateranges.append(StandardDaterange(day, other))
550 return
551 print "No match for", entry
552 self.invalid_entries.append(entry)
555 def apply_inheritance(self):
556 pass
559 #create daterange from unresolved param
560 def explode(self, timeperiods):
561 for entry in self.unresolved:
562 #print "Revolving entry", entry
563 self.resolve_daterange(self.dateranges, entry)
564 self.unresolved = []
567 #Will make tp in exclude with id of the timeperiods
568 def linkify(self, timeperiods):
569 new_exclude = []
570 if self.has('exclude') and self.exclude != '':
571 print "I have excluded"
572 print self.get_name(), self.exclude
573 excluded_tps = self.exclude.split(',')
574 #print "I will exclude from:", excluded_tps
575 for tp_name in excluded_tps:
576 tp = timeperiods.find_by_name(tp_name.strip())
577 if tp != None:
578 new_exclude.append(tp)
579 else:
580 print "Error : the timeperiod", tp_name, "is unknown!"
581 self.exclude = new_exclude
584 def check_exclude_rec(self):
585 if self.rec_tag:
586 print "Error :", self.get_name(), "is in a loop in exclude parameter"
587 return False
588 self.rec_tag = True
589 for tp in self.exclude:
590 tp.check_exclude_rec()
591 return True
594 def fill_data_brok_from(self, data, brok_type):
595 cls = self.__class__
596 #Now config properties
597 for prop in cls.properties:
598 #Is this property intended for brokking?
599 # if 'fill_brok' in cls.properties[prop]:
600 if brok_type in cls.properties[prop].fill_brok:
601 if hasattr(self, prop):
602 data[prop] = getattr(self, prop)
603 elif 'default' in cls.properties[prop]:
604 data[prop] = cls.properties[prop].default
607 #Get a brok with initial status
608 def get_initial_status_brok(self):
609 cls = self.__class__
610 my_type = cls.my_type
611 data = {'id' : self.id}
613 self.fill_data_brok_from(data, 'full_status')
614 b = Brok('initial_'+my_type+'_status', data)
615 return b
619 class Timeperiods(Items):
620 name_property = "timeperiod_name"
621 inner_class = Timeperiod
624 def explode(self):
625 for id in self.items:
626 tp = self.items[id]
627 tp.explode(self)
630 def linkify(self):
631 for id in self.items:
632 tp = self.items[id]
633 tp.linkify(self)
636 def apply_inheritance(self):
637 #The only interesting property to inherit is exclude
638 self.apply_partial_inheritance('exclude')
639 for i in self:
640 i.get_customs_properties_by_inheritance(self)
642 #And now apply inheritance for unresolved properties
643 #like the dateranges in fact
644 for tp in self:
645 tp.get_unresolved_properties_by_inheritance(self.items)
648 #check for loop in definition
649 def is_correct(self):
650 r = True
651 #We do not want a same hg to be explode again and again
652 #so we tag it
653 for tp in self.items.values():
654 tp.rec_tag = False
656 for tp in self.items.values():
657 for tmp_tp in self.items.values():
658 tmp_tp.rec_tag = False
659 r &= tp.check_exclude_rec()
661 #We clean the tags
662 for tp in self.items.values():
663 del tp.rec_tag
665 #And check all timeperiods for correct (sounday is false)
666 for tp in self:
667 r &= tp.is_correct()
670 return r
674 if __name__ == '__main__':
675 t = Timeperiod()
676 test = ['1999-01-28 00:00-24:00',
677 'monday 3 00:00-24:00 ',
678 'day 2 00:00-24:00',
679 'february 10 00:00-24:00',
680 'february -1 00:00-24:00',
681 'friday -2 00:00-24:00',
682 'thursday -1 november 00:00-24:00',
683 '2007-01-01 - 2008-02-01 00:00-24:00',
684 'monday 3 - thursday 4 00:00-24:00',
685 'day 1 - 15 00:00-24:00',
686 'day 20 - -1 00:00-24:00',
687 'july -10 - -1 00:00-24:00',
688 'april 10 - may 15 00:00-24:00',
689 'tuesday 1 april - friday 2 may 00:00-24:00',
690 '2007-01-01 - 2008-02-01 / 3 00:00-24:00',
691 '2008-04-01 / 7 00:00-24:00',
692 'day 1 - 15 / 5 00:00-24:00',
693 'july 10 - 15 / 2 00:00-24:00',
694 'tuesday 1 april - friday 2 may / 6 00:00-24:00',
695 'tuesday 1 october - friday 2 may / 6 00:00-24:00',
696 'monday 3 - thursday 4 / 2 00:00-24:00',
697 'monday 4 - thursday 3 / 2 00:00-24:00',
698 'day -1 - 15 / 5 01:00-24:00,00:30-05:60',
699 'tuesday 00:00-24:00',
700 'sunday 00:00-24:00',
701 'saturday 03:00-24:00,00:32-01:02',
702 'wednesday 09:00-15:46,00:00-21:00',
703 'may 7 - february 2 00:00-10:00',
704 'day -1 - 5 00:00-10:00',
705 'tuesday 1 february - friday 1 may 01:00-24:00,00:30-05:60',
706 'december 2 - may -15 00:00-24:00',
708 for entry in test:
709 print "**********************"
710 print entry
711 t = Timeperiod()
712 t.timeperiod_name = ''
713 t.resolve_daterange(t.dateranges, entry)
714 #t.exclude = []
715 #t.resolve_daterange(t.exclude, 'monday 00:00-19:00')
716 #t.check_valid_for_today()
717 now = time.time()
718 #print "Is valid NOW?", t.is_time_valid(now)
719 t_next = t.get_next_valid_time_from_t(now + 5*60)
720 if t_next is not None:
721 print "Get next valid for now + 5 min ==>", time.asctime(time.localtime(t_next)),"<=="
722 else:
723 print "===> No future time!!!"
724 #print "End date:", t.get_end_time()
725 #print "Next valid", time.asctime(time.localtime(t.get_next_valid_time()))
726 print str(t)+'\n\n'
728 print "*************************************************************"
729 t3 = Timeperiod()
730 t3.timeperiod_name = 't3'
731 t3.resolve_daterange(t3.dateranges, 'day 1 - 10 10:30-15:00')
732 t3.exclude = []
734 t2 = Timeperiod()
735 t2.timeperiod_name = 't2'
736 t2.resolve_daterange(t2.dateranges, 'day 1 - 10 12:00-17:00')
737 t2.exclude = [t3]
740 t = Timeperiod()
741 t.timeperiod_name = 't'
742 t.resolve_daterange(t.dateranges, 'day 1 - 10 14:00-15:00')
743 t.exclude = [t2]
745 print "Mon T", str(t)+'\n\n'
746 t_next = t.get_next_valid_time_from_t(now)
747 t_no_next = t.get_next_invalid_time_from_t(now)
748 print "Get next valid for now ==>", time.asctime(time.localtime(t_next)),"<=="
749 print "Get next invalid for now ==>", time.asctime(time.localtime(t_no_next)),"<=="