<commit_before>import os
import urllib
import datetime
import logging
# This is needed for timezone conversion (but not part of standard lib)
#import dateutil

from google.appengine.api import users
from google.appengine.ext import ndb

import jinja2
import webapp2

JINJA_ENVIRONMENT = jinja2.Environment(
    loader=jinja2.FileSystemLoader(os.path.dirname(__file__)),
    extensions=['jinja2.ext.autoescape'],
    autoescape=True)

def db_key(db_name):
    """
    Constructs a Datastore key for a player list.
    We use the list name as the key.
    """
    return ndb.Key("Entries", db_name)

def chat_db_key(db_name):
    """
    Constructs a Datastore key for a chat comment list.
    We use the list name as the key.
    """
    return ndb.Key("ChatEntries", db_name)

def get_login_info(h):
    user = users.get_current_user()
    if user:
        logged_in = True
        url       = users.create_logout_url(h.request.uri)
        linktext  = 'Logout'
    else:
        logged_in = False
        url       = users.create_login_url(h.request.uri)
        linktext  = 'Login'
    info = {
        'logged_in': logged_in,
        'url': url,
        'linktext': linktext,
    }
    return info

def get_year_string():
    now = datetime.datetime.utcnow()
    return now.strftime("%Y")

def get_vball_type(h):
    comps = h.request.path.split("/")
    logging.info("comps: %s" % comps)
    return comps[1]

class Player(ndb.Model):
    """
    Sub model for representing a player.
    """
    identity = ndb.StringProperty(indexed=False)
    email    = ndb.StringProperty(indexed=False)
    name     = ndb.StringProperty(indexed=False)

class Entry(ndb.Model):
    """
    A main model for representing an individual player entry.
    """
    player    = ndb.StructuredProperty(Player)
    comment   = ndb.StringProperty(indexed=False)
    committed = ndb.BooleanProperty(indexed=True)
    date      = ndb.DateTimeProperty(auto_now_add=True)

class ChatEntry(ndb.Model):
    """
    Model for representing an chat comment.
    """
    identity = ndb.StringProperty(indexed=False)
    email    = ndb.StringProperty(indexed=False)
    name     = ndb.StringProperty(indexed=False)
    comment  = ndb.StringProperty(indexed=False)
    date     = ndb.DateTimeProperty(auto_now_add=True)

class ChatEntryLocal(object):
    """
    To covert datetime to local timezone
    """

    def __init__(self, entry):
        self.identity = entry.identity
        self.email    = entry.email
        self.name     = entry.name
        self.comment  = entry.comment
        self.date     = self.utc_to_local(entry.date)

    def utc_to_local(self, utc_dt):
        # Becase GAE doesn't have dateutil
        utc_offset = 6 # Through testing - not sure about DST
        hour = int(utc_dt.strftime("%H"))
        min  = int(utc_dt.strftime("%M"))
        if hour > utc_offset:
            hour = hour - utc_offset
        ampm = "PM" if (hour > 11) else "AM"
        if hour > 12:
            hour = hour - 12
        return "%d:%02d %s" % (hour, min, ampm)

        ## Define zones
        #utc_zone = dateutil.tz.gettz('UTC')
        #mtn_zone = dateutil.tz.gettz('America/Boise')
        ## Tell the datetime object that it's in UTC time zone since
        ## datetime objects are 'naive' by default
        #utc_dt = utc_dt.replace(tzinfo=utc_zone)
        ## Convert time zone to mountain
        #return utc_dt.astimezone(mtn_zone)

class MainPage(webapp2.RequestHandler):
    """
    Reads the database and creates the data for rendering the signup list
    """
    def get(self):
        vball_type = get_vball_type(self)
        # Filter for today only
        now = datetime.datetime.today()
        today = datetime.datetime(now.year, now.month, now.day)

        # Get committed entries list
        qry_c = Entry.query(ancestor=db_key(vball_type))
        qry_c = qry_c.filter(Entry.date >= today)
        qry_c = qry_c.filter(Entry.committed == True)
        qry_c = qry_c.order(Entry.date)
        entries_c = qry_c.fetch(100)

        # Get maybe entries list
        qry_m = Entry.query(ancestor=db_key(vball_type))
        qry_m = qry_m.filter(Entry.date >= today)
        qry_m = qry_m.filter(Entry.committed == False)
        qry_m = qry_m.order(Entry.date)
        entries_m = qry_m.fetch(100)

        # Get chat messages (posts) - convert timestamps too
        qry_t = ChatEntry.query(ancestor=chat_db_key(vball_type))
        qry_t = qry_t.filter(ChatEntry.date >= today)
        qry_t = qry_t.order(ChatEntry.date)
        entries_t = qry_t.fetch(1000)
        entries_p = []
        for entry in entries_t:
            entries_p.append(ChatEntryLocal(entry))

        # See if user is logged in and signed up
        login_info = get_login_info(self)
        user = users.get_current_user()
        is_signed_up = False
        signed_up_entry = None
        if user:
            for entry in entries_c + entries_m:
                if entry.player.identity == user.user_id():
                    is_signed_up = True
                    signed_up_entry = entry

        template_values = {
            'vball_type': vball_type,
            'year': get_year_string(),
            'page': 'signup',
            'user': user,
            'entries_c': entries_c,
            'entries_m': entries_m,
            'entries_p': entries_p,
            'date': today.strftime("%m-%d-%Y"),
            'is_signed_up': is_signed_up,
            'signed_up_entry': signed_up_entry,
            'login': login_info,
        }

        template = JINJA_ENVIRONMENT.get_template('signup.html')
        self.response.write(template.render(template_values))

class Chat(webapp2.RequestHandler):
    """
    Manages adding a chat message.
    """
    def post(self):
        vball_type = get_vball_type(self)
        user = users.get_current_user()
        if user:
            entry = ChatEntry(parent=chat_db_key(vball_type))
            entry.identity = user.user_id()
            entry.email    = user.email()
            entry.name     = user.nickname()
            entry.comment  = self.request.get('comment')
            entry.put()
            self.redirect('/%s' % vball_type)

class Signup(webapp2.RequestHandler):
    """
    Manages adding a new player to the signup list for today.
    """
    def post(self):
        vball_type = get_vball_type(self)
        user = users.get_current_user()
        if user:
            entry = Entry(parent=db_key(vball_type))
            entry.player = Player(identity=user.user_id(), email=user.email(), name=user.nickname())
            entry.comment = ""
            if self.request.get('action') == "Commit":
                entry.committed = True
            else:
                entry.committed = False
            entry.put()
            self.redirect('/%s' % vball_type)

class Unsignup(webapp2.RequestHandler):
    """
    Manages removing the current logged in user from the signup
    sheet (for today).
    """
    def post(self):
        vball_type = get_vball_type(self)
        user = users.get_current_user()
        if user:
            logging.info("in user section")
            now = datetime.datetime.today()
            today = datetime.datetime(now.year, now.month, now.day)

            qry = Entry.query(ancestor=db_key(vball_type))
            qry = qry.filter(Entry.date >= today)
            entries = qry.fetch(100)
            for entry in entries:
                if entry.player.identity == user.user_id():
                    entry.key.delete()
        self.redirect('/%s' % vball_type)

class Info(webapp2.RequestHandler):
    """
    Renders Info page
    """
    def get(self):
        vball_type = get_vball_type(self)
        login_info = get_login_info(self)
        template_values = {
            'vball_type': vball_type,
            'year': get_year_string(),
            'page' : 'info',
            'login': login_info
        }
        template = JINJA_ENVIRONMENT.get_template('info.html')
        self.response.write(template.render(template_values))

class Store(webapp2.RequestHandler):
    """
    Renders Store page
    """
    def get(self):
        vball_type = get_vball_type(self)
        login_info = get_login_info(self)
        template_values = {
            'vball_type': vball_type,
            'year': get_year_string(),
            'page' : 'store',
            'login': login_info
        }
        template = JINJA_ENVIRONMENT.get_template('store.html')
        self.response.write(template.render(template_values))

class Log(webapp2.RequestHandler):
    """
    Renders Log page (hidden)
    """
    def get(self):
        # Get committed entries list
        vball_type = get_vball_type(self)
        qry = Entry.query(ancestor=db_key(vball_type))
        qry = qry.order(-Entry.date)
        entries = qry.fetch()

        login_info = get_login_info(self)
        template_values = {
            'vball_type': vball_type,
            'year': get_year_string(),
            'page': 'log',
            'login': login_info,
            'entries': entries,
        }
        template = JINJA_ENVIRONMENT.get_template('log.html')
        self.response.write(template.render(template_values))

class Index(webapp2.RequestHandler):
    """
    Redirects to grass (default)
    """
    def get(self):
        self.redirect('/grass')

app = webapp2.WSGIApplication([
    ('/',               Index),
    ('/grass',          MainPage),
    ('/grass/signup',   Signup),
    ('/grass/unsignup', Unsignup),
    ('/grass/info',     Info),
    ('/grass/store',    Store),
    ('/grass/log',      Log),
    ('/grass/chat',     Chat),
    ('/elite',          MainPage),
    ('/elite/signup',   Signup),
    ('/elite/unsignup', Unsignup),
    ('/elite/info',     Info),
    ('/elite/log',      Log),
    ('/elite/chat',     Chat),
], debug=True)
<commit_msg>Adds store link from alt page<commit_after>import os
import urllib
import datetime
import logging
# This is needed for timezone conversion (but not part of standard lib)
#import dateutil

from google.appengine.api import users
from google.appengine.ext import ndb

import jinja2
import webapp2

JINJA_ENVIRONMENT = jinja2.Environment(
    loader=jinja2.FileSystemLoader(os.path.dirname(__file__)),
    extensions=['jinja2.ext.autoescape'],
    autoescape=True)

def db_key(db_name):
    """
    Constructs a Datastore key for a player list.
    We use the list name as the key.
    """
    return ndb.Key("Entries", db_name)

def chat_db_key(db_name):
    """
    Constructs a Datastore key for a chat comment list.
    We use the list name as the key.
    """
    return ndb.Key("ChatEntries", db_name)

def get_login_info(h):
    user = users.get_current_user()
    if user:
        logged_in = True
        url       = users.create_logout_url(h.request.uri)
        linktext  = 'Logout'
    else:
        logged_in = False
        url       = users.create_login_url(h.request.uri)
        linktext  = 'Login'
    info = {
        'logged_in': logged_in,
        'url': url,
        'linktext': linktext,
    }
    return info

def get_year_string():
    now = datetime.datetime.utcnow()
    return now.strftime("%Y")

def get_vball_type(h):
    comps = h.request.path.split("/")
    logging.info("comps: %s" % comps)
    return comps[1]

class Player(ndb.Model):
    """
    Sub model for representing a player.
    """
    identity = ndb.StringProperty(indexed=False)
    email    = ndb.StringProperty(indexed=False)
    name     = ndb.StringProperty(indexed=False)

class Entry(ndb.Model):
    """
    A main model for representing an individual player entry.
    """
    player    = ndb.StructuredProperty(Player)
    comment   = ndb.StringProperty(indexed=False)
    committed = ndb.BooleanProperty(indexed=True)
    date      = ndb.DateTimeProperty(auto_now_add=True)

