1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 """
19 Contains unit test utility functions.
20
21 Many functions use a human readable date and time string as argument.
22 Such a string has a day, month, year and an optional time like this::
23
24 "1 Aug 2012" or "12 Jan 2017 12:05:30"
25 """
26
27 import random
28 import xml.etree.ElementTree as ET
29
30 from timelinelib.calendar.gregorian.gregorian import GregorianDateTime
31 from timelinelib.calendar.gregorian.monthnames import ABBREVIATED_ENGLISH_MONTH_NAMES
32 from timelinelib.calendar.gregorian.time import GregorianDelta
33 from timelinelib.calendar.gregorian.timetype import GregorianTimeType
34 from timelinelib.canvas.data import Category
35 from timelinelib.canvas.data import Container
36 from timelinelib.canvas.data import Era
37 from timelinelib.canvas.data import Event
38 from timelinelib.canvas.data import Subevent
39 from timelinelib.canvas.data import TimePeriod
40
41
42 ANY_TIME = "1 Jan 2010"
43 ANY_NUM_TIME = 10
44
45
53
54
56 """
57 Create a numeric TimePeriod object.
58 The start and end are numeric values.
59 """
60 return TimePeriod(start, end)
61
62
64 """
65 Create a :doc:`GregorianTime <timelinelib.calendar.gregorian.time>` object
66 from a human readable date and time string.
67 """
68 (year, month, day, hour, minute, seconds) = human_time_to_ymdhm(human_time)
69 return GregorianDateTime(year, month, day, hour, minute, seconds).to_time()
70
71
73 """Create a random :doc:`TimePeriod <timelinelib_canvas_data_timeperiod>` object."""
74 year = random.randint(1, 4000)
75 month = random.randint(1, 12)
76 day = random.randint(1, 28)
77 end_year = year + random.randint(1, 5)
78 end_month = random.randint(1, 12)
79 end_day = random.randint(1, 28)
80 return TimePeriod(GregorianDateTime(year, month, day, 0, 0, 0).to_time(),
81 GregorianDateTime(end_year, end_month, end_day, 0, 0, 0).to_time())
82
83
85 """
86 Convert a human readable date and time string into a tuple of
87 numeric values.
88 """
89 parts = human_time.split(" ")
90 day_part, month_part, year_part = parts[0], parts[1], parts[2]
91 day = int(day_part)
92 month = ABBREVIATED_ENGLISH_MONTH_NAMES.index(month_part) + 1
93 year = int(year_part)
94 if len(parts) == 4:
95 hour = int(parts[3][:2])
96 minute = int(parts[3][3:5])
97 if len(parts[3]) == 8:
98 seconds = int(parts[3][6:8])
99 else:
100 seconds = 0
101 else:
102 hour = 0
103 minute = 0
104 seconds = 0
105 return (year, month, day, hour, minute, seconds)
106
107
111
112
113 -def an_event_with(human_start_time=None, human_end_time=None, time=ANY_TIME,
114 text="foo", fuzzy=False, locked=False, ends_today=False,
115 category=None, categories=[], default_color=None):
135
136
138 """Create a :doc:`Subevent <timelinelib_canvas_data_subevent>` object."""
139 return a_subevent_with()
140
141
153
154
167
168
175
176
178 """Create a :doc:`Category <timelinelib_canvas_data_category>` object."""
179 return a_category_with(name="category")
180
181
182 -def a_category_with(name, color=(255, 0, 0), font_color=(0, 255, 255),
183 parent=None):
191
192
194 """Create an :doc:`Era <timelinelib_canvas_data_era>` object."""
195 return a_gregorian_era_with()
196
197
211
212
214 """Create an :doc:`Era <timelinelib_canvas_data_era>` object."""
215 return a_numeric_era_with()
216
217
224
225
227 """Return the number + 1. If number is None return 8."""
228 if number is None:
229 return 8
230 else:
231 return number + 1
232
233
240
241
248
249
251 """Return the event's progress + 1. If the event's progress is None, return 8."""
252 if event.get_progress() is None:
253 return 8
254 else:
255 return (event.get_progress() + 1) % 100
256
257
267
268
269 EVENT_MODIFIERS = [
270 ("change fuzzy", lambda event:
271 event.set_fuzzy(not event.get_fuzzy())),
272 ("change locked", lambda event:
273 event.set_locked(not event.get_locked())),
274 ("change ends today", modifier_change_ends_today),
275 ("change id", lambda event:
276 event.set_id(inc(event.get_id()))),
277 ("change time period", lambda event:
278 event.set_time_period(event.get_time_period().move_delta(GregorianDelta.from_days(1)))),
279 ("change text", lambda event:
280 event.set_text("was: %s" % event.get_text())),
281 ("change category", lambda event:
282 event.set_category(new_cat(event))),
283 ("change icon", lambda event:
284 event.set_icon("was: %s" % event.get_icon())),
285 ("change description", lambda event:
286 event.set_description("was: %s" % event.get_description())),
287 ("change hyperlink", lambda event:
288 event.set_hyperlink("was: %s" % event.get_hyperlink())),
289 ("change progress", lambda event:
290 event.set_progress(new_progress(event))),
291 ("change alert", lambda event:
292 event.set_alert("was: %s" % event.get_alert())),
293 ]
294
295
296 SUBEVENT_MODIFIERS = EVENT_MODIFIERS
297
298
299 CONTAINER_MODIFIERS = [
300 ("change time period", lambda event:
301 event.set_time_period(event.get_time_period().move_delta(GregorianDelta.from_days(1)))),
302 ("change text", lambda event:
303 event.set_text("was: %s" % event.get_text())),
304 ("change category", lambda event:
305 event.set_category(new_cat(event))),
306 ]
307
308
309 CATEGORY_MODIFIERS = [
310 ("change name", lambda category:
311 category.set_name("was: %s" % category.get_name())),
312 ("change id", lambda category:
313 category.set_id(inc(category.get_id()))),
314 ("change color", lambda category:
315 category.set_color(category.get_color() + (1, 0, 3))),
316 ("change font color", lambda category:
317 category.set_font_color(category.get_font_color() + (1, 0, 3))),
318 ("change parent", lambda category:
319 category.set_parent(new_parent(category))),
320 ]
321
322
323 TIME_PERIOD_MODIFIERS = [
324 ("zoom", lambda time_period: time_period.zoom(-1)),
325 ("move left", lambda time_period: time_period.move(-1)),
326 ("move right", lambda time_period: time_period.move(1)),
327 ]
328
329
330 ERA_MODIFIERS = [
331 ("change id", lambda era: era.set_id(inc(era.get_id()))),
332 ("change time period", lambda era: era.set_time_period(era.get_time_period().move_delta(GregorianDelta.from_days(1)))),
333 ("change text", lambda era: era.set_name("was: %s" % era.get_name())),
334 ("change color", lambda era: era.set_color(tuple([x + 1 for x in era.get_color()])))
335 ]
336
337 NUM_ERA_MODIFIERS = [
338 ("change id", lambda era: era.set_id(inc(era.get_id()))),
339 ("change time period", lambda era: era.set_time_period(era.get_time_period().move_delta(1))),
340 ("change text", lambda era: era.set_name("was: %s" % era.get_name())),
341 ("change color", lambda era: era.set_color(tuple([x + 1 for x in era.get_color()])))
342 ]
343
344
345 TIME_MODIFIERS = [
346 ("add", lambda time: time + GregorianDelta(1)),
347 ]
348
349
351 """An object of this class can be treated as a boolean."""
353 self.truth_value = truth_value
354
356 return self.truth_value
357
358
372
373
375 """An object of this class is always considered equal to any other object."""
376
379 ANY = _ANY()
380 """This object is always considered equal to any other object."""
381
382
384 def node_to_dict(node):
385 return {
386 "name": node.tag,
387 "attributes": {key: attribute(key, value) for key, value in node.attrib.items()},
388 "children": [node_to_dict(child) for child in node]
389 }
390 def attribute(key, value):
391 if key == "style":
392 styles = {}
393 for style in value.strip().split(";"):
394 if style.strip():
395 name, value = style.split(":")
396 styles[name.strip()] = value.strip()
397 return styles
398 else:
399 return value
400 return node_to_dict(ET.fromstring(xml))
401