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

import sys
import tempfile
import time
import os
import subprocess
import argparse
import logging
from contextlib import contextmanager

import uuid

log = logging.getLogger("serviced-tests")

SERVICED_ROOT = os.path.dirname(os.path.abspath(__file__))
DEVNULL = open(os.devnull, 'w')

def fail(msg):
    log.critical(msg)
    sys.exit(1)

def which(prog):
    return subprocess.check_output("which %s" % prog, shell=True).strip()

@contextmanager
def elastic_server(port):
    try:
        log.info("Starting elastic on port %d " % port)
        container_name = str(uuid.uuid4())
        # TODO: handle already started
        # TODO: Get image name from serviced binary or isvcs.go
        # TODO: Wait for start more betterly
        cmd = ["docker", "run", "-d", "--name", container_name,
               "-p", "%d:9200" % port, "zenoss/serviced-isvcs:v38",
               "/opt/elasticsearch-0.90.9/bin/elasticsearch", "-f",
               "-Des.cluster.name=%s" % container_name,
               "-Dmulticast.enabled=false",
               "-Ddiscovery.zen.ping.multicast.ping.enabled=false"]
        subprocess.call(cmd)
        time.sleep(10)
        yield
    finally:
        log.info("Stopping elastic")
        subprocess.call(["docker", "stop", container_name])

@contextmanager
def dummy(*args, **kwargs):
    yield

def ensure_tool(executable, importpath):
    try:
        return which(executable)
    except subprocess.CalledProcessError:
        log.info("Installing %s tool" % executable)
        subprocess.call(["go", "get", importpath])
        return which(executable)

def has_dm_deferred_remove():
    """
    Test whether libdevmapper.h is new enough to support deferred remove
    functionality by compiling a file to see if the function is defined.
    """
    cmd = """
command -v gcc && ! (
cat <<EOF | gcc -ldevmapper -xc -
#include <libdevmapper.h>
int main() { dm_task_deferred_remove(NULL); }
EOF
)
"""
    try:
        subprocess.check_call(cmd, shell=True, stdout=DEVNULL, stderr=subprocess.STDOUT)
        return False
    except subprocess.CalledProcessError:
        return True

def args():
    """
    --all (some subset that is useful for someone)
    --packages (maybe positional?)
    """
    parser = argparse.ArgumentParser("serviced-tests")

    parser.add_argument("-v", "--verbose", action="store_true", help="verbose logging")

    types = parser.add_argument_group("Test Type")
    types.add_argument("--unit", action="store_true", help="pass the 'unit' build tag")
    types.add_argument("--integration", action="store_true", help="pass the 'integration' build tag")

    options = parser.add_argument_group("Test Options")
    options.add_argument("--no-godep", dest="nogodep", action="store_true",
            help="don't add the godep workspace to GOPATH")
    options.add_argument("--quick", action="store_true", help="don't run tests with the '!quick' build constraint")
    options.add_argument("--root", action="store_true", help="run the tests as the root user")
    options.add_argument("--race", action="store_true", help="run tests with race detection")
    options.add_argument("--cover", action="store_true", help="run tests with coverage")
    options.add_argument("--tag", action="append", help="optional extra build tag (may be specified multiple times)")

    coverage = parser.add_argument_group("Coverage Options")
    coverage.add_argument("--cover-html", required=False, help="output file for HTML coverage report")
    coverage.add_argument("--cover-xml", required=False, help="output file for Cobertura coverage report")

    fixtures = parser.add_argument_group("Fixture Options")
    fixtures.add_argument("--elastic", action="store_true", help="start an elastic server before the test run")
    fixtures.add_argument("--elastic-port", type=int, help="elastic server port", default=9202)

    parser.add_argument("--packages", nargs="*", help="serviced packages to test, relative to the serviced root (defaults to ./...)")
    parser.add_argument("arguments", nargs=argparse.REMAINDER, help="optional arguments to be passed through to the test runner")

    return parser.parse_args()

def build_tags(options):
    tags = options.tag or []

    # We always need the daemon tag
    tags.append("daemon")

    if not has_dm_deferred_remove():
        tags.append("libdm_no_deferred_remove")

    if options.unit:
        tags.append("unit")

    if options.integration:
        tags.append('integration')

    if options.quick:
        tags.append('quick')

    if options.root:
        tags.append('root')

    log.debug("Using build tags: %s" % tags)
    return tags

def get_gopath():
    gopath = os.environ.get("GOPATH")
    log.debug("Original GOPATH=%s" % (gopath or ""))
    try:
        godep_path = subprocess.check_output(["godep", "path"], cwd=SERVICED_ROOT)
    except subprocess.CalledProcessError:
        fail("Unable to run 'godep path'. Please check your environment.")
    gopath = "%s:%s" % (godep_path.strip(), gopath.strip())
    log.debug("Modified GOPATH=%s" % gopath)
    return gopath

def main(options):
    logging.basicConfig(level=logging.DEBUG if options.verbose else logging.INFO)

    if not any((options.unit, options.integration)):
        fail("No tests were specified to run. Please pass at least one of --unit or --integration.")

    log.debug("Running tests under serviced in %s" % SERVICED_ROOT)

    env = os.environ

    env["SERVICED_HOME"] = SERVICED_ROOT

    # Unset EDITOR so CLI tests won't fail
    env.pop("EDITOR", None)

    tags = build_tags(options)

    args = {}

    if options.cover:
        if options.race:
            fail("--race and --cover are mutually exclusive.")
        runner = ensure_tool("gocov", "github.com/axw/gocov/gocov")
        log.debug("Using gocov executable %s" % runner)
        if options.cover_html:
            ensure_tool("gocov-html", "gopkg.in/matm/v1/gocov-html")
        if options.cover_xml:
            ensure_tool("gocov-xml", "github.com/AlekSi/gocov-xml")
        stdout = tempfile.NamedTemporaryFile()
        log.debug("Writing temporary coverage output to %s" % stdout.name)
        args["stdout"] = stdout

    else:
        runner = which("go")
        log.debug("Using go executable %s" % runner)

    # Modify this after we've gotten all the tools.
    if not options.nogodep:
        env["GOPATH"] = get_gopath()

    # TODO: Get a sudo session set up with an interactive proc
    cmd = ["sudo", "-E", "PATH=%s" % env["PATH"]] if options.root else []

    cmd.extend([runner, "test", "-tags", " ".join(tags)])

    usep1 = False

    if options.integration:
        if options.cover:
            env["GOMAXPROCS"] = "1"
        else:
            usep1 = True

    if options.race:
        log.debug("Running with race detection")
        env["GORACE"] = "history_size=7 halt_on_error=1"
        cmd.append("-race")
        usep1 = True

    if usep1:
        cmd.extend(['-p', '1'])

    passthru = options.arguments
    if passthru and passthru[0] == "--":
        passthru = passthru[1:]
    cmd.extend(passthru)
    cmd.extend(options.packages or ["./..."])

    log.debug("Running command: %s" % cmd)
    log.debug("Running in directory: %s" % SERVICED_ROOT)

    fixture = elastic_server if options.elastic else dummy

    with fixture(options.elastic_port):
        try:
                subprocess.check_call(
                    cmd,
                    env=env,
                    cwd=SERVICED_ROOT,
                    **args
                )
        except (subprocess.CalledProcessError, KeyboardInterrupt):
            sys.exit(1)

    if options.cover_html:
        log.debug("Converting coverage to HTML")
        with open(options.cover_html, 'w') as output:
            subprocess.call(["gocov-html", stdout.name], stdout=output)
        log.info("HTML output written to %s" % options.cover_html)

    if options.cover_xml:
        log.debug("Converting coverage to Cobertura XML")
        with open(options.cover_xml, 'w') as output:
            proc = subprocess.Popen(["gocov-xml", stdout.name], stdout=output, stdin=subprocess.PIPE)
            stdout.seek(0)
            proc.communicate(stdout.read())
        log.info("Cobertura output written to %s" % options.cover_xml)

if __name__ == "__main__":
    options = args()
    main(options)
<commit_msg>CC-2021: Reposition positional arguments<commit_after>#!/usr/bin/env python

import sys
import tempfile
import time
import os
import subprocess
import argparse
import logging
from contextlib import contextmanager

import uuid

log = logging.getLogger("serviced-tests")

SERVICED_ROOT = os.path.dirname(os.path.abspath(__file__))
DEVNULL = open(os.devnull, 'w')

def fail(msg):
    log.critical(msg)
    sys.exit(1)

def which(prog):
    return subprocess.check_output("which %s" % prog, shell=True).strip()

@contextmanager
def elastic_server(port):
    try:
        log.info("Starting elastic on port %d " % port)
        container_name = str(uuid.uuid4())
        # TODO: handle already started
        # TODO: Get image name from serviced binary or isvcs.go
        # TODO: Wait for start more betterly
        cmd = ["docker", "run", "-d", "--name", container_name,
               "-p", "%d:9200" % port, "zenoss/serviced-isvcs:v38",
               "/opt/elasticsearch-0.90.9/bin/elasticsearch", "-f",
               "-Des.cluster.name=%s" % container_name,
               "-Dmulticast.enabled=false",
               "-Ddiscovery.zen.ping.multicast.ping.enabled=false"]
        subprocess.call(cmd)
        time.sleep(10)
        yield
    finally:
        log.info("Stopping elastic")
        subprocess.call(["docker", "stop", container_name])

@contextmanager
def dummy(*args, **kwargs):
    yield

def ensure_tool(executable, importpath):
    try:
        return which(executable)
    except subprocess.CalledProcessError:
        log.info("Installing %s tool" % executable)
        subprocess.call(["go", "get", importpath])
        return which(executable)

def has_dm_deferred_remove():
    """
    Test whether libdevmapper.h is new enough to support deferred remove
    functionality by compiling a file to see if the function is defined.
    """
    cmd = """
command -v gcc && ! (
cat <<EOF | gcc -ldevmapper -xc -
#include <libdevmapper.h>
int main() { dm_task_deferred_remove(NULL); }
EOF
)
"""
    try:
        subprocess.check_call(cmd, shell=True, stdout=DEVNULL, stderr=subprocess.STDOUT)
        return False
    except subprocess.CalledProcessError:
        return True