class ChatEntry(ndb.Model):
    """
    Model for representing an chat comment.
    """
    identity = ndb.StringProperty(indexed=False)
    email    = ndb.StringProperty(indexed=False)
    name     = ndb.StringProperty(indexed=False)
    comment  = ndb.StringProperty(indexed=False)
    date     = ndb.DateTimeProperty(auto_now_add=True)

class ChatEntryLocal(object):
    """
    To covert datetime to local timezone
    """

    def __init__(self, entry):
        self.identity = entry.identity
        self.email    = entry.email
        self.name     = entry.name
        self.comment  = entry.comment
        self.date     = self.utc_to_local(entry.date)

    def utc_to_local(self, utc_dt):
        # Becase GAE doesn't have dateutil
        utc_offset = 6 # Through testing - not sure about DST
        hour = int(utc_dt.strftime("%H"))
        min  = int(utc_dt.strftime("%M"))
        if hour > utc_offset:
            hour = hour - utc_offset
        ampm = "PM" if (hour > 11) else "AM"
        if hour > 12:
            hour = hour - 12
        return "%d:%02d %s" % (hour, min, ampm)

        ## Define zones
        #utc_zone = dateutil.tz.gettz('UTC')
        #mtn_zone = dateutil.tz.gettz('America/Boise')
        ## Tell the datetime object that it's in UTC time zone since
        ## datetime objects are 'naive' by default
        #utc_dt = utc_dt.replace(tzinfo=utc_zone)
        ## Convert time zone to mountain
        #return utc_dt.astimezone(mtn_zone)

class MainPage(webapp2.RequestHandler):
    """
    Reads the database and creates the data for rendering the signup list
    """
    def get(self):
        vball_type = get_vball_type(self)
        # Filter for today only
        now = datetime.datetime.today()
        today = datetime.datetime(now.year, now.month, now.day)

        # Get committed entries list
        qry_c = Entry.query(ancestor=db_key(vball_type))
        qry_c = qry_c.filter(Entry.date >= today)
        qry_c = qry_c.filter(Entry.committed == True)
        qry_c = qry_c.order(Entry.date)
        entries_c = qry_c.fetch(100)

        # Get maybe entries list
        qry_m = Entry.query(ancestor=db_key(vball_type))
        qry_m = qry_m.filter(Entry.date >= today)
        qry_m = qry_m.filter(Entry.committed == False)
        qry_m = qry_m.order(Entry.date)
        entries_m = qry_m.fetch(100)

        # Get chat messages (posts) - convert timestamps too
        qry_t = ChatEntry.query(ancestor=chat_db_key(vball_type))
        qry_t = qry_t.filter(ChatEntry.date >= today)
        qry_t = qry_t.order(ChatEntry.date)
        entries_t = qry_t.fetch(1000)
        entries_p = []
        for entry in entries_t:
            entries_p.append(ChatEntryLocal(entry))

        # See if user is logged in and signed up
        login_info = get_login_info(self)
        user = users.get_current_user()
        is_signed_up = False
        signed_up_entry = None
        if user:
            for entry in entries_c + entries_m:
                if entry.player.identity == user.user_id():
                    is_signed_up = True
                    signed_up_entry = entry

        template_values = {
            'vball_type': vball_type,
            'year': get_year_string(),
            'page': 'signup',
            'user': user,
            'entries_c': entries_c,
            'entries_m': entries_m,
            'entries_p': entries_p,
            'date': today.strftime("%m-%d-%Y"),
            'is_signed_up': is_signed_up,
            'signed_up_entry': signed_up_entry,
            'login': login_info,
        }

        template = JINJA_ENVIRONMENT.get_template('signup.html')
        self.response.write(template.render(template_values))

class Chat(webapp2.RequestHandler):
    """
    Manages adding a chat message.
    """
    def post(self):
        vball_type = get_vball_type(self)
        user = users.get_current_user()
        if user:
            entry = ChatEntry(parent=chat_db_key(vball_type))
            entry.identity = user.user_id()
            entry.email    = user.email()
            entry.name     = user.nickname()
            entry.comment  = self.request.get('comment')
            entry.put()
            self.redirect('/%s' % vball_type)

class Signup(webapp2.RequestHandler):
    """
    Manages adding a new player to the signup list for today.
    """
    def post(self):
        vball_type = get_vball_type(self)
        user = users.get_current_user()
        if user:
            entry = Entry(parent=db_key(vball_type))
            entry.player = Player(identity=user.user_id(), email=user.email(), name=user.nickname())
            entry.comment = ""
            if self.request.get('action') == "Commit":
                entry.committed = True
            else:
                entry.committed = False
            entry.put()
            self.redirect('/%s' % vball_type)

class Unsignup(webapp2.RequestHandler):
    """
    Manages removing the current logged in user from the signup
    sheet (for today).
    """
    def post(self):
        vball_type = get_vball_type(self)
        user = users.get_current_user()
        if user:
            logging.info("in user section")
            now = datetime.datetime.today()
            today = datetime.datetime(now.year, now.month, now.day)

            qry = Entry.query(ancestor=db_key(vball_type))
            qry = qry.filter(Entry.date >= today)
            entries = qry.fetch(100)
            for entry in entries:
                if entry.player.identity == user.user_id():
                    entry.key.delete()
        self.redirect('/%s' % vball_type)

class Info(webapp2.RequestHandler):
    """
    Renders Info page
    """
    def get(self):
        vball_type = get_vball_type(self)
        login_info = get_login_info(self)
        template_values = {
            'vball_type': vball_type,
            'year': get_year_string(),
            'page' : 'info',
            'login': login_info
        }
        template = JINJA_ENVIRONMENT.get_template('info.html')
        self.response.write(template.render(template_values))

class Store(webapp2.RequestHandler):
    """
    Renders Store page
    """
    def get(self):
        vball_type = get_vball_type(self)
        login_info = get_login_info(self)
        template_values = {
            'vball_type': vball_type,
            'year': get_year_string(),
            'page' : 'store',
            'login': login_info
        }
        template = JINJA_ENVIRONMENT.get_template('store.html')
        self.response.write(Gtemplate.render(template_values))

class Log(webapp2.RequestHandler):
    """
    Renders Log page (hidden)
    """
    def get(self):
        # Get committed entries list
        vball_type = get_vball_type(self)
        qry = Entry.query(ancestor=db_key(vball_type))
        qry = qry.order(-Entry.date)
        entries = qry.fetch()

        login_info = get_login_info(self)
        template_values = {
            'vball_type': vball_type,
            'year': get_year_string(),
            'page': 'log',
            'login': login_info,
            'entries': entries,
        }
        template = JINJA_ENVIRONMENT.get_template('log.html')
        self.response.write(template.render(template_values))

class Index(webapp2.RequestHandler):
    """
    Redirects to grass (default)
    """
    def get(self):
        self.redirect('/grass')

app = webapp2.WSGIApplication([
    ('/',               Index),
    ('/grass',          MainPage),
    ('/grass/signup',   Signup),
    ('/grass/unsignup', Unsignup),
    ('/grass/info',     Info),
    ('/grass/store',    Store),
    ('/grass/log',      Log),
    ('/grass/chat',     Chat),
    ('/elite',          MainPage),
    ('/elite/signup',   Signup),
    ('/elite/unsignup', Unsignup),
    ('/elite/info',     Info),
    ('/elite/store',    Store),
    ('/elite/log',      Log),
    ('/elite/chat',     Chat),
], debug=True)
<|endoftext|>


<commit_before>import re
from string import ascii_lowercase as chars
from random import choice

from aleph import Aleph
from rsd import RSD

from services.webservice import WebService

def ilp_aleph(input_dict):
    aleph = Aleph()
    settings = input_dict['settings']
    mode = input_dict['mode']
    pos = input_dict['pos']
    neg = input_dict['neg']
    b = input_dict['b']
    # Parse settings provided via file
    if settings:
        aleph.settingsAsFacts(settings)
    # Parse settings provided as parameters (these have higher priority)
    for setting, def_val in Aleph.ESSENTIAL_PARAMS.items():
        aleph.set(setting, input_dict.get(setting, def_val))
    # Run aleph
    theory = aleph.induce(mode, pos, neg, b)
    return {'theory' : theory}

def ilp_rsd(input_dict):
    rsd = RSD()
    settings = input_dict.get('settings',None)
    pos = input_dict.get('pos', None)
    neg = input_dict.get('neg', None)
    examples = input_dict.get('examples', None)
    b = input_dict['b']
    subgroups = True if input_dict['subgroups'] == 'true' else False
    # Parse settings
    if settings:
        rsd.settingsAsFacts(settings)
    # Parse settings provided as parameters (these have higher priority)
    for setting, def_val in RSD.ESSENTIAL_PARAMS.items():
        rsd.set(setting, input_dict.get(setting, def_val))
    # Run rsd
    features, arff, rules = rsd.induce(b, examples=examples, pos=pos, neg=neg, cn2sd=subgroups)
    return {'features' : features, 'arff' : arff, 'rules' : rules}

def ilp_sdmsegs_rule_viewer(input_dict):
    return {}

def ilp_sdmaleph(input_dict):
    ws = WebService('http://vihar.ijs.si:8097', 3600)
    response = ws.client.sdmaleph(
        examples=input_dict.get('examples'),
        mapping=input_dict.get('mapping'),
        ontologies=[{'ontology' : ontology} for ontology in input_dict.get('ontology')],
        relations=[{'relation' : relation} for relation in input_dict.get('relation')],
        posClassVal=input_dict.get('posClassVal') if input_dict.get('posClassVal') != '' else None,
        cutoff=input_dict.get('cutoff') if input_dict.get('cutoff') != '' else None,
        minPos=input_dict.get('minPos') if input_dict.get('minPos') != '' else None,
        noise=input_dict.get('noise') if input_dict.get('noise') != '' else None,
        clauseLen=input_dict.get('clauseLen') if input_dict.get('clauseLen') != '' else None,
        dataFormat=input_dict.get('dataFormat') if input_dict.get('dataFormat') != '' else None
    )
    return {'theory' : response['theory']}<commit_msg>new service addr<commit_after>import re
from string import ascii_lowercase as chars
from random import choice

from aleph import Aleph
from rsd import RSD

from services.webservice import WebService

def ilp_aleph(input_dict):
    aleph = Aleph()
    settings = input_dict['settings']
    mode = input_dict['mode']
    pos = input_dict['pos']
    neg = input_dict['neg']
    b = input_dict['b']
    # Parse settings provided via file
    if settings:
        aleph.settingsAsFacts(settings)
    # Parse settings provided as parameters (these have higher priority)
    for setting, def_val in Aleph.ESSENTIAL_PARAMS.items():
        aleph.set(setting, input_dict.get(setting, def_val))
    # Run aleph
    theory = aleph.induce(mode, pos, neg, b)
    return {'theory' : theory}

