<commit_before>import sys

from attribute_converter import to_local
from saml2 import time_util
from saml2 import s_utils
from saml2.s_utils import OtherError

from saml2.validate import valid_instance
from saml2.validate import NotValid
from saml2.response import IncorrectlySigned

def _dummy(_arg):
    return None

class Request(object):
    def __init__(self, sec_context, receiver_addrs, log=None, timeslack=0,
                    debug=0):
        self.sec = sec_context
        self.receiver_addrs = receiver_addrs
        self.timeslack = timeslack
        self.log = log
        self.debug = debug
        if self.debug and not self.log:
            self.debug = 0

        self.xmlstr = ""
        self.name_id = ""
        self.message = None
        self.not_on_or_after = 0

        self.signature_check = _dummy # has to be set !!!

    def _clear(self):
        self.xmlstr = ""
        self.name_id = ""
        self.message = None
        self.not_on_or_after = 0

    def _loads(self, xmldata, decode=True):
        if decode:
            decoded_xml = s_utils.decode_base64_and_inflate(xmldata)
        else:
            decoded_xml = xmldata

        # own copy
        self.xmlstr = decoded_xml[:]
        if self.debug:
            self.log.info("xmlstr: %s" % (self.xmlstr,))
        try:
            self.message = self.signature_check(decoded_xml)
        except TypeError:
            raise
        except Exception, excp:
            if self.log:
                self.log.info("EXCEPTION: %s", excp)

        if not self.message:
            if self.log:
                self.log.error("Response was not correctly signed")
                self.log.info(decoded_xml)
            raise IncorrectlySigned()

        if self.debug:
            self.log.info("request: %s" % (self.message,))

        try:
            valid_instance(self.message)
        except NotValid, exc:
            if self.log:
                self.log.error("Not valid request: %s" % exc.args[0])
            else:
                print >> sys.stderr, "Not valid request: %s" % exc.args[0]
            raise

        return self

    def issue_instant_ok(self):
        """ Check that the request was issued at a reasonable time """
        upper = time_util.shift_time(time_util.time_in_a_while(days=1),
                                    self.timeslack).timetuple()
        lower = time_util.shift_time(time_util.time_a_while_ago(days=1),
                                    -self.timeslack).timetuple()
        # print "issue_instant: %s" % self.message.issue_instant
        # print "%s < x < %s" % (lower, upper)
        issued_at = time_util.str_to_time(self.message.issue_instant)
        return issued_at > lower and issued_at < upper

    def _verify(self):
        assert self.message.version == "2.0"
        if self.message.destination and \
            self.message.destination not in self.receiver_addrs:
            if self.log:
                self.log.error("%s != %s" % (self.message.destination,
                                                self.receiver_addrs))
            else:
                print >> sys.stderr, "%s != %s" % (self.message.destination,
                                                    self.receiver_addrs)
            raise OtherError("Not destined for me!")

        assert self.issue_instant_ok()
        return self

    def loads(self, xmldata, decode=True):
        return self._loads(xmldata, decode)

    def verify(self):
        try:
            return self._verify()
        except AssertionError:
            return None

    def subject_id(self):
        """ The name of the subject can be in either of
        BaseID, NameID or EncryptedID

        """

        if self.message.base_id:
            return self.message.base_id
        elif self.message.name_id:
            return self.message.name_id
        else: # EncryptedID
            pass

    def sender(self):
        return self.message.issuer.text()

class LogoutRequest(Request):
    def __init__(self, sec_context, receiver_addrs, log=None, timeslack=0,
                    debug=0):
        Request.__init__(self, sec_context, receiver_addrs, log, timeslack,
                            debug)
        self.signature_check = self.sec.correctly_signed_logout_request

class AttributeQuery(Request):
    def __init__(self, sec_context, receiver_addrs, log=None, timeslack=0,
                    debug=0):
        Request.__init__(self, sec_context, receiver_addrs, log, timeslack,
                            debug)
        self.signature_check = self.sec.correctly_signed_attribute_query

    def attribute(self):
        """ Which attributes that are sought for """

        return []

class AuthnRequest(Request):
    def __init__(self, sec_context, attribute_converters, receiver_addrs,
                    log=None, timeslack=0, debug=0):
        Request.__init__(self, sec_context, receiver_addrs, log, timeslack,
                            debug)
        self.attribute_converters = attribute_converters
        self.signature_check = self.sec.correctly_signed_authn_request

    def attributes(self):
        return to_local(self.attribute_converters, self.message)

<commit_msg>Adding PDP support<commit_after>import sys

from attribute_converter import to_local
from saml2 import time_util
from saml2 import s_utils
from saml2.s_utils import OtherError

from saml2.validate import valid_instance
from saml2.validate import NotValid
from saml2.response import IncorrectlySigned

def _dummy(_arg):
    return None

class Request(object):
    def __init__(self, sec_context, receiver_addrs, log=None, timeslack=0,
                    debug=0):
        self.sec = sec_context
        self.receiver_addrs = receiver_addrs
        self.timeslack = timeslack
        self.log = log
        self.debug = debug
        if self.debug and not self.log:
            self.debug = 0

        self.xmlstr = ""
        self.name_id = ""
        self.message = None
        self.not_on_or_after = 0

        self.signature_check = _dummy # has to be set !!!

    def _clear(self):
        self.xmlstr = ""
        self.name_id = ""
        self.message = None
        self.not_on_or_after = 0

    def _loads(self, xmldata, decode=True):
        if decode:
            decoded_xml = s_utils.decode_base64_and_inflate(xmldata)
        else:
            decoded_xml = xmldata

        # own copy
        self.xmlstr = decoded_xml[:]
        if self.debug:
            self.log.info("xmlstr: %s" % (self.xmlstr,))
        try:
            self.message = self.signature_check(decoded_xml)
        except TypeError:
            raise
        except Exception, excp:
            if self.log:
                self.log.info("EXCEPTION: %s", excp)

        if not self.message:
            if self.log:
                self.log.error("Response was not correctly signed")
                self.log.info(decoded_xml)
            raise IncorrectlySigned()

        if self.debug:
            self.log.info("request: %s" % (self.message,))

        try:
            valid_instance(self.message)
        except NotValid, exc:
            if self.log:
                self.log.error("Not valid request: %s" % exc.args[0])
            else:
                print >> sys.stderr, "Not valid request: %s" % exc.args[0]
            raise

        return self

    def issue_instant_ok(self):
        """ Check that the request was issued at a reasonable time """
        upper = time_util.shift_time(time_util.time_in_a_while(days=1),
                                    self.timeslack).timetuple()
        lower = time_util.shift_time(time_util.time_a_while_ago(days=1),
                                    -self.timeslack).timetuple()
        # print "issue_instant: %s" % self.message.issue_instant
        # print "%s < x < %s" % (lower, upper)
        issued_at = time_util.str_to_time(self.message.issue_instant)
        return issued_at > lower and issued_at < upper

    def _verify(self):
        assert self.message.version == "2.0"
        if self.message.destination and \
            self.message.destination not in self.receiver_addrs:
            if self.log:
                self.log.error("%s != %s" % (self.message.destination,
                                                self.receiver_addrs))
            else:
                print >> sys.stderr, "%s != %s" % (self.message.destination,
                                                    self.receiver_addrs)
            raise OtherError("Not destined for me!")

        assert self.issue_instant_ok()
        return self

    def loads(self, xmldata, decode=True):
        return self._loads(xmldata, decode)

    def verify(self):
        try:
            return self._verify()
        except AssertionError:
            return None

    def subject_id(self):
        """ The name of the subject can be in either of
        BaseID, NameID or EncryptedID

        :return: The identifier if there is one
        """

        if self.message.base_id:
            return self.message.base_id
        elif self.message.name_id:
            return self.message.name_id
        else: # EncryptedID
            pass

    def sender(self):
        return self.message.issuer.text()

class LogoutRequest(Request):
    def __init__(self, sec_context, receiver_addrs, log=None, timeslack=0,
                    debug=0):
        Request.__init__(self, sec_context, receiver_addrs, log, timeslack,
                            debug)
        self.signature_check = self.sec.correctly_signed_logout_request

class AttributeQuery(Request):
    def __init__(self, sec_context, receiver_addrs, log=None, timeslack=0,
                    debug=0):
        Request.__init__(self, sec_context, receiver_addrs, log, timeslack,
                            debug)
        self.signature_check = self.sec.correctly_signed_attribute_query

    def attribute(self):
        """ Which attributes that are sought for """

        return []

class AuthnRequest(Request):
    def __init__(self, sec_context, attribute_converters, receiver_addrs,
                    log=None, timeslack=0, debug=0):
        Request.__init__(self, sec_context, receiver_addrs, log, timeslack,
                            debug)
        self.attribute_converters = attribute_converters
        self.signature_check = self.sec.correctly_signed_authn_request

    def attributes(self):
        return to_local(self.attribute_converters, self.message)

class AuthzRequest(Request):
    def __init__(self, sec_context, receiver_addrs, log=None, timeslack=0,
                    debug=0):
        Request.__init__(self, sec_context, receiver_addrs, log, timeslack,
                            debug)
        self.signature_check = self.sec.correctly_signed_logout_request

    def action(self):
        """ Which action authorization is requested for """
        pass

    def evidence(self):
        """ The evidence on which the decision is based """
        pass

    def resource(self):
        """ On which resource the action is expected to occur """
        pass<|endoftext|>


<commit_before>#!/usr/bin/env python
#==============================================================================
#Name:      OpsServerConfig.py
#Purpose:   Sets various variables used by other installation scripts.
#
#History:   Fixed CR 239,138 08/03/2012 - "Modify OpsServerConfig.py script to
#               automatically obtain the fully qualified domain name of the
#               server." Replaced "platform" module with "socket" module, and
#               used getfqdn and gethostname functions.
#
#           Fixed CR 239,142 "Alter default value for "sharing" variables.
#               Change to False."
#==============================================================================
import os
import socket
from Utilities import makePath

valid_ops_types = ['All', 'Land', 'Maritime', 'Intel', 'Air', 'NG']

# ----------------------------------------------------------------------------
# Server name/domain/port related information

# Get server name without domain, i.e. mymachine
serverName = socket.gethostname().lower()

# Get server name with domain, i.e. mymachine.esri.com
serverFullyQualifiedDomainName = socket.getfqdn().lower()

# Get domain name, i.e. esri.com
serverDomain = serverFullyQualifiedDomainName.replace(serverName, "")[1:]

# Set ArcGIS Server port number
serverPort = 6080

serverDrive = 'c'       # Drive where software will be installed

# ----------------------------------------------------------------------------
# "Name of database": True/False - Flag indicating whether database
#   will be registered with ArcGIS Server as managed.
# Also SDE connection files will be created for all databases not registered
# as managed.
# NOTE: only one database should be registered as managed