def args():
    """
    --all (some subset that is useful for someone)
    --packages (maybe positional?)
    """
    parser = argparse.ArgumentParser("serviced-tests")

    parser.add_argument("-v", "--verbose", action="store_true", help="verbose logging")

    types = parser.add_argument_group("Test Type")
    types.add_argument("--unit", action="store_true", help="pass the 'unit' build tag")
    types.add_argument("--integration", action="store_true", help="pass the 'integration' build tag")

    options = parser.add_argument_group("Test Options")
    options.add_argument("--no-godep", dest="nogodep", action="store_true",
            help="don't add the godep workspace to GOPATH")
    options.add_argument("--quick", action="store_true", help="don't run tests with the '!quick' build constraint")
    options.add_argument("--root", action="store_true", help="run the tests as the root user")
    options.add_argument("--race", action="store_true", help="run tests with race detection")
    options.add_argument("--cover", action="store_true", help="run tests with coverage")
    options.add_argument("--tag", action="append", help="optional extra build tag (may be specified multiple times)")

    coverage = parser.add_argument_group("Coverage Options")
    coverage.add_argument("--cover-html", required=False, help="output file for HTML coverage report")
    coverage.add_argument("--cover-xml", required=False, help="output file for Cobertura coverage report")

    fixtures = parser.add_argument_group("Fixture Options")
    fixtures.add_argument("--elastic", action="store_true", help="start an elastic server before the test run")
    fixtures.add_argument("--elastic-port", type=int, help="elastic server port", default=9202)

    parser.add_argument("--packages", nargs="*", help="serviced packages to test, relative to the serviced root (defaults to ./...)")
    parser.add_argument("arguments", nargs=argparse.REMAINDER, help="optional arguments to be passed through to the test runner")

    return parser.parse_args()

def build_tags(options):
    tags = options.tag or []

    # We always need the daemon tag
    tags.append("daemon")

    if not has_dm_deferred_remove():
        tags.append("libdm_no_deferred_remove")

    if options.unit:
        tags.append("unit")

    if options.integration:
        tags.append('integration')

    if options.quick:
        tags.append('quick')

    if options.root:
        tags.append('root')

    log.debug("Using build tags: %s" % tags)
    return tags

def get_gopath():
    gopath = os.environ.get("GOPATH")
    log.debug("Original GOPATH=%s" % (gopath or ""))
    try:
        godep_path = subprocess.check_output(["godep", "path"], cwd=SERVICED_ROOT)
    except subprocess.CalledProcessError:
        fail("Unable to run 'godep path'. Please check your environment.")
    gopath = "%s:%s" % (godep_path.strip(), gopath.strip())
    log.debug("Modified GOPATH=%s" % gopath)
    return gopath

def main(options):
    logging.basicConfig(level=logging.DEBUG if options.verbose else logging.INFO)

    if not any((options.unit, options.integration)):
        fail("No tests were specified to run. Please pass at least one of --unit or --integration.")

    log.debug("Running tests under serviced in %s" % SERVICED_ROOT)

    env = os.environ

    env["SERVICED_HOME"] = SERVICED_ROOT

    # Unset EDITOR so CLI tests won't fail
    env.pop("EDITOR", None)

    tags = build_tags(options)

    args = {}

    if options.cover:
        if options.race:
            fail("--race and --cover are mutually exclusive.")
        runner = ensure_tool("gocov", "github.com/axw/gocov/gocov")
        log.debug("Using gocov executable %s" % runner)
        if options.cover_html:
            ensure_tool("gocov-html", "gopkg.in/matm/v1/gocov-html")
        if options.cover_xml:
            ensure_tool("gocov-xml", "github.com/AlekSi/gocov-xml")
        stdout = tempfile.NamedTemporaryFile()
        log.debug("Writing temporary coverage output to %s" % stdout.name)
        args["stdout"] = stdout

    else:
        runner = which("go")
        log.debug("Using go executable %s" % runner)

    # Modify this after we've gotten all the tools.
    if not options.nogodep:
        env["GOPATH"] = get_gopath()

    # TODO: Get a sudo session set up with an interactive proc
    cmd = ["sudo", "-E", "PATH=%s" % env["PATH"]] if options.root else []

    cmd.extend([runner, "test", "-tags", " ".join(tags)])

    usep1 = False

    if options.integration:
        if options.cover:
            env["GOMAXPROCS"] = "1"
        else:
            usep1 = True

    if options.race:
        log.debug("Running with race detection")
        env["GORACE"] = "history_size=7 halt_on_error=1"
        cmd.append("-race")
        usep1 = True

    if usep1:
        cmd.extend(['-p', '1'])

    cmd.extend(options.packages or ["./..."])

    passthru = options.arguments
    if passthru and passthru[0] == "--":
        passthru = passthru[1:]
    cmd.extend(passthru)

    log.debug("Running command: %s" % cmd)
    log.debug("Running in directory: %s" % SERVICED_ROOT)

    fixture = elastic_server if options.elastic else dummy

    with fixture(options.elastic_port):
        try:
                subprocess.check_call(
                    cmd,
                    env=env,
                    cwd=SERVICED_ROOT,
                    **args
                )
        except (subprocess.CalledProcessError, KeyboardInterrupt):
            sys.exit(1)

    if options.cover_html:
        log.debug("Converting coverage to HTML")
        with open(options.cover_html, 'w') as output:
            subprocess.call(["gocov-html", stdout.name], stdout=output)
        log.info("HTML output written to %s" % options.cover_html)

    if options.cover_xml:
        log.debug("Converting coverage to Cobertura XML")
        with open(options.cover_xml, 'w') as output:
            proc = subprocess.Popen(["gocov-xml", stdout.name], stdout=output, stdin=subprocess.PIPE)
            stdout.seek(0)
            proc.communicate(stdout.read())
        log.info("Cobertura output written to %s" % options.cover_xml)

if __name__ == "__main__":
    options = args()
    main(options)
<|endoftext|>


<commit_before>from __future__ import division
from operator import attrgetter

from ryu.app import simple_switch_13
from ryu.controller import ofp_event
from ryu.controller.handler import MAIN_DISPATCHER, DEAD_DISPATCHER
from ryu.controller.handler import set_ev_cls
from ryu.lib import hub

class SimpleMonitor(simple_switch_13.SimpleSwitch13):

    def __init__(self, *args, **kwargs):
        super(SimpleMonitor, self).__init__(*args, **kwargs)
        self.datapaths = {}
        self.monitor_thread = hub.spawn(self._monitor)
        self.port_stats = {}
        self.port_speed = {}
        self.flow_stats = {}
        self.flow_speed = {}
        self.sleep = 2

    @set_ev_cls(ofp_event.EventOFPStateChange,
                [MAIN_DISPATCHER, DEAD_DISPATCHER])
    def _state_change_handler(self, ev):
        datapath = ev.datapath
        if ev.state == MAIN_DISPATCHER:
            if not datapath.id in self.datapaths:
                self.logger.debug('register datapath: %016x', datapath.id)
                self.datapaths[datapath.id] = datapath
        elif ev.state == DEAD_DISPATCHER:
            if datapath.id in self.datapaths:
                self.logger.debug('unregister datapath: %016x', datapath.id)
                del self.datapaths[datapath.id]

    def _monitor(self):
        while True:
            for dp in self.datapaths.values():
                self._request_stats(dp)
            hub.sleep(self.sleep)

    def _request_stats(self, datapath):
        self.logger.debug('send stats request: %016x', datapath.id)
        ofproto = datapath.ofproto
        parser = datapath.ofproto_parser

        req = parser.OFPFlowStatsRequest(datapath)
        datapath.send_msg(req)

        req = parser.OFPPortStatsRequest(datapath, 0, ofproto.OFPP_ANY)
        datapath.send_msg(req)

    def _save_stats(self, dist, key, value, length):
        if key not in dist:
                dist[key] = []
        dist[key].append(value)

        if len(dist[key]) > length:
            dist[key].pop(0)

    def _get_speed(self, now, pre, period):
        return (now-pre)/period/8

    def _get_time(self, sec, nsec):
        return sec + nsec/(10**9)

    def _get_period(self, n_sec, n_nsec, p_sec, p_nsec):
        return self._get_time(n_sec, n_nsec) - self._get_time(p_sec, p_nsec)

    @set_ev_cls(ofp_event.EventOFPFlowStatsReply, MAIN_DISPATCHER)
    def _flow_stats_reply_handler(self, ev):
        body = ev.msg.body

        # self.logger.info('datapath         '
        #                  'in-port  eth-dst           '
        #                  'out-port packets  bytes')
        # self.logger.info('---------------- '
        #                  '-------- ----------------- '
        #                  '-------- -------- --------')

        for stat in sorted([flow for flow in body if flow.priority == 1],
                           key=lambda flow: (flow.match['in_port'],
                                             flow.match['eth_dst'])):
            # self.logger.info('%016x %8x %17s %8x %8d %8d',
            #                  ev.msg.datapath.id,
            #                  stat.match['in_port'], stat.match['eth_dst'],
            #                  stat.instructions[0].actions[0].port,
            #                  stat.packet_count, stat.byte_count)

            key = (
                stat.match['in_port'], stat.match['eth_dst'],
                stat.instructions[0].actions[0].port,)
            value = (
                stat.packet_count, stat.byte_count,
                stat.duration_sec, stat.duration_nsec)
            self._save_stats(self.flow_stats, key, value, 5)

            # Get flow's speed.
            pre = 0
            period = self.sleep
            tmp = self.flow_stats[key]
            if len(tmp) > 1:
                pre = tmp[-2][1]
                period = self._get_period(
                    tmp[-1][2], tmp[-1][3],
                    tmp[-2][2], tmp[-2][3])
                # print "flow period: ", period

            speed = self._get_speed(
                self.flow_stats[key][-1][1], pre, period)

            self._save_stats(self.flow_speed, key, speed, 5)
            print '\n Flow Speed:\n', self.flow_speed

    @set_ev_cls(ofp_event.EventOFPPortStatsReply, MAIN_DISPATCHER)
    def _port_stats_reply_handler(self, ev):
        body = ev.msg.body

        # self.logger.info('datapath         port     '
        #                 'rx-pkts  rx-bytes rx-error '
        #                 'tx-pkts  tx-bytes tx-error')
        # self.logger.info('---------------- -------- '
        #                 '-------- -------- -------- '
        #                 '-------- -------- --------')
        for stat in sorted(body, key=attrgetter('port_no')):
            # self.logger.info('%016x %8x %8d %8d %8d %8d %8d %8d',
            #                  ev.msg.datapath.id, stat.port_no,
            #                  stat.rx_packets, stat.rx_bytes, stat.rx_errors,
            #                  stat.tx_packets, stat.tx_bytes, stat.tx_errors)

            key = (ev.msg.datapath.id, stat.port_no)
            value = (
                stat.rx_packets, stat.rx_bytes, stat.rx_errors,
                stat.duration_sec, stat.duration_nsec)

            self._save_stats(self.port_stats, key, value, 5)

            # Get port speed.
            pre = 0
            period = self.sleep
            tmp = self.port_stats[key]
            if len(tmp) > 1:
                pre = tmp[-2][1]
                period = self._get_period(
                    tmp[-1][3], tmp[-1][4],
                    tmp[-2][3], tmp[-2][4])

            speed = self._get_speed(
                self.port_stats[key][-1][1], pre, period)

            self._save_stats(self.port_speed, key, speed, 5)
            print '\n Speed:\n', self.port_speed
