<commit_before>import ConfigParser
import curses
import os
import pexpect
import pytest

from .. import menu_launcher
import test_env

def test_pathdirs():
    """ Gets path directory class from menu_launcher """
    path_dirs = menu_launcher.PathDirs()

def test_get_plugin_status():
    """ Test get_plugin_status function with valid and invalid directories """
    path_dirs = test_env.PathDirs()
    invalid_dirs = test_env.PathDirs(base_dir="/tmp/")
    menu_launcher.get_plugin_status(path_dirs)
    menu_launcher.get_plugin_status(invalid_dirs)

def test_run_plugins():
    """ Test get_run_plugins function with valid and invalid directories """
    # Prep
    os.system("cp modes.backup templates/modes.template")
    os.system("cp core.backup templates/core.template")

    path_dirs = test_env.PathDirs()
    invalid_dirs = test_env.PathDirs(base_dir="/tmp/")
    menu_launcher.run_plugins(path_dirs, "start")
    menu_launcher.run_plugins(invalid_dirs, "start")

    ### Visualization Test ###
    # Find modes.template
    os.system("touch "+path_dirs.template_dir+'modes.template')
    config = ConfigParser.RawConfigParser()
    config.read(path_dirs.template_dir+'modes.template')

    # Check for valid sections/options
    if not config.has_section("plugins"):
        config.add_section("plugins")
    config.set("plugins", "vis_test", "all")

    with open(path_dirs.template_dir+'modes.template', 'w') as f:
        config.write(f)

    # Test with one visualization plugin (filewalk)
    vis_test = "/vis_test"
    if not os.path.exists(path_dirs.vis_dir+vis_test):
        os.system("mkdir "+path_dirs.vis_dir+vis_test)

    menu_launcher.run_plugins(path_dirs, "start")

    # Cleanup
    os.system("rm -rf "+path_dirs.vis_dir+vis_test)
    os.system("cp modes.backup templates/modes.template")

    ### Collectors: Passive/Active Test ###
    # Find core.template
    os.system("touch "+path_dirs.template_dir+'core.template')
    config = ConfigParser.RawConfigParser()
    config.read(path_dirs.template_dir+'core.template')

    # Check for valid sections/options
    config.set("local-collection", "passive", "on")
    config.set("local-collection", "active", "on")

    with open(path_dirs.template_dir+'core.template', 'w') as f:
        config.write(f)

    # Test with one passive/active collector.
    active = "/active-test-collector"
    passive = "/passive-test-collector"

    if not os.path.exists(path_dirs.collectors_dir+active):
        os.system("mkdir "+path_dirs.collectors_dir+active)
    if not os.path.exists(path_dirs.collectors_dir+passive):
        os.system("mkdir "+path_dirs.collectors_dir+passive)

    menu_launcher.run_plugins(path_dirs, "start")

    # Cleanup
    os.system("rm -rf "+path_dirs.collectors_dir+active)
    os.system("rm -rf "+path_dirs.collectors_dir+active)
    os.system("cp core.backup templates/core.template")

    menu_launcher.run_plugins(path_dirs, "start")

def test_get_installed_plugin_repos():
    """ Test get_installed_plugin_repos function with valid and invalid directories """
    path_dirs = test_env.PathDirs()
    invalid_dirs = test_env.PathDirs(base_dir="/tmp/")
    menu_launcher.get_installed_plugin_repos(path_dirs, "INFO", "remove")
    menu_launcher.get_installed_plugin_repos(path_dirs, "INFO", "update")
    menu_launcher.get_installed_plugin_repos(path_dirs, "INFO", "")
    menu_launcher.get_installed_plugin_repos(invalid_dirs, "INFO", "remove")
    menu_launcher.get_installed_plugin_repos(invalid_dirs, "INFO", "update")
    menu_launcher.get_installed_plugin_repos(invalid_dirs, "INFO", "")

    # Test with installed plugins
    url = "https://github.com/CyberReboot/vent-plugins.git"
    env = test_env.TestEnv()
    env.add_plugin(path_dirs, url)
    menu_launcher.get_installed_plugin_repos(path_dirs, "INFO", "remove")
    menu_launcher.get_installed_plugin_repos(path_dirs, "INFO", "update")
    menu_launcher.get_installed_plugin_repos(path_dirs, "INFO", "")
    env.remove_plugin(path_dirs, url)

def test_update_plugins():
    """ Test update_plugins function with valid and invalid directories """
    path_dirs = test_env.PathDirs()
    invalid_dirs = test_env.PathDirs(base_dir="/tmp/")
    menu_launcher.update_plugins(path_dirs)
    menu_launcher.update_plugins(invalid_dirs)

def test_build_menu_dict():
    """ Test build_menu_dict """
    path_dirs = test_env.PathDirs()
    menu_launcher.build_menu_dict(path_dirs)

def test_get_container_menu():
    """test get_container_menu"""
    path_dirs = test_env.PathDirs()
    menu_launcher.get_container_menu(path_dirs)

def test_get_namespace_menu():
    """test get_namespace_menu"""
    path_dirs = test_env.PathDirs()
    menu_launcher.get_namespace_menu(path_dirs)

def test_running_menu():
    """ test running the actual menu """
    cmd_invalid_path = "python2.7 menu_launcher.py "
    child0 = pexpect.spawn(cmd_invalid_path)
    # expect main menu
    child0.expect('Exit')
    # go to mode
    child0.sendline('1')
    child0.expect('Return to Vent menu')
    # go to main menu
    child0.sendline('6')
    child0.expect('Exit')
    # exit
    child0.sendline('7')
    child0.read()
    child0.close()

    path_dirs = test_env.PathDirs()
    cmd = "python2.7 menu_launcher.py "+path_dirs.base_dir+" "+path_dirs.info_dir+" "+path_dirs.data_dir
    invalid_url = "https://thisisinvalid-.git"
    child = pexpect.spawn(cmd)
    # expect main menu
    child.expect('Exit')
    ### Mode Menu ###
    # go to mode
    child.sendline('1')
    child.expect('Return to Vent menu')
    # go to start
    child.sendline('1')
    child.expect('Return to Mode menu')
    # return to mode
    child.sendline('2')
    child.expect('Return to Vent menu')
    # go to stop
    child.sendline('2')
    child.expect('Return to Mode menu')
    # return to mode
    child.sendline('2')
    child.expect('Return to Vent menu')
    # go to clean
    child.sendline('3')
    child.expect('Return to Mode menu')
    # return to mode
    child.sendline('2')
    child.expect('Return to Vent menu')
    # go to status
    child.sendline('4')
    child.expect('Return to Mode menu')
    # return to mode
    child.sendline('7')
    child.expect('Return to Vent menu')
    # go to configure
    child.sendline('5')
    child.expect('Return to Mode menu')
    # return to mode
    child.sendline('5')
    child.expect('Return to Vent menu')
    # return to main menu
    child.sendline('6')
    child.expect('Exit')

    ### Plugins Menu ###
    # go to plugins menu
    child.sendline('2')
    child.expect('Return to Vent menu')
    # add plugin
    child.sendline('1')
    # send url
    child.sendline(invalid_url)
    child.expect('Operation complete. Press any key to continue...')
    # press a key
    # go to plugins menu
    child.send('q')
    child.expect('Exit')
    # go to plugins menu
    child.sendline('2')
    child.expect('Return to Vent menu')
    # go to remove plugin
    child.sendline('2')
    child.expect('Return to Plugins menu')
    # remove plugin
    child.sendline('1')
    child.expect('Return to Vent menu')
    # go to install plugins
    child.sendline('3')
    child.expect('Return to Plugins menu')
    # go to plugins menu
    child.sendline('2')
    child.expect('Return to Vent menu')
    # go to update plugins
    child.sendline('4')
    child.expect('Return to Plugins menu')
    # go to plugins menu
    child.sendline('2')
    child.expect('Return to Vent menu')
    # go to main menu
    child.sendline('5')
    child.expect('Exit')

    ### System Info Menu ###
    # go to System Info Menu
    child.sendline('3')
    child.expect('Return to Vent menu')
    # go to Container Stats
    child.sendline('1')
    child.expect('CONTAINER')
    # return to System Info Menu
    child.sendcontrol('c')
    child.expect('Return to Vent menu')
    # return to Main Menu
    child.sendline('9')
    child.expect('Exit')

    ### Build Menu ###
    # go to Build menu
    child.sendline('4')
    child.expect('Return to Vent menu')
    # Build new plugins and core
    child.sendline('1')
    child.expect('Operation complete. Press any key to continue...')
    # Send confirmation
    child.send('q')
    child.expect('Return to Vent menu')
    # !! TODO - Test Force Rebuild
    # return to Main Menu
    child.sendline('3')
    child.expect('Exit')

    ### System Commands Menu ###
    # go to system commands
    child.sendline('5')
    child.expect('Return to Vent menu')
    # go to logs menu
    child.sendline('1')
    child.expect('Return to System Commands menu')
    # go to containers menu
    child.sendline('1')
    child.expect('Return to Logs menu')
    # return to logs menu
    child.sendline('2')
    child.expect('Return to System Commands menu')
    # go to namespaces menu
    child.sendline('2')
    child.expect('Return to Logs menu')
    # return to logs menu
    child.sendline('2')
    child.expect('Return to System Commands menu')
    # return to system commands menu
    child.sendline('5')
    child.expect('Return to Vent menu')
    # go to main menu
    child.sendline('5')
    child.expect('Exit')

    ### Help ###
    # go to Help
    child.sendline('6')
    child.expect('getting started')
    # return to Main Menu
    child.send('q')
    child.expect('Exit')

    # exit
    child.sendline('7')
    child.read()
    child.close()
    # TODO finish going through menu actions

def test_running_add_plugin():
    """ testing running the menu and adding a plugin """
    path_dirs = test_env.PathDirs()
    cmd = "python2.7 menu_launcher.py "+path_dirs.base_dir+" "+path_dirs.info_dir+" "+path_dirs.data_dir
    child1 = pexpect.spawn(cmd)
    child1.timeout = 600
    ### Plugins Menu ###
    # go to plugins menu
    child1.sendline('2')
    child1.expect('Return to Vent menu')
    # add plugin
    child1.sendline('1')
    # send url
    child1.sendline("https://github.com/CyberReboot/vent-plugins.git")
    child1.expect('Press any key to continue...')
    # press a key
    # go to plugins menu
    child1.send('q')
    child1.expect('Exit')
    child1.sendline('7')
    child1.read()
    child1.close()

def test_running_remove_plugin():
    """ testing running the menu and removing a plugin """
    path_dirs = test_env.PathDirs()
    cmd = "python2.7 menu_launcher.py "+path_dirs.base_dir+" "+path_dirs.info_dir+" "+path_dirs.data_dir
    child1 = pexpect.spawn(cmd)
    ### Plugins Menu ###
    # go to plugins menu
    child1.sendline('2')
    child1.expect('Return to Vent menu')
    # remove plugin menu
    child1.sendline('2')
    child1.expect('Return to Plugins menu')
    # remove plugin
    child1.sendline('1')
    child1.expect('Press any key to continue...')
    # press a key
    # go to plugins menu
    child1.send('q')
    child1.expect('Return to Vent menu')
    # go to main menu
    child1.sendline('5')
    child1.expect('Exit')
    child1.sendline('7')
    child1.read()
    child1.close()