# Syntax: ["databasename": [Managed (True or False), AGS registration name]
# 'AGS registration name' is "label" given to the data store.
databasesToCreate = {"operations":[False,"Operations"], \
                    "utds":[False, "UTDS"], \
                    "economic":[False, "Economic"], \
                    "imagery":[False, "Imagery"], \
                    "infrastructure":[False, "Infrastructure"], \
                    "physical":[False, "Physical"], \
                    "political":[False, "Political"], \
                    "social":[False, "Social"], \
                    "rtds":[False, "RTDS"], \
                    "currentoperations":[False, "CurrentOperations"], \
                    "military":[False, "Military"], \
                    "information":[False, "Information"], \
                    "workflow":[False, "Workflow"], \
                    "emergencymanagement":[False, "EmergencyManagement"]}

# ----------------------------------------------------------------------------
# Shared / Replicated Database Configuration
#
# Set with database configuration used during publishing.
# Set to True if you want to use shared configuration (i.e
# publisher databases and ArcGIS Server databases are the same );
# Set to False if you want to use a replicated configuration
# (i.e. publisher database is different then the ArcGIS
# Server database)
sharedDataStoreConfig = True

# Set following variable to which server containing the
# publisher database. Variable only used when
# variable "sharedDBConfigForPublishing" = False
publishingDBServer = "afmcomstaging"
publishingFolder = r"\\disldb\development\Commercial\OPSServer\LandOps\Server\Staging\Data"

# 'Registration Name' for data folder data store
dataFolderDStoreName = "OpsServerData"

# 'Publishing' path for temporary folder data stores
#installOnlyPublishingFolders = {dataFolderDStoreName: r"\\afmiedev\data"}

# Key is name of server where data folder is located; Value is path to "data" folder
installOnlyPublishingFolders = {"afmiedev": r"\\afmiedev\data", "afmcomstaging": r"\\afmcomstaging\data"}

# 'Publishing' server names for temporary database data stores
installOnlyPublishingDBServers = ["afmiedevdb", "afmcomstaging"]

# ----------------------------------------------------------------------------
# Set root path variables/root path functions

def getPostgreSQLRootPath():
    try:
        postgreSQLRootPath = os.environ['ops_postgresqlInstallDIR']
        return postgreSQLRootPath
    except KeyError, e:
        return None

def getOpsServerRootPath(dataDrive):
    return makePath(dataDrive, ["OpsServer"])

def getEnvDataRootPath(dataDrive):
    opsServerRootPath = getOpsServerRootPath(dataDrive)
    return os.path.join(opsServerRootPath, *["Data"])

def getDBConnFileRootPath(dataDrive):
    opsServerRootPath = getOpsServerRootPath(dataDrive)
    return os.path.join(opsServerRootPath, *["DBConnections"])

def getCacheRootPath(cacheDrive):
    return makePath(cacheDrive, ["arcgisserver", "directories", "arcgiscache"])

# ----------------------------------------------------------------------------
# Other functions

def validateOpsTypes(specified_ops_types):

    is_valid = True
    values_to_use = []
    ops_type_all = "all"

    # Create copy of valid value list (so we can alter values) and convert to lower case
    valid_values = [element.lower().strip() for element in list(valid_ops_types)]

    # Convert user specified list of ops types to list and convert
    # to lower case and remove any leading or trailing "whitespace"
    # this handles cases where user entered spaces between
    # values i.e. "Land, Maritime".
    specified_values = [element.lower().strip() for element in specified_ops_types.split(",")]

    #print "specified_values: " + str(specified_values)

    # If user specified "all" then return list containing only this value
    if ops_type_all.lower() in specified_values:
        #values_to_use.append(ops_type_all.lower())
        values_to_use = list(valid_ops_types)
        #print "values_to_use:  " + str(values_to_use)
        return True, values_to_use

    # Check if user specified valid ops types
    for ops_type in specified_values:
        if ops_type not in valid_values:
            return False, values_to_use
        values_to_use.append(ops_type)

    # If the user has specified at least one valid value then add "all" to list
    # so that the load function will publish items that have the "all" to addition
    # to the items with the other tags specified.
    if len(values_to_use) > 0:
        values_to_use.append(ops_type_all)

    return is_valid, values_to_use

def hasOpsTypeTags(find_tags, tags_to_search):
    '''Determines if specific "OpsServer" values exist in list of tags'''
    found = False

    DEBUG = False

    # Create list of possible "OpsServer" type tag prefixes; i.e. in case someone didn't
    # specify the correct prefix.
    ops_type_flags = ["opsserver", "opsservers", "opserver", "opservers", "opssrver", "opssrvr"]

    # Convert find_tags to lower case and remove and leading/trailing spaces
    find_tags_mod = [element.lower().strip().encode("ascii") for element in list(find_tags)]

    # Convert tags_to_search to lower case and remove and leading/trailing spaces
    tags_to_search_mod = [element.lower().strip().encode("ascii") for element in list(tags_to_search)]

    if DEBUG:
        print "In tags_exist function: "
        print "\tfind_tags_mod: " + str(find_tags_mod)
        print "\ttags_to_search_mod: " + str(tags_to_search_mod)
        print "\tops_type_flags: " + str(ops_type_flags)

    # Loop through tags to search and look for the find tags
    for search in tags_to_search_mod:
        search = search.replace(" ","")

        if DEBUG:
            print "\tsearch: " + search

        if search.find(":") > -1:

            if DEBUG:
                print "\tI'm in the find : if statement"

            element1 = search.split(":")[0]
            element2 = search.split(":")[1]

            if DEBUG:
                print "\t\telement1: " + element1
                print "\t\telement2: " + element2

            if element1 in ops_type_flags:
                if element2 in find_tags_mod:
                    found = True

    if DEBUG:
        print "\tfound: " + str(found)

    return found<commit_msg>Resolved #535<commit_after>#!/usr/bin/env python
#==============================================================================
#Name:      OpsServerConfig.py
#Purpose:   Sets various variables used by other installation scripts.
#
#History:   Fixed CR 239,138 08/03/2012 - "Modify OpsServerConfig.py script to
#               automatically obtain the fully qualified domain name of the
#               server." Replaced "platform" module with "socket" module, and
#               used getfqdn and gethostname functions.
#
#           Fixed CR 239,142 "Alter default value for "sharing" variables.
#               Change to False."
#==============================================================================
import os
import socket
from Utilities import makePath

valid_ops_types = ['All', 'Land', 'Maritime', 'Intel', 'Air', 'NG']

# ----------------------------------------------------------------------------
# Server name/domain/port related information

# Get server name without domain, i.e. mymachine
serverName = socket.gethostname().lower()

# Get server name with domain, i.e. mymachine.esri.com
serverFullyQualifiedDomainName = socket.getfqdn().lower()

# Get domain name, i.e. esri.com
serverDomain = serverFullyQualifiedDomainName.replace(serverName, "")[1:]

# Set ArcGIS Server port number
serverPort = 6080

serverDrive = 'c'       # Drive where software will be installed

# ----------------------------------------------------------------------------
# "Name of database": True/False - Flag indicating whether database
#   will be registered with ArcGIS Server as managed.
# Also SDE connection files will be created for all databases not registered
# as managed.
# NOTE: only one database should be registered as managed

# Syntax: ["databasename": [Managed (True or False), AGS registration name]
# 'AGS registration name' is "label" given to the data store.
databasesToCreate = {"utds":[False, "UTDS"], \
                    "economic":[False, "Economic"], \
                    "infrastructure":[False, "Infrastructure"], \
                    "political":[False, "Political"], \
                    "social":[False, "Social"], \
                    "rtds":[False, "RTDS"], \
                    "currentoperations":[False, "CurrentOperations"], \
                    "military":[False, "Military"], \
                    "information":[False, "Information"], \
                    "emergencymanagement":[False, "EmergencyManagement"]}

#databasesToCreate = {"operations":[False,"Operations"], \
#                    "utds":[False, "UTDS"], \
#                    "economic":[False, "Economic"], \
#                    "imagery":[False, "Imagery"], \
#                    "infrastructure":[False, "Infrastructure"], \
#                    "physical":[False, "Physical"], \
#                    "political":[False, "Political"], \
#                    "social":[False, "Social"], \
#                    "rtds":[False, "RTDS"], \
#                    "currentoperations":[False, "CurrentOperations"], \
#                    "military":[False, "Military"], \
#                    "information":[False, "Information"], \
#                    "workflow":[False, "Workflow"], \
#                    "emergencymanagement":[False, "EmergencyManagement"]}

# ----------------------------------------------------------------------------
# Shared / Replicated Database Configuration
#
# Set with database configuration used during publishing.
# Set to True if you want to use shared configuration (i.e
# publisher databases and ArcGIS Server databases are the same );
# Set to False if you want to use a replicated configuration
# (i.e. publisher database is different then the ArcGIS
# Server database)
sharedDataStoreConfig = True

# Set following variable to which server containing the
# publisher database. Variable only used when
# variable "sharedDBConfigForPublishing" = False
publishingDBServer = "afmcomstaging"
publishingFolder = r"\\disldb\development\Commercial\OPSServer\LandOps\Server\Staging\Data"

# 'Registration Name' for data folder data store
dataFolderDStoreName = "OpsServerData"

# 'Publishing' path for temporary folder data stores
#installOnlyPublishingFolders = {dataFolderDStoreName: r"\\afmiedev\data"}

# Key is name of server where data folder is located; Value is path to "data" folder
installOnlyPublishingFolders = {"afmiedev": r"\\afmiedev\data", "afmcomstaging": r"\\afmcomstaging\data"}

# 'Publishing' server names for temporary database data stores
installOnlyPublishingDBServers = ["afmiedevdb", "afmcomstaging"]

# ----------------------------------------------------------------------------
# Set root path variables/root path functions

def getPostgreSQLRootPath():
    try:
        postgreSQLRootPath = os.environ['ops_postgresqlInstallDIR']
        return postgreSQLRootPath
    except KeyError, e:
        return None

def getOpsServerRootPath(dataDrive):
    return makePath(dataDrive, ["OpsServer"])

def getEnvDataRootPath(dataDrive):
    opsServerRootPath = getOpsServerRootPath(dataDrive)
    return os.path.join(opsServerRootPath, *["Data"])

def getDBConnFileRootPath(dataDrive):
    opsServerRootPath = getOpsServerRootPath(dataDrive)
    return os.path.join(opsServerRootPath, *["DBConnections"])

def getCacheRootPath(cacheDrive):
    return makePath(cacheDrive, ["arcgisserver", "directories", "arcgiscache"])

# ----------------------------------------------------------------------------
# Other functions