<commit_msg>add simple_monitor.py<commit_after>from __future__ import division
from operator import attrgetter
from ryu.base import app_manager
from ryu.app import simple_switch_13
from ryu.controller import ofp_event
from ryu.controller.handler import MAIN_DISPATCHER, DEAD_DISPATCHER
from ryu.controller.handler import CONFIG_DISPATCHER
from ryu.controller.handler import set_ev_cls
from ryu.lib import hub
from ryu.lib.packet import packet

class SimpleMonitor(app_manager.RyuApp):

    def __init__(self, *args, **kwargs):
        super(SimpleMonitor, self).__init__(*args, **kwargs)
        self.datapaths = {}
        self.monitor_thread = hub.spawn(self._monitor)
        self.port_stats = {}
        self.port_speed = {}
        self.flow_stats = {}
        self.flow_speed = {}
        self.sleep = 2
        self.state_len = 3

    @set_ev_cls(ofp_event.EventOFPStateChange,
                [MAIN_DISPATCHER, DEAD_DISPATCHER])
    def _state_change_handler(self, ev):
        datapath = ev.datapath
        if ev.state == MAIN_DISPATCHER:
            if not datapath.id in self.datapaths:
                self.logger.debug('register datapath: %016x', datapath.id)
                self.datapaths[datapath.id] = datapath
        elif ev.state == DEAD_DISPATCHER:
            if datapath.id in self.datapaths:
                self.logger.debug('unregister datapath: %016x', datapath.id)
                del self.datapaths[datapath.id]

    # get the ports' features.
    @set_ev_cls(
        ofp_event.EventOFPStateChange,
        [MAIN_DISPATCHER, DEAD_DISPATCHER])
    def port_features_handler(self, ev):
        datapath = ev.datapath
        ofproto = datapath.ofproto
        parser = datapath.ofproto_parser

    def _monitor(self):
        while True:
            for dp in self.datapaths.values():
                self._request_stats(dp)
            hub.sleep(self.sleep)

    def _request_stats(self, datapath):
        self.logger.debug('send stats request: %016x', datapath.id)
        ofproto = datapath.ofproto
        parser = datapath.ofproto_parser

        req = parser.OFPFlowStatsRequest(datapath)
        datapath.send_msg(req)

        req = parser.OFPPortStatsRequest(datapath, 0, ofproto.OFPP_ANY)
        datapath.send_msg(req)

    def _save_stats(self, dist, key, value, length):
        if key not in dist:
                dist[key] = []
        dist[key].append(value)

        if len(dist[key]) > length:
            dist[key].pop(0)

    def _get_speed(self, now, pre, period):
        return (now-pre)/period/8

    def _get_time(self, sec, nsec):
        return sec + nsec/(10**9)

    def _get_period(self, n_sec, n_nsec, p_sec, p_nsec):
        return self._get_time(n_sec, n_nsec) - self._get_time(p_sec, p_nsec)

    @set_ev_cls(ofp_event.EventOFPFlowStatsReply, MAIN_DISPATCHER)
    def _flow_stats_reply_handler(self, ev):
        body = ev.msg.body

        for stat in sorted([flow for flow in body if flow.priority == 1],
                           key=lambda flow: (flow.match['in_port'],
                                             flow.match['eth_dst'])):

            key = (
                stat.match['in_port'], stat.match['eth_dst'],
                stat.instructions[0].actions[0].port,)
            value = (
                stat.packet_count, stat.byte_count,
                stat.duration_sec, stat.duration_nsec)
            self._save_stats(self.flow_stats, key, value, self.state_len)

            # Get flow's speed.
            pre = 0
            period = self.sleep
            tmp = self.flow_stats[key]
            if len(tmp) > 1:
                pre = tmp[-2][1]
                period = self._get_period(
                    tmp[-1][2], tmp[-1][3],
                    tmp[-2][2], tmp[-2][3])

            speed = self._get_speed(
                self.flow_stats[key][-1][1], pre, period)

            self._save_stats(self.flow_speed, key, speed, self.state_len)

    @set_ev_cls(ofp_event.EventOFPPortStatsReply, MAIN_DISPATCHER)
    def _port_stats_reply_handler(self, ev):
        body = ev.msg.body

        for stat in sorted(body, key=attrgetter('port_no')):
            key = (ev.msg.datapath.id, stat.port_no)
            value = (
                stat.rx_packets, stat.rx_bytes, stat.rx_errors,
                stat.duration_sec, stat.duration_nsec)

            self._save_stats(self.port_stats, key, value, self.state_len)

            # Get port speed.
            pre = 0
            period = self.sleep
            tmp = self.port_stats[key]
            if len(tmp) > 1:
                pre = tmp[-2][1]
                period = self._get_period(
                    tmp[-1][3], tmp[-1][4],
                    tmp[-2][3], tmp[-2][4])

            speed = self._get_speed(
                self.port_stats[key][-1][1], pre, period)

            self._save_stats(self.port_speed, key, speed, self.state_len)
            print '\n Speed:\n', self.port_speed
<|endoftext|>


<commit_before>import urllib2, urllib

def flatten_nested_hash(hash_table):
    """
    Flatten nested dictionary for GET / POST / DELETE API request
    """
    def flatten(hash_table, brackets=True):
        f = {}
        for key,value in hash_table.items():
            _key = '[' + str(key) + ']' if (brackets == True) else str(key)
            if type(value) is dict:
                for k,v in flatten(value).items():
                    f[_key + k] = v
            elif type(value) is list:
                temp_hash = {}
                for i,v in enumerate(value):
                    temp_hash[str(i)] = v
                for k,v in flatten(temp_hash).items():
                    f[ _key + k] = v
            else:
                f[_key] = value
        return f
    return flatten(hash_table, False)

def sailthru_http_request(url, data, method):
    """
    Perform an HTTP GET / POST / DELETE request
    """
    data = flatten_nested_hash(data)
    data = urllib.urlencode(data, True)
    opener = urllib2.build_opener(urllib2.HTTPHandler)
    try:
        if method == 'POST':
            req = urllib2.Request(url, data)
        else:
            url += '?' + data
            req = urllib2.Request(url)
        req.add_header('User-Agent', 'Sailthru API Python Client')
        req.get_method = lambda: method
        response = opener.open(req)
        response_data = response.read()
        response.close()
        return response_data
    except urllib2.URLError, e:
        return str(e)
    except urllib2.HTTPError, e:
        return e.read()<commit_msg>must catch urllib2.HTTPError before urllib2.URLError.. since URLError will also gobble up HTTPError.. and then response returns generic 404 message.. instead of intended response.<commit_after>import urllib2, urllib

def flatten_nested_hash(hash_table):
    """
    Flatten nested dictionary for GET / POST / DELETE API request
    """
    def flatten(hash_table, brackets=True):
        f = {}
        for key,value in hash_table.items():
            _key = '[' + str(key) + ']' if (brackets == True) else str(key)
            if type(value) is dict:
                for k,v in flatten(value).items():
                    f[_key + k] = v
            elif type(value) is list:
                temp_hash = {}
                for i,v in enumerate(value):
                    temp_hash[str(i)] = v
                for k,v in flatten(temp_hash).items():
                    f[ _key + k] = v
            else:
                f[_key] = value
        return f
    return flatten(hash_table, False)

def sailthru_http_request(url, data, method):
    """
    Perform an HTTP GET / POST / DELETE request
    """
    data = flatten_nested_hash(data)
    data = urllib.urlencode(data, True)
    opener = urllib2.build_opener(urllib2.HTTPHandler)
    try:
        if method == 'POST':
            req = urllib2.Request(url, data)
        else:
            url += '?' + data
            req = urllib2.Request(url)
        req.add_header('User-Agent', 'Sailthru API Python Client')
        req.get_method = lambda: method
        response = opener.open(req)
        response_data = response.read()
        response.close()
        return response_data
    except urllib2.HTTPError, e:
        return e.read()
    except urllib2.URLError, e:
        return str(e)<|endoftext|>


<commit_before># -*- coding: utf-8 -*-
"""
A route is a rule that specifies how certain packets should be handled by the
virtual network. Routes are associated with virtual machine instances by tag,
and the set of routes for a particular VM is called its routing table.
For each packet leaving a virtual machine, the system searches that machine's
routing table for a single best matching route.

.. versionadded:: 2018.3.0

This module will create a route to send traffic destined to the Internet
through your gateway instance.

:codeauthor: `Pratik Bandarkar <pratik.bandarkar@gmail.com>`
:maturity:   new
:depends:    google-api-python-client
:platform:   Linux

"""

# Import Python libs
from __future__ import absolute_import, print_function, unicode_literals

import logging

# Import salt libs
from salt.ext import six

log = logging.getLogger(__name__)

try:
    import googleapiclient.discovery
    import oauth2client.service_account

    HAS_LIB = True
except ImportError:
    HAS_LIB = False

__virtualname__ = "gcp"

def __virtual__():
    """
    Check for googleapiclient api
    """
    if HAS_LIB is False:
        return (
            False,
            "Required dependencies 'googleapiclient' and/or 'oauth2client' were not found.",
        )
    return __virtualname__

def _get_network(project_id, network_name, service):
    """
    Fetch network selfLink from network name.
    """
    return service.networks().get(project=project_id, network=network_name).execute()

def _get_instance(project_id, instance_zone, name, service):
    """
    Get instance details
    """
    return (
        service.instances()
        .get(project=project_id, zone=instance_zone, instance=name)
        .execute()
    )