def ilp_rsd(input_dict):
    rsd = RSD()
    settings = input_dict.get('settings',None)
    pos = input_dict.get('pos', None)
    neg = input_dict.get('neg', None)
    examples = input_dict.get('examples', None)
    b = input_dict['b']
    subgroups = True if input_dict['subgroups'] == 'true' else False
    # Parse settings
    if settings:
        rsd.settingsAsFacts(settings)
    # Parse settings provided as parameters (these have higher priority)
    for setting, def_val in RSD.ESSENTIAL_PARAMS.items():
        rsd.set(setting, input_dict.get(setting, def_val))
    # Run rsd
    features, arff, rules = rsd.induce(b, examples=examples, pos=pos, neg=neg, cn2sd=subgroups)
    return {'features' : features, 'arff' : arff, 'rules' : rules}

def ilp_sdmsegs_rule_viewer(input_dict):
    return {}

def ilp_sdmaleph(input_dict):
    ws = WebService('http://workflow.ijs.si:8081', 3600)
    response = ws.client.sdmaleph(
        examples=input_dict.get('examples'),
        mapping=input_dict.get('mapping'),
        ontologies=[{'ontology' : ontology} for ontology in input_dict.get('ontology')],
        relations=[{'relation' : relation} for relation in input_dict.get('relation')],
        posClassVal=input_dict.get('posClassVal') if input_dict.get('posClassVal') != '' else None,
        cutoff=input_dict.get('cutoff') if input_dict.get('cutoff') != '' else None,
        minPos=input_dict.get('minPos') if input_dict.get('minPos') != '' else None,
        noise=input_dict.get('noise') if input_dict.get('noise') != '' else None,
        clauseLen=input_dict.get('clauseLen') if input_dict.get('clauseLen') != '' else None,
        dataFormat=input_dict.get('dataFormat') if input_dict.get('dataFormat') != '' else None
    )
    return {'theory' : response['theory']}<|endoftext|>


<commit_before>#  File:       pythagorean_triplet.py
#  Purpose:    A Pythagorean triplet program
#  Programmer: Amal Shehu
#  Course:     Exercism
#  Date:       Thursday 29 September 2016, 04:30 PM
<commit_msg>Add pythagorean_triples function<commit_after>#  File:       pythagorean_triplet.py
#  Purpose:    A Pythagorean triplet program
#  Programmer: Amal Shehu
#  Course:     Exercism
#  Date:       Thursday 29 September 2016, 04:30 PM

def pythagorean_triples(n):
    n = int(n)
    if n>0:
        if a in range(1,n-1):
            if b in range(a+1, n):
                if c in range(b+1,n+1):
                    if a*a+b*b==c*c:
                        print a,b,c
    else:
        return "Wrong input"

pythagorean_triples(30)
<|endoftext|>


<commit_before># snapy - a python snmp library
#
# Copyright (C) 2009 ITA Software, Inc.
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# version 2 as published by the Free Software Foundation.
#
# 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 General Public License for more details.

import os
import signal
import warnings
import tempfile

from twisted.internet import defer, error, process, protocol, reactor
from twisted.python import log
from twisted.trial import unittest

class LoggingProtocol(protocol.ProcessProtocol):
    """Log snmpd output via the twisted logging api"""

    def __init__(self, factory):
        self.factory = factory

    def outReceived(self, data):
        for line in data.splitlines():
            log.msg("snmpd: %s" % line)

    def errReceived(self, data):
        for line in data.splitlines():
            if line.startswith("NET-SNMP"):
                self.factory.started()
            log.err("snmpd: %s" % line)

    def processEnded(self, status):
        if isinstance(status.value, error.ProcessDone):
            log.msg("snmpd: exit(0)")
            self.factory.done(None)
        elif isinstance(status.value, error.ProcessTerminated):
            log.err("snmpd: exit(%s)" % status.value.exitCode)
            self.factory.done(status)
        else:
            log.err("snmpd: %s" % status)
            self.factory.done(status)

class Server(process.Process):
    """Run snmpd"""

    def __init__(self):
        self._deferred = defer.Deferred()
        self._address = defer.Deferred()
        self._timeout = None
        self.conf = "%s/snmpd.conf" % os.path.dirname(__file__)

        # XXX: Not perfect, there is a race condition between
        # the unlink and snmpd's bind call but it's good enough.
        fd, self.socket_name = tempfile.mkstemp()
        self.socket = "unix:%s" % self.socket_name
        os.unlink(self.socket_name)
        os.close(fd)

        proto = LoggingProtocol(self)
        env = {"PATH": "/bin:/sbin:/usr/bin:/usr/sbin"}
        cmd = ("snmpd", "-f", "-I", "override", "-C", "-c", self.conf,
                "--noPersistentLoad=1", "--noPersistentSave=1", self.socket)
        super(Server, self).__init__(reactor, cmd[0], cmd, env, None, proto)

    def started(self):
        self._address.callback(self.socket)

    def address(self):
        return self._address

    def stop(self):
        assert self.pid and self._deferred
        os.kill(self.pid, signal.SIGTERM)
        self._timeout = reactor.callLater(1.0, self.timeout)
        return self._deferred

    def timeout(self):
        assert self.pid
        os.kill(self.pid, signal.SIGKILL)
        self._timeout = None

    def done(self, status):
        assert self._deferred

        if self._timeout:
            self._timeout.cancel()
            self._timeout = None

        if os.path.exists(self.socket_name):
            os.unlink(self.socket_name)

        self._deferred.callback(status)
        self._deferred = None

class TestCase(unittest.TestCase):

    def setUp(self):
        # Twisted falsely raises it's zombie warning during tests
        warnings.simplefilter("ignore", error.PotentialZombieWarning)

        self.server = Server()
        d = self.server.address()
        d.addCallback(self.setUpSession)
        d.addErrback(lambda x: self.server.stop())
        return d

    def setUpSession(self, address):
        pass

    def tearDown(self):
        d = self.server.stop()
        d.addCallback(lambda x: self.tearDownSession())
        return d

    def tearDownSession(self):
        pass
<commit_msg>Fix the order of snmpd tearDown steps<commit_after># snapy - a python snmp library
#
# Copyright (C) 2009 ITA Software, Inc.
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# version 2 as published by the Free Software Foundation.
#
# 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 General Public License for more details.

import os
import signal
import warnings
import tempfile

from twisted.internet import defer, error, process, protocol, reactor
from twisted.python import log
from twisted.trial import unittest

class LoggingProtocol(protocol.ProcessProtocol):
    """Log snmpd output via the twisted logging api"""

    def __init__(self, factory):
        self.factory = factory

    def outReceived(self, data):
        for line in data.splitlines():
            log.msg("snmpd: %s" % line)

    def errReceived(self, data):
        for line in data.splitlines():
            if line.startswith("NET-SNMP"):
                self.factory.started()
            log.err("snmpd: %s" % line)

    def processEnded(self, status):
        if isinstance(status.value, error.ProcessDone):
            log.msg("snmpd: exit(0)")
            self.factory.done(None)
        elif isinstance(status.value, error.ProcessTerminated):
            log.err("snmpd: exit(%s)" % status.value.exitCode)
            self.factory.done(status)
        else:
            log.err("snmpd: %s" % status)
            self.factory.done(status)

class Server(process.Process):
    """Run snmpd"""

    def __init__(self):
        self._deferred = defer.Deferred()
        self._address = defer.Deferred()
        self._timeout = None
        self.conf = "%s/snmpd.conf" % os.path.dirname(__file__)

        # XXX: Not perfect, there is a race condition between
        # the unlink and snmpd's bind call but it's good enough.
        fd, self.socket_name = tempfile.mkstemp()
        self.socket = "unix:%s" % self.socket_name
        os.unlink(self.socket_name)
        os.close(fd)

        proto = LoggingProtocol(self)
        env = {"PATH": "/bin:/sbin:/usr/bin:/usr/sbin"}
        cmd = ("snmpd", "-f", "-I", "override", "-C", "-c", self.conf,
                "--noPersistentLoad=1", "--noPersistentSave=1", self.socket)
        super(Server, self).__init__(reactor, cmd[0], cmd, env, None, proto)

    def started(self):
        self._address.callback(self.socket)

    def address(self):
        return self._address

    def stop(self):
        assert self.pid and self._deferred
        os.kill(self.pid, signal.SIGTERM)
        self._timeout = reactor.callLater(1.0, self.timeout)
        return self._deferred

    def timeout(self):
        assert self.pid
        os.kill(self.pid, signal.SIGKILL)
        self._timeout = None

    def done(self, status):
        assert self._deferred

        if self._timeout:
            self._timeout.cancel()
            self._timeout = None

        if os.path.exists(self.socket_name):
            os.unlink(self.socket_name)

        self._deferred.callback(status)
        self._deferred = None

class TestCase(unittest.TestCase):

    def setUp(self):
        # Twisted falsely raises it's zombie warning during tests
        warnings.simplefilter("ignore", error.PotentialZombieWarning)

        self.server = Server()
        d = self.server.address()
        d.addCallback(self.setUpSession)
        d.addErrback(lambda x: self.server.stop())
        return d

    def setUpSession(self, address):
        pass

    def tearDown(self):
        try:
            self.tearDownSession()
        finally:
            d = self.server.stop()
        return d

    def tearDownSession(self):
        pass
<|endoftext|>


<commit_before>""" simple """

# python imports
import re
import datetime
import os
from functools import wraps
from unicodedata import normalize

# web stuff and markdown imports
import markdown
from flask.ext.sqlalchemy import SQLAlchemy
from werkzeug.security import check_password_hash
from flask import render_template, request, Flask, flash, redirect, url_for, \
                  abort, jsonify, Response, make_response
from werkzeug.contrib.cache import FileSystemCache, NullCache

try:
    import pygments
    from pygments.formatters import HtmlFormatter
except ImportError:
    pygments = None

app = Flask(__name__)
app.config.from_object('settings')
db = SQLAlchemy(app)
cache_directory = os.path.dirname(__file__)
try:
    cache = FileSystemCache(os.path.join(cache_directory, "cache"))
except Exception,e:
    print "Could not create cache folder, caching will be disabled."
    print "Error: %s"%e
    cache = NullCache()

_punct_re = re.compile(r'[\t !"#$%&\'()*\-/<=>?@\[\\\]^_`{|},.]+')

extentions = ['fenced_code', 'toc']
if pygments is not None:
    extentions.append('codehilite')

MARKDOWN_PARSER = markdown.Markdown(extensions=['fenced_code','codehilite', 'toc'],
                                    output_format="html5")

class Post(db.Model):
    def __init__(self, title=None, created_at=None):
        if title:
            self.title = title
            self.slug = slugify(title)
        if created_at:
            self.created_at = created_at
            self.updated_at = created_at

    __tablename__ = "posts"
    id    = db.Column(db.Integer, primary_key=True)
    title = db.Column(db.String())
    slug  = db.Column(db.String(), unique=True)
    text  = db.Column(db.String(), default="")
    draft = db.Column(db.Boolean(), index=True, default=True)
    views = db.Column(db.Integer(), default=0)
    created_at = db.Column(db.DateTime, index=True)
    updated_at = db.Column(db.DateTime)

    def render_content(self):
        _cached = cache.get("post_%s"%self.id)
        if _cached is not None:
            return _cached
        text = MARKDOWN_PARSER.convert(self.text)
        cache.set("post_%s"%self.id, text)
        return text

    def set_content(self, content):
        cache.delete("post_%s"%self.id)
        self.text = content