def validateOpsTypes(specified_ops_types):

    is_valid = True
    values_to_use = []
    ops_type_all = "all"

    # Create copy of valid value list (so we can alter values) and convert to lower case
    valid_values = [element.lower().strip() for element in list(valid_ops_types)]

    # Convert user specified list of ops types to list and convert
    # to lower case and remove any leading or trailing "whitespace"
    # this handles cases where user entered spaces between
    # values i.e. "Land, Maritime".
    specified_values = [element.lower().strip() for element in specified_ops_types.split(",")]

    #print "specified_values: " + str(specified_values)

    # If user specified "all" then return list containing only this value
    if ops_type_all.lower() in specified_values:
        #values_to_use.append(ops_type_all.lower())
        values_to_use = list(valid_ops_types)
        #print "values_to_use:  " + str(values_to_use)
        return True, values_to_use

    # Check if user specified valid ops types
    for ops_type in specified_values:
        if ops_type not in valid_values:
            return False, values_to_use
        values_to_use.append(ops_type)

    # If the user has specified at least one valid value then add "all" to list
    # so that the load function will publish items that have the "all" to addition
    # to the items with the other tags specified.
    if len(values_to_use) > 0:
        values_to_use.append(ops_type_all)

    return is_valid, values_to_use

def hasOpsTypeTags(find_tags, tags_to_search):
    '''Determines if specific "OpsServer" values exist in list of tags'''
    found = False

    DEBUG = False

    # Create list of possible "OpsServer" type tag prefixes; i.e. in case someone didn't
    # specify the correct prefix.
    ops_type_flags = ["opsserver", "opsservers", "opserver", "opservers", "opssrver", "opssrvr"]

    # Convert find_tags to lower case and remove and leading/trailing spaces
    find_tags_mod = [element.lower().strip().encode("ascii") for element in list(find_tags)]

    # Convert tags_to_search to lower case and remove and leading/trailing spaces
    tags_to_search_mod = [element.lower().strip().encode("ascii") for element in list(tags_to_search)]

    if DEBUG:
        print "In tags_exist function: "
        print "\tfind_tags_mod: " + str(find_tags_mod)
        print "\ttags_to_search_mod: " + str(tags_to_search_mod)
        print "\tops_type_flags: " + str(ops_type_flags)

    # Loop through tags to search and look for the find tags
    for search in tags_to_search_mod:
        search = search.replace(" ","")

        if DEBUG:
            print "\tsearch: " + search

        if search.find(":") > -1:

            if DEBUG:
                print "\tI'm in the find : if statement"

            element1 = search.split(":")[0]
            element2 = search.split(":")[1]

            if DEBUG:
                print "\t\telement1: " + element1
                print "\t\telement2: " + element2

            if element1 in ops_type_flags:
                if element2 in find_tags_mod:
                    found = True

    if DEBUG:
        print "\tfound: " + str(found)

    return found<|endoftext|>


<commit_before>import matplotlib.pyplot as plt

def visit_cluster(tree, labels, xticks, counter = 0):
    if isinstance(tree[0], tuple):
        (blx, bly) = visit_cluster(tree[0], labels, xticks)
    else:
        (blx, bly) = (0, len(labels))
        labels.append(tree[0])
    if isinstance(tree[1], tuple):
        (brx, bry) = visit_cluster(tree[1], labels, xticks)
    else:
        (brx, bry) = (0, len(labels))
        labels.append(tree[1])

    (ulx, uly) = (tree[2], bly)
    (urx, ury) = (tree[2], bry)

    plt.plot([blx, ulx, urx, brx], [bly, uly, ury, bry], "k")

    xticks.append(tree[2])

    return (tree[2], (bly + bry) / 2)

# tree = (((A, B, dist), C, dist), ...)
def plot(tree):
    labels = []
    xticks = [0]

    visit_cluster(tree, labels, xticks)

    plt.yticks(list(range(len(labels))), labels)
    plt.xlim(0, max(xticks) + 1)
    plt.xticks(xticks)

    plt.show()<commit_msg>Prettier dendrogram plot<commit_after>import matplotlib.pyplot as plt
from matplotlib.ticker import MultipleLocator

linewidth = 1.5
xoffset = 0.5
color = "k"
xgrid = False

def visit_cluster(tree, labels, xticks, counter = 0):
    if isinstance(tree[0], tuple):
        (blx, bly) = visit_cluster(tree[0], labels, xticks)
    else:
        (blx, bly) = (0, len(labels))
        labels.append(tree[0])
    if isinstance(tree[1], tuple):
        (brx, bry) = visit_cluster(tree[1], labels, xticks)
    else:
        (brx, bry) = (0, len(labels))
        labels.append(tree[1])

    (ulx, uly) = (tree[2], bly)
    (urx, ury) = (tree[2], bry)

    plt.plot(
        [blx, ulx, urx, brx],
        [bly, uly, ury, bry],
        color,
        linewidth = linewidth)

    xticks.append(tree[2])

    return (tree[2], (bly + bry) / 2)

# tree = (((A, B, dist), C, dist), ...)
def plot(tree):
    labels = []
    xticks = [0]

    fig, ax = plt.subplots()

    visit_cluster(tree, labels, xticks)

    ml = MultipleLocator(xoffset)
    ax.set_yticks(list(range(len(labels))))
    ax.set_yticklabels(labels)
    ax.set_xlim(0, max(xticks) + xoffset)
    ax.set_xticks(xticks)
    ax.xaxis.set_minor_locator(ml)
    ax.yaxis.set_tick_params(width = linewidth)

    if xgrid:
        ax.xaxis.grid()

    fig.show()

    return fig<|endoftext|>


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

from oslo_config import cfg
from oslo_db.sqlalchemy import enginefacade
from oslo_log import log as logging

LOG = logging.getLogger(__name__)

context_manager = enginefacade.transaction_context()

_FACADE = None

def _create_facade_lazily():
    global _FACADE

    if _FACADE is None:
        context_manager.configure(sqlite_fk=True, **cfg.CONF.database)
        _FACADE = context_manager._factory.get_legacy_facade()

    return _FACADE

def get_engine():
    """Helper method to grab engine."""
    facade = _create_facade_lazily()
    return facade.get_engine()

def get_session(autocommit=True, expire_on_commit=False):
    """Helper method to grab session."""
    facade = _create_facade_lazily()
    return facade.get_session(autocommit=autocommit,
                              expire_on_commit=expire_on_commit)
<commit_msg>Remove unused LOG to keep code clean<commit_after># Copyright 2011 VMware, Inc.
# All Rights Reserved.
#
#    Licensed under the Apache License, Version 2.0 (the "License"); you may
#    not use this file except in compliance with the License. You may obtain
#    a copy of the License at
#
#         http://www.apache.org/licenses/LICENSE-2.0
#
#    Unless required by applicable law or agreed to in writing, software
#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
#    License for the specific language governing permissions and limitations
#    under the License.

from oslo_config import cfg
from oslo_db.sqlalchemy import enginefacade

context_manager = enginefacade.transaction_context()

_FACADE = None

def _create_facade_lazily():
    global _FACADE

    if _FACADE is None:
        context_manager.configure(sqlite_fk=True, **cfg.CONF.database)
        _FACADE = context_manager._factory.get_legacy_facade()

    return _FACADE

def get_engine():
    """Helper method to grab engine."""
    facade = _create_facade_lazily()
    return facade.get_engine()

def get_session(autocommit=True, expire_on_commit=False):
    """Helper method to grab session."""
    facade = _create_facade_lazily()
    return facade.get_session(autocommit=autocommit,
                              expire_on_commit=expire_on_commit)
<|endoftext|>


<commit_before># -*- coding: utf-8 -*-
import datetime
import json
from flask_sqlalchemy import SQLAlchemy
from sqlalchemy import Column, Integer, String, Boolean, ForeignKey, Float, \
    Enum, DateTime, Numeric, Text, Unicode, UnicodeText
from sqlalchemy import event
from sqlalchemy.sql import func
from sqlalchemy.orm import relationship, backref
from sqlalchemy_i18n import make_translatable, translation_base, Translatable

make_translatable(options={'locales': ['pt', 'en', 'es'],
                           'auto_create_locales': True,
                           'fallback_locale': 'en'})

db = SQLAlchemy()

# noinspection PyClassHasNoInit
class OperationType:
    ACTION = 'ACTION'
    VISUALIZATION = 'VISUALIZATION'
    SHUFFLE = 'SHUFFLE'
    TRANSFORMATION = 'TRANSFORMATION'

    @staticmethod
    def values():
        return [n for n in OperationType.__dict__.keys()
                if n[0] != '_' and n != 'values']

# noinspection PyClassHasNoInit
class OperationPortType:
    INPUT = 'INPUT'
    OUTPUT = 'OUTPUT'

    @staticmethod
    def values():
        return [n for n in OperationPortType.__dict__.keys()
                if n[0] != '_' and n != 'values']

# noinspection PyClassHasNoInit
class OperationPortMultiplicity:
    MANY = 'MANY'
    ONE = 'ONE'

    @staticmethod
    def values():
        return [n for n in OperationPortMultiplicity.__dict__.keys()
                if n[0] != '_' and n != 'values']

# noinspection PyClassHasNoInit
class ApplicationType:
    SPARK_APPLICATION = 'SPARK_APPLICATION'
    SPARK_CODE_FUNCTION = 'SPARK_CODE_FUNCTION'

    @staticmethod
    def values():
        return [n for n in ApplicationType.__dict__.keys()
                if n[0] != '_' and n != 'values']

# noinspection PyClassHasNoInit
class OperationFieldScope:
    BOTH = 'BOTH'
    EXECUTION = 'EXECUTION'
    DESIGN = 'DESIGN'

    @staticmethod
    def values():
        return [n for n in OperationFieldScope.__dict__.keys()
                if n[0] != '_' and n != 'values']

# noinspection PyClassHasNoInit
class DataType:
    FLOAT = 'FLOAT'
    LAT_LONG = 'LAT_LONG'
    TIME = 'TIME'
    DOUBLE = 'DOUBLE'
    DECIMAL = 'DECIMAL'
    ENUM = 'ENUM'
    CHARACTER = 'CHARACTER'
    LONG = 'LONG'
    DATETIME = 'DATETIME'
    VECTOR = 'VECTOR'
    TEXT = 'TEXT'
    DATE = 'DATE'
    INTEGER = 'INTEGER'
    TIMESTAMP = 'TIMESTAMP'

    @staticmethod
    def values():
        return [n for n in DataType.__dict__.keys()
                if n[0] != '_' and n != 'values']

# noinspection PyClassHasNoInit
class OperationUiCodeType:
    ATTRIBUTE_LIST = 'ATTRIBUTE_LIST'

    @staticmethod
    def values():
        return [n for n in OperationUiCodeType.__dict__.keys()
                if n[0] != '_' and n != 'values']

