<commit_before>from spack import *
import os

class Trilinos(Package):
    """The Trilinos Project is an effort to develop algorithms and enabling technologies within an object-oriented
    software framework for the solution of large-scale, complex multi-physics engineering and scientific problems.
    A unique design feature of Trilinos is its focus on packages.
    """
    homepage = "https://trilinos.org/"
    url = "http://trilinos.csbsju.edu/download/files/trilinos-12.2.1-Source.tar.gz"

    version('12.6.1', 'adcf2d3aab74cdda98f88fee19cd1442604199b0515ee3da4d80cbe8f37d00e4')
    version('12.4.2', '7c830f7f0f68b8ad324690603baf404e')
    version('12.2.1', '6161926ea247863c690e927687f83be9')
    version('12.0.1', 'bd99741d047471e127b8296b2ec08017')
    version('11.14.3', '2f4f83f8333e4233c57d0f01c4b57426')
    version('11.14.2', 'a43590cf896c677890d75bfe75bc6254')
    version('11.14.1', '40febc57f76668be8b6a77b7607bb67f')

    variant('shared', default=True, description='Enables the build of shared libraries')
    variant('debug', default=False, description='Builds a debug version of the libraries')

    # Everything should be compiled with -fpic
    depends_on('blas')
    depends_on('lapack')
    depends_on('boost')
    depends_on('matio')
    depends_on('glm')
    depends_on('swig')
    depends_on('metis')
    depends_on('suite-sparse')

    # MPI related dependencies
    depends_on('mpi')
    depends_on('netcdf+mpi')
    depends_on('parmetis')
    depends_on('mumps+metis+parmetis')
    # depends_on('scalapack') # see FIXME below
    depends_on('superlu-dist')
    depends_on('hypre')
    depends_on('hdf5+mpi')

    depends_on('python') #  Needs py-numpy activated

    patch('umfpack_from_suitesparse.patch')

    def install(self, spec, prefix):
        options = []
        options.extend(std_cmake_args)

        mpi_bin = spec['mpi'].prefix.bin
        options.extend(['-DTrilinos_ENABLE_ALL_PACKAGES:BOOL=ON',
                        '-DTrilinos_ENABLE_ALL_OPTIONAL_PACKAGES:BOOL=ON',
                        '-DTrilinos_VERBOSE_CONFIGURE:BOOL=OFF',
                        '-DTrilinos_ENABLE_TESTS:BOOL=OFF',
                        '-DTrilinos_ENABLE_EXAMPLES:BOOL=OFF',
                        '-DCMAKE_BUILD_TYPE:STRING=%s' % ('DEBUG' if '+debug' in spec else 'RELEASE'),
                        '-DBUILD_SHARED_LIBS:BOOL=%s' % ('ON' if '+shared' in spec else 'OFF'),
                        '-DTPL_ENABLE_MPI:BOOL=ON',
                        '-DMPI_BASE_DIR:PATH=%s' % spec['mpi'].prefix,
                        '-DTPL_ENABLE_BLAS=ON',
                        '-DBLAS_LIBRARY_NAMES=blas',
                        '-DBLAS_LIBRARY_DIRS=/usr/lib', # % spec['blas'].prefix, #FIXME
                        '-DTPL_ENABLE_LAPACK=ON',
                        '-DLAPACK_LIBRARY_NAMES=lapack',
                        '-DLAPACK_LIBRARY_DIRS=/usr/lib', # % spec['lapack'].prefix, #FIXME
                        '-DTPL_ENABLE_Boost:BOOL=ON',
                        '-DBoost_INCLUDE_DIRS:PATH=%s' % spec['boost'].prefix.include,
                        '-DBoost_LIBRARY_DIRS:PATH=%s' % spec['boost'].prefix.lib,
                        # '-DTrilinos_ENABLE_Fortran=OFF', # FIXME
                        '-DTrilinos_ENABLE_EXPLICIT_INSTANTIATION:BOOL=ON',
                        '-DTrilinos_ENABLE_CXX11:BOOL=ON',
                        '-DTrilinos_CXX11_FLAGS=-std=c++11',
                        '-DTPL_ENABLE_Netcdf:BOOL=ON',
                        '-DTPL_ENABLE_HYPRE:BOOL=ON',
                        '-DTPL_ENABLE_HDF5:BOOL=ON',
                        # Need to use MPI wrappers, otherwise: Undefined symbols for architecture x86_64: "_mpi_abort_","_mpi_allgatherv_", etc from MUMPS
                        '-DCMAKE_C_COMPILER=%s' % join_path(mpi_bin,'mpicc'), # FIXME: dont hardcode compiler name
                        '-DCMAKE_CXX_COMPILER=%s' % join_path(mpi_bin,'mpicxx'),
                        '-DCMAKE_Fortran_COMPILER=%s' % join_path(mpi_bin,'mpif90')
                        ])

        # Fortran lib
        libgfortran = os.path.dirname (os.popen('%s --print-file-name libgfortran.a' % join_path(mpi_bin,'mpif90') ).read())
        #os.environ['LDFLAGS'] = '-L%s -lgfortran' % libgfortran
        options.extend([
            '-DTrilinos_EXTRA_LINK_FLAGS:STRING=-lgfortran',
            '-DCMAKE_EXE_LINKER_FLAGS:STRING=-L%s -lgfortran' % libgfortran
        ])

        # for build-debug only:
        options.extend([
            '-DCMAKE_VERBOSE_MAKEFILE:BOOL=TRUE'
        ])

        # suite-sparse related
        options.extend([
            '-DTPL_ENABLE_Cholmod:BOOL=OFF', # FIXME: Trilinos seems to be looking for static libs only, patch CMake TPL file?
            #'-DTPL_ENABLE_Cholmod:BOOL=ON',
            #'-DCholmod_LIBRARY_DIRS:PATH=%s' % spec['suite-sparse'].prefix.lib,
            #'-DCholmod_INCLUDE_DIRS:PATH=%s' % spec['suite-sparse'].prefix.include,
            '-DTPL_ENABLE_UMFPACK:BOOL=ON',
            '-DUMFPACK_LIBRARY_DIRS:PATH=%s' % spec['suite-sparse'].prefix.lib,
            '-DUMFPACK_INCLUDE_DIRS:PATH=%s' % spec['suite-sparse'].prefix.include,
            '-DUMFPACK_LIBRARY_NAMES=umfpack;amd;colamd;cholmod;suitesparseconfig'
        ])

        # metis / parmetis
        options.extend([
            '-DTPL_ENABLE_METIS:BOOL=ON',
            '-DMETIS_LIBRARY_DIRS=%s' % spec['metis'].prefix.lib,
            '-DMETIS_LIBRARY_NAMES=metis',
            '-DTPL_METIS_INCLUDE_DIRS=%s' % spec['metis'].prefix.include,
            '-DTPL_ENABLE_ParMETIS:BOOL=ON',
            '-DParMETIS_LIBRARY_DIRS=%s;%s' % (spec['parmetis'].prefix.lib,spec['metis'].prefix.lib),
            '-DParMETIS_LIBRARY_NAMES=parmetis;metis',
            '-DTPL_ParMETIS_INCLUDE_DIRS=%s' % spec['parmetis'].prefix.include
        ])

        # mumps
        options.extend([
            '-DTPL_ENABLE_MUMPS:BOOL=ON',
            '-DMUMPS_LIBRARY_DIRS=%s' % spec['mumps'].prefix.lib,
            '-DMUMPS_LIBRARY_NAMES=dmumps;mumps_common;pord' # order is important!
        ])

        # scalapack
        options.extend([
            '-DTPL_ENABLE_SCALAPACK:BOOL=OFF', #FIXME: Undefined symbols for architecture x86_64: "_blacs_gridinfo__", referenced from: Amesos_Scalapack::RedistributeA() in Amesos_Scalapack.cpp.o
            #'-DSCALAPACK_LIBRARY_NAMES=scalapack' # FIXME: for MKL it's mkl_scalapack_lp64;mkl_blacs_mpich_lp64
        ])

        # superlu_dist:
        # Amesos, conflicting types of double and complex SLU_D
        # see https://trilinos.org/pipermail/trilinos-users/2015-March/004731.html
        # and https://trilinos.org/pipermail/trilinos-users/2015-March/004802.html
        options.extend([
            '-DTeuchos_ENABLE_COMPLEX:BOOL=OFF',
            '-DKokkosTSQR_ENABLE_Complex:BOOL=OFF'
        ])
        options.extend([
            '-DTPL_ENABLE_SuperLUDist:BOOL=ON',
            '-DSuperLUDist_LIBRARY_DIRS=%s' % spec['superlu-dist'].prefix.lib,
            '-DSuperLUDist_INCLUDE_DIRS=%s/superlu_dist' % spec['superlu-dist'].prefix.include # superlu_dist and superlu have the same header names :-( In order to avoid conflicts, try to keep "dist" version headers in a subfolder
        ])
        if spec.satisfies('^superlu-dist@4.0:'):
            options.extend([
                '-DHAVE_SUPERLUDIST_LUSTRUCTINIT_2ARG:BOOL=ON'
            ])

        # disable due to compiler / config errors:
        options.extend([
            '-DTrilinos_ENABLE_SEACAS=OFF',
            '-DTrilinos_ENABLE_Pike=OFF',
            '-DTrilinos_ENABLE_STK=OFF'
        ])

        #if self.compiler.name == "clang":
        #    options.extend([
        #        '-DCMAKE_EXE_LINKER_FLAGS:STRING=-Qunused-arguments'
        #    ])

        with working_dir('spack-build', create=True):
            cmake('..', *options)
            make()
            make('install')
<commit_msg>fiddle more<commit_after>from spack import *
import os