try:
    db.create_all()
except Exception:
    pass

def is_admin():
    auth = request.authorization
    if not auth or not (auth.username == app.config["ADMIN_USERNAME"]
                        and check_password_hash(app.config["ADMIN_PASSWORD"],
                                                auth.password)):
        return False
    return True

def requires_authentication(func):
    """ function decorator for handling authentication """
    @wraps(func)
    def _auth_decorator(*args, **kwargs):
        """ does the wrapping """
        if not is_admin():
            return Response("Could not authenticate you",
                            401,
                            {"WWW-Authenticate":'Basic realm="Login Required"'})
        return func(*args, **kwargs)

    return _auth_decorator

@app.route("/")
def index():
    """ Index Page. Here is where the magic starts """
    page = request.args.get("page", 0, type=int)
    posts_master = db.session.query(Post)\
                       .filter_by(draft=False)\
                       .order_by(Post.created_at.desc())

    posts_count = posts_master.count()

    posts = posts_master\
                .limit(app.config["POSTS_PER_PAGE"])\
                .offset(page * app.config["POSTS_PER_PAGE"])\
                .all()

    # Sorry for the verbose names, but this seemed like a sensible
    # thing to do.
    last_possible_post_on_page = page * app.config["POSTS_PER_PAGE"]\
                               + app.config["POSTS_PER_PAGE"]
    there_is_more = posts_count > last_possible_post_on_page

    return render_template("index.html",
                           posts=posts,
                           now=datetime.datetime.now(),
                           is_more=there_is_more,
                           current_page=page,
                           is_admin=is_admin())

@app.route("/style.css")
def render_font_style():
    t = render_template("font_style.css",
                            font_name=app.config["FONT_NAME"])
    return Response(t, mimetype="text/css")

@app.route("/<int:post_id>")
def view_post(post_id):
    """ view_post renders a post and returns the Response object """
    try:
        post = db.session.query(Post).filter_by(id=post_id, draft=False).one()
    except Exception:
        return abort(404)

    db.session.query(Post)\
        .filter_by(id=post_id)\
        .update({Post.views:Post.views + 1})
    db.session.commit()

    return render_template("view.html", post=post, is_admin=is_admin())

@app.route("/<slug>")
def view_post_slug(slug):
    slug = slug.encode('utf-8')

    try:
        post = db.session.query(Post).filter_by(slug=slug, draft=False).one()
    except Exception:
        #TODO: Better exception
        return abort(404)

    if not any(botname in request.user_agent.string for botname in
                ['Googlebot',  'Slurp',         'Twiceler',     'msnbot',
                 'KaloogaBot', 'YodaoBot',      '"Baiduspider',
                 'googlebot',  'Speedy Spider', 'DotBot']):
        db.session.query(Post)\
            .filter_by(slug=slug)\
            .update({Post.views:Post.views+1})
        db.session.commit()

    pid = request.args.get("pid", "0")
    return render_template("view.html", post=post, pid=pid, is_admin=is_admin())

@app.route("/new", methods=["POST", "GET"])
@requires_authentication
def new_post():
    post = Post(title=request.form.get("title","untitled"),
                created_at=datetime.datetime.now())

    db.session.add(post)
    db.session.commit()

    return redirect(url_for("edit", post_id=post.id))

@app.route("/edit/<int:post_id>", methods=["GET","POST"])
@requires_authentication
def edit(post_id):
    try:
        post = db.session.query(Post).filter_by(id=post_id).one()
    except Exception:
        #TODO: better exception
        return abort(404)

    if request.method == "GET":
        return render_template("edit.html", post=post)
    else:
        if post.title != request.form.get("post_title", ""):
            post.title = request.form.get("post_title","")
            post.slug = slugify(post.title)
        post.set_content(request.form.get("post_content",""))
        post.updated_at = datetime.datetime.now()

        if any(request.form.getlist("post_draft", type=int)):
            post.draft = True
        else:
            post.draft = False

        db.session.add(post)
        db.session.commit()
        return redirect(url_for("edit", post_id=post_id))

@app.route("/delete/<int:post_id>", methods=["GET","POST"])
@requires_authentication
def delete(post_id):
    try:
        post = db.session.query(Post).filter_by(id=post_id).one()
    except Exception:
        # TODO: define better exceptions for db failure.
        flash("Error deleting post ID %s"%post_id, category="error")
    else:
        db.session.delete(post)
        db.session.commit()

    return redirect(request.args.get("next","")
        or request.referrer
        or url_for('index'))

@app.route("/admin", methods=["GET", "POST"])
@requires_authentication
def admin():
    drafts = db.session.query(Post)\
                 .filter_by(draft=True)\
                 .order_by(Post.created_at.desc()).all()
    posts  = db.session.query(Post)\
                 .filter_by(draft=False)\
                 .order_by(Post.created_at.desc()).all()
    return render_template("admin.html", drafts=drafts, posts=posts)

@app.route("/admin/save/<int:post_id>", methods=["POST"])
@requires_authentication
def save_post(post_id):
    try:
        post = db.session.query(Post).filter_by(id=post_id).one()
    except Exception:
        # TODO Better exception
        return abort(404)
    if post.title != request.form.get("title", ""):
        post.title = request.form.get("title","")
        post.slug = slugify(post.title)
    post.set_content(request.form.get("content", ""))
    post.updated_at = datetime.datetime.now()
    db.session.add(post)
    db.session.commit()
    return jsonify(success=True)

@app.route("/preview/<int:post_id>")
@requires_authentication
def preview(post_id):
    try:
        post = db.session.query(Post).filter_by(id=post_id).one()
    except Exception:
        # TODO: Better exception
        return abort(404)

    return render_template("post_preview.html", post=post)

@app.route("/posts.rss")
def feed():
    posts = db.session.query(Post)\
                .filter_by(draft=False)\
                .order_by(Post.created_at.desc())\
                .limit(10)\
                .all()

    response = make_response(render_template('index.xml', posts=posts))
    response.mimetype = "application/xml"
    return response

def slugify(text, delim='-'):
    """Generates an slightly worse ASCII-only slug."""
    result = []
    for word in _punct_re.split(text.lower()):
        word = normalize('NFKD', unicode(word)).encode('utf-8')
        if word:
            result.append(word)
    slug = delim.join(result)
    # This could have issues if a post is marked as draft, then live, then
    # draft, then live and there are > 1 posts with the same slug. Oh well.
    count = db.session.query(Post).filter_by(slug=slug).count()
    if count > 0:
        return "%s%s%s" % (slug, delim, count)
    else:
        return slug

if __name__ == "__main__":
    # Listen on all interfaces. This is so I could view the page on my iPhone/WP7 *not* so you can deploy using this file.
    if pygments is not None:
        to_write_path = os.path.join(app.static_folder, "css", "code_styles.css")
        if not os.path.exists(to_write_path):
            to_write = HtmlFormatter().get_style_defs(".codehilite")
            try:
                with open(to_write_path, "w") as fd:
                    fd.write(to_write)
            except IOError:
                pass
    app.run(host="0.0.0.0")
<commit_msg>Small fix with the extensions logic.<commit_after>""" simple """

# python imports
import re
import datetime
import os
from functools import wraps
from unicodedata import normalize

# web stuff and markdown imports
import markdown
from flask.ext.sqlalchemy import SQLAlchemy
from werkzeug.security import check_password_hash
from flask import render_template, request, Flask, flash, redirect, url_for, \
                  abort, jsonify, Response, make_response
from werkzeug.contrib.cache import FileSystemCache, NullCache

try:
    import pygments
    from pygments.formatters import HtmlFormatter
except ImportError:
    pygments = None

app = Flask(__name__)
app.config.from_object('settings')
db = SQLAlchemy(app)
cache_directory = os.path.dirname(__file__)
try:
    cache = FileSystemCache(os.path.join(cache_directory, "cache"))
except Exception,e:
    print "Could not create cache folder, caching will be disabled."
    print "Error: %s"%e
    cache = NullCache()

_punct_re = re.compile(r'[\t !"#$%&\'()*\-/<=>?@\[\\\]^_`{|},.]+')

extensions = ['fenced_code', 'toc']
if pygments is not None:
    extensions.append('codehilite')

MARKDOWN_PARSER = markdown.Markdown(extensions=extensions,
                                    output_format="html5")

class Post(db.Model):
    def __init__(self, title=None, created_at=None):
        if title:
            self.title = title
            self.slug = slugify(title)
        if created_at:
            self.created_at = created_at
            self.updated_at = created_at

    __tablename__ = "posts"
    id    = db.Column(db.Integer, primary_key=True)
    title = db.Column(db.String())
    slug  = db.Column(db.String(), unique=True)
    text  = db.Column(db.String(), default="")
    draft = db.Column(db.Boolean(), index=True, default=True)
    views = db.Column(db.Integer(), default=0)
    created_at = db.Column(db.DateTime, index=True)
    updated_at = db.Column(db.DateTime)

    def render_content(self):
        _cached = cache.get("post_%s"%self.id)
        if _cached is not None:
            return _cached
        text = MARKDOWN_PARSER.convert(self.text)
        cache.set("post_%s"%self.id, text)
        return text

    def set_content(self, content):
        cache.delete("post_%s"%self.id)
        self.text = content

try:
    db.create_all()
except Exception:
    pass

def is_admin():
    auth = request.authorization
    if not auth or not (auth.username == app.config["ADMIN_USERNAME"]
                        and check_password_hash(app.config["ADMIN_PASSWORD"],
                                                auth.password)):
        return False
    return True

def requires_authentication(func):
    """ function decorator for handling authentication """
    @wraps(func)
    def _auth_decorator(*args, **kwargs):
        """ does the wrapping """
        if not is_admin():
            return Response("Could not authenticate you",
                            401,
                            {"WWW-Authenticate":'Basic realm="Login Required"'})
        return func(*args, **kwargs)

    return _auth_decorator

@app.route("/")
def index():
    """ Index Page. Here is where the magic starts """
    page = request.args.get("page", 0, type=int)
    posts_master = db.session.query(Post)\
                       .filter_by(draft=False)\
                       .order_by(Post.created_at.desc())

    posts_count = posts_master.count()

    posts = posts_master\
                .limit(app.config["POSTS_PER_PAGE"])\
                .offset(page * app.config["POSTS_PER_PAGE"])\
                .all()

    # Sorry for the verbose names, but this seemed like a sensible
    # thing to do.
    last_possible_post_on_page = page * app.config["POSTS_PER_PAGE"]\
                               + app.config["POSTS_PER_PAGE"]
    there_is_more = posts_count > last_possible_post_on_page

    return render_template("index.html",
                           posts=posts,
                           now=datetime.datetime.now(),
                           is_more=there_is_more,
                           current_page=page,
                           is_admin=is_admin())

@app.route("/style.css")
def render_font_style():
    t = render_template("font_style.css",
                            font_name=app.config["FONT_NAME"])
    return Response(t, mimetype="text/css")