class Application(db.Model):
    """ Any external application that can be ran by Juicer """
    __tablename__ = 'application'

    # Fields
    id = Column(Integer, primary_key=True)
    name = Column(String(200), nullable=False)
    description = Column(String(200), nullable=False)
    enabled = Column(Boolean,
                     default=True, nullable=False)
    type = Column(Enum(*ApplicationType.values(),
                       name='ApplicationTypeEnumType'), nullable=False)
    execution_parameters = Column(Text)
    __mapper_args__ = {
        'order_by': 'name'
    }

    def __unicode__(self):
        return self.name

    def __repr__(self):
        return '<Instance {}: {}>'.format(self.__class__, self.id)

class Flow(db.Model):
    """ Flow of data between two tasks in Lemonade """
    __tablename__ = 'flow'

    # Fields
    id = Column(Integer, primary_key=True)
    source_port = Column(Integer, nullable=False)
    target_port = Column(Integer, nullable=False)
    source_port_name = Column(String(200), nullable=False)
    target_port_name = Column(String(200), nullable=False)

    # Associations
    source_id = Column(String(250),
                       ForeignKey("task.id"), nullable=False)
    source = relationship("Task", foreign_keys=[source_id],
                          backref=backref(
                              "sources",
                              cascade="all, delete-orphan"))
    target_id = Column(String(250),
                       ForeignKey("task.id"), nullable=False)
    target = relationship("Task", foreign_keys=[target_id],
                          backref=backref(
                              "targets",
                              cascade="all, delete-orphan"))
    workflow_id = Column(Integer,
                         ForeignKey("workflow.id"), nullable=False)
    workflow = relationship("Workflow", foreign_keys=[workflow_id],
                            backref=backref(
                                "flows",
                                cascade="all, delete-orphan"))

    def __unicode__(self):
        return self.source_port

    def __repr__(self):
        return '<Instance {}: {}>'.format(self.__class__, self.id)

class Operation(db.Model, Translatable):
    """ Operation executed in Lemonade """
    __tablename__ = 'operation'
    __translatable__ = {'locales': ['pt', 'en', 'es']}

    # Fields
    id = Column(Integer, primary_key=True)
    slug = Column(String(200), nullable=False)
    enabled = Column(Boolean, nullable=False)
    type = Column(Enum(*OperationType.values(),
                       name='OperationTypeEnumType'), nullable=False)
    icon = Column(String(200), nullable=False)

    # Associations
    # noinspection PyUnresolvedReferences
    operation_category_operation = db.Table(
        'operation_category_operation',
        Column('operation_id', Integer, ForeignKey('operation.id')),
        Column('operation_category_id', Integer, ForeignKey('operation_category.id')))
    categories = relationship(
        "OperationCategory",
        secondary=operation_category_operation)
    # noinspection PyUnresolvedReferences
    operation_platform = db.Table(
        'operation_platform',
        Column('operation_id', Integer, ForeignKey('operation.id')),
        Column('platform_id', Integer, ForeignKey('platform.id')))
    platforms = relationship(
        "Platform",
        secondary=operation_platform,
        secondaryjoin=("and_("
                       "Platform.id==operation_platform.platform_id,"
                       "Platform.enabled==1)"))
    # noinspection PyUnresolvedReferences
    operation_operation_form = db.Table(
        'operation_operation_form',
        Column('operation_id', Integer, ForeignKey('operation.id')),
        Column('operation_form_id', Integer, ForeignKey('operation_form.id')))
    forms = relationship(
        "OperationForm",
        secondary=operation_operation_form,
        secondaryjoin=("and_("
                       "OperationForm.id==operation_operation_form.operation_form_id,"
                       "OperationForm.enabled==1)"))
    ports = relationship("OperationPort", back_populates="operation")

    def __unicode__(self):
        return self.name

    def __repr__(self):
        return '<Instance {}: {}>'.format(self.__class__, self.id)

class OperationTranslation(translation_base(Operation)):
    """ Translation table for Operation """
    __tablename__ = 'operation_translation'

    # Fields
    name = Column(Unicode(200))
    description = Column(Unicode(200))

class OperationCategory(db.Model, Translatable):
    """ Allows categorize operations """
    __tablename__ = 'operation_category'
    __translatable__ = {'locales': ['pt', 'en', 'es']}

    # Fields
    id = Column(Integer, primary_key=True)
    type = Column(String(200), nullable=False)

    def __unicode__(self):
        return self.name

    def __repr__(self):
        return '<Instance {}: {}>'.format(self.__class__, self.id)

class OperationCategoryTranslation(translation_base(OperationCategory)):
    """ Translation table for OperationCategory """
    __tablename__ = 'operation_category_translation'

    # Fields
    name = Column(Unicode(200))

class OperationForm(db.Model, Translatable):
    """ A form used to fill parameters to the operations """
    __tablename__ = 'operation_form'
    __translatable__ = {'locales': ['pt', 'en', 'es']}

    # Fields
    id = Column(Integer, primary_key=True)
    enabled = Column(Boolean,
                     default=True, nullable=False)
    order = Column(Integer, nullable=False)
    category = Column(String(200), nullable=False)
    __mapper_args__ = {
        'order_by': 'order'
    }

    # Associations
    fields = relationship("OperationFormField",
                          order_by="OperationFormField.order")

    def __unicode__(self):
        return self.name

    def __repr__(self):
        return '<Instance {}: {}>'.format(self.__class__, self.id)

class OperationFormTranslation(translation_base(OperationForm)):
    """ Translation table for OperationForm """
    __tablename__ = 'operation_form_translation'

    # Fields
    name = Column(Unicode(200))

class OperationFormField(db.Model, Translatable):
    """ A field used to fill one parameter of a form for an operations """
    __tablename__ = 'operation_form_field'
    __translatable__ = {'locales': ['pt', 'en', 'es']}

    # Fields
    id = Column(Integer, primary_key=True)
    name = Column(String(200), nullable=False)
    type = Column(Enum(*DataType.values(),
                       name='DataTypeEnumType'), nullable=False)
    required = Column(Boolean, nullable=False)
    order = Column(Integer, nullable=False)
    default = Column(Text)
    suggested_widget = Column(String(200))
    values_url = Column(String(200))
    values = Column(Text)
    scope = Column(Enum(*OperationFieldScope.values(),
                        name='OperationFieldScopeEnumType'), nullable=False)
    __mapper_args__ = {
        'order_by': 'order'
    }

    # Associations
    form_id = Column(Integer,
                     ForeignKey("operation_form.id"), nullable=False)
    form = relationship("OperationForm", foreign_keys=[form_id])

    def __unicode__(self):
        return self.name

    def __repr__(self):
        return '<Instance {}: {}>'.format(self.__class__, self.id)

class OperationFormFieldTranslation(translation_base(OperationFormField)):
    """ Translation table for OperationFormField """
    __tablename__ = 'operation_form_field_translation'

    # Fields
    label = Column(Unicode(200))
    help = Column(UnicodeText())

class OperationPort(db.Model, Translatable):
    """ An input or output port for operation """
    __tablename__ = 'operation_port'
    __translatable__ = {'locales': ['pt', 'en', 'es']}

    # Fields
    id = Column(Integer, primary_key=True)
    type = Column(Enum(*OperationPortType.values(),
                       name='OperationPortTypeEnumType'), nullable=False)
    tags = Column(Text)
    order = Column(Integer)
    multiplicity = Column(Enum(*OperationPortMultiplicity.values(),
                               name='OperationPortMultiplicityEnumType'),
                          default=1, nullable=False)
    __mapper_args__ = {
        'order_by': 'order'
    }

    # Associations
    # noinspection PyUnresolvedReferences
    operation_port_interface_operation_port = db.Table(
        'operation_port_interface_operation_port',
        Column('operation_port_id', Integer, ForeignKey('operation_port.id')),
        Column('operation_port_interface_id', Integer, ForeignKey('operation_port_interface.id')))
    interfaces = relationship(
        "OperationPortInterface",
        secondary=operation_port_interface_operation_port)
    operation_id = Column(Integer,
                          ForeignKey("operation.id"), nullable=False)
    operation = relationship("Operation", foreign_keys=[operation_id])

    def __unicode__(self):
        return self.name

    def __repr__(self):
        return '<Instance {}: {}>'.format(self.__class__, self.id)

class OperationPortTranslation(translation_base(OperationPort)):
    """ Translation table for OperationPort """
    __tablename__ = 'operation_port_translation'

    # Fields
    name = Column(Unicode(200))
    description = Column(Unicode(200))

class OperationPortInterface(db.Model, Translatable):
    """ An interface that a operation port supports """
    __tablename__ = 'operation_port_interface'
    __translatable__ = {'locales': ['pt', 'en', 'es']}

    # Fields
    id = Column(Integer, primary_key=True)
    color = Column(String(50), nullable=False)

    def __unicode__(self):
        return self.name

    def __repr__(self):
        return '<Instance {}: {}>'.format(self.__class__, self.id)

class OperationPortInterfaceTranslation(
        translation_base(OperationPortInterface)):
    """ Translation table for OperationPortInterface """
    __tablename__ = 'operation_port_interface_translation'

    # Fields
    name = Column(Unicode(200))

class OperationUiCode(db.Model):
    """ Associated UI code """
    __tablename__ = 'operation_ui_code'

    # Fields
    id = Column(Integer, primary_key=True)
    type = Column(Enum(*OperationUiCodeType.values(),
                       name='OperationUiCodeTypeEnumType'), nullable=False)
    value = Column(Text, nullable=False)

    # Associations
    operation_id = Column(Integer,
                          ForeignKey("operation.id"), nullable=False)
    operation = relationship("Operation", foreign_keys=[operation_id])

    def __unicode__(self):
        return self.type

    def __repr__(self):
        return '<Instance {}: {}>'.format(self.__class__, self.id)

class Platform(db.Model, Translatable):
    """ Execution platform """
    __tablename__ = 'platform'
    __translatable__ = {'locales': ['pt', 'en', 'es']}

    # Fields
    id = Column(Integer, primary_key=True)
    slug = Column(String(200), nullable=False)
    enabled = Column(Boolean, nullable=False)
    icon = Column(String(200), nullable=False)

    def __unicode__(self):
        return self.name

    def __repr__(self):
        return '<Instance {}: {}>'.format(self.__class__, self.id)

class PlatformTranslation(translation_base(Platform)):
    """ Translation table for Platform """
    __tablename__ = 'platform_translation'

    # Fields
    name = Column(Unicode(200))
    description = Column(Unicode(200))

