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

## Import needed modules
import socket
import re
import random
import sys
import time
import importlib
sys.path.insert(0, './modules') ## Path for the modules

## Config
import configjaska

## Load modules from the config
for mod in configjaska.config["modules"].split(","):
	try:
		print("Loading module {0}".format(mod))
		globals()[mod] = __import__(mod)
	except:
		raise

## Class pyBot
class pyBot:
	def __init__( self ):

		## Config and start the bot
		self.config = configjaska.config
		self.loop()

	## Send data function
	def send_data( self, data ):
		data += "\r\n"
		self.s.sendall( data.encode("utf-8") )
		print( data )

	## Join channel
	def join_chan( self, chan ):
		self.send_data("JOIN " + chan)

	## Send text to channel
	def send_chan( self, data ):
		msg = "PRIVMSG " + self.msg[2] + " :" + str(data)
		self.send_data( msg )
		print("Sending: " + msg)

	## Send a PM to the user doing a command
	def send_pm( self, data ):
		msg = "PRIVMSG " + self.get_nick() + " :" +str(data)
		self.send_data( msg )
		print("Sending PM: " + msg)

	## Parse commands function
	def parse_command( self, cmd ):
		try:
			print(getattr(globals()[cmd], cmd)( self ))
		except KeyError:
			self.send_chan( "Unknown command: !" + cmd )

	## Get nick
	def get_nick( self ):
		nick = re.search(":(.*)!", self.msg[0]).group(1)
		return(nick)

	## Main loop, connect etc.
	def loop( self ):

		nick = "NICK " + self.config["nick"]
		user = "USER " + self.config["ident"] + " " + self.config["host"] + " " + "pyTsunku :" + self.config["realname"]

		## ipv4/ipv6 support
		for res in socket.getaddrinfo( self.config["host"], self.config["port"], socket.AF_UNSPEC, socket.SOCK_STREAM ):
			af, socktype, proto, canonname, sa = res

		self.s = socket.socket( af, socktype, proto )

		try:
			self.s.connect(sa)
		except socket.error as msg:
			s.close()
			print("Could not open socket")

		## Send identification to the server
		self.send_data( nick )
		self.send_data( user )
		connected = 1
		logger = 0

		while connected == 1:
			try:
				data = self.s.recv(4096).decode("utf-8")
				if len(data) == 0:
					connected == 0
					print("Connection died, reconnecting");
					time.sleep(5)
					self.loop()
			except ConnectionResetError as msg:
					connected == 0
					if "ERROR :Trying to reconnect too fast." in data: ## Sleep 15 secs if reconnecting too fast
						time.sleep(15)
					else:
						time.sleep(5)
					self.loop()

			self.msg = data.split(" ") ## Slice data into list

			## Logger
			if logger == 1:
				logger_daemon.logger_daemon( self )

			## PING PONG
			if self.msg[0] == "PING":
				self.send_data( "PONG " + self.msg[1] )

			## Check if nick is in use, try alternative, if still in use, generate random number to the end of the nick
			try:
				if "433" in self.msg:
					self.send_data( "NICK " + self.config["altnick"] )
					if "433" in self.msg:
						self.send_data( "NICK " + self.config["nick"] + str(random.randrange(1,10+1)) )
			except IndexError:
				pass

			## If MOTD ended, everything is OK, so join the chans
			if "376" in self.msg:
				chans = self.config["chans"].split(",")
				for chan in chans:
					self.join_chan( chan )
				if self.config["logging"] == "true":
					logger = 1
					print("Logging enabled\r\n")
				else:
					print("Logging disabled\r\n")

			try:
				cmd = self.msg[3].rstrip("\r\n")
				cmd = cmd.lstrip(":")
				if cmd[0] == "!":
					cmd = cmd.lstrip("!") ## remove ! from the command before parsing it
					self.parse_command( cmd )
			except IndexError:
				pass ## No need to do anything

			## Get title for the URLs
			try:
				if "372" not in self.msg:
					url = re.search( "(http)(s)?:\/\/[a-zA-Z0-9\-\=.?&_/]+", data ).group(0)
					if url != None:
						title.title( self, url )
			except:
				pass

			## if debug is true, print some stuff
			if self.config["debug"] == "true":
				print(self.msg)
				print(data)

## Run the bot
try:
	bot = pyBot()
except KeyboardInterrupt:
	print("Ctrl+C Pressed, Quitting")
	<commit_msg>Add reload function<commit_after>#!/usr/bin/env python3

## Import needed modules
import socket
import re
import random
import sys
import time
import importlib
import imp

sys.path.insert(0, './modules') ## Path for the modules

## Config
import configjaska

## Load modules from the config
for mod in configjaska.config["modules"].split(","):
	try:
		print("Loading module {0}".format(mod))
		globals()[mod] = __import__(mod)
	except:
		raise

## Class pyBot
class pyBot:
	def __init__( self ):

		## Config and start the bot
		self.config = configjaska.config
		self.loop()

	## Send data function
	def send_data( self, data ):
		data += "\r\n"
		self.s.sendall( data.encode("utf-8") )
		print( data )

	## Join channel
	def join_chan( self, chan ):
		self.send_data("JOIN " + chan)

	## Send text to channel
	def send_chan( self, data ):
		msg = "PRIVMSG " + self.msg[2] + " :" + str(data)
		self.send_data( msg )
		print("Sending: " + msg)

	## Send a PM to the user doing a command
	def send_pm( self, data ):
		msg = "PRIVMSG " + self.get_nick() + " :" +str(data)
		self.send_data( msg )
		print("Sending PM: " + msg)

	## Parse commands function
	def parse_command( self, cmd ):
		try:
			print(getattr(globals()[cmd], cmd)( self ))
		except KeyError:
			self.send_chan( "Unknown command: !" + cmd )

	## Get nick
	def get_nick( self ):
		nick = re.search(":(.*)!", self.msg[0]).group(1)
		return(nick)

	## Reload modules
	def reload( self ):
		if self.get_nick() not in self.config["opers"]:
			return
		for mod in configjaska.config["modules"].split(","):
			try:
				print("Reloading module {0}".format(mod))
				imp.reload(globals()[mod])
			except:
				raise

	## Main loop, connect etc.
	def loop( self ):

		nick = "NICK " + self.config["nick"]
		user = "USER " + self.config["ident"] + " " + self.config["host"] + " " + "pyTsunku :" + self.config["realname"]

		## ipv4/ipv6 support
		for res in socket.getaddrinfo( self.config["host"], self.config["port"], socket.AF_UNSPEC, socket.SOCK_STREAM ):
			af, socktype, proto, canonname, sa = res

		self.s = socket.socket( af, socktype, proto )

		try:
			self.s.connect(sa)
		except socket.error as msg:
			s.close()
			print("Could not open socket")

		## Send identification to the server
		self.send_data( nick )
		self.send_data( user )
		connected = 1
		logger = 0

		while connected == 1:
			try:
				data = self.s.recv(4096).decode("utf-8")
				if len(data) == 0:
					connected == 0
					print("Connection died, reconnecting");
					time.sleep(5)
					self.loop()
			except ConnectionResetError as msg:
					connected == 0
					if "ERROR :Trying to reconnect too fast." in data: ## Sleep 15 secs if reconnecting too fast
						time.sleep(15)
					else:
						time.sleep(5)
					self.loop()

			self.msg = data.split(" ") ## Slice data into list

			## Logger
			if logger == 1:
				logger_daemon.logger_daemon( self )

			## PING PONG
			if self.msg[0] == "PING":
				self.send_data( "PONG " + self.msg[1] )

			## Check if nick is in use, try alternative, if still in use, generate random number to the end of the nick
			try:
				if "433" in self.msg:
					self.send_data( "NICK " + self.config["altnick"] )
					if "433" in self.msg:
						self.send_data( "NICK " + self.config["nick"] + str(random.randrange(1,10+1)) )
			except IndexError:
				pass

			## If MOTD ended, everything is OK, so join the chans
			if "376" in self.msg:
				chans = self.config["chans"].split(",")
				for chan in chans:
					self.join_chan( chan )
				if self.config["logging"] == "true":
					logger = 1
					print("Logging enabled\r\n")
				else:
					print("Logging disabled\r\n")

			try:
				cmd = self.msg[3].rstrip("\r\n")
				cmd = cmd.lstrip(":")
				if cmd[0] == "!":
					if cmd == "!reload":
						self.reload( )
					else:
						cmd = cmd.lstrip("!") ## remove ! from the command before parsing it
						self.parse_command( cmd )
			except IndexError:
				pass ## No need to do anything

			## Get title for the URLs
			try:
				if "372" not in self.msg:
					url = re.search( "(http)(s)?:\/\/[a-zA-Z0-9\-\=.?&_/]+", data ).group(0)
					if url != None:
						title.title( self, url )
			except:
				pass

			## if debug is true, print some stuff
			if self.config["debug"] == "true":
				print(self.msg)
				print(data)

## Run the bot
try:
	bot = pyBot()
except KeyboardInterrupt:
	print("Ctrl+C Pressed, Quitting")
	<|endoftext|>


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

from __future__ import print_function
from builtins import input

""" Python 2.7 & 3.4 disk wiping utility for use on Linux operating systems. RUN AS ROOT. """

import sys              # For interpreter variables & associated functions
import os               # For operating system dependent functions
import re               # For regular expression parsing

""" Define functions """

def osCheck():
    """ Check if OS is 'Linux' """
    if not sys.platform.startswith('linux'):
        print("This program was designed for Linux. Exiting.")
        sys.exit()

def listDevices():
    """ List mounted device(s) / partition(s) """

    print(22 * "-", "DEVICES & PARTITIONS", 22 * "-")                                      # Header

    return os.system('lsblk /dev/sd* --nodeps --output NAME,MODEL,VENDOR,SIZE,TYPE,STATE') # lsblk -d -o NAME,MODEL,VENDOR...