@app.route("/<int:post_id>")
def view_post(post_id):
    """ view_post renders a post and returns the Response object """
    try:
        post = db.session.query(Post).filter_by(id=post_id, draft=False).one()
    except Exception:
        return abort(404)

    db.session.query(Post)\
        .filter_by(id=post_id)\
        .update({Post.views:Post.views + 1})
    db.session.commit()

    return render_template("view.html", post=post, is_admin=is_admin())

@app.route("/<slug>")
def view_post_slug(slug):
    slug = slug.encode('utf-8')

    try:
        post = db.session.query(Post).filter_by(slug=slug, draft=False).one()
    except Exception:
        #TODO: Better exception
        return abort(404)

    if not any(botname in request.user_agent.string for botname in
                ['Googlebot',  'Slurp',         'Twiceler',     'msnbot',
                 'KaloogaBot', 'YodaoBot',      '"Baiduspider',
                 'googlebot',  'Speedy Spider', 'DotBot']):
        db.session.query(Post)\
            .filter_by(slug=slug)\
            .update({Post.views:Post.views+1})
        db.session.commit()

    pid = request.args.get("pid", "0")
    return render_template("view.html", post=post, pid=pid, is_admin=is_admin())

@app.route("/new", methods=["POST", "GET"])
@requires_authentication
def new_post():
    post = Post(title=request.form.get("title","untitled"),
                created_at=datetime.datetime.now())

    db.session.add(post)
    db.session.commit()

    return redirect(url_for("edit", post_id=post.id))

@app.route("/edit/<int:post_id>", methods=["GET","POST"])
@requires_authentication
def edit(post_id):
    try:
        post = db.session.query(Post).filter_by(id=post_id).one()
    except Exception:
        #TODO: better exception
        return abort(404)

    if request.method == "GET":
        return render_template("edit.html", post=post)
    else:
        if post.title != request.form.get("post_title", ""):
            post.title = request.form.get("post_title","")
            post.slug = slugify(post.title)
        post.set_content(request.form.get("post_content",""))
        post.updated_at = datetime.datetime.now()

        if any(request.form.getlist("post_draft", type=int)):
            post.draft = True
        else:
            post.draft = False

        db.session.add(post)
        db.session.commit()
        return redirect(url_for("edit", post_id=post_id))

@app.route("/delete/<int:post_id>", methods=["GET","POST"])
@requires_authentication
def delete(post_id):
    try:
        post = db.session.query(Post).filter_by(id=post_id).one()
    except Exception:
        # TODO: define better exceptions for db failure.
        flash("Error deleting post ID %s"%post_id, category="error")
    else:
        db.session.delete(post)
        db.session.commit()

    return redirect(request.args.get("next","")
        or request.referrer
        or url_for('index'))

@app.route("/admin", methods=["GET", "POST"])
@requires_authentication
def admin():
    drafts = db.session.query(Post)\
                 .filter_by(draft=True)\
                 .order_by(Post.created_at.desc()).all()
    posts  = db.session.query(Post)\
                 .filter_by(draft=False)\
                 .order_by(Post.created_at.desc()).all()
    return render_template("admin.html", drafts=drafts, posts=posts)

@app.route("/admin/save/<int:post_id>", methods=["POST"])
@requires_authentication
def save_post(post_id):
    try:
        post = db.session.query(Post).filter_by(id=post_id).one()
    except Exception:
        # TODO Better exception
        return abort(404)
    if post.title != request.form.get("title", ""):
        post.title = request.form.get("title","")
        post.slug = slugify(post.title)
    post.set_content(request.form.get("content", ""))
    post.updated_at = datetime.datetime.now()
    db.session.add(post)
    db.session.commit()
    return jsonify(success=True)

@app.route("/preview/<int:post_id>")
@requires_authentication
def preview(post_id):
    try:
        post = db.session.query(Post).filter_by(id=post_id).one()
    except Exception:
        # TODO: Better exception
        return abort(404)

    return render_template("post_preview.html", post=post)

@app.route("/posts.rss")
def feed():
    posts = db.session.query(Post)\
                .filter_by(draft=False)\
                .order_by(Post.created_at.desc())\
                .limit(10)\
                .all()

    response = make_response(render_template('index.xml', posts=posts))
    response.mimetype = "application/xml"
    return response

def slugify(text, delim='-'):
    """Generates an slightly worse ASCII-only slug."""
    result = []
    for word in _punct_re.split(text.lower()):
        word = normalize('NFKD', unicode(word)).encode('utf-8')
        if word:
            result.append(word)
    slug = delim.join(result)
    # This could have issues if a post is marked as draft, then live, then
    # draft, then live and there are > 1 posts with the same slug. Oh well.
    count = db.session.query(Post).filter_by(slug=slug).count()
    if count > 0:
        return "%s%s%s" % (slug, delim, count)
    else:
        return slug

if __name__ == "__main__":
    # Listen on all interfaces. This is so I could view the page on my iPhone/WP7 *not* so you can deploy using this file.
    if pygments is not None:
        to_write_path = os.path.join(app.static_folder, "css", "code_styles.css")
        if not os.path.exists(to_write_path):
            to_write = HtmlFormatter().get_style_defs(".codehilite")
            try:
                with open(to_write_path, "w") as fd:
                    fd.write(to_write)
            except IOError:
                pass
    app.run(host="0.0.0.0")
<|endoftext|>


<commit_before>"""
wrapanapi.entities.vm

Methods/classes pertaining to performing actions on a VM/instance
"""
from abc import ABCMeta, abstractmethod, abstractproperty

from cached_property import cached_property_with_ttl
from wait_for import wait_for, TimedOutError

from wrapanapi.const import CACHED_PROPERTY_TTL
from wrapanapi.exceptions import MultipleItemsError, NotFoundError
from wrapanapi.entities.base import Entity, EntityMixin

class VmState(object):
    """
    Represents a state for a VM/instance on the provider system.

    Implementations of ``Vm`` should map to these states
    """
    RUNNING = 'VmState.RUNNING'
    STOPPED = 'VmState.STOPPED'
    PAUSED = 'VmState.PAUSED'
    SUSPENDED = 'VmState.SUSPENDED'
    DELETED = 'VmState.DELETED'
    STARTING = 'VmState.STARTING'
    STOPPING = 'VmState.STOPPING'
    ERROR = 'VmState.ERROR'
    UNKNOWN = 'VmState.UNKNOWN'
    SHELVED = 'VmState.SHELVED'
    SHELVED_OFFLOADED = 'VmState.SHELVED_OFFLOADED'

    @classmethod
    def valid_states(cls):
        return [
            var_val for _, var_val in vars(cls).items()
            if isinstance(var_val, basestring) and var_val.startswith('VmState.')
        ]

