views:

248

answers:

2

I have a timer function:

# This is a class that schedules tasks. It will call it's ring() funtion
# when the timer starts, and call it's running() function when within the
# time limit, and call it's over() function when the time is up.

# This class uses SYSTEM time.

import time, threading
import settings

from object import Object

class Timer(Object, threading.Thread):
    # INIT -------------------------------------------------------------
    # Init vars
    #
    # If autotick is True (default) the timer will run in a seperate
    # process. Other wise it will need to be updated automatically by
    # calling tick()
    def __init__(self, autotick=False):
     # Call inherited __init__ first.
     threading.Thread.__init__(self)
     Object.__init__(self)

     # Now our vars
     self.startTimeString = "" # The time when the timer starts as a string
     self.endTimeString = "" # The time when the timer stops as a string
     self.timeFormat = "" # The string to use as the format for the string  
     self.set = False # The timer starts deactivated
     self.process = autotick # Wether or not to run in a seperate process.
     self.rung = False # Has the timer rang yet?


    # ACTIVATE --------------------------------------------------------------
    # Sets the timer
    def activate(self, startTime, endTime, format):
     # Set the timer.
     self.startTimeString = startTime
     self.endTimeString = endTime
     self.timeFormat = format

     # Conver the strings to time using format
     try:
      self.startTime = time.strptime(startTime, self.timeFormat)
      self.endTime = time.strptime(endTime, self.timeFormat)
     except ValueError:
      # Error
      print ("Error: Cannot convert time according to format")
      return False

     # Try and convert the time to seconds
     try:
      self.startTimeSecs = time.mktime(self.startTime)
      self.endTimeSecs = time.mktime(self.endTime)
     except OverflowError, ValueError:
      # Error
      print ("Error: Cannot convert time to seconds")
      return False

     # The timer is now set
     self.set = True

     # If self.process is true, we need to start calling tick in a
     # seperate process.
     if self.process:
      self.deamon = True # We don't want python to hang if a timer
              # is still running at exit.
      self.start()

    # RING -------------------------------------------------------------
    # This function is called when the timer starts.
    def ring(self):
     pass

    # RUNNING ----------------------------------------------------------
    # Called when the the time is whithin the time limits.
    def running(self):
     pass

    # OVER -------------------------------------------------------------
    # Called when the time is up
    def over(self):
     pass

    # TICK -------------------------------------------------------------
    # Call this every loop (or in a seperate process)
    def tick(self): 
     print time.time(), self.startTimeSecs, self.endTimeSecs, time.strftime("%A %H:%M", time.localtime(self.startTimeSecs))

     # Check the time
     if time.mktime(time.localtime()) > self.startTimeSecs and time.mktime(time.localtime()) < self.endTimeSecs and not self.rung:
      # The time has come =)
      # Call ring()
      self.ring()

      # Now set self.rung to True
      self.rung = True

     # If the time is up..
     elif time.mktime(time.localtime()) > self.endTimeSecs and self.rung:
      self.over()

      # Unset the timer
      self.set = False
      self.rung = False

     # If we are inbetween the starttime and endtime.
     elif time.mktime(time.localtime()) > self.startTimeSecs and time.mktime(time.localtime()) < self.endTimeSecs and self.rung:
      self.running()

     # If any of those aren't true, then the timer hasn't started yet
     else:
      # Check if the endTime has already passed
      if time.mktime(time.localtime()) > self.endTimeSecs:

       # The time has already passed.
       self.set = False


    # THREADING STUFF --------------------------------------------------
    # This is run by Threads start() method.
    def run(self):
     while self.set == True:
      # Tick
      self.tick()

      # Sleep for a bit to save CPU
      time.sleep(settings.TIMER_SLEEP)

And I am added schedule blocks to a scheduler:

# LOAD -------------------------------------------------------------
# Loads schedule from a file (schedule_settings.py).
def load(self):
 # Add blocks
 for block in schedule_settings.BLOCKS:
  # Calculate the day
  start_day = str(getDate(block[1].split()[0]))
  end_day = str(getDate(block[2].split()[0]))

  self.scheduler.add(start_day + " " + block[1].split()[1], end_day + " " + block[2].split()[1], "%j %H:%M", block[0])

 for block in self.scheduler.blocks:
  block.timer.tick()

 print len(self.scheduler.blocks)

 # Start the scheduler (if it isn't already)
 if not self.scheduler.running:
  self.scheduler.start()

The add function looks like this:

# ADD --------------------------------------------------------------
# Add a scheduled time
# 
# block should be a Block instance, describing what to do at this time.
def add(self, startTime, endTime, format, block):
 # Add this block
 newBlock = block

 # Start a timer for this block
 newBlock.timer = Timer()

 # Figure out the time
 year = time.strftime("%Y")

 # Add the block timer
 newBlock.timer.activate(year + " " + startTime, year + " " + endTime, "%Y " + format)

 # Add this block to the list
 self.blocks.append(newBlock)

 return

Basically with my program you can make a week's schedule and play your videos as if it were a TV channel. A block is a period of time where the channel will play certain episodes, or certain series.