def defineDevice():
    """ Prompt user to define device or partition to wipe """

    while True:
        try:
            device = str(input("Enter letter [and number] of device/partition to wipe,\ne.g. to wipe '/dev/sdb' enter 'b': "))

            # if not re.match("^[a-z]$|^[a-z]\d$", device):
            if not re.match("^[a-z][0-9]?$", device):
                raise ValueError()
            return device

        except ValueError:
            print("Sorry, that's not a valid device or partition. Try again.")

def appendDevice():
    """ Append user-defined device/partition to /dev/sd """

    letter = defineDevice()

    return '/dev/sd' + letter

def numberOfWipes():
    """ Prompt user for number of wipes to perform """

    while True:
        try:
            wipes = int(input("How many times do you want to wipe the device or partition?: "))

            if not wipes > 0:
                raise ValueError()
            return wipes

        except ValueError:
            print("Sorry, that's not a valid number. Try again.")

def confirmWipe():
    """ Prompt user to confirm disk erasure """

    print("WARNING!!! WRITING CHANGES TO DISK WILL RESULT IN IRRECOVERABLE DATA LOSS.")

    while True:
        try:
            reply = str(input("Are you sure you want to proceed? (Yes/No): ")).lower().strip()

            if reply == 'yes':
                return True
            elif reply == 'no':
                print("Exiting pyWype.")
                sys.exit()

        except ValueError:
            print("Sorry, that's not a valid entry. Try again: ")

def zerosToDevice():
    """ Write zeros to device/partition """

    append = appendDevice()
    num = numberOfWipes()
    confirm = confirmWipe()

    passes = 1

    for int in range(num):
        print("Processing pass count {} of {} ... ".format(passes, num))
        os.system(('dd if=/dev/zero |pv --progress --time --rate --bytes| dd of={} bs=4096'.format(append))) # pv -ptrb
        passes += 1

def randomToDevice():
    """ Write random zeros and ones to device/partition """

    append = appendDevice()
    num = numberOfWipes()
    confirm = confirmWipe()

    passes = 1

    for int in range(num):
        print("Processing pass count {} of {} ... ".format(passes, num))
        os.system(('dd if=/dev/random |pv --progress --time --rate --bytes| dd of={} bs=4096'.format(append))) # pv -ptrb
        passes += 1

def menu():
    """ Menu prompt for use to select program option """

    devices = listDevices()

    while True:
        print(30 * "-", "MENU", 30 * "-")
        print("1. Overwrite device or partition with 0's \n(faster, less secure).")
        print("2. Overwrite device or partition with random 0\'s & 1\'s \n(slower, more secure).")
        print("3. Quit.")
        choice = input("Select an option (1, 2 or 3): ")

        if choice in ('1', '2', '3'):
            return choice

def interactiveMode():
    """ Display menu-driven options and run function based on selection """
    while True:
        choice = menu()

        if choice == '3':
            sys.exit()
        elif choice == '1':
            zerosToDevice()
        elif choice == '2':
            randomToDevice()

def wipeDevice():
    """ Program to Wipe drive """

    osCheck()
    interactiveMode()

if __name__ == '__main__':
    print(28 * '-', " pyWype ", 28 * '-')
    print("PYTHON DISK & PARTITION  WIPING UTILITY FOR LINUX.\nTHIS WILL IRRECOVERABLY WIPE DATA FROM DRIVE.\nPROCEED WITH CAUTION.")

    wipeDevice()
<commit_msg>remove oldregex<commit_after>#!/usr/bin/env python

from __future__ import print_function
from builtins import input

""" Python 2.7 & 3.4 disk wiping utility for use on Linux operating systems. RUN AS ROOT. """

import sys              # For interpreter variables & associated functions
import os               # For operating system dependent functions
import re               # For regular expression parsing

""" Define functions """

def osCheck():
    """ Check if OS is 'Linux' """
    if not sys.platform.startswith('linux'):
        print("This program was designed for Linux. Exiting.")
        sys.exit()

def listDevices():
    """ List mounted device(s) / partition(s) """

    print(22 * "-", "DEVICES & PARTITIONS", 22 * "-")                                      # Header

    return os.system('lsblk /dev/sd* --nodeps --output NAME,MODEL,VENDOR,SIZE,TYPE,STATE') # lsblk -d -o NAME,MODEL,VENDOR...

def defineDevice():
    """ Prompt user to define device or partition to wipe """

    while True:
        try:
            device = str(input("Enter letter [and number] of device/partition to wipe,\ne.g. to wipe '/dev/sdb' enter 'b': "))

            if not re.match("^[a-z][0-9]?$", device):
                raise ValueError()
            return device

        except ValueError:
            print("Sorry, that's not a valid device or partition. Try again.")

def appendDevice():
    """ Append user-defined device/partition to /dev/sd """

    letter = defineDevice()

    return '/dev/sd' + letter

def numberOfWipes():
    """ Prompt user for number of wipes to perform """

    while True:
        try:
            wipes = int(input("How many times do you want to wipe the device or partition?: "))

            if not wipes > 0:
                raise ValueError()
            return wipes

        except ValueError:
            print("Sorry, that's not a valid number. Try again.")

def confirmWipe():
    """ Prompt user to confirm disk erasure """

    print("WARNING!!! WRITING CHANGES TO DISK WILL RESULT IN IRRECOVERABLE DATA LOSS.")

    while True:
        try:
            reply = str(input("Are you sure you want to proceed? (Yes/No): ")).lower().strip()

            if reply == 'yes':
                return True
            elif reply == 'no':
                print("Exiting pyWype.")
                sys.exit()

        except ValueError:
            print("Sorry, that's not a valid entry. Try again: ")

def zerosToDevice():
    """ Write zeros to device/partition """

    append = appendDevice()
    num = numberOfWipes()
    confirm = confirmWipe()

    passes = 1

    for int in range(num):
        print("Processing pass count {} of {} ... ".format(passes, num))
        os.system(('dd if=/dev/zero |pv --progress --time --rate --bytes| dd of={} bs=4096'.format(append))) # pv -ptrb
        passes += 1

def randomToDevice():
    """ Write random zeros and ones to device/partition """

    append = appendDevice()
    num = numberOfWipes()
    confirm = confirmWipe()

    passes = 1

    for int in range(num):
        print("Processing pass count {} of {} ... ".format(passes, num))
        os.system(('dd if=/dev/random |pv --progress --time --rate --bytes| dd of={} bs=4096'.format(append))) # pv -ptrb
        passes += 1

def menu():
    """ Menu prompt for use to select program option """

    devices = listDevices()

    while True:
        print(30 * "-", "MENU", 30 * "-")
        print("1. Overwrite device or partition with 0's \n(faster, less secure).")
        print("2. Overwrite device or partition with random 0\'s & 1\'s \n(slower, more secure).")
        print("3. Quit.")
        choice = input("Select an option (1, 2 or 3): ")

        if choice in ('1', '2', '3'):
            return choice

def interactiveMode():
    """ Display menu-driven options and run function based on selection """
    while True:
        choice = menu()

        if choice == '3':
            sys.exit()
        elif choice == '1':
            zerosToDevice()
        elif choice == '2':
            randomToDevice()

def wipeDevice():
    """ Program to Wipe drive """

    osCheck()
    interactiveMode()

if __name__ == '__main__':
    print(28 * '-', " pyWype ", 28 * '-')
    print("PYTHON DISK & PARTITION  WIPING UTILITY FOR LINUX.\nTHIS WILL IRRECOVERABLY WIPE DATA FROM DRIVE.\nPROCEED WITH CAUTION.")

    wipeDevice()
<|endoftext|>


<commit_before># -*- coding: utf8 -*-
# This file is part of PyBossa.
#
# Copyright (C) 2013 SF Isle of Man Limited
#
# PyBossa 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.
#
# PyBossa 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 PyBossa.  If not, see <http://www.gnu.org/licenses/>.

import os
import logging
import json
import os

from flask import Response, request, g, render_template,\
        abort, flash, redirect, session, url_for
from flask.ext.login import login_user, logout_user, current_user
from flask.ext.babel import lazy_gettext
from sqlalchemy.exc import UnboundExecutionError
from sqlalchemy import func, desc
from werkzeug.exceptions import *

import pybossa
from pybossa.core import app, login_manager, db, babel
import pybossa.model as model
from pybossa.api import blueprint as api
from pybossa.view.account import blueprint as account
from pybossa.view.applications import blueprint as applications
from pybossa.view.admin import blueprint as admin
from pybossa.view.leaderboard import blueprint as leaderboard
from pybossa.view.stats import blueprint as stats
from pybossa.view.help import blueprint as help
from pybossa.cache import apps as cached_apps
from pybossa.cache import users as cached_users
from pybossa.cache import categories as cached_cat
from pybossa.ratelimit import get_view_rate_limit

logger = logging.getLogger('pybossa')

# other views ...
app.register_blueprint(api, url_prefix='/api')
app.register_blueprint(account, url_prefix='/account')
app.register_blueprint(applications, url_prefix='/app')
app.register_blueprint(admin, url_prefix='/admin')
app.register_blueprint(leaderboard, url_prefix='/leaderboard')
app.register_blueprint(stats, url_prefix='/stats')
app.register_blueprint(help, url_prefix='/help')

# Enable Twitter if available
try:  # pragma: no cover
    if (app.config['TWITTER_CONSUMER_KEY'] and
            app.config['TWITTER_CONSUMER_SECRET']):
        from pybossa.view.twitter import blueprint as twitter
        app.register_blueprint(twitter, url_prefix='/twitter')
except Exception as inst:  # pragma: no cover
    print type(inst)
    print inst.args
    print inst
    print "Twitter signin disabled"

# Enable Facebook if available
try:  # pragma: no cover
    if (app.config['FACEBOOK_APP_ID'] and app.config['FACEBOOK_APP_SECRET']):
        from pybossa.view.facebook import blueprint as facebook
        app.register_blueprint(facebook, url_prefix='/facebook')
except Exception as inst: # pragma: no cover
    print type(inst)
    print inst.args
    print inst
    print "Facebook signin disabled"

# Enable Google if available
try:  # pragma: no cover
    if (app.config['GOOGLE_CLIENT_ID'] and app.config['GOOGLE_CLIENT_SECRET']):
        from pybossa.view.google import blueprint as google
        app.register_blueprint(google, url_prefix='/google')