class Vm(Entity):
    """
    Represents a single VM/instance on a management system.
    """
    __metaclass__ = ABCMeta

    # Implementations must define a dict which maps API states returned by the
    # system to a VmState. Example:
    #    {'running': VmState.RUNNING, 'shutdown': VmState.STOPPED}
    state_map = None

    def __init__(self, *args, **kwargs):
        """
        Verify the required class variables are implemented during init

        Since abc has no 'abstract class property' concept, this is the approach taken.
        """
        state_map = getattr(self, 'state_map')
        if (not state_map or not isinstance(state_map, dict) or
                not all(value in VmState.valid_states() for value in state_map.values())):
            raise NotImplementedError(
                "property '{}' not properly implemented in class '{}'"
                .format('state_map', self.__class__.__name__)
            )
        super(Vm, self).__init__(*args, **kwargs)

    def _api_state_to_vmstate(self, api_state):
        """
        Use the state_map for this instance to map a state string into a VmState constant
        """
        try:
            return self.state_map[api_state]
        except KeyError:
            self.logger.warn(
                "Unmapped VM state '%s' received from system, mapped to '%s'",
                api_state, VmState.UNKNOWN
            )
            return VmState.UNKNOWN

    @property
    def exists(self):
        """Extend 'exists' method to also check in VM state is deleted."""
        exists = super(Vm, self).exists
        if exists:
            if self.state == VmState.DELETED:
                return False
        return exists

    @abstractmethod
    def _get_state(self):
        """
        Returns VMState object representing the VM's current state

        Should call self.refresh() if necessary to get the latest status from the API
        """

    @cached_property_with_ttl(ttl=CACHED_PROPERTY_TTL)
    def state(self):
        """
        Returns a cached value of state.

        This avoids repeatedly querying for state for uses like:
        (self.is_running or self.is_stopped or self.is_paused)

        This property returns updated state only if the last time we retrieved state from
        the API is >1sec.

        This is the property that should be used when querying for VM state. _get_state
        shouldn't be the main method utilized.
        """
        return self._get_state()

    @property
    def is_running(self):
        """Return True if VM is running."""
        return self.state == VmState.RUNNING

    @property
    def is_started(self):
        """An alias for ``is_running``."""
        return self.is_running

    @property
    def is_stopped(self):
        """Return True if VM is stopped."""
        return self.state == VmState.STOPPED

    @property
    def is_paused(self):
        """Return True if VM is paused."""
        return self.state == VmState.PAUSED

    @property
    def is_suspended(self):
        """Return True if VM is suspended."""
        return self.state == VmState.SUSPENDED

    @property
    def is_starting(self):
        """Return True if VM is starting."""
        return self.state == VmState.STARTING

    @property
    def is_stopping(self):
        """Return True if VM is stopping."""
        return self.state == VmState.STOPPING

    @abstractproperty
    def ip(self):
        """
        Returns IP address of the VM/instance

        Should refresh if necessary to get most up-to-date info
        """

    @abstractproperty
    def creation_time(self):
        """
        Returns creation time of VM/instance
        """

    def wait_for_state(self, state, timeout='6m', delay=15):
        """
        Waits for a VM to be in the desired state

        Args:
            state: desired VmState
            timeout: wait_for timeout value
            delay: delay when looping to check for updated state
        """
        valid_states = self.state_map.values()
        if state not in valid_states:
            self.logger.error(
                "Invalid desired state. Valid states for %s: %s",
                self.__class__.__name__, valid_states
            )
            raise ValueError('Invalid desired state')

        wait_for(
            lambda: self.state == state,
            timeout=timeout,
            delay=delay,
            message="wait for vm {} to reach state '{}'".format(self._log_id, state))

    def _handle_transition(self, in_desired_state, in_state_requiring_prep, in_actionable_state,
                           do_prep, do_action, state, timeout, delay):
        """
        Handles state transition for ensure_state() method

        See that docstring below for explanation of the args. Each arg here is a callable except for
        'state', 'timeout' and 'delay'
        """
        def _transition():
            if in_desired_state():
                return True
            elif in_state_requiring_prep():
                self.logger.info(
                    "VM %s in state requiring prep. current state: %s, ensuring state: %s)",
                    self._log_id, self.state, state
                )
                do_prep()
            elif in_actionable_state():
                self.logger.info(
                    "VM %s in actionable state. current state: %s, ensuring state: %s)",
                    self._log_id, self.state, state
                )
                do_action()

        return wait_for(
            _transition, timeout=timeout, delay=delay,
            message="ensure vm {} reaches state '{}'".format(self._log_id, state)
        )

    def ensure_state(self, state, timeout='6m', delay=5):
        """
        Perform the actions required to get the VM to the desired state.

        State can be one of:
            VmState.RUNNING, VmState.STOPPED, VmState.SUSPENDED, VmState.PAUSED

        Each desired state requires various checks/steps to ensure we "achieve" that state.

        The logic implied while waiting is:
        1. Check if VM is in_desired_state, if so, we're done
        2. If not, check if it is in_state_requiring_prep
            (for example, you can't stop a suspended VM, so we need to prep the VM by starting it)
        3. Move the VM to the correct 'prep state' (calling method do_prep)
        4. Check if the VM is in a state that allows moving to the desired state
            (in_actionable_state should return True)
        5. Perform the action to put the VM into that state (calling method do_action)

        The methods are defined differently for each desired state.

        For some states, step 2 and 3 do not apply, see for example when desired state is
        'running', in those cases just make sure that 'in_state_requiring_prep' always returns
        false.

        Args:
            state: desired VMState
            timeout: wait_for timeout value
            delay: delay when looping to check for new state
        """
        valid_states = self.state_map.values()
        if state not in valid_states:
            self.logger.error(
                "Invalid desired state. Valid states for %s: %s",
                self.__class__.__name__, valid_states
            )
            raise ValueError('Invalid desired state')

        if state == VmState.RUNNING:
            return self._handle_transition(
                in_desired_state=lambda: self.is_running,
                in_state_requiring_prep=lambda: False,
                in_actionable_state=lambda: self.is_stopped or self.is_suspended or self.is_paused,
                do_prep=lambda: None,
                do_action=self.start,
                state=state, timeout=timeout, delay=delay
            )
        elif state == VmState.STOPPED:
            return self._handle_transition(
                in_desired_state=lambda: self.is_stopped,
                in_state_requiring_prep=lambda: self.is_suspended or self.is_paused,
                in_actionable_state=lambda: self.is_running,
                do_prep=self.start,
                do_action=self.stop,
                state=state, timeout=timeout, delay=delay
            )
        elif state == VmState.SUSPENDED:
            if not self.system.can_suspend:
                raise ValueError(
                    'System {} is unable to suspend'.format(self.system.__class__.__name__))
            return self._handle_transition(
                in_desired_state=lambda: self.is_suspended,
                in_state_requiring_prep=lambda: self.is_stopped or self.is_paused,
                in_actionable_state=lambda: self.is_running,
                do_prep=self.start,
                do_action=self.suspend,
                state=state, timeout=timeout, delay=delay
            )
        elif state == VmState.PAUSED:
            if not self.system.can_pause:
                raise ValueError(
                    'System {} is unable to pause'.format(self.system.__class__.__name__))
            return self._handle_transition(
                in_desired_state=lambda: self.is_paused,
                in_state_requiring_prep=lambda: self.is_stopped or self.is_suspended,
                in_actionable_state=lambda: self.is_running,
                do_prep=self.start,
                do_action=self.pause,
                state=state, timeout=timeout, delay=delay
            )
        else:
            raise ValueError("Invalid desired state '{}'".format(state))

    @property
    def in_steady_state(self):
        """
        Return whether the virtual machine is in a steady state

        Returns: boolean
        """
        return self.state in [VmState.RUNNING, VmState.STOPPED, VmState.PAUSED, VmState.SUSPENDED]

    def wait_for_steady_state(self, timeout=None, delay=5):
        """
        Waits for the system's steady_wait_time for VM to reach a steady state

        Args:
            num_sec: Time to wait to override default steady_wait_time
        """
        try:
            return wait_for(
                lambda: self.in_steady_state,
                timeout=timeout if timeout else self.system.steady_wait_time,
                delay=delay,
                message="VM/Instance '{}' in steady state".format(self._log_id)
            )
        except TimedOutError:
            self.logger.exception(
                "VM %s stuck in '%s' while waiting for steady state.", self._log_id, self.state)
            raise

    @abstractmethod
    def start(self):
        """
        Starts the VM/instance. Blocks until task completes.

        Returns: True if vm action has been initiated properly
        """

    @abstractmethod
    def stop(self):
        """
        Stops the VM/instance. Blocks until task completes.

        Returns: True if vm action has been initiated properly
        """

    @abstractmethod
    def restart(self):
        """
        Restarts the VM/instance. Blocks until task completes.

        Returns: True if vm action has been initiated properly
        """

    def rename(self, name):
        """
        Rename VM/instance. Not supported on all platforms.
        """
        raise NotImplementedError('rename not implemented.')

    def suspend(self):
        """
        Suspends the VM/instance.  Blocks until task completes.

        This method may not always be implemented.

        Returns: True if vm action has been initiated properly
        """
        raise NotImplementedError('suspend not implemented.')

    def pause(self):
        """
        Pauses the VM/instance.  Blocks until task completes.

        This method may not always be implemented.

        Returns: True if vm action has been initiated properly
        """
        raise NotImplementedError('pause not implemented.')

    def clone(self, vm_name, **kwargs):
        """
        Clones the VM to a new VM of name 'vm_name'.

        This method may not always be implemented.

        Args:
            vm_name: The name of the new VM
        Returns: VM object for the new VM
        """
        raise NotImplementedError('clone not implemented.')

    def get_hardware_configuration(self):
        """Return hardware configuration of the VM."""
        raise NotImplementedError(
            'Provider {} does not implement get_hardware_configuration'
            .format(type(self.system).__name__)
        )

class VmMixin(EntityMixin):
    """
    Defines methods or properties a wrapanapi.systems.System that manages Vm's should have
    """
    __metaclass__ = ABCMeta

    # Implementations must define whether this system can suspend (True/False)
    can_suspend = None
    # Implementations must define whether this system can pause (True/False)
    can_pause = None
    # Implementations may override the amount of sec to wait for a VM to reach steady state
    steady_wait_time = 180

    def __init__(self, *args, **kwargs):
        """
        Verify the required class variables are implemented during init

        Since abc has no 'abstract class property' concept, this is the approach taken.
        """
        required_props = ['can_suspend', 'can_pause']
        for prop in required_props:
            prop_value = getattr(self, prop)
            if not isinstance(prop_value, bool):
                raise NotImplementedError(
                    "property '{}' must be implemented in class '{}'"
                    .format(prop, self.__class__.__name__)
                )
        super(VmMixin, self).__init__(*args, **kwargs)

    @abstractproperty
    def can_suspend(self):
        """Return True if this system can suspend VM's/instances, False if not."""

    @abstractproperty
    def can_pause(self):
        """Return True if this system can pause VM's/instances, False if not."""

    @abstractmethod
    def get_vm(self, name, **kwargs):
        """
        Get VM from system with name 'name'

        This should return only ONE matching entity. If multiple entities match
        the criteria, a MultipleItemsError should be raised

        Returns:
            wrapanapi.entities.Vm if it exists
        Raises:
            wrapanapi.exceptions.MultipleItemsError if multiple matches are found
        """

    @abstractmethod
    def create_vm(self, name, **kwargs):
        """
        Create VM on system with name 'name'

        Returns:
            wrapanapi.entities.Vm for newly created VM
        """

    @abstractmethod
    def list_vms(self, **kwargs):
        """
        List VMs on system

        Returns:
            list of wrapanapi.entities.Vm
        """

    @abstractmethod
    def find_vms(self, name, **kwargs):
        """
        Find VMs on system based on name or other filters in kwargs

        Should return an empty list if no matches were found

        Returns:
            list of wrapanapi.entities.Vm for matches found
        """

    def does_vm_exist(self, name):
        """
        Checks if a VM with 'name' exists on the system

        If multiple VMs with the same name exist, this still returns 'True'
        """
        try:
            return bool(self.get_vm(name))
        except MultipleItemsError:
            return True
        except NotFoundError:
            return False
<commit_msg>Remove super in VmMixin.__init__ since System no longer has __init__<commit_after>"""
wrapanapi.entities.vm

Methods/classes pertaining to performing actions on a VM/instance
"""
from abc import ABCMeta, abstractmethod, abstractproperty

from cached_property import cached_property_with_ttl
from wait_for import wait_for, TimedOutError

from wrapanapi.const import CACHED_PROPERTY_TTL
from wrapanapi.exceptions import MultipleItemsError, NotFoundError
from wrapanapi.entities.base import Entity, EntityMixin

class VmState(object):
    """
    Represents a state for a VM/instance on the provider system.

    Implementations of ``Vm`` should map to these states
    """
    RUNNING = 'VmState.RUNNING'
    STOPPED = 'VmState.STOPPED'
    PAUSED = 'VmState.PAUSED'
    SUSPENDED = 'VmState.SUSPENDED'
    DELETED = 'VmState.DELETED'
    STARTING = 'VmState.STARTING'
    STOPPING = 'VmState.STOPPING'
    ERROR = 'VmState.ERROR'
    UNKNOWN = 'VmState.UNKNOWN'
    SHELVED = 'VmState.SHELVED'
    SHELVED_OFFLOADED = 'VmState.SHELVED_OFFLOADED'

    @classmethod
    def valid_states(cls):
        return [
            var_val for _, var_val in vars(cls).items()
            if isinstance(var_val, basestring) and var_val.startswith('VmState.')
        ]