def route_create(
    credential_file=None,
    project_id=None,
    name=None,
    dest_range=None,
    next_hop_instance=None,
    instance_zone=None,
    tags=None,
    network=None,
    priority=None,
):
    """
    Create a route to send traffic destined to the Internet through your
    gateway instance

    credential_file : string
        File location of application default credential. For more information,
        refer: https://developers.google.com/identity/protocols/application-default-credentials
    project_id : string
        Project ID where instance and network resides.
    name : string
        name of the route to create
    next_hop_instance : string
        the name of an instance that should handle traffic matching this route.
    instance_zone : string
        zone where instance("next_hop_instance") resides
    network : string
        Specifies the network to which the route will be applied.
    dest_range : string
        The destination range of outgoing packets that the route will apply to.
    tags : list
        (optional) Identifies the set of instances that this route will apply to.
    priority : int
        (optional) Specifies the priority of this route relative to other routes.
        default=1000

    CLI Example:

    salt 'salt-master.novalocal' gcp.route_create
        credential_file=/root/secret_key.json
        project_id=cp100-170315
        name=derby-db-route1
        next_hop_instance=instance-1
        instance_zone=us-central1-a
        network=default
        dest_range=0.0.0.0/0
        tags=['no-ip']
        priority=700

    In above example, the instances which are having tag "no-ip" will route the
    packet to instance "instance-1"(if packet is intended to other network)
    """

    credentials = oauth2client.service_account.ServiceAccountCredentials.from_json_keyfile_name(
        credential_file
    )
    service = googleapiclient.discovery.build("compute", "v1", credentials=credentials)
    routes = service.routes()

    routes_config = {
        "name": six.text_type(name),
        "network": _get_network(project_id, six.text_type(network), service=service)[
            "selfLink"
        ],
        "destRange": six.text_type(dest_range),
        "nextHopInstance": _get_instance(
            project_id, instance_zone, next_hop_instance, service=service
        )["selfLink"],
        "tags": tags,
        "priority": priority,
    }
    route_create_request = routes.insert(project=project_id, body=routes_config)
    return route_create_request.execute()
<commit_msg>Drop Py2 and six on salt/modules/gcp_addon.py<commit_after>"""
A route is a rule that specifies how certain packets should be handled by the
virtual network. Routes are associated with virtual machine instances by tag,
and the set of routes for a particular VM is called its routing table.
For each packet leaving a virtual machine, the system searches that machine's
routing table for a single best matching route.

.. versionadded:: 2018.3.0

This module will create a route to send traffic destined to the Internet
through your gateway instance.

:codeauthor: `Pratik Bandarkar <pratik.bandarkar@gmail.com>`
:maturity:   new
:depends:    google-api-python-client
:platform:   Linux

"""

import logging

try:
    import googleapiclient.discovery
    import oauth2client.service_account

    HAS_LIB = True
except ImportError:
    HAS_LIB = False

log = logging.getLogger(__name__)

__virtualname__ = "gcp"

def __virtual__():
    """
    Check for googleapiclient api
    """
    if HAS_LIB is False:
        return (
            False,
            "Required dependencies 'googleapiclient' and/or 'oauth2client' were not found.",
        )
    return __virtualname__

def _get_network(project_id, network_name, service):
    """
    Fetch network selfLink from network name.
    """
    return service.networks().get(project=project_id, network=network_name).execute()

def _get_instance(project_id, instance_zone, name, service):
    """
    Get instance details
    """
    return (
        service.instances()
        .get(project=project_id, zone=instance_zone, instance=name)
        .execute()
    )

def route_create(
    credential_file=None,
    project_id=None,
    name=None,
    dest_range=None,
    next_hop_instance=None,
    instance_zone=None,
    tags=None,
    network=None,
    priority=None,
):
    """
    Create a route to send traffic destined to the Internet through your
    gateway instance

    credential_file : string
        File location of application default credential. For more information,
        refer: https://developers.google.com/identity/protocols/application-default-credentials
    project_id : string
        Project ID where instance and network resides.
    name : string
        name of the route to create
    next_hop_instance : string
        the name of an instance that should handle traffic matching this route.
    instance_zone : string
        zone where instance("next_hop_instance") resides
    network : string
        Specifies the network to which the route will be applied.
    dest_range : string
        The destination range of outgoing packets that the route will apply to.
    tags : list
        (optional) Identifies the set of instances that this route will apply to.
    priority : int
        (optional) Specifies the priority of this route relative to other routes.
        default=1000

    CLI Example:

    salt 'salt-master.novalocal' gcp.route_create
        credential_file=/root/secret_key.json
        project_id=cp100-170315
        name=derby-db-route1
        next_hop_instance=instance-1
        instance_zone=us-central1-a
        network=default
        dest_range=0.0.0.0/0
        tags=['no-ip']
        priority=700

    In above example, the instances which are having tag "no-ip" will route the
    packet to instance "instance-1"(if packet is intended to other network)
    """

    credentials = oauth2client.service_account.ServiceAccountCredentials.from_json_keyfile_name(
        credential_file
    )
    service = googleapiclient.discovery.build("compute", "v1", credentials=credentials)
    routes = service.routes()

    routes_config = {
        "name": str(name),
        "network": _get_network(project_id, str(network), service=service)["selfLink"],
        "destRange": str(dest_range),
        "nextHopInstance": _get_instance(
            project_id, instance_zone, next_hop_instance, service=service
        )["selfLink"],
        "tags": tags,
        "priority": priority,
    }
    route_create_request = routes.insert(project=project_id, body=routes_config)
    return route_create_request.execute()
<|endoftext|>


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

'''
Manage Chocolatey package installs
.. versionadded:: 2016.3.0
'''

# Import Python libs
from __future__ import absolute_import

# Import Salt libs
import salt.utils.data
import salt.utils.versions
from salt.exceptions import SaltInvocationError

def __virtual__():
    '''
    Load only if chocolatey is loaded
    '''
    return 'chocolatey' if 'chocolatey.install' in __salt__ else False

def installed(name, version=None, source=None, force=False, pre_versions=False,
              install_args=None, override_args=False, force_x86=False,
              package_args=None, allow_multiple=False):
    '''
    Installs a package if not already installed

    Args:

        name (str):
            The name of the package to be installed. Required.

        version (str):
            Install a specific version of the package. Defaults to latest
            version. If the version is different to the one installed then the
            specified version will be installed. Default is None.

        source (str):
            Chocolatey repository (directory, share or remote URL, feed).
            Defaults to the official Chocolatey feed. Default is None.

        force (bool):
            Reinstall the current version of an existing package. Do not use
            with ``allow_multiple``. Default is False.

        pre_versions (bool):
            Include pre-release packages. Default is False.

        install_args (str):
            Install arguments you want to pass to the installation process, i.e
            product key or feature list. Default is None.

        override_args (bool):
            Set to True if you want to override the original install arguments
            (for the native installer) in the package and use your own. When
            this is set to False install_args will be appended to the end of the
            default arguments. Default is False.

        force_x86 (bool):
            Force x86 (32bit) installation on 64 bit systems. Default is False.

        package_args (str):
            Arguments you want to pass to the package. Default is None.

        allow_multiple (bool):
            Allow mulitiple versions of the package to be installed. Do not use
            with ``force``. Does not work with all packages. Default is False.

            .. versionadded:: 2017.7.0

    .. code-block:: yaml

        Installsomepackage:
          chocolatey.installed:
            - name: packagename
            - version: '12.04'
            - source: 'mychocolatey/source'
            - force: True
    '''
    if force and allow_multiple:
        raise SaltInvocationError(
            'Cannot use \'force\' in conjunction with \'allow_multiple\'')

    ret = {'name': name,
           'result': True,
           'changes': {},
           'comment': ''}

    # Get list of currently installed packages
    pre_install = __salt__['chocolatey.list'](local_only=True)

    # Determine action
    # Package not installed
    if name.lower() not in [package.lower() for package in pre_install.keys()]:
        if version:
            ret['changes'] = {name: 'Version {0} will be installed'
                                    ''.format(version)}
        else:
            ret['changes'] = {name: 'Latest version will be installed'}

    # Package installed
    else:
        version_info = __salt__['chocolatey.version'](name, check_remote=True)

        full_name = name
        for pkg in version_info:
            if name.lower() == pkg.lower():
                full_name = pkg

        installed_version = version_info[full_name]['installed'][0]

        if version:
            if salt.utils.versions.compare(
                    ver1=installed_version, oper="==", ver2=version):
                if force:
                    ret['changes'] = {
                        name: 'Version {0} will be reinstalled'.format(version)}
                    ret['comment'] = 'Reinstall {0} {1}' \
                                     ''.format(full_name, version)
                else:
                    ret['comment'] = '{0} {1} is already installed' \
                                     ''.format(name, version)
                    if __opts__['test']:
                        ret['result'] = None
                    return ret
            else:
                if allow_multiple:
                    ret['changes'] = {
                        name: 'Version {0} will be installed side by side with '
                              'Version {1} if supported'
                              ''.format(version, installed_version)}
                    ret['comment'] = 'Install {0} {1} side-by-side with {0} {2}' \
                                     ''.format(full_name, version, installed_version)
                else:
                    ret['changes'] = {
                        name: 'Version {0} will be installed over Version {1} '
                              ''.format(version, installed_version)}
                    ret['comment'] = 'Install {0} {1} over {0} {2}' \
                                     ''.format(full_name, version, installed_version)
                    force = True
        else:
            version = installed_version
            if force:
                ret['changes'] = {
                    name: 'Version {0} will be reinstalled'.format(version)}
                ret['comment'] = 'Reinstall {0} {1}' \
                                 ''.format(full_name, version)
            else:
                ret['comment'] = '{0} {1} is already installed' \
                                 ''.format(name, version)
                if __opts__['test']:
                    ret['result'] = None
                return ret

    if __opts__['test']:
        ret['result'] = None
        ret['comment'] = 'The installation was tested'
        return ret

    # Install the package
    result = __salt__['chocolatey.install'](name=name,
                                            version=version,
                                            source=source,
                                            force=force,
                                            pre_versions=pre_versions,
                                            install_args=install_args,
                                            override_args=override_args,
                                            force_x86=force_x86,
                                            package_args=package_args,
                                            allow_multiple=allow_multiple)

    if 'Running chocolatey failed' not in result:
        ret['result'] = True
    else:
        ret['result'] = False

    if not ret['result']:
        ret['comment'] = 'Failed to install the package {0}'.format(name)

    # Get list of installed packages after 'chocolatey.install'
    post_install = __salt__['chocolatey.list'](local_only=True)

    ret['changes'] = salt.utils.data.compare_dicts(pre_install, post_install)

    return ret