def test_running_configure_template():
    """ testing running the menu and configuring a template file """
    path_dirs = test_env.PathDirs()
    cmd = "python2.7 menu_launcher.py "+path_dirs.base_dir+" "+path_dirs.info_dir+" "+path_dirs.data_dir
    child1 = pexpect.spawn(cmd)
    # go to modes menu
    child1.sendline('1')
    child1.expect('Return to Vent menu')
    # go to configure menu
    child1.sendline('5')
    child1.expect('Return to Mode menu')
    # configure a template
    child1.sendline('1')
    child1.expect('Suplemon')
    # quit out of editing the template
    child1.sendcontrol('q')
    child1.expect('Return to Mode menu')
    # return to modes menu
    child1.sendline('6')
    child1.expect('Return to Vent menu')
    # go to main menu
    child1.sendline('6')
    child1.expect('Exit')
    child1.sendline('7')
    child1.read()
    child1.close()
<commit_msg>Now that info_dir is fixed in test instance, get_info is revealed as broken. Testing to see if its just get_info that is broken.<commit_after>import ConfigParser
import curses
import os
import pexpect
import pytest

from .. import menu_launcher
import test_env

def test_pathdirs():
    """ Gets path directory class from menu_launcher """
    path_dirs = menu_launcher.PathDirs()

def test_get_plugin_status():
    """ Test get_plugin_status function with valid and invalid directories """
    path_dirs = test_env.PathDirs()
    invalid_dirs = test_env.PathDirs(base_dir="/tmp/")
    menu_launcher.get_plugin_status(path_dirs)
    menu_launcher.get_plugin_status(invalid_dirs)

def test_run_plugins():
    """ Test get_run_plugins function with valid and invalid directories """
    # Prep
    os.system("cp modes.backup templates/modes.template")
    os.system("cp core.backup templates/core.template")

    path_dirs = test_env.PathDirs()
    invalid_dirs = test_env.PathDirs(base_dir="/tmp/")
    menu_launcher.run_plugins(path_dirs, "start")
    menu_launcher.run_plugins(invalid_dirs, "start")

    ### Visualization Test ###
    # Find modes.template
    os.system("touch "+path_dirs.template_dir+'modes.template')
    config = ConfigParser.RawConfigParser()
    config.read(path_dirs.template_dir+'modes.template')

    # Check for valid sections/options
    if not config.has_section("plugins"):
        config.add_section("plugins")
    config.set("plugins", "vis_test", "all")

    with open(path_dirs.template_dir+'modes.template', 'w') as f:
        config.write(f)

    # Test with one visualization plugin (filewalk)
    vis_test = "/vis_test"
    if not os.path.exists(path_dirs.vis_dir+vis_test):
        os.system("mkdir "+path_dirs.vis_dir+vis_test)

    menu_launcher.run_plugins(path_dirs, "start")

    # Cleanup
    os.system("rm -rf "+path_dirs.vis_dir+vis_test)
    os.system("cp modes.backup templates/modes.template")

    ### Collectors: Passive/Active Test ###
    # Find core.template
    os.system("touch "+path_dirs.template_dir+'core.template')
    config = ConfigParser.RawConfigParser()
    config.read(path_dirs.template_dir+'core.template')

    # Check for valid sections/options
    config.set("local-collection", "passive", "on")
    config.set("local-collection", "active", "on")

    with open(path_dirs.template_dir+'core.template', 'w') as f:
        config.write(f)

    # Test with one passive/active collector.
    active = "/active-test-collector"
    passive = "/passive-test-collector"

    if not os.path.exists(path_dirs.collectors_dir+active):
        os.system("mkdir "+path_dirs.collectors_dir+active)
    if not os.path.exists(path_dirs.collectors_dir+passive):
        os.system("mkdir "+path_dirs.collectors_dir+passive)

    menu_launcher.run_plugins(path_dirs, "start")

    # Cleanup
    os.system("rm -rf "+path_dirs.collectors_dir+active)
    os.system("rm -rf "+path_dirs.collectors_dir+active)
    os.system("cp core.backup templates/core.template")

    menu_launcher.run_plugins(path_dirs, "start")

def test_get_installed_plugin_repos():
    """ Test get_installed_plugin_repos function with valid and invalid directories """
    path_dirs = test_env.PathDirs()
    invalid_dirs = test_env.PathDirs(base_dir="/tmp/")
    menu_launcher.get_installed_plugin_repos(path_dirs, "INFO", "remove")
    menu_launcher.get_installed_plugin_repos(path_dirs, "INFO", "update")
    menu_launcher.get_installed_plugin_repos(path_dirs, "INFO", "")
    menu_launcher.get_installed_plugin_repos(invalid_dirs, "INFO", "remove")
    menu_launcher.get_installed_plugin_repos(invalid_dirs, "INFO", "update")
    menu_launcher.get_installed_plugin_repos(invalid_dirs, "INFO", "")

    # Test with installed plugins
    url = "https://github.com/CyberReboot/vent-plugins.git"
    env = test_env.TestEnv()
    env.add_plugin(path_dirs, url)
    menu_launcher.get_installed_plugin_repos(path_dirs, "INFO", "remove")
    menu_launcher.get_installed_plugin_repos(path_dirs, "INFO", "update")
    menu_launcher.get_installed_plugin_repos(path_dirs, "INFO", "")
    env.remove_plugin(path_dirs, url)

def test_update_plugins():
    """ Test update_plugins function with valid and invalid directories """
    path_dirs = test_env.PathDirs()
    invalid_dirs = test_env.PathDirs(base_dir="/tmp/")
    menu_launcher.update_plugins(path_dirs)
    menu_launcher.update_plugins(invalid_dirs)

def test_build_menu_dict():
    """ Test build_menu_dict """
    path_dirs = test_env.PathDirs()
    menu_launcher.build_menu_dict(path_dirs)

def test_get_container_menu():
    """test get_container_menu"""
    path_dirs = test_env.PathDirs()
    menu_launcher.get_container_menu(path_dirs)

def test_get_namespace_menu():
    """test get_namespace_menu"""
    path_dirs = test_env.PathDirs()
    menu_launcher.get_namespace_menu(path_dirs)

def test_running_menu():
    """ test running the actual menu """
    cmd_invalid_path = "python2.7 menu_launcher.py "
    child0 = pexpect.spawn(cmd_invalid_path)
    # expect main menu
    child0.expect('Exit')
    # go to mode
    child0.sendline('1')
    child0.expect('Return to Vent menu')
    # go to main menu
    child0.sendline('6')
    child0.expect('Exit')
    # exit
    child0.sendline('7')
    child0.read()
    child0.close()

    path_dirs = test_env.PathDirs()
    cmd = "python2.7 menu_launcher.py "+path_dirs.base_dir+" "+path_dirs.info_dir+" "+path_dirs.data_dir
    invalid_url = "https://thisisinvalid-.git"
    child = pexpect.spawn(cmd)
    # expect main menu
    child.expect('Exit')
    ### Mode Menu ###
    # go to mode
    child.sendline('1')
    child.expect('Return to Vent menu')
    # go to start
    child.sendline('1')
    child.expect('Return to Mode menu')
    # return to mode
    child.sendline('2')
    child.expect('Return to Vent menu')
    # go to stop
    child.sendline('2')
    child.expect('Return to Mode menu')
    # return to mode
    child.sendline('2')
    child.expect('Return to Vent menu')
    # go to clean
    child.sendline('3')
    child.expect('Return to Mode menu')
    # return to mode
    child.sendline('2')
    child.expect('Return to Vent menu')
    # go to status
    child.sendline('4')
    child.expect('Return to Mode menu')
    # return to mode
    child.sendline('7')
    child.expect('Return to Vent menu')
    # go to configure
    child.sendline('5')
    child.expect('Return to Mode menu')
    # return to mode
    child.sendline('5')
    child.expect('Return to Vent menu')
    # return to main menu
    child.sendline('6')
    child.expect('Exit')

    ### Plugins Menu ###
    # go to plugins menu
    child.sendline('2')
    child.expect('Return to Vent menu')
    # add plugin
    child.sendline('1')
    # send url
    child.sendline(invalid_url)
    child.expect('Operation complete. Press any key to continue...')
    # press a key
    # go to plugins menu
    child.send('q')
    child.expect('Exit')
    # go to plugins menu
    child.sendline('2')
    child.expect('Return to Vent menu')
    # go to remove plugin
    child.sendline('2')
    child.expect('Return to Plugins menu')
    # remove plugin
    child.sendline('1')
    child.expect('Return to Vent menu')
    # go to install plugins
    child.sendline('3')
    child.expect('Return to Plugins menu')
    # go to plugins menu
    child.sendline('2')
    child.expect('Return to Vent menu')
    # go to update plugins
    child.sendline('4')
    child.expect('Return to Plugins menu')
    # go to plugins menu
    child.sendline('2')
    child.expect('Return to Vent menu')
    # go to main menu
    child.sendline('5')
    child.expect('Exit')

    ### System Info Menu ###
    # go to System Info Menu
    child.sendline('3')
    child.expect('Return to Vent menu')
    # go to Container Stats
    child.sendline('1')
    child.expect('CONTAINER')
    # return to System Info Menu
    child.sendcontrol('c')
    child.expect('Return to Vent menu')
    # return to Main Menu
    child.sendline('9')
    child.expect('Exit')

    ### Build Menu ###
    # go to Build menu
    child.sendline('4')
    child.expect('Return to Vent menu')
    # Build new plugins and core
    child.sendline('1')
    child.expect('Operation complete. Press any key to continue...')
    # Send confirmation
    child.send('q')
    child.expect('Return to Vent menu')
    # !! TODO - Test Force Rebuild
    # return to Main Menu
    child.sendline('3')
    child.expect('Exit')

    ### System Commands Menu ###
    # go to system commands
    child.sendline('5')
    child.expect('Return to Vent menu')
    # go to logs menu
    child.sendline('1')
    child.expect('Return to System Commands menu')
    # # go to containers menu
    # child.sendline('1')
    # child.expect('Return to Logs menu')
    # # return to logs menu
    # child.sendline('2')
    # child.expect('Return to System Commands menu')
    # # go to namespaces menu
    # child.sendline('2')
    # child.expect('Return to Logs menu')
    # # return to logs menu
    # child.sendline('2')
    # child.expect('Return to System Commands menu')
    # return to system commands menu
    child.sendline('5')
    child.expect('Return to Vent menu')
    # go to main menu
    child.sendline('5')
    child.expect('Exit')

    ### Help ###
    # go to Help
    child.sendline('6')
    child.expect('getting started')
    # return to Main Menu
    child.send('q')
    child.expect('Exit')

    # exit
    child.sendline('7')
    child.read()
    child.close()
    # TODO finish going through menu actions