class Trilinos(Package):
    """The Trilinos Project is an effort to develop algorithms and enabling technologies within an object-oriented
    software framework for the solution of large-scale, complex multi-physics engineering and scientific problems.
    A unique design feature of Trilinos is its focus on packages.
    """
    homepage = "https://trilinos.org/"
    url = "http://trilinos.csbsju.edu/download/files/trilinos-12.2.1-Source.tar.gz"

    version('12.6.1', 'adcf2d3aab74cdda98f88fee19cd1442604199b0515ee3da4d80cbe8f37d00e4')
    version('12.4.2', '7c830f7f0f68b8ad324690603baf404e')
    version('12.2.1', '6161926ea247863c690e927687f83be9')
    version('12.0.1', 'bd99741d047471e127b8296b2ec08017')
    version('11.14.3', '2f4f83f8333e4233c57d0f01c4b57426')
    version('11.14.2', 'a43590cf896c677890d75bfe75bc6254')
    version('11.14.1', '40febc57f76668be8b6a77b7607bb67f')

    variant('shared', default=True, description='Enables the build of shared libraries')
    variant('debug', default=False, description='Builds a debug version of the libraries')

    # Everything should be compiled with -fpic
    depends_on('blas')
    depends_on('lapack')
    depends_on('boost')
    depends_on('matio')
    depends_on('glm')
    depends_on('swig')
    depends_on('metis')
    depends_on('suite-sparse')

    # MPI related dependencies
    depends_on('mpi')
    depends_on('netcdf+mpi')
    depends_on('parmetis')
    depends_on('mumps+metis+parmetis')
    # depends_on('scalapack') # see FIXME below
    depends_on('superlu-dist')
    depends_on('hypre')
    depends_on('hdf5+mpi')

    depends_on('python') #  Needs py-numpy activated

    patch('umfpack_from_suitesparse.patch')

    def install(self, spec, prefix):
        options = []
        options.extend(std_cmake_args)

        mpi_bin = spec['mpi'].prefix.bin
        options.extend(['-DTrilinos_ENABLE_ALL_PACKAGES:BOOL=ON',
                        '-DTrilinos_ENABLE_ALL_OPTIONAL_PACKAGES:BOOL=ON',
                        '-DTrilinos_VERBOSE_CONFIGURE:BOOL=OFF',
                        '-DTrilinos_ENABLE_TESTS:BOOL=OFF',
                        '-DTrilinos_ENABLE_EXAMPLES:BOOL=OFF',
                        '-DCMAKE_BUILD_TYPE:STRING=%s' % ('DEBUG' if '+debug' in spec else 'RELEASE'),
                        '-DBUILD_SHARED_LIBS:BOOL=%s' % ('ON' if '+shared' in spec else 'OFF'),
                        '-DTPL_ENABLE_MPI:BOOL=ON',
                        '-DMPI_BASE_DIR:PATH=%s' % spec['mpi'].prefix,
                        '-DTPL_ENABLE_BLAS=ON',
                        '-DBLAS_LIBRARY_NAMES=blas',
                        '-DBLAS_LIBRARY_DIRS=/usr/lib', # % spec['blas'].prefix, #FIXME
                        '-DTPL_ENABLE_LAPACK=ON',
                        '-DLAPACK_LIBRARY_NAMES=lapack',
                        '-DLAPACK_LIBRARY_DIRS=/usr/lib', # % spec['lapack'].prefix, #FIXME
                        '-DTPL_ENABLE_Boost:BOOL=ON',
                        '-DBoost_INCLUDE_DIRS:PATH=%s' % spec['boost'].prefix.include,
                        '-DBoost_LIBRARY_DIRS:PATH=%s' % spec['boost'].prefix.lib,
                        '-DTrilinos_ENABLE_EXPLICIT_INSTANTIATION:BOOL=ON',
                        '-DTrilinos_ENABLE_CXX11:BOOL=ON',
                        '-DTrilinos_CXX11_FLAGS=-std=c++11',
                        '-DTPL_ENABLE_Netcdf:BOOL=ON',
                        '-DTPL_ENABLE_HYPRE:BOOL=ON',
                        '-DTPL_ENABLE_HDF5:BOOL=ON',
                        # Need to use MPI wrappers, otherwise: Undefined symbols for architecture x86_64: "_mpi_abort_","_mpi_allgatherv_", etc from MUMPS
                        '-DCMAKE_C_COMPILER=%s' % join_path(mpi_bin,'mpicc'), # FIXME: dont hardcode compiler name
                        '-DCMAKE_CXX_COMPILER=%s' % join_path(mpi_bin,'mpicxx'),
                        '-DCMAKE_Fortran_COMPILER=%s' % join_path(mpi_bin,'mpif90')
                        ])

        # Fortran lib
        libgfortran = os.path.dirname (os.popen('%s --print-file-name libgfortran.a' % join_path(mpi_bin,'mpif90') ).read())
        options.extend([
            '-DTrilinos_EXTRA_LINK_FLAGS:STRING=-L%s/ -lgfortran' % libgfortran,
            '-DTrilinos_ENABLE_Fortran=OFF' # FIXME: otherwise VerifyFortranC fails as it does not contain -lgfortran , issues with IMPLICIT_LINK_LIBRARIES in CMakeFiles/CMake(C|CXX|Fortran)Compiler.cmake?
        ])

        # for build-debug only:
        options.extend([
            '-DCMAKE_VERBOSE_MAKEFILE:BOOL=TRUE'
        ])

        # suite-sparse related
        options.extend([
            '-DTPL_ENABLE_Cholmod:BOOL=OFF', # FIXME: Trilinos seems to be looking for static libs only, patch CMake TPL file?
            #'-DTPL_ENABLE_Cholmod:BOOL=ON',
            #'-DCholmod_LIBRARY_DIRS:PATH=%s' % spec['suite-sparse'].prefix.lib,
            #'-DCholmod_INCLUDE_DIRS:PATH=%s' % spec['suite-sparse'].prefix.include,
            '-DTPL_ENABLE_UMFPACK:BOOL=ON',
            '-DUMFPACK_LIBRARY_DIRS:PATH=%s' % spec['suite-sparse'].prefix.lib,
            '-DUMFPACK_INCLUDE_DIRS:PATH=%s' % spec['suite-sparse'].prefix.include,
            '-DUMFPACK_LIBRARY_NAMES=umfpack;amd;colamd;cholmod;suitesparseconfig'
        ])

        # metis / parmetis
        options.extend([
            '-DTPL_ENABLE_METIS:BOOL=ON',
            '-DMETIS_LIBRARY_DIRS=%s' % spec['metis'].prefix.lib,
            '-DMETIS_LIBRARY_NAMES=metis',
            '-DTPL_METIS_INCLUDE_DIRS=%s' % spec['metis'].prefix.include,
            '-DTPL_ENABLE_ParMETIS:BOOL=ON',
            '-DParMETIS_LIBRARY_DIRS=%s;%s' % (spec['parmetis'].prefix.lib,spec['metis'].prefix.lib),
            '-DParMETIS_LIBRARY_NAMES=parmetis;metis',
            '-DTPL_ParMETIS_INCLUDE_DIRS=%s' % spec['parmetis'].prefix.include
        ])

        # mumps
        options.extend([
            '-DTPL_ENABLE_MUMPS:BOOL=ON',
            '-DMUMPS_LIBRARY_DIRS=%s' % spec['mumps'].prefix.lib,
            '-DMUMPS_LIBRARY_NAMES=dmumps;mumps_common;pord' # order is important!
        ])

        # scalapack
        options.extend([
            '-DTPL_ENABLE_SCALAPACK:BOOL=OFF', #FIXME: Undefined symbols for architecture x86_64: "_blacs_gridinfo__", referenced from: Amesos_Scalapack::RedistributeA() in Amesos_Scalapack.cpp.o
            #'-DSCALAPACK_LIBRARY_NAMES=scalapack' # FIXME: for MKL it's mkl_scalapack_lp64;mkl_blacs_mpich_lp64
        ])

        # superlu_dist:
        # Amesos, conflicting types of double and complex SLU_D
        # see https://trilinos.org/pipermail/trilinos-users/2015-March/004731.html
        # and https://trilinos.org/pipermail/trilinos-users/2015-March/004802.html
        options.extend([
            '-DTeuchos_ENABLE_COMPLEX:BOOL=OFF',
            '-DKokkosTSQR_ENABLE_Complex:BOOL=OFF'
        ])
        options.extend([
            '-DTPL_ENABLE_SuperLUDist:BOOL=ON',
            '-DSuperLUDist_LIBRARY_DIRS=%s' % spec['superlu-dist'].prefix.lib,
            '-DSuperLUDist_INCLUDE_DIRS=%s/superlu_dist' % spec['superlu-dist'].prefix.include # superlu_dist and superlu have the same header names :-( In order to avoid conflicts, try to keep "dist" version headers in a subfolder
        ])
        if spec.satisfies('^superlu-dist@4.0:'):
            options.extend([
                '-DHAVE_SUPERLUDIST_LUSTRUCTINIT_2ARG:BOOL=ON'
            ])

        # disable due to compiler / config errors:
        options.extend([
            '-DTrilinos_ENABLE_SEACAS=OFF',
            '-DTrilinos_ENABLE_Pike=OFF',
            '-DTrilinos_ENABLE_STK=OFF'
        ])

        with working_dir('spack-build', create=True):
            cmake('..', *options)
            make()
            make('install')
<|endoftext|>


<commit_before># Copyright (c) 2015 Nicolas JOUANIN
#
# See the file license.txt for copying permission.
import unittest
import asyncio

from hbmqtt.mqtt.connect import ConnectPacket, ConnectVariableHeader, ConnectPayload
from hbmqtt.mqtt.packet import MQTTFixedHeader, PacketType
from hbmqtt.errors import MQTTException