class Vm(Entity):
    """
    Represents a single VM/instance on a management system.
    """
    __metaclass__ = ABCMeta

    # Implementations must define a dict which maps API states returned by the
    # system to a VmState. Example:
    #    {'running': VmState.RUNNING, 'shutdown': VmState.STOPPED}
    state_map = None

    def __init__(self, *args, **kwargs):
        """
        Verify the required class variables are implemented during init

        Since abc has no 'abstract class property' concept, this is the approach taken.
        """
        state_map = getattr(self, 'state_map')
        if (not state_map or not isinstance(state_map, dict) or
                not all(value in VmState.valid_states() for value in state_map.values())):
            raise NotImplementedError(
                "property '{}' not properly implemented in class '{}'"
                .format('state_map', self.__class__.__name__)
            )
        super(Vm, self).__init__(*args, **kwargs)

    def _api_state_to_vmstate(self, api_state):
        """
        Use the state_map for this instance to map a state string into a VmState constant
        """
        try:
            return self.state_map[api_state]
        except KeyError:
            self.logger.warn(
                "Unmapped VM state '%s' received from system, mapped to '%s'",
                api_state, VmState.UNKNOWN
            )
            return VmState.UNKNOWN

    @property
    def exists(self):
        """Extend 'exists' method to also check in VM state is deleted."""
        exists = super(Vm, self).exists
        if exists:
            if self.state == VmState.DELETED:
                return False
        return exists

    @abstractmethod
    def _get_state(self):
        """
        Returns VMState object representing the VM's current state

        Should call self.refresh() if necessary to get the latest status from the API
        """

    @cached_property_with_ttl(ttl=CACHED_PROPERTY_TTL)
    def state(self):
        """
        Returns a cached value of state.

        This avoids repeatedly querying for state for uses like:
        (self.is_running or self.is_stopped or self.is_paused)

        This property returns updated state only if the last time we retrieved state from
        the API is >1sec.

        This is the property that should be used when querying for VM state. _get_state
        shouldn't be the main method utilized.
        """
        return self._get_state()

    @property
    def is_running(self):
        """Return True if VM is running."""
        return self.state == VmState.RUNNING

    @property
    def is_started(self):
        """An alias for ``is_running``."""
        return self.is_running

    @property
    def is_stopped(self):
        """Return True if VM is stopped."""
        return self.state == VmState.STOPPED

    @property
    def is_paused(self):
        """Return True if VM is paused."""
        return self.state == VmState.PAUSED

    @property
    def is_suspended(self):
        """Return True if VM is suspended."""
        return self.state == VmState.SUSPENDED

    @property
    def is_starting(self):
        """Return True if VM is starting."""
        return self.state == VmState.STARTING

    @property
    def is_stopping(self):
        """Return True if VM is stopping."""
        return self.state == VmState.STOPPING

    @abstractproperty
    def ip(self):
        """
        Returns IP address of the VM/instance

        Should refresh if necessary to get most up-to-date info
        """

    @abstractproperty
    def creation_time(self):
        """
        Returns creation time of VM/instance
        """

    def wait_for_state(self, state, timeout='6m', delay=15):
        """
        Waits for a VM to be in the desired state

        Args:
            state: desired VmState
            timeout: wait_for timeout value
            delay: delay when looping to check for updated state
        """
        valid_states = self.state_map.values()
        if state not in valid_states:
            self.logger.error(
                "Invalid desired state. Valid states for %s: %s",
                self.__class__.__name__, valid_states
            )
            raise ValueError('Invalid desired state')

        wait_for(
            lambda: self.state == state,
            timeout=timeout,
            delay=delay,
            message="wait for vm {} to reach state '{}'".format(self._log_id, state))

    def _handle_transition(self, in_desired_state, in_state_requiring_prep, in_actionable_state,
                           do_prep, do_action, state, timeout, delay):
        """
        Handles state transition for ensure_state() method

        See that docstring below for explanation of the args. Each arg here is a callable except for
        'state', 'timeout' and 'delay'
        """
        def _transition():
            if in_desired_state():
                return True
            elif in_state_requiring_prep():
                self.logger.info(
                    "VM %s in state requiring prep. current state: %s, ensuring state: %s)",
                    self._log_id, self.state, state
                )
                do_prep()
            elif in_actionable_state():
                self.logger.info(
                    "VM %s in actionable state. current state: %s, ensuring state: %s)",
                    self._log_id, self.state, state
                )
                do_action()

        return wait_for(
            _transition, timeout=timeout, delay=delay,
            message="ensure vm {} reaches state '{}'".format(self._log_id, state)
        )

    def ensure_state(self, state, timeout='6m', delay=5):
        """
        Perform the actions required to get the VM to the desired state.

        State can be one of:
            VmState.RUNNING, VmState.STOPPED, VmState.SUSPENDED, VmState.PAUSED

        Each desired state requires various checks/steps to ensure we "achieve" that state.

        The logic implied while waiting is:
        1. Check if VM is in_desired_state, if so, we're done
        2. If not, check if it is in_state_requiring_prep
            (for example, you can't stop a suspended VM, so we need to prep the VM by starting it)
        3. Move the VM to the correct 'prep state' (calling method do_prep)
        4. Check if the VM is in a state that allows moving to the desired state
            (in_actionable_state should return True)
        5. Perform the action to put the VM into that state (calling method do_action)

        The methods are defined differently for each desired state.

        For some states, step 2 and 3 do not apply, see for example when desired state is
        'running', in those cases just make sure that 'in_state_requiring_prep' always returns
        false.

        Args:
            state: desired VMState
            timeout: wait_for timeout value
            delay: delay when looping to check for new state
        """
        valid_states = self.state_map.values()
        if state not in valid_states:
            self.logger.error(
                "Invalid desired state. Valid states for %s: %s",
                self.__class__.__name__, valid_states
            )
            raise ValueError('Invalid desired state')

        if state == VmState.RUNNING:
            return self._handle_transition(
                in_desired_state=lambda: self.is_running,
                in_state_requiring_prep=lambda: False,
                in_actionable_state=lambda: self.is_stopped or self.is_suspended or self.is_paused,
                do_prep=lambda: None,
                do_action=self.start,
                state=state, timeout=timeout, delay=delay
            )
        elif state == VmState.STOPPED:
            return self._handle_transition(
                in_desired_state=lambda: self.is_stopped,
                in_state_requiring_prep=lambda: self.is_suspended or self.is_paused,
                in_actionable_state=lambda: self.is_running,
                do_prep=self.start,
                do_action=self.stop,
                state=state, timeout=timeout, delay=delay
            )
        elif state == VmState.SUSPENDED:
            if not self.system.can_suspend:
                raise ValueError(
                    'System {} is unable to suspend'.format(self.system.__class__.__name__))
            return self._handle_transition(
                in_desired_state=lambda: self.is_suspended,
                in_state_requiring_prep=lambda: self.is_stopped or self.is_paused,
                in_actionable_state=lambda: self.is_running,
                do_prep=self.start,
                do_action=self.suspend,
                state=state, timeout=timeout, delay=delay
            )
        elif state == VmState.PAUSED:
            if not self.system.can_pause:
                raise ValueError(
                    'System {} is unable to pause'.format(self.system.__class__.__name__))
            return self._handle_transition(
                in_desired_state=lambda: self.is_paused,
                in_state_requiring_prep=lambda: self.is_stopped or self.is_suspended,
                in_actionable_state=lambda: self.is_running,
                do_prep=self.start,
                do_action=self.pause,
                state=state, timeout=timeout, delay=delay
            )
        else:
            raise ValueError("Invalid desired state '{}'".format(state))

    @property
    def in_steady_state(self):
        """
        Return whether the virtual machine is in a steady state

        Returns: boolean
        """
        return self.state in [VmState.RUNNING, VmState.STOPPED, VmState.PAUSED, VmState.SUSPENDED]

    def wait_for_steady_state(self, timeout=None, delay=5):
        """
        Waits for the system's steady_wait_time for VM to reach a steady state

        Args:
            num_sec: Time to wait to override default steady_wait_time
        """
        try:
            return wait_for(
                lambda: self.in_steady_state,
                timeout=timeout if timeout else self.system.steady_wait_time,
                delay=delay,
                message="VM/Instance '{}' in steady state".format(self._log_id)
            )
        except TimedOutError:
            self.logger.exception(
                "VM %s stuck in '%s' while waiting for steady state.", self._log_id, self.state)
            raise

    @abstractmethod
    def start(self):
        """
        Starts the VM/instance. Blocks until task completes.

        Returns: True if vm action has been initiated properly
        """

    @abstractmethod
    def stop(self):
        """
        Stops the VM/instance. Blocks until task completes.

        Returns: True if vm action has been initiated properly
        """

    @abstractmethod
    def restart(self):
        """
        Restarts the VM/instance. Blocks until task completes.

        Returns: True if vm action has been initiated properly
        """

    def rename(self, name):
        """
        Rename VM/instance. Not supported on all platforms.
        """
        raise NotImplementedError('rename not implemented.')

    def suspend(self):
        """
        Suspends the VM/instance.  Blocks until task completes.

        This method may not always be implemented.

        Returns: True if vm action has been initiated properly
        """
        raise NotImplementedError('suspend not implemented.')

    def pause(self):
        """
        Pauses the VM/instance.  Blocks until task completes.

        This method may not always be implemented.

        Returns: True if vm action has been initiated properly
        """
        raise NotImplementedError('pause not implemented.')

    def clone(self, vm_name, **kwargs):
        """
        Clones the VM to a new VM of name 'vm_name'.

        This method may not always be implemented.

        Args:
            vm_name: The name of the new VM
        Returns: VM object for the new VM
        """
        raise NotImplementedError('clone not implemented.')

    def get_hardware_configuration(self):
        """Return hardware configuration of the VM."""
        raise NotImplementedError(
            'Provider {} does not implement get_hardware_configuration'
            .format(type(self.system).__name__)
        )

class VmMixin(EntityMixin):
    """
    Defines methods or properties a wrapanapi.systems.System that manages Vm's should have
    """
    __metaclass__ = ABCMeta

    # Implementations must define whether this system can suspend (True/False)
    can_suspend = None
    # Implementations must define whether this system can pause (True/False)
    can_pause = None
    # Implementations may override the amount of sec to wait for a VM to reach steady state
    steady_wait_time = 180

    def __init__(self, *args, **kwargs):
        """
        Verify the required class variables are implemented during init

        Since abc has no 'abstract class property' concept, this is the approach taken.
        """
        required_props = ['can_suspend', 'can_pause']
        for prop in required_props:
            prop_value = getattr(self, prop)
            if not isinstance(prop_value, bool):
                raise NotImplementedError(
                    "property '{}' must be implemented in class '{}'"
                    .format(prop, self.__class__.__name__)
                )

    @abstractproperty
    def can_suspend(self):
        """Return True if this system can suspend VM's/instances, False if not."""

    @abstractproperty
    def can_pause(self):
        """Return True if this system can pause VM's/instances, False if not."""

    @abstractmethod
    def get_vm(self, name, **kwargs):
        """
        Get VM from system with name 'name'

        This should return only ONE matching entity. If multiple entities match
        the criteria, a MultipleItemsError should be raised

        Returns:
            wrapanapi.entities.Vm if it exists
        Raises:
            wrapanapi.exceptions.MultipleItemsError if multiple matches are found
        """

    @abstractmethod
    def create_vm(self, name, **kwargs):
        """
        Create VM on system with name 'name'

        Returns:
            wrapanapi.entities.Vm for newly created VM
        """

    @abstractmethod
    def list_vms(self, **kwargs):
        """
        List VMs on system

        Returns:
            list of wrapanapi.entities.Vm
        """

    @abstractmethod
    def find_vms(self, name, **kwargs):
        """
        Find VMs on system based on name or other filters in kwargs

        Should return an empty list if no matches were found

        Returns:
            list of wrapanapi.entities.Vm for matches found
        """

    def does_vm_exist(self, name):
        """
        Checks if a VM with 'name' exists on the system

        If multiple VMs with the same name exist, this still returns 'True'
        """
        try:
            return bool(self.get_vm(name))
        except MultipleItemsError:
            return True
        except NotFoundError:
            return False
<|endoftext|>


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

from optparse import OptionParser
from regscrape_lib.util import get_db
import sys

# arguments
arg_parser = OptionParser()
arg_parser.add_option('-r', '--restart', action="store_true", dest="restart_scrape", default=False)
arg_parser.add_option("-c", "--continue", action="store_true", dest="continue_scrape", default=False)
arg_parser.add_option("-C", "--check", action="store_true", dest="check", default=False)

def run(options, args):
    from regscrape_lib.actors import MasterActor
    import time

    import settings

    db = get_db()
    if settings.MODE == 'search' and (not options.continue_scrape) and (not options.restart_scrape) and len(db.collection_names()) > 0:
        print 'This database already contains data; please run with either --restart or --continue to specify what you want to do with it.'
        sys.exit()

    if settings.BROWSER['driver'] == 'Chrome':
        from regscrape_lib.monkey import patch_selenium_chrome
        patch_selenium_chrome()

    if settings.MODE == 'search':
        settings.CLEAR_FIRST = not options.continue_scrape
    else:
        settings.CLEAR_FIRST = False

    settings.CHECK_BEFORE_SCRAPE = options.check

    master = MasterActor.start(settings.INSTANCES)
    master.send_one_way({'command': 'scrape', 'max': settings.MAX_RECORDS})
    while True:
        time.sleep(60)
        master.send_one_way({'command': 'tick'})