def test_running_add_plugin():
    """ testing running the menu and adding a plugin """
    path_dirs = test_env.PathDirs()
    cmd = "python2.7 menu_launcher.py "+path_dirs.base_dir+" "+path_dirs.info_dir+" "+path_dirs.data_dir
    child1 = pexpect.spawn(cmd)
    child1.timeout = 600
    ### Plugins Menu ###
    # go to plugins menu
    child1.sendline('2')
    child1.expect('Return to Vent menu')
    # add plugin
    child1.sendline('1')
    # send url
    child1.sendline("https://github.com/CyberReboot/vent-plugins.git")
    child1.expect('Press any key to continue...')
    # press a key
    # go to plugins menu
    child1.send('q')
    child1.expect('Exit')
    child1.sendline('7')
    child1.read()
    child1.close()

def test_running_remove_plugin():
    """ testing running the menu and removing a plugin """
    path_dirs = test_env.PathDirs()
    cmd = "python2.7 menu_launcher.py "+path_dirs.base_dir+" "+path_dirs.info_dir+" "+path_dirs.data_dir
    child1 = pexpect.spawn(cmd)
    ### Plugins Menu ###
    # go to plugins menu
    child1.sendline('2')
    child1.expect('Return to Vent menu')
    # remove plugin menu
    child1.sendline('2')
    child1.expect('Return to Plugins menu')
    # remove plugin
    child1.sendline('1')
    child1.expect('Press any key to continue...')
    # press a key
    # go to plugins menu
    child1.send('q')
    child1.expect('Return to Vent menu')
    # go to main menu
    child1.sendline('5')
    child1.expect('Exit')
    child1.sendline('7')
    child1.read()
    child1.close()

def test_running_configure_template():
    """ testing running the menu and configuring a template file """
    path_dirs = test_env.PathDirs()
    cmd = "python2.7 menu_launcher.py "+path_dirs.base_dir+" "+path_dirs.info_dir+" "+path_dirs.data_dir
    child1 = pexpect.spawn(cmd)
    # go to modes menu
    child1.sendline('1')
    child1.expect('Return to Vent menu')
    # go to configure menu
    child1.sendline('5')
    child1.expect('Return to Mode menu')
    # configure a template
    child1.sendline('1')
    child1.expect('Suplemon')
    # quit out of editing the template
    child1.sendcontrol('q')
    child1.expect('Return to Mode menu')
    # return to modes menu
    child1.sendline('6')
    child1.expect('Return to Vent menu')
    # go to main menu
    child1.sendline('6')
    child1.expect('Exit')
    child1.sendline('7')
    child1.read()
    child1.close()
<|endoftext|>


<commit_before>"""Fetch SEPTA (Philadelphia) bus and rail feeds."""

from datetime import datetime
import logging
import os
import zipfile

from bs4 import BeautifulSoup
import requests

from FeedSource import FeedSource, TIMECHECK_FMT

DEVELOPER_URL = 'http://www2.septa.org/developer/'
URL = DEVELOPER_URL + 'download.php'
LAST_UPDATED_FMT = '%a, %d %b %Y %H:%M:%S'

# SEPTA provides two GTFS .zip files themselves zipped together
DOWNLOAD_FILE_NAME = 'septa.zip'
# names of the two files in the downloaded .zip
BUS_EXTRACT_FILE = 'google_bus.zip'
RAIL_EXTRACT_FILE = 'google_rail.zip'
# rename the extrated GTFS to this
BUS_FILE = 'septa_bus.zip'
RAIL_FILE = 'septa_rail.zip'

LOG = logging.getLogger(__name__)

class Septa(FeedSource):
    """Fetch SEPTA feeds."""
    def __init__(self):
        super(Septa, self).__init__()
        self.urls = {DOWNLOAD_FILE_NAME: URL}

    def fetch(self):
        """Fetch SEPTA bus and rail feeds.

        First scrape the download page to see if a new feed is available,
        since the last-modified header is not set on the download.
        """
        page = requests.get(DEVELOPER_URL)
        LOG.debug('Checking last SEPTA update time...')
        last_mod = datetime.utcnow()
        if page.ok:
            soup = BeautifulSoup(page.text)
            last_mod = soup.find('div', 'col_content').find('p').text
            LOG.info('SEPTA download page: %s.', last_mod)
            last_mod_str = last_mod[14:]  # trim out date string
            last_mod = datetime.strptime(last_mod_str, LAST_UPDATED_FMT)  # convert to date
            stat = self.status.get(BUS_FILE)
            posted_date = last_mod.strftime(TIMECHECK_FMT)
            if stat:
                got_last = datetime.strptime(stat['posted_date'], TIMECHECK_FMT)
                if got_last >= last_mod:
                    LOG.info('No new download available for SEPTA.')
                    self.update_existing_status(BUS_FILE)
                    self.update_existing_status(RAIL_FILE)
                    return
                else:
                    LOG.info('New SEPTA download available.')
                    LOG.info('Latest SEPTA download posted: %s.', last_mod)
                    LOG.info('Previous download retrieved: %s.', got_last)
            else:
                LOG.debug('No previous SEPTA download found.')
        else:
            LOG.error('failed to get SEPTA dowload info page.')

        self.set_posted_date(BUS_FILE, posted_date)
        self.set_posted_date(RAIL_FILE, posted_date)

        if self.download(DOWNLOAD_FILE_NAME, URL, do_stream=False):
            # remove posted date status for parent zip
            del self.status[DOWNLOAD_FILE_NAME]
            septa_file = os.path.join(self.ddir, DOWNLOAD_FILE_NAME)
            if self.extract(septa_file):
                self.write_status()
            # delete download file once the two GTFS zips in it are extracted
            os.remove(septa_file)
        else:
            # clear error for parent septa.zip download, and set statuses for bus and rail feeds
            err = self.status.get(DOWNLOAD_FILE_NAME, 'Could not download file')
            self.status = {}
            self.set_error(BUS_FILE, err)
            self.set_error(RAIL_FILE, err)

    def extract(self, file_name):
        """Extract bus and rail GTFS files from downloaded zip, then validate each."""
        with zipfile.ZipFile(file_name) as zipped_septa:
            if len(zipped_septa.namelist()) == 2:
                zipped_septa.extractall(path=self.ddir)
                bus_path = os.path.join(self.ddir, BUS_EXTRACT_FILE)
                rail_path = os.path.join(self.ddir, RAIL_EXTRACT_FILE)
                if os.path.isfile(bus_path) and os.path.isfile(rail_path):
                    # rename the extracted files
                    os.rename(rail_path, os.path.join(self.ddir, RAIL_FILE))
                    os.rename(bus_path, os.path.join(self.ddir, BUS_FILE))

                    rail_good = bus_good = False
                    if self.verify(BUS_FILE):
                        bus_good = True
                    else:
                        LOG.warn('SEPTA bus GTFS verification failed.')
                        return False
                    if self.verify(RAIL_FILE):
                        rail_good = True
                    else:
                        LOG.warn('SEPTA rail GTFS verification failed.')
                        return False
                    if rail_good and bus_good:
                        LOG.info('SEPTA bus and rail verification succeeded.')
                        return True
                else:
                    LOG.error('Could not find SEPTA GTFS files with expected names.')
                    return False
            else:
                LOG.error('Unexpected contents in SEPTA zip file download: %s',
                          zipped_septa.namelist())
                LOG.error('Expected two files, but got %s.',
                          len(zipped_septa.namelist()))
                LOG.error('Not extracting SEPTA zip.')
                return False

        LOG.error('How did we get here? In SEPTA extract.')
        return False # should be unreachable
<commit_msg>Fetch SEPTA from GitHub.<commit_after>"""Fetch SEPTA (Philadelphia) bus and rail feeds."""

from datetime import datetime
import logging
import os
import zipfile

import requests

from FeedSource import FeedSource, TIMECHECK_FMT

URL = 'https://api.github.com/repos/septadev/GTFS/releases/latest'
LAST_UPDATED_FMT = '%Y-%m-%dT%H:%M:%SZ'

# SEPTA provides two GTFS .zip files themselves zipped together
DOWNLOAD_FILE_NAME = 'septa.zip'
# names of the two files in the downloaded .zip
BUS_EXTRACT_FILE = 'google_bus.zip'
RAIL_EXTRACT_FILE = 'google_rail.zip'
# rename the extrated GTFS to this
BUS_FILE = 'septa_bus.zip'
RAIL_FILE = 'septa_rail.zip'

LOG = logging.getLogger(__name__)

class Septa(FeedSource):
    """Fetch SEPTA feeds."""
    def __init__(self):
        super(Septa, self).__init__()
        self.urls = {DOWNLOAD_FILE_NAME: URL}

    def fetch(self):
        """Fetch SEPTA bus and rail feeds.
        """
        # Check GitHub latest release page to see if there is a newer download available.
        request = requests.get(URL)
        if request.ok:
            response = request.json()
            download_url = response['assets'][0]['browser_download_url']
            last_updated_str = response['assets'][0]['updated_at']
            last_updated = datetime.strptime(last_updated_str, LAST_UPDATED_FMT)
            stat = self.status.get(BUS_FILE)
            if stat:
                got_last = datetime.strptime(stat['posted_date'], TIMECHECK_FMT)
                LOG.debug('SEPTA GTFS last fetched: %s, last updated: %s', got_last, last_updated)
                if got_last >= last_updated:
                    LOG.info('No new download available for SEPTA.')
                    self.update_existing_status(BUS_FILE)
                    self.update_existing_status(RAIL_FILE)
                    return
            else:
                LOG.info('No previous SEPTA download found. Last update posted: %s', last_updated)

            posted_date = last_updated.strftime(TIMECHECK_FMT)
            self.set_posted_date(BUS_FILE, posted_date)
            self.set_posted_date(RAIL_FILE, posted_date)

            if self.download(DOWNLOAD_FILE_NAME, download_url, do_stream=False):
                # remove posted date status for parent zip
                del self.status[DOWNLOAD_FILE_NAME]
                septa_file = os.path.join(self.ddir, DOWNLOAD_FILE_NAME)
                if self.extract(septa_file):
                    self.write_status()
                # delete download file once the two GTFS zips in it are extracted
                os.remove(septa_file)
            else:
                # clear error for parent septa.zip download, and set statuses for bus and rail feeds
                err = self.status.get(DOWNLOAD_FILE_NAME, 'Could not download file')
                self.status = {}
                self.set_error(BUS_FILE, err)
                self.set_error(RAIL_FILE, err)
                self.write_status()
        else:
            LOG.error('Could not check GitHub relases page for SEPTA.')

    def extract(self, file_name):
        """Extract bus and rail GTFS files from downloaded zip, then validate each."""
        with zipfile.ZipFile(file_name) as zipped_septa:
            if len(zipped_septa.namelist()) == 2:
                zipped_septa.extractall(path=self.ddir)
                bus_path = os.path.join(self.ddir, BUS_EXTRACT_FILE)
                rail_path = os.path.join(self.ddir, RAIL_EXTRACT_FILE)
                if os.path.isfile(bus_path) and os.path.isfile(rail_path):
                    # rename the extracted files
                    os.rename(rail_path, os.path.join(self.ddir, RAIL_FILE))
                    os.rename(bus_path, os.path.join(self.ddir, BUS_FILE))

                    rail_good = bus_good = False
                    if self.verify(BUS_FILE):
                        bus_good = True
                    else:
                        LOG.warn('SEPTA bus GTFS verification failed.')
                        return False
                    if self.verify(RAIL_FILE):
                        rail_good = True
                    else:
                        LOG.warn('SEPTA rail GTFS verification failed.')
                        return False
                    if rail_good and bus_good:
                        LOG.info('SEPTA bus and rail verification succeeded.')
                        return True
                else:
                    LOG.error('Could not find SEPTA GTFS files with expected names.')
                    return False
            else:
                LOG.error('Unexpected contents in SEPTA zip file download: %s',
                          zipped_septa.namelist())
                LOG.error('Expected two files, but got %s.',
                          len(zipped_septa.namelist()))
                LOG.error('Not extracting SEPTA zip.')
                return False

        LOG.error('How did we get here? In SEPTA extract.')
        return False # should be unreachable