class Task(db.Model):
    """ Task executed in Lemonade """
    __tablename__ = 'task'

    # Fields
    id = Column(String(250), primary_key=True,
                autoincrement=False)
    left = Column(Integer, nullable=False)
    top = Column(Integer, nullable=False)
    z_index = Column(Integer, nullable=False)
    forms = Column(Text, nullable=False)
    version = Column(Integer, nullable=False)
    __mapper_args__ = {
        'version_id_col': version,
    }

    # Associations
    workflow_id = Column(Integer,
                         ForeignKey("workflow.id"), nullable=False)
    workflow = relationship("Workflow", foreign_keys=[workflow_id],
                            backref=backref(
                                "tasks",
                                cascade="all, delete-orphan"))
    operation_id = Column(Integer,
                          ForeignKey("operation.id"), nullable=False)
    operation = relationship("Operation", foreign_keys=[operation_id])

    def __unicode__(self):
        return self.left

    def __repr__(self):
        return '<Instance {}: {}>'.format(self.__class__, self.id)

class Workflow(db.Model):
    """ Workflow in Lemonade. It's a set of tasks """
    __tablename__ = 'workflow'

    # Fields
    id = Column(Integer, primary_key=True)
    name = Column(String(200), nullable=False)
    description = Column(Text)
    enabled = Column(Boolean,
                     default=True, nullable=False)
    user_id = Column(Integer, nullable=False)
    user_login = Column(String(50), nullable=False)
    user_name = Column(String(200), nullable=False)
    created = Column(DateTime,
                     default=datetime.datetime.utcnow, nullable=False)
    updated = Column(DateTime,
                     default=datetime.datetime.utcnow, nullable=False, onupdate=datetime.datetime.utcnow)
    version = Column(Integer, nullable=False)
    image = Column(String(1000))
    __mapper_args__ = {
        'version_id_col': version, 'order_by': 'name'
    }

    # Associations
    platform_id = Column(Integer,
                         ForeignKey("platform.id"), nullable=False)
    platform = relationship("Platform", foreign_keys=[platform_id])

    def __unicode__(self):
        return self.name

    def __repr__(self):
        return '<Instance {}: {}>'.format(self.__class__, self.id)

<commit_msg>Support to filter associations by enabled attr<commit_after># -*- coding: utf-8 -*-
import datetime
import json
from flask_sqlalchemy import SQLAlchemy
from sqlalchemy import Column, Integer, String, Boolean, ForeignKey, Float, \
    Enum, DateTime, Numeric, Text, Unicode, UnicodeText
from sqlalchemy import event
from sqlalchemy.sql import func
from sqlalchemy.orm import relationship, backref
from sqlalchemy_i18n import make_translatable, translation_base, Translatable

make_translatable(options={'locales': ['pt', 'en', 'es'],
                           'auto_create_locales': True,
                           'fallback_locale': 'en'})

db = SQLAlchemy()

# noinspection PyClassHasNoInit
class OperationType:
    ACTION = 'ACTION'
    VISUALIZATION = 'VISUALIZATION'
    SHUFFLE = 'SHUFFLE'
    TRANSFORMATION = 'TRANSFORMATION'

    @staticmethod
    def values():
        return [n for n in OperationType.__dict__.keys()
                if n[0] != '_' and n != 'values']

# noinspection PyClassHasNoInit
class OperationPortType:
    INPUT = 'INPUT'
    OUTPUT = 'OUTPUT'

    @staticmethod
    def values():
        return [n for n in OperationPortType.__dict__.keys()
                if n[0] != '_' and n != 'values']

# noinspection PyClassHasNoInit
class OperationPortMultiplicity:
    MANY = 'MANY'
    ONE = 'ONE'

    @staticmethod
    def values():
        return [n for n in OperationPortMultiplicity.__dict__.keys()
                if n[0] != '_' and n != 'values']

# noinspection PyClassHasNoInit
class ApplicationType:
    SPARK_APPLICATION = 'SPARK_APPLICATION'
    SPARK_CODE_FUNCTION = 'SPARK_CODE_FUNCTION'

    @staticmethod
    def values():
        return [n for n in ApplicationType.__dict__.keys()
                if n[0] != '_' and n != 'values']

# noinspection PyClassHasNoInit
class OperationFieldScope:
    BOTH = 'BOTH'
    EXECUTION = 'EXECUTION'
    DESIGN = 'DESIGN'

    @staticmethod
    def values():
        return [n for n in OperationFieldScope.__dict__.keys()
                if n[0] != '_' and n != 'values']

# noinspection PyClassHasNoInit
class DataType:
    FLOAT = 'FLOAT'
    LAT_LONG = 'LAT_LONG'
    TIME = 'TIME'
    DOUBLE = 'DOUBLE'
    DECIMAL = 'DECIMAL'
    ENUM = 'ENUM'
    CHARACTER = 'CHARACTER'
    LONG = 'LONG'
    DATETIME = 'DATETIME'
    VECTOR = 'VECTOR'
    TEXT = 'TEXT'
    DATE = 'DATE'
    INTEGER = 'INTEGER'
    TIMESTAMP = 'TIMESTAMP'

    @staticmethod
    def values():
        return [n for n in DataType.__dict__.keys()
                if n[0] != '_' and n != 'values']

# noinspection PyClassHasNoInit
class OperationUiCodeType:
    ATTRIBUTE_LIST = 'ATTRIBUTE_LIST'

    @staticmethod
    def values():
        return [n for n in OperationUiCodeType.__dict__.keys()
                if n[0] != '_' and n != 'values']

class Application(db.Model):
    """ Any external application that can be ran by Juicer """
    __tablename__ = 'application'

    # Fields
    id = Column(Integer, primary_key=True)
    name = Column(String(200), nullable=False)
    description = Column(String(200), nullable=False)
    enabled = Column(Boolean,
                     default=True, nullable=False)
    type = Column(Enum(*ApplicationType.values(),
                       name='ApplicationTypeEnumType'), nullable=False)
    execution_parameters = Column(Text)
    __mapper_args__ = {
        'order_by': 'name'
    }

    def __unicode__(self):
        return self.name

    def __repr__(self):
        return '<Instance {}: {}>'.format(self.__class__, self.id)

class Flow(db.Model):
    """ Flow of data between two tasks in Lemonade """
    __tablename__ = 'flow'

    # Fields
    id = Column(Integer, primary_key=True)
    source_port = Column(Integer, nullable=False)
    target_port = Column(Integer, nullable=False)
    source_port_name = Column(String(200), nullable=False)
    target_port_name = Column(String(200), nullable=False)

    # Associations
    source_id = Column(String(250),
                       ForeignKey("task.id"), nullable=False)
    source = relationship("Task", foreign_keys=[source_id],
                          backref=backref(
                              "sources",
                              cascade="all, delete-orphan"))
    target_id = Column(String(250),
                       ForeignKey("task.id"), nullable=False)
    target = relationship("Task", foreign_keys=[target_id],
                          backref=backref(
                              "targets",
                              cascade="all, delete-orphan"))
    workflow_id = Column(Integer,
                         ForeignKey("workflow.id"), nullable=False)
    workflow = relationship("Workflow", foreign_keys=[workflow_id],
                            backref=backref(
                                "flows",
                                cascade="all, delete-orphan"))

    def __unicode__(self):
        return self.source_port

    def __repr__(self):
        return '<Instance {}: {}>'.format(self.__class__, self.id)

class Operation(db.Model, Translatable):
    """ Operation executed in Lemonade """
    __tablename__ = 'operation'
    __translatable__ = {'locales': ['pt', 'en', 'es']}

    # Fields
    id = Column(Integer, primary_key=True)
    slug = Column(String(200), nullable=False)
    enabled = Column(Boolean, nullable=False)
    type = Column(Enum(*OperationType.values(),
                       name='OperationTypeEnumType'), nullable=False)
    icon = Column(String(200), nullable=False)

    # Associations
    # noinspection PyUnresolvedReferences
    operation_category_operation = db.Table(
        'operation_category_operation',
        Column('operation_id', Integer, ForeignKey('operation.id')),
        Column('operation_category_id', Integer, ForeignKey('operation_category.id')))
    categories = relationship(
        "OperationCategory",
        secondary=operation_category_operation)
    # noinspection PyUnresolvedReferences
    operation_platform = db.Table(
        'operation_platform',
        Column('operation_id', Integer, ForeignKey('operation.id')),
        Column('platform_id', Integer, ForeignKey('platform.id')))
    platforms = relationship(
        "Platform",
        secondary=operation_platform,
        secondaryjoin=("and_("
                       "Platform.id==operation_platform.c.platform_id,"
                       "Platform.enabled==1)"))
    # noinspection PyUnresolvedReferences
    operation_operation_form = db.Table(
        'operation_operation_form',
        Column('operation_id', Integer, ForeignKey('operation.id')),
        Column('operation_form_id', Integer, ForeignKey('operation_form.id')))
    forms = relationship(
        "OperationForm",
        secondary=operation_operation_form,
        secondaryjoin=("and_("
                       "OperationForm.id==operation_operation_form.c.operation_form_id,"
                       "OperationForm.enabled==1)"))
    ports = relationship("OperationPort", back_populates="operation")

    def __unicode__(self):
        return self.name

    def __repr__(self):
        return '<Instance {}: {}>'.format(self.__class__, self.id)

class OperationTranslation(translation_base(Operation)):
    """ Translation table for Operation """
    __tablename__ = 'operation_translation'

    # Fields
    name = Column(Unicode(200))
    description = Column(Unicode(200))

class OperationCategory(db.Model, Translatable):
    """ Allows categorize operations """
    __tablename__ = 'operation_category'
    __translatable__ = {'locales': ['pt', 'en', 'es']}

    # Fields
    id = Column(Integer, primary_key=True)
    type = Column(String(200), nullable=False)

    def __unicode__(self):
        return self.name

    def __repr__(self):
        return '<Instance {}: {}>'.format(self.__class__, self.id)

class OperationCategoryTranslation(translation_base(OperationCategory)):
    """ Translation table for OperationCategory """
    __tablename__ = 'operation_category_translation'

    # Fields
    name = Column(Unicode(200))

class OperationForm(db.Model, Translatable):
    """ A form used to fill parameters to the operations """
    __tablename__ = 'operation_form'
    __translatable__ = {'locales': ['pt', 'en', 'es']}

    # Fields
    id = Column(Integer, primary_key=True)
    enabled = Column(Boolean,
                     default=True, nullable=False)
    order = Column(Integer, nullable=False)
    category = Column(String(200), nullable=False)
    __mapper_args__ = {
        'order_by': 'order'
    }

    # Associations
    fields = relationship("OperationFormField",
                          order_by="OperationFormField.order")

    def __unicode__(self):
        return self.name

    def __repr__(self):
        return '<Instance {}: {}>'.format(self.__class__, self.id)

class OperationFormTranslation(translation_base(OperationForm)):
    """ Translation table for OperationForm """
    __tablename__ = 'operation_form_translation'

    # Fields
    name = Column(Unicode(200))