def uninstalled(name, version=None, uninstall_args=None, override_args=False):
    '''
    Uninstalls a package

    name
      The name of the package to be uninstalled

    version
      Uninstalls a specific version of the package. Defaults to latest
      version installed.

    uninstall_args
      A list of uninstall arguments you want to pass to the uninstallation
      process i.e product key or feature list

    override_args
      Set to true if you want to override the original uninstall arguments (
      for the native uninstaller)in the package and use your own.
      When this is set to False uninstall_args will be appended to the end of
      the default arguments

    .. code-block: yaml

      Removemypackage:
        chocolatey.uninstalled:
          - name: mypackage
          - version: '21.5'

    '''

    ret = {'name': name,
           'result': True,
           'changes': {},
           'comment': ''}

    # Get list of currently installed packages
    pre_uninstall = __salt__['chocolatey.list'](local_only=True)

    # Determine if package is installed
    if name.lower() in [package.lower() for package in pre_uninstall.keys()]:
        try:
            ret['changes'] = {name: '{0} version {1} will be removed'
                                    ''.format(name, pre_uninstall[name][0])}
        except KeyError:
            ret['changes'] = {name: '{0} will be removed'
                                    ''.format(name)}
    else:
        ret['comment'] = 'The package {0} is not installed'.format(name)
        return ret

    if __opts__['test']:
        ret['result'] = None
        ret['comment'] = 'The uninstall was tested'
        return ret

    # Uninstall the package
    result = __salt__['chocolatey.uninstall'](name,
                                              version,
                                              uninstall_args,
                                              override_args)

    if 'Running chocolatey failed' not in result:
        ret['result'] = True
    else:
        ret['result'] = False

    if not ret['result']:
        ret['comment'] = 'Failed to uninstall the package {0}'.format(name)

    # Get list of installed packages after 'chocolatey.uninstall'
    post_uninstall = __salt__['chocolatey.list'](local_only=True)

    ret['changes'] = salt.utils.data.compare_dicts(pre_uninstall, post_uninstall)

    return ret

def upgraded(name,
             version=None,
             source=None,
             force=False,
             pre_versions=False,
             install_args=None,
             override_args=False,
             force_x86=False,
             package_args=None):
    '''
    Upgrades a package. Will install the package if not installed.

    .. versionadded: 2017.7.3

    Args:

        name (str):
            The name of the package to be installed. Required.

        version (str):
            Install a specific version of the package. Defaults to latest
            version. If the version is greater than the one installed then the
            specified version will be installed. Default is ``None``.

        source (str):
            Chocolatey repository (directory, share or remote URL, feed).
            Defaults to the official Chocolatey feed. Default is ``None``.

        force (bool):
            ``True`` will reinstall an existing package with the same version.
            Default is ``False``.

        pre_versions (bool):
            ``True`` will nclude pre-release packages. Default is ``False``.

        install_args (str):
            Install arguments you want to pass to the installation process, i.e
            product key or feature list. Default is ``None``.

        override_args (bool):
            ``True`` will override the original install arguments (for the
            native installer) in the package and use those specified in
            ``install_args``. ``False`` will append install_args to the end of
            the default arguments. Default is ``False``.

        force_x86 (bool):
            ``True`` forces 32bit installation on 64 bit systems. Default is
            ``False``.

        package_args (str):
            Arguments you want to pass to the package. Default is ``None``.

    .. code-block:: yaml

        upgrade_some_package:
          chocolatey.upgraded:
            - name: packagename
            - version: '12.04'
            - source: 'mychocolatey/source'
    '''
    ret = {'name': name,
           'result': True,
           'changes': {},
           'pchanges': {},
           'comment': ''}

    # Get list of currently installed packages
    pre_install = __salt__['chocolatey.list'](local_only=True)

    # Determine if there are changes
    # Package not installed
    if name.lower() not in [package.lower() for package in pre_install.keys()]:
        if version:
            ret['pchanges'] = {name: 'Version {0} will be installed'
                                     ''.format(version)}
            ret['comment'] = 'Install version {0}'.format(version)
        else:
            ret['pchanges'] = {name: 'Latest version will be installed'}
            ret['comment'] = 'Install latest version'

    # Package installed
    else:
        version_info = __salt__['chocolatey.version'](name, check_remote=True)

        # Get the actual full name out of version_info
        full_name = name
        for pkg in version_info:
            if name.lower() == pkg.lower():
                full_name = pkg

        installed_version = version_info[full_name]['installed'][0]

        # If version is not passed, use available... if available is available
        if not version:
            if 'available' in version_info[full_name]:
                version = version_info[full_name]['available'][0]

        if version:
            # If installed version and new version are the same
            if salt.utils.compare_versions(
                    ver1=installed_version,
                    oper="==",
                    ver2=version):
                if force:
                    ret['pchanges'] = {
                        name: 'Version {0} will be reinstalled'.format(version)}
                    ret['comment'] = 'Reinstall {0} {1}' \
                                     ''.format(full_name, version)
                else:
                    ret['comment'] = '{0} {1} is already installed' \
                                     ''.format(name, installed_version)
            else:
                # If installed version is older than new version
                if salt.utils.compare_versions(
                        ver1=installed_version, oper="<", ver2=version):
                    ret['pchanges'] = {
                        name: 'Version {0} will be upgraded to Version {1} '
                              ''.format(installed_version, version)}
                    ret['comment'] = 'Upgrade {0} {1} to {2}' \
                                     ''.format(full_name, installed_version, version)
                # If installed version is newer than new version
                else:
                    ret['comment'] = '{0} {1} (newer) is already installed' \
                                     ''.format(name, installed_version)
        # Catch all for a condition where version is not passed and there is no
        # available version
        else:
            ret['comment'] = 'No version found to install'

    # Return if `test=True`
    if __opts__['test']:
        ret['result'] = None
        return ret

    # Return if there are no changes to be made
    if not ret['pchanges']:
        return ret

    # Install the package
    result = __salt__['chocolatey.upgrade'](name=name,
                                            version=version,
                                            source=source,
                                            force=force,
                                            pre_versions=pre_versions,
                                            install_args=install_args,
                                            override_args=override_args,
                                            force_x86=force_x86,
                                            package_args=package_args)

    if 'Running chocolatey failed' not in result:
        ret['comment'] = 'Package {0} upgraded successfully'.format(name)
        ret['result'] = True
    else:
        ret['comment'] = 'Failed to upgrade the package {0}'.format(name)
        ret['result'] = False

    # Get list of installed packages after 'chocolatey.install'
    post_install = __salt__['chocolatey.list'](local_only=True)

    ret['changes'] = salt.utils.compare_dicts(pre_install, post_install)

    return ret
<commit_msg>Changed versionadded to Oxygen<commit_after># -*- coding: utf-8 -*-

'''
Manage Chocolatey package installs
.. versionadded:: 2016.3.0
'''

# Import Python libs
from __future__ import absolute_import

# Import Salt libs
import salt.utils.data
import salt.utils.versions
from salt.exceptions import SaltInvocationError

def __virtual__():
    '''
    Load only if chocolatey is loaded
    '''
    return 'chocolatey' if 'chocolatey.install' in __salt__ else False

def installed(name, version=None, source=None, force=False, pre_versions=False,
              install_args=None, override_args=False, force_x86=False,
              package_args=None, allow_multiple=False):
    '''
    Installs a package if not already installed

    Args:

        name (str):
            The name of the package to be installed. Required.

        version (str):
            Install a specific version of the package. Defaults to latest
            version. If the version is different to the one installed then the
            specified version will be installed. Default is None.

        source (str):
            Chocolatey repository (directory, share or remote URL, feed).
            Defaults to the official Chocolatey feed. Default is None.

        force (bool):
            Reinstall the current version of an existing package. Do not use
            with ``allow_multiple``. Default is False.

        pre_versions (bool):
            Include pre-release packages. Default is False.

        install_args (str):
            Install arguments you want to pass to the installation process, i.e
            product key or feature list. Default is None.

        override_args (bool):
            Set to True if you want to override the original install arguments
            (for the native installer) in the package and use your own. When
            this is set to False install_args will be appended to the end of the
            default arguments. Default is False.

        force_x86 (bool):
            Force x86 (32bit) installation on 64 bit systems. Default is False.

        package_args (str):
            Arguments you want to pass to the package. Default is None.

        allow_multiple (bool):
            Allow mulitiple versions of the package to be installed. Do not use
            with ``force``. Does not work with all packages. Default is False.

            .. versionadded:: 2017.7.0

    .. code-block:: yaml

        Installsomepackage:
          chocolatey.installed:
            - name: packagename
            - version: '12.04'
            - source: 'mychocolatey/source'
            - force: True
    '''
    if force and allow_multiple:
        raise SaltInvocationError(
            'Cannot use \'force\' in conjunction with \'allow_multiple\'')

    ret = {'name': name,
           'result': True,
           'changes': {},
           'comment': ''}

    # Get list of currently installed packages
    pre_install = __salt__['chocolatey.list'](local_only=True)

    # Determine action
    # Package not installed
    if name.lower() not in [package.lower() for package in pre_install.keys()]:
        if version:
            ret['changes'] = {name: 'Version {0} will be installed'
                                    ''.format(version)}
        else:
            ret['changes'] = {name: 'Latest version will be installed'}

    # Package installed
    else:
        version_info = __salt__['chocolatey.version'](name, check_remote=True)

        full_name = name
        for pkg in version_info:
            if name.lower() == pkg.lower():
                full_name = pkg

        installed_version = version_info[full_name]['installed'][0]

        if version:
            if salt.utils.versions.compare(
                    ver1=installed_version, oper="==", ver2=version):
                if force:
                    ret['changes'] = {
                        name: 'Version {0} will be reinstalled'.format(version)}
                    ret['comment'] = 'Reinstall {0} {1}' \
                                     ''.format(full_name, version)
                else:
                    ret['comment'] = '{0} {1} is already installed' \
                                     ''.format(name, version)
                    if __opts__['test']:
                        ret['result'] = None
                    return ret
            else:
                if allow_multiple:
                    ret['changes'] = {
                        name: 'Version {0} will be installed side by side with '
                              'Version {1} if supported'
                              ''.format(version, installed_version)}
                    ret['comment'] = 'Install {0} {1} side-by-side with {0} {2}' \
                                     ''.format(full_name, version, installed_version)
                else:
                    ret['changes'] = {
                        name: 'Version {0} will be installed over Version {1} '
                              ''.format(version, installed_version)}
                    ret['comment'] = 'Install {0} {1} over {0} {2}' \
                                     ''.format(full_name, version, installed_version)
                    force = True
        else:
            version = installed_version
            if force:
                ret['changes'] = {
                    name: 'Version {0} will be reinstalled'.format(version)}
                ret['comment'] = 'Reinstall {0} {1}' \
                                 ''.format(full_name, version)
            else:
                ret['comment'] = '{0} {1} is already installed' \
                                 ''.format(name, version)
                if __opts__['test']:
                    ret['result'] = None
                return ret

    if __opts__['test']:
        ret['result'] = None
        ret['comment'] = 'The installation was tested'
        return ret

    # Install the package
    result = __salt__['chocolatey.install'](name=name,
                                            version=version,
                                            source=source,
                                            force=force,
                                            pre_versions=pre_versions,
                                            install_args=install_args,
                                            override_args=override_args,
                                            force_x86=force_x86,
                                            package_args=package_args,
                                            allow_multiple=allow_multiple)

    if 'Running chocolatey failed' not in result:
        ret['result'] = True
    else:
        ret['result'] = False

    if not ret['result']:
        ret['comment'] = 'Failed to install the package {0}'.format(name)

    # Get list of installed packages after 'chocolatey.install'
    post_install = __salt__['chocolatey.list'](local_only=True)

    ret['changes'] = salt.utils.data.compare_dicts(pre_install, post_install)

    return ret