<|endoftext|>


<commit_before>import unittest
import mock

from chainer import testing
from chainer import training

class DummyExtension(training.extension.Extension):

    def __init__(self):
        self.is_called = False
        self.is_finalized = False

    def __call__(self, trainer):
        self.is_called = True

    def finalize(self):
        self.is_finalized = True

class TestExtension(unittest.TestCase):

    def setUp(self):
        self.trainer = _get_mocked_trainer()

    def test_default_name(self):
        class MyExtension(training.Extension):
            pass

        ext = MyExtension()
        self.assertEqual(ext.default_name, 'MyExtension')

    def test_make_extension(self):
        @training.make_extension(trigger=(2, 'epoch'), default_name='my_ext',
                                 priority=50, invoke_before_training=True)
        def my_extension(trainer):
            pass

        self.assertEqual(my_extension.trigger, (2, 'epoch'))
        self.assertEqual(my_extension.default_name, 'my_ext')
        self.assertEqual(my_extension.priority, 50)
        self.assertTrue(my_extension.invoke_before_training)

    def test_make_extension_default_values(self):
        @training.make_extension()
        def my_extension(trainer):
            pass

        self.assertEqual(my_extension.trigger, (1, 'iteration'))
        self.assertEqual(my_extension.default_name, 'my_extension')
        self.assertEqual(my_extension.priority, training.PRIORITY_READER)
        self.assertFalse(my_extension.invoke_before_training)

    def test_add_class_extension(self):
        dummy_extension = DummyExtension()
        self.trainer.extend(dummy_extension)
        self.trainer.run()
        self.assertTrue(dummy_extension.is_called)
        self.assertTrue(dummy_extension.is_finalized)

    def test_add_make_extension(self):
        self.is_called = False
        @training.make_extension()
        def dummy_extension(trainer):
            self.is_called = True

        self.trainer.extend(dummy_extension)
        self.trainer.run()
        self.assertTrue(self.is_called)

    def test_add_two_extensions_default_priority(self):
        self.called_order = []

        @training.make_extension(trigger=(1, 'epoch'))
        def dummy_extension_1(trainer):
            self.called_order.append(1)

        @training.make_extension(trigger=(1, 'epoch'))
        def dummy_extension_2(trainer):
            self.called_order.append(2)

        self.trainer.extend(dummy_extension_1)
        self.trainer.extend(dummy_extension_2)
        self.trainer.run()
        self.assertEqual(self.called_order, [1, 2])

    def test_add_two_extensions_specific_priority(self):
        self.called_order = []

        @training.make_extension(trigger=(1, 'epoch'), priority=50)
        def dummy_extension_1(trainer):
            self.called_order.append(1)

        @training.make_extension(trigger=(1, 'epoch'), priority=100)
        def dummy_extension_2(trainer):
            self.called_order.append(2)

        self.trainer.extend(dummy_extension_1)
        self.trainer.extend(dummy_extension_2)
        self.trainer.run()
        self.assertEqual(self.called_order, [2, 1])

def _get_mocked_trainer(stop_trigger=(10, 'iteration')):
    updater = mock.Mock()
    updater.get_all_optimizers.return_value = {}
    updater.iteration = 0
    updater.epoch_detail = 1

    def update():
        updater.iteration += 1

    updater.update = update
    return training.Trainer(updater, stop_trigger)

testing.run_module(__name__, __file__)
<commit_msg>flake8<commit_after>import mock
import unittest

from chainer import testing
from chainer import training

class DummyExtension(training.extension.Extension):

    def __init__(self):
        self.is_called = False
        self.is_finalized = False

    def __call__(self, trainer):
        self.is_called = True

    def finalize(self):
        self.is_finalized = True

class TestExtension(unittest.TestCase):

    def setUp(self):
        self.trainer = _get_mocked_trainer()

    def test_default_name(self):
        class MyExtension(training.Extension):
            pass

        ext = MyExtension()
        self.assertEqual(ext.default_name, 'MyExtension')

    def test_make_extension(self):
        @training.make_extension(trigger=(2, 'epoch'), default_name='my_ext',
                                 priority=50, invoke_before_training=True)
        def my_extension(trainer):
            pass

        self.assertEqual(my_extension.trigger, (2, 'epoch'))
        self.assertEqual(my_extension.default_name, 'my_ext')
        self.assertEqual(my_extension.priority, 50)
        self.assertTrue(my_extension.invoke_before_training)

    def test_make_extension_default_values(self):
        @training.make_extension()
        def my_extension(trainer):
            pass

        self.assertEqual(my_extension.trigger, (1, 'iteration'))
        self.assertEqual(my_extension.default_name, 'my_extension')
        self.assertEqual(my_extension.priority, training.PRIORITY_READER)
        self.assertFalse(my_extension.invoke_before_training)

    def test_add_class_extension(self):
        dummy_extension = DummyExtension()
        self.trainer.extend(dummy_extension)
        self.trainer.run()
        self.assertTrue(dummy_extension.is_called)
        self.assertTrue(dummy_extension.is_finalized)

    def test_add_make_extension(self):
        self.is_called = False

        @training.make_extension()
        def dummy_extension(trainer):
            self.is_called = True

        self.trainer.extend(dummy_extension)
        self.trainer.run()
        self.assertTrue(self.is_called)

    def test_add_two_extensions_default_priority(self):
        self.called_order = []

        @training.make_extension(trigger=(1, 'epoch'))
        def dummy_extension_1(trainer):
            self.called_order.append(1)

        @training.make_extension(trigger=(1, 'epoch'))
        def dummy_extension_2(trainer):
            self.called_order.append(2)

        self.trainer.extend(dummy_extension_1)
        self.trainer.extend(dummy_extension_2)
        self.trainer.run()
        self.assertEqual(self.called_order, [1, 2])

    def test_add_two_extensions_specific_priority(self):
        self.called_order = []

        @training.make_extension(trigger=(1, 'epoch'), priority=50)
        def dummy_extension_1(trainer):
            self.called_order.append(1)

        @training.make_extension(trigger=(1, 'epoch'), priority=100)
        def dummy_extension_2(trainer):
            self.called_order.append(2)

        self.trainer.extend(dummy_extension_1)
        self.trainer.extend(dummy_extension_2)
        self.trainer.run()
        self.assertEqual(self.called_order, [2, 1])

def _get_mocked_trainer(stop_trigger=(10, 'iteration')):
    updater = mock.Mock()
    updater.get_all_optimizers.return_value = {}
    updater.iteration = 0
    updater.epoch_detail = 1

    def update():
        updater.iteration += 1

    updater.update = update
    return training.Trainer(updater, stop_trigger)

testing.run_module(__name__, __file__)
<|endoftext|>


<commit_before># Copyright 2019 CyberTech Labs Ltd. & Andrei Khodko
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import os
import types
from enum import IntEnum

script = types.SimpleNamespace()
script.random = script_cpp.random
script.wait = script_cpp.wait
script.time = script_cpp.time
script.timer = script_cpp.timer
script.system = script_cpp.system
script.writeToFile = script_cpp.writeToFile
script.writeData = script_cpp.writeData
script.readAll = script_cpp.readAll
script.removeFile = script_cpp.removeFile
script.run = script_cpp.run
script.quit = script_cpp.quit
script.reset = script_cpp.reset

class KeysEnum(IntEnum):
    Left = 105
    Up = 103
    Down = 108
    Enter = 28
    Right = 106
    Power = 116
    Esc = 1

class Events(IntEnum):
    Sync = 0
    Key = 1
    Relative = 2
    Absolute = 3
    Misc = 4

class MouseEventCodes(IntEnum):
    X = 0
    Y = 1
    Wheel = 8

    LeftBtn = 272
    RightBtn = 273
    MiddleBtn = 274

class PadEventCodes(IntEnum):
    BtnA = 304
    BtnB = 305
    BtnC = 306
    BtnX = 307
    BtnY = 308
    BtnZ = 309

    BtnTL = 310
    BtnTR = 311
    BtnTL2 = 312
    BtnTR2 = 313
    BtnSelect = 314
    BtnStart = 315

    X = 0
    Y = 1
    Z = 2
    Rx = 3
    Ry = 4
    Rz = 5

    Throttle = 6
    Rudder = 7
    Wheel = 8
    Gas = 9
    Break = 10

    Hat0X = 16
    Hat0Y = 17
    Hat1X = 18
    Hat1Y = 19
<commit_msg>Check for python modules in user folder<commit_after># Copyright 2019 CyberTech Labs Ltd. & Andrei Khodko
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import os
import types
import sys
from enum import IntEnum

script = types.SimpleNamespace()
script.random = script_cpp.random
script.wait = script_cpp.wait
script.time = script_cpp.time
script.timer = script_cpp.timer
script.system = script_cpp.system
script.writeToFile = script_cpp.writeToFile
script.writeData = script_cpp.writeData
script.readAll = script_cpp.readAll
script.removeFile = script_cpp.removeFile
script.run = script_cpp.run
script.quit = script_cpp.quit
script.reset = script_cpp.reset

sys.path.append('')

class KeysEnum(IntEnum):
    Left = 105
    Up = 103
    Down = 108
    Enter = 28
    Right = 106
    Power = 116
    Esc = 1

class Events(IntEnum):
    Sync = 0
    Key = 1
    Relative = 2
    Absolute = 3
    Misc = 4

class MouseEventCodes(IntEnum):
    X = 0
    Y = 1
    Wheel = 8

    LeftBtn = 272
    RightBtn = 273
    MiddleBtn = 274

class PadEventCodes(IntEnum):
    BtnA = 304
    BtnB = 305
    BtnC = 306
    BtnX = 307
    BtnY = 308
    BtnZ = 309

    BtnTL = 310
    BtnTR = 311
    BtnTL2 = 312
    BtnTR2 = 313
    BtnSelect = 314
    BtnStart = 315

    X = 0
    Y = 1
    Z = 2
    Rx = 3
    Ry = 4
    Rz = 5

    Throttle = 6
    Rudder = 7
    Wheel = 8
    Gas = 9
    Break = 10

    Hat0X = 16
    Hat0Y = 17
    Hat1X = 18
    Hat1Y = 19
<|endoftext|>


<commit_before>#    BOREALISbot2 - a Discord bot to interface between SS13 and discord.
#    Copyright (C) 2016 Skull132

#    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/.

from .command import BorealisCommand

