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, default_color=None):
134
135
137 """Create a :doc:`Subevent <timelinelib_canvas_data_subevent>` object."""
138 return a_subevent_with()
139
140
152
153
166
167
174
175
177 """Create a :doc:`Category <timelinelib_canvas_data_category>` object."""
178 return a_category_with(name="category")
179
180
181 -def a_category_with(name, color=(255, 0, 0), font_color=(0, 255, 255),
182 parent=None):
190
191
193 """Create an :doc:`Era <timelinelib_canvas_data_era>` object."""
194 return a_gregorian_era_with()
195
196
210
211
213 """Create an :doc:`Era <timelinelib_canvas_data_era>` object."""
214 return a_numeric_era_with()
215
216
223
224
226 """Return the number + 1. If number is None return 8."""
227 if number is None:
228 return 8
229 else:
230 return number + 1
231
232
239
240
247
248
250 """Return the event's progress + 1. If the event's progress is None, return 8."""
251 if event.get_progress() is None:
252 return 8
253 else:
254 return (event.get_progress() + 1) % 100
255
256
266
267
268 EVENT_MODIFIERS = [
269 ("change fuzzy", lambda event:
270 event.set_fuzzy(not event.get_fuzzy())),
271 ("change locked", lambda event:
272 event.set_locked(not event.get_locked())),
273 ("change ends today", modifier_change_ends_today),
274 ("change id", lambda event:
275 event.set_id(inc(event.get_id()))),
276 ("change time period", lambda event:
277 event.set_time_period(event.get_time_period().move_delta(GregorianDelta.from_days(1)))),
278 ("change text", lambda event:
279 event.set_text("was: %s" % event.get_text())),
280 ("change category", lambda event:
281 event.set_category(new_cat(event))),
282 ("change icon", lambda event:
283 event.set_icon("was: %s" % event.get_icon())),
284 ("change description", lambda event:
285 event.set_description("was: %s" % event.get_description())),
286 ("change hyperlink", lambda event:
287 event.set_hyperlink("was: %s" % event.get_hyperlink())),
288 ("change progress", lambda event:
289 event.set_progress(new_progress(event))),
290 ("change alert", lambda event:
291 event.set_alert("was: %s" % event.get_alert())),
292 ]
293
294
295 SUBEVENT_MODIFIERS = EVENT_MODIFIERS
296
297
298 CONTAINER_MODIFIERS = [
299 ("change time period", lambda event:
300 event.set_time_period(event.get_time_period().move_delta(GregorianDelta.from_days(1)))),
301 ("change text", lambda event:
302 event.set_text("was: %s" % event.get_text())),
303 ("change category", lambda event:
304 event.set_category(new_cat(event))),
305 ]
306
307
308 CATEGORY_MODIFIERS = [
309 ("change name", lambda category:
310 category.set_name("was: %s" % category.get_name())),
311 ("change id", lambda category:
312 category.set_id(inc(category.get_id()))),
313 ("change color", lambda category:
314 category.set_color(category.get_color() + (1, 0, 3))),
315 ("change font color", lambda category:
316 category.set_font_color(category.get_font_color() + (1, 0, 3))),
317 ("change parent", lambda category:
318 category.set_parent(new_parent(category))),
319 ]
320
321
322 TIME_PERIOD_MODIFIERS = [
323 ("zoom", lambda time_period: time_period.zoom(-1)),
324 ("move left", lambda time_period: time_period.move(-1)),
325 ("move right", lambda time_period: time_period.move(1)),
326 ]
327
328
329 ERA_MODIFIERS = [
330 ("change id", lambda era: era.set_id(inc(era.get_id()))),
331 ("change time period", lambda era: era.set_time_period(era.get_time_period().move_delta(GregorianDelta.from_days(1)))),
332 ("change text", lambda era: era.set_name("was: %s" % era.get_name())),
333 ("change color", lambda era: era.set_color(tuple([x + 1 for x in era.get_color()])))
334 ]
335
336 NUM_ERA_MODIFIERS = [
337 ("change id", lambda era: era.set_id(inc(era.get_id()))),
338 ("change time period", lambda era: era.set_time_period(era.get_time_period().move_delta(1))),
339 ("change text", lambda era: era.set_name("was: %s" % era.get_name())),
340 ("change color", lambda era: era.set_color(tuple([x + 1 for x in era.get_color()])))
341 ]
342
343
344 TIME_MODIFIERS = [
345 ("add", lambda time: time + GregorianDelta(1)),
346 ]
347
348
350 """An object of this class can be treated as a boolean."""
352 self.truth_value = truth_value
353
355 return self.truth_value
356
357
371
372
374 """An object of this class is always considered equal to any other object."""
375
378 ANY = _ANY()
379 """This object is always considered equal to any other object."""
380
381
383 def node_to_dict(node):
384 return {
385 "name": node.tag,
386 "attributes": {key: attribute(key, value) for key, value in node.attrib.items()},
387 "children": [node_to_dict(child) for child in node]
388 }
389 def attribute(key, value):
390 if key == "style":
391 styles = {}
392 for style in value.strip().split(";"):
393 if style.strip():
394 name, value = style.split(":")
395 styles[name.strip()] = value.strip()
396 return styles
397 else:
398 return value
399 return node_to_dict(ET.fromstring(xml))
400