def uninstalled(name, version=None, uninstall_args=None, override_args=False):
    '''
    Uninstalls a package

    name
      The name of the package to be uninstalled

    version
      Uninstalls a specific version of the package. Defaults to latest
      version installed.

    uninstall_args
      A list of uninstall arguments you want to pass to the uninstallation
      process i.e product key or feature list

    override_args
      Set to true if you want to override the original uninstall arguments (
      for the native uninstaller)in the package and use your own.
      When this is set to False uninstall_args will be appended to the end of
      the default arguments

    .. code-block: yaml

      Removemypackage:
        chocolatey.uninstalled:
          - name: mypackage
          - version: '21.5'

    '''

    ret = {'name': name,
           'result': True,
           'changes': {},
           'comment': ''}

    # Get list of currently installed packages
    pre_uninstall = __salt__['chocolatey.list'](local_only=True)

    # Determine if package is installed
    if name.lower() in [package.lower() for package in pre_uninstall.keys()]:
        try:
            ret['changes'] = {name: '{0} version {1} will be removed'
                                    ''.format(name, pre_uninstall[name][0])}
        except KeyError:
            ret['changes'] = {name: '{0} will be removed'
                                    ''.format(name)}
    else:
        ret['comment'] = 'The package {0} is not installed'.format(name)
        return ret

    if __opts__['test']:
        ret['result'] = None
        ret['comment'] = 'The uninstall was tested'
        return ret

    # Uninstall the package
    result = __salt__['chocolatey.uninstall'](name,
                                              version,
                                              uninstall_args,
                                              override_args)

    if 'Running chocolatey failed' not in result:
        ret['result'] = True
    else:
        ret['result'] = False

    if not ret['result']:
        ret['comment'] = 'Failed to uninstall the package {0}'.format(name)

    # Get list of installed packages after 'chocolatey.uninstall'
    post_uninstall = __salt__['chocolatey.list'](local_only=True)

    ret['changes'] = salt.utils.data.compare_dicts(pre_uninstall, post_uninstall)

    return ret

def upgraded(name,
             version=None,
             source=None,
             force=False,
             pre_versions=False,
             install_args=None,
             override_args=False,
             force_x86=False,
             package_args=None):
    '''
    Upgrades a package. Will install the package if not installed.

    .. versionadded: Oxygen

    Args:

        name (str):
            The name of the package to be installed. Required.

        version (str):
            Install a specific version of the package. Defaults to latest
            version. If the version is greater than the one installed then the
            specified version will be installed. Default is ``None``.

        source (str):
            Chocolatey repository (directory, share or remote URL, feed).
            Defaults to the official Chocolatey feed. Default is ``None``.

        force (bool):
            ``True`` will reinstall an existing package with the same version.
            Default is ``False``.

        pre_versions (bool):
            ``True`` will nclude pre-release packages. Default is ``False``.

        install_args (str):
            Install arguments you want to pass to the installation process, i.e
            product key or feature list. Default is ``None``.

        override_args (bool):
            ``True`` will override the original install arguments (for the
            native installer) in the package and use those specified in
            ``install_args``. ``False`` will append install_args to the end of
            the default arguments. Default is ``False``.

        force_x86 (bool):
            ``True`` forces 32bit installation on 64 bit systems. Default is
            ``False``.

        package_args (str):
            Arguments you want to pass to the package. Default is ``None``.

    .. code-block:: yaml

        upgrade_some_package:
          chocolatey.upgraded:
            - name: packagename
            - version: '12.04'
            - source: 'mychocolatey/source'
    '''
    ret = {'name': name,
           'result': True,
           'changes': {},
           'pchanges': {},
           'comment': ''}

    # Get list of currently installed packages
    pre_install = __salt__['chocolatey.list'](local_only=True)

    # Determine if there are changes
    # Package not installed
    if name.lower() not in [package.lower() for package in pre_install.keys()]:
        if version:
            ret['pchanges'] = {name: 'Version {0} will be installed'
                                     ''.format(version)}
            ret['comment'] = 'Install version {0}'.format(version)
        else:
            ret['pchanges'] = {name: 'Latest version will be installed'}
            ret['comment'] = 'Install latest version'

    # Package installed
    else:
        version_info = __salt__['chocolatey.version'](name, check_remote=True)

        # Get the actual full name out of version_info
        full_name = name
        for pkg in version_info:
            if name.lower() == pkg.lower():
                full_name = pkg

        installed_version = version_info[full_name]['installed'][0]

        # If version is not passed, use available... if available is available
        if not version:
            if 'available' in version_info[full_name]:
                version = version_info[full_name]['available'][0]

        if version:
            # If installed version and new version are the same
            if salt.utils.compare_versions(
                    ver1=installed_version,
                    oper="==",
                    ver2=version):
                if force:
                    ret['pchanges'] = {
                        name: 'Version {0} will be reinstalled'.format(version)}
                    ret['comment'] = 'Reinstall {0} {1}' \
                                     ''.format(full_name, version)
                else:
                    ret['comment'] = '{0} {1} is already installed' \
                                     ''.format(name, installed_version)
            else:
                # If installed version is older than new version
                if salt.utils.compare_versions(
                        ver1=installed_version, oper="<", ver2=version):
                    ret['pchanges'] = {
                        name: 'Version {0} will be upgraded to Version {1} '
                              ''.format(installed_version, version)}
                    ret['comment'] = 'Upgrade {0} {1} to {2}' \
                                     ''.format(full_name, installed_version, version)
                # If installed version is newer than new version
                else:
                    ret['comment'] = '{0} {1} (newer) is already installed' \
                                     ''.format(name, installed_version)
        # Catch all for a condition where version is not passed and there is no
        # available version
        else:
            ret['comment'] = 'No version found to install'

    # Return if `test=True`
    if __opts__['test']:
        ret['result'] = None
        return ret

    # Return if there are no changes to be made
    if not ret['pchanges']:
        return ret

    # Install the package
    result = __salt__['chocolatey.upgrade'](name=name,
                                            version=version,
                                            source=source,
                                            force=force,
                                            pre_versions=pre_versions,
                                            install_args=install_args,
                                            override_args=override_args,
                                            force_x86=force_x86,
                                            package_args=package_args)

    if 'Running chocolatey failed' not in result:
        ret['comment'] = 'Package {0} upgraded successfully'.format(name)
        ret['result'] = True
    else:
        ret['comment'] = 'Failed to upgrade the package {0}'.format(name)
        ret['result'] = False

    # Get list of installed packages after 'chocolatey.install'
    post_install = __salt__['chocolatey.list'](local_only=True)

    ret['changes'] = salt.utils.compare_dicts(pre_install, post_install)

    return ret
<|endoftext|>


<commit_before>import re
import numpy as nm

from base import Struct, IndexedStruct, dict_to_struct, pause, output, copy,\
     import_file, assert_, get_default
from reader import Reader

_required = ['filename_mesh', 'field_[0-9]+|fields',
             'ebc_[0-9]+|ebcs', 'fe', 'equations',
             'region_[0-9]+|regions', 'variable_[0-9]+|variables',
             'material_[0-9]+|materials', 'integral_[0-9]+|integrals',
             'solver_[0-9]+|solvers']
_other = ['epbc_[0-9]+|epbcs', 'lcbc_[0-9]+|lcbcs', 'nbc_[0-9]+|nbcs',
          'ic_[0-9]+|ics', 'options']

##
# c: 19.02.2008, r: 19.02.2008
def get_standard_keywords():
    return copy( _required ), copy( _other )

##
# c: 10.04.2008, r: 10.04.2008
def tuple_to_conf( name, vals, order ):
    conf = Struct( name = name )
    for ii, key in enumerate( order ):
        setattr( conf, key, vals[ii] )
    return conf

##
# Short syntax: key is suffixed with '__<number>' to prevent collisions with
# long syntax keys -> both cases can be used in a single input.
def transform_variables( adict ):
    d2 = {}
    for ii, (key, conf) in enumerate( adict.iteritems() ):
        if isinstance( conf, tuple ):
            c2 = tuple_to_conf( key, conf, ['kind', 'field'] )
            if len( conf ) >= 3:
                kind = c2.kind.split()[0]
                if kind == 'unknown':
                    c2.order = conf[2]
                elif kind == 'test':
                    c2.dual = conf[2]
                elif kind == 'parameter':
                    if isinstance(conf[2], str):
                        c2.like = conf[2]
                    else:
                        c2.like = None
                        c2.special = conf[2]
                if len( conf ) == 4:
                    c2.history = conf[3]
            d2['variable_%s__%d' % (c2.name, ii)] = c2
        else:
            c2 = transform_to_struct_1( conf )
            d2['variable_'+c2.name] = c2
    return d2