except Exception as inst:  # pragma: no cover
    print type(inst)
    print inst.args
    print inst
    print "Google signin disabled"

# Check if app stats page can generate the map
geolite = app.root_path + '/../dat/GeoLiteCity.dat'
if not os.path.exists(geolite):  # pragma: no cover
    app.config['GEO'] = False
    print("GeoLiteCity.dat file not found")
    print("App page stats web map disabled")
else:  # pragma: no cover
    app.config['GEO'] = True

def url_for_other_page(page):
    args = request.view_args.copy()
    args['page'] = page
    return url_for(request.endpoint, **args)
app.jinja_env.globals['url_for_other_page'] = url_for_other_page

@app.errorhandler(404)
def page_not_found(e):
    return render_template('404.html'), 404

@app.errorhandler(500)
def server_error(e):  # pragma: no cover
    return render_template('500.html'), 500

@app.errorhandler(403)
def forbidden(e):
    return render_template('403.html'), 403

@app.errorhandler(401)
def unauthorized(e):
    return render_template('401.html'), 401

@app.after_request
def inject_x_rate_headers(response):
    limit = get_view_rate_limit()
    if limit and limit.send_x_headers:
        h = response.headers
        h.add('X-RateLimit-Remaining', str(limit.remaining))
        h.add('X-RateLimit-Limit', str(limit.limit))
        h.add('X-RateLimit-Reset', str(limit.reset))
    return response

@app.context_processor
def global_template_context():
    if current_user.is_authenticated():
        if (current_user.email_addr == current_user.name or
                current_user.email_addr == "None"):
            flash(lazy_gettext("Please update your e-mail address in your profile page,"
                  " right now it is empty!"), 'error')

    # Cookies warning
    cookie_name = app.config['BRAND'] + "_accept_cookies"
    show_cookies_warning = False
    print request.cookies.get(cookie_name)
    if not request.cookies.get(cookie_name):
        show_cookies_warning = True

    # Announcement sections
    if app.config.get('ANNOUNCEMENT'):
        announcement = app.config['ANNOUNCEMENT']
        if current_user.is_authenticated():
            for key in announcement.keys():
                if key == 'admin' and current_user.admin:
                    flash(announcement[key], 'info')
                if key == 'owner' and len(current_user.apps) != 0:
                    flash(announcement[key], 'info')
                if key == 'user':
                    flash(announcement[key], 'info')

    if app.config.get('CONTACT_EMAIL'):  # pragma: no cover
        contact_email = app.config.get('CONTACT_EMAIL')
    else:
        contact_email = 'info@pybossa.com'

    if app.config.get('CONTACT_TWITTER'):  # pragma: no cover
        contact_twitter = app.config.get('CONTACT_TWITTER')
    else:
        contact_twitter = 'PyBossa'

    return dict(
        brand=app.config['BRAND'],
        title=app.config['TITLE'],
        logo=app.config['LOGO'],
        copyright=app.config['COPYRIGHT'],
        description=app.config['DESCRIPTION'],
        terms_of_use=app.config['TERMSOFUSE'],
        data_use=app.config['DATAUSE'],
        enforce_privacy=app.config['ENFORCE_PRIVACY'],
        version=pybossa.__version__,
        current_user=current_user,
        show_cookies_warning=show_cookies_warning,
        contact_email=contact_email,
        contact_twitter=contact_twitter)

@login_manager.user_loader
def load_user(username):
    return db.session.query(model.User).filter_by(name=username).first()

@app.before_request
def api_authentication():
    """ Attempt API authentication on a per-request basis."""
    apikey = request.args.get('api_key', None)
    from flask import _request_ctx_stack
    if 'Authorization' in request.headers:
        apikey = request.headers.get('Authorization')
    if apikey:
        user = db.session.query(model.User).filter_by(api_key=apikey).first()
        ## HACK:
        # login_user sets a session cookie which we really don't want.
        # login_user(user)
        if user:
            _request_ctx_stack.top.user = user

@app.route('/')
def home():
    """ Render home page with the cached apps and users"""
    d = {'featured': cached_apps.get_featured_front_page(),
         'top_apps': cached_apps.get_top(),
         'top_users': None}

    # Get all the categories with apps
    categories = cached_cat.get_used()
    d['categories'] = categories
    d['categories_apps'] = {}
    for c in categories:
        tmp_apps, count = cached_apps.get(c['short_name'], per_page=20)
        d['categories_apps'][str(c['short_name'])] = tmp_apps

    # Add featured
    tmp_apps, count = cached_apps.get_featured('featured', per_page=20)
    if count > 0:
        featured = model.Category(name='Featured', short_name='featured')
        d['categories'].append(featured)
        d['categories_apps']['featured'] = tmp_apps

    if app.config['ENFORCE_PRIVACY'] and current_user.is_authenticated():
        if current_user.admin:
            d['top_users'] = cached_users.get_top()
    if not app.config['ENFORCE_PRIVACY']:
        d['top_users'] = cached_users.get_top()
    return render_template('/home/index.html', **d)

@app.route("/about")
def about():
    """Render the about template"""
    return render_template("/home/about.html")

@app.route("/search")
def search():
    """Render search results page"""
    return render_template("/home/search.html")

def get_port():
    port = os.environ.get('PORT', '')
    if port.isdigit():
        return int(port)
    else:
        return app.config['PORT']

if __name__ == "__main__":  # pragma: no cover
    logging.basicConfig(level=logging.NOTSET)
    app.run(host=app.config['HOST'], port=get_port(),
            debug=app.config.get('DEBUG', True))
<commit_msg>Place featured in the first posion.<commit_after># -*- coding: utf8 -*-
# This file is part of PyBossa.
#
# Copyright (C) 2013 SF Isle of Man Limited
#
# PyBossa 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.
#
# PyBossa 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 PyBossa.  If not, see <http://www.gnu.org/licenses/>.

import os
import logging
import json
import os

from flask import Response, request, g, render_template,\
        abort, flash, redirect, session, url_for
from flask.ext.login import login_user, logout_user, current_user
from flask.ext.babel import lazy_gettext
from sqlalchemy.exc import UnboundExecutionError
from sqlalchemy import func, desc
from werkzeug.exceptions import *

import pybossa
from pybossa.core import app, login_manager, db, babel
import pybossa.model as model
from pybossa.api import blueprint as api
from pybossa.view.account import blueprint as account
from pybossa.view.applications import blueprint as applications
from pybossa.view.admin import blueprint as admin
from pybossa.view.leaderboard import blueprint as leaderboard
from pybossa.view.stats import blueprint as stats
from pybossa.view.help import blueprint as help
from pybossa.cache import apps as cached_apps
from pybossa.cache import users as cached_users
from pybossa.cache import categories as cached_cat
from pybossa.ratelimit import get_view_rate_limit

logger = logging.getLogger('pybossa')

# other views ...
app.register_blueprint(api, url_prefix='/api')
app.register_blueprint(account, url_prefix='/account')
app.register_blueprint(applications, url_prefix='/app')
app.register_blueprint(admin, url_prefix='/admin')
app.register_blueprint(leaderboard, url_prefix='/leaderboard')
app.register_blueprint(stats, url_prefix='/stats')
app.register_blueprint(help, url_prefix='/help')

# Enable Twitter if available
try:  # pragma: no cover
    if (app.config['TWITTER_CONSUMER_KEY'] and
            app.config['TWITTER_CONSUMER_SECRET']):
        from pybossa.view.twitter import blueprint as twitter
        app.register_blueprint(twitter, url_prefix='/twitter')
except Exception as inst:  # pragma: no cover
    print type(inst)
    print inst.args
    print inst
    print "Twitter signin disabled"

# Enable Facebook if available
try:  # pragma: no cover
    if (app.config['FACEBOOK_APP_ID'] and app.config['FACEBOOK_APP_SECRET']):
        from pybossa.view.facebook import blueprint as facebook
        app.register_blueprint(facebook, url_prefix='/facebook')
except Exception as inst: # pragma: no cover
    print type(inst)
    print inst.args
    print inst
    print "Facebook signin disabled"

# Enable Google if available
try:  # pragma: no cover
    if (app.config['GOOGLE_CLIENT_ID'] and app.config['GOOGLE_CLIENT_SECRET']):
        from pybossa.view.google import blueprint as google
        app.register_blueprint(google, url_prefix='/google')
except Exception as inst:  # pragma: no cover
    print type(inst)
    print inst.args
    print inst
    print "Google signin disabled"

# Check if app stats page can generate the map
geolite = app.root_path + '/../dat/GeoLiteCity.dat'
if not os.path.exists(geolite):  # pragma: no cover
    app.config['GEO'] = False
    print("GeoLiteCity.dat file not found")
    print("App page stats web map disabled")
else:  # pragma: no cover
    app.config['GEO'] = True

def url_for_other_page(page):
    args = request.view_args.copy()
    args['page'] = page
    return url_for(request.endpoint, **args)
app.jinja_env.globals['url_for_other_page'] = url_for_other_page

@app.errorhandler(404)
def page_not_found(e):
    return render_template('404.html'), 404

@app.errorhandler(500)
def server_error(e):  # pragma: no cover
    return render_template('500.html'), 500

@app.errorhandler(403)
def forbidden(e):
    return render_template('403.html'), 403

@app.errorhandler(401)
def unauthorized(e):
    return render_template('401.html'), 401

@app.after_request
def inject_x_rate_headers(response):
    limit = get_view_rate_limit()
    if limit and limit.send_x_headers:
        h = response.headers
        h.add('X-RateLimit-Remaining', str(limit.remaining))
        h.add('X-RateLimit-Limit', str(limit.limit))
        h.add('X-RateLimit-Reset', str(limit.reset))
    return response