class ConnectPacketTest(unittest.TestCase):
    def setUp(self):
        self.loop = asyncio.new_event_loop()

    def test_decode_ok(self):
        data = b'\x10\x3e\x00\x04MQTT\x04\xce\x00\x00\x00\x0a0123456789\x00\x09WillTopic\x00\x0bWillMessage\x00\x04user\x00\x08password'
        stream = asyncio.StreamReader(loop=self.loop)
        stream.feed_data(data)
        message = self.loop.run_until_complete(ConnectPacket.from_stream(stream))
        self.assertEqual(message.variable_header.proto_name, "MQTT")
        self.assertEqual(message.variable_header.proto_level, 4)
        self.assertTrue(message.variable_header.username_flag)
        self.assertTrue(message.variable_header.password_flag)
        self.assertFalse(message.variable_header.will_retain_flag)
        self.assertEqual(message.variable_header.will_qos, 1)
        self.assertTrue(message.variable_header.will_flag)
        self.assertTrue(message.variable_header.clean_session_flag)
        self.assertFalse(message.variable_header.reserved_flag)
        self.assertEqual(message.payload.client_id, '0123456789')
        self.assertEqual(message.payload.will_topic, 'WillTopic')
        self.assertEqual(message.payload.will_message, 'WillMessage')
        self.assertEqual(message.payload.username, 'user')
        self.assertEqual(message.payload.password, 'password')

    def test_decode_fail_protocol_name(self):
        data = b'\x10\x3e\x00\x04TTQM\x04\xce\x00\x00\x00\x0a0123456789\x00\x09WillTopic\x00\x0bWillMessage\x00\x04user\x00\x08password'
        stream = asyncio.StreamReader(loop=self.loop)
        stream.feed_data(data)
        with self.assertRaises(MQTTException):
            self.loop.run_until_complete(ConnectPacket.from_stream(stream))

    def test_decode_fail_reserved_flag(self):
        data = b'\x10\x3e\x00\x04MQTT\x04\xcf\x00\x00\x00\x0a0123456789\x00\x09WillTopic\x00\x0bWillMessage\x00\x04user\x00\x08password'
        stream = asyncio.StreamReader(loop=self.loop)
        stream.feed_data(data)
        with self.assertRaises(MQTTException):
            self.loop.run_until_complete(ConnectPacket.from_stream(stream))

    def test_decode_fail_miss_clientId(self):
        data = b'\x10\x0a\x00\x04MQTT\x04\xce\x00\x00'
        stream = asyncio.StreamReader(loop=self.loop)
        stream.feed_data(data)
        stream.feed_eof()
        with self.assertRaises(MQTTException):
            self.loop.run_until_complete(ConnectPacket.from_stream(stream))

    def test_decode_fail_miss_willtopic(self):
        data = b'\x10\x16\x00\x04MQTT\x04\xce\x00\x00\x00\x0a0123456789'
        stream = asyncio.StreamReader(loop=self.loop)
        stream.feed_data(data)
        stream.feed_eof()
        with self.assertRaises(MQTTException):
            self.loop.run_until_complete(ConnectPacket.from_stream(stream))

    def test_decode_fail_miss_username(self):
        data = b'\x10\x2e\x00\x04MQTT\x04\xce\x00\x00\x00\x0a0123456789\x00\x09WillTopic\x00\x0bWillMessage'
        stream = asyncio.StreamReader(loop=self.loop)
        stream.feed_data(data)
        stream.feed_eof()
        with self.assertRaises(MQTTException):
            self.loop.run_until_complete(ConnectPacket.from_stream(stream))

    def test_decode_fail_miss_password(self):
        data = b'\x10\x34\x00\x04MQTT\x04\xce\x00\x00\x00\x0a0123456789\x00\x09WillTopic\x00\x0bWillMessage\x00\x04user'
        stream = asyncio.StreamReader(loop=self.loop)
        stream.feed_data(data)
        stream.feed_eof()
        with self.assertRaises(MQTTException):
            self.loop.run_until_complete(ConnectPacket.from_stream(stream))

    def test_encode(self):
        header = MQTTFixedHeader(PacketType.CONNECT, 0x00, 0)
        variable_header = ConnectVariableHeader(0xce, 0, 'MQTT', 4)
        payload = ConnectPayload('0123456789', 'WillTopic', 'WillMessage', 'user', 'password')
        message = ConnectPacket(header, variable_header, payload)
        encoded = message.to_bytes()
        self.assertEqual(encoded, b'\x10\x3e\x00\x04MQTT\x04\xce\x00\x00\x00\x0a0123456789\x00\x09WillTopic\x00\x0bWillMessage\x00\x04user\x00\x08password')
<commit_msg>Fix testing<commit_after># Copyright (c) 2015 Nicolas JOUANIN
#
# See the file license.txt for copying permission.
import unittest
import asyncio

from hbmqtt.mqtt.connect import ConnectPacket, ConnectVariableHeader, ConnectPayload
from hbmqtt.mqtt.packet import MQTTFixedHeader, PacketType
from hbmqtt.errors import MQTTException

class ConnectPacketTest(unittest.TestCase):
    def setUp(self):
        self.loop = asyncio.new_event_loop()

    def test_decode_ok(self):
        data = b'\x10\x3e\x00\x04MQTT\x04\xce\x00\x00\x00\x0a0123456789\x00\x09WillTopic\x00\x0bWillMessage\x00\x04user\x00\x08password'
        stream = asyncio.StreamReader(loop=self.loop)
        stream.feed_data(data)
        message = self.loop.run_until_complete(ConnectPacket.from_stream(stream))
        self.assertEqual(message.variable_header.proto_name, "MQTT")
        self.assertEqual(message.variable_header.proto_level, 4)
        self.assertTrue(message.variable_header.username_flag)
        self.assertTrue(message.variable_header.password_flag)
        self.assertFalse(message.variable_header.will_retain_flag)
        self.assertEqual(message.variable_header.will_qos, 1)
        self.assertTrue(message.variable_header.will_flag)
        self.assertTrue(message.variable_header.clean_session_flag)
        self.assertFalse(message.variable_header.reserved_flag)
        self.assertEqual(message.payload.client_id, '0123456789')
        self.assertEqual(message.payload.will_topic, 'WillTopic')
        self.assertEqual(message.payload.will_message, 'WillMessage')
        self.assertEqual(message.payload.username, 'user')
        self.assertEqual(message.payload.password, 'password')

    def test_decode_fail_protocol_name(self):
        data = b'\x10\x3e\x00\x04TTQM\x04\xce\x00\x00\x00\x0a0123456789\x00\x09WillTopic\x00\x0bWillMessage\x00\x04user\x00\x08password'
        stream = asyncio.StreamReader(loop=self.loop)
        stream.feed_data(data)
        with self.assertRaises(MQTTException):
            self.loop.run_until_complete(ConnectPacket.from_stream(stream))

    def test_decode_fail_reserved_flag(self):
        data = b'\x10\x3e\x00\x04MQTT\x04\xcf\x00\x00\x00\x0a0123456789\x00\x09WillTopic\x00\x0bWillMessage\x00\x04user\x00\x08password'
        stream = asyncio.StreamReader(loop=self.loop)
        stream.feed_data(data)
        message = self.loop.run_until_complete(ConnectPacket.from_stream(stream))
        self.assertTrue(message.variable_header.reserved_flag)

    def test_decode_fail_miss_clientId(self):
        data = b'\x10\x0a\x00\x04MQTT\x04\xce\x00\x00'
        stream = asyncio.StreamReader(loop=self.loop)
        stream.feed_data(data)
        stream.feed_eof()
        message = self.loop.run_until_complete(ConnectPacket.from_stream(stream))
        self.assertIs(message.payload.client_id, None)

    def test_decode_fail_miss_willtopic(self):
        data = b'\x10\x16\x00\x04MQTT\x04\xce\x00\x00\x00\x0a0123456789'
        stream = asyncio.StreamReader(loop=self.loop)
        stream.feed_data(data)
        stream.feed_eof()
        message = self.loop.run_until_complete(ConnectPacket.from_stream(stream))
        self.assertIs(message.payload.will_topic, None)

    def test_decode_fail_miss_username(self):
        data = b'\x10\x2e\x00\x04MQTT\x04\xce\x00\x00\x00\x0a0123456789\x00\x09WillTopic\x00\x0bWillMessage'
        stream = asyncio.StreamReader(loop=self.loop)
        stream.feed_data(data)
        stream.feed_eof()
        message = self.loop.run_until_complete(ConnectPacket.from_stream(stream))
        self.assertIs(message.payload.username, None)

    def test_decode_fail_miss_password(self):
        data = b'\x10\x34\x00\x04MQTT\x04\xce\x00\x00\x00\x0a0123456789\x00\x09WillTopic\x00\x0bWillMessage\x00\x04user'
        stream = asyncio.StreamReader(loop=self.loop)
        stream.feed_data(data)
        stream.feed_eof()
        message = self.loop.run_until_complete(ConnectPacket.from_stream(stream))
        self.assertIs(message.payload.password, None)

    def test_encode(self):
        header = MQTTFixedHeader(PacketType.CONNECT, 0x00, 0)
        variable_header = ConnectVariableHeader(0xce, 0, 'MQTT', 4)
        payload = ConnectPayload('0123456789', 'WillTopic', 'WillMessage', 'user', 'password')
        message = ConnectPacket(header, variable_header, payload)
        encoded = message.to_bytes()
        self.assertEqual(encoded, b'\x10\x3e\x00\x04MQTT\x04\xce\x00\x00\x00\x0a0123456789\x00\x09WillTopic\x00\x0bWillMessage\x00\x04user\x00\x08password')
<|endoftext|>


<commit_before># -*- coding: utf-8 -*-
"""Provides programs to process and analyze PROBA2/LYRA data."""
from __future__ import absolute_import

from sunpy.lightcurve import LightCurve

import os
import pandas
import datetime
from matplotlib import pyplot as plt
import urlparse
import pyfits
import sunpy

class LYRALightCurve(LightCurve):
    """SDO EVE light curve definition

    Examples
    --------
    >>> import sunpy
    >>> lyra = sunpy.lightcurve.LYRALightCurve()
    >>> lyra = sunpy.lightcurve.LYRALightCurve('~/Data/lyra/lyra_20110810-000000_lev2_std.fits')
    >>> lyra = sunpy.lightcurve.LYRALightCurve('2011/08/10')
    >>> lyra = sunpy.lightcurve.LYRALightCurve("http://proba2.oma.be/lyra/data/bsd/2011/08/10/lyra_20110810-000000_lev2_std.fits")
    >>>
    >>> lyra.show()

    References
    ----------
    | http://lasp.colorado.edu/home/eve/data/data-access/
    """
    def __init__(self, *args, **kwargs):
        LightCurve.__init__(self, *args, **kwargs)

    def show(self, names=3, **kwargs):
        """Plots the LYRA data

        See: http://pandas.sourceforge.net/visualization.html
        """
        lyranames = (('Lyman alpha','Herzberg cont.','Al filter','Zr filter'),
                 ('120-123nm','190-222nm','17-80nm + <5nm','6-20nm + <2nm'))

        # Choose title if none was specified
        #if not kwargs.has_key("title"):
        #    if len(self.data.columns) > 1:
        #        kwargs['title'] = 'LYRA data'
        #    else:
        #        if self._filename is not None:
        #            base = self._filename
        #            kwargs['title'] = os.path.splitext(base)[0]
        #        else:
        #            kwargs['title'] = 'LYRA data'

        """Shows a plot of all four light curves"""
        axes = self.data.plot(subplots=True, sharex=True, **kwargs)
        #plt.legend(loc='best')

        for i, name in enumerate(self.data.columns):
            if names < 3:
                name = lyranames[names][i]
            else:
                name = lyranames[0][i] + ' (' + lyranames[1][i] + ')'
            axes[i].set_ylabel("%s (%s)" % (name, "W/m**2"))

        axes[0].set_title("LYRA ("+ self.data.index[0].strftime('%Y-%m-%d') +")")
        axes[-1].set_xlabel("Time")
        plt.show()

    def _get_url_for_date(self, date):
        """Returns a URL to the LYRA data for the specified date
        """
        dt = sunpy.time.parse_time(date or datetime.datetime.utcnow())

        # Filename
        filename = "lyra_%s000000_lev%d_%s.fits" % (dt.strftime('%Y%m%d-'),
                                                    2, 'std')
        # URL
        base_url = "http://proba2.oma.be/lyra/data/bsd/"
        url_path = urlparse.urljoin(dt.strftime('%Y/%m/%d/'), filename)
        return urlparse.urljoin(base_url, url_path)

    def _get_default_uri(self):
        """Look for and download today's LYRA data"""
        return _get_url_for_date(self,datetime.utcnow())

    def _parse_fits(self,filepath):
        """Loads LYRA data from a FITS file"""
        # Open file with PyFITS
        hdulist = pyfits.open(filepath)
        fits_record = hdulist[1].data
        #secondary_header = hdulist[1].header

        # Start and end dates.  Different LYRA FITS files have
        # different tags for the date obs.
        if 'date-obs' in hdulist[0].header:
            start_str = hdulist[0].header['date-obs']
        elif 'date_obs' in hdulist[0].header:
            start_str = hdulist[0].header['date_obs']
        #end_str = hdulist[0].header['date-end']

        start = datetime.datetime.strptime(start_str, '%Y-%m-%dT%H:%M:%S.%f')
        #end = datetime.datetime.strptime(end_str, '%Y-%m-%dT%H:%M:%S.%f')

        # First column are times
        times = [start + datetime.timedelta(0, n) for n in fits_record.field(0)]

        # Rest of columns are the data
        table = {}

        for i, col in enumerate(fits_record.columns[1:-1]):
            table[col.name] = fits_record.field(i + 1)

        # Return the header and the data
        return hdulist[0].header, pandas.DataFrame(table, index=times)
        <commit_msg>fixed LYRA start time issue by using parse_time in sunpy.  Weirdness in plotting possibly related to numpy 64 bit datetimes - see pandas 0.8.0 notes<commit_after># -*- coding: utf-8 -*-
