from typing import Callable, Optional, List  # noqa: F401
from datetime import timedelta, datetime
from collections import namedtuple

Time = namedtuple("Time", ['hours', 'minutes', 'seconds'])


class Schedule:

    def __init__(self) -> None:
        self._days = 0
        self._at = None  # type: Optional[Time]
        self._hours = 0
        self._minutes = 0
        self._seconds = 0

    def day(self):
        return self.days(1)

    def days(self, value: int):
        self._days = value
        return self

    def at(self, hours: int, minutes: int, seconds: int = 0):
        if self._hours or self._minutes:
            raise Exception("At can only be used on day(s)")
        if not self._days:
            raise Exception("At can only be used on day(s)")
        self._at = Time(hours, minutes, seconds)
        return self

    def hour(self):
        return self.hours(1)

    def hours(self, value: int):
        self._hours = value
        return self

    def minute(self):
        return self.minutes(1)

    def minutes(self, value: int):
        self._minutes = value
        return self

    def second(self):
        return self.seconds(1)

    def seconds(self, value: int):
        self._seconds = value
        return self

    def get_next_run_time(self, last_run: datetime) -> datetime:
        if self._at:
            next_day = last_run + timedelta(days=self._days)
            return next_day.replace(hour=self._at.hours,
                                    minute=self._at.minutes,
                                    second=self._at.seconds,
                                    microsecond=0)

        return last_run + timedelta(days=self._days,
                                    hours=self._hours,
                                    minutes=self._minutes,
                                    seconds=self._seconds)


class Job:
    def __init__(self, schedule: Schedule, func: Callable) -> None:
        self.func = func
        self.schedule = schedule
        self.func = func
        self.next_run = self.schedule.get_next_run_time(datetime.now())

    def should_run(self) -> bool:
        return self.next_run <= datetime.now()

    def run(self) -> None:
        self.func()
        self.next_run = self.schedule.get_next_run_time(datetime.now())


class Scheduler:
    def __init__(self):
        self.jobs = []  # type: List[Job]

    def add_job(self, job: Job) -> None:
        self.jobs.append(job)

    def run_pending(self) -> None:
        jobs_to_run = [job for job in self.jobs
                       if job.should_run()]  # type: List[Job]
        for job in jobs_to_run:
            job.run()

@@ -36,16 +36,25 @@
 al, List
+, TypeVar
   # noqa
@@ -196,16 +196,67 @@
 onds'%5D)%0A
+TSchedule = TypeVar(%22TSchedule%22, bound='Schedule')%0A
 %0A%0Aclass 
@@ -457,32 +457,63 @@
  def day(self):%0A
+        # type: () -%3E Schedule%0A
         return s
@@ -541,39 +541,68 @@
 days(self, value
-: int):
+):%0A        # type: (int) -%3E Schedule
 %0A        self._d
@@ -656,21 +656,16 @@
 f, hours
-: int
 , minute
@@ -665,21 +665,16 @@
  minutes
-: int
 , second
@@ -678,19 +678,56 @@
 onds
-: int = 0):
+=0):%0A        # type: (int, int, int) -%3E Schedule
 %0A   
@@ -995,32 +995,63 @@
 def hour(self):%0A
+        # type: () -%3E Schedule%0A
         return s
@@ -1081,39 +1081,68 @@
 ours(self, value
-: int):
+):%0A        # type: (int) -%3E Schedule
 %0A        self._h
@@ -1189,32 +1189,63 @@
 f minute(self):%0A
+        # type: () -%3E Schedule%0A
         return s
@@ -1279,39 +1279,68 @@
 utes(self, value
-: int):
+):%0A        # type: (int) -%3E Schedule
 %0A        self._m
@@ -1389,32 +1389,63 @@
 f second(self):%0A
+        # type: () -%3E Schedule%0A
         return s
@@ -1491,15 +1491,44 @@
 alue
-: int):
+):%0A        # type: (int) -%3E Schedule
 %0A   
@@ -2654,24 +2654,32 @@
 init__(self)
+ -%3E None
 :%0A        se

Fix scheduler types