@app.context_processor
def global_template_context():
    if current_user.is_authenticated():
        if (current_user.email_addr == current_user.name or
                current_user.email_addr == "None"):
            flash(lazy_gettext("Please update your e-mail address in your profile page,"
                  " right now it is empty!"), 'error')

    # Cookies warning
    cookie_name = app.config['BRAND'] + "_accept_cookies"
    show_cookies_warning = False
    print request.cookies.get(cookie_name)
    if not request.cookies.get(cookie_name):
        show_cookies_warning = True

    # Announcement sections
    if app.config.get('ANNOUNCEMENT'):
        announcement = app.config['ANNOUNCEMENT']
        if current_user.is_authenticated():
            for key in announcement.keys():
                if key == 'admin' and current_user.admin:
                    flash(announcement[key], 'info')
                if key == 'owner' and len(current_user.apps) != 0:
                    flash(announcement[key], 'info')
                if key == 'user':
                    flash(announcement[key], 'info')

    if app.config.get('CONTACT_EMAIL'):  # pragma: no cover
        contact_email = app.config.get('CONTACT_EMAIL')
    else:
        contact_email = 'info@pybossa.com'

    if app.config.get('CONTACT_TWITTER'):  # pragma: no cover
        contact_twitter = app.config.get('CONTACT_TWITTER')
    else:
        contact_twitter = 'PyBossa'

    return dict(
        brand=app.config['BRAND'],
        title=app.config['TITLE'],
        logo=app.config['LOGO'],
        copyright=app.config['COPYRIGHT'],
        description=app.config['DESCRIPTION'],
        terms_of_use=app.config['TERMSOFUSE'],
        data_use=app.config['DATAUSE'],
        enforce_privacy=app.config['ENFORCE_PRIVACY'],
        version=pybossa.__version__,
        current_user=current_user,
        show_cookies_warning=show_cookies_warning,
        contact_email=contact_email,
        contact_twitter=contact_twitter)

@login_manager.user_loader
def load_user(username):
    return db.session.query(model.User).filter_by(name=username).first()

@app.before_request
def api_authentication():
    """ Attempt API authentication on a per-request basis."""
    apikey = request.args.get('api_key', None)
    from flask import _request_ctx_stack
    if 'Authorization' in request.headers:
        apikey = request.headers.get('Authorization')
    if apikey:
        user = db.session.query(model.User).filter_by(api_key=apikey).first()
        ## HACK:
        # login_user sets a session cookie which we really don't want.
        # login_user(user)
        if user:
            _request_ctx_stack.top.user = user

@app.route('/')
def home():
    """ Render home page with the cached apps and users"""
    d = {'featured': cached_apps.get_featured_front_page(),
         'top_apps': cached_apps.get_top(),
         'top_users': None}

    # Get all the categories with apps
    categories = cached_cat.get_used()
    d['categories'] = categories
    d['categories_apps'] = {}
    for c in categories:
        tmp_apps, count = cached_apps.get(c['short_name'], per_page=20)
        d['categories_apps'][str(c['short_name'])] = tmp_apps

    # Add featured
    tmp_apps, count = cached_apps.get_featured('featured', per_page=20)
    if count > 0:
        featured = model.Category(name='Featured', short_name='featured')
        d['categories'].insert(0,featured)
        d['categories_apps']['featured'] = tmp_apps

    if app.config['ENFORCE_PRIVACY'] and current_user.is_authenticated():
        if current_user.admin:
            d['top_users'] = cached_users.get_top()
    if not app.config['ENFORCE_PRIVACY']:
        d['top_users'] = cached_users.get_top()
    return render_template('/home/index.html', **d)

@app.route("/about")
def about():
    """Render the about template"""
    return render_template("/home/about.html")

@app.route("/search")
def search():
    """Render search results page"""
    return render_template("/home/search.html")

def get_port():
    port = os.environ.get('PORT', '')
    if port.isdigit():
        return int(port)
    else:
        return app.config['PORT']

if __name__ == "__main__":  # pragma: no cover
    logging.basicConfig(level=logging.NOTSET)
    app.run(host=app.config['HOST'], port=get_port(),
            debug=app.config.get('DEBUG', True))
<|endoftext|>


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

from numpy import clip, interp
import rospy

from vortex_msgs.msg import Manipulator, Pwm
from stepper import Stepper

COMPUTER = rospy.get_param('/computer')

SERVO_PWM_PIN = rospy.get_param('/pwm/pins/claw_servo')
LOOKUP_POSITION = rospy.get_param('/servo/lookup/position')
LOOKUP_PULSE_WIDTH = rospy.get_param('/servo/lookup/pulse_width')

STEPPER_NUM_STEPS = rospy.get_param('/stepper/steps_per_rev')
STEPPER_RPM = rospy.get_param('/stepper/default_speed_rpm')

STEPPER_VALVE_PINS = rospy.get_param('/stepper/pins/valve')
STEPPER_VALVE_ENABLE_PIN = rospy.get_param('/stepper/pins/valve_enable')

STEPPER_AGAR_PINS = rospy.get_param('/stepper/pins/agar')
STEPPER_AGAR_ENABLE_PIN = rospy.get_param('/stepper/pins/agar_enable')

class ManipulatorInterface(object):
    def __init__(self):
        self.is_initialized = False
        rospy.init_node('manipulator_interface', anonymous=False)
        self.pub = rospy.Publisher('pwm', Pwm, queue_size=10)
        self.sub = rospy.Subscriber('manipulator_command', Manipulator, self.callback)

        self.neutral_pulse_width = self.servo_position_to_microsecs(0)

        rospy.sleep(0.1)  # Initial set to zero seems to disappear without a short sleep here
        self.servo_set_to_zero()
        rospy.on_shutdown(self.shutdown)
        self.claw_direction = 0.0
        self.claw_position = 0.0  # 1 = open, -1 = closed
        self.claw_speed = 1.0

        try:
            self.valve_stepper = Stepper(STEPPER_NUM_STEPS,
                                         STEPPER_VALVE_PINS,
                                         STEPPER_VALVE_ENABLE_PIN,
                                         COMPUTER)
            self.valve_direction = 0

            self.agar_stepper = Stepper(STEPPER_NUM_STEPS,
                                        STEPPER_AGAR_PINS,
                                        STEPPER_AGAR_ENABLE_PIN,
                                        COMPUTER)
            self.agar_direction = 0
        except NameError:
            rospy.logfatal('Could not initialize stepper.py. Is /computer parameter set correctly? '
                           'Shutting down node...')
            rospy.signal_shutdown('')

        rospy.loginfo('Initialized with {0} RPM steppers.'.format(STEPPER_RPM))
        self.is_initialized = True
        self.spin()

    def spin(self):
        period = 60.0 / (STEPPER_NUM_STEPS * STEPPER_RPM)
        rate = rospy.Rate(1/period)
        prev_time = rospy.get_rostime()
        min_pwm_interval = rospy.Duration(0.1)

        while not rospy.is_shutdown():
            # Accumulate claw position
            self.claw_position += self.claw_speed * period * self.claw_direction
            # Saturate claw position to [-1, 1]
            self.claw_position = clip(self.claw_position, -1, 1)

            # Step steppers if nonzero direction
            if abs(self.valve_direction) == 1:
                self.valve_stepper.step_once(self.valve_direction)
            if abs(self.agar_direction) == 1:
                self.agar_stepper.step_once(self.agar_direction)

            # Move servo if nonzero direction
            if abs(self.claw_direction) == 1:
                if (rospy.get_rostime() - prev_time) > min_pwm_interval:
                    self.set_claw_pwm(self.claw_position)
                    prev_time = rospy.get_rostime()

            rate.sleep()

    def servo_set_to_zero(self):
        msg = Pwm()
        msg.pins.append(SERVO_PWM_PIN)
        msg.positive_width_us.append(self.neutral_pulse_width)
        self.pub.publish(msg)
        rospy.loginfo("Setting servo position to zero")

    def shutdown(self):
        self.servo_set_to_zero()
        self.valve_stepper.shutdown()

    def callback(self, msg):
        if not self.is_initialized:
            rospy.logwarn('Callback before node initialized, ignoring...')
            return

        if not self.healthy_message(msg):
            return

        self.claw_direction = msg.claw_direction

        if msg.valve_direction != self.valve_direction:
            self.valve_direction = msg.valve_direction
            if self.valve_direction == 0:
                self.valve_stepper.disable()
            else:
                self.valve_stepper.enable()

        if msg.agar_direction != self.agar_direction:
            self.agar_direction = msg.agar_direction
            if self.agar_direction == 0:
                self.agar_stepper.disable()
            else:
                self.agar_stepper.enable()

    def servo_position_to_microsecs(self, thrust):
        return interp(thrust, LOOKUP_POSITION, LOOKUP_PULSE_WIDTH)

    def set_claw_pwm(self, position):
        microsecs = self.servo_position_to_microsecs(position)

        msg = Pwm()
        msg.pins.append(SERVO_PWM_PIN)
        msg.positive_width_us.append(microsecs)

        self.pub.publish(msg)

    def healthy_message(self, msg):
        if abs(msg.claw_direction) > 1:
            rospy.logwarn_throttle(1, 'Claw position out of range. Ignoring message...')
            return False

        if abs(msg.valve_direction) > 1:
            rospy.logwarn_throttle(1, 'Valve spinner command out of range. Ignoring message...')
            return False

        if abs(msg.agar_direction) > 1:
            rospy.logwarn_throttle(1, 'Agar screwer command out of range. Ignoring message...')
            return False

        return True

if __name__ == '__main__':
    try:
        manipulator_interface = ManipulatorInterface()
        rospy.spin()
    except rospy.ROSInterruptException:
        pass
<commit_msg>Only print servo info if initialized<commit_after>#!/usr/bin/env python

from numpy import clip, interp
import rospy

from vortex_msgs.msg import Manipulator, Pwm
from stepper import Stepper

COMPUTER = rospy.get_param('/computer')

SERVO_PWM_PIN = rospy.get_param('/pwm/pins/claw_servo')
LOOKUP_POSITION = rospy.get_param('/servo/lookup/position')
LOOKUP_PULSE_WIDTH = rospy.get_param('/servo/lookup/pulse_width')

STEPPER_NUM_STEPS = rospy.get_param('/stepper/steps_per_rev')
STEPPER_RPM = rospy.get_param('/stepper/default_speed_rpm')