"""Provides programs to process and analyze PROBA2/LYRA data."""
from __future__ import absolute_import

from sunpy.lightcurve import LightCurve

import os
import pandas
import datetime
from matplotlib import pyplot as plt
import urlparse
import pyfits
import sunpy

class LYRALightCurve(LightCurve):
    """SDO EVE light curve definition

    Examples
    --------
    >>> import sunpy
    >>> lyra = sunpy.lightcurve.LYRALightCurve()
    >>> lyra = sunpy.lightcurve.LYRALightCurve('~/Data/lyra/lyra_20110810-000000_lev2_std.fits')
    >>> lyra = sunpy.lightcurve.LYRALightCurve('2011/08/10')
    >>> lyra = sunpy.lightcurve.LYRALightCurve("http://proba2.oma.be/lyra/data/bsd/2011/08/10/lyra_20110810-000000_lev2_std.fits")
    >>>
    >>> lyra.show()

    References
    ----------
    | http://lasp.colorado.edu/home/eve/data/data-access/
    """
    def __init__(self, *args, **kwargs):
        LightCurve.__init__(self, *args, **kwargs)

    def show(self, names=3, **kwargs):
        """Plots the LYRA data

        See: http://pandas.sourceforge.net/visualization.html
        """
        lyranames = (('Lyman alpha','Herzberg cont.','Al filter','Zr filter'),
                 ('120-123nm','190-222nm','17-80nm + <5nm','6-20nm + <2nm'))

        # Choose title if none was specified
        #if not kwargs.has_key("title"):
        #    if len(self.data.columns) > 1:
        #        kwargs['title'] = 'LYRA data'
        #    else:
        #        if self._filename is not None:
        #            base = self._filename
        #            kwargs['title'] = os.path.splitext(base)[0]
        #        else:
        #            kwargs['title'] = 'LYRA data'

        """Shows a plot of all four light curves"""
        axes = self.data.plot(subplots=True, sharex=True, **kwargs)
        #plt.legend(loc='best')

        for i, name in enumerate(self.data.columns):
            if names < 3:
                name = lyranames[names][i]
            else:
                name = lyranames[0][i] + ' (' + lyranames[1][i] + ')'
            axes[i].set_ylabel("%s (%s)" % (name, "W/m**2"))

        axes[0].set_title("LYRA ("+ self.data.index[0].strftime('%Y-%m-%d') +")")
        axes[-1].set_xlabel("Time")
        plt.show()

    def _get_url_for_date(self, date):
        """Returns a URL to the LYRA data for the specified date
        """
        dt = sunpy.time.parse_time(date or datetime.datetime.utcnow())

        # Filename
        filename = "lyra_%s000000_lev%d_%s.fits" % (dt.strftime('%Y%m%d-'),
                                                    2, 'std')
        # URL
        base_url = "http://proba2.oma.be/lyra/data/bsd/"
        url_path = urlparse.urljoin(dt.strftime('%Y/%m/%d/'), filename)
        return urlparse.urljoin(base_url, url_path)

    def _get_default_uri(self):
        """Look for and download today's LYRA data"""
        return _get_url_for_date(self,datetime.utcnow())

    def _parse_fits(self,filepath):
        """Loads LYRA data from a FITS file"""
        # Open file with PyFITS
        hdulist = pyfits.open(filepath)
        fits_record = hdulist[1].data
        #secondary_header = hdulist[1].header

        # Start and end dates.  Different LYRA FITS files have
        # different tags for the date obs.
        if 'date-obs' in hdulist[0].header:
            start_str = hdulist[0].header['date-obs']
        elif 'date_obs' in hdulist[0].header:
            start_str = hdulist[0].header['date_obs']
        #end_str = hdulist[0].header['date-end']

        #start = datetime.datetime.strptime(start_str, '%Y-%m-%dT%H:%M:%S.%f')
        start = sunpy.time.parse_time(start_str)
        #end = datetime.datetime.strptime(end_str, '%Y-%m-%dT%H:%M:%S.%f')

        # First column are times
        times = [start + datetime.timedelta(0, n) for n in fits_record.field(0)]

        # Rest of columns are the data
        table = {}

        for i, col in enumerate(fits_record.columns[1:-1]):
            table[col.name] = fits_record.field(i + 1)

        # Return the header and the data
        return hdulist[0].header, pandas.DataFrame(table, index=times)
        <|endoftext|>


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

"""Reports for image content gap."""

def create(articlelist):
    """Create a report from article list with views

    Args:
        articlelist (list): list of dictionnaries with name and views for
            each article [{'name': 'Foo', 'views': 42}, ...]
    Returns:
        str: wiki code for the report
    """
    reportcode = "== Report ==\n"
    for article in articlelist:
        reportcode += "* [[{0}]] {1}\n".format(article['name'],
                                               article['views'])
    return reportcode

def save(site, pagename, report):
    """Save report on the wiki site as pagename.

    Args:
        site (mwclient.Site): wiki to save to
        pagename (str): name of the page to save the report to
        report (str): surface image content gap report
    """
    page = site.Pages[pagename]
    page.save(report, summary='Content gap report')
<commit_msg>Add decode('utf-8') to report name. It should close #6<commit_after># -*- coding: utf-8 -*-

"""Reports for image content gap."""

def create(articlelist):
    """Create a report from article list with views

    Args:
        articlelist (list): list of dictionnaries with name and views for
            each article [{'name': 'Foo', 'views': 42}, ...]
    Returns:
        str: wiki code for the report
    """
    reportcode = "== Report ==\n"
    for article in articlelist:
        reportcode += "* [[{0}]] {1}\n".format(article['name'],
                                               article['views'])
    return reportcode

def save(site, pagename, report):
    """Save report on the wiki site as pagename.

    Args:
        site (mwclient.Site): wiki to save to
        pagename (str): name of the page to save the report to
        report (str): surface image content gap report
    """
    page = site.Pages[pagename.decode('utf-8')]
    page.save(report, summary='Content gap report')
<|endoftext|>


<commit_before>"""
ParametersFrame class.

$Id$
"""
__version__='$Revision$'

# CEBHACKALERT: this file is being reorganized.

from inspect import getdoc

import Pmw
from Tkinter import Frame, Button, RIGHT, TOP, BOTH, BOTTOM, END, YES, N,S,E,W,X, Menu, Toplevel, Label, LEFT

import topo.misc.utils
from topo.misc.utils import keys_sorted_by_value, dict_translator, eval_atof
from topo.base.parameterizedobject import ParameterizedObject,ParameterizedObjectMetaclass,classlist
from topo.base.parameterclasses import Number,Enumeration,ClassSelectorParameter,BooleanParameter

from propertiesframe import PropertiesFrame
from translatorwidgets import CheckbuttonTranslator

# CEBHACKALERT: there used to be a 'reset_to_defaults' method, which
# didn't work. When Parameters can be set and then maintained between
# classes (e.g. for PatternGenerators), reset_to_defaults() should be
# re-implemented so that Parameters can be returned to default values
# for the current class.