def transform_conditions( adict, prefix ):
    d2 = {}
    for ii, (key, conf) in enumerate( adict.iteritems() ):
        if isinstance( conf, tuple ):
            c2 = tuple_to_conf( key, conf, ['region', 'dofs'] )
            if len( conf ) == 3:
                c2.filename = conf[2]
            d2['%s_%s__%d' % (prefix, c2.name, ii)] = c2
        else:
            c2 = transform_to_struct_1( conf )
            d2['%s_%s' % (prefix, c2.name)] = c2
    return d2

def transform_ebcs( adict ):
    return transform_conditions( adict, 'ebc' )

def transform_ics( adict ):
    return transform_conditions( adict, 'ic' )

def transform_lcbcs( adict ):
    return transform_conditions( adict, 'lcbc' )

def transform_regions( adict ):
    d2 = {}
    for ii, (key, conf) in enumerate( adict.iteritems() ):
        if isinstance( conf, tuple ):
            c2 = tuple_to_conf( key, conf, ['select', 'flags'] )
            for flag, val in c2.flags.iteritems():
                setattr( c2, flag, val )
            delattr( c2, 'flags' )
            d2['region_%s__%d' % (c2.name, ii)] = c2
        else:
            c2 = transform_to_struct_1( conf )
            d2['region_'+c2.name] = c2
    return d2

def transform_integrals( adict ):
    d2 = {}
    for ii, (key, conf) in enumerate( adict.iteritems() ):
        if isinstance( conf, tuple ):
            c2 = tuple_to_conf( key, conf, ['kind', 'quadrature'] )
            d2['integral_%s__%d' % (c2.name, ii)] = c2
        else:
            c2 = transform_to_struct_1( conf )
            d2['integral_'+c2.name] = c2
    return d2

def transform_fields( adict ):
    dtypes = {'real' : nm.float64, 'complex' : nm.complex128}
    d2 = {}
    for ii, (key, conf) in enumerate( adict.iteritems() ):
        if isinstance( conf, tuple ):
            c2 = tuple_to_conf( key, conf, ['dim', 'type', 'domain','bases'] )
            setattr( c2, 'dtype', dtypes[c2.type] )
            d2['field_%s__%d' % (c2.name, ii)] = c2
        else:
            c2 = transform_to_struct_1( conf )
            c2.set_default_attr('type', 'real')
            setattr( c2, 'dtype', dtypes[c2.type] )
            d2['field_'+c2.name] = c2
    return d2

def transform_materials( adict ):
    d2 = {}
    for ii, (key, conf) in enumerate( adict.iteritems() ):
        if isinstance( conf, tuple ):
            c2 = tuple_to_conf( key, conf, ['mode', 'region', 'params'] )
            dpar = {}
            dpar['name'] = key
            dpar['mode'] = c2.mode
            dpar['region'] = c2.region
            dpar.update( c2.params )
            d2['material_%s__%d' % (c2.name, ii)] = dpar
        else:
            d2['material_'+conf['name']] = conf
    return d2

def transform_solvers( adict ):
    d2 = {}
    for ii, (key, conf) in enumerate( adict.iteritems() ):
        if isinstance( conf, tuple ):
            c2 = tuple_to_conf( key, conf, ['kind','params'] )
            for param, val in c2.params.iteritems():
                setattr( c2, param, val )
            delattr( c2, 'params' )
            d2['solvers_%s__%d' % (c2.name, ii)] = c2
        else:
            c2 = transform_to_struct_1( conf )
            d2['solvers_'+c2.name] = c2
    return d2

##
# c: 20.06.2007, r: 18.02.2008
def transform_to_struct_1( adict ):
    return dict_to_struct( adict, flag = (1,) )
def transform_to_i_struct_1( adict ):
    return dict_to_struct( adict, flag = (1,), constructor = IndexedStruct )
def transform_to_struct_01( adict ):
    return dict_to_struct( adict, flag = (0,1) )
def transform_to_struct_10( adict ):
    return dict_to_struct( adict, flag = (1,0) )

transforms = {
    'options'   : transform_to_i_struct_1,
    'solvers'   : transform_solvers,
    'integrals' : transform_integrals,
    'opt'       : transform_to_struct_1,
    'fe'        : transform_to_struct_1,
    'regions'   : transform_regions,
    'shape_opt' : transform_to_struct_10,
    'fields'    : transform_fields,
    'variables' : transform_variables,
    'ebcs'      : transform_ebcs,
    'epbcs'     : transform_to_struct_01,
    'nbcs'      : transform_to_struct_01,
    'lcbcs'     : transform_lcbcs,
    'ics'       : transform_ics,
    'materials' : transform_materials,
}

##
# 27.10.2005, c
class ProblemConf( Struct ):
    """
    Problem configuration, corresponding to an input (problem description
    file). It validates the input using lists of required and other keywords
    that have to/can appear in the input. Default keyword lists can be obtained
    by sfepy.base.conf.get_standard_keywords().

    ProblemConf instance is used to construct a ProblemDefinition instance via
    ProblemDefinition.from_conf( conf ).
    """
    ##
    # c: 25.07.2006, r: 10.07.2008
    def from_file( filename, required = None, other = None ):
        """
        Loads the problem definition from a file.

        The filename can either contain plain definitions, or it can contain
        the define() function, in which case it will be called to return the
        input definitions.

        The job of the define() function is to return a dictionary of
        parameters. How the dictionary is constructed is not our business, but
        the usual way is to simply have a function define() along these lines
        in the input file:

            def define():
                options = {
                    'save_eig_vectors' : None,
                    'eigen_solver' : 'eigen1',
                }
                region_2 = {
                    'name' : 'Surface',
                    'select' : 'nodes of surface',
                }
                return locals()

        """
        funmod = import_file( filename )
        obj = ProblemConf()
        if "define" in funmod.__dict__:
            define_dict = funmod.__dict__["define"]()
        else:
            define_dict = funmod.__dict__

        obj.__dict__.update( define_dict )

        obj.setup( define_dict, funmod, filename, required, other )

        return obj
    from_file = staticmethod( from_file )

    def from_module( module, required = None, other = None ):
        obj = ProblemConf()
        obj.__dict__.update( module.__dict__ )

        obj.setup( funmod = module, required = required, other = other )

        return obj
    from_module = staticmethod( from_module )

    def from_dict( dict_, funmod, required = None, other = None ):
        obj = ProblemConf()
        obj.__dict__.update( dict_ )

        obj.setup( funmod = funmod, required = required, other = other )

        return obj
    from_dict = staticmethod( from_dict )

    def setup( self, define_dict = None, funmod = None, filename = None,
               required = None, other = None ):

        define_dict = get_default( define_dict, self.__dict__ )

        self._filename = filename

        other_missing = self.validate( required = required, other = other )

        self.transform_input_trivial()
        self._raw = {}
        for key, val in define_dict.iteritems():
            if isinstance( val, dict ):
                self._raw[key] = copy( val )

        self.transform_input()
        self.funmod = funmod

    ##
    # 27.10.2005, c
    # 19.09.2006
    # 05.06.2007
    def _validate_helper( self, items, but_nots ):
        keys = self.__dict__.keys()
        left_over = keys[:]
        if but_nots is not None:
            for item in but_nots:
                match = re.compile( '^' + item + '$' ).match
                for key in keys:
                    if match( key ):
                        left_over.remove( key )

        missing = []
        if items is not None:
            for item in items:
                found = False
                match = re.compile( '^' + item + '$' ).match
                for key in keys:
                    if match( key ):
                        found = True
                        left_over.remove( key )
                if not found:
                    missing.append( item )
        return left_over, missing

    ##
    # c: 27.10.2005, r: 11.07.2008
    def validate( self, required = None, other = None ):
        required_left_over, required_missing \
                          = self._validate_helper( required, other )
        other_left_over, other_missing \
                       = self._validate_helper( other, required )

        assert_( required_left_over == other_left_over )

        err = False
        if required_missing:
            err = True
            output( 'error: required missing:', required_missing )

        if other_left_over:
            output( 'left over:', other_left_over )

        if err:
            raise ValueError

        return other_missing

    ##
    # c: 31.10.2005, r: 10.07.2008
    def transform_input_trivial( self ):
        """Trivial input transformations."""

        ##
        # Unordered inputs.
        tr_list = ['([a-zA-Z0-9]+)_[0-9]+']
        # Keywords not in 'required', but needed even empty (e.g. for run_tests).
        for key in transforms.keys():
            if not self.__dict__.has_key( key ):
                self.__dict__[key] = {}

        keys = self.__dict__.keys()
        for item in tr_list:
            match = re.compile( item ).match
            for key in keys:
                obj = match( key )
                if obj:
                    new = obj.group( 1 ) + 's'
                    result = {key : self.__dict__[key]}
                    try:
                        self.__dict__[new].update( result )
                    except:
                        self.__dict__[new] = result

                    del self.__dict__[key]

    def transform_input( self ):
        keys = self.__dict__.keys()
        for key, transform in transforms.iteritems():
            if not key in keys: continue
            self.__dict__[key] = transform( self.__dict__[key] )

    def get_raw( self, key = None ):
        if key is None:
            return self._raw
        else:
            return self._raw[key]

    def edit( self, key, newval ):
        self.__dict__[key] = transforms[key]( newval )
<commit_msg>fixed parameter variables for for 'like is None'<commit_after>import re
import numpy as nm

from base import Struct, IndexedStruct, dict_to_struct, pause, output, copy,\
     import_file, assert_, get_default
from reader import Reader

_required = ['filename_mesh', 'field_[0-9]+|fields',
             'ebc_[0-9]+|ebcs', 'fe', 'equations',
             'region_[0-9]+|regions', 'variable_[0-9]+|variables',
             'material_[0-9]+|materials', 'integral_[0-9]+|integrals',
             'solver_[0-9]+|solvers']
_other = ['epbc_[0-9]+|epbcs', 'lcbc_[0-9]+|lcbcs', 'nbc_[0-9]+|nbcs',
          'ic_[0-9]+|ics', 'options']

##
# c: 19.02.2008, r: 19.02.2008
def get_standard_keywords():
    return copy( _required ), copy( _other )

##
# c: 10.04.2008, r: 10.04.2008
def tuple_to_conf( name, vals, order ):
    conf = Struct( name = name )
    for ii, key in enumerate( order ):
        setattr( conf, key, vals[ii] )
    return conf