<commit_msg>Allow overriding the temporary directory used for Firefox profiles.<commit_after>#!/usr/bin/env python

from optparse import OptionParser
from regscrape_lib.util import get_db
import sys

# arguments
arg_parser = OptionParser()
arg_parser.add_option('-r', '--restart', action="store_true", dest="restart_scrape", default=False)
arg_parser.add_option("-c", "--continue", action="store_true", dest="continue_scrape", default=False)
arg_parser.add_option("-C", "--check", action="store_true", dest="check", default=False)

def run(options, args):
    from regscrape_lib.actors import MasterActor
    import time

    import settings

    db = get_db()
    if settings.MODE == 'search' and (not options.continue_scrape) and (not options.restart_scrape) and len(db.collection_names()) > 0:
        print 'This database already contains data; please run with either --restart or --continue to specify what you want to do with it.'
        sys.exit()

    if settings.BROWSER['driver'] == 'Chrome':
        from regscrape_lib.monkey import patch_selenium_chrome
        patch_selenium_chrome()

    if getattr(settings, 'TEMP_DIR', False):
        import tempfile
        tempfile.tempdir = settings.TEMP_DIR

    if settings.MODE == 'search':
        settings.CLEAR_FIRST = not options.continue_scrape
    else:
        settings.CLEAR_FIRST = False

    settings.CHECK_BEFORE_SCRAPE = options.check

    master = MasterActor.start(settings.INSTANCES)
    master.send_one_way({'command': 'scrape', 'max': settings.MAX_RECORDS})
    while True:
        time.sleep(60)
        master.send_one_way({'command': 'tick'})
<|endoftext|>


<commit_before># coding: utf-8
from __future__ import unicode_literals, division, absolute_import, print_function

import sys
import os
import imp

from . import build_root

deps_dir = os.path.join(build_root, 'modularcrypto-deps')
if os.path.exists(deps_dir):
    sys.path.insert(1, deps_dir)

if sys.version_info[0:2] not in [(2, 6), (3, 2)]:
    from .lint import run as run_lint
else:
    run_lint = None

if sys.version_info[0:2] != (3, 2):
    from .coverage import run as run_coverage
    run_tests = None

else:
    from .tests import run as run_tests
    run_coverage = None

def run():
    """
    Runs the linter and tests

    :return:
        A bool - if the linter and tests ran successfully
    """

    print('Python ' + sys.version.replace('\n', ''))

    oscrypto_path = os.path.join(build_root, 'oscrypto')
    if not os.path.exists(oscrypto_path):
        oscrypto_path = os.path.join(build_root, 'modularcrypto-deps', 'oscrypto')
    if not os.path.exists(oscrypto_path):
        print(
            'Unable to locate oscrypto.tests',
            file=sys.stderr
        )
        return False

    try:
        oscrypto_tests_module_info = imp.find_module('tests', [oscrypto_path])
    except ImportError:
        print(
            'Error loading oscrypto.tests from "%s"' % oscrypto_path,
            file=sys.stderr
        )
        return False
    oscrypto_tests = imp.load_module('oscrypto.tests', *oscrypto_tests_module_info)
    asn1crypto, oscrypto = oscrypto_tests.local_oscrypto()
    print(
        '\nasn1crypto: %s, %s' % (
            asn1crypto.__version__,
            os.path.dirname(asn1crypto.__file__)
        )
    )
    print(
        'oscrypto: %s backend, %s, %s' % (
            oscrypto.backend(),
            oscrypto.__version__,
            os.path.dirname(oscrypto.__file__)
        )
    )

    if run_lint:
        print('')
        lint_result = run_lint()
    else:
        lint_result = True

    if run_coverage:
        print('\nRunning tests (via coverage.py)')
        sys.stdout.flush()
        tests_result = run_coverage(ci=True)
    else:
        print('\nRunning tests')
        sys.stdout.flush()
        tests_result = run_tests(ci=True)
    sys.stdout.flush()

    return lint_result and tests_result
<commit_msg>More debug info<commit_after># coding: utf-8
from __future__ import unicode_literals, division, absolute_import, print_function

import sys
import os
import imp

from . import build_root

deps_dir = os.path.join(build_root, 'modularcrypto-deps')
if os.path.exists(deps_dir):
    sys.path.insert(1, deps_dir)

if sys.version_info[0:2] not in [(2, 6), (3, 2)]:
    from .lint import run as run_lint
else:
    run_lint = None

if sys.version_info[0:2] != (3, 2):
    from .coverage import run as run_coverage
    run_tests = None

else:
    from .tests import run as run_tests
    run_coverage = None

def run():
    """
    Runs the linter and tests

    :return:
        A bool - if the linter and tests ran successfully
    """

    print('Python ' + sys.version.replace('\n', ''))

    oscrypto_path = os.path.join(build_root, 'oscrypto')
    if not os.path.exists(oscrypto_path):
        oscrypto_path = os.path.join(build_root, 'modularcrypto-deps', 'oscrypto')
    if not os.path.exists(oscrypto_path):
        print(
            'Unable to locate oscrypto.tests',
            file=sys.stderr
        )
        return False

    try:
        oscrypto_tests_module_info = imp.find_module('tests', [oscrypto_path])
    except ImportError:
        print(
            'Error loading oscrypto.tests from "%s":' % oscrypto_path,
            file=sys.stderr
        )
        for subpath in os.listdir(oscrypto_path):
            slash = os.sep if os.path.isdir(os.path.join(oscrypto_path, subpath)) else ''
            print('  %s%s' % (subpath, slash), file=sys.stderr)
        return False
    oscrypto_tests = imp.load_module('oscrypto.tests', *oscrypto_tests_module_info)
    asn1crypto, oscrypto = oscrypto_tests.local_oscrypto()
    print(
        '\nasn1crypto: %s, %s' % (
            asn1crypto.__version__,
            os.path.dirname(asn1crypto.__file__)
        )
    )
    print(
        'oscrypto: %s backend, %s, %s' % (
            oscrypto.backend(),
            oscrypto.__version__,
            os.path.dirname(oscrypto.__file__)
        )
    )

    if run_lint:
        print('')
        lint_result = run_lint()
    else:
        lint_result = True

    if run_coverage:
        print('\nRunning tests (via coverage.py)')
        sys.stdout.flush()
        tests_result = run_coverage(ci=True)
    else:
        print('\nRunning tests')
        sys.stdout.flush()
        tests_result = run_tests(ci=True)
    sys.stdout.flush()

    return lint_result and tests_result
<|endoftext|>


<commit_before><commit_msg>add --action_group option to deploy_action.py<commit_after><|endoftext|>


<commit_before>from __future__ import absolute_import, division
import json
import re
from . import requests

_urls_to_objects = {}

class Linker(object):
	"""
	Responsible for on-demand loading of JSON objects.
	"""
	def __init__(self, url, parent=None, _requests=None):
		self.url = url
		self.__parent = parent
		self._requests = _requests or __import__('requests')

	def __call__(self, expand=None):
		def _object_hook(obj):
			if 'links' in obj:
				rv = JsonObject(obj)
				rv._requests = self._requests
				return rv
			else:
				return obj

		params = None
		if expand is not None:
			if isinstance(expand, basestring):
				params = {'expand': expand}
			else:
				params = {'expand': ','.join(expand)}

		rv = json.JSONDecoder(object_hook=_object_hook).decode(self._requests.get(self.url, params=params).text)
		rv._requests = self._requests
		if self.__parent is not None:
			rv.parent = self.__parent
		return rv

	def __repr__(self):
		return "<%s url=%r>" % (type(self).__name__, self.url)

class JsonObject(dict):
	"""
	Nice wrapper around the JSON objects and their links.
	"""
	def __getattr__(self, name):
		if name in self.get('links', {}):
			return Linker(self['links'][name], parent=self, _requests=self._requests)
		elif name in self:
			return self[name]
		else:
			raise AttributeError("%r object has no attribute %r" % (type(self).__name__, name))

	def save(self):
		return requests.put(self['links']['self']).json()

	def delete(self):
		return requests.delete(self['links']['self']).json()

class Room(JsonObject):
	def message(self, *p, **kw):
		"""
		Redirects to notification (for now)
		"""
		return self.notification(*p, **kw)

	def notification(self, message, color='yellow', notify=False, format='html'):
		raise NotImplementedError

	def topic(self, text):
		raise NotImplementedError

	def history(self, date='recent'):
		raise NotImplementedError

	def invite(self, user, reason):
		raise NotImplementedError

_urls_to_objects[re.compile(r'https://api.hipchat.com/v2/room/[^/]+')] = Room<commit_msg>Use subclasses when available<commit_after>from __future__ import absolute_import, division
import json
import re
from . import requests

_urls_to_objects = {}

class Linker(object):
	"""
	Responsible for on-demand loading of JSON objects.
	"""
	def __init__(self, url, parent=None, _requests=None):
		self.url = url
		self.__parent = parent
		self._requests = _requests or __import__('requests')

	def __call__(self, expand=None):
		def _object_hook(obj):
			if 'links' in obj:
				klass = JsonObject
				if 'self' in obj['links']:
					for p, c in _urls_to_objects.iteritems():
						if p.match(obj['links']['self']):
							klass = c
							break
				rv = klass(obj)
				rv._requests = self._requests
				return rv
			else:
				return obj

		params = None
		if expand is not None:
			if isinstance(expand, basestring):
				params = {'expand': expand}
			else:
				params = {'expand': ','.join(expand)}

		rv = json.JSONDecoder(object_hook=_object_hook).decode(self._requests.get(self.url, params=params).text)
		rv._requests = self._requests
		if self.__parent is not None:
			rv.parent = self.__parent
		return rv

	def __repr__(self):
		return "<%s url=%r>" % (type(self).__name__, self.url)

class JsonObject(dict):
	"""
	Nice wrapper around the JSON objects and their links.
	"""
	def __getattr__(self, name):
		if name in self.get('links', {}):
			return Linker(self['links'][name], parent=self, _requests=self._requests)
		elif name in self:
			return self[name]
		else:
			raise AttributeError("%r object has no attribute %r" % (type(self).__name__, name))

	def save(self):
		return requests.put(self['links']['self']).json()

	def delete(self):
		return requests.delete(self['links']['self']).json()

class Room(JsonObject):
	def message(self, *p, **kw):
		"""
		Redirects to notification (for now)
		"""
		return self.notification(*p, **kw)

	def notification(self, message, color='yellow', notify=False, format='html'):
		raise NotImplementedError

	def topic(self, text):
		raise NotImplementedError

	def history(self, date='recent'):
		raise NotImplementedError

	def invite(self, user, reason):
		raise NotImplementedError

_urls_to_objects[re.compile(r'https://api.hipchat.com/v2/room/[^/]+')] = Room<|endoftext|>