class ParametersFrame(Frame):
    """
    Frame for all non-hidden Parameters of a ParameterizedObject class.

    When asked to create wigets, ... makes a PropertiesFrame containing all the specified class' Parameters.
    """

    def __init__(self, parent=None, **config):
        """
        """
        Frame.__init__(self,parent,config)
        self.__properties_frame = PropertiesFrame(parent)
        self.__properties_frame.pack(side=TOP,expand=YES,fill=BOTH)

        # CB: investigate
        self.translator_dictionary = {}

        # CB: surely there's a better way?
        self.topo_obj = None
        self.topo_class = None

        # CB: what does all this do?
        self.option_add("*Menu.tearOff", "0")
        self.menu = Menu(self)
        self.menu.insert_command(END, label = 'Properties', command = lambda:
            self.show_parameter_properties(self.parameters_properties))

        self.__help_balloon = Pmw.Balloon(parent)

        # CB: check these are used consistently
        self.__widgets = {}
        self.__visible_parameters = {}

        # The dictionary of parameter_type:property_to_add pairs.
        self.__parameter_property = {
            Number: self.__add_numeric_property,
            Enumeration: self.__add_enumeration_property,
            BooleanParameter: self.__add_boolean_property,
            ClassSelectorParameter: self.__add_class_selector_property}

    def set_class_parameters(self) :
        """
        """
        assert isinstance(self.topo_class,ParameterizedObjectMetaclass), "ParameterFrame must be associated with a ParameterizedObjectMetaclass to set class parameters."

        for name in self.__visible_parameters:
            # [0] is label (Message), [1] is widget
            w = self.__widgets[name][1]

            if w.get_value()!=getattr(self.topo_class,name):
                setattr(self.topo_class,name,w.get_value())

    def set_obj_params(self):
        """
        For all non-Constant Parameters of the currently set
        ParameterizedObject(), set the values of the Parameters to
        those specified by the widgets.

        Only sets the value on the object if the value in the widget
        is different from the one in the object. This prevents a local
        copy of a variable being made into a ParameterizedObject just
        because the ParameterizedObject is opened in the model editor.
        """
        assert isinstance(self.topo_obj,ParameterizedObject), "ParametersFrame must be associated with a ParameterizedObject to set object parameters."

        # CEBHACKALERT: name should be a constant Parameter; the
        # 'or name==...' can be removed when it is.
        parameters_to_modify = [(name,parameter)
                                for (name,parameter)
                                in self.__visible_parameters.items()
                                if not (parameter.constant==True or name=='name')]

        for (name,parameter) in parameters_to_modify:
            # [0] is label (Message), [1] is widget
            w = self.__widgets[name][1]

            if w.get_value()!=getattr(self.topo_obj,name):
                setattr(self.topo_obj,name,w.get_value())

    def __new_widgets(self,class_=False):
        """
        Remove old labels and widgets from the screen (if there
        are any), then create new ones, sort them by Parameter
        precedence, and finally add them to the screen.
        """

        # wipe old labels and widgets from screen
        for (label,widget) in self.__widgets.values():
            label.grid_forget()
            widget.grid_forget()

        # create the widgets
        self.__widgets = {}
        for (parameter_name, parameter) in self.__visible_parameters.items():
            self.__add_property_for_parameter(parameter_name,parameter,class_=class_)

        # sort Parameters by precedence (oops actually reverse of precedence!)
        parameter_precedences = {}
        for name,parameter in self.__visible_parameters.items():
            parameter_precedences[name] = parameter.precedence
        sorted_parameter_names = keys_sorted_by_value(parameter_precedences)

        # add widgets to screen
        rows = range(len(sorted_parameter_names))
        for (row,parameter_name) in zip(rows,sorted_parameter_names):
            (label,widget) = self.__widgets[parameter_name]

            help_text = getdoc(self.__visible_parameters[parameter_name])

            label.grid(row=row,
                       column=0,
                       padx=self.__properties_frame.padding,
                       pady=self.__properties_frame.padding,
                       sticky=E)

            # We want widgets to stretch to both sides...
            posn=E+W
            # ...except Checkbuttons, which should be left-aligned.
            if isinstance(widget,CheckbuttonTranslator):
                posn=W

            widget.grid(row=row,
                        column=1,
                        padx=self.__properties_frame.padding,
                        pady=self.__properties_frame.padding,
                        sticky=posn)

            self.__help_balloon.bind(label, help_text)

    def create_class_widgets(self, topo_class, translator_dictionary = {}) :
        """
        """
        assert isinstance(topo_class,ParameterizedObjectMetaclass), "ParameterFrame must be passed a ParameterizedObjectMetaclass to create widgets for class Parameters."

        self.translator_dictionary = translator_dictionary

        self.topo_class = topo_class

        self.__visible_parameters = dict([(parameter_name,parameter)
                                      for (parameter_name,parameter)
                                      in self.topo_class.classparams().items()
                                      if not parameter.hidden])
        self.__new_widgets(class_=True)

    def create_widgets(self, topo_obj, translator_dictionary = {}):
        """
        topo.base.parameterclasses.Constant:
        Create widgets for all non-hidden Parameters of topo_obj and add them
        to the screen.

        Each Parameter gets a suitable widget (e.g. a slider for a Number with
        soft_bounds). The default widget is a text box.

        parameters must be Parameter objects.

        Widgets are added in order of the Parameters' precedences.

        If a dictionary is passed in when create_widgets is called
        __add_class_selector_property will attempt to get
        dictionary[parameter_name]. It expects these entries to be
        lists of relevant objects to cover the selectable classes. It
        updates the lists and it can be retrieved from
        self.translator_dictionary when set_obj_params is called and
        used on subsequent uses.
        """
        assert isinstance(topo_obj,ParameterizedObject), "ParameterFrame must be passed a ParameterizedObject to create widgets for Parameters."

        self.topo_obj=topo_obj

        self.__visible_parameters = dict([(parameter_name,parameter)
                                        for (parameter_name,parameter)
                                        in self.topo_obj.params().items()
                                        if not parameter.hidden])
        self.__new_widgets()

    def __add_property_for_parameter(self,parameter_name,parameter,class_=False):
        """
        Find the correct property type for the given parameter.

        If the parameter's type is not listed in
        self.__parameter_property, the class hierarchy is traversed until
        a match is found. If no match is found, the Parameter just gets a
        textbox.
        """
        # CEBHACKALERT: results in DynamicNumber being called and producing
        # a value, rather than displaying information about the dynamic number.
        if class_:
            value = getattr(self.topo_class,parameter_name)
            # or parameter.default for the class?
        else:
            value = getattr(self.topo_obj,parameter_name)

        # CEBHACKALERT: name should be a constant Parameter; the
        # 'or parameter_name' can be removed when it is. (see earlier alert too)
        if (parameter.constant==True or parameter_name=='name') and class_==False:
            self.__add_readonly_text_property(parameter_name,value,parameter)
        else:
            for c in classlist(type(parameter))[::-1]:
                if self.__parameter_property.has_key(c):
                    # find the right method...
                    property_to_add = self.__parameter_property[c]
                    # ...then call it
                    property_to_add(parameter_name,value,parameter)
                    return
            # no match: use text box
            self.__add_text_property(parameter_name,value,parameter)

    def __add_text_property(self,parameter_name,value,parameter):
        """
        Add a text property to the properties_frame.
        """
        # Used to keep track of the value and its string representation, or
        # to evaluate the string representation in __main__.__dict__
        translator = lambda in_string: dict_translator(in_string,translator_dictionary={str(value):value})

        self.__widgets[parameter_name]=self.__properties_frame.add_text_property(
            parameter_name,
            translator = translator,
            value = value)

    def __add_readonly_text_property(self,parameter_name,value,parameter):
        """
        Add a readonly text property to the properties_frame.
        """
        self.__widgets[parameter_name] = self.__properties_frame.add_text_property(
            parameter_name,
            value = value,
            readonly = True)

    def __add_numeric_property(self,parameter_name,value,parameter):
        """
        Add a numeric property to the properties_frame.

        If the parameter has distinct low and high softbounds, a tagged_slider
        property is added. Otherwise, just a textbox is added (with
        a translator for string to float).
        """
        try:
            low_bound,high_bound = parameter.get_soft_bounds()

            if low_bound==None or high_bound==None or low_bound==high_bound:
                # i.e. there aren't really softbounds
                raise AttributeError

            self.__widgets[parameter_name] = self.__properties_frame.add_tagged_slider_property(
                parameter_name,
                value,
                min_value = str(low_bound),
                max_value = str(high_bound),
                string_format = '%.6f',
                translator = topo.misc.utils.eval_atof)

        except AttributeError:
            self.__widgets[parameter_name] = self.__properties_frame.add_text_property(parameter_name,value=value,translator=topo.misc.utils.eval_atof)

    def __add_enumeration_property(self,parameter_name,value,parameter):
        """
        Add an enumeration property to the properties_frame by representing
        it with a ComboBox.
        """
        # CEBHACKALERT: only string Enumerations work at the moment.
        self.__widgets[parameter_name] = self.__properties_frame.add_combobox_property(
                    parameter_name,
                    value = value,
                    scrolledlist_items = parameter.available)

    # CB: how does this work?
    def __add_class_selector_property(self,parameter_name,value,parameter):
        """
        Add a package property to the properties_frame by representing it
        with a ComboBox.
        """
        translator_dictionary = {}
        value_text = ''

        # for each of the classes that this selector can select
        # between loop through and find if there is a suitable object
        # already instantiated in either the current value or in the
        # dictionary passed in.

        possible_classes = parameter.range()
        self.translator_dictionary[parameter_name] = possible_classes

        for (visible_name,class_) in possible_classes.items():

            if class_ == value.__class__:
                value_text = visible_name
                # add the object to the translator dictionary so it's
                # returned again if its class is selected
                self.translator_dictionary[parameter_name].update(
                    {visible_name:value})

        # maps the class key to the object found above.
        translator = lambda in_string: dict_translator(in_string, parameter_name,
            translator_dictionary = self.translator_dictionary)

        self.__widgets[parameter_name] = self.__properties_frame.add_combobox_property(
                    parameter_name,
                    value = value_text,
                    scrolledlist_items = possible_classes.keys(),
                    translator = translator)
        w = self.__widgets[parameter_name][1]
        # bind right click to allow the selected classes properties to be changed.
        w._entryWidget.bind('<Button-3>',
            lambda event: self.right_click(event, w))

    def __add_boolean_property(self,parameter_name,value,parameter):
        """
        Add a boolean property to the properties_frame by representing it with a
        Checkbutton.
        """
        self.__widgets[parameter_name] = self.__properties_frame.add_checkbutton_property(parameter_name,value=value)

    def right_click(self, event, widget) :
        self.parameters_properties = widget
        self.menu.tk_popup(event.x_root, event.y_root)

    def show_parameter_properties(self, widget):
        """
        Open a new window containing a ParametersFrame for the
        current object in the supplied widget.
        """
        obj = widget.get_value()

        # CEBALERT: If the selected field is a class rather than an
        # object, then we can't handle it yet.
        if not isinstance(obj, ParameterizedObject):
            raise NotImplementedError("Right-click editing for a class is not yet supported.") # ...because we have to clean the class vs object editing first.

        parameter_window = Toplevel()
        parameter_window.title(obj.name+' parameters')
        title = Label(parameter_window, text = obj.name)
        title.pack(side = TOP)
        self.__help_balloon.bind(title,getdoc(obj))
        parameter_frame = ParametersFrame(parameter_window)
        parameter_frame.create_widgets(obj)
        button_panel = Frame(parameter_window)
        button_panel.pack(side = BOTTOM)
        Button(button_panel, text = 'Ok', command = lambda frame=parameter_frame, win=parameter_window:
            self.parameter_properties_ok(frame, win)).pack(side = RIGHT)
        Button(button_panel, text = 'Apply',
            command = parameter_frame.set_obj_params).pack(side = RIGHT)

    # CB: where's this called from?
    def parameter_properties_ok(self,frame, win) :
        frame.set_obj_params()
        win.destroy()