STEPPER_VALVE_PINS = rospy.get_param('/stepper/pins/valve')
STEPPER_VALVE_ENABLE_PIN = rospy.get_param('/stepper/pins/valve_enable')

STEPPER_AGAR_PINS = rospy.get_param('/stepper/pins/agar')
STEPPER_AGAR_ENABLE_PIN = rospy.get_param('/stepper/pins/agar_enable')

class ManipulatorInterface(object):
    def __init__(self):
        self.is_initialized = False
        rospy.init_node('manipulator_interface', anonymous=False)
        self.pub = rospy.Publisher('pwm', Pwm, queue_size=10)
        self.sub = rospy.Subscriber('manipulator_command', Manipulator, self.callback)

        self.neutral_pulse_width = self.servo_position_to_microsecs(0)

        rospy.sleep(0.1)  # Initial set to zero seems to disappear without a short sleep here
        self.servo_set_to_zero()
        rospy.on_shutdown(self.shutdown)
        self.claw_direction = 0.0
        self.claw_position = 0.0  # 1 = open, -1 = closed
        self.claw_speed = 1.0

        try:
            self.valve_stepper = Stepper(STEPPER_NUM_STEPS,
                                         STEPPER_VALVE_PINS,
                                         STEPPER_VALVE_ENABLE_PIN,
                                         COMPUTER)
            self.valve_direction = 0

            self.agar_stepper = Stepper(STEPPER_NUM_STEPS,
                                        STEPPER_AGAR_PINS,
                                        STEPPER_AGAR_ENABLE_PIN,
                                        COMPUTER)
            self.agar_direction = 0
        except NameError:
            rospy.logfatal('Could not initialize stepper.py. Is /computer parameter set correctly? '
                           'Shutting down node...')
            rospy.signal_shutdown('')

        rospy.loginfo('Initialized with {0} RPM steppers.'.format(STEPPER_RPM))
        self.is_initialized = True
        self.spin()

    def spin(self):
        period = 60.0 / (STEPPER_NUM_STEPS * STEPPER_RPM)
        rate = rospy.Rate(1/period)
        prev_time = rospy.get_rostime()
        min_pwm_interval = rospy.Duration(0.1)

        while not rospy.is_shutdown():
            # Accumulate claw position
            self.claw_position += self.claw_speed * period * self.claw_direction
            # Saturate claw position to [-1, 1]
            self.claw_position = clip(self.claw_position, -1, 1)

            # Step steppers if nonzero direction
            if abs(self.valve_direction) == 1:
                self.valve_stepper.step_once(self.valve_direction)
            if abs(self.agar_direction) == 1:
                self.agar_stepper.step_once(self.agar_direction)

            # Move servo if nonzero direction
            if abs(self.claw_direction) == 1:
                if (rospy.get_rostime() - prev_time) > min_pwm_interval:
                    self.set_claw_pwm(self.claw_position)
                    prev_time = rospy.get_rostime()

            rate.sleep()

    def servo_set_to_zero(self):
        msg = Pwm()
        msg.pins.append(SERVO_PWM_PIN)
        msg.positive_width_us.append(self.neutral_pulse_width)
        self.pub.publish(msg)
        if self.is_initialized:
            rospy.loginfo("Setting servo position to zero")

    def shutdown(self):
        self.servo_set_to_zero()
        self.valve_stepper.shutdown()

    def callback(self, msg):
        if not self.is_initialized:
            rospy.logwarn('Callback before node initialized, ignoring...')
            return

        if not self.healthy_message(msg):
            return

        self.claw_direction = msg.claw_direction

        if msg.valve_direction != self.valve_direction:
            self.valve_direction = msg.valve_direction
            if self.valve_direction == 0:
                self.valve_stepper.disable()
            else:
                self.valve_stepper.enable()

        if msg.agar_direction != self.agar_direction:
            self.agar_direction = msg.agar_direction
            if self.agar_direction == 0:
                self.agar_stepper.disable()
            else:
                self.agar_stepper.enable()

    def servo_position_to_microsecs(self, thrust):
        return interp(thrust, LOOKUP_POSITION, LOOKUP_PULSE_WIDTH)

    def set_claw_pwm(self, position):
        microsecs = self.servo_position_to_microsecs(position)

        msg = Pwm()
        msg.pins.append(SERVO_PWM_PIN)
        msg.positive_width_us.append(microsecs)

        self.pub.publish(msg)

    def healthy_message(self, msg):
        if abs(msg.claw_direction) > 1:
            rospy.logwarn_throttle(1, 'Claw position out of range. Ignoring message...')
            return False

        if abs(msg.valve_direction) > 1:
            rospy.logwarn_throttle(1, 'Valve spinner command out of range. Ignoring message...')
            return False

        if abs(msg.agar_direction) > 1:
            rospy.logwarn_throttle(1, 'Agar screwer command out of range. Ignoring message...')
            return False

        return True

if __name__ == '__main__':
    try:
        manipulator_interface = ManipulatorInterface()
        rospy.spin()
    except rospy.ROSInterruptException:
        pass
<|endoftext|>


<commit_before>#!/usr/bin/python2.5
#
# Copyright 2009 the Melange authors.
#
# 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.

"""GHOPTask (Model) query functions.
"""

__authors__ = [
    '"Madhusudan.C.S" <madhusudancs@gmail.com>',
    '"Lennard de Rijk" <ljvderijk@gmail.com>',
  ]

import datetime

from google.appengine.ext import db

from django.utils import simplejson
from django.utils.translation import ugettext

from soc.logic.models import base

import soc.models.linkable

import soc.modules.ghop.logic.models.organization
import soc.modules.ghop.models.task

STATE_TRANSITIONS = {
    'Claimed': 'transitFromClaimed',
    'NeedsReview': 'transitFromNeedsReview',
    'ActionNeeded': 'transitFromActionNeeded',
    'NeedsWork': 'transitFromNeedsWork',
    }