class CommandUserInfo(BorealisCommand):
	"""Returns the name, UID, and auths (if any) of the targeted user."""

	@classmethod
	async def do_command(cls, bot, message, params):
		reply = "```\n"
		reply += "Nickname: {0}\n".format(message.mentions[0].name)
		reply += "Discord ID: {0}\n\n".format(message.mentions[0].id)

		try:
			response = bot.query_api("/discord/strike", "get", {"discord_id" : message.mentions[0].id}, ["strike_count"], enforce_return_keys = True)

			reply += "Active strikes: {0}\n\n".format(response["strike_count"])
		except RuntimeError as e:
			reply += "Unable to retreive active strike count!\n\n"

		if message.mentions[0].id in bot.config.users:
			reply += "They are linked to staff permits with the following details:\n"
			user_dict = bot.config.users[message.mentions[0].id]
			reply += "Associated ckey: {0}\n".format(user_dict["ckey"])
			reply += "Associated auths: {0}\n".format(user_dict["auth"])
		else:
			reply += "They are not linked to staff permits.\n"

		reply += "```"

		await bot.send_message(message.channel, reply)
		return

	@classmethod
	def get_name(cls):
		return "UserInfo"

	@classmethod
	def get_description(cls):
		return "Showcases information about the specified Discord user."

	@classmethod
	def get_params(cls):
		return "<mention user>"

	@classmethod
	def get_auths(cls):
		return ["R_MOD", "R_ADMIN"]

	@classmethod
	def verify_params(cls, params, message, bot):
		if super(CommandUserInfo, cls).verify_params(params, message, bot) == False:
			return False

		if len(message.mentions) != 1:
			return False

		return True
<commit_msg>CommandUserInfo - messages to requester Instead of pasta-ing potentially sensitive information over the public discord, it now sends it to the authorized individual requesting it. Weee.<commit_after>#    BOREALISbot2 - a Discord bot to interface between SS13 and discord.
#    Copyright (C) 2016 Skull132

#    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/.

from .command import BorealisCommand

class CommandUserInfo(BorealisCommand):
	"""Returns the name, UID, and auths (if any) of the targeted user."""

	@classmethod
	async def do_command(cls, bot, message, params):
		reply = "```\n"
		reply += "Nickname: {0}\n".format(message.mentions[0].name)
		reply += "Discord ID: {0}\n\n".format(message.mentions[0].id)

		try:
			response = bot.query_api("/discord/strike", "get", {"discord_id" : message.mentions[0].id}, ["strike_count"], enforce_return_keys = True)

			reply += "Active strikes: {0}\n\n".format(response["strike_count"])
		except RuntimeError as e:
			reply += "Unable to retreive active strike count!\n\n"

		if message.mentions[0].id in bot.config.users:
			reply += "They are linked to staff permits with the following details:\n"
			user_dict = bot.config.users[message.mentions[0].id]
			reply += "Associated ckey: {0}\n".format(user_dict["ckey"])
			reply += "Associated auths: {0}\n".format(user_dict["auth"])
		else:
			reply += "They are not linked to staff permits.\n"

		reply += "```"

		await bot.send_message(message.channel, "{0}, I've sent the requested information to you in a PM!".format(message.author.mention))
		await bot.forward_message(message.author, reply)
		return

	@classmethod
	def get_name(cls):
		return "UserInfo"

	@classmethod
	def get_description(cls):
		return "Showcases information about the specified Discord user."

	@classmethod
	def get_params(cls):
		return "<mention user>"

	@classmethod
	def get_auths(cls):
		return ["R_MOD", "R_ADMIN"]

	@classmethod
	def verify_params(cls, params, message, bot):
		if super(CommandUserInfo, cls).verify_params(params, message, bot) == False:
			return False

		if len(message.mentions) != 1:
			return False

		return True
<|endoftext|>


<commit_before>import os
from datetime import datetime
from lxml import etree

from django.conf import settings
from django.core.mail import send_mail
from django.db.models import get_model
from django.template.loader import render_to_string

from .settings import FEEDMAPPER

class Parser(object):
    "Base parser class for mapping Django model fields to feed nodes."

    def __init__(self, mapping):
        self.mapping = mapping
        self.nsmap = {}
        self.data_dir = FEEDMAPPER['DATA_DIR']

    @property
    def data_source(self):
        if not self.mapping.source.startswith('/') and not '://' in self.mapping.source:
            return os.path.join(self.data_dir, self.mapping.source)
        return self.mapping.source

    def validate_model_format(self, model_string):
        "Validate that a model in the JSON mapping is in the format app.model."
        if not '.' in model_string or model_string.count('.') > 1:
            return False
        return True

    def generate_filter_kwargs(self, filter_string):
        """
        Convert a string to kwargs that can be passed to the Django ORM's filter
        method. For example, 'slug__icontains="darth", name="Anakin"' will get
        converted to {'slug__icontains': 'darth', 'name': 'Anakin'}.
        """
        filters = filter_string.replace('"', '').replace("'", '').split(',')
        filter_kwargs = dict([str(filter).strip().split('=') for filter in filters])
        return filter_kwargs

    def notify_failure(self, subject=None):
        "Notify recipients, if specified, of an error during parsing."
        if not subject:
            subject = "django-feedmapper parsing failure notice"
        message = render_to_string('feedmapper/notify_failure.txt', {
            'mapping': self.mapping,
            'parse_attempted': self.mapping.parse_attempted,
            'parse_log': self.mapping.parse_log
        })
        recipients = self.mapping.notification_recipients.split('\r\n')
        send_mail(subject, message, settings.DEFAULT_FROM_EMAIL, recipients)

    def parse(self):
        raise NotImplementedError("You must override the parse method in a Parser subclass.")

class XMLParser(Parser):
    "A parser for XML that does not follow any standard."

    def get_value(self, node, path, as_text=True):
        "Attempts to retrieve either the node text or node attribute specified."
        if '@' in path:
            if path.count('@') > 1:
                raise ValueError("You have more than one attribute accessor. (e.g. foo.@bar.@baz)")
            path, attr = path.rsplit('.@')
            resolved = node.find(path, namespaces=self.nsmap).attrib.get(attr, "")
        else:
            if path == ".":
                # this will get text in an XML node, regardless of placement
                resolved = ''.join([text.strip() for text in node.xpath("text()")])
            else:
                # fixme: hacky shit; separate get_value to get_value and get_value_text
                resolved = node.findall(path, namespaces=self.nsmap)
                resolved = ((len(resolved) > 0 and resolved[0].text) or "") if as_text else resolved

        return resolved.strip() if as_text else resolved

    def join_fields(self, node, fields):
        "Joins the text for the specified fields."
        values = [self.get_value(node, field) for field in fields]
        return " ".join(values)

    def parse(self):
        """
        Traverses through the XML document and parses the data, applying it to the
        model specified in the :py:class:`~feedmapper.models.Mapping`.
        """
        self.mapping.parse_attempted = datetime.now()
        try:
            tree = etree.parse(self.data_source)
            root = tree.getroot()

            model_mappings = self.mapping.data_map['models']
            purge_filter = self.mapping.data_map.get('purge_filter')
            for model_string, configuration in model_mappings.items():
                if not self.validate_model_format(model_string):
                    raise ValueError("Invalid model format in JSON mapping: %s" % model_string)
                identifier = configuration.get('identifier')
                if not identifier and not self.mapping.purge:
                    raise UserWarning("Purging is off and the JSON mapping doesn't supply an identifier.")
                model = get_model(*model_string.split('.'))
                node_path = configuration['nodePath'].replace('.', '/')
                fields = configuration['fields']
                nodes = root.xpath(node_path, namespaces=self.nsmap)

                if self.mapping.purge:
                    # remove existing items
                    existing_items = model.objects.all()
                    if purge_filter:
                        filter_kwargs = self.generate_filter_kwargs(purge_filter)
                        if filter_kwargs:
                            existing_items = existing_items.filter(**filter_kwargs)
                    existing_items.delete()

                for node in nodes:
                    if self.mapping.purge:
                        instance = model()
                    else:
                        # purge is turned off, retrieve an existing instance
                        identifier_value = node.find(identifier, namespaces=self.nsmap).text

                        kwargs = {identifier: identifier_value}
                        new = False
                        try:
                            instance = model.objects.get(**kwargs)
                        except model.DoesNotExist:
                            instance = model(**kwargs)
                            new = True

                    many_to_many = {}
                    for field, target in fields.items():
                        # if field != identifier:
                        if isinstance(target, basestring):
                            # maps one model field to one feed node
                            value = self.get_value(node, target)
                        elif isinstance(target, list):
                            # maps one model field to multiple feed nodes
                            value = self.join_fields(node, target)
                        elif isinstance(target, dict):
                            value = None
                            if 'transformer' in target:
                                # maps one model field to a transformer method
                                transformer = getattr(instance, target['transformer'])

                                transformer_args = []

                                field_is_m2m = False
                                if len(target["fields"]) == 1 and target["fields"][0].endswith("*"):
                                    # we've hit a many2many relation
                                    transformer_args = self.get_value(node, target["fields"][0][:-1], as_text=False)
                                    field_is_m2m = True

                                else:
                                    for target_field in target["fields"]:

                                        if target_field.endswith("*"):
                                            raise ValueError(u"M2m fields can only contain one target field")
                                        else:
                                            transformer_args.append(self.get_value(node, target_field))

                                value = transformer(*transformer_args)

                                if field_is_m2m:
                                    many_to_many[field] = value
                                    continue

                            if 'default' in target and not value:
                                # maps one model field to a default value
                                value = target['default']
                        setattr(instance, field, value)
                    instance.save()

                    # handle m2m
                    for field, values in many_to_many.iteritems():
                        instance_field = getattr(instance, field)
                        old_m2ms = instance_field.all()

                        # remove not anymore existing m2ms
                        for old_m2m_value in old_m2ms:
                            if not old_m2m_value in values:
                                instance_field.remove(old_m2m_value)

                        # add new m2ms
                        for value in values:
                            if not value in old_m2ms:
                                instance_field.add(value)

            self.mapping.parse_succeeded = True
            self.mapping.parse_log = ""
        except etree.Error as e:
            self.mapping.parse_succeeded = False
            self.mapping.parse_log = str(e.error_log)
        except IOError as e:
            self.mapping.parse_succeeded = False
            self.mapping.parse_log = e.args[0]
        # clear the lxml error log so errors don't compound
        etree.clear_error_log()
        self.mapping.save()

        # notify the authorities if a failure occured
        if not self.mapping.parse_succeeded and self.mapping.notification_recipients:
            self.notify_failure()

class AtomParser(XMLParser):
    "An XML parser for the Atom standard."

    def __init__(self, mapping):
        super(AtomParser, self).__init__(mapping)
        self.nsmap = {'atom': 'http://www.w3.org/2005/Atom'}<commit_msg>refactor docstrings<commit_after>import os
from datetime import datetime
from lxml import etree

from django.conf import settings
from django.core.mail import send_mail
from django.db.models import get_model
from django.template.loader import render_to_string

from .settings import FEEDMAPPER