class OperationFormField(db.Model, Translatable):
    """ A field used to fill one parameter of a form for an operations """
    __tablename__ = 'operation_form_field'
    __translatable__ = {'locales': ['pt', 'en', 'es']}

    # Fields
    id = Column(Integer, primary_key=True)
    name = Column(String(200), nullable=False)
    type = Column(Enum(*DataType.values(),
                       name='DataTypeEnumType'), nullable=False)
    required = Column(Boolean, nullable=False)
    order = Column(Integer, nullable=False)
    default = Column(Text)
    suggested_widget = Column(String(200))
    values_url = Column(String(200))
    values = Column(Text)
    scope = Column(Enum(*OperationFieldScope.values(),
                        name='OperationFieldScopeEnumType'), nullable=False)
    __mapper_args__ = {
        'order_by': 'order'
    }

    # Associations
    form_id = Column(Integer,
                     ForeignKey("operation_form.id"), nullable=False)
    form = relationship("OperationForm", foreign_keys=[form_id])

    def __unicode__(self):
        return self.name

    def __repr__(self):
        return '<Instance {}: {}>'.format(self.__class__, self.id)

class OperationFormFieldTranslation(translation_base(OperationFormField)):
    """ Translation table for OperationFormField """
    __tablename__ = 'operation_form_field_translation'

    # Fields
    label = Column(Unicode(200))
    help = Column(UnicodeText())

class OperationPort(db.Model, Translatable):
    """ An input or output port for operation """
    __tablename__ = 'operation_port'
    __translatable__ = {'locales': ['pt', 'en', 'es']}

    # Fields
    id = Column(Integer, primary_key=True)
    type = Column(Enum(*OperationPortType.values(),
                       name='OperationPortTypeEnumType'), nullable=False)
    tags = Column(Text)
    order = Column(Integer)
    multiplicity = Column(Enum(*OperationPortMultiplicity.values(),
                               name='OperationPortMultiplicityEnumType'),
                          default=1, nullable=False)
    __mapper_args__ = {
        'order_by': 'order'
    }

    # Associations
    # noinspection PyUnresolvedReferences
    operation_port_interface_operation_port = db.Table(
        'operation_port_interface_operation_port',
        Column('operation_port_id', Integer, ForeignKey('operation_port.id')),
        Column('operation_port_interface_id', Integer, ForeignKey('operation_port_interface.id')))
    interfaces = relationship(
        "OperationPortInterface",
        secondary=operation_port_interface_operation_port)
    operation_id = Column(Integer,
                          ForeignKey("operation.id"), nullable=False)
    operation = relationship("Operation", foreign_keys=[operation_id])

    def __unicode__(self):
        return self.name

    def __repr__(self):
        return '<Instance {}: {}>'.format(self.__class__, self.id)

class OperationPortTranslation(translation_base(OperationPort)):
    """ Translation table for OperationPort """
    __tablename__ = 'operation_port_translation'

    # Fields
    name = Column(Unicode(200))
    description = Column(Unicode(200))

class OperationPortInterface(db.Model, Translatable):
    """ An interface that a operation port supports """
    __tablename__ = 'operation_port_interface'
    __translatable__ = {'locales': ['pt', 'en', 'es']}

    # Fields
    id = Column(Integer, primary_key=True)
    color = Column(String(50), nullable=False)

    def __unicode__(self):
        return self.name

    def __repr__(self):
        return '<Instance {}: {}>'.format(self.__class__, self.id)

class OperationPortInterfaceTranslation(
        translation_base(OperationPortInterface)):
    """ Translation table for OperationPortInterface """
    __tablename__ = 'operation_port_interface_translation'

    # Fields
    name = Column(Unicode(200))

class OperationUiCode(db.Model):
    """ Associated UI code """
    __tablename__ = 'operation_ui_code'

    # Fields
    id = Column(Integer, primary_key=True)
    type = Column(Enum(*OperationUiCodeType.values(),
                       name='OperationUiCodeTypeEnumType'), nullable=False)
    value = Column(Text, nullable=False)

    # Associations
    operation_id = Column(Integer,
                          ForeignKey("operation.id"), nullable=False)
    operation = relationship("Operation", foreign_keys=[operation_id])

    def __unicode__(self):
        return self.type

    def __repr__(self):
        return '<Instance {}: {}>'.format(self.__class__, self.id)

class Platform(db.Model, Translatable):
    """ Execution platform """
    __tablename__ = 'platform'
    __translatable__ = {'locales': ['pt', 'en', 'es']}

    # Fields
    id = Column(Integer, primary_key=True)
    slug = Column(String(200), nullable=False)
    enabled = Column(Boolean, nullable=False)
    icon = Column(String(200), nullable=False)

    def __unicode__(self):
        return self.name

    def __repr__(self):
        return '<Instance {}: {}>'.format(self.__class__, self.id)

class PlatformTranslation(translation_base(Platform)):
    """ Translation table for Platform """
    __tablename__ = 'platform_translation'

    # Fields
    name = Column(Unicode(200))
    description = Column(Unicode(200))

class Task(db.Model):
    """ Task executed in Lemonade """
    __tablename__ = 'task'

    # Fields
    id = Column(String(250), primary_key=True,
                autoincrement=False)
    left = Column(Integer, nullable=False)
    top = Column(Integer, nullable=False)
    z_index = Column(Integer, nullable=False)
    forms = Column(Text, nullable=False)
    version = Column(Integer, nullable=False)
    __mapper_args__ = {
        'version_id_col': version,
    }

    # Associations
    workflow_id = Column(Integer,
                         ForeignKey("workflow.id"), nullable=False)
    workflow = relationship("Workflow", foreign_keys=[workflow_id],
                            backref=backref(
                                "tasks",
                                cascade="all, delete-orphan"))
    operation_id = Column(Integer,
                          ForeignKey("operation.id"), nullable=False)
    operation = relationship("Operation", foreign_keys=[operation_id])

    def __unicode__(self):
        return self.left

    def __repr__(self):
        return '<Instance {}: {}>'.format(self.__class__, self.id)

class Workflow(db.Model):
    """ Workflow in Lemonade. It's a set of tasks """
    __tablename__ = 'workflow'

    # Fields
    id = Column(Integer, primary_key=True)
    name = Column(String(200), nullable=False)
    description = Column(Text)
    enabled = Column(Boolean,
                     default=True, nullable=False)
    user_id = Column(Integer, nullable=False)
    user_login = Column(String(50), nullable=False)
    user_name = Column(String(200), nullable=False)
    created = Column(DateTime,
                     default=datetime.datetime.utcnow, nullable=False)
    updated = Column(DateTime,
                     default=datetime.datetime.utcnow, nullable=False, onupdate=datetime.datetime.utcnow)
    version = Column(Integer, nullable=False)
    image = Column(String(1000))
    __mapper_args__ = {
        'version_id_col': version, 'order_by': 'name'
    }

    # Associations
    platform_id = Column(Integer,
                         ForeignKey("platform.id"), nullable=False)
    platform = relationship("Platform", foreign_keys=[platform_id])

    def __unicode__(self):
        return self.name

    def __repr__(self):
        return '<Instance {}: {}>'.format(self.__class__, self.id)

<|endoftext|>


<commit_before># -*- coding: utf-8 -*-
from datetime import datetime, timedelta
from django import forms
from abonapp.models import Abon
from models import Task
from accounts_app.models import UserProfile

class TaskFrm(forms.ModelForm):
    abon = forms.ModelChoiceField(
        queryset=Abon.objects.all(),
        required=False,
        widget=forms.Select(attrs={'class': 'form-control selectpicker',
            'data-live-search':'true','title':"Выберите абонента"})
    )
    recipient = forms.ModelChoiceField(
        queryset=UserProfile.objects.filter(is_admin=True),
        widget=forms.Select(attrs={'class': 'form-control', 'required':''})
    )

    class Meta:
        model = Task
        exclude = ['time_of_create', 'author']
        widgets = {
            'descr': forms.TextInput(attrs={
                'placeholder': u'Краткое описание',
                'class': "form-control",
                'required': ''
            }),
            'device': forms.Select(attrs={'class': 'form-control', 'required':''}),
            'priority': forms.Select(attrs={'class': 'form-control'}),
            'state': forms.Select(attrs={'class': 'form-control'}),
            'out_date': forms.DateInput(attrs={'class': 'form-control'}),
            'attachment': forms.FileInput(attrs={'class': 'form-control'}),
            'mode': forms.Select(attrs={'class': 'form-control'})
        }
        initials = {
            'out_date': datetime.now()+timedelta(days=7)
        }
<commit_msg>время выполнения по умолчанию 3 дня<commit_after># -*- coding: utf-8 -*-
from datetime import datetime, timedelta
from django import forms
from abonapp.models import Abon
from models import Task
from accounts_app.models import UserProfile

class TaskFrm(forms.ModelForm):
    abon = forms.ModelChoiceField(
        queryset=Abon.objects.all(),
        required=False,
        widget=forms.Select(attrs={'class': 'form-control selectpicker',
            'data-live-search':'true','title':"Выберите абонента"})
    )
    recipient = forms.ModelChoiceField(
        queryset=UserProfile.objects.filter(is_admin=True),
        widget=forms.Select(attrs={'class': 'form-control', 'required':''})
    )

    class Meta:
        model = Task
        exclude = ['time_of_create', 'author']
        widgets = {
            'descr': forms.TextInput(attrs={
                'placeholder': u'Краткое описание',
                'class': "form-control",
                'required': ''
            }),
            'device': forms.Select(attrs={'class': 'form-control', 'required':''}),
            'priority': forms.Select(attrs={'class': 'form-control'}),
            'state': forms.Select(attrs={'class': 'form-control'}),
            'out_date': forms.DateInput(attrs={'class': 'form-control'}),
            'attachment': forms.FileInput(attrs={'class': 'form-control'}),
            'mode': forms.Select(attrs={'class': 'form-control'})
        }
        initials = {
            'out_date': datetime.now()+timedelta(days=3)
        }
<|endoftext|>


<commit_before># -*- coding: utf-8 -*-

#    Copyright (C) 2013 Rackspace Hosting Inc. All Rights Reserved.
#    Copyright (C) 2013 Yahoo! Inc. All Rights Reserved.
#
#    Licensed under the Apache License, Version 2.0 (the "License"); you may
#    not use this file except in compliance with the License. You may obtain
#    a copy of the License at
#
#         http://www.apache.org/licenses/LICENSE-2.0
#
#    Unless required by applicable law or agreed to in writing, software
#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
#    License for the specific language governing permissions and limitations
#    under the License.

import abc
import collections
import contextlib
import copy
import logging

import six

from taskflow import atom
from taskflow.utils import reflection

LOG = logging.getLogger(__name__)

# Constants passed into revert kwargs.
#
# Contain the execute() result (if any).
REVERT_RESULT = 'result'
#
# The cause of the flow failure/s
REVERT_FLOW_FAILURES = 'flow_failures'

# Common events
EVENT_UPDATE_PROGRESS = 'update_progress'