class Logic(base.Logic):
  """Logic methods for the GHOPTask model.
  """

  DEF_ACTION_NEEDED_MSG = ugettext(
      '(The Melange Automated System has detected that the intial '
      'deadline has been passed and it has set the task status to '
      'ActionNeeded.)')

  DEF_NO_MORE_WORK_MSG = ugettext(
      '(The Melange Automated System has detected that the deadline '
      'has been passed and no more work can be submitted.)')

  DEF_REOPENED_MSG = ugettext(
      '(The Melange Automated System has detected that the final '
      'deadline has been passed and it has Reopened the task.)')

  def __init__(self, model=soc.modules.ghop.models.task.GHOPTask,
               base_model=soc.models.linkable.Linkable,
               scope_logic=soc.modules.ghop.logic.models.organization):
    """Defines the name, key_name and model for this entity.
    """

    super(Logic, self).__init__(model, base_model=base_model,
                                scope_logic=scope_logic)

  def updateEntityProperties(self, entity, entity_properties,
                             silent=False, store=True):
    """See base.Logic.updateEntityProperties().

    Also ensures that the history property of the task is updated in the same
    datastore operation.
    """

    from soc.logic.models import base as base_logic

    # TODO: History needs a proper test drive and perhaps a refactoring
    history = {}

    # we construct initial snapshot of the task when it is published
    # for the first time.
    if entity_properties and 'status' in entity_properties:
      if entity.status == 'Unpublished' or entity.status == 'Unapproved':
        if entity_properties['status'] == 'Open':
          history = {
              'title': entity.title,
              'description': entity.description,
              'difficulty': entity.difficulty[0].tag,
              'task_type': [type.tag for type in entity.task_type],
              'time_to_complete': entity.time_to_complete,
              'mentors': [m_key.name() for m_key in entity.mentors],
              'user': '',
              'student': '',
              'status': entity.status,
              'deadline': '',
              'created_by': entity.created_by.key().name(),
              'created_on': str(entity.created_on),
              'modified_on': str(entity.modified_on),
              }

          if entity.modified_by:
            history['modified_by'] = entity.modified_by.key().name()

          # initialize history
          task_history = {}
      # extract the existing json history from the entity to update it
    else:
      task_history = simplejson.loads(entity.history)

      # we construct history for only changed entity properties
      if entity_properties:
        for property in entity_properties:
          changed_val = getattr(entity, property)
          if changed_val != entity_properties[property]:
            if property == 'deadline':
              history[property] = str(changed_val)
            else:
              history[property] = changed_val

    if history:
      # create a dictionary for the new history update with timestamp as key
      tstamp = str(datetime.datetime.now())
      new_history = {tstamp: history}

      # update existing history
      task_history.update(new_history)
      task_history_str = simplejson.dumps(task_history)

      # update the task's history property
      history_property = {
          'history': task_history_str
          }
      entity_properties.update(history_property)

    # call the base logic method to store the updated Task entity
    return super(Logic, self).updateEntityProperties(
        entity, entity_properties, silent=silent, store=store)

  def updateEntityPropertiesWithCWS(self, entity, entity_properties,
                                    comment_properties=None,
                                    ws_properties=None, silent=False):
    """Updates the GHOPTask entity properties and creates a comment
    entity.

    Args:
      entity: a model entity
      entity_properties: keyword arguments that correspond to entity
          properties and their values
      comment_properties: keyword arguments that correspond to the
          GHOPTask's to be created comment entity
      silent: iff True does not call post store methods.
    """

    from soc.modules.ghop.logic.models.comment import logic as \
        ghop_comment_logic
    from soc.modules.ghop.logic.models.work_submission import logic as \
        ghop_work_submission_logic
    from soc.modules.ghop.models import comment as ghop_comment_model
    from soc.modules.ghop.models import work_submission as \
        ghop_work_submission_model

    if entity_properties:
      entity = self.updateEntityProperties(entity, entity_properties,
                                           silent=silent, store=False)

    comment_entity = ghop_comment_model.GHOPComment(**comment_properties)

    ws_entity = None
    if ws_properties:
      ws_entity = ghop_work_submission_model.GHOPWorkSubmission(
          **ws_properties)

    def comment_create():
      """Method to be run in transaction that stores Task, Comment and
      WorkSubmission.
      """
      entity.put()
      if ws_entity:
        ws_entity.put()
        comment_entity.content = comment_entity.content % (
            ws_entity.key().id_or_name())
        comment_entity.put()
        return entity, comment_entity, ws_entity
      else:
        comment_entity.put()
        return entity, comment_entity, None

    entity, comment_entity, ws_entity = db.run_in_transaction(
        comment_create)

    if not silent:
      # call the _onCreate methods for the Comment and WorkSubmission
      if comment_entity:
        ghop_comment_logic._onCreate(comment_entity)

      if ws_entity:
        ghop_work_submission_logic._onCreate(ws_entity)

    return entity, comment_entity, ws_entity

  def updateOrCreateFromFields(self, properties, silent=False):
    """See base.Logic.updateOrCreateFromFields().
    """

    # TODO: History needs to be tested and perhaps refactored
    if properties['status'] == 'Open':
      history = {
          'title': properties['title'],
          'description': properties['description'],
          'difficulty': properties['difficulty']['tags'],
          'task_type': properties['type_tags'],
          'time_to_complete': properties['time_to_complete'],
          'mentors': [m_key.name() for m_key in properties['mentors']],
          'user': '',
          'student': '',
          'status': properties['status'],
          'deadline': '',
          'created_on': str(properties['created_on']),
          'modified_on': str(properties['modified_on']),
          }

      if 'created_by' in properties and properties['created_by']:
        history['created_by'] = properties['created_by'].key().name()
        history['modified_by'] = properties['modified_by'].key().name()

      # Constructs new history from the _constructNewHistory method, assigns
      # it as a value to the dictionary key with current timestamp and dumps
      # a JSON string.
      task_history_str = simplejson.dumps({
          str(datetime.datetime.now()): history,
          })

      # update the task's history property
      history_property = {
          'history': task_history_str
          }
      properties.update(history_property)

    entity = super(Logic, self).updateOrCreateFromFields(properties, silent)

    if entity:
      if properties.get('task_type'):
        setattr(entity, 'task_type', properties['task_type'])

      if properties.get('difficulty'):
        setattr(entity, 'difficulty', properties['difficulty'])

    return entity

  def getFromKeyFieldsWithCWSOr404(self, fields):
    """Returns the Task, all Comments and all WorkSubmissions for the Task
    specified by the fields argument.

    For args see base.getFromKeyFieldsOr404().
    """

    from soc.modules.ghop.logic.models.comment import logic as \
        ghop_comment_logic
    from soc.modules.ghop.logic.models.work_submission import logic as \
        ghop_work_submission_logic

    entity = self.getFromKeyFieldsOr404(fields)

    comment_entities = ghop_comment_logic.getForFields(
        ancestors=[entity], order=['created_on'])

    ws_entities = ghop_work_submission_logic.getForFields(
        ancestors=[entity], order=['submitted_on'])

    return entity, comment_entities, ws_entities

  def updateTaskStatus(self, entity):
    """Method used to transit a task from a state to another state
    depending on the context. Whenever the deadline has passed.

    Args:
      entity: The GHOPTask entity

    Returns:
      Task entity and a Comment entity if the occurring transit created one.
    """

    from soc.modules.ghop.tasks import task_update

    if entity.deadline and datetime.datetime.now() > entity.deadline:
      # calls a specific method to make a transition depending on the
      # task's current state
      transit_func = getattr(self, STATE_TRANSITIONS[entity.status])
      update_dict = transit_func(entity)

      comment_properties = {
          'parent': entity,
          'scope_path': entity.key().name(),
          'created_by': None,
          'content': update_dict['content'],
          'changes': update_dict['changes'],
          }

      entity, comment_entity, _ = self.updateEntityPropertiesWithCWS(
          entity, update_dict['properties'], comment_properties)

      if entity.deadline:
        # only if there is a deadline set we should schedule another task
        task_update.spawnUpdateTask(entity)
    else:
      comment_entity=None

    return entity, comment_entity

  def transitFromClaimed(self, entity):
    """Makes a state transition of a GHOP Task from Claimed state
    to a relevant state.

    Args:
      entity: The GHOPTask entity
    """

    # deadline is extended by 24 hours.
    deadline = entity.deadline + datetime.timedelta(
        hours=24)

    properties = {
        'status': 'ActionNeeded',
        'deadline': deadline,
        }

    changes = [ugettext('User-MelangeAutomatic'),
               ugettext('Action-Warned for action'),
               ugettext('Status-%s' % (properties['status']))]

    content = self.DEF_ACTION_NEEDED_MSG

    update_dict = {
        'properties': properties,
        'changes': changes,
        'content': content,
        }

    return update_dict

  def transitFromNeedsReview(self, entity):
    """Makes a state transition of a GHOP Task from NeedsReview state
    to a relevant state.

    Args:
      entity: The GHOPTask entity
    """

    properties = {
        'deadline': None,
        }

    changes = [ugettext('User-MelangeAutomatic'),
               ugettext('Action-Deadline passed'),
               ugettext('Status-%s' % (entity.status))]

    content = self.DEF_NO_MORE_WORK_MSG

    update_dict = {
        'properties': properties,
        'changes': changes,
        'content': content,
        }

    return update_dict

  def transitFromActionNeeded(self, entity):
    """Makes a state transition of a GHOP Task from ActionNeeded state
    to a relevant state.

    Args:
      entity: The GHOPTask entity
    """

    properties = {
        'user': None,
        'student': None,
        'status': 'Reopened',
        'deadline': None,
        }

    changes = [ugettext('User-MelangeAutomatic'),
               ugettext('Action-Forcibly reopened'),
               ugettext('Status-Reopened')]

    content = self.DEF_REOPENED_MSG

    update_dict = {
        'properties': properties,
        'changes': changes,
        'content': content,
        }

    return update_dict

  def transitFromNeedsWork(self, entity):
    """Makes a state transition of a GHOP Task from NeedsWork state
    to a relevant state.

    Args:
      entity: The GHOPTask entity
    """

    properties = {
        'user': None,
        'student': None,
        'status': 'Reopened',
        'deadline': None,
        }

    changes = [ugettext('User-MelangeAutomatic'),
               ugettext('Action-Forcibly reopened'),
               ugettext('Status-Reopened')]

    update_dict = {
        'properties': properties,
        'changes': changes,
        'content': None,
        }

    return update_dict

logic = Logic()
<commit_msg>Fixed an error with the task_history not being loaded when it was empty.<commit_after>#!/usr/bin/python2.5
#
# Copyright 2009 the Melange authors.
#
# 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.

"""GHOPTask (Model) query functions.
"""

__authors__ = [
    '"Madhusudan.C.S" <madhusudancs@gmail.com>',
    '"Lennard de Rijk" <ljvderijk@gmail.com>',
  ]

import datetime

from google.appengine.ext import db

from django.utils import simplejson
from django.utils.translation import ugettext

from soc.logic.models import base

import soc.models.linkable

import soc.modules.ghop.logic.models.organization
import soc.modules.ghop.models.task

STATE_TRANSITIONS = {
    'Claimed': 'transitFromClaimed',
    'NeedsReview': 'transitFromNeedsReview',
    'ActionNeeded': 'transitFromActionNeeded',
    'NeedsWork': 'transitFromNeedsWork',
    }