My problem is that the blocks get completley messed up after using the add function. Some get duplicated, they're in the wrong order, etc. However before the add function they are completely fine. If I use a small amount of blocks (2 or 3) it seems to work fine, though.

For example if my schedule_settings.py (set's up a weeks schedule) looks like this:

# -*- coding: utf-8 -*-
# This file contains settings for a week's schedule
from block import Block
from series import Series

# MAIN BLOCK (All old episodes)
mainBlock = Block()
mainBlock.picker = 'random'
mainBlock.name = "Main Block"
mainBlock.auto(".")
mainBlock.old_episodes = True

# ONE PIECE
onepieceBlock = Block()
onepieceBlock.picker = 'latest'
onepieceBlock.name = "One Piece"
onepieceBlock.series = [
        Series(auto="One Piece"),
]

# NEWISH STUFF
newishBlock = Block()
newishBlock.picker = 'random'
newishBlock.auto(".")
newishBlock.name = "NewishBlock"
newishBlock.exclude_series = [
        #Series(auto="One Piece"),
        #Series(auto="Nyan Koi!"),
]

# NEW STUFF
newBlock = Block()
newBlock.picker = 'latest'
newBlock.name = "New Stuff"
newBlock.series = [
        Series(auto="Nyan Koi!"),
]

# ACTIVE BLOCKS
BLOCKS = (
        # MONDAY
        (mainBlock, "Monday 08:00", "Monday 22:20"),
        (onepieceBlock, "Monday 22:20", "Monday 22:30"),
        (newishBlock, "Monday 22:30", "Monday 23:00"),

        # TUESDAY
        (mainBlock, "Tuesday 08:00", "Tuesday 18:00"),
        (newBlock, "Tuesday 18:00", "Tuesday 18:30"),
        (newishBlock, "Tuesday 18:30", "Tuesday 22:00"),

        # WEDNESDAY
        (mainBlock, "Wednesday 08:00", "Wednesday 18:00"),
        (newBlock, "Wednesday 18:00", "Wednesday 18:30"),
        (newishBlock, "Wednesday 18:30", "Wednesday 22:00"),

        # THURSDAY
        (mainBlock, "Thursday 08:00", "Thursday 18:00"),
        (newBlock, "Thursday 18:00", "Thursday 18:30"),
        (newishBlock, "Thursday 18:30", "Thursday 22:00"),

        # FRIDAY
        (mainBlock, "Friday 08:00", "Friday 18:00"),
        (newBlock, "Friday 18:00", "Friday 18:30"),

        # WEEKEND
        (newishBlock, "Saturday 08:00", "Saturday 23:00"),

        (newishBlock, "Sunday 08:00", "Sunday 23:00"),

)

Before adding to the scheduler, The list produced looks fine, but after adding, then printing it out, I get:

1254810368.0 1255071600.0 1255107600.0 Friday 08:00
1254810368.0 1254777600.0 1254778200.0 Monday 22:20
1254810368.0 1255244400.0 1255298400.0 Sunday 08:00
1254810368.0 1255071600.0 1255107600.0 Friday 08:00
1254810368.0 1255107600.0 1255109400.0 Friday 18:00
1254810368.0 1255244400.0 1255298400.0 Sunday 08:00
1254810368.0 1255071600.0 1255107600.0 Friday 08:00
1254810368.0 1255107600.0 1255109400.0 Friday 18:00
1254810368.0 1255244400.0 1255298400.0 Sunday 08:00
1254810368.0 1255071600.0 1255107600.0 Friday 08:00
1254810368.0 1255107600.0 1255109400.0 Friday 18:00
1254810368.0 1255244400.0 1255298400.0 Sunday 08:00
1254810368.0 1255071600.0 1255107600.0 Friday 08:00
1254810368.0 1255107600.0 1255109400.0 Friday 18:00
1254810368.0 1255244400.0 1255298400.0 Sunday 08:00
1254810368.0 1255244400.0 1255298400.0 Sunday 08:00

I'm assuming this has somthing to do with the subclassing of threading.Thread I have done in my Timer class. Does passing it through a function and adding it to a list mess this up somehow?

(Edit) Sorry if that wasn't very concise, I was in rush and forgot to post the most important code =( Using the timer to tick manually was just some debug code, normally I would have auto=True in the timer class.

You can find all my code at: http://github.com/bombpersons/MYOT

A: 

You show us tons of code but not the key parts -- the Scheduler part (and what's that peculiar upper-case-O Object class...?). Anyway, to answer your question, passing instances of Thread subclasses through functions, adding them to lists, etc etc, is perfectly fine (though other things you're doing may not be -- e.g. you may not realize that, just because tick is a method of a Thread subclass, calling it from another thread does NOT mean it will execute in its own thread... rather, when called, it will execute in the calling thread).

May I suggest using the sched module in Python standard library to implement scheduling functionality, rather than running your own...?

Alex Martelli
Ah sorry =(Yes, I'm just calling tick at the moment for debuging, normally it would be in a seperate thread.
bombpersons
A: 

Ugh.. I feel stupid now. The problem was that, the blocks were being passed by reference to the scheduler, therefore everytime I added a timer to the block, I was overwriting the older timer.

I made a schedulerBlock class containing a timer and a block. It now works perfectly =)

bombpersons