<commit_msg>Added hackalert plus a break to stop unnecessary looping.<commit_after>"""
ParametersFrame class.

$Id$
"""
__version__='$Revision$'

# CEBHACKALERT: this file is being reorganized.

from inspect import getdoc

import Pmw
from Tkinter import Frame, Button, RIGHT, TOP, BOTH, BOTTOM, END, YES, N,S,E,W,X, Menu, Toplevel, Label, LEFT

import topo.misc.utils
from topo.misc.utils import keys_sorted_by_value, dict_translator, eval_atof
from topo.base.parameterizedobject import ParameterizedObject,ParameterizedObjectMetaclass,classlist
from topo.base.parameterclasses import Number,Enumeration,ClassSelectorParameter,BooleanParameter

from propertiesframe import PropertiesFrame
from translatorwidgets import CheckbuttonTranslator

# CEBHACKALERT: there used to be a 'reset_to_defaults' method, which
# didn't work. When Parameters can be set and then maintained between
# classes (e.g. for PatternGenerators), reset_to_defaults() should be
# re-implemented so that Parameters can be returned to default values
# for the current class.

class ParametersFrame(Frame):
    """
    Frame for all non-hidden Parameters of a ParameterizedObject class.

    When asked to create wigets, ... makes a PropertiesFrame containing all the specified class' Parameters.
    """

    def __init__(self, parent=None, **config):
        """
        """
        Frame.__init__(self,parent,config)
        self.__properties_frame = PropertiesFrame(parent)
        self.__properties_frame.pack(side=TOP,expand=YES,fill=BOTH)

        # CB: investigate
        self.translator_dictionary = {}

        # CB: surely there's a better way?
        self.topo_obj = None
        self.topo_class = None

        # CB: what does all this do?
        self.option_add("*Menu.tearOff", "0")
        self.menu = Menu(self)
        self.menu.insert_command(END, label = 'Properties', command = lambda:
            self.show_parameter_properties(self.parameters_properties))

        self.__help_balloon = Pmw.Balloon(parent)

        # CB: check these are used consistently
        self.__widgets = {}
        self.__visible_parameters = {}

        # The dictionary of parameter_type:property_to_add pairs.
        self.__parameter_property = {
            Number: self.__add_numeric_property,
            Enumeration: self.__add_enumeration_property,
            BooleanParameter: self.__add_boolean_property,
            ClassSelectorParameter: self.__add_class_selector_property}

    def set_class_parameters(self) :
        """
        """
        assert isinstance(self.topo_class,ParameterizedObjectMetaclass), "ParameterFrame must be associated with a ParameterizedObjectMetaclass to set class parameters."

        for name in self.__visible_parameters:
            # [0] is label (Message), [1] is widget
            w = self.__widgets[name][1]

            if w.get_value()!=getattr(self.topo_class,name):
                setattr(self.topo_class,name,w.get_value())

    def set_obj_params(self):
        """
        For all non-Constant Parameters of the currently set
        ParameterizedObject(), set the values of the Parameters to
        those specified by the widgets.

        Only sets the value on the object if the value in the widget
        is different from the one in the object. This prevents a local
        copy of a variable being made into a ParameterizedObject just
        because the ParameterizedObject is opened in the model editor.
        """
        assert isinstance(self.topo_obj,ParameterizedObject), "ParametersFrame must be associated with a ParameterizedObject to set object parameters."

        # CEBHACKALERT: name should be a constant Parameter; the
        # 'or name==...' can be removed when it is.
        parameters_to_modify = [(name,parameter)
                                for (name,parameter)
                                in self.__visible_parameters.items()
                                if not (parameter.constant==True or name=='name')]

        for (name,parameter) in parameters_to_modify:
            # [0] is label (Message), [1] is widget
            w = self.__widgets[name][1]

            if w.get_value()!=getattr(self.topo_obj,name):
                setattr(self.topo_obj,name,w.get_value())

    def __new_widgets(self,class_=False):
        """
        Remove old labels and widgets from the screen (if there
        are any), then create new ones, sort them by Parameter
        precedence, and finally add them to the screen.
        """

        # wipe old labels and widgets from screen
        for (label,widget) in self.__widgets.values():
            label.grid_forget()
            widget.grid_forget()

        # create the widgets
        self.__widgets = {}
        for (parameter_name, parameter) in self.__visible_parameters.items():
            self.__add_property_for_parameter(parameter_name,parameter,class_=class_)

        # sort Parameters by precedence (oops actually reverse of precedence!)
        parameter_precedences = {}
        for name,parameter in self.__visible_parameters.items():
            parameter_precedences[name] = parameter.precedence
        sorted_parameter_names = keys_sorted_by_value(parameter_precedences)

        # add widgets to screen
        rows = range(len(sorted_parameter_names))
        for (row,parameter_name) in zip(rows,sorted_parameter_names):
            (label,widget) = self.__widgets[parameter_name]

            help_text = getdoc(self.__visible_parameters[parameter_name])

            label.grid(row=row,
                       column=0,
                       padx=self.__properties_frame.padding,
                       pady=self.__properties_frame.padding,
                       sticky=E)

            # We want widgets to stretch to both sides...
            posn=E+W
            # ...except Checkbuttons, which should be left-aligned.
            if isinstance(widget,CheckbuttonTranslator):
                posn=W

            widget.grid(row=row,
                        column=1,
                        padx=self.__properties_frame.padding,
                        pady=self.__properties_frame.padding,
                        sticky=posn)

            self.__help_balloon.bind(label, help_text)

    def create_class_widgets(self, topo_class, translator_dictionary = {}) :
        """
        """
        assert isinstance(topo_class,ParameterizedObjectMetaclass), "ParameterFrame must be passed a ParameterizedObjectMetaclass to create widgets for class Parameters."

        self.translator_dictionary = translator_dictionary

        self.topo_class = topo_class

        self.__visible_parameters = dict([(parameter_name,parameter)
                                      for (parameter_name,parameter)
                                      in self.topo_class.classparams().items()
                                      if not parameter.hidden])
        self.__new_widgets(class_=True)

    def create_widgets(self, topo_obj, translator_dictionary = {}):
        """
        topo.base.parameterclasses.Constant:
        Create widgets for all non-hidden Parameters of topo_obj and add them
        to the screen.

        Each Parameter gets a suitable widget (e.g. a slider for a Number with
        soft_bounds). The default widget is a text box.

        parameters must be Parameter objects.

        Widgets are added in order of the Parameters' precedences.

        If a dictionary is passed in when create_widgets is called
        __add_class_selector_property will attempt to get
        dictionary[parameter_name]. It expects these entries to be
        lists of relevant objects to cover the selectable classes. It
        updates the lists and it can be retrieved from
        self.translator_dictionary when set_obj_params is called and
        used on subsequent uses.
        """
        assert isinstance(topo_obj,ParameterizedObject), "ParameterFrame must be passed a ParameterizedObject to create widgets for Parameters."

        self.topo_obj=topo_obj

        self.__visible_parameters = dict([(parameter_name,parameter)
                                        for (parameter_name,parameter)
                                        in self.topo_obj.params().items()
                                        if not parameter.hidden])
        self.__new_widgets()

    def __add_property_for_parameter(self,parameter_name,parameter,class_=False):
        """
        Find the correct property type for the given parameter.

        If the parameter's type is not listed in
        self.__parameter_property, the class hierarchy is traversed until
        a match is found. If no match is found, the Parameter just gets a
        textbox.
        """
        # CEBHACKALERT: results in DynamicNumber being called and producing
        # a value, rather than displaying information about the dynamic number.
        if class_:
            value = getattr(self.topo_class,parameter_name)
            # or parameter.default for the class?
        else:
            value = getattr(self.topo_obj,parameter_name)

        # CEBHACKALERT: name should be a constant Parameter; the
        # 'or parameter_name' can be removed when it is. (see earlier alert too)
        if (parameter.constant==True or parameter_name=='name') and class_==False:
            self.__add_readonly_text_property(parameter_name,value,parameter)
        else:
            for c in classlist(type(parameter))[::-1]:
                if self.__parameter_property.has_key(c):
                    # find the right method...
                    property_to_add = self.__parameter_property[c]
                    # ...then call it
                    property_to_add(parameter_name,value,parameter)
                    return
            # no match: use text box
            self.__add_text_property(parameter_name,value,parameter)

    def __add_text_property(self,parameter_name,value,parameter):
        """
        Add a text property to the properties_frame.
        """
        # Used to keep track of the value and its string representation, or
        # to evaluate the string representation in __main__.__dict__
        translator = lambda in_string: dict_translator(in_string,translator_dictionary={str(value):value})

        self.__widgets[parameter_name]=self.__properties_frame.add_text_property(
            parameter_name,
            translator = translator,
            value = value)

    def __add_readonly_text_property(self,parameter_name,value,parameter):
        """
        Add a readonly text property to the properties_frame.
        """
        self.__widgets[parameter_name] = self.__properties_frame.add_text_property(
            parameter_name,
            value = value,
            readonly = True)

    def __add_numeric_property(self,parameter_name,value,parameter):
        """
        Add a numeric property to the properties_frame.

        If the parameter has distinct low and high softbounds, a tagged_slider
        property is added. Otherwise, just a textbox is added (with
        a translator for string to float).
        """
        try:
            low_bound,high_bound = parameter.get_soft_bounds()

            if low_bound==None or high_bound==None or low_bound==high_bound:
                # i.e. there aren't really softbounds
                raise AttributeError

            self.__widgets[parameter_name] = self.__properties_frame.add_tagged_slider_property(
                parameter_name,
                value,
                min_value = str(low_bound),
                max_value = str(high_bound),
                string_format = '%.6f',
                translator = topo.misc.utils.eval_atof)

        except AttributeError:
            self.__widgets[parameter_name] = self.__properties_frame.add_text_property(parameter_name,value=value,translator=topo.misc.utils.eval_atof)

    def __add_enumeration_property(self,parameter_name,value,parameter):
        """
        Add an enumeration property to the properties_frame by representing
        it with a ComboBox.
        """
        # CEBHACKALERT: only string Enumerations work at the moment.
        self.__widgets[parameter_name] = self.__properties_frame.add_combobox_property(
                    parameter_name,
                    value = value,
                    scrolledlist_items = parameter.available)

    # CB: how does this work?
    def __add_class_selector_property(self,parameter_name,value,parameter):
        """
        Add a package property to the properties_frame by representing it
        with a ComboBox.
        """
        translator_dictionary = {}
        value_text = ''

        # for each of the classes that this selector can select
        # between loop through and find if there is a suitable object
        # already instantiated in either the current value or in the
        # dictionary passed in.

        possible_classes = parameter.range()
        self.translator_dictionary[parameter_name] = possible_classes

        # CEBHACKALERT: since this method is only called on creation of
        # the widgets, 'caching' the object like this only works for the
        # default object!
        for (visible_name,class_) in possible_classes.items():
            if class_ == value.__class__:
                value_text = visible_name
                # overwrite the class in {visible_name:class} with
                # the object, so it will be returned rather than a
                # new object if this class is selected again
                self.translator_dictionary[parameter_name].update(
                    {visible_name:value})
                break

        # maps the class key to the object found above.
        translator = lambda in_string: dict_translator(in_string, parameter_name,
            translator_dictionary = self.translator_dictionary)

        self.__widgets[parameter_name] = self.__properties_frame.add_combobox_property(
                    parameter_name,
                    value = value_text,
                    scrolledlist_items = possible_classes.keys(),
                    translator = translator)
        w = self.__widgets[parameter_name][1]
        # bind right click to allow the selected classes properties to be changed.
        w._entryWidget.bind('<Button-3>',
            lambda event: self.right_click(event, w))

    def __add_boolean_property(self,parameter_name,value,parameter):
        """
        Add a boolean property to the properties_frame by representing it with a
        Checkbutton.
        """
        self.__widgets[parameter_name] = self.__properties_frame.add_checkbutton_property(parameter_name,value=value)

    def right_click(self, event, widget) :
        self.parameters_properties = widget
        self.menu.tk_popup(event.x_root, event.y_root)

    def show_parameter_properties(self, widget):
        """
        Open a new window containing a ParametersFrame for the
        current object in the supplied widget.
        """
        obj = widget.get_value()

        # CEBALERT: If the selected field is a class rather than an
        # object, then we can't handle it yet.
        if not isinstance(obj, ParameterizedObject):
            raise NotImplementedError("Right-click editing for a class is not yet supported.") # ...because we have to clean the class vs object editing first.

        parameter_window = Toplevel()
        parameter_window.title(obj.name+' parameters')
        title = Label(parameter_window, text = obj.name)
        title.pack(side = TOP)
        self.__help_balloon.bind(title,getdoc(obj))
        parameter_frame = ParametersFrame(parameter_window)
        parameter_frame.create_widgets(obj)
        button_panel = Frame(parameter_window)
        button_panel.pack(side = BOTTOM)
        Button(button_panel, text = 'Ok', command = lambda frame=parameter_frame, win=parameter_window:
            self.parameter_properties_ok(frame, win)).pack(side = RIGHT)
        Button(button_panel, text = 'Apply',
            command = parameter_frame.set_obj_params).pack(side = RIGHT)

    # CB: where's this called from?
    def parameter_properties_ok(self,frame, win) :
        frame.set_obj_params()
        win.destroy()