@six.add_metaclass(abc.ABCMeta)
class BaseTask(atom.Atom):
    """An abstraction that defines a potential piece of work.

    This potential piece of work is expected to be able to contain
    functionality that defines what can be executed to accomplish that work
    as well as a way of defining what can be executed to reverted/undo that
    same piece of work.
    """

    # Known events this task can have callbacks bound to (others that are not
    # in this set/tuple will not be able to be bound); this should be updated
    # and/or extended in subclasses as needed to enable or disable new or
    # existing events...
    TASK_EVENTS = (EVENT_UPDATE_PROGRESS,)

    def __init__(self, name, provides=None, inject=None):
        if name is None:
            name = reflection.get_class_name(self)
        super(BaseTask, self).__init__(name, provides, inject=inject)
        # Map of events => lists of callbacks to invoke on task events.
        self._events_listeners = collections.defaultdict(list)

    def pre_execute(self):
        """Code to be run prior to executing the task.

        A common pattern for initializing the state of the system prior to
        running tasks is to define some code in a base class that all your
        tasks inherit from.  In that class, you can define a ``pre_execute``
        method and it will always be invoked just prior to your tasks running.
        """

    @abc.abstractmethod
    def execute(self, *args, **kwargs):
        """Activate a given task which will perform some operation and return.

        This method can be used to perform an action on a given set of input
        requirements (passed in via ``*args`` and ``**kwargs``) to accomplish
        some type of operation. This operation may provide some named
        outputs/results as a result of it executing for later reverting (or for
        other tasks to depend on).

        NOTE(harlowja): the result (if any) that is returned should be
        persistable so that it can be passed back into this task if
        reverting is triggered (especially in the case where reverting
        happens in a different python process or on a remote machine) and so
        that the result can be transmitted to other tasks (which may be local
        or remote).

        :param args: positional arguments that task requires to execute.
        :param kwargs: any keyword arguments that task requires to execute.
        """

    def post_execute(self):
        """Code to be run after executing the task.

        A common pattern for cleaning up global state of the system after the
        execution of tasks is to define some code in a base class that all your
        tasks inherit from.  In that class, you can define a ``post_execute``
        method and it will always be invoked just after your tasks execute,
        regardless of whether they succeded or not.

        This pattern is useful if you have global shared database sessions
        that need to be cleaned up, for example.
        """

    def pre_revert(self):
        """Code to be run prior to reverting the task.

        This works the same as :meth:`.pre_execute`, but for the revert phase.
        """

    def revert(self, *args, **kwargs):
        """Revert this task.

        This method should undo any side-effects caused by previous execution
        of the task using the result of the :py:meth:`execute` method and
        information on the failure which triggered reversion of the flow the
        task is contained in (if applicable).

        :param args: positional arguments that the task required to execute.
        :param kwargs: any keyword arguments that the task required to
                       execute; the special key ``'result'`` will contain
                       the :py:meth:`execute` result (if any) and
                       the ``**kwargs`` key ``'flow_failures'`` will contain
                       any failure information.
        """

    def post_revert(self):
        """Code to be run after reverting the task.

        This works the same as :meth:`.post_execute`, but for the revert phase.
        """

    def copy(self, retain_listeners=True):
        """Clone/copy this task.

        :param retain_listeners: retain the attached listeners when cloning,
                                 when false the listeners will be emptied, when
                                 true the listeners will be copied and retained

        :rtype: task
        :return: the copied task
        """
        c = copy.copy(self)
        c._events_listeners = c._events_listeners.copy()
        c._events_listeners.clear()
        if retain_listeners:
            for event_name, listeners in six.iteritems(self._events_listeners):
                c._events_listeners[event_name] = listeners[:]
        return c

    def update_progress(self, progress, **kwargs):
        """Update task progress and notify all registered listeners.

        :param progress: task progress float value between 0.0 and 1.0
        :param kwargs: any keyword arguments that are tied to the specific
                       progress value.
        """
        if progress > 1.0:
            LOG.warn("Progress must be <= 1.0, clamping to upper bound")
            progress = 1.0
        if progress < 0.0:
            LOG.warn("Progress must be >= 0.0, clamping to lower bound")
            progress = 0.0
        self.trigger(EVENT_UPDATE_PROGRESS, progress, **kwargs)

    def trigger(self, event_name, *args, **kwargs):
        """Execute all callbacks registered for the given event type.

        NOTE(harlowja): if a bound callback raises an exception it will be
                        logged (at a ``WARNING`` level) and the exception
                        will be dropped.

        :param event_name: event name to trigger
        :param args: arbitrary positional arguments passed to the triggered
                     callbacks (if any are matched), these will be in addition
                     to any ``kwargs`` provided on binding (these are passed
                     as positional arguments to the callback).
        :param kwargs: arbitrary keyword arguments passed to the triggered
                     callbacks (if any are matched), these will be in addition
                     to any ``kwargs`` provided on binding (these are passed
                     as keyword arguments to the callback).
        """
        for (cb, event_data) in self._events_listeners.get(event_name, []):
            try:
                cb(self, event_data, *args, **kwargs)
            except Exception:
                LOG.warn("Failed calling callback `%s` on event '%s'",
                         reflection.get_callable_name(cb), event_name,
                         exc_info=True)

    @contextlib.contextmanager
    def autobind(self, event_name, callback, **kwargs):
        """Binds & unbinds a given callback to the task.

        This function binds and unbinds using the context manager protocol.
        When events are triggered on the task of the given event name this
        callback will automatically be called with the provided
        keyword arguments as the first argument (further arguments may be
        provided by the entity triggering the event).

        The arguments are interpreted as for :func:`bind() <bind>`.
        """
        bound = False
        if callback is not None:
            try:
                self.bind(event_name, callback, **kwargs)
                bound = True
            except ValueError:
                LOG.warn("Failed binding callback `%s` as a receiver of"
                         " event '%s' notifications emitted from task '%s'",
                         reflection.get_callable_name(callback), event_name,
                         self, exc_info=True)
        try:
            yield self
        finally:
            if bound:
                self.unbind(event_name, callback)

    def bind(self, event_name, callback, **kwargs):
        """Attach a callback to be triggered on a task event.

        Callbacks should *not* be bound, modified, or removed after execution
        has commenced (they may be adjusted after execution has finished). This
        is primarily due to the need to preserve the callbacks that exist at
        execution time for engines which run tasks remotely or out of
        process (so that those engines can correctly proxy back transmitted
        events).

        Callbacks should also be *quick* to execute so that the engine calling
        them can continue execution in a timely manner (if long running
        callbacks need to exist, consider creating a separate pool + queue
        for those that the attached callbacks put long running operations into
        for execution by other entities).

        :param event_name: event type name
        :param callback: callable to execute each time event is triggered
        :param kwargs: optional named parameters that will be passed to the
                       callable object as a dictionary to the callbacks
                       *second* positional parameter.
        :raises ValueError: if invalid event type, or callback is passed
        """
        if event_name not in self.TASK_EVENTS:
            raise ValueError("Unknown task event '%s', can only bind"
                             " to events %s" % (event_name, self.TASK_EVENTS))
        if callback is not None:
            if not six.callable(callback):
                raise ValueError("Event handler callback must be callable")
            self._events_listeners[event_name].append((callback, kwargs))

    def unbind(self, event_name, callback=None):
        """Remove a previously-attached event callback from the task.

        If a callback is not passed, then this will unbind *all* event
        callbacks for the provided event. If multiple of the same callbacks
        are bound, then the first match is removed (and only the first match).

        :param event_name: event type
        :param callback: callback previously bound

        :rtype: boolean
        :return: whether anything was removed
        """
        removed_any = False
        if not callback:
            removed_any = self._events_listeners.pop(event_name, removed_any)
        else:
            event_listeners = self._events_listeners.get(event_name, [])
            for i, (cb, _event_data) in enumerate(event_listeners):
                if reflection.is_same_callback(cb, callback):
                    # NOTE(harlowja): its safe to do this as long as we stop
                    # iterating after we do the removal, otherwise its not
                    # safe (since this could have resized the list).
                    event_listeners.pop(i)
                    removed_any = True
                    break
        return bool(removed_any)

    def listeners_iter(self):
        """Return an iterator over the mapping of event => callbacks bound."""
        for event_name in list(six.iterkeys(self._events_listeners)):
            # Use get() just incase it was removed while iterating...
            event_listeners = self._events_listeners.get(event_name, [])
            if event_listeners:
                yield (event_name, event_listeners[:])

class Task(BaseTask):
    """Base class for user-defined tasks (derive from it at will!).

    Adds the following features on top of the :py:class:`.BaseTask`:

    - Auto-generates a name from the class name if a name is not
      explicitly provided.
    - Automatically adds all :py:meth:`.BaseTask.execute` argument names to
      the task requirements (items provided by the task may be also specified
      via ``default_provides`` class attribute or instance property).
    """

    default_provides = None

    def __init__(self, name=None, provides=None, requires=None,
                 auto_extract=True, rebind=None, inject=None):
        if provides is None:
            provides = self.default_provides
        super(Task, self).__init__(name, provides=provides, inject=inject)
        self._build_arg_mapping(self.execute, requires, rebind, auto_extract)

class FunctorTask(BaseTask):
    """Adaptor to make a task from a callable.

    Take any callable pair and make a task from it.

    NOTE(harlowja): If a name is not provided the function/method name of
    the ``execute`` callable will be used as the name instead (the name of
    the ``revert`` callable is not used).
    """

    def __init__(self, execute, name=None, provides=None,
                 requires=None, auto_extract=True, rebind=None, revert=None,
                 version=None, inject=None):
        if not six.callable(execute):
            raise ValueError("Function to use for executing must be"
                             " callable")
        if revert is not None:
            if not six.callable(revert):
                raise ValueError("Function to use for reverting must"
                                 " be callable")
        if name is None:
            name = reflection.get_callable_name(execute)
        super(FunctorTask, self).__init__(name, provides=provides,
                                          inject=inject)
        self._execute = execute
        self._revert = revert
        if version is not None:
            self.version = version
        self._build_arg_mapping(execute, requires, rebind, auto_extract)

    def execute(self, *args, **kwargs):
        return self._execute(*args, **kwargs)

    def revert(self, *args, **kwargs):
        if self._revert:
            return self._revert(*args, **kwargs)
        else:
            return None
<commit_msg>Remove rtype from task clone() doc<commit_after># -*- coding: utf-8 -*-

#    Copyright (C) 2013 Rackspace Hosting Inc. All Rights Reserved.
#    Copyright (C) 2013 Yahoo! Inc. All Rights Reserved.
#
#    Licensed under the Apache License, Version 2.0 (the "License"); you may
#    not use this file except in compliance with the License. You may obtain
#    a copy of the License at
#
#         http://www.apache.org/licenses/LICENSE-2.0
#
#    Unless required by applicable law or agreed to in writing, software
#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
#    License for the specific language governing permissions and limitations
#    under the License.