class Logic(base.Logic):
  """Logic methods for the GHOPTask model.
  """

  DEF_ACTION_NEEDED_MSG = ugettext(
      '(The Melange Automated System has detected that the intial '
      'deadline has been passed and it has set the task status to '
      'ActionNeeded.)')

  DEF_NO_MORE_WORK_MSG = ugettext(
      '(The Melange Automated System has detected that the deadline '
      'has been passed and no more work can be submitted.)')

  DEF_REOPENED_MSG = ugettext(
      '(The Melange Automated System has detected that the final '
      'deadline has been passed and it has Reopened the task.)')

  def __init__(self, model=soc.modules.ghop.models.task.GHOPTask,
               base_model=soc.models.linkable.Linkable,
               scope_logic=soc.modules.ghop.logic.models.organization):
    """Defines the name, key_name and model for this entity.
    """

    super(Logic, self).__init__(model, base_model=base_model,
                                scope_logic=scope_logic)

  def updateEntityProperties(self, entity, entity_properties,
                             silent=False, store=True):
    """See base.Logic.updateEntityProperties().

    Also ensures that the history property of the task is updated in the same
    datastore operation.
    """

    from soc.logic.models import base as base_logic

    # TODO: History needs a proper test drive and perhaps a refactoring
    history = {}

    # we construct initial snapshot of the task when it is published
    # for the first time.
    if entity_properties and 'status' in entity_properties:
      if entity.status == 'Unpublished' or entity.status == 'Unapproved':
        if entity_properties['status'] == 'Open':
          history = {
              'title': entity.title,
              'description': entity.description,
              'difficulty': entity.difficulty[0].tag,
              'task_type': [type.tag for type in entity.task_type],
              'time_to_complete': entity.time_to_complete,
              'mentors': [m_key.name() for m_key in entity.mentors],
              'user': '',
              'student': '',
              'status': entity.status,
              'deadline': '',
              'created_by': entity.created_by.key().name(),
              'created_on': str(entity.created_on),
              'modified_on': str(entity.modified_on),
              }

          if entity.modified_by:
            history['modified_by'] = entity.modified_by.key().name()

          # initialize history
          task_history = {}
      # extract the existing json history from the entity to update it
    elif entity.history:
      task_history = simplejson.loads(entity.history)
    else:
      task_history = {}

      # we construct history for only changed entity properties
      if entity_properties:
        for property in entity_properties:
          changed_val = getattr(entity, property)
          if changed_val != entity_properties[property]:
            if property == 'deadline':
              history[property] = str(changed_val)
            else:
              history[property] = changed_val

    if history:
      # create a dictionary for the new history update with timestamp as key
      tstamp = str(datetime.datetime.now())
      new_history = {tstamp: history}

      # update existing history
      task_history.update(new_history)
      task_history_str = simplejson.dumps(task_history)

      # update the task's history property
      history_property = {
          'history': task_history_str
          }
      entity_properties.update(history_property)

    # call the base logic method to store the updated Task entity
    return super(Logic, self).updateEntityProperties(
        entity, entity_properties, silent=silent, store=store)

  def updateEntityPropertiesWithCWS(self, entity, entity_properties,
                                    comment_properties=None,
                                    ws_properties=None, silent=False):
    """Updates the GHOPTask entity properties and creates a comment
    entity.

    Args:
      entity: a model entity
      entity_properties: keyword arguments that correspond to entity
          properties and their values
      comment_properties: keyword arguments that correspond to the
          GHOPTask's to be created comment entity
      silent: iff True does not call post store methods.
    """

    from soc.modules.ghop.logic.models.comment import logic as \
        ghop_comment_logic
    from soc.modules.ghop.logic.models.work_submission import logic as \
        ghop_work_submission_logic
    from soc.modules.ghop.models import comment as ghop_comment_model
    from soc.modules.ghop.models import work_submission as \
        ghop_work_submission_model

    if entity_properties:
      entity = self.updateEntityProperties(entity, entity_properties,
                                           silent=silent, store=False)

    comment_entity = ghop_comment_model.GHOPComment(**comment_properties)

    ws_entity = None
    if ws_properties:
      ws_entity = ghop_work_submission_model.GHOPWorkSubmission(
          **ws_properties)

    def comment_create():
      """Method to be run in transaction that stores Task, Comment and
      WorkSubmission.
      """
      entity.put()
      if ws_entity:
        ws_entity.put()
        comment_entity.content = comment_entity.content % (
            ws_entity.key().id_or_name())
        comment_entity.put()
        return entity, comment_entity, ws_entity
      else:
        comment_entity.put()
        return entity, comment_entity, None

    entity, comment_entity, ws_entity = db.run_in_transaction(
        comment_create)

    if not silent:
      # call the _onCreate methods for the Comment and WorkSubmission
      if comment_entity:
        ghop_comment_logic._onCreate(comment_entity)

      if ws_entity:
        ghop_work_submission_logic._onCreate(ws_entity)

    return entity, comment_entity, ws_entity

  def updateOrCreateFromFields(self, properties, silent=False):
    """See base.Logic.updateOrCreateFromFields().
    """

    # TODO: History needs to be tested and perhaps refactored
    if properties['status'] == 'Open':
      history = {
          'title': properties['title'],
          'description': properties['description'],
          'difficulty': properties['difficulty']['tags'],
          'task_type': properties['type_tags'],
          'time_to_complete': properties['time_to_complete'],
          'mentors': [m_key.name() for m_key in properties['mentors']],
          'user': '',
          'student': '',
          'status': properties['status'],
          'deadline': '',
          'created_on': str(properties['created_on']),
          'modified_on': str(properties['modified_on']),
          }

      if 'created_by' in properties and properties['created_by']:
        history['created_by'] = properties['created_by'].key().name()
        history['modified_by'] = properties['modified_by'].key().name()

      # Constructs new history from the _constructNewHistory method, assigns
      # it as a value to the dictionary key with current timestamp and dumps
      # a JSON string.
      task_history_str = simplejson.dumps({
          str(datetime.datetime.now()): history,
          })

      # update the task's history property
      history_property = {
          'history': task_history_str
          }
      properties.update(history_property)

    entity = super(Logic, self).updateOrCreateFromFields(properties, silent)

    if entity:
      if properties.get('task_type'):
        setattr(entity, 'task_type', properties['task_type'])

      if properties.get('difficulty'):
        setattr(entity, 'difficulty', properties['difficulty'])

    return entity

  def getFromKeyFieldsWithCWSOr404(self, fields):
    """Returns the Task, all Comments and all WorkSubmissions for the Task
    specified by the fields argument.

    For args see base.getFromKeyFieldsOr404().
    """

    from soc.modules.ghop.logic.models.comment import logic as \
        ghop_comment_logic
    from soc.modules.ghop.logic.models.work_submission import logic as \
        ghop_work_submission_logic

    entity = self.getFromKeyFieldsOr404(fields)

    comment_entities = ghop_comment_logic.getForFields(
        ancestors=[entity], order=['created_on'])

    ws_entities = ghop_work_submission_logic.getForFields(
        ancestors=[entity], order=['submitted_on'])

    return entity, comment_entities, ws_entities

  def updateTaskStatus(self, entity):
    """Method used to transit a task from a state to another state
    depending on the context. Whenever the deadline has passed.

    Args:
      entity: The GHOPTask entity

    Returns:
      Task entity and a Comment entity if the occurring transit created one.
    """

    from soc.modules.ghop.tasks import task_update

    if entity.deadline and datetime.datetime.now() > entity.deadline:
      # calls a specific method to make a transition depending on the
      # task's current state
      transit_func = getattr(self, STATE_TRANSITIONS[entity.status])
      update_dict = transit_func(entity)

      comment_properties = {
          'parent': entity,
          'scope_path': entity.key().name(),
          'created_by': None,
          'content': update_dict['content'],
          'changes': update_dict['changes'],
          }

      entity, comment_entity, _ = self.updateEntityPropertiesWithCWS(
          entity, update_dict['properties'], comment_properties)

      if entity.deadline:
        # only if there is a deadline set we should schedule another task
        task_update.spawnUpdateTask(entity)
    else:
      comment_entity=None

    return entity, comment_entity

  def transitFromClaimed(self, entity):
    """Makes a state transition of a GHOP Task from Claimed state
    to a relevant state.

    Args:
      entity: The GHOPTask entity
    """

    # deadline is extended by 24 hours.
    deadline = entity.deadline + datetime.timedelta(
        hours=24)

    properties = {
        'status': 'ActionNeeded',
        'deadline': deadline,
        }

    changes = [ugettext('User-MelangeAutomatic'),
               ugettext('Action-Warned for action'),
               ugettext('Status-%s' % (properties['status']))]

    content = self.DEF_ACTION_NEEDED_MSG

    update_dict = {
        'properties': properties,
        'changes': changes,
        'content': content,
        }

    return update_dict

  def transitFromNeedsReview(self, entity):
    """Makes a state transition of a GHOP Task from NeedsReview state
    to a relevant state.

    Args:
      entity: The GHOPTask entity
    """

    properties = {
        'deadline': None,
        }

    changes = [ugettext('User-MelangeAutomatic'),
               ugettext('Action-Deadline passed'),
               ugettext('Status-%s' % (entity.status))]

    content = self.DEF_NO_MORE_WORK_MSG

    update_dict = {
        'properties': properties,
        'changes': changes,
        'content': content,
        }

    return update_dict

  def transitFromActionNeeded(self, entity):
    """Makes a state transition of a GHOP Task from ActionNeeded state
    to a relevant state.

    Args:
      entity: The GHOPTask entity
    """

    properties = {
        'user': None,
        'student': None,
        'status': 'Reopened',
        'deadline': None,
        }

    changes = [ugettext('User-MelangeAutomatic'),
               ugettext('Action-Forcibly reopened'),
               ugettext('Status-Reopened')]

    content = self.DEF_REOPENED_MSG

    update_dict = {
        'properties': properties,
        'changes': changes,
        'content': content,
        }

    return update_dict

  def transitFromNeedsWork(self, entity):
    """Makes a state transition of a GHOP Task from NeedsWork state
    to a relevant state.

    Args:
      entity: The GHOPTask entity
    """

    properties = {
        'user': None,
        'student': None,
        'status': 'Reopened',
        'deadline': None,
        }

    changes = [ugettext('User-MelangeAutomatic'),
               ugettext('Action-Forcibly reopened'),
               ugettext('Status-Reopened')]

    update_dict = {
        'properties': properties,
        'changes': changes,
        'content': None,
        }

    return update_dict

logic = Logic()
<|endoftext|>


<commit_before>import inspect

from rpython.rlib import jit, unroll

class Link(object):
    def __init__(self, k, v, next):
        from pycket.values import W_Object
        assert isinstance(k, W_Object)
        assert isinstance(v, W_Object)
        assert (next is None) or isinstance(next, Link)
        self.key = k
        self.val = v
        self.next = next

class BaseCont(object):
    # Racket also keeps a separate stack for continuation marks
    # so that they can be saved without saving the whole continuation.
    def __init__(self):
        self.marks = None

    def get_ast(self):
        return None # best effort

    def get_next_executed_ast(self):
        return None # best effort

    def find_cm(self, k):
        from pycket.prims.equal import eqp_logic
        l = self.marks
        while l is not None:
            if eqp_logic(l.key, k):
                return l.val
            l = l.next
        return None

    def update_cm(self, k, v):
        from pycket.prims.equal import eqp_logic
        l = self.marks
        while l is not None:
            if eqp_logic(l.key, k):
                l.val = v
                return
            l = l.next
        self.marks = Link(k, v, self.marks)

    def get_marks(self, key):
        from pycket import values
        v = self.find_cm(key)
        return values.W_Cons.make(v, values.w_null) if v is not None else values.w_null

    def get_mark_first(self, key):
        p = self
        while isinstance(p, Cont):
            v = p.find_cm(key)
            if v:
                return v
            elif p.prev:
                p = p.prev
        return p.find_cm(key)

    def plug_reduce(self, _vals, env):
        raise NotImplementedError("abstract method")

    def tostring(self):
        "NOT_RPYTHON"
        if not isinstance(self, NilCont) and self.prev:
            return "%s(%s)"%(self.__class__.__name__,self.prev.tostring())
        else:
            return "%s()"%(self.__class__.__name__)

# Continuation used to signal that the computation is done.
class NilCont(BaseCont):
    def plug_reduce(self, vals, env):
        from pycket.interpreter import Done
        raise Done(vals)

nil_continuation = NilCont()

class Cont(BaseCont):
    _immutable_fields_ = ['env', 'prev']
    def __init__(self, env, prev):
        # TODO: Consider using a dictionary to store the marks
        BaseCont.__init__(self)
        self.env = env
        self.prev = prev

    def get_marks(self, key):
        from pycket import values
        v = self.find_cm(key)
        if v is not None:
            return values.W_Cons.make(v, self.prev.get_marks(key))
        else:
            return self.prev.get_marks(key)