<|endoftext|>


<commit_before>from django.shortcuts import render, get_object_or_404, redirect
from django.http import HttpResponse
from django.core.exceptions import PermissionDenied

from django.contrib.auth.models import User #to get auth_user table
from .models import user as csv2_user

from .view_utils import db_open, getAuthUser, getcsv2User, verifyUser, getSuperUserStatus, _render
from collections import defaultdict
import bcrypt

from sqlalchemy import exists
from sqlalchemy.sql import select
from lib.schema import *
import sqlalchemy.exc

#-------------------------------------------------------------------------------

MODIFY_IGNORE_KEYS = (
    'action',
    'csrfmiddlewaretoken'
    )

def _db_execute(db_connection, request):
    try:
        db_connection.execute(request)
        return True,None
    except sqlalchemy.exc.IntegrityError as ex:
        return False, ex.orig
    except Exception as ex:
        return False, ex

def _set_user_groups(request, db_session, db_map):
    active_user = getcsv2User(request)
    user_groups = db_map.classes.csv2_user_groups
    user_group_rows = db_session.query(user_groups).filter(user_groups.username==active_user)
    user_groups = []
    if user_group_rows is not None:
        for row in user_group_rows:
            user_groups.append(row.group_name)

    if not user_groups:
        return 1,'user "%s" is not a member of any group.' % active_user,active_user,user_groups

    # if the POST request specified a group, validate and set the specified group as the active group.
    if request.method == 'POST':
        group_name = request.POST.get('group')
        if group_name is not None:
            if group_name in user_groups:
                active_user.active_group = group_name
                active_user.save()
            else:
                return 1,'cannnot switch to invalid group "%s".' % group_name,active_user,user_groups

    # if no active group, set first group as default.
    if active_user.active_group is None:
        active_user.active_group = user_groups[0]
        active_user.save()

    return 0,None,active_user,user_groups

#-------------------------------------------------------------------------------

def list(
    request,
    group=None,
    group_name=None,
    response_code=0,
    message=None,
    active_user=None,
    user_groups=None
    ):

    if not verifyUser(request):
        raise PermissionDenied

    # open the database.
    db_engine,db_session,db_connection,db_map = db_open()

    # Retrieve the active user, associated group list and optionally set the active group.
    if not active_user:
        response_code,message,active_user,user_groups = _set_user_groups(request, db_session, db_map)
        if response_code != 0:
            db_connection.close()
            return _render(request, 'csv2/groups.html', {'response_code': 1, 'message': message})

    #get group info
    s = select([view_groups_with_yaml])
    group_list = {'ResultProxy': [dict(r) for r in db_connection.execute(s)]}

    db_connection.close()

    # Position the page.
    obj_act_id = request.path.split('/')
    if group:
        if group == '-':
            current_group = ''
        else:
            current_group = group
    elif len(obj_act_id) > 2 and len(obj_act_id[3]) > 0:
        current_group = str(obj_act_id[3])
    else:
        if len(group_list['ResultProxy']) > 0:
            current_group = str(group_list['ResultProxy'][0]['group_name'])
        else:
            current_group = ''

    # Render the page.
    context = {
            'active_user': active_user,
            'active_group': active_user.active_group,
            'user_groups': user_groups,
            'group_list': group_list,
            'current_group': current_group,
            'response_code': 0,
            'message': None
        }

    return _render(request, 'csv2/groups.html', context)

#-------------------------------------------------------------------------------

def modify(request):
    if not verifyUser(request):
        raise PermissionDenied
    if not getSuperUserStatus(request):
        raise PermissionDenied

    if request.method == 'POST' and 'action' in request.POST and 'group_name' in request.POST:
        # open the database.
        db_engine,db_session,db_connection,db_map = db_open()

        # Retrieve the active user, associated group list and optionally set the active group.
        response_code,message,active_user,user_groups = _set_user_groups(request, db_session, db_map)
        if response_code != 0:
            return list(request, group='-', response_code=1, message=message, active_user=active_user, user_groups=user_groups)

        # map the field list.
        metadata = MetaData(bind=db_engine)
        table = Table('csv2_groups', metadata, autoload=True)

        values = [{}, {}]
        for key in request.POST:
            if key in table.c:
                if key == 'group_name':
                    values[0][key] = request.POST[key]
                else:
                    if request.POST[key]:
                        values[1][key] = request.POST[key]
            else:
                if key not in MODIFY_IGNORE_KEYS:
                    return list(request, group='-', response_code=1, message='group modify request contained bad parameter "%s".' % key, active_user=active_user, user_groups=user_groups)

        if request.POST['action'] == 'add':
            if values[0] and values[1]:
                success,message = _db_execute(db_connection, table.insert().values({**values[0], **values[1]}))

            db_connection.close()
            if success:
                return list(request, group=values[0]['group_name'], response_code=0, message='group "%s" successfully added.' % (values[0]['group_name']), active_user=active_user, user_groups=user_groups)
            else:
                return list(request, group=values[0]['group_name'], response_code=1, message='group "%s" add failed - %s.' % (values[0]['group_name'], message), active_user=active_user, user_groups=user_groups)

        elif request.POST['action'] == 'delete':

            # Before deleting make sure there are no VMs running accociated with the group.
            table_vms = Table('csv2_vms', metadata, autoload=True)

            if(db_session.query(exists().where(table_vms.c.group_name==values[0]['group_name'])).scalar()):
                return list(request, group=values[0]['group_name'], response_code=1, message='group "%s" delete failed. VMs exist on accociated clouds.' % (values[0]['group_name']), active_user=active_user, user_groups=user_groups)

            # Delete the group and accociated enteries in other tables:

            # Load the tables:
            table_users = Table('csv2_user_groups', metadata, autoload=True)
            table_defaults = Table('csv2_group_defaults', metadata, autoload=True)
            table_resources = Table('csv2_group_resources', metadata, autoload=True)
            table_resources_yaml = Table('csv2_group_resource_yaml', metadata, autoload=True)
            table_yaml = Table('csv2_group_yaml', metadata, autoload=True)
            table_user_groups = Table('csv2_user_groups', metadata, autoload=True)

            # Delete all rows accociated with target group:
            success,message = _db_execute(db_connection,
                table.delete(table.c.group_name==values[0]['group_name']))

            success2,message2 = _db_execute(db_connection,
                table_users.delete(table_users.c.group_name==values[0]['group_name']))

            success3,message3 = _db_execute(db_connection,
                table_defaults.delete(table_defaults.c.group_name==values[0]['group_name']))

            success4,message4 = _db_execute(db_connection,
                table_resources.delete(table_resources.c.group_name==values[0]['group_name']))

            success5,message5 = _db_execute(db_connection,
                table_resources_yaml.delete(table_resources_yaml.c.group_name==values[0]['group_name']))

            success6,message6 = _db_execute(db_connection,
                table_yaml.delete(table_yaml.c.group_name==values[0]['group_name']))

            success7,message7 = _db_execute(db_connection,
                table_user_groups.delete(table_user_groups.c.group_name==values[0]['group_name']))

            db_connection.close()

            if success:
                return list(request, group=values[0]['group_name'], response_code=0, message='group "%s" successfully deleted.' % (values[0]['group_name']), active_user=active_user, user_groups=user_groups)
            else:
                return list(request, group=values[0]['group_name'], response_code=1, message='group "%s" delete failed - %s.' % (values[0]['group_name'], message), active_user=active_user, user_groups=user_groups)

        elif request.POST['action'] == 'modify':
            success,message = _db_execute(db_connection, table.update().where(table.c.group_name==values[0]['group_name']).values(values[1]))
            db_connection.close()
            if success:
                return list(request, group=values[0]['group_name'], response_code=0, message='group "%s" successfully modified.' % (values[0]['group_name']), active_user=active_user, user_groups=user_groups)
            else:
                return list(request, group=values[0]['group_name'], response_code=1, message='group "%s" modify failed - %s.' % (values[0]['group_name'], message), active_user=active_user, user_groups=user_groups)

        else:
            return list(request, group=values[0]['group_name'], response_code=1, message='invalid action "%s" specified.' % request.POST['action'], active_user=active_user, user_groups=user_groups)
    else:
        if request.method == 'POST':
            return list(request, response_code=1, message='invalid method "%s" specified.' % request.method)
        elif 'action' not in request.POST:
            return list(request, response_code=1, message='no action specified.')
        else:
            return list(request, response_code=1, message='no group name specified.')