class Parser(object):
    """
    Base parser class for mapping Django model fields to feed nodes.
    """

    def __init__(self, mapping):
        self.mapping = mapping
        self.nsmap = {}
        self.data_dir = FEEDMAPPER['DATA_DIR']

    @property
    def data_source(self):
        if not self.mapping.source.startswith('/') and not '://' in self.mapping.source:
            return os.path.join(self.data_dir, self.mapping.source)
        return self.mapping.source

    def validate_model_format(self, model_string):
        """
        Validate that a model in the JSON mapping is in the format app.model.
        """
        if not '.' in model_string or model_string.count('.') > 1:
            return False
        return True

    def generate_filter_kwargs(self, filter_string):
        """
        Convert a string to kwargs that can be passed to the Django ORM's filter
        method. For example, 'slug__icontains="darth", name="Anakin"' will get
        converted to {'slug__icontains': 'darth', 'name': 'Anakin'}.
        """
        filters = filter_string.replace('"', '').replace("'", '').split(',')
        filter_kwargs = dict([str(filter).strip().split('=') for filter in filters])
        return filter_kwargs

    def notify_failure(self, subject=None):
        """
        Notify recipients, if specified, of an error during parsing.
        """

        if not subject:
            subject = "django-feedmapper parsing failure notice"
        message = render_to_string('feedmapper/notify_failure.txt', {
            'mapping': self.mapping,
            'parse_attempted': self.mapping.parse_attempted,
            'parse_log': self.mapping.parse_log
        })
        recipients = self.mapping.notification_recipients.split('\r\n')
        send_mail(subject, message, settings.DEFAULT_FROM_EMAIL, recipients)

    def parse(self):
        raise NotImplementedError("You must override the parse method in a Parser subclass.")

class XMLParser(Parser):
    """
    A parser for XML that does not follow any standard.
    """

    def get_value(self, node, path, as_text=True):
        """
        Attempts to retrieve either the node text or node attribute specified.
        :param node:
        :param path:
        :param as_text:
        :return:
        """
        if '@' in path:
            if path.count('@') > 1:
                raise ValueError("You have more than one attribute accessor. (e.g. foo.@bar.@baz)")
            path, attr = path.rsplit('.@')
            resolved = node.find(path, namespaces=self.nsmap).attrib.get(attr, "")
        else:
            if path == ".":
                # this will get text in an XML node, regardless of placement
                resolved = ''.join([text.strip() for text in node.xpath("text()")])
            else:
                # fixme: hacky shit; separate get_value to get_value and get_value_text
                resolved = node.findall(path, namespaces=self.nsmap)
                resolved = ((len(resolved) > 0 and resolved[0].text) or "") if as_text else resolved

        return resolved.strip() if as_text else resolved

    def join_fields(self, node, fields):
        """
        Joins the text for the specified fields.
        :param node:
        :param fields:
        :return:
        """
        values = [self.get_value(node, field) for field in fields]
        return " ".join(values)

    def parse(self):
        """
        Traverses through the XML document and parses the data, applying it to the
        model specified in the :py:class:`~feedmapper.models.Mapping`.
        """
        self.mapping.parse_attempted = datetime.now()
        try:
            tree = etree.parse(self.data_source)
            root = tree.getroot()

            model_mappings = self.mapping.data_map['models']
            purge_filter = self.mapping.data_map.get('purge_filter')
            for model_string, configuration in model_mappings.items():
                if not self.validate_model_format(model_string):
                    raise ValueError("Invalid model format in JSON mapping: %s" % model_string)
                identifier = configuration.get('identifier')
                if not identifier and not self.mapping.purge:
                    raise UserWarning("Purging is off and the JSON mapping doesn't supply an identifier.")
                model = get_model(*model_string.split('.'))
                node_path = configuration['nodePath'].replace('.', '/')
                fields = configuration['fields']
                nodes = root.xpath(node_path, namespaces=self.nsmap)

                if self.mapping.purge:
                    # remove existing items
                    existing_items = model.objects.all()
                    if purge_filter:
                        filter_kwargs = self.generate_filter_kwargs(purge_filter)
                        if filter_kwargs:
                            existing_items = existing_items.filter(**filter_kwargs)
                    existing_items.delete()

                for node in nodes:
                    if self.mapping.purge:
                        instance = model()
                    else:
                        # purge is turned off, retrieve an existing instance
                        identifier_value = node.find(identifier, namespaces=self.nsmap).text

                        kwargs = {identifier: identifier_value}
                        new = False
                        try:
                            instance = model.objects.get(**kwargs)
                        except model.DoesNotExist:
                            instance = model(**kwargs)
                            new = True

                    many_to_many = {}
                    for field, target in fields.items():
                        # if field != identifier:
                        if isinstance(target, basestring):
                            # maps one model field to one feed node
                            value = self.get_value(node, target)
                        elif isinstance(target, list):
                            # maps one model field to multiple feed nodes
                            value = self.join_fields(node, target)
                        elif isinstance(target, dict):
                            value = None
                            if 'transformer' in target:
                                # maps one model field to a transformer method
                                transformer = getattr(instance, target['transformer'])

                                transformer_args = []

                                field_is_m2m = False
                                if len(target["fields"]) == 1 and target["fields"][0].endswith("*"):
                                    # we've hit a many2many relation
                                    transformer_args = self.get_value(node, target["fields"][0][:-1], as_text=False)
                                    field_is_m2m = True

                                else:
                                    for target_field in target["fields"]:

                                        if target_field.endswith("*"):
                                            raise ValueError(u"M2m fields can only contain one target field")
                                        else:
                                            transformer_args.append(self.get_value(node, target_field))

                                value = transformer(*transformer_args)

                                if field_is_m2m:
                                    many_to_many[field] = value
                                    continue

                            if 'default' in target and not value:
                                # maps one model field to a default value
                                value = target['default']
                        setattr(instance, field, value)
                    instance.save()

                    # handle m2m
                    for field, values in many_to_many.iteritems():
                        instance_field = getattr(instance, field)
                        old_m2ms = instance_field.all()

                        # remove not anymore existing m2ms
                        for old_m2m_value in old_m2ms:
                            if not old_m2m_value in values:
                                instance_field.remove(old_m2m_value)

                        # add new m2ms
                        for value in values:
                            if not value in old_m2ms:
                                instance_field.add(value)

            self.mapping.parse_succeeded = True
            self.mapping.parse_log = ""
        except etree.Error as e:
            self.mapping.parse_succeeded = False
            self.mapping.parse_log = str(e.error_log)
        except IOError as e:
            self.mapping.parse_succeeded = False
            self.mapping.parse_log = e.args[0]
        # clear the lxml error log so errors don't compound
        etree.clear_error_log()
        self.mapping.save()

        # notify the authorities if a failure occured
        if not self.mapping.parse_succeeded and self.mapping.notification_recipients:
            self.notify_failure()

class AtomParser(XMLParser):
    """
    An XML parser for the Atom standard.
    """

    def __init__(self, mapping):
        super(AtomParser, self).__init__(mapping)
        self.nsmap = {'atom': 'http://www.w3.org/2005/Atom'}<|endoftext|>


<commit_before># game.py  (c) 2017 D.J.Whale  22/01/2017
# Star-Wars 'Use the Force, Luke' game
# Using many moving parts provided by Martin O'Hanlon

#----- CONFIGURATION ----------------------------------------------------------

DEATHSTAR_CENTRE_POS = (100,100,10)
TARGET_POS           = (100,100,10)
IN_RANGE             = ((100,100,10), (100,100,10))
XWING_START_POS      = (46,10,-61)
PLAY_TIME_SECS       = 5 #(2*60)
NUMBER_OF_TRIES      = 3
FRAMES_PER_SEC       = 10

#TODO: Mart's code animates the trench separately from deathstar
#so do we need to switch over to that animation at the right position?
#also is there a visual clue to where the trench is, in the deathstar model?

#TODO: xwing can turn or shift
#might make it turn if you tilt it left or right a long way
#in which case we need l,L and r,R for two ranges of left and right tilt

#----- LOAD ALL THE DEPENDENT PARTS -------------------------------------------

import sys
if sys.version_info[0] != 2:
    print("Please run this game with Python version 2")
    sys.exit()

import time
import controller # auto-connects to the controller
import starwars   # auto-connects to Minecraft

#----- GAME STATE -------------------------------------------------------------

deathstar      = None
xwing          = None
missile        = None
xwing_crashed  = False
missile_missed = False
missile_hit    = False
game_stop_time = 0

#----- BUILD THE GAME WORLD ---------------------------------------------------

def clear_space():
    print("will clear_space")
    #TODO:

def build_deathstar():
    print("will build_deathstar")
    #TODO: build at DEATHSTAR_CENTRE_POS

def create_xwing():
    global xwing
    if xwing is not None:
        # kill off old x-wing
        xwing.clear()
        xwing = None

    xwing = starwars.MCObject(starwars.XWING_BLOCKS, XWING_START_POS)
    xwing.draw()

def setup_game():
    clear_space()
    build_deathstar()
    create_xwing()
    clear_flags()

def wait_for_start():
    print("will wait_for_start")
    raw_input("press RETURN to start")
    #TODO: wait for A button press on micro:bit
    #loop, read from micro:bit, until see 'A'

#----- GAME ACTIONS -----------------------------------------------------------

def fly_xwing():
    buttons = controller.get_command_flags()
    if buttons is not None:
        up    = 'U' in buttons
        down  = 'D' in buttons
        left  = 'L' in buttons
        right = 'R' in buttons
        fire  = 'A' in buttons
        eject = 'B' in buttons

        # change xwing position based on u/d/l/r
        if left:
            xwing.move_by(x=-1)
            print("left")
        if right:
            xwing.move_by(x=+1)
            print("right")
        if up:
            xwing.move_by(y=+1)
            print("up")
        if down:
            xwing.move_by(y=-1)
            print("down")

        if fire:  print("boom!!")
        if eject: print("yeehar!!")

    # always move xwing forward by one block
    ##xwing.move_by(z=-1)

    # if xwing crashes into any block
    #   set_xwing_crashed()
    #if fire:  start_missile()
    #if eject: ejector_seat()

def start_missile():
    print("will start_missile")
    #TODO:
    # create missile object in front of xwing
    # note we need to know what direction the xwing is flying in
    # we also need to know a range of positions to succeed from

def move_missile():
    print("will move_missile")
    #TODO:
    # if missile now out of range:
    #   set_missile_missed()
    # elif missile not yet hit target:
    #   move missile forward by 1
    # else must have hit
    #   set_missile_hit()

def ejector_seat():
    print("will ejector_seat")
    animate_eject()
    animate_xwing_crashed()
    set_xwing_crashed()

#------ GAME CONDITIONS -------------------------------------------------------
#
# Set various game conditions in the game state.
# The main loop will detect and action these appropriately.
# This prevents passing lots of variables around,
# but contains the global variables a bit more into a controlled space (here)

def clear_flags():
    global xwing_crashed, missile_missed, missile_hit
    xwing_crashed  = False
    missile_missed = False
    missile_hit    = False

def set_xwing_crashed():
    global xwing_crashed
    xwing_crashed = True

def set_missile_missed():
    global missile_missed
    missile_missed = True

def set_missile_hit():
    global missile_hit
    missile_hit = True

#----- ANIMATIONS -------------------------------------------------------------

def animate_missile_missed():
    print("will animate_missile_missed")
    #TODO:

def animate_missile_hit():
    print("will animate_missile_hit")
    #TODO:

def animate_eject():
    print("will animate_eject")
    #TODO:

def animate_xwing_crashed():
    print("will xwing_crashed")
    #TODO:

def animate_blow_up_deathstar():
    print("will blow_up_deathstar")
    #TODO:
    # auto pilot the ship to a safe location
    # animate the deathstar blowing up
    # return when deathstar gone

#----- SPLASH SCREENS ---------------------------------------------------------

def splash_screen():
    print("will splash_screen")
    #TODO:

def game_over_failed():
    print("will game_over_failed")
    #TODO:

def game_over_succeeded():
    print("will game_over_succeeded")
    #TODO:

#----- GAME LOOP --------------------------------------------------------------

def start_game():
    global game_stop_time
    print("will start_game")
    #TODO: move player to position on start (hides splash screen)
    game_stop_time = time.time() + PLAY_TIME_SECS

def run_out_of_time():
    return time.time() >= game_stop_time

def play_game():
    missiles_left = NUMBER_OF_TRIES

    while not run_out_of_time() and not xwing_crashed and not missile_hit and missiles_left > 0:

        time.sleep(1/float(FRAMES_PER_SEC))

        fly_xwing()
        if missile is not None:
            move_missile()

        if missile_missed:
            animate_missile_missed()
            missiles_left -= 1

        elif missile_hit:
            animate_missile_hit()
            animate_blow_up_deathstar()

    return missile_hit

def whereami():
    import starwars.mcpi.minecraft as minecraft
    mc = minecraft.Minecraft.create()
    x,y,z = mc.player.getTilePos()
    print(x,y,z)

#----- MAIN PROGRAM -----------------------------------------------------------

#if __name__ == "__main__":
#    while True:
#        setup_game()
#        splash_screen()
#        wait_for_start()
#        start_game()
#
#        success = play_game()
#
#        if success:
#            game_over_succeeded()
#        else:
#            game_over_failed()

#whereami()

create_xwing()
while True:
    print("fly")
    fly_xwing()
    time.sleep(0.1)

# END

<commit_msg>Can now fly an xwing with a micro:bit This is not just turns, it's up and down as well.<commit_after># game.py  (c) 2017 D.J.Whale  22/01/2017
# Star-Wars 'Use the Force, Luke' game
# Using many moving parts provided by Martin O'Hanlon

#----- CONFIGURATION ----------------------------------------------------------

DEATHSTAR_CENTRE_POS = (100,100,10)
TARGET_POS           = (100,100,10)
IN_RANGE             = ((100,100,10), (100,100,10))
XWING_START_POS      = (46,10,-61)
PLAY_TIME_SECS       = 5 #(2*60)
NUMBER_OF_TRIES      = 3
FRAMES_PER_SEC       = 10

#TODO: Mart's code animates the trench separately from deathstar
#so do we need to switch over to that animation at the right position?
#also is there a visual clue to where the trench is, in the deathstar model?

#TODO: xwing can turn or shift
#might make it turn if you tilt it left or right a long way
#in which case we need l,L and r,R for two ranges of left and right tilt

#----- LOAD ALL THE DEPENDENT PARTS -------------------------------------------

import sys
if sys.version_info[0] != 2:
    print("Please run this game with Python version 2")
    sys.exit()

import time
import controller # auto-connects to the controller
import starwars   # auto-connects to Minecraft

#----- GAME STATE -------------------------------------------------------------

deathstar      = None
xwing          = None
missile        = None
xwing_crashed  = False
missile_missed = False
missile_hit    = False
game_stop_time = 0

#----- BUILD THE GAME WORLD ---------------------------------------------------

def clear_space():
    print("will clear_space")
    #TODO:

def build_deathstar():
    print("will build_deathstar")
    #TODO: build at DEATHSTAR_CENTRE_POS

def create_xwing():
    global xwing
    if xwing is not None:
        # kill off old x-wing
        xwing.clear()
        xwing = None

    xwing = starwars.MCObject(starwars.XWING_BLOCKS, XWING_START_POS)
    xwing.draw()

def setup_game():
    clear_space()
    build_deathstar()
    create_xwing()
    clear_flags()

def wait_for_start():
    print("will wait_for_start")
    raw_input("press RETURN to start")
    #TODO: wait for A button press on micro:bit
    #loop, read from micro:bit, until see 'A'

#----- GAME ACTIONS -----------------------------------------------------------

def fly_xwing():
    buttons = controller.get_command_flags()
    if buttons is not None:
        up    = 'U' in buttons
        down  = 'D' in buttons
        left  = 'L' in buttons
        right = 'R' in buttons
        fire  = 'A' in buttons
        eject = 'B' in buttons

        # change xwing position based on u/d/l/r
        if left:
            xwing.rotate_by(yaw=-10)
            print("left")
        if right:
            xwing.rotate_by(yaw=+10)
            print("right")
        if up:
            xwing.move_by(y=+1)
            print("up")
        if down:
            xwing.move_by(y=-1)
            print("down")

        if fire:  print("boom!!")
        if eject: print("yeehar!!")

    # always move xwing forward by one block
    xwing.fly()

    # if xwing crashes into any block
    #   set_xwing_crashed()
    #if fire:  start_missile()
    #if eject: ejector_seat()

def start_missile():
    print("will start_missile")
    #TODO:
    # create missile object in front of xwing
    # note we need to know what direction the xwing is flying in
    # we also need to know a range of positions to succeed from

def move_missile():
    print("will move_missile")
    #TODO:
    # if missile now out of range:
    #   set_missile_missed()
    # elif missile not yet hit target:
    #   move missile forward by 1
    # else must have hit
    #   set_missile_hit()

def ejector_seat():
    print("will ejector_seat")
    animate_eject()
    animate_xwing_crashed()
    set_xwing_crashed()

#------ GAME CONDITIONS -------------------------------------------------------
#
# Set various game conditions in the game state.
# The main loop will detect and action these appropriately.
# This prevents passing lots of variables around,
# but contains the global variables a bit more into a controlled space (here)

def clear_flags():
    global xwing_crashed, missile_missed, missile_hit
    xwing_crashed  = False
    missile_missed = False
    missile_hit    = False

def set_xwing_crashed():
    global xwing_crashed
    xwing_crashed = True

def set_missile_missed():
    global missile_missed
    missile_missed = True

def set_missile_hit():
    global missile_hit
    missile_hit = True

#----- ANIMATIONS -------------------------------------------------------------

def animate_missile_missed():
    print("will animate_missile_missed")
    #TODO:

def animate_missile_hit():
    print("will animate_missile_hit")
    #TODO:

def animate_eject():
    print("will animate_eject")
    #TODO:

def animate_xwing_crashed():
    print("will xwing_crashed")
    #TODO:

def animate_blow_up_deathstar():
    print("will blow_up_deathstar")
    #TODO:
    # auto pilot the ship to a safe location
    # animate the deathstar blowing up
    # return when deathstar gone

#----- SPLASH SCREENS ---------------------------------------------------------

def splash_screen():
    print("will splash_screen")
    #TODO:

def game_over_failed():
    print("will game_over_failed")
    #TODO:

def game_over_succeeded():
    print("will game_over_succeeded")
    #TODO:

#----- GAME LOOP --------------------------------------------------------------

def start_game():
    global game_stop_time
    print("will start_game")
    #TODO: move player to position on start (hides splash screen)
    game_stop_time = time.time() + PLAY_TIME_SECS

def run_out_of_time():
    return time.time() >= game_stop_time

def play_game():
    missiles_left = NUMBER_OF_TRIES

    while not run_out_of_time() and not xwing_crashed and not missile_hit and missiles_left > 0:

        time.sleep(1/float(FRAMES_PER_SEC))

        fly_xwing()
        if missile is not None:
            move_missile()

        if missile_missed:
            animate_missile_missed()
            missiles_left -= 1

        elif missile_hit:
            animate_missile_hit()
            animate_blow_up_deathstar()

    return missile_hit

def whereami():
    import starwars.mcpi.minecraft as minecraft
    mc = minecraft.Minecraft.create()
    x,y,z = mc.player.getTilePos()
    print(x,y,z)

#----- MAIN PROGRAM -----------------------------------------------------------

#if __name__ == "__main__":
#    while True:
#        setup_game()
#        splash_screen()
#        wait_for_start()
#        start_game()
#
#        success = play_game()
#
#        if success:
#            game_over_succeeded()
#        else:
#            game_over_failed()

#whereami()

create_xwing()
while True:
    print("fly")
    fly_xwing()
    time.sleep(0.1)

# END

<|endoftext|>


<commit_before>#!/usr/bin/env python

from PyQt4.QtCore import *
from PyQt4.QtGui import *
from structdata import g_project
from structdata.requirement import Requirement
from structdata import Action
from eventeditor import EventEditor

class EditorButton(QPushButton):
    entries = None

    def __init__(self, item=None, parent=None):
        super(EditorButton, self).__init__(parent)
        self.item = item
        self.createButton()

    def createButton(self):
        if self.item is not None:
            self.setText(self.calcText(self.item))
        else:
            self.setText("+")
            menu = QMenu()
            for entry in self.entries:
                menu.addAction(entry)
            self.setMenu(menu)

    def calcText(self, item):
        raise NotImplementedError

class ActionButton(EditorButton):
    entries = ["ROOM_GOTO", "ITEM_MOVE", "VAR_SET"]

    def calcText(self, action):
        line = action.id
        for param in action.params:
            line = "%s %s" % (line, param.value)
        return line

class RequirementButton(EditorButton):
    entries = ["ITEM_REQ", "VAR_REQ"]

    def calcText(self, requirement):
        line = "%s %s %s" % (requirement.tag_name.upper(),
                             requirement.id, requirement.value)
        return line

class MinusButton(QPushButton):
    def sizeHint(self):
        return QSize(30, 30)

    def __init__(self, item, parent=None):
        super(MinusButton, self).__init__(parent)
        self.item = item
        self.setText("-")

