Source

pyld / pyld / process.py

Full commit
#! /usr/bin/env python
# -*- coding: utf-8 -*-
#
# Copyright (C) 2011 uniqx
#  Metalab, 1010 Vienna, Austria
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published
# by the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
#

import os
import ast
import time

from multiprocessing import Process, Queue

class PyldFile():

  def __init__(self,file_name,global_vars={}):

    self.local_vars = {}
    self.global_vars = global_vars
    self.file_name = file_name

    self._read_and_compile_code_objects(True)

  def _read_and_compile_code_objects(self, compile_init=False):
    """Reads the script file at ``file_name`` and builds code objetcs
    for the relevant parts of the script. Is ``compile_init`` set to
    True the code object for __init_pyld__ will also be compiled.
    """

    src = self.__read_text_file_to_string(self.file_name)

    for block in ast.parse(src).body:

      if 'test' in dir(block):
        dump = ast.dump(block.test)
        if compile_init and '__pyld_init__' in dump:
          self.__init_co = compile(ast.Module(block.body),
            os.path.basename(self.file_name),'exec')
        elif '__pyld_reload__' in dump:
          self.__reload_co = compile(ast.Module(block.body),
            os.path.basename(self.file_name),'exec')
        elif '__pyld_unload__' in dump:
          self.__unload_co = compile(ast.Module(block.body),
            os.path.basename(self.file_name),'exec')
        elif '__pyld_tick__' in dump:
          self.__tick_co = compile(ast.Module(block.body),
            os.path.basename(self.file_name),'exec')

  def __read_text_file_to_string(self,path):
    """This function reads the entire file located at ``path`` and returns
    it as string.
    """

    ret = ''

    with open(path,'r') as f:
      ret = '\n'.join([ line for line in f ])
    f.closed

    return ret


  def _execute_init(self):
    '''
    '''
    exec(self.__init_co,self.global_vars,self.local_vars)

  def _execute_reload(self):
    '''
    '''
    exec(self.__reload_co,self.global_vars,self.local_vars)

  def _execute_unload(self):
    '''
    '''
    exec(self.__unload_co,self.global_vars,self.local_vars)

  def _execute_tick(self):
    '''
    '''
    exec(self.__tick_co,self.global_vars,self.local_vars)






class PyldProcess(Process):

  def __init__(self, file_name_list):
    '''PyldProcess will execute all files from ``file_name_list``.
    '''

    self.add_file_queue = Queue()
    self.update_file_queue = Queue()

    Process.__init__(self,args=[self.update_file_queue])
    self.files = {}

  def update_file(self,file_name):
    '''
    '''

    self.update_file_queue.put_nowait(file_name)

  def add_file(self,pyld_file):
    '''
    '''

    self.add_file_queue.put_nowait(file_name)

  def run(self):
    '''
    '''

    while True:

      while not self.add_file_queue.empty():
        file_name = self.add_file.queue.get_nowait()
        self.files[pyld_file] = PyldFile(file_name)
        self.files[pyld_file]._execute_init()

        print '### file %s added' % file_name

      # check for files to update
      while not self.update_file_queue.empty():
        file_name = self.update_file_queue.get_nowait()
        self.files[file_name]._execute_unload()
        self.files[file_name]._read_and_compile_code_objects()
        self.files[file_name]._execute_reload()

      for file_name, pyld_file in self.files.iteritems():
        pyld_file._execute_tick()

      time.sleep(0)