#-------------------------------------------------------------------------------

def prepare(request):
    """
    This function returns a minimal response plus a CSRF.
    """

    context = {
            'response_code': 0,
            'message': None
    }

    return _render(request, 'csv2/groups.html', context)
<commit_msg>Delete group from all accociated tables if VMs=0<commit_after>from django.shortcuts import render, get_object_or_404, redirect
from django.http import HttpResponse
from django.core.exceptions import PermissionDenied

from django.contrib.auth.models import User #to get auth_user table
from .models import user as csv2_user

from .view_utils import db_open, getAuthUser, getcsv2User, verifyUser, getSuperUserStatus, _render
from collections import defaultdict
import bcrypt

from sqlalchemy import exists
from sqlalchemy.sql import select
from lib.schema import *
import sqlalchemy.exc

#-------------------------------------------------------------------------------

MODIFY_IGNORE_KEYS = (
    'action',
    'csrfmiddlewaretoken'
    )

def _db_execute(db_connection, request):
    try:
        db_connection.execute(request)
        return True,None
    except sqlalchemy.exc.IntegrityError as ex:
        return False, ex.orig
    except Exception as ex:
        return False, ex

def _set_user_groups(request, db_session, db_map):
    active_user = getcsv2User(request)
    user_groups = db_map.classes.csv2_user_groups
    user_group_rows = db_session.query(user_groups).filter(user_groups.username==active_user)
    user_groups = []
    if user_group_rows is not None:
        for row in user_group_rows:
            user_groups.append(row.group_name)

    if not user_groups:
        return 1,'user "%s" is not a member of any group.' % active_user,active_user,user_groups

    # if the POST request specified a group, validate and set the specified group as the active group.
    if request.method == 'POST':
        group_name = request.POST.get('group')
        if group_name is not None:
            if group_name in user_groups:
                active_user.active_group = group_name
                active_user.save()
            else:
                return 1,'cannnot switch to invalid group "%s".' % group_name,active_user,user_groups

    # if no active group, set first group as default.
    if active_user.active_group is None:
        active_user.active_group = user_groups[0]
        active_user.save()

    return 0,None,active_user,user_groups

#-------------------------------------------------------------------------------

def list(
    request,
    group=None,
    group_name=None,
    response_code=0,
    message=None,
    active_user=None,
    user_groups=None
    ):

    if not verifyUser(request):
        raise PermissionDenied

    # open the database.
    db_engine,db_session,db_connection,db_map = db_open()

    # Retrieve the active user, associated group list and optionally set the active group.
    if not active_user:
        response_code,message,active_user,user_groups = _set_user_groups(request, db_session, db_map)
        if response_code != 0:
            db_connection.close()
            return _render(request, 'csv2/groups.html', {'response_code': 1, 'message': message})

    #get group info
    s = select([view_groups_with_yaml])
    group_list = {'ResultProxy': [dict(r) for r in db_connection.execute(s)]}

    db_connection.close()

    # Position the page.
    obj_act_id = request.path.split('/')
    if group:
        if group == '-':
            current_group = ''
        else:
            current_group = group
    elif len(obj_act_id) > 2 and len(obj_act_id[3]) > 0:
        current_group = str(obj_act_id[3])
    else:
        if len(group_list['ResultProxy']) > 0:
            current_group = str(group_list['ResultProxy'][0]['group_name'])
        else:
            current_group = ''

    # Render the page.
    context = {
            'active_user': active_user,
            'active_group': active_user.active_group,
            'user_groups': user_groups,
            'group_list': group_list,
            'current_group': current_group,
            'response_code': 0,
            'message': None
        }

    return _render(request, 'csv2/groups.html', context)

#-------------------------------------------------------------------------------

def modify(request):
    if not verifyUser(request):
        raise PermissionDenied
    if not getSuperUserStatus(request):
        raise PermissionDenied

    if request.method == 'POST' and 'action' in request.POST and 'group_name' in request.POST:
        # open the database.
        db_engine,db_session,db_connection,db_map = db_open()

        # Retrieve the active user, associated group list and optionally set the active group.
        response_code,message,active_user,user_groups = _set_user_groups(request, db_session, db_map)
        if response_code != 0:
            return list(request, group='-', response_code=1, message=message, active_user=active_user, user_groups=user_groups)

        # map the field list.
        metadata = MetaData(bind=db_engine)
        table = Table('csv2_groups', metadata, autoload=True)

        values = [{}, {}]
        for key in request.POST:
            if key in table.c:
                if key == 'group_name':
                    values[0][key] = request.POST[key]
                else:
                    if request.POST[key]:
                        values[1][key] = request.POST[key]
            else:
                if key not in MODIFY_IGNORE_KEYS:
                    return list(request, group='-', response_code=1, message='group modify request contained bad parameter "%s".' % key, active_user=active_user, user_groups=user_groups)

        if request.POST['action'] == 'add':
            if values[0] and values[1]:
                success,message = _db_execute(db_connection, table.insert().values({**values[0], **values[1]}))

            db_connection.close()
            if success:
                return list(request, group=values[0]['group_name'], response_code=0, message='group "%s" successfully added.' % (values[0]['group_name']), active_user=active_user, user_groups=user_groups)
            else:
                return list(request, group=values[0]['group_name'], response_code=1, message='group "%s" add failed - %s.' % (values[0]['group_name'], message), active_user=active_user, user_groups=user_groups)

        elif request.POST['action'] == 'delete':

            # Before deleting make sure there are no VMs running accociated with the group.

            view_status = Table('view_cloud_status', metadata, autoload=True)

            if(db_session.query(exists().where((view_status.c.group_name==values[0]['group_name']) & (view_status.c.VMs==0))).scalar()):
                return list(request, group=values[0]['group_name'], response_code=1, message='group "%s" delete failed. VMs exist on accociated clouds.' % (values[0]['group_name']), active_user=active_user, user_groups=user_groups)

            # Delete the group and accociated enteries in other tables:

            # Load the tables:
            table_vms = Table('csv2_vms', metadata, autoload=True)
            table_users = Table('csv2_user_groups', metadata, autoload=True)
            table_defaults = Table('csv2_group_defaults', metadata, autoload=True)
            table_resources = Table('csv2_group_resources', metadata, autoload=True)
            table_resources_yaml = Table('csv2_group_resource_yaml', metadata, autoload=True)
            table_yaml = Table('csv2_group_yaml', metadata, autoload=True)
            table_user_groups = Table('csv2_user_groups', metadata, autoload=True)
            table_networks = Table('cloud_networks', metadata, autoload=True)
            table_limits = Table('cloud_limits', metadata, autoload=True)
            table_images = Table('cloud_images', metadata, autoload=True)
            table_flavors = Table('cloud_flavors', metadata, autoload=True)

            # Delete all rows accociated with target group:
            success,message = _db_execute(db_connection,
                table.delete(table.c.group_name==values[0]['group_name']))

            success1,message1 = _db_execute(db_connection,
                table_users.delete(table_vms.c.group_name==values[0]['group_name']))

            success2,message2 = _db_execute(db_connection,
                table_users.delete(table_users.c.group_name==values[0]['group_name']))

            success3,message3 = _db_execute(db_connection,
                table_defaults.delete(table_defaults.c.group_name==values[0]['group_name']))

            success4,message4 = _db_execute(db_connection,
                table_resources.delete(table_resources.c.group_name==values[0]['group_name']))

            success5,message5 = _db_execute(db_connection,
                table_resources_yaml.delete(table_resources_yaml.c.group_name==values[0]['group_name']))

            success6,message6 = _db_execute(db_connection,
                table_yaml.delete(table_yaml.c.group_name==values[0]['group_name']))

            success7,message7 = _db_execute(db_connection,
                table_user_groups.delete(table_user_groups.c.group_name==values[0]['group_name']))

            success8,message8 = _db_execute(db_connection,
                table_users.delete(table_networks.c.group_name==values[0]['group_name']))

            success9,message9 = _db_execute(db_connection,
                table_users.delete(table_limits.c.group_name==values[0]['group_name']))

            success10,message10 = _db_execute(db_connection,
                table_users.delete(table_images.c.group_name==values[0]['group_name']))

            success11,message11 = _db_execute(db_connection,
                table_users.delete(table_flavors.c.group_name==values[0]['group_name']))

            db_connection.close()

            if success:
                return list(request, group=values[0]['group_name'], response_code=0, message='group "%s" successfully deleted.' % (values[0]['group_name']), active_user=active_user, user_groups=user_groups)
            else:
                return list(request, group=values[0]['group_name'], response_code=1, message='group "%s" delete failed - %s.' % (values[0]['group_name'], message), active_user=active_user, user_groups=user_groups)

        elif request.POST['action'] == 'modify':
            success,message = _db_execute(db_connection, table.update().where(table.c.group_name==values[0]['group_name']).values(values[1]))
            db_connection.close()
            if success:
                return list(request, group=values[0]['group_name'], response_code=0, message='group "%s" successfully modified.' % (values[0]['group_name']), active_user=active_user, user_groups=user_groups)
            else:
                return list(request, group=values[0]['group_name'], response_code=1, message='group "%s" modify failed - %s.' % (values[0]['group_name'], message), active_user=active_user, user_groups=user_groups)

        else:
            return list(request, group=values[0]['group_name'], response_code=1, message='invalid action "%s" specified.' % request.POST['action'], active_user=active_user, user_groups=user_groups)
    else:
        if request.method == 'POST':
            return list(request, response_code=1, message='invalid method "%s" specified.' % request.method)
        elif 'action' not in request.POST:
            return list(request, response_code=1, message='no action specified.')
        else:
            return list(request, response_code=1, message='no group name specified.')

#-------------------------------------------------------------------------------

def prepare(request):
    """
    This function returns a minimal response plus a CSRF.
    """

    context = {
            'response_code': 0,
            'message': None
    }

    return _render(request, 'csv2/groups.html', context)
<|endoftext|>