def _make_args_class(base, argnames):
    unroll_argnames = unroll.unrolling_iterable(enumerate(argnames))

    class Args(base):
        _immutable_fields_ = getattr(base, '_immutable_fields_', []) + argnames
        def _init_args(self, *args):
            for i, name in unroll_argnames:
                setattr(self, name, args[i])

        def _get_args(self):
            args = ()
            for i, name in unroll_argnames:
                args += (getattr(self, name), )
            return args
    return Args

def continuation(func):
    """ workaround for the lack of closures in RPython. use to decorate a
    function that is supposed to be usable as a continuation. When the
    continuation triggers, the original function is called with one extra
    argument, the computed vals. """

    argspec = inspect.getargspec(func)
    assert argspec.varargs is None
    assert argspec.keywords is None
    assert argspec.defaults is None
    argnames = argspec.args[:-1]
    assert argnames[-1] == "cont"
    assert argnames[-2] == "env"
    argnames = argnames[:-2]

    PrimCont = _make_args_class(Cont, argnames)
    def __init__(self, *args):
        env = args[-2]
        cont = args[-1]
        Cont.__init__(self, env, cont)
        args = args[:-2]
        self._init_args(*args)
    PrimCont.__init__ = __init__

    def plug_reduce(self, vals, env):
        args = self._get_args()
        args += (self.env, self.prev, vals,)
        return func(*args)
    PrimCont.plug_reduce = plug_reduce
    PrimCont.__name__ = func.func_name + "PrimCont"

    def make_continuation(*args):
        return PrimCont(*args)

    make_continuation.func_name = func.func_name + "_make_continuation"
    return make_continuation

def make_label(func, enter=False):
    from pycket.AST import AST

    func = jit.unroll_safe(func)
    func_argnames, varargs, varkw, defaults = inspect.getargspec(func)
    assert not varkw and not defaults
    if varargs: # grrr, bad
        class Args(BaseCont):
            def __init__(self, *args):
                BaseCont.__init__(self)
                self.args = args

            def _get_args(self):
                return self.args
    else:
        assert func_argnames[-2] == "env", "next to last argument to %s must be named 'env', not %r" % (func.func_name, func_argnames[-2])

        Args = _make_args_class(BaseCont, func_argnames)
        def __init__(self, *args):
            BaseCont.__init__(self)
            self._init_args(*args)
        Args.__init__ = __init__

    # The @label decorator will produce a new Label per each use, as an @label can be
    # used to encode a loop (as they act in a manner similar to an assembly label).
    if enter:
        clsname = "LoopLabel"
    else:
        clsname = "Label"
    strrepr = "%s(%s:%s:%s)" % (clsname, func.func_name, func.__module__,
                                func.__code__.co_firstlineno)
    class Label(AST):
        should_enter = enter
        def interpret(self, env, cont):
            assert type(cont) is Args
            return func(*cont._get_args())
        def tostring(self):
            return strrepr
    Label.__name__ = clsname

    the_label = Label()

    def make(*args):
        env = args[-2]
        return the_label, env, Args(*args)

    return make

def loop_label(func):
    return make_label(func, enter=True)

# A label is function wrapped by some extra logic to hand back control to the
# CEK loop before invocation.
def label(func):
    return make_label(func, enter=False)

# A useful continuation constructor. This invokes the given procedure with
# the enviroment and continuation when values are supplied.
# This is just a simple way to place a function call onto the continuation.
@continuation
def call_cont(proc, env, cont, vals):
    return proc.call(vals._get_full_list(), env, cont)

<commit_msg>Some useful additions<commit_after>import inspect

from rpython.rlib import jit, unroll

class Link(object):
    _immutable_fields_ = ["key", "val", "next"]
    def __init__(self, k, v, next):
        from pycket.values import W_Object
        assert isinstance(k, W_Object)
        assert isinstance(v, W_Object)
        assert (next is None) or isinstance(next, Link)
        self.key = k
        self.val = v
        self.next = next

class BaseCont(object):
    # Racket also keeps a separate stack for continuation marks
    # so that they can be saved without saving the whole continuation.
    def __init__(self):
        self.marks = None

    def get_ast(self):
        return None # best effort

    def get_next_executed_ast(self):
        return None # best effort

    def find_cm(self, k):
        from pycket.prims.equal import eqp_logic
        l = self.marks
        while l is not None:
            if eqp_logic(l.key, k):
                return l.val
            l = l.next
        return None

    def update_cm(self, k, v):
        from pycket.prims.equal import eqp_logic
        l = self.marks
        while l is not None:
            if eqp_logic(l.key, k):
                l.val = v
                return
            l = l.next
        self.marks = Link(k, v, self.marks)

    def get_marks(self, key):
        from pycket import values
        v = self.find_cm(key)
        return values.W_Cons.make(v, values.w_null) if v is not None else values.w_null

    def get_mark_first(self, key):
        p = self
        while isinstance(p, Cont):
            v = p.find_cm(key)
            if v:
                return v
            elif p.prev:
                p = p.prev
        return p.find_cm(key)

    def plug_reduce(self, _vals, env):
        raise NotImplementedError("abstract method")

    def tostring(self):
        "NOT_RPYTHON"
        if not isinstance(self, NilCont) and self.prev:
            return "%s(%s)"%(self.__class__.__name__,self.prev.tostring())
        else:
            return "%s()"%(self.__class__.__name__)

# Continuation used to signal that the computation is done.
class NilCont(BaseCont):
    def plug_reduce(self, vals, env):
        from pycket.interpreter import Done
        raise Done(vals)

nil_continuation = NilCont()

class Cont(BaseCont):
    _immutable_fields_ = ['env', 'prev']
    def __init__(self, env, prev):
        # TODO: Consider using a dictionary to store the marks
        BaseCont.__init__(self)
        self.env = env
        self.prev = prev

    def get_ast(self):
        return self.prev.get_ast()

    def get_next_executed_ast(self):
        return self.prev.get_next_executed_ast()

    def get_marks(self, key):
        from pycket import values
        v = self.find_cm(key)
        if v is not None:
            return values.W_Cons.make(v, self.prev.get_marks(key))
        else:
            return self.prev.get_marks(key)

def _make_args_class(base, argnames):
    unroll_argnames = unroll.unrolling_iterable(enumerate(argnames))

    class Args(base):
        _immutable_fields_ = getattr(base, '_immutable_fields_', []) + argnames
        def _init_args(self, *args):
            for i, name in unroll_argnames:
                setattr(self, name, args[i])

        def _get_args(self):
            args = ()
            for i, name in unroll_argnames:
                args += (getattr(self, name), )
            return args
    return Args

def continuation(func):
    """ workaround for the lack of closures in RPython. use to decorate a
    function that is supposed to be usable as a continuation. When the
    continuation triggers, the original function is called with one extra
    argument, the computed vals. """

    argspec = inspect.getargspec(func)
    assert argspec.varargs is None
    assert argspec.keywords is None
    assert argspec.defaults is None
    argnames = argspec.args[:-1]
    assert argnames[-1] == "cont"
    assert argnames[-2] == "env"
    argnames = argnames[:-2]

    PrimCont = _make_args_class(Cont, argnames)
    def __init__(self, *args):
        env = args[-2]
        cont = args[-1]
        Cont.__init__(self, env, cont)
        args = args[:-2]
        self._init_args(*args)
    PrimCont.__init__ = __init__

    def plug_reduce(self, vals, env):
        args = self._get_args()
        args += (self.env, self.prev, vals,)
        return func(*args)
    PrimCont.plug_reduce = plug_reduce
    PrimCont.__name__ = func.func_name + "PrimCont"

    def make_continuation(*args):
        return PrimCont(*args)

    make_continuation.func_name = func.func_name + "_make_continuation"
    return make_continuation

def make_label(func, enter=False):
    from pycket.AST import AST

    func = jit.unroll_safe(func)
    func_argnames, varargs, varkw, defaults = inspect.getargspec(func)
    assert not varkw and not defaults
    if varargs: # grrr, bad
        class Args(BaseCont):
            def __init__(self, *args):
                BaseCont.__init__(self)
                self.args = args

            def _get_args(self):
                return self.args
    else:
        assert func_argnames[-2] == "env", "next to last argument to %s must be named 'env', not %r" % (func.func_name, func_argnames[-2])

        Args = _make_args_class(BaseCont, func_argnames)
        def __init__(self, *args):
            BaseCont.__init__(self)
            self._init_args(*args)
        Args.__init__ = __init__

    # The @label decorator will produce a new Label per each use, as an @label can be
    # used to encode a loop (as they act in a manner similar to an assembly label).
    if enter:
        clsname = "LoopLabel"
    else:
        clsname = "Label"
    strrepr = "%s(%s:%s:%s)" % (clsname, func.func_name, func.__module__,
                                func.__code__.co_firstlineno)
    class Label(AST):
        should_enter = enter
        def interpret(self, env, cont):
            assert type(cont) is Args
            return func(*cont._get_args())
        def tostring(self):
            return strrepr
    Label.__name__ = clsname

    the_label = Label()

    def make(*args):
        env = args[-2]
        return the_label, env, Args(*args)

    return make

def loop_label(func):
    return make_label(func, enter=True)

# A label is function wrapped by some extra logic to hand back control to the
# CEK loop before invocation.
def label(func):
    return make_label(func, enter=False)

# A useful continuation constructor. This invokes the given procedure with
# the enviroment and continuation when values are supplied.
# This is just a simple way to place a function call onto the continuation.
@continuation
def call_cont(proc, env, cont, vals):
    return proc.call(vals._get_full_list(), env, cont)

# A useful continuation constructor. This invokes the given procedure with
# the enviroment and continuation when values are supplied.
# This is just a simple way to place a function call onto the continuation.
@continuation
def call_extra_cont(proc, calling_app, env, cont, vals):
    return proc.call_with_extra_info(vals._get_full_list(), env, cont, calling_app)
<|endoftext|>