import time

import itertools


class Timer(object):
    def __init__(self, name, is_root=True):
        self.name = name
        self.beginning = None
        self.end = None
        self.subs = []
        self.root = self if is_root else None
        self.parent = None

    def init(self, root, parent):
        self.root = root
        self.parent = parent

    def start(self):
        self.beginning = time.time()

    def stop(self):
        self.end = time.time()

    def append(self, timer):
        timer.init(self.root, self)
        self.subs.append(timer)

    @property
    def duration(self):
        if self.beginning and self.end:
            return self.end - self.beginning

    @property
    def percent_of_total(self):
        return (self.duration / self.root.duration * 100) if self.duration and self.root else None

    @property
    def percent_of_parent(self):
        return (self.duration / self.parent.duration * 100) if self.parent else None

    def to_dict(self):
        return {
            'name': self.name,
            'duration': self.duration,
            'percent_total': self.percent_of_total,
            'percent_parent': self.percent_of_parent,
            'subs': [sub.to_dict() for sub in self.subs]
        }

    def to_list(self):
        timers = [self] + list(itertools.chain(*[sub.to_list() for sub in self.subs]))
        return timers

    def __repr__(self):
        return "Timer(name='{}', beginning={}, end={}, parent='{}')".format(
            self.name,
            self.beginning,
            self.end,
            self.parent.name if self.parent else ''
        )


class TimingContext(object):
    def __init__(self , name):
        self.timings = {}
        self.root = Timer(name, is_root=True)
        self.stack = [self.root]

    def __call__(self, name):
        timer = Timer(name)
        current = self.peek()
        current.append(timer)
        self.stack.append(timer)
        return self

    def peek(self):
        return self.stack[len(self.stack) - 1]

    def __enter__(self):
        self.peek().start()
        return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        timer = self.stack.pop()
        timer.stop()

    def to_dict(self):
        return self.root.to_dict()

    def to_list(self):
        return self.root.to_list()

@@ -31,16 +31,24 @@
 %0A%0Aclass 
+Nestable
 Timer(ob
@@ -46,32 +46,107 @@
 eTimer(object):%0A
+    %22%22%22Timer object that can be nested. Used by %60%60TimingContext%60%60.%0A    %22%22%22%0A
     def __init__
@@ -1507,16 +1507,24 @@
 return %22
+Nestable
 Timer(na
@@ -1738,24 +1738,474 @@
 xt(object):%0A
+    %22%22%22Context manager for timing operations. Particularly useful for doing nested timing.%0A%0A    Example usage:%0A        def sleep():%0A            time.sleep(0.1)%0A%0A        def inner_sleep(timing_context):%0A            sleep()%0A            with timing_context('inner_sleep'):%0A                sleep()%0A%0A        with TimingContext('demo_timing') as context:%0A            sleep()%0A            with context('level0'):%0A                inner_sleep(context)%0A    %22%22%22%0A
     def __in
@@ -2269,16 +2269,24 @@
 .root = 
+Nestable
 Timer(na
@@ -2383,16 +2383,24 @@
 timer = 
+Nestable
 Timer(na
@@ -2800,58 +2800,639 @@
     
-return self.root.to_dict()%0A%0A    def to_list(self):
+%22%22%22Get timing data as a recursive dictionary of the format:%0A        %7B%0A            %22name%22: %22demo_timing%22,%0A            %22duration%22: 0.3,%0A            %22percent_total%22: 100.0,%0A            %22percent_parent%22: null,%0A            %22subs%22: %5B%0A                %7B%0A                    %22name%22: %22level0%22,%0A                    %22duration%22: 0.2,%0A                    %22percent_total%22: 66.66,%0A                    %22percent_parent%22: 66.66,%0A                    %22subs%22: %5B...%5D%0A                %7D%0A            %5D%0A        %7D%0A        %22%22%22%0A        return self.root.to_dict()%0A%0A    def to_list(self):%0A        %22%22%22Get the list of %60%60NestableTimer%60%60 objects in hierarchy order%22%22%22
 %0A   

rename and add docs