class AreaEditor(QDialog):

    def __init__(self, area, parent=None):
        super(AreaEditor, self).__init__(parent)
        g_project.subscribe(self)
        self.area = area

        self.vl = QVBoxLayout(self)

        self.gl = QGridLayout()
        self.createList()

        self.vl.addLayout(self.gl)
        gl = QGridLayout()
        gl.addWidget(QLabel("Area name"), 0, 0)
        self.change_area_name = QLineEdit()
        self.change_area_name.setText(self.area.id)
        gl.addWidget(self.change_area_name, 0, 1)
        gl.addWidget(QLabel("Event name"), 1, 0)
        self.change_event_name = QLineEdit()
        self.change_event_name.setText(self.area.event)
        gl.addWidget(self.change_event_name, 1, 1)
        self.vl.addLayout(gl)
        self.vl.addStretch()
        self.vl.addWidget(QStatusBar(self))
        self.connect(self.change_area_name, SIGNAL("returnPressed()"),
                     self.changeAreaName)
        self.connect(self.change_event_name, SIGNAL("returnPressed()"),
                     self.changeEventName)

    def changeAreaName(self):
        """
        funzione che modifica il nome dell'area che si sta editando
        """
        if self.area.id != str(self.change_area_name.text()):
            self.area.id = str(self.change_area_name.text())
            g_project.notify()

    def changeEventName(self):
        """
        funzione che cambia il nome dell'evento associato all'area che si sta
        editando
        """
        if self.area.event != str(self.change_event_name.text()):
            event = g_project.data['events'][self.area.event]
            del g_project.data['events'][event.id]
            event.id = str(self.change_event_name.text())
            g_project.data['events'][event.id] = event
            self.area.event = event.id
            g_project.notify()

    def closeEvent(self, event=None):
        g_project.unsubscribe(self)

    def updateData(self):
        while (self.gl.itemAt(0)):
            item = self.gl.itemAt(0)
            item.widget().deleteLater()
            self.gl.removeItem(item)
        self.signal_minus_mapper.deleteLater()
        self.createList()

    def createList(self):
        """
        funzione che crea la lista dei bottoni per l'agigunta e la modifica
        di action e requirement
        """
        self.signal_minus_mapper = QSignalMapper(self)
        self.minus_buttons = []
        if self.area.event in g_project.data['events'].keys():
            self.event = g_project.data['events'][self.area.event]
        self.gl.addWidget(QLabel("Actions", parent=self), 0, 0)
        row, i = self.createButtons(ActionButton, self.event.actions, 1, 0)
        self.gl.addWidget(QLabel("Requirements", parent=self), row, 0)
        row += 1
        row, i = self.createButtons(RequirementButton, self.event.requirements,
                                 row, i)
        self.connect(self.signal_minus_mapper, SIGNAL("mapped(int)"),
                     self.removeElement)

    def createButtons(self, button_type, items, row_start, mapper_start_index):
        """
        funzione che crea tutti i bottoni per particolare insieme di dati.
        I parametri necessari sono il tipo di bottone che deve essere creato
        (button_type), l'elenco degli elementi da associare ai bottoni (items),
        la riga di partenza in cui inserire il bottone e l'indice da
        associare al QSignalMapper.
        La funzione ritorna la riga a cui e' arrivato nella costruzione e
        l'indice a cui e' arrivato il QSignalMapper
        """
        row = row_start
        i = mapper_start_index
        for item in items:
            button = button_type(item, self)
            minus_button = MinusButton(item)
            self.minus_buttons.append(minus_button)
            self.gl.addWidget(minus_button, row , 1)
            self.gl.addWidget(button, row, 0)
            self.connect(minus_button, SIGNAL("clicked()"),
                         self.signal_minus_mapper, SLOT("map()"))
            self.signal_minus_mapper.setMapping(minus_button, i)
            self.connect(button, SIGNAL("clicked()"),
                         self.editEvent)
            row += 1
            i += 1
        self.add_button = button_type(parent=self)
        self.gl.addWidget(self.add_button, row, 0)
        row += 1
        self.connect(self.add_button.menu(), SIGNAL("triggered(QAction *)"),
                     self.createNewEvent)
        return row, i

    def editEvent(self):
        self.createEventEditor(item=self.sender().item)

    def createNewEvent(self, act):
        self.createEventEditor(tag=act.text())

    def createEventEditor(self, tag=None, item=None):
        """
        funzione che crea un EventEditor relativo all'evento associato
        all'area
        """
        self.event_editor = EventEditor(self.event, item, tag, self)
        self.event_editor.move(self.x() + self.width() + 50, self.y())
        self.event_editor.setModal(True)
        self.event_editor.show()

    def removeElement(self, index):
        """
        funzione che elimina un action o un requirement dall'event associato
        all'area. La funzione prende in ingresso l'indice relativo
        al bottone selezionato
        """
        item = self.minus_buttons[index].item
        if isinstance(item, Action):
            index = self.event.actions.index(item)
            g_project.data['events'][self.area.event].actions.pop(index)
        else:
            index = self.event.requirements.index(item)
            g_project.data['events'][self.area.event].requirements.pop(index)
        g_project.notify()

if __name__ == "__main__":
    from openfilerooms import openFileRooms
    from savefilerooms import saveFileRooms

    openFileRooms('world.rooms')

    app = QApplication([])
    room = g_project.data['rooms']['Stanza Stella']
    area = AreaEditor(room.areas[1])

    area.show()
    area.move(200, 200)
    app.exec_()
    saveFileRooms("a.rooms")

<commit_msg>for each button in AreaEditor add setAutoDefault(False) so it isn't a button always with focus<commit_after>#!/usr/bin/env python

from PyQt4.QtCore import *
from PyQt4.QtGui import *
from structdata import g_project
from structdata.requirement import Requirement
from structdata import Action
from eventeditor import EventEditor

class EditorButton(QPushButton):
    entries = None

    def __init__(self, item=None, parent=None):
        super(EditorButton, self).__init__(parent)
        self.item = item
        self.createButton()

    def createButton(self):
        if self.item is not None:
            self.setText(self.calcText(self.item))
        else:
            self.setText("+")
            menu = QMenu()
            for entry in self.entries:
                menu.addAction(entry)
            self.setMenu(menu)

    def calcText(self, item):
        raise NotImplementedError

class ActionButton(EditorButton):
    entries = ["ROOM_GOTO", "ITEM_MOVE", "VAR_SET"]

    def calcText(self, action):
        line = action.id
        for param in action.params:
            line = "%s %s" % (line, param.value)
        return line

class RequirementButton(EditorButton):
    entries = ["ITEM_REQ", "VAR_REQ"]

    def calcText(self, requirement):
        line = "%s %s %s" % (requirement.tag_name.upper(),
                             requirement.id, requirement.value)
        return line

class MinusButton(QPushButton):
    def sizeHint(self):
        return QSize(30, 30)

    def __init__(self, item, parent=None):
        super(MinusButton, self).__init__(parent)
        self.item = item
        self.setText("-")

class AreaEditor(QDialog):

    def __init__(self, area, parent=None):
        super(AreaEditor, self).__init__(parent)
        g_project.subscribe(self)
        self.area = area

        self.vl = QVBoxLayout(self)

        self.gl = QGridLayout()
        self.createList()

        self.vl.addLayout(self.gl)
        gl = QGridLayout()
        gl.addWidget(QLabel("Area name"), 0, 0)
        self.change_area_name = QLineEdit()
        self.change_area_name.setText(self.area.id)
        gl.addWidget(self.change_area_name, 0, 1)
        gl.addWidget(QLabel("Event name"), 1, 0)
        self.change_event_name = QLineEdit()
        self.change_event_name.setText(self.area.event)
        gl.addWidget(self.change_event_name, 1, 1)
        self.vl.addLayout(gl)
        self.vl.addStretch()
        self.vl.addWidget(QStatusBar(self))
        self.connect(self.change_area_name, SIGNAL("returnPressed()"),
                     self.changeAreaName)
        self.connect(self.change_event_name, SIGNAL("returnPressed()"),
                     self.changeEventName)

    def changeAreaName(self):
        """
        funzione che modifica il nome dell'area che si sta editando
        """
        if self.area.id != str(self.change_area_name.text()):
            self.area.id = str(self.change_area_name.text())
            g_project.notify()

    def changeEventName(self):
        """
        funzione che cambia il nome dell'evento associato all'area che si sta
        editando
        """
        if self.area.event != str(self.change_event_name.text()):
            event = g_project.data['events'][self.area.event]
            del g_project.data['events'][event.id]
            event.id = str(self.change_event_name.text())
            g_project.data['events'][event.id] = event
            self.area.event = event.id
            g_project.notify()

    def closeEvent(self, event=None):
        g_project.unsubscribe(self)

    def updateData(self):
        while (self.gl.itemAt(0)):
            item = self.gl.itemAt(0)
            item.widget().deleteLater()
            self.gl.removeItem(item)
        self.signal_minus_mapper.deleteLater()
        self.createList()

    def createList(self):
        """
        funzione che crea la lista dei bottoni per l'agigunta e la modifica
        di action e requirement
        """
        self.signal_minus_mapper = QSignalMapper(self)
        self.minus_buttons = []
        if self.area.event in g_project.data['events'].keys():
            self.event = g_project.data['events'][self.area.event]
        self.gl.addWidget(QLabel("Actions", parent=self), 0, 0)
        row, i = self.createButtons(ActionButton, self.event.actions, 1, 0)
        self.gl.addWidget(QLabel("Requirements", parent=self), row, 0)
        row += 1
        row, i = self.createButtons(RequirementButton, self.event.requirements,
                                 row, i)
        self.connect(self.signal_minus_mapper, SIGNAL("mapped(int)"),
                     self.removeElement)

    def createButtons(self, button_type, items, row_start, mapper_start_index):
        """
        funzione che crea tutti i bottoni per particolare insieme di dati.
        I parametri necessari sono il tipo di bottone che deve essere creato
        (button_type), l'elenco degli elementi da associare ai bottoni (items),
        la riga di partenza in cui inserire il bottone e l'indice da
        associare al QSignalMapper.
        La funzione ritorna la riga a cui e' arrivato nella costruzione e
        l'indice a cui e' arrivato il QSignalMapper
        """
        row = row_start
        i = mapper_start_index
        for item in items:
            button = button_type(item, self)
            button.setAutoDefault(False)
            minus_button = MinusButton(item)
            minus_button.setAutoDefault(False)
            self.minus_buttons.append(minus_button)
            self.gl.addWidget(minus_button, row , 1)
            self.gl.addWidget(button, row, 0)
            self.connect(minus_button, SIGNAL("clicked()"),
                         self.signal_minus_mapper, SLOT("map()"))
            self.signal_minus_mapper.setMapping(minus_button, i)
            self.connect(button, SIGNAL("clicked()"),
                         self.editEvent)
            row += 1
            i += 1
        self.add_button = button_type(parent=self)
        self.add_button.setAutoDefault(False)
        self.gl.addWidget(self.add_button, row, 0)
        row += 1
        self.connect(self.add_button.menu(), SIGNAL("triggered(QAction *)"),
                     self.createNewEvent)
        return row, i

    def editEvent(self):
        self.createEventEditor(item=self.sender().item)

    def createNewEvent(self, act):
        self.createEventEditor(tag=act.text())

    def createEventEditor(self, tag=None, item=None):
        """
        funzione che crea un EventEditor relativo all'evento associato
        all'area
        """
        self.event_editor = EventEditor(self.event, item, tag, self)
        self.event_editor.move(self.x() + self.width() + 50, self.y())
        self.event_editor.setModal(True)
        self.event_editor.show()

    def removeElement(self, index):
        """
        funzione che elimina un action o un requirement dall'event associato
        all'area. La funzione prende in ingresso l'indice relativo
        al bottone selezionato
        """
        item = self.minus_buttons[index].item
        if isinstance(item, Action):
            index = self.event.actions.index(item)
            g_project.data['events'][self.area.event].actions.pop(index)
        else:
            index = self.event.requirements.index(item)
            g_project.data['events'][self.area.event].requirements.pop(index)
        g_project.notify()

if __name__ == "__main__":
    from openfilerooms import openFileRooms
    from savefilerooms import saveFileRooms

    openFileRooms('world.rooms')

    app = QApplication([])
    room = g_project.data['rooms']['Stanza Stella']
    area = AreaEditor(room.areas[1])

    area.show()
    area.move(200, 200)
    app.exec_()
    saveFileRooms("a.rooms")

<|endoftext|>