##
# Short syntax: key is suffixed with '__<number>' to prevent collisions with
# long syntax keys -> both cases can be used in a single input.
def transform_variables( adict ):
    d2 = {}
    for ii, (key, conf) in enumerate( adict.iteritems() ):
        if isinstance( conf, tuple ):
            c2 = tuple_to_conf( key, conf, ['kind', 'field'] )
            if len( conf ) >= 3:
                kind = c2.kind.split()[0]
                if kind == 'unknown':
                    c2.order = conf[2]
                elif kind == 'test':
                    c2.dual = conf[2]
                elif kind == 'parameter':
                    if isinstance(conf[2], str) or (conf[2] is None):
                        c2.like = conf[2]
                    else:
                        c2.like = None
                        c2.special = conf[2]
                if len( conf ) == 4:
                    c2.history = conf[3]
            d2['variable_%s__%d' % (c2.name, ii)] = c2
        else:
            c2 = transform_to_struct_1( conf )
            d2['variable_'+c2.name] = c2
    return d2

def transform_conditions( adict, prefix ):
    d2 = {}
    for ii, (key, conf) in enumerate( adict.iteritems() ):
        if isinstance( conf, tuple ):
            c2 = tuple_to_conf( key, conf, ['region', 'dofs'] )
            if len( conf ) == 3:
                c2.filename = conf[2]
            d2['%s_%s__%d' % (prefix, c2.name, ii)] = c2
        else:
            c2 = transform_to_struct_1( conf )
            d2['%s_%s' % (prefix, c2.name)] = c2
    return d2

def transform_ebcs( adict ):
    return transform_conditions( adict, 'ebc' )

def transform_ics( adict ):
    return transform_conditions( adict, 'ic' )

def transform_lcbcs( adict ):
    return transform_conditions( adict, 'lcbc' )

def transform_regions( adict ):
    d2 = {}
    for ii, (key, conf) in enumerate( adict.iteritems() ):
        if isinstance( conf, tuple ):
            c2 = tuple_to_conf( key, conf, ['select', 'flags'] )
            for flag, val in c2.flags.iteritems():
                setattr( c2, flag, val )
            delattr( c2, 'flags' )
            d2['region_%s__%d' % (c2.name, ii)] = c2
        else:
            c2 = transform_to_struct_1( conf )
            d2['region_'+c2.name] = c2
    return d2

def transform_integrals( adict ):
    d2 = {}
    for ii, (key, conf) in enumerate( adict.iteritems() ):
        if isinstance( conf, tuple ):
            c2 = tuple_to_conf( key, conf, ['kind', 'quadrature'] )
            d2['integral_%s__%d' % (c2.name, ii)] = c2
        else:
            c2 = transform_to_struct_1( conf )
            d2['integral_'+c2.name] = c2
    return d2

def transform_fields( adict ):
    dtypes = {'real' : nm.float64, 'complex' : nm.complex128}
    d2 = {}
    for ii, (key, conf) in enumerate( adict.iteritems() ):
        if isinstance( conf, tuple ):
            c2 = tuple_to_conf( key, conf, ['dim', 'type', 'domain','bases'] )
            setattr( c2, 'dtype', dtypes[c2.type] )
            d2['field_%s__%d' % (c2.name, ii)] = c2
        else:
            c2 = transform_to_struct_1( conf )
            c2.set_default_attr('type', 'real')
            setattr( c2, 'dtype', dtypes[c2.type] )
            d2['field_'+c2.name] = c2
    return d2

def transform_materials( adict ):
    d2 = {}
    for ii, (key, conf) in enumerate( adict.iteritems() ):
        if isinstance( conf, tuple ):
            c2 = tuple_to_conf( key, conf, ['mode', 'region', 'params'] )
            dpar = {}
            dpar['name'] = key
            dpar['mode'] = c2.mode
            dpar['region'] = c2.region
            dpar.update( c2.params )
            d2['material_%s__%d' % (c2.name, ii)] = dpar
        else:
            d2['material_'+conf['name']] = conf
    return d2

def transform_solvers( adict ):
    d2 = {}
    for ii, (key, conf) in enumerate( adict.iteritems() ):
        if isinstance( conf, tuple ):
            c2 = tuple_to_conf( key, conf, ['kind','params'] )
            for param, val in c2.params.iteritems():
                setattr( c2, param, val )
            delattr( c2, 'params' )
            d2['solvers_%s__%d' % (c2.name, ii)] = c2
        else:
            c2 = transform_to_struct_1( conf )
            d2['solvers_'+c2.name] = c2
    return d2

##
# c: 20.06.2007, r: 18.02.2008
def transform_to_struct_1( adict ):
    return dict_to_struct( adict, flag = (1,) )
def transform_to_i_struct_1( adict ):
    return dict_to_struct( adict, flag = (1,), constructor = IndexedStruct )
def transform_to_struct_01( adict ):
    return dict_to_struct( adict, flag = (0,1) )
def transform_to_struct_10( adict ):
    return dict_to_struct( adict, flag = (1,0) )

transforms = {
    'options'   : transform_to_i_struct_1,
    'solvers'   : transform_solvers,
    'integrals' : transform_integrals,
    'opt'       : transform_to_struct_1,
    'fe'        : transform_to_struct_1,
    'regions'   : transform_regions,
    'shape_opt' : transform_to_struct_10,
    'fields'    : transform_fields,
    'variables' : transform_variables,
    'ebcs'      : transform_ebcs,
    'epbcs'     : transform_to_struct_01,
    'nbcs'      : transform_to_struct_01,
    'lcbcs'     : transform_lcbcs,
    'ics'       : transform_ics,
    'materials' : transform_materials,
}

##
# 27.10.2005, c
class ProblemConf( Struct ):
    """
    Problem configuration, corresponding to an input (problem description
    file). It validates the input using lists of required and other keywords
    that have to/can appear in the input. Default keyword lists can be obtained
    by sfepy.base.conf.get_standard_keywords().

    ProblemConf instance is used to construct a ProblemDefinition instance via
    ProblemDefinition.from_conf( conf ).
    """
    ##
    # c: 25.07.2006, r: 10.07.2008
    def from_file( filename, required = None, other = None ):
        """
        Loads the problem definition from a file.

        The filename can either contain plain definitions, or it can contain
        the define() function, in which case it will be called to return the
        input definitions.

        The job of the define() function is to return a dictionary of
        parameters. How the dictionary is constructed is not our business, but
        the usual way is to simply have a function define() along these lines
        in the input file:

            def define():
                options = {
                    'save_eig_vectors' : None,
                    'eigen_solver' : 'eigen1',
                }
                region_2 = {
                    'name' : 'Surface',
                    'select' : 'nodes of surface',
                }
                return locals()

        """
        funmod = import_file( filename )
        obj = ProblemConf()
        if "define" in funmod.__dict__:
            define_dict = funmod.__dict__["define"]()
        else:
            define_dict = funmod.__dict__

        obj.__dict__.update( define_dict )

        obj.setup( define_dict, funmod, filename, required, other )

        return obj
    from_file = staticmethod( from_file )

    def from_module( module, required = None, other = None ):
        obj = ProblemConf()
        obj.__dict__.update( module.__dict__ )

        obj.setup( funmod = module, required = required, other = other )

        return obj
    from_module = staticmethod( from_module )

    def from_dict( dict_, funmod, required = None, other = None ):
        obj = ProblemConf()
        obj.__dict__.update( dict_ )

        obj.setup( funmod = funmod, required = required, other = other )

        return obj
    from_dict = staticmethod( from_dict )

    def setup( self, define_dict = None, funmod = None, filename = None,
               required = None, other = None ):

        define_dict = get_default( define_dict, self.__dict__ )

        self._filename = filename

        other_missing = self.validate( required = required, other = other )

        self.transform_input_trivial()
        self._raw = {}
        for key, val in define_dict.iteritems():
            if isinstance( val, dict ):
                self._raw[key] = copy( val )

        self.transform_input()
        self.funmod = funmod

    ##
    # 27.10.2005, c
    # 19.09.2006
    # 05.06.2007
    def _validate_helper( self, items, but_nots ):
        keys = self.__dict__.keys()
        left_over = keys[:]
        if but_nots is not None:
            for item in but_nots:
                match = re.compile( '^' + item + '$' ).match
                for key in keys:
                    if match( key ):
                        left_over.remove( key )

        missing = []
        if items is not None:
            for item in items:
                found = False
                match = re.compile( '^' + item + '$' ).match
                for key in keys:
                    if match( key ):
                        found = True
                        left_over.remove( key )
                if not found:
                    missing.append( item )
        return left_over, missing

    ##
    # c: 27.10.2005, r: 11.07.2008
    def validate( self, required = None, other = None ):
        required_left_over, required_missing \
                          = self._validate_helper( required, other )
        other_left_over, other_missing \
                       = self._validate_helper( other, required )

        assert_( required_left_over == other_left_over )

        err = False
        if required_missing:
            err = True
            output( 'error: required missing:', required_missing )

        if other_left_over:
            output( 'left over:', other_left_over )

        if err:
            raise ValueError

        return other_missing

    ##
    # c: 31.10.2005, r: 10.07.2008
    def transform_input_trivial( self ):
        """Trivial input transformations."""

        ##
        # Unordered inputs.
        tr_list = ['([a-zA-Z0-9]+)_[0-9]+']
        # Keywords not in 'required', but needed even empty (e.g. for run_tests).
        for key in transforms.keys():
            if not self.__dict__.has_key( key ):
                self.__dict__[key] = {}

        keys = self.__dict__.keys()
        for item in tr_list:
            match = re.compile( item ).match
            for key in keys:
                obj = match( key )
                if obj:
                    new = obj.group( 1 ) + 's'
                    result = {key : self.__dict__[key]}
                    try:
                        self.__dict__[new].update( result )
                    except:
                        self.__dict__[new] = result

                    del self.__dict__[key]

    def transform_input( self ):
        keys = self.__dict__.keys()
        for key, transform in transforms.iteritems():
            if not key in keys: continue
            self.__dict__[key] = transform( self.__dict__[key] )

    def get_raw( self, key = None ):
        if key is None:
            return self._raw
        else:
            return self._raw[key]

    def edit( self, key, newval ):
        self.__dict__[key] = transforms[key]( newval )
<|endoftext|>