import abc
import collections
import contextlib
import copy
import logging

import six

from taskflow import atom
from taskflow.utils import reflection

LOG = logging.getLogger(__name__)

# Constants passed into revert kwargs.
#
# Contain the execute() result (if any).
REVERT_RESULT = 'result'
#
# The cause of the flow failure/s
REVERT_FLOW_FAILURES = 'flow_failures'

# Common events
EVENT_UPDATE_PROGRESS = 'update_progress'

@six.add_metaclass(abc.ABCMeta)
class BaseTask(atom.Atom):
    """An abstraction that defines a potential piece of work.

    This potential piece of work is expected to be able to contain
    functionality that defines what can be executed to accomplish that work
    as well as a way of defining what can be executed to reverted/undo that
    same piece of work.
    """

    # Known events this task can have callbacks bound to (others that are not
    # in this set/tuple will not be able to be bound); this should be updated
    # and/or extended in subclasses as needed to enable or disable new or
    # existing events...
    TASK_EVENTS = (EVENT_UPDATE_PROGRESS,)

    def __init__(self, name, provides=None, inject=None):
        if name is None:
            name = reflection.get_class_name(self)
        super(BaseTask, self).__init__(name, provides, inject=inject)
        # Map of events => lists of callbacks to invoke on task events.
        self._events_listeners = collections.defaultdict(list)

    def pre_execute(self):
        """Code to be run prior to executing the task.

        A common pattern for initializing the state of the system prior to
        running tasks is to define some code in a base class that all your
        tasks inherit from.  In that class, you can define a ``pre_execute``
        method and it will always be invoked just prior to your tasks running.
        """

    @abc.abstractmethod
    def execute(self, *args, **kwargs):
        """Activate a given task which will perform some operation and return.

        This method can be used to perform an action on a given set of input
        requirements (passed in via ``*args`` and ``**kwargs``) to accomplish
        some type of operation. This operation may provide some named
        outputs/results as a result of it executing for later reverting (or for
        other tasks to depend on).

        NOTE(harlowja): the result (if any) that is returned should be
        persistable so that it can be passed back into this task if
        reverting is triggered (especially in the case where reverting
        happens in a different python process or on a remote machine) and so
        that the result can be transmitted to other tasks (which may be local
        or remote).

        :param args: positional arguments that task requires to execute.
        :param kwargs: any keyword arguments that task requires to execute.
        """

    def post_execute(self):
        """Code to be run after executing the task.

        A common pattern for cleaning up global state of the system after the
        execution of tasks is to define some code in a base class that all your
        tasks inherit from.  In that class, you can define a ``post_execute``
        method and it will always be invoked just after your tasks execute,
        regardless of whether they succeded or not.

        This pattern is useful if you have global shared database sessions
        that need to be cleaned up, for example.
        """

    def pre_revert(self):
        """Code to be run prior to reverting the task.

        This works the same as :meth:`.pre_execute`, but for the revert phase.
        """

    def revert(self, *args, **kwargs):
        """Revert this task.

        This method should undo any side-effects caused by previous execution
        of the task using the result of the :py:meth:`execute` method and
        information on the failure which triggered reversion of the flow the
        task is contained in (if applicable).

        :param args: positional arguments that the task required to execute.
        :param kwargs: any keyword arguments that the task required to
                       execute; the special key ``'result'`` will contain
                       the :py:meth:`execute` result (if any) and
                       the ``**kwargs`` key ``'flow_failures'`` will contain
                       any failure information.
        """

    def post_revert(self):
        """Code to be run after reverting the task.

        This works the same as :meth:`.post_execute`, but for the revert phase.
        """

    def copy(self, retain_listeners=True):
        """Clone/copy this task.

        :param retain_listeners: retain the attached listeners when cloning,
                                 when false the listeners will be emptied, when
                                 true the listeners will be copied and retained

        :return: the copied task
        """
        c = copy.copy(self)
        c._events_listeners = c._events_listeners.copy()
        c._events_listeners.clear()
        if retain_listeners:
            for event_name, listeners in six.iteritems(self._events_listeners):
                c._events_listeners[event_name] = listeners[:]
        return c

    def update_progress(self, progress, **kwargs):
        """Update task progress and notify all registered listeners.

        :param progress: task progress float value between 0.0 and 1.0
        :param kwargs: any keyword arguments that are tied to the specific
                       progress value.
        """
        if progress > 1.0:
            LOG.warn("Progress must be <= 1.0, clamping to upper bound")
            progress = 1.0
        if progress < 0.0:
            LOG.warn("Progress must be >= 0.0, clamping to lower bound")
            progress = 0.0
        self.trigger(EVENT_UPDATE_PROGRESS, progress, **kwargs)

    def trigger(self, event_name, *args, **kwargs):
        """Execute all callbacks registered for the given event type.

        NOTE(harlowja): if a bound callback raises an exception it will be
                        logged (at a ``WARNING`` level) and the exception
                        will be dropped.

        :param event_name: event name to trigger
        :param args: arbitrary positional arguments passed to the triggered
                     callbacks (if any are matched), these will be in addition
                     to any ``kwargs`` provided on binding (these are passed
                     as positional arguments to the callback).
        :param kwargs: arbitrary keyword arguments passed to the triggered
                     callbacks (if any are matched), these will be in addition
                     to any ``kwargs`` provided on binding (these are passed
                     as keyword arguments to the callback).
        """
        for (cb, event_data) in self._events_listeners.get(event_name, []):
            try:
                cb(self, event_data, *args, **kwargs)
            except Exception:
                LOG.warn("Failed calling callback `%s` on event '%s'",
                         reflection.get_callable_name(cb), event_name,
                         exc_info=True)

    @contextlib.contextmanager
    def autobind(self, event_name, callback, **kwargs):
        """Binds & unbinds a given callback to the task.

        This function binds and unbinds using the context manager protocol.
        When events are triggered on the task of the given event name this
        callback will automatically be called with the provided
        keyword arguments as the first argument (further arguments may be
        provided by the entity triggering the event).

        The arguments are interpreted as for :func:`bind() <bind>`.
        """
        bound = False
        if callback is not None:
            try:
                self.bind(event_name, callback, **kwargs)
                bound = True
            except ValueError:
                LOG.warn("Failed binding callback `%s` as a receiver of"
                         " event '%s' notifications emitted from task '%s'",
                         reflection.get_callable_name(callback), event_name,
                         self, exc_info=True)
        try:
            yield self
        finally:
            if bound:
                self.unbind(event_name, callback)

    def bind(self, event_name, callback, **kwargs):
        """Attach a callback to be triggered on a task event.

        Callbacks should *not* be bound, modified, or removed after execution
        has commenced (they may be adjusted after execution has finished). This
        is primarily due to the need to preserve the callbacks that exist at
        execution time for engines which run tasks remotely or out of
        process (so that those engines can correctly proxy back transmitted
        events).

        Callbacks should also be *quick* to execute so that the engine calling
        them can continue execution in a timely manner (if long running
        callbacks need to exist, consider creating a separate pool + queue
        for those that the attached callbacks put long running operations into
        for execution by other entities).

        :param event_name: event type name
        :param callback: callable to execute each time event is triggered
        :param kwargs: optional named parameters that will be passed to the
                       callable object as a dictionary to the callbacks
                       *second* positional parameter.
        :raises ValueError: if invalid event type, or callback is passed
        """
        if event_name not in self.TASK_EVENTS:
            raise ValueError("Unknown task event '%s', can only bind"
                             " to events %s" % (event_name, self.TASK_EVENTS))
        if callback is not None:
            if not six.callable(callback):
                raise ValueError("Event handler callback must be callable")
            self._events_listeners[event_name].append((callback, kwargs))

    def unbind(self, event_name, callback=None):
        """Remove a previously-attached event callback from the task.

        If a callback is not passed, then this will unbind *all* event
        callbacks for the provided event. If multiple of the same callbacks
        are bound, then the first match is removed (and only the first match).

        :param event_name: event type
        :param callback: callback previously bound

        :rtype: boolean
        :return: whether anything was removed
        """
        removed_any = False
        if not callback:
            removed_any = self._events_listeners.pop(event_name, removed_any)
        else:
            event_listeners = self._events_listeners.get(event_name, [])
            for i, (cb, _event_data) in enumerate(event_listeners):
                if reflection.is_same_callback(cb, callback):
                    # NOTE(harlowja): its safe to do this as long as we stop
                    # iterating after we do the removal, otherwise its not
                    # safe (since this could have resized the list).
                    event_listeners.pop(i)
                    removed_any = True
                    break
        return bool(removed_any)

    def listeners_iter(self):
        """Return an iterator over the mapping of event => callbacks bound."""
        for event_name in list(six.iterkeys(self._events_listeners)):
            # Use get() just incase it was removed while iterating...
            event_listeners = self._events_listeners.get(event_name, [])
            if event_listeners:
                yield (event_name, event_listeners[:])

class Task(BaseTask):
    """Base class for user-defined tasks (derive from it at will!).

    Adds the following features on top of the :py:class:`.BaseTask`:

    - Auto-generates a name from the class name if a name is not
      explicitly provided.
    - Automatically adds all :py:meth:`.BaseTask.execute` argument names to
      the task requirements (items provided by the task may be also specified
      via ``default_provides`` class attribute or instance property).
    """

    default_provides = None

    def __init__(self, name=None, provides=None, requires=None,
                 auto_extract=True, rebind=None, inject=None):
        if provides is None:
            provides = self.default_provides
        super(Task, self).__init__(name, provides=provides, inject=inject)
        self._build_arg_mapping(self.execute, requires, rebind, auto_extract)

class FunctorTask(BaseTask):
    """Adaptor to make a task from a callable.

    Take any callable pair and make a task from it.

    NOTE(harlowja): If a name is not provided the function/method name of
    the ``execute`` callable will be used as the name instead (the name of
    the ``revert`` callable is not used).
    """

    def __init__(self, execute, name=None, provides=None,
                 requires=None, auto_extract=True, rebind=None, revert=None,
                 version=None, inject=None):
        if not six.callable(execute):
            raise ValueError("Function to use for executing must be"
                             " callable")
        if revert is not None:
            if not six.callable(revert):
                raise ValueError("Function to use for reverting must"
                                 " be callable")
        if name is None:
            name = reflection.get_callable_name(execute)
        super(FunctorTask, self).__init__(name, provides=provides,
                                          inject=inject)
        self._execute = execute
        self._revert = revert
        if version is not None:
            self.version = version
        self._build_arg_mapping(execute, requires, rebind, auto_extract)

    def execute(self, *args, **kwargs):
        return self._execute(*args, **kwargs)

    def revert(self, *args, **kwargs):
        if self._revert:
            return self._revert(*args, **kwargs)
        else:
            return None